gsd-pi 2.43.0 → 2.44.0-dev.0b97ffd
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 +30 -12
- package/dist/cli.js +13 -1
- package/dist/help-text.js +24 -0
- package/dist/resources/extensions/bg-shell/overlay.js +3 -0
- package/dist/resources/extensions/github-sync/sync.js +2 -1
- package/dist/resources/extensions/gsd/auto/loop.js +0 -2
- package/dist/resources/extensions/gsd/auto/phases.js +7 -12
- package/dist/resources/extensions/gsd/auto-dashboard.js +19 -18
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +34 -19
- package/dist/resources/extensions/gsd/auto-dispatch.js +36 -21
- package/dist/resources/extensions/gsd/auto-post-unit.js +128 -14
- package/dist/resources/extensions/gsd/auto-prompts.js +202 -92
- package/dist/resources/extensions/gsd/auto-recovery.js +83 -135
- package/dist/resources/extensions/gsd/auto-start.js +10 -0
- package/dist/resources/extensions/gsd/auto-supervisor.js +14 -0
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +4 -7
- package/dist/resources/extensions/gsd/auto-verification.js +5 -10
- package/dist/resources/extensions/gsd/auto-worktree.js +123 -30
- package/dist/resources/extensions/gsd/auto.js +1 -4
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +611 -0
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +28 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +3 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +15 -1
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
- package/dist/resources/extensions/gsd/commands-maintenance.js +78 -3
- package/dist/resources/extensions/gsd/dashboard-overlay.js +32 -31
- package/dist/resources/extensions/gsd/db-writer.js +95 -4
- package/dist/resources/extensions/gsd/dispatch-guard.js +35 -30
- package/dist/resources/extensions/gsd/doctor-checks.js +28 -11
- package/dist/resources/extensions/gsd/doctor-environment.js +28 -0
- package/dist/resources/extensions/gsd/doctor-types.js +0 -15
- package/dist/resources/extensions/gsd/doctor.js +46 -282
- package/dist/resources/extensions/gsd/file-watcher.js +5 -1
- package/dist/resources/extensions/gsd/files.js +14 -198
- package/dist/resources/extensions/gsd/git-service.js +4 -0
- package/dist/resources/extensions/gsd/gitignore.js +4 -0
- package/dist/resources/extensions/gsd/gsd-db.js +819 -197
- package/dist/resources/extensions/gsd/guided-flow.js +18 -8
- package/dist/resources/extensions/gsd/markdown-renderer.js +862 -0
- package/dist/resources/extensions/gsd/md-importer.js +182 -4
- package/dist/resources/extensions/gsd/native-git-bridge.js +10 -1
- package/dist/resources/extensions/gsd/parallel-eligibility.js +14 -19
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +38 -0
- package/dist/resources/extensions/gsd/parsers-legacy.js +239 -0
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +9 -0
- package/dist/resources/extensions/gsd/preferences.js +1 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +22 -9
- package/dist/resources/extensions/gsd/prompts/discuss.md +2 -2
- package/dist/resources/extensions/gsd/prompts/execute-task.md +15 -5
- package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +6 -10
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -7
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -3
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -7
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +6 -6
- package/dist/resources/extensions/gsd/reactive-graph.js +33 -3
- package/dist/resources/extensions/gsd/skill-health.js +3 -1
- package/dist/resources/extensions/gsd/state.js +484 -30
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +128 -0
- package/dist/resources/extensions/gsd/tools/complete-slice.js +244 -0
- package/dist/resources/extensions/gsd/tools/complete-task.js +204 -0
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +205 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +155 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +94 -0
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +152 -0
- package/dist/resources/extensions/gsd/tools/replan-slice.js +146 -0
- package/dist/resources/extensions/gsd/triage-resolution.js +17 -1
- package/dist/resources/extensions/gsd/undo.js +197 -3
- package/dist/resources/extensions/gsd/visualizer-data.js +53 -16
- package/dist/resources/extensions/gsd/workspace-index.js +63 -39
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -17
- package/dist/web/standalone/.next/build-manifest.json +4 -4
- 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/required-server-files.json +4 -4
- package/dist/web/standalone/.next/routes-manifest.json +6 -0
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- 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/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
- 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 +4 -4
- 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 +2 -2
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -0
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -0
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -0
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +5 -5
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
- 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 +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -17
- package/dist/web/standalone/.next/server/chunks/229.js +3 -3
- package/dist/web/standalone/.next/server/chunks/471.js +3 -3
- package/dist/web/standalone/.next/server/functions-config-manifest.json +1 -0
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/alS4hoANx0TK4UVZY27da/_buildManifest.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{4024.c195dc1fdd2adbea.js → 4024.0de81b543b28b9fe.js} +2 -2
- package/dist/web/standalone/.next/static/chunks/app/_global-error/{page-d07a2c023f1aef1e.js → page-d83ba70a25a85472.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-f2a7482d42a5614b.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/boot/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/input/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/resize/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/captures/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/files/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/git/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/history/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/projects/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/steer/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/switch-root/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/undo/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/update/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{main-app-2f2ee7b85712c2bd.js → main-app-fdab67f7802d7832.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-fa307370fcf9fb2c.js → webpack-9014b5adb127a98a.js} +1 -1
- package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +4 -4
- package/packages/pi-ai/dist/models.custom.d.ts +173 -0
- package/packages/pi-ai/dist/models.custom.d.ts.map +1 -0
- package/packages/pi-ai/dist/models.custom.js +170 -0
- package/packages/pi-ai/dist/models.custom.js.map +1 -0
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.js +16 -1
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/models.test.d.ts +2 -0
- package/packages/pi-ai/dist/models.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/models.test.js +67 -0
- package/packages/pi-ai/dist/models.test.js.map +1 -0
- package/packages/pi-ai/src/models.custom.ts +172 -0
- package/packages/pi-ai/src/models.test.ts +85 -0
- package/packages/pi-ai/src/models.ts +17 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +10 -3
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +21 -34
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +4 -4
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +80 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.test.js +63 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +37 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/fallback-resolver.js +2 -3
- package/packages/pi-coding-agent/dist/core/fallback-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js +12 -2
- package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +38 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +192 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js +69 -21
- package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +255 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-commands.d.ts +25 -0
- package/packages/pi-coding-agent/dist/core/package-commands.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/package-commands.js +253 -0
- package/packages/pi-coding-agent/dist/core/package-commands.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/package-commands.test.js +225 -0
- package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +4 -0
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +3 -1
- 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/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +11 -199
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts +6 -0
- 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 +21 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +8 -15
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/print-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/print-mode.js +45 -34
- package/packages/pi-coding-agent/dist/modes/print-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +7 -2
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +2 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +26 -37
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
- package/packages/pi-coding-agent/src/core/compaction/branch-summarization.ts +2 -2
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +3 -3
- package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +4 -4
- package/packages/pi-coding-agent/src/core/extensions/index.ts +5 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.test.ts +96 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +89 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
- package/packages/pi-coding-agent/src/core/extensions/types.ts +44 -0
- package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +15 -2
- package/packages/pi-coding-agent/src/core/fallback-resolver.ts +2 -3
- package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
- package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +274 -0
- package/packages/pi-coding-agent/src/core/lsp/client.ts +83 -21
- package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +288 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +39 -3
- package/packages/pi-coding-agent/src/core/package-commands.test.ts +240 -0
- package/packages/pi-coding-agent/src/core/package-commands.ts +310 -0
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
- package/packages/pi-coding-agent/src/core/sdk.ts +4 -0
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
- package/packages/pi-coding-agent/src/index.ts +7 -0
- package/packages/pi-coding-agent/src/main.ts +11 -232
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +20 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +9 -16
- package/packages/pi-coding-agent/src/modes/print-mode.ts +42 -32
- package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +8 -2
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -1
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
- package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +8 -15
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/bg-shell/overlay.ts +4 -0
- package/src/resources/extensions/github-sync/sync.ts +2 -1
- package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -8
- package/src/resources/extensions/gsd/auto/loop.ts +0 -2
- package/src/resources/extensions/gsd/auto/phases.ts +7 -20
- package/src/resources/extensions/gsd/auto/types.ts +0 -1
- package/src/resources/extensions/gsd/auto-dashboard.ts +20 -16
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +34 -19
- package/src/resources/extensions/gsd/auto-dispatch.ts +38 -21
- package/src/resources/extensions/gsd/auto-post-unit.ts +150 -15
- package/src/resources/extensions/gsd/auto-prompts.ts +186 -103
- package/src/resources/extensions/gsd/auto-recovery.ts +77 -142
- package/src/resources/extensions/gsd/auto-start.ts +14 -0
- package/src/resources/extensions/gsd/auto-supervisor.ts +14 -0
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +6 -7
- package/src/resources/extensions/gsd/auto-verification.ts +4 -9
- package/src/resources/extensions/gsd/auto-worktree.ts +126 -30
- package/src/resources/extensions/gsd/auto.ts +0 -9
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +675 -4
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +31 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +3 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +15 -1
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
- package/src/resources/extensions/gsd/commands-maintenance.ts +86 -3
- package/src/resources/extensions/gsd/dashboard-overlay.ts +17 -13
- package/src/resources/extensions/gsd/db-writer.ts +105 -4
- package/src/resources/extensions/gsd/dispatch-guard.ts +32 -30
- package/src/resources/extensions/gsd/doctor-checks.ts +25 -11
- package/src/resources/extensions/gsd/doctor-environment.ts +31 -0
- package/src/resources/extensions/gsd/doctor-types.ts +0 -23
- package/src/resources/extensions/gsd/doctor.ts +45 -295
- package/src/resources/extensions/gsd/file-watcher.ts +4 -1
- package/src/resources/extensions/gsd/files.ts +16 -220
- package/src/resources/extensions/gsd/git-service.ts +4 -0
- package/src/resources/extensions/gsd/gitignore.ts +4 -0
- package/src/resources/extensions/gsd/gsd-db.ts +1157 -370
- package/src/resources/extensions/gsd/guided-flow.ts +20 -8
- package/src/resources/extensions/gsd/markdown-renderer.ts +1098 -0
- package/src/resources/extensions/gsd/md-importer.ts +211 -2
- package/src/resources/extensions/gsd/native-git-bridge.ts +12 -1
- package/src/resources/extensions/gsd/parallel-eligibility.ts +14 -18
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +43 -0
- package/src/resources/extensions/gsd/parsers-legacy.ts +271 -0
- package/src/resources/extensions/gsd/preferences-types.ts +3 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +9 -0
- package/src/resources/extensions/gsd/preferences.ts +1 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +22 -9
- package/src/resources/extensions/gsd/prompts/discuss.md +2 -2
- package/src/resources/extensions/gsd/prompts/execute-task.md +15 -5
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +6 -10
- package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -7
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -3
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -7
- package/src/resources/extensions/gsd/prompts/replan-slice.md +6 -6
- package/src/resources/extensions/gsd/reactive-graph.ts +33 -3
- package/src/resources/extensions/gsd/skill-health.ts +2 -1
- package/src/resources/extensions/gsd/state.ts +547 -29
- package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
- package/src/resources/extensions/gsd/tests/atomic-task-closeout.test.ts +8 -120
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +20 -11
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +600 -513
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
- package/src/resources/extensions/gsd/tests/auto-stash-merge.test.ts +121 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +540 -668
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
- package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
- package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
- package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +39 -60
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +375 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +387 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
- package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +0 -2
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +390 -420
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +512 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +644 -84
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
- package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +192 -161
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
- package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +30 -90
- package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +57 -80
- package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +164 -0
- package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +55 -153
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +53 -97
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
- package/src/resources/extensions/gsd/tests/doctor.test.ts +109 -149
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
- package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +278 -0
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +232 -0
- package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
- package/src/resources/extensions/gsd/tests/git-service.test.ts +291 -390
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +440 -0
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -270
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
- package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
- package/src/resources/extensions/gsd/tests/integration-proof.test.ts +643 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -3
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1161 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +81 -94
- package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +429 -0
- package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +89 -97
- package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +127 -164
- package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
- package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
- package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
- package/src/resources/extensions/gsd/tests/parsers.test.ts +548 -612
- package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +176 -113
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +305 -0
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
- package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
- package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +325 -0
- package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
- package/src/resources/extensions/gsd/tests/replan-handler.test.ts +410 -0
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
- package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
- package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +296 -0
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
- package/src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts +176 -0
- package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
- package/src/resources/extensions/gsd/tests/token-cost-display.test.ts +118 -0
- package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +19 -13
- package/src/resources/extensions/gsd/tests/undo.test.ts +321 -1
- package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +0 -142
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
- package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +12 -5
- package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
- package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +176 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +300 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +245 -0
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +249 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +194 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +116 -0
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +203 -0
- package/src/resources/extensions/gsd/tools/replan-slice.ts +192 -0
- package/src/resources/extensions/gsd/triage-resolution.ts +20 -1
- package/src/resources/extensions/gsd/types.ts +50 -0
- package/src/resources/extensions/gsd/undo.ts +247 -3
- package/src/resources/extensions/gsd/visualizer-data.ts +54 -17
- package/src/resources/extensions/gsd/workspace-index.ts +64 -46
- package/dist/resources/extensions/gsd/auto-observability.js +0 -56
- package/dist/resources/extensions/gsd/observability-validator.js +0 -422
- package/dist/resources/extensions/gsd/roadmap-mutations.js +0 -110
- package/dist/web/standalone/.next/static/VvclDCW6TAWjEyLU-EYL1/_buildManifest.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-e07acdb7dd069836.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/captures/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/files/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/git/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/history/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/projects/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/steer/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/undo/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/update/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-745c6ed5fea5fb06.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/page-801b53eff6e83579.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-e6255954dccfcf0a.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/css/123c0bb039697968.css +0 -1
- package/src/resources/extensions/gsd/auto-observability.ts +0 -74
- package/src/resources/extensions/gsd/observability-validator.ts +0 -456
- package/src/resources/extensions/gsd/roadmap-mutations.ts +0 -134
- package/src/resources/extensions/gsd/tests/doctor-task-done-missing-summary-slice-loop.test.ts +0 -174
- package/src/resources/extensions/gsd/tests/plan-quality-validator.test.ts +0 -474
- /package/dist/web/standalone/.next/static/{VvclDCW6TAWjEyLU-EYL1 → alS4hoANx0TK4UVZY27da}/_ssgManifest.js +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { describe, test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
1
3
|
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, symlinkSync } from "node:fs";
|
|
2
4
|
import { join, dirname } from "node:path";
|
|
3
5
|
import { tmpdir } from "node:os";
|
|
@@ -20,174 +22,170 @@ import {
|
|
|
20
22
|
type TaskCommitContext,
|
|
21
23
|
} from "../git-service.ts";
|
|
22
24
|
import { nativeAddAllWithExclusions } from "../native-git-bridge.ts";
|
|
23
|
-
import { createTestContext } from './test-helpers.ts';
|
|
24
|
-
|
|
25
|
-
const { assertEq, assertTrue, report } = createTestContext();
|
|
26
25
|
function run(command: string, cwd: string): string {
|
|
27
26
|
return execSync(command, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
async
|
|
29
|
+
describe('git-service', async () => {
|
|
31
30
|
// ─── inferCommitType ───────────────────────────────────────────────────
|
|
32
31
|
|
|
33
|
-
console.log("\n=== inferCommitType ===");
|
|
34
32
|
|
|
35
|
-
|
|
33
|
+
assert.deepStrictEqual(
|
|
36
34
|
inferCommitType("Implement user authentication"),
|
|
37
35
|
"feat",
|
|
38
36
|
"generic feature title → feat"
|
|
39
37
|
);
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
assert.deepStrictEqual(
|
|
42
40
|
inferCommitType("Add dashboard page"),
|
|
43
41
|
"feat",
|
|
44
42
|
"add-style title → feat"
|
|
45
43
|
);
|
|
46
44
|
|
|
47
|
-
|
|
45
|
+
assert.deepStrictEqual(
|
|
48
46
|
inferCommitType("Fix login redirect bug"),
|
|
49
47
|
"fix",
|
|
50
48
|
"title with 'fix' → fix"
|
|
51
49
|
);
|
|
52
50
|
|
|
53
|
-
|
|
51
|
+
assert.deepStrictEqual(
|
|
54
52
|
inferCommitType("Bug in session handling"),
|
|
55
53
|
"fix",
|
|
56
54
|
"title with 'bug' → fix"
|
|
57
55
|
);
|
|
58
56
|
|
|
59
|
-
|
|
57
|
+
assert.deepStrictEqual(
|
|
60
58
|
inferCommitType("Hotfix for production crash"),
|
|
61
59
|
"fix",
|
|
62
60
|
"title with 'hotfix' → fix"
|
|
63
61
|
);
|
|
64
62
|
|
|
65
|
-
|
|
63
|
+
assert.deepStrictEqual(
|
|
66
64
|
inferCommitType("Patch memory leak"),
|
|
67
65
|
"fix",
|
|
68
66
|
"title with 'patch' → fix"
|
|
69
67
|
);
|
|
70
68
|
|
|
71
|
-
|
|
69
|
+
assert.deepStrictEqual(
|
|
72
70
|
inferCommitType("Refactor state management"),
|
|
73
71
|
"refactor",
|
|
74
72
|
"title with 'refactor' → refactor"
|
|
75
73
|
);
|
|
76
74
|
|
|
77
|
-
|
|
75
|
+
assert.deepStrictEqual(
|
|
78
76
|
inferCommitType("Restructure project layout"),
|
|
79
77
|
"refactor",
|
|
80
78
|
"title with 'restructure' → refactor"
|
|
81
79
|
);
|
|
82
80
|
|
|
83
|
-
|
|
81
|
+
assert.deepStrictEqual(
|
|
84
82
|
inferCommitType("Reorganize module imports"),
|
|
85
83
|
"refactor",
|
|
86
84
|
"title with 'reorganize' → refactor"
|
|
87
85
|
);
|
|
88
86
|
|
|
89
|
-
|
|
87
|
+
assert.deepStrictEqual(
|
|
90
88
|
inferCommitType("Update API documentation"),
|
|
91
89
|
"docs",
|
|
92
90
|
"title with 'documentation' → docs"
|
|
93
91
|
);
|
|
94
92
|
|
|
95
|
-
|
|
93
|
+
assert.deepStrictEqual(
|
|
96
94
|
inferCommitType("Add doc for setup guide"),
|
|
97
95
|
"docs",
|
|
98
96
|
"title with 'doc' → docs"
|
|
99
97
|
);
|
|
100
98
|
|
|
101
|
-
|
|
99
|
+
assert.deepStrictEqual(
|
|
102
100
|
inferCommitType("Add unit tests for auth"),
|
|
103
101
|
"test",
|
|
104
102
|
"title with 'tests' → test"
|
|
105
103
|
);
|
|
106
104
|
|
|
107
|
-
|
|
105
|
+
assert.deepStrictEqual(
|
|
108
106
|
inferCommitType("Testing infrastructure setup"),
|
|
109
107
|
"test",
|
|
110
108
|
"title with 'testing' → test"
|
|
111
109
|
);
|
|
112
110
|
|
|
113
|
-
|
|
111
|
+
assert.deepStrictEqual(
|
|
114
112
|
inferCommitType("Chore: update dependencies"),
|
|
115
113
|
"chore",
|
|
116
114
|
"title with 'chore' → chore"
|
|
117
115
|
);
|
|
118
116
|
|
|
119
|
-
|
|
117
|
+
assert.deepStrictEqual(
|
|
120
118
|
inferCommitType("Cleanup unused imports"),
|
|
121
119
|
"chore",
|
|
122
120
|
"title with 'cleanup' → chore"
|
|
123
121
|
);
|
|
124
122
|
|
|
125
|
-
|
|
123
|
+
assert.deepStrictEqual(
|
|
126
124
|
inferCommitType("Clean up stale branches"),
|
|
127
125
|
"chore",
|
|
128
126
|
"title with 'clean up' → chore"
|
|
129
127
|
);
|
|
130
128
|
|
|
131
|
-
|
|
129
|
+
assert.deepStrictEqual(
|
|
132
130
|
inferCommitType("Archive old milestones"),
|
|
133
131
|
"chore",
|
|
134
132
|
"title with 'archive' → chore"
|
|
135
133
|
);
|
|
136
134
|
|
|
137
|
-
|
|
135
|
+
assert.deepStrictEqual(
|
|
138
136
|
inferCommitType("Remove deprecated endpoints"),
|
|
139
137
|
"chore",
|
|
140
138
|
"title with 'remove' → chore"
|
|
141
139
|
);
|
|
142
140
|
|
|
143
|
-
|
|
141
|
+
assert.deepStrictEqual(
|
|
144
142
|
inferCommitType("Delete temp files"),
|
|
145
143
|
"chore",
|
|
146
144
|
"title with 'delete' → chore"
|
|
147
145
|
);
|
|
148
146
|
|
|
149
147
|
// Mixed keywords — first match wins
|
|
150
|
-
|
|
148
|
+
assert.deepStrictEqual(
|
|
151
149
|
inferCommitType("Fix and refactor the login module"),
|
|
152
150
|
"fix",
|
|
153
151
|
"mixed keywords → first match wins (fix before refactor)"
|
|
154
152
|
);
|
|
155
153
|
|
|
156
|
-
|
|
154
|
+
assert.deepStrictEqual(
|
|
157
155
|
inferCommitType("Refactor test utilities"),
|
|
158
156
|
"refactor",
|
|
159
157
|
"mixed keywords → first match wins (refactor before test)"
|
|
160
158
|
);
|
|
161
159
|
|
|
162
160
|
// Unknown / unrecognized title → feat
|
|
163
|
-
|
|
161
|
+
assert.deepStrictEqual(
|
|
164
162
|
inferCommitType("Build the new pipeline"),
|
|
165
163
|
"feat",
|
|
166
164
|
"unrecognized title → feat"
|
|
167
165
|
);
|
|
168
166
|
|
|
169
|
-
|
|
167
|
+
assert.deepStrictEqual(
|
|
170
168
|
inferCommitType(""),
|
|
171
169
|
"feat",
|
|
172
170
|
"empty title → feat"
|
|
173
171
|
);
|
|
174
172
|
|
|
175
173
|
// Word boundary: "testify" should NOT match "test"
|
|
176
|
-
|
|
174
|
+
assert.deepStrictEqual(
|
|
177
175
|
inferCommitType("Testify integration"),
|
|
178
176
|
"feat",
|
|
179
177
|
"'testify' does not match 'test' — word boundary prevents partial match"
|
|
180
178
|
);
|
|
181
179
|
|
|
182
180
|
// "documentary" should NOT match "doc" (word boundary)
|
|
183
|
-
|
|
181
|
+
assert.deepStrictEqual(
|
|
184
182
|
inferCommitType("Documentary style UI"),
|
|
185
183
|
"feat",
|
|
186
184
|
"'documentary' does not match 'doc' — word boundary prevents partial match"
|
|
187
185
|
);
|
|
188
186
|
|
|
189
187
|
// "prefix" should NOT match "fix" (word boundary)
|
|
190
|
-
|
|
188
|
+
assert.deepStrictEqual(
|
|
191
189
|
inferCommitType("Add prefix to all IDs"),
|
|
192
190
|
"feat",
|
|
193
191
|
"'prefix' does not match 'fix' — word boundary prevents partial match"
|
|
@@ -195,15 +193,14 @@ async function main(): Promise<void> {
|
|
|
195
193
|
|
|
196
194
|
// ─── inferCommitType with oneLiner ──────────────────────────────────────
|
|
197
195
|
|
|
198
|
-
console.log("\n=== inferCommitType with oneLiner ===");
|
|
199
196
|
|
|
200
|
-
|
|
197
|
+
assert.deepStrictEqual(
|
|
201
198
|
inferCommitType("implement dashboard", "Fixed rendering bug in sidebar"),
|
|
202
199
|
"fix",
|
|
203
200
|
"one-liner with 'fixed' overrides generic title → fix"
|
|
204
201
|
);
|
|
205
202
|
|
|
206
|
-
|
|
203
|
+
assert.deepStrictEqual(
|
|
207
204
|
inferCommitType("add search", "Optimized query performance with caching"),
|
|
208
205
|
"perf",
|
|
209
206
|
"one-liner with 'performance' and 'caching' → perf"
|
|
@@ -211,29 +208,27 @@ async function main(): Promise<void> {
|
|
|
211
208
|
|
|
212
209
|
// ─── buildTaskCommitMessage ─────────────────────────────────────────────
|
|
213
210
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
{
|
|
211
|
+
test('buildTaskCommitMessage', () => {
|
|
217
212
|
const msg = buildTaskCommitMessage({
|
|
218
213
|
taskId: "S01/T02",
|
|
219
214
|
taskTitle: "implement user authentication",
|
|
220
215
|
oneLiner: "Added JWT-based auth with refresh token rotation",
|
|
221
216
|
keyFiles: ["src/auth.ts", "src/middleware/jwt.ts"],
|
|
222
217
|
});
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
218
|
+
assert.ok(msg.startsWith("feat(S01/T02):"), "message starts with type(scope)");
|
|
219
|
+
assert.ok(msg.includes("JWT-based auth"), "message includes one-liner content");
|
|
220
|
+
assert.ok(msg.includes("- src/auth.ts"), "message body includes key files");
|
|
221
|
+
assert.ok(msg.includes("- src/middleware/jwt.ts"), "message body includes second key file");
|
|
222
|
+
});
|
|
228
223
|
|
|
229
224
|
{
|
|
230
225
|
const msg = buildTaskCommitMessage({
|
|
231
226
|
taskId: "S02/T01",
|
|
232
227
|
taskTitle: "fix login redirect bug",
|
|
233
228
|
});
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
229
|
+
assert.ok(msg.startsWith("fix(S02/T01):"), "infers fix type from title");
|
|
230
|
+
assert.ok(msg.includes("fix login redirect bug"), "uses task title when no one-liner");
|
|
231
|
+
assert.ok(!msg.includes("\n"), "no body when no key files");
|
|
237
232
|
}
|
|
238
233
|
|
|
239
234
|
{
|
|
@@ -242,17 +237,16 @@ async function main(): Promise<void> {
|
|
|
242
237
|
taskTitle: "add tests",
|
|
243
238
|
oneLiner: "Unit tests for auth module with coverage",
|
|
244
239
|
});
|
|
245
|
-
|
|
240
|
+
assert.ok(msg.startsWith("test(S01/T03):"), "infers test type");
|
|
246
241
|
}
|
|
247
242
|
|
|
248
243
|
// ─── RUNTIME_EXCLUSION_PATHS ───────────────────────────────────────────
|
|
249
244
|
|
|
250
|
-
console.log("\n=== RUNTIME_EXCLUSION_PATHS ===");
|
|
251
245
|
|
|
252
|
-
|
|
246
|
+
assert.deepStrictEqual(
|
|
253
247
|
RUNTIME_EXCLUSION_PATHS.length,
|
|
254
|
-
|
|
255
|
-
"exactly
|
|
248
|
+
13,
|
|
249
|
+
"exactly 13 runtime exclusion paths"
|
|
256
250
|
);
|
|
257
251
|
|
|
258
252
|
const expectedPaths = [
|
|
@@ -264,27 +258,30 @@ async function main(): Promise<void> {
|
|
|
264
258
|
".gsd/completed-units.json",
|
|
265
259
|
".gsd/STATE.md",
|
|
266
260
|
".gsd/gsd.db",
|
|
261
|
+
".gsd/gsd.db-shm",
|
|
262
|
+
".gsd/gsd.db-wal",
|
|
263
|
+
".gsd/journal/",
|
|
264
|
+
".gsd/doctor-history.jsonl",
|
|
267
265
|
".gsd/DISCUSSION-MANIFEST.json",
|
|
268
266
|
];
|
|
269
267
|
|
|
270
|
-
|
|
268
|
+
assert.deepStrictEqual(
|
|
271
269
|
[...RUNTIME_EXCLUSION_PATHS],
|
|
272
270
|
expectedPaths,
|
|
273
271
|
"paths match expected set in order"
|
|
274
272
|
);
|
|
275
273
|
|
|
276
|
-
|
|
274
|
+
assert.ok(
|
|
277
275
|
RUNTIME_EXCLUSION_PATHS.includes(".gsd/activity/"),
|
|
278
276
|
"includes .gsd/activity/"
|
|
279
277
|
);
|
|
280
|
-
|
|
278
|
+
assert.ok(
|
|
281
279
|
RUNTIME_EXCLUSION_PATHS.includes(".gsd/STATE.md"),
|
|
282
280
|
"includes .gsd/STATE.md"
|
|
283
281
|
);
|
|
284
282
|
|
|
285
283
|
// ─── runGit ────────────────────────────────────────────────────────────
|
|
286
284
|
|
|
287
|
-
console.log("\n=== runGit ===");
|
|
288
285
|
|
|
289
286
|
const tempDir = mkdtempSync(join(tmpdir(), "gsd-git-service-test-"));
|
|
290
287
|
run("git init -b main", tempDir);
|
|
@@ -293,11 +290,11 @@ async function main(): Promise<void> {
|
|
|
293
290
|
|
|
294
291
|
// runGit should work on a valid repo
|
|
295
292
|
const branch = runGit(tempDir, ["branch", "--show-current"]);
|
|
296
|
-
|
|
293
|
+
assert.deepStrictEqual(branch, "main", "runGit returns current branch");
|
|
297
294
|
|
|
298
295
|
// runGit allowFailure returns empty string on failure
|
|
299
296
|
const result = runGit(tempDir, ["log", "--oneline"], { allowFailure: true });
|
|
300
|
-
|
|
297
|
+
assert.deepStrictEqual(result, "", "runGit allowFailure returns empty on error (no commits yet)");
|
|
301
298
|
|
|
302
299
|
// runGit throws on failure without allowFailure
|
|
303
300
|
let threw = false;
|
|
@@ -305,22 +302,21 @@ async function main(): Promise<void> {
|
|
|
305
302
|
runGit(tempDir, ["log", "--oneline"]);
|
|
306
303
|
} catch (e) {
|
|
307
304
|
threw = true;
|
|
308
|
-
|
|
305
|
+
assert.ok(
|
|
309
306
|
(e as Error).message.includes("git log --oneline failed"),
|
|
310
307
|
"error message includes command and path"
|
|
311
308
|
);
|
|
312
309
|
}
|
|
313
|
-
|
|
310
|
+
assert.ok(threw, "runGit throws without allowFailure on error");
|
|
314
311
|
|
|
315
312
|
// ─── Type exports compile check ────────────────────────────────────────
|
|
316
313
|
|
|
317
|
-
console.log("\n=== Type exports ===");
|
|
318
314
|
|
|
319
315
|
// These are compile-time checks — if we got here, the types import fine
|
|
320
316
|
const _prefs: GitPreferences = { auto_push: true, remote: "origin" };
|
|
321
317
|
const _opts: CommitOptions = { message: "test" };
|
|
322
|
-
|
|
323
|
-
|
|
318
|
+
assert.ok(true, "GitPreferences type exported and usable");
|
|
319
|
+
assert.ok(true, "CommitOptions type exported and usable");
|
|
324
320
|
|
|
325
321
|
// Cleanup T01 temp dir
|
|
326
322
|
rmSync(tempDir, { recursive: true, force: true });
|
|
@@ -347,9 +343,7 @@ async function main(): Promise<void> {
|
|
|
347
343
|
|
|
348
344
|
// ─── GitServiceImpl: smart staging ─────────────────────────────────────
|
|
349
345
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
{
|
|
346
|
+
test('GitServiceImpl: smart staging', () => {
|
|
353
347
|
const repo = initTempRepo();
|
|
354
348
|
const svc = new GitServiceImpl(repo);
|
|
355
349
|
|
|
@@ -366,34 +360,32 @@ async function main(): Promise<void> {
|
|
|
366
360
|
|
|
367
361
|
const result = svc.commit({ message: "test: smart staging" });
|
|
368
362
|
|
|
369
|
-
|
|
363
|
+
assert.deepStrictEqual(result, "test: smart staging", "commit returns the commit message");
|
|
370
364
|
|
|
371
365
|
// Verify only src/code.ts is in the commit
|
|
372
366
|
const showStat = run("git show --stat --format= HEAD", repo);
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
367
|
+
assert.ok(showStat.includes("src/code.ts"), "src/code.ts is in the commit");
|
|
368
|
+
assert.ok(!showStat.includes(".gsd/activity"), ".gsd/activity/ excluded from commit");
|
|
369
|
+
assert.ok(!showStat.includes(".gsd/runtime"), ".gsd/runtime/ excluded from commit");
|
|
370
|
+
assert.ok(!showStat.includes("STATE.md"), ".gsd/STATE.md excluded from commit");
|
|
371
|
+
assert.ok(!showStat.includes("auto.lock"), ".gsd/auto.lock excluded from commit");
|
|
372
|
+
assert.ok(!showStat.includes("metrics.json"), ".gsd/metrics.json excluded from commit");
|
|
373
|
+
assert.ok(!showStat.includes(".gsd/worktrees"), ".gsd/worktrees/ excluded from commit");
|
|
380
374
|
|
|
381
375
|
// Verify runtime files are still untracked
|
|
382
376
|
// git status --short may collapse to "?? .gsd/" or show individual files
|
|
383
377
|
// Use --untracked-files=all to force individual listing
|
|
384
378
|
const statusOut = run("git status --short --untracked-files=all", repo);
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
379
|
+
assert.ok(statusOut.includes(".gsd/activity/"), "activity still untracked after commit");
|
|
380
|
+
assert.ok(statusOut.includes(".gsd/runtime/"), "runtime still untracked after commit");
|
|
381
|
+
assert.ok(statusOut.includes(".gsd/STATE.md"), "STATE.md still untracked after commit");
|
|
388
382
|
|
|
389
383
|
rmSync(repo, { recursive: true, force: true });
|
|
390
|
-
}
|
|
384
|
+
});
|
|
391
385
|
|
|
392
386
|
// ─── GitServiceImpl: smart staging excludes tracked runtime files ──────
|
|
393
387
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
{
|
|
388
|
+
test('GitServiceImpl: smart staging excludes tracked runtime files', () => {
|
|
397
389
|
// Reproduces the real bug: .gsd/ runtime files that are already tracked
|
|
398
390
|
// (in the git index) must be excluded from staging even when .gsd/ is
|
|
399
391
|
// in .gitignore. The old pathspec-exclude approach failed silently in
|
|
@@ -423,9 +415,9 @@ async function main(): Promise<void> {
|
|
|
423
415
|
|
|
424
416
|
// Verify runtime files are tracked (precondition)
|
|
425
417
|
const tracked = run("git ls-files .gsd/", repo);
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
418
|
+
assert.ok(tracked.includes("metrics.json"), "precondition: metrics.json tracked");
|
|
419
|
+
assert.ok(tracked.includes("completed-units.json"), "precondition: completed-units.json tracked");
|
|
420
|
+
assert.ok(tracked.includes("activity/log.jsonl"), "precondition: activity log tracked");
|
|
429
421
|
|
|
430
422
|
// Now modify both runtime and real files
|
|
431
423
|
createFile(repo, ".gsd/metrics.json", '{"version":2}');
|
|
@@ -436,15 +428,15 @@ async function main(): Promise<void> {
|
|
|
436
428
|
// autoCommit should commit real.ts. The first call also runs auto-cleanup
|
|
437
429
|
// which removes runtime files from the index via a dedicated commit.
|
|
438
430
|
const msg = svc.autoCommit("execute-task", "M001/S01/T01");
|
|
439
|
-
|
|
431
|
+
assert.ok(msg !== null, "autoCommit produces a commit");
|
|
440
432
|
|
|
441
433
|
const show = run("git show --stat HEAD", repo);
|
|
442
|
-
|
|
434
|
+
assert.ok(show.includes("src/real.ts"), "real files are committed");
|
|
443
435
|
|
|
444
436
|
// After the commit, runtime files must no longer be in the git index.
|
|
445
437
|
// They remain on disk but are untracked (protected by .gitignore).
|
|
446
438
|
const trackedAfter = run("git ls-files .gsd/", repo);
|
|
447
|
-
|
|
439
|
+
assert.deepStrictEqual(trackedAfter, "", "no .gsd/ runtime files remain in the index");
|
|
448
440
|
|
|
449
441
|
// Verify a second autoCommit with changed runtime files does NOT stage them
|
|
450
442
|
createFile(repo, ".gsd/metrics.json", '{"version":3}');
|
|
@@ -452,37 +444,33 @@ async function main(): Promise<void> {
|
|
|
452
444
|
createFile(repo, "src/real.ts", "third version");
|
|
453
445
|
|
|
454
446
|
const msg2 = svc.autoCommit("execute-task", "M001/S01/T02");
|
|
455
|
-
|
|
447
|
+
assert.ok(msg2 !== null, "second autoCommit produces a commit");
|
|
456
448
|
|
|
457
449
|
const show2 = run("git show --stat HEAD", repo);
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
450
|
+
assert.ok(show2.includes("src/real.ts"), "real files committed in second commit");
|
|
451
|
+
assert.ok(!show2.includes("metrics"), "metrics.json not in second commit");
|
|
452
|
+
assert.ok(!show2.includes("completed-units"), "completed-units.json not in second commit");
|
|
453
|
+
assert.ok(!show2.includes("activity"), "activity not in second commit");
|
|
462
454
|
|
|
463
455
|
rmSync(repo, { recursive: true, force: true });
|
|
464
|
-
}
|
|
456
|
+
});
|
|
465
457
|
|
|
466
458
|
// ─── GitServiceImpl: autoCommit on clean repo ──────────────────────────
|
|
467
459
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
{
|
|
460
|
+
test('GitServiceImpl: autoCommit', () => {
|
|
471
461
|
const repo = initTempRepo();
|
|
472
462
|
const svc = new GitServiceImpl(repo);
|
|
473
463
|
|
|
474
464
|
// Clean repo — autoCommit should return null
|
|
475
465
|
const cleanResult = svc.autoCommit("task", "T01");
|
|
476
|
-
|
|
466
|
+
assert.deepStrictEqual(cleanResult, null, "autoCommit on clean repo returns null");
|
|
477
467
|
|
|
478
468
|
rmSync(repo, { recursive: true, force: true });
|
|
479
|
-
}
|
|
469
|
+
});
|
|
480
470
|
|
|
481
471
|
// ─── GitServiceImpl: autoCommit on dirty repo ──────────────────────────
|
|
482
472
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
{
|
|
473
|
+
test('GitServiceImpl: autoCommit on dirty repo', () => {
|
|
486
474
|
const repo = initTempRepo();
|
|
487
475
|
const svc = new GitServiceImpl(repo);
|
|
488
476
|
|
|
@@ -490,10 +478,10 @@ async function main(): Promise<void> {
|
|
|
490
478
|
|
|
491
479
|
// Without task context, autoCommit uses generic chore message
|
|
492
480
|
const msg = svc.autoCommit("task", "T01");
|
|
493
|
-
|
|
481
|
+
assert.deepStrictEqual(msg, "chore(T01): auto-commit after task", "autoCommit returns generic format without task context");
|
|
494
482
|
|
|
495
483
|
const log = run("git log --oneline -1", repo);
|
|
496
|
-
|
|
484
|
+
assert.ok(log.includes("chore(T01): auto-commit after task"), "generic commit message is in git log");
|
|
497
485
|
|
|
498
486
|
// With task context, autoCommit uses meaningful message
|
|
499
487
|
createFile(repo, "src/auth.ts", "export function login() {}");
|
|
@@ -503,18 +491,16 @@ async function main(): Promise<void> {
|
|
|
503
491
|
oneLiner: "Added JWT-based auth with refresh token rotation",
|
|
504
492
|
keyFiles: ["src/auth.ts"],
|
|
505
493
|
});
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
494
|
+
assert.ok(msg2 !== null, "autoCommit with task context returns a message");
|
|
495
|
+
assert.ok(msg2!.startsWith("feat(S01/T02):"), "meaningful commit uses feat type and scope");
|
|
496
|
+
assert.ok(msg2!.includes("JWT-based auth"), "meaningful commit includes one-liner content");
|
|
509
497
|
|
|
510
498
|
rmSync(repo, { recursive: true, force: true });
|
|
511
|
-
}
|
|
499
|
+
});
|
|
512
500
|
|
|
513
501
|
// ─── GitServiceImpl: empty-after-staging guard ─────────────────────────
|
|
514
502
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
{
|
|
503
|
+
test('GitServiceImpl: empty-after-staging guard', () => {
|
|
518
504
|
const repo = initTempRepo();
|
|
519
505
|
const svc = new GitServiceImpl(repo);
|
|
520
506
|
|
|
@@ -522,20 +508,18 @@ async function main(): Promise<void> {
|
|
|
522
508
|
createFile(repo, ".gsd/activity/x.jsonl", "data");
|
|
523
509
|
|
|
524
510
|
const result = svc.autoCommit("task", "T02");
|
|
525
|
-
|
|
511
|
+
assert.deepStrictEqual(result, null, "autoCommit returns null when only runtime files are dirty");
|
|
526
512
|
|
|
527
513
|
// Verify no new commit was created (should still be at init commit)
|
|
528
514
|
const logCount = run("git rev-list --count HEAD", repo);
|
|
529
|
-
|
|
515
|
+
assert.deepStrictEqual(logCount, "1", "no new commit created when only runtime files changed");
|
|
530
516
|
|
|
531
517
|
rmSync(repo, { recursive: true, force: true });
|
|
532
|
-
}
|
|
518
|
+
});
|
|
533
519
|
|
|
534
520
|
// ─── GitServiceImpl: autoCommit with extraExclusions ───────────────────
|
|
535
521
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
{
|
|
522
|
+
test('GitServiceImpl: autoCommit with extraExclusions', () => {
|
|
539
523
|
const repo = initTempRepo();
|
|
540
524
|
const svc = new GitServiceImpl(repo);
|
|
541
525
|
|
|
@@ -545,21 +529,19 @@ async function main(): Promise<void> {
|
|
|
545
529
|
|
|
546
530
|
// Auto-commit with .gsd/ excluded (simulates pre-switch)
|
|
547
531
|
const msg = svc.autoCommit("pre-switch", "main", [".gsd/"]);
|
|
548
|
-
|
|
532
|
+
assert.deepStrictEqual(msg, "chore(main): auto-commit after pre-switch", "pre-switch autoCommit with .gsd/ exclusion commits");
|
|
549
533
|
|
|
550
534
|
// Verify .gsd/ file was NOT committed
|
|
551
535
|
const show = run("git show --stat HEAD", repo);
|
|
552
|
-
|
|
553
|
-
|
|
536
|
+
assert.ok(!show.includes("ROADMAP"), ".gsd/ files excluded from pre-switch auto-commit");
|
|
537
|
+
assert.ok(show.includes("feature.ts"), "non-.gsd/ files included in pre-switch auto-commit");
|
|
554
538
|
|
|
555
539
|
rmSync(repo, { recursive: true, force: true });
|
|
556
|
-
}
|
|
540
|
+
});
|
|
557
541
|
|
|
558
542
|
// ─── GitServiceImpl: autoCommit extraExclusions — only .gsd/ dirty ────
|
|
559
543
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
{
|
|
544
|
+
test('GitServiceImpl: autoCommit extraExclusions — only .gsd/ dirty', () => {
|
|
563
545
|
const repo = initTempRepo();
|
|
564
546
|
const svc = new GitServiceImpl(repo);
|
|
565
547
|
|
|
@@ -569,25 +551,23 @@ async function main(): Promise<void> {
|
|
|
569
551
|
|
|
570
552
|
// Auto-commit with .gsd/ excluded — nothing else to commit
|
|
571
553
|
const result = svc.autoCommit("pre-switch", "main", [".gsd/"]);
|
|
572
|
-
|
|
554
|
+
assert.deepStrictEqual(result, null, "autoCommit returns null when only .gsd/ files are dirty and excluded");
|
|
573
555
|
|
|
574
556
|
rmSync(repo, { recursive: true, force: true });
|
|
575
|
-
}
|
|
557
|
+
});
|
|
576
558
|
|
|
577
559
|
// ─── GitServiceImpl: commit returns null when nothing staged ───────────
|
|
578
560
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
{
|
|
561
|
+
test('GitServiceImpl: commit empty', () => {
|
|
582
562
|
const repo = initTempRepo();
|
|
583
563
|
const svc = new GitServiceImpl(repo);
|
|
584
564
|
|
|
585
565
|
// Nothing dirty, commit should return null
|
|
586
566
|
const result = svc.commit({ message: "should not commit" });
|
|
587
|
-
|
|
567
|
+
assert.deepStrictEqual(result, null, "commit returns null when nothing to stage");
|
|
588
568
|
|
|
589
569
|
rmSync(repo, { recursive: true, force: true });
|
|
590
|
-
}
|
|
570
|
+
});
|
|
591
571
|
|
|
592
572
|
// ─── Helper: create repo for branch tests ────────────────────────────
|
|
593
573
|
|
|
@@ -604,36 +584,32 @@ async function main(): Promise<void> {
|
|
|
604
584
|
|
|
605
585
|
// ─── getCurrentBranch ────────────────────────────────────────────────
|
|
606
586
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
{
|
|
587
|
+
test('Branch queries', () => {
|
|
610
588
|
const repo = initBranchTestRepo();
|
|
611
589
|
const svc = new GitServiceImpl(repo);
|
|
612
590
|
|
|
613
|
-
|
|
591
|
+
assert.deepStrictEqual(svc.getCurrentBranch(), "main", "getCurrentBranch returns main on main branch");
|
|
614
592
|
|
|
615
593
|
run("git checkout -b gsd/M001/S01", repo);
|
|
616
|
-
|
|
594
|
+
assert.deepStrictEqual(svc.getCurrentBranch(), "gsd/M001/S01", "getCurrentBranch returns slice branch name");
|
|
617
595
|
|
|
618
596
|
run("git checkout -b feature/foo", repo);
|
|
619
|
-
|
|
597
|
+
assert.deepStrictEqual(svc.getCurrentBranch(), "feature/foo", "getCurrentBranch returns feature branch name");
|
|
620
598
|
|
|
621
599
|
rmSync(repo, { recursive: true, force: true });
|
|
622
|
-
}
|
|
600
|
+
});
|
|
623
601
|
|
|
624
602
|
// ─── getMainBranch ────────────────────────────────────────────────────
|
|
625
603
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
{
|
|
604
|
+
test('getMainBranch', () => {
|
|
629
605
|
const repo = initBranchTestRepo();
|
|
630
606
|
const svc = new GitServiceImpl(repo);
|
|
631
607
|
|
|
632
608
|
// Basic case: repo has "main" branch
|
|
633
|
-
|
|
609
|
+
assert.deepStrictEqual(svc.getMainBranch(), "main", "getMainBranch returns main when main exists");
|
|
634
610
|
|
|
635
611
|
rmSync(repo, { recursive: true, force: true });
|
|
636
|
-
}
|
|
612
|
+
});
|
|
637
613
|
|
|
638
614
|
{
|
|
639
615
|
// master-only repo
|
|
@@ -646,7 +622,7 @@ async function main(): Promise<void> {
|
|
|
646
622
|
run('git commit -m "init"', repo);
|
|
647
623
|
|
|
648
624
|
const svc = new GitServiceImpl(repo);
|
|
649
|
-
|
|
625
|
+
assert.deepStrictEqual(svc.getMainBranch(), "master", "getMainBranch returns master when only master exists");
|
|
650
626
|
|
|
651
627
|
rmSync(repo, { recursive: true, force: true });
|
|
652
628
|
}
|
|
@@ -657,9 +633,7 @@ async function main(): Promise<void> {
|
|
|
657
633
|
|
|
658
634
|
// ─── createSnapshot: prefs enabled ─────────────────────────────────────
|
|
659
635
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
{
|
|
636
|
+
test('createSnapshot: enabled', () => {
|
|
663
637
|
const repo = initBranchTestRepo();
|
|
664
638
|
const svc = new GitServiceImpl(repo, { snapshots: true });
|
|
665
639
|
|
|
@@ -673,16 +647,14 @@ async function main(): Promise<void> {
|
|
|
673
647
|
|
|
674
648
|
// Verify ref exists under refs/gsd/snapshots/
|
|
675
649
|
const refs = run("git for-each-ref refs/gsd/snapshots/", repo);
|
|
676
|
-
|
|
650
|
+
assert.ok(refs.includes("refs/gsd/snapshots/gsd/M001/S01/"), "snapshot ref created under refs/gsd/snapshots/");
|
|
677
651
|
|
|
678
652
|
rmSync(repo, { recursive: true, force: true });
|
|
679
|
-
}
|
|
653
|
+
});
|
|
680
654
|
|
|
681
655
|
// ─── createSnapshot: prefs disabled ────────────────────────────────────
|
|
682
656
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
{
|
|
657
|
+
test('createSnapshot: disabled', () => {
|
|
686
658
|
const repo = initBranchTestRepo();
|
|
687
659
|
const svc = new GitServiceImpl(repo, { snapshots: false });
|
|
688
660
|
|
|
@@ -694,16 +666,14 @@ async function main(): Promise<void> {
|
|
|
694
666
|
svc.createSnapshot("gsd/M001/S01");
|
|
695
667
|
|
|
696
668
|
const refs = run("git for-each-ref refs/gsd/snapshots/", repo);
|
|
697
|
-
|
|
669
|
+
assert.deepStrictEqual(refs, "", "no snapshot ref created when prefs.snapshots is false");
|
|
698
670
|
|
|
699
671
|
rmSync(repo, { recursive: true, force: true });
|
|
700
|
-
}
|
|
672
|
+
});
|
|
701
673
|
|
|
702
674
|
// ─── runPreMergeCheck: pass ────────────────────────────────────────────
|
|
703
675
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
{
|
|
676
|
+
test('runPreMergeCheck: pass', () => {
|
|
707
677
|
const repo = initBranchTestRepo();
|
|
708
678
|
// Create package.json with passing test script
|
|
709
679
|
createFile(repo, "package.json", JSON.stringify({
|
|
@@ -716,17 +686,15 @@ async function main(): Promise<void> {
|
|
|
716
686
|
const svc = new GitServiceImpl(repo, { pre_merge_check: true });
|
|
717
687
|
const result: PreMergeCheckResult = svc.runPreMergeCheck();
|
|
718
688
|
|
|
719
|
-
|
|
720
|
-
|
|
689
|
+
assert.deepStrictEqual(result.passed, true, "runPreMergeCheck returns passed:true when tests pass");
|
|
690
|
+
assert.ok(!result.skipped, "runPreMergeCheck is not skipped when enabled");
|
|
721
691
|
|
|
722
692
|
rmSync(repo, { recursive: true, force: true });
|
|
723
|
-
}
|
|
693
|
+
});
|
|
724
694
|
|
|
725
695
|
// ─── runPreMergeCheck: fail ────────────────────────────────────────────
|
|
726
696
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
{
|
|
697
|
+
test('runPreMergeCheck: fail', () => {
|
|
730
698
|
const repo = initBranchTestRepo();
|
|
731
699
|
// Create package.json with failing test script
|
|
732
700
|
createFile(repo, "package.json", JSON.stringify({
|
|
@@ -739,17 +707,15 @@ async function main(): Promise<void> {
|
|
|
739
707
|
const svc = new GitServiceImpl(repo, { pre_merge_check: true });
|
|
740
708
|
const result: PreMergeCheckResult = svc.runPreMergeCheck();
|
|
741
709
|
|
|
742
|
-
|
|
743
|
-
|
|
710
|
+
assert.deepStrictEqual(result.passed, false, "runPreMergeCheck returns passed:false when tests fail");
|
|
711
|
+
assert.ok(!result.skipped, "runPreMergeCheck is not skipped when enabled");
|
|
744
712
|
|
|
745
713
|
rmSync(repo, { recursive: true, force: true });
|
|
746
|
-
}
|
|
714
|
+
});
|
|
747
715
|
|
|
748
716
|
// ─── runPreMergeCheck: disabled ────────────────────────────────────────
|
|
749
717
|
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
{
|
|
718
|
+
test('runPreMergeCheck: disabled', () => {
|
|
753
719
|
const repo = initBranchTestRepo();
|
|
754
720
|
createFile(repo, "package.json", JSON.stringify({
|
|
755
721
|
name: "test-disabled",
|
|
@@ -761,98 +727,86 @@ async function main(): Promise<void> {
|
|
|
761
727
|
const svc = new GitServiceImpl(repo, { pre_merge_check: false });
|
|
762
728
|
const result: PreMergeCheckResult = svc.runPreMergeCheck();
|
|
763
729
|
|
|
764
|
-
|
|
765
|
-
|
|
730
|
+
assert.deepStrictEqual(result.skipped, true, "runPreMergeCheck skipped when pre_merge_check is false");
|
|
731
|
+
assert.deepStrictEqual(result.passed, true, "runPreMergeCheck returns passed:true when skipped (no block)");
|
|
766
732
|
|
|
767
733
|
rmSync(repo, { recursive: true, force: true });
|
|
768
|
-
}
|
|
734
|
+
});
|
|
769
735
|
|
|
770
736
|
// ─── runPreMergeCheck: custom command ──────────────────────────────────
|
|
771
737
|
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
{
|
|
738
|
+
test('runPreMergeCheck: custom command', () => {
|
|
775
739
|
const repo = initBranchTestRepo();
|
|
776
740
|
// Custom command string overrides auto-detection
|
|
777
741
|
const svc = new GitServiceImpl(repo, { pre_merge_check: 'node -e "process.exit(0)"' });
|
|
778
742
|
const result: PreMergeCheckResult = svc.runPreMergeCheck();
|
|
779
743
|
|
|
780
|
-
|
|
781
|
-
|
|
744
|
+
assert.deepStrictEqual(result.passed, true, "runPreMergeCheck passes with custom command that exits 0");
|
|
745
|
+
assert.ok(!result.skipped, "custom command is not skipped");
|
|
782
746
|
|
|
783
747
|
rmSync(repo, { recursive: true, force: true });
|
|
784
|
-
}
|
|
748
|
+
});
|
|
785
749
|
|
|
786
750
|
// ─── VALID_BRANCH_NAME regex ──────────────────────────────────────────
|
|
787
751
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
{
|
|
752
|
+
test('VALID_BRANCH_NAME regex', () => {
|
|
791
753
|
// Valid branch names
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
754
|
+
assert.ok(VALID_BRANCH_NAME.test("main"), "VALID_BRANCH_NAME accepts 'main'");
|
|
755
|
+
assert.ok(VALID_BRANCH_NAME.test("master"), "VALID_BRANCH_NAME accepts 'master'");
|
|
756
|
+
assert.ok(VALID_BRANCH_NAME.test("develop"), "VALID_BRANCH_NAME accepts 'develop'");
|
|
757
|
+
assert.ok(VALID_BRANCH_NAME.test("feature/foo"), "VALID_BRANCH_NAME accepts 'feature/foo'");
|
|
758
|
+
assert.ok(VALID_BRANCH_NAME.test("release-1.0"), "VALID_BRANCH_NAME accepts 'release-1.0'");
|
|
759
|
+
assert.ok(VALID_BRANCH_NAME.test("my_branch"), "VALID_BRANCH_NAME accepts 'my_branch'");
|
|
760
|
+
assert.ok(VALID_BRANCH_NAME.test("v2.0.1"), "VALID_BRANCH_NAME accepts 'v2.0.1'");
|
|
799
761
|
|
|
800
762
|
// Invalid / injection attempts
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
}
|
|
763
|
+
assert.ok(!VALID_BRANCH_NAME.test("main; rm -rf /"), "VALID_BRANCH_NAME rejects shell injection");
|
|
764
|
+
assert.ok(!VALID_BRANCH_NAME.test("main && echo pwned"), "VALID_BRANCH_NAME rejects && injection");
|
|
765
|
+
assert.ok(!VALID_BRANCH_NAME.test(""), "VALID_BRANCH_NAME rejects empty string");
|
|
766
|
+
assert.ok(!VALID_BRANCH_NAME.test("branch name"), "VALID_BRANCH_NAME rejects spaces");
|
|
767
|
+
assert.ok(!VALID_BRANCH_NAME.test("branch`cmd`"), "VALID_BRANCH_NAME rejects backticks");
|
|
768
|
+
assert.ok(!VALID_BRANCH_NAME.test("branch$(cmd)"), "VALID_BRANCH_NAME rejects $() subshell");
|
|
769
|
+
});
|
|
808
770
|
|
|
809
771
|
// ─── getMainBranch: configured main_branch preference ──────────────────
|
|
810
772
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
{
|
|
773
|
+
test('getMainBranch: configured main_branch', () => {
|
|
814
774
|
const repo = initBranchTestRepo();
|
|
815
775
|
const svc = new GitServiceImpl(repo, { main_branch: "trunk" });
|
|
816
776
|
|
|
817
|
-
|
|
777
|
+
assert.deepStrictEqual(svc.getMainBranch(), "trunk", "getMainBranch returns configured main_branch preference");
|
|
818
778
|
|
|
819
779
|
rmSync(repo, { recursive: true, force: true });
|
|
820
|
-
}
|
|
780
|
+
});
|
|
821
781
|
|
|
822
782
|
// ─── getMainBranch: falls back to auto-detection when not set ──────────
|
|
823
783
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
{
|
|
784
|
+
test('getMainBranch: fallback to auto-detection', () => {
|
|
827
785
|
const repo = initBranchTestRepo();
|
|
828
786
|
const svc = new GitServiceImpl(repo, {});
|
|
829
787
|
|
|
830
|
-
|
|
788
|
+
assert.deepStrictEqual(svc.getMainBranch(), "main", "getMainBranch falls back to auto-detection when main_branch not set");
|
|
831
789
|
|
|
832
790
|
rmSync(repo, { recursive: true, force: true });
|
|
833
|
-
}
|
|
791
|
+
});
|
|
834
792
|
|
|
835
793
|
// ─── getMainBranch: ignores invalid branch names ───────────────────────
|
|
836
794
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
{
|
|
795
|
+
test('getMainBranch: ignores invalid branch name', () => {
|
|
840
796
|
const repo = initBranchTestRepo();
|
|
841
797
|
const svc = new GitServiceImpl(repo, { main_branch: "main; rm -rf /" });
|
|
842
798
|
|
|
843
|
-
|
|
799
|
+
assert.deepStrictEqual(svc.getMainBranch(), "main", "getMainBranch ignores invalid branch name and falls back to auto-detection");
|
|
844
800
|
|
|
845
801
|
rmSync(repo, { recursive: true, force: true });
|
|
846
|
-
}
|
|
802
|
+
});
|
|
847
803
|
|
|
848
804
|
// ─── PreMergeCheckResult type export compile check ─────────────────────
|
|
849
805
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
{
|
|
806
|
+
test('PreMergeCheckResult type export', () => {
|
|
853
807
|
const _checkResult: PreMergeCheckResult = { passed: true, skipped: false };
|
|
854
|
-
|
|
855
|
-
}
|
|
808
|
+
assert.ok(true, "PreMergeCheckResult type exported and usable");
|
|
809
|
+
});
|
|
856
810
|
|
|
857
811
|
// ═══════════════════════════════════════════════════════════════════════
|
|
858
812
|
// Integration branch — feature-branch workflow support
|
|
@@ -860,82 +814,70 @@ async function main(): Promise<void> {
|
|
|
860
814
|
|
|
861
815
|
// ─── writeIntegrationBranch / readIntegrationBranch: round-trip ────────
|
|
862
816
|
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
{
|
|
817
|
+
test('Integration branch: write and read', () => {
|
|
866
818
|
const repo = initBranchTestRepo();
|
|
867
819
|
|
|
868
820
|
// Initially no integration branch
|
|
869
|
-
|
|
821
|
+
assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), null, "readIntegrationBranch returns null when no metadata");
|
|
870
822
|
|
|
871
823
|
// Write integration branch
|
|
872
824
|
writeIntegrationBranch(repo, "M001", "f-123-new-thing");
|
|
873
|
-
|
|
825
|
+
assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), "f-123-new-thing", "readIntegrationBranch returns written branch");
|
|
874
826
|
|
|
875
827
|
rmSync(repo, { recursive: true, force: true });
|
|
876
|
-
}
|
|
828
|
+
});
|
|
877
829
|
|
|
878
830
|
// ─── writeIntegrationBranch: updates when branch changes (#300) ──────
|
|
879
831
|
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
{
|
|
832
|
+
test('Integration branch: updates on branch change', () => {
|
|
883
833
|
const repo = initBranchTestRepo();
|
|
884
834
|
|
|
885
835
|
writeIntegrationBranch(repo, "M001", "f-123-first");
|
|
886
836
|
writeIntegrationBranch(repo, "M001", "f-456-second"); // updates to new branch (#300)
|
|
887
837
|
|
|
888
|
-
|
|
838
|
+
assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), "f-456-second", "second write updates integration branch to new value");
|
|
889
839
|
|
|
890
840
|
rmSync(repo, { recursive: true, force: true });
|
|
891
|
-
}
|
|
841
|
+
});
|
|
892
842
|
|
|
893
843
|
// ─── writeIntegrationBranch: same branch is idempotent ─────────────────
|
|
894
844
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
{
|
|
845
|
+
test('Integration branch: same branch is idempotent', () => {
|
|
898
846
|
const repo = initBranchTestRepo();
|
|
899
847
|
|
|
900
848
|
writeIntegrationBranch(repo, "M001", "f-123-first");
|
|
901
849
|
writeIntegrationBranch(repo, "M001", "f-123-first"); // same branch — no-op
|
|
902
850
|
|
|
903
|
-
|
|
851
|
+
assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), "f-123-first", "same branch write is idempotent");
|
|
904
852
|
|
|
905
853
|
rmSync(repo, { recursive: true, force: true });
|
|
906
|
-
}
|
|
854
|
+
});
|
|
907
855
|
|
|
908
856
|
// ─── writeIntegrationBranch: rejects slice branches ───────────────────
|
|
909
857
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
{
|
|
858
|
+
test('Integration branch: rejects slice branches', () => {
|
|
913
859
|
const repo = initBranchTestRepo();
|
|
914
860
|
|
|
915
861
|
writeIntegrationBranch(repo, "M001", "gsd/M001/S01");
|
|
916
|
-
|
|
862
|
+
assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), null, "slice branches are not recorded as integration branch");
|
|
917
863
|
|
|
918
864
|
rmSync(repo, { recursive: true, force: true });
|
|
919
|
-
}
|
|
865
|
+
});
|
|
920
866
|
|
|
921
867
|
// ─── writeIntegrationBranch: rejects invalid branch names ─────────────
|
|
922
868
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
{
|
|
869
|
+
test('Integration branch: rejects invalid names', () => {
|
|
926
870
|
const repo = initBranchTestRepo();
|
|
927
871
|
|
|
928
872
|
writeIntegrationBranch(repo, "M001", "bad; rm -rf /");
|
|
929
|
-
|
|
873
|
+
assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), null, "invalid branch name is not recorded");
|
|
930
874
|
|
|
931
875
|
rmSync(repo, { recursive: true, force: true });
|
|
932
|
-
}
|
|
876
|
+
});
|
|
933
877
|
|
|
934
878
|
// ─── getMainBranch: uses integration branch when milestone set ────────
|
|
935
879
|
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
{
|
|
880
|
+
test('getMainBranch: integration branch from milestone metadata', () => {
|
|
939
881
|
const repo = initBranchTestRepo();
|
|
940
882
|
|
|
941
883
|
// Create a feature branch
|
|
@@ -947,20 +889,18 @@ async function main(): Promise<void> {
|
|
|
947
889
|
|
|
948
890
|
// Without milestone set, getMainBranch returns "main"
|
|
949
891
|
const svc = new GitServiceImpl(repo);
|
|
950
|
-
|
|
892
|
+
assert.deepStrictEqual(svc.getMainBranch(), "main", "getMainBranch returns main when no milestone set");
|
|
951
893
|
|
|
952
894
|
// With milestone set, getMainBranch returns the integration branch
|
|
953
895
|
svc.setMilestoneId("M001");
|
|
954
|
-
|
|
896
|
+
assert.deepStrictEqual(svc.getMainBranch(), "f-123-feature", "getMainBranch returns integration branch when milestone set");
|
|
955
897
|
|
|
956
898
|
rmSync(repo, { recursive: true, force: true });
|
|
957
|
-
}
|
|
899
|
+
});
|
|
958
900
|
|
|
959
901
|
// ─── getMainBranch: main_branch pref still takes priority ─────────────
|
|
960
902
|
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
{
|
|
903
|
+
test('getMainBranch: main_branch pref overrides integration branch', () => {
|
|
964
904
|
const repo = initBranchTestRepo();
|
|
965
905
|
|
|
966
906
|
run("git checkout -b f-123-feature", repo);
|
|
@@ -972,16 +912,14 @@ async function main(): Promise<void> {
|
|
|
972
912
|
// Explicit preference still wins
|
|
973
913
|
const svc = new GitServiceImpl(repo, { main_branch: "trunk" });
|
|
974
914
|
svc.setMilestoneId("M001");
|
|
975
|
-
|
|
915
|
+
assert.deepStrictEqual(svc.getMainBranch(), "trunk", "main_branch preference overrides integration branch");
|
|
976
916
|
|
|
977
917
|
rmSync(repo, { recursive: true, force: true });
|
|
978
|
-
}
|
|
918
|
+
});
|
|
979
919
|
|
|
980
920
|
// ─── getMainBranch: falls back when integration branch deleted ────────
|
|
981
921
|
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
{
|
|
922
|
+
test('getMainBranch: fallback when integration branch deleted', () => {
|
|
985
923
|
const repo = initBranchTestRepo();
|
|
986
924
|
|
|
987
925
|
// Write metadata pointing to a branch that doesn't exist
|
|
@@ -989,75 +927,67 @@ async function main(): Promise<void> {
|
|
|
989
927
|
|
|
990
928
|
const svc = new GitServiceImpl(repo);
|
|
991
929
|
svc.setMilestoneId("M001");
|
|
992
|
-
|
|
930
|
+
assert.deepStrictEqual(svc.getMainBranch(), "main", "getMainBranch falls back to main when integration branch no longer exists");
|
|
993
931
|
|
|
994
932
|
rmSync(repo, { recursive: true, force: true });
|
|
995
|
-
}
|
|
933
|
+
});
|
|
996
934
|
|
|
997
935
|
// ─── resolveMilestoneIntegrationBranch: recorded branch wins when it exists ───
|
|
998
936
|
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
{
|
|
937
|
+
test('Integration branch: resolver prefers recorded branch', () => {
|
|
1002
938
|
const repo = initBranchTestRepo();
|
|
1003
939
|
run("git checkout -b feature/live", repo);
|
|
1004
940
|
run("git checkout main", repo);
|
|
1005
941
|
writeIntegrationBranch(repo, "M001", "feature/live");
|
|
1006
942
|
|
|
1007
943
|
const resolved = resolveMilestoneIntegrationBranch(repo, "M001");
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
944
|
+
assert.deepStrictEqual(resolved.status, "recorded", "resolver reports recorded branch when metadata branch exists");
|
|
945
|
+
assert.deepStrictEqual(resolved.recordedBranch, "feature/live", "resolver includes recorded branch");
|
|
946
|
+
assert.deepStrictEqual(resolved.effectiveBranch, "feature/live", "resolver uses recorded branch as effective branch");
|
|
1011
947
|
|
|
1012
948
|
rmSync(repo, { recursive: true, force: true });
|
|
1013
|
-
}
|
|
949
|
+
});
|
|
1014
950
|
|
|
1015
951
|
// ─── resolveMilestoneIntegrationBranch: falls back to detected default ────────
|
|
1016
952
|
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
{
|
|
953
|
+
test('Integration branch: resolver falls back to detected default', () => {
|
|
1020
954
|
const repo = initBranchTestRepo();
|
|
1021
955
|
writeIntegrationBranch(repo, "M001", "deleted-branch");
|
|
1022
956
|
|
|
1023
957
|
const resolved = resolveMilestoneIntegrationBranch(repo, "M001");
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
958
|
+
assert.deepStrictEqual(resolved.status, "fallback", "resolver reports fallback when recorded branch is stale");
|
|
959
|
+
assert.deepStrictEqual(resolved.recordedBranch, "deleted-branch", "resolver preserves stale recorded branch for diagnostics");
|
|
960
|
+
assert.deepStrictEqual(resolved.effectiveBranch, "main", "resolver falls back to detected default branch");
|
|
961
|
+
assert.ok(
|
|
1028
962
|
resolved.reason.includes("deleted-branch") && resolved.reason.includes("main"),
|
|
1029
963
|
"resolver reason mentions stale recorded branch and fallback branch",
|
|
1030
964
|
);
|
|
1031
965
|
|
|
1032
966
|
rmSync(repo, { recursive: true, force: true });
|
|
1033
|
-
}
|
|
967
|
+
});
|
|
1034
968
|
|
|
1035
969
|
// ─── resolveMilestoneIntegrationBranch: configured main_branch is fallback ─────
|
|
1036
970
|
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
{
|
|
971
|
+
test('Integration branch: resolver uses configured fallback branch', () => {
|
|
1040
972
|
const repo = initBranchTestRepo();
|
|
1041
973
|
run("git checkout -b trunk", repo);
|
|
1042
974
|
run("git checkout main", repo);
|
|
1043
975
|
writeIntegrationBranch(repo, "M001", "deleted-branch");
|
|
1044
976
|
|
|
1045
977
|
const resolved = resolveMilestoneIntegrationBranch(repo, "M001", { main_branch: "trunk" });
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
978
|
+
assert.deepStrictEqual(resolved.status, "fallback", "resolver reports fallback when using configured main_branch");
|
|
979
|
+
assert.deepStrictEqual(resolved.effectiveBranch, "trunk", "resolver prefers configured main_branch as fallback");
|
|
980
|
+
assert.ok(
|
|
1049
981
|
resolved.reason.includes("deleted-branch") && resolved.reason.includes("trunk"),
|
|
1050
982
|
"configured fallback reason mentions stale branch and configured branch",
|
|
1051
983
|
);
|
|
1052
984
|
|
|
1053
985
|
rmSync(repo, { recursive: true, force: true });
|
|
1054
|
-
}
|
|
986
|
+
});
|
|
1055
987
|
|
|
1056
988
|
// ─── Per-milestone isolation: different milestones, different targets ──
|
|
1057
989
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
{
|
|
990
|
+
test('Integration branch: per-milestone isolation', () => {
|
|
1061
991
|
const repo = initBranchTestRepo();
|
|
1062
992
|
|
|
1063
993
|
run("git checkout -b feature-a", repo);
|
|
@@ -1070,37 +1000,33 @@ async function main(): Promise<void> {
|
|
|
1070
1000
|
const svc = new GitServiceImpl(repo);
|
|
1071
1001
|
|
|
1072
1002
|
svc.setMilestoneId("M001");
|
|
1073
|
-
|
|
1003
|
+
assert.deepStrictEqual(svc.getMainBranch(), "feature-a", "M001 integration branch is feature-a");
|
|
1074
1004
|
|
|
1075
1005
|
svc.setMilestoneId("M002");
|
|
1076
|
-
|
|
1006
|
+
assert.deepStrictEqual(svc.getMainBranch(), "feature-b", "M002 integration branch is feature-b");
|
|
1077
1007
|
|
|
1078
1008
|
svc.setMilestoneId(null);
|
|
1079
|
-
|
|
1009
|
+
assert.deepStrictEqual(svc.getMainBranch(), "main", "no milestone set → falls back to main");
|
|
1080
1010
|
|
|
1081
1011
|
rmSync(repo, { recursive: true, force: true });
|
|
1082
|
-
}
|
|
1012
|
+
});
|
|
1083
1013
|
|
|
1084
1014
|
// ─── Backward compatibility: no metadata → existing behavior ──────────
|
|
1085
1015
|
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
{
|
|
1016
|
+
test('Integration branch: backward compat', () => {
|
|
1089
1017
|
const repo = initBranchTestRepo();
|
|
1090
1018
|
const svc = new GitServiceImpl(repo);
|
|
1091
1019
|
|
|
1092
1020
|
// Set milestone but no metadata file exists
|
|
1093
1021
|
svc.setMilestoneId("M001");
|
|
1094
|
-
|
|
1022
|
+
assert.deepStrictEqual(svc.getMainBranch(), "main", "backward compat: no metadata file → falls back to main");
|
|
1095
1023
|
|
|
1096
1024
|
rmSync(repo, { recursive: true, force: true });
|
|
1097
|
-
}
|
|
1025
|
+
});
|
|
1098
1026
|
|
|
1099
1027
|
// ─── untrackRuntimeFiles: removes tracked runtime files from index ───
|
|
1100
1028
|
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
{
|
|
1029
|
+
test('untrackRuntimeFiles', async () => {
|
|
1104
1030
|
const { untrackRuntimeFiles } = await import("../gitignore.ts");
|
|
1105
1031
|
const repo = mkdtempSync(join(tmpdir(), "gsd-untrack-"));
|
|
1106
1032
|
run("git init -b main", repo);
|
|
@@ -1121,38 +1047,36 @@ async function main(): Promise<void> {
|
|
|
1121
1047
|
|
|
1122
1048
|
// Precondition: runtime files are tracked
|
|
1123
1049
|
const trackedBefore = run("git ls-files .gsd/", repo);
|
|
1124
|
-
|
|
1125
|
-
|
|
1050
|
+
assert.ok(trackedBefore.includes("completed-units.json"), "untrack: precondition — completed-units tracked");
|
|
1051
|
+
assert.ok(trackedBefore.includes("metrics.json"), "untrack: precondition — metrics tracked");
|
|
1126
1052
|
|
|
1127
1053
|
// Run untrackRuntimeFiles
|
|
1128
1054
|
untrackRuntimeFiles(repo);
|
|
1129
1055
|
|
|
1130
1056
|
// Runtime files should be removed from the index
|
|
1131
1057
|
const trackedAfter = run("git ls-files .gsd/", repo);
|
|
1132
|
-
|
|
1058
|
+
assert.deepStrictEqual(trackedAfter, "", "untrack: all runtime files removed from index");
|
|
1133
1059
|
|
|
1134
1060
|
// Non-runtime files remain tracked
|
|
1135
1061
|
const srcTracked = run("git ls-files src.ts", repo);
|
|
1136
|
-
|
|
1062
|
+
assert.ok(srcTracked.includes("src.ts"), "untrack: non-runtime files remain tracked");
|
|
1137
1063
|
|
|
1138
1064
|
// Files still exist on disk
|
|
1139
|
-
|
|
1065
|
+
assert.ok(existsSync(join(repo, ".gsd", "completed-units.json")),
|
|
1140
1066
|
"untrack: completed-units.json still on disk");
|
|
1141
|
-
|
|
1067
|
+
assert.ok(existsSync(join(repo, ".gsd", "metrics.json")),
|
|
1142
1068
|
"untrack: metrics.json still on disk");
|
|
1143
1069
|
|
|
1144
1070
|
// Idempotent — running again doesn't error
|
|
1145
1071
|
untrackRuntimeFiles(repo);
|
|
1146
|
-
|
|
1072
|
+
assert.ok(true, "untrack: second call is idempotent (no error)");
|
|
1147
1073
|
|
|
1148
1074
|
rmSync(repo, { recursive: true, force: true });
|
|
1149
|
-
}
|
|
1075
|
+
});
|
|
1150
1076
|
|
|
1151
1077
|
// ─── smartStage excludes runtime files but allows milestone artifacts ──
|
|
1152
1078
|
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
{
|
|
1079
|
+
test('smartStage excludes runtime files, allows milestone artifacts', () => {
|
|
1156
1080
|
const repo = mkdtempSync(join(tmpdir(), "gsd-smart-stage-excludes-"));
|
|
1157
1081
|
run("git init -b main", repo);
|
|
1158
1082
|
run("git config user.email test@test.com", repo);
|
|
@@ -1174,71 +1098,65 @@ async function main(): Promise<void> {
|
|
|
1174
1098
|
// smartStage excludes only runtime paths, not all of .gsd/ (#1326)
|
|
1175
1099
|
const svc = new GitServiceImpl(repo);
|
|
1176
1100
|
const msg = svc.commit({ message: "test commit" });
|
|
1177
|
-
|
|
1101
|
+
assert.ok(msg !== null, "smartStage: commit succeeds");
|
|
1178
1102
|
|
|
1179
1103
|
const committed = run("git show --name-only HEAD", repo);
|
|
1180
|
-
|
|
1104
|
+
assert.ok(committed.includes("src.ts"), "smartStage: source files ARE in commit");
|
|
1181
1105
|
// Runtime files should NOT be committed
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1106
|
+
assert.ok(!committed.includes(".gsd/STATE.md"), "smartStage: STATE.md excluded (runtime)");
|
|
1107
|
+
assert.ok(!committed.includes(".gsd/runtime/"), "smartStage: runtime/ excluded");
|
|
1108
|
+
assert.ok(!committed.includes(".gsd/activity/"), "smartStage: activity/ excluded");
|
|
1185
1109
|
// Milestone artifacts SHOULD be committed when not gitignored (#1326)
|
|
1186
|
-
|
|
1110
|
+
assert.ok(committed.includes(".gsd/milestones/"), "smartStage: milestone artifacts ARE committed");
|
|
1187
1111
|
|
|
1188
1112
|
rmSync(repo, { recursive: true, force: true });
|
|
1189
|
-
}
|
|
1113
|
+
});
|
|
1190
1114
|
|
|
1191
1115
|
// ─── writeIntegrationBranch: no commit (metadata in external storage) ──
|
|
1192
1116
|
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
{
|
|
1117
|
+
test('writeIntegrationBranch: no commit', () => {
|
|
1196
1118
|
const repo = initBranchTestRepo();
|
|
1197
1119
|
const commitsBefore = run("git rev-list --count HEAD", repo);
|
|
1198
1120
|
|
|
1199
1121
|
writeIntegrationBranch(repo, "M001", "f-123-new-thing");
|
|
1200
1122
|
|
|
1201
1123
|
// File should still be written to disk
|
|
1202
|
-
|
|
1124
|
+
assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), "f-123-new-thing",
|
|
1203
1125
|
"writeIntegrationBranch: metadata file exists on disk");
|
|
1204
1126
|
|
|
1205
1127
|
// No commit — .gsd/ is managed externally
|
|
1206
1128
|
const commitsAfter = run("git rev-list --count HEAD", repo);
|
|
1207
|
-
|
|
1129
|
+
assert.deepStrictEqual(commitsBefore, commitsAfter,
|
|
1208
1130
|
"writeIntegrationBranch: no git commit created for integration branch");
|
|
1209
1131
|
|
|
1210
1132
|
rmSync(repo, { recursive: true, force: true });
|
|
1211
|
-
}
|
|
1133
|
+
});
|
|
1212
1134
|
|
|
1213
1135
|
// ─── ensureGitignore: always adds .gsd to gitignore ──────────────────
|
|
1214
1136
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
{
|
|
1137
|
+
test('ensureGitignore: adds .gsd entry', async () => {
|
|
1218
1138
|
const { ensureGitignore } = await import("../gitignore.ts");
|
|
1219
1139
|
const repo = mkdtempSync(join(tmpdir(), "gsd-gitignore-external-state-"));
|
|
1220
1140
|
|
|
1221
1141
|
// Should add .gsd to gitignore (external state dir is a symlink)
|
|
1222
1142
|
const modified = ensureGitignore(repo);
|
|
1223
|
-
|
|
1143
|
+
assert.ok(modified, "ensureGitignore: gitignore was modified");
|
|
1224
1144
|
|
|
1225
1145
|
const { readFileSync } = await import("node:fs");
|
|
1226
1146
|
const content = readFileSync(join(repo, ".gitignore"), "utf-8");
|
|
1227
1147
|
const lines = content.split("\n").map(l => l.trim()).filter(l => l && !l.startsWith("#"));
|
|
1228
|
-
|
|
1148
|
+
assert.ok(lines.includes(".gsd"), "ensureGitignore: .gitignore contains .gsd");
|
|
1229
1149
|
|
|
1230
1150
|
// Idempotent — calling again doesn't add duplicates
|
|
1231
1151
|
const modified2 = ensureGitignore(repo);
|
|
1232
|
-
|
|
1152
|
+
assert.ok(!modified2, "ensureGitignore: second call is idempotent");
|
|
1233
1153
|
|
|
1234
1154
|
rmSync(repo, { recursive: true, force: true });
|
|
1235
|
-
}
|
|
1155
|
+
});
|
|
1236
1156
|
|
|
1237
1157
|
// ─── nativeAddAllWithExclusions: symlinked .gsd fallback ───────────────
|
|
1238
1158
|
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
{
|
|
1159
|
+
test('nativeAddAllWithExclusions: symlinked .gsd fallback', () => {
|
|
1242
1160
|
// When .gsd is a symlink, git rejects `:!.gsd/...` pathspecs with
|
|
1243
1161
|
// "fatal: pathspec '...' is beyond a symbolic link". The fix falls
|
|
1244
1162
|
// back to plain `git add -A`, which respects .gitignore.
|
|
@@ -1267,22 +1185,20 @@ async function main(): Promise<void> {
|
|
|
1267
1185
|
threw = true;
|
|
1268
1186
|
console.error(" unexpected error:", e);
|
|
1269
1187
|
}
|
|
1270
|
-
|
|
1188
|
+
assert.ok(!threw, "nativeAddAllWithExclusions does not throw with symlinked .gsd");
|
|
1271
1189
|
|
|
1272
1190
|
// Verify the real file was staged
|
|
1273
1191
|
const staged = run("git diff --cached --name-only", repo);
|
|
1274
|
-
|
|
1275
|
-
|
|
1192
|
+
assert.ok(staged.includes("src/app.ts"), "real file staged despite symlinked .gsd");
|
|
1193
|
+
assert.ok(!staged.includes(".gsd"), ".gsd content not staged");
|
|
1276
1194
|
|
|
1277
1195
|
rmSync(repo, { recursive: true, force: true });
|
|
1278
1196
|
rmSync(externalGsd, { recursive: true, force: true });
|
|
1279
|
-
}
|
|
1197
|
+
});
|
|
1280
1198
|
|
|
1281
1199
|
// ─── nativeAddAllWithExclusions: non-symlinked .gsd still works ───────
|
|
1282
1200
|
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
{
|
|
1201
|
+
test('nativeAddAllWithExclusions: non-symlinked .gsd still works', () => {
|
|
1286
1202
|
// Verify the normal (non-symlink) case still works with pathspec exclusions
|
|
1287
1203
|
const repo = initTempRepo();
|
|
1288
1204
|
|
|
@@ -1296,96 +1212,91 @@ async function main(): Promise<void> {
|
|
|
1296
1212
|
} catch {
|
|
1297
1213
|
threw = true;
|
|
1298
1214
|
}
|
|
1299
|
-
|
|
1215
|
+
assert.ok(!threw, "nativeAddAllWithExclusions works with normal .gsd directory");
|
|
1300
1216
|
|
|
1301
1217
|
const staged = run("git diff --cached --name-only", repo);
|
|
1302
|
-
|
|
1218
|
+
assert.ok(staged.includes("src/code.ts"), "real file staged with normal .gsd");
|
|
1303
1219
|
|
|
1304
1220
|
rmSync(repo, { recursive: true, force: true });
|
|
1305
|
-
}
|
|
1221
|
+
});
|
|
1306
1222
|
|
|
1307
1223
|
// ─── MergeConflictError: constructor fields ───────────────────────────────
|
|
1308
1224
|
|
|
1309
|
-
|
|
1310
|
-
{
|
|
1225
|
+
test('MergeConflictError: constructor fields', () => {
|
|
1311
1226
|
const err = new MergeConflictError(
|
|
1312
1227
|
["src/foo.ts", "src/bar.ts"],
|
|
1313
1228
|
"squash",
|
|
1314
1229
|
"gsd/M001/S01",
|
|
1315
1230
|
"main",
|
|
1316
1231
|
);
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
}
|
|
1232
|
+
assert.deepStrictEqual(err.conflictedFiles, ["src/foo.ts", "src/bar.ts"], "MergeConflictError.conflictedFiles populated");
|
|
1233
|
+
assert.deepStrictEqual(err.strategy, "squash", "MergeConflictError.strategy set");
|
|
1234
|
+
assert.deepStrictEqual(err.branch, "gsd/M001/S01", "MergeConflictError.branch set");
|
|
1235
|
+
assert.deepStrictEqual(err.mainBranch, "main", "MergeConflictError.mainBranch set");
|
|
1236
|
+
assert.deepStrictEqual(err.name, "MergeConflictError", "MergeConflictError.name is MergeConflictError");
|
|
1237
|
+
assert.ok(err.message.includes("src/foo.ts"), "MergeConflictError message lists conflicted files");
|
|
1238
|
+
assert.ok(err.message.toLowerCase().includes("squash"), "MergeConflictError message mentions strategy");
|
|
1239
|
+
assert.ok(err instanceof MergeConflictError, "MergeConflictError is an instanceof MergeConflictError");
|
|
1240
|
+
assert.ok(err instanceof Error, "MergeConflictError is an Error instance");
|
|
1241
|
+
});
|
|
1327
1242
|
|
|
1328
1243
|
// ─── Integration branch: rejects gsd/quick/* branches ────────────────────
|
|
1329
1244
|
|
|
1330
|
-
|
|
1331
|
-
{
|
|
1245
|
+
test('Integration branch: rejects gsd/quick/* branches', () => {
|
|
1332
1246
|
const repo = initBranchTestRepo();
|
|
1333
1247
|
|
|
1334
1248
|
writeIntegrationBranch(repo, "M001", "gsd/quick/1234-some-task");
|
|
1335
|
-
|
|
1249
|
+
assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), null, "gsd/quick/* branches are not recorded as integration branch");
|
|
1336
1250
|
|
|
1337
1251
|
rmSync(repo, { recursive: true, force: true });
|
|
1338
|
-
}
|
|
1252
|
+
});
|
|
1339
1253
|
|
|
1340
1254
|
// ─── Integration branch: resolver returns missing when no metadata ────────
|
|
1341
1255
|
|
|
1342
|
-
|
|
1343
|
-
{
|
|
1256
|
+
test('Integration branch: resolver returns missing when no metadata', () => {
|
|
1344
1257
|
const repo = initBranchTestRepo();
|
|
1345
1258
|
|
|
1346
1259
|
// No writeIntegrationBranch call — no metadata file exists
|
|
1347
1260
|
const resolved = resolveMilestoneIntegrationBranch(repo, "M999");
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1261
|
+
assert.deepStrictEqual(resolved.status, "missing", "resolver reports missing when no metadata file");
|
|
1262
|
+
assert.deepStrictEqual(resolved.recordedBranch, null, "resolver recordedBranch is null when no metadata");
|
|
1263
|
+
assert.deepStrictEqual(resolved.effectiveBranch, null, "resolver effectiveBranch is null when no metadata");
|
|
1264
|
+
assert.ok(resolved.reason.includes("M999"), "resolver reason mentions the milestone ID");
|
|
1352
1265
|
|
|
1353
1266
|
rmSync(repo, { recursive: true, force: true });
|
|
1354
|
-
}
|
|
1267
|
+
});
|
|
1355
1268
|
|
|
1356
1269
|
// ─── Integration branch: resolver missing when both recorded and configured branches gone ───
|
|
1357
1270
|
|
|
1358
|
-
|
|
1359
|
-
{
|
|
1271
|
+
test('Integration branch: resolver missing when both recorded and configured branches gone', () => {
|
|
1360
1272
|
const repo = initBranchTestRepo();
|
|
1361
1273
|
|
|
1362
1274
|
// Record a branch that doesn't exist
|
|
1363
1275
|
writeIntegrationBranch(repo, "M001", "deleted-feature");
|
|
1364
1276
|
// configured main_branch also doesn't exist
|
|
1365
1277
|
const resolved = resolveMilestoneIntegrationBranch(repo, "M001", { main_branch: "nonexistent-branch" });
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1278
|
+
assert.deepStrictEqual(resolved.status, "missing", "resolver reports missing when recorded branch and configured main_branch both absent");
|
|
1279
|
+
assert.deepStrictEqual(resolved.recordedBranch, "deleted-feature", "resolver preserves stale recorded branch");
|
|
1280
|
+
assert.deepStrictEqual(resolved.effectiveBranch, null, "resolver effectiveBranch is null when no safe fallback");
|
|
1281
|
+
assert.ok(
|
|
1370
1282
|
resolved.reason.includes("deleted-feature") && resolved.reason.includes("nonexistent-branch"),
|
|
1371
1283
|
"reason mentions both stale branch and unavailable configured branch",
|
|
1372
1284
|
);
|
|
1373
1285
|
|
|
1374
1286
|
rmSync(repo, { recursive: true, force: true });
|
|
1375
|
-
}
|
|
1287
|
+
});
|
|
1376
1288
|
|
|
1377
1289
|
// ─── buildTaskCommitMessage: issueNumber appends Resolves trailer ─────────
|
|
1378
1290
|
|
|
1379
|
-
|
|
1380
|
-
{
|
|
1291
|
+
test('buildTaskCommitMessage: issueNumber appends Resolves trailer', () => {
|
|
1381
1292
|
const msg = buildTaskCommitMessage({
|
|
1382
1293
|
taskId: "S01/T03",
|
|
1383
1294
|
taskTitle: "fix login redirect",
|
|
1384
1295
|
issueNumber: 42,
|
|
1385
1296
|
});
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
}
|
|
1297
|
+
assert.ok(msg.includes("Resolves #42"), "buildTaskCommitMessage includes Resolves #N trailer when issueNumber is set");
|
|
1298
|
+
assert.ok(msg.startsWith("fix(S01/T03):"), "buildTaskCommitMessage infers fix type");
|
|
1299
|
+
});
|
|
1389
1300
|
|
|
1390
1301
|
{
|
|
1391
1302
|
// No issueNumber — no Resolves trailer
|
|
@@ -1393,29 +1304,26 @@ async function main(): Promise<void> {
|
|
|
1393
1304
|
taskId: "S01/T04",
|
|
1394
1305
|
taskTitle: "add dashboard widget",
|
|
1395
1306
|
});
|
|
1396
|
-
|
|
1307
|
+
assert.ok(!msg.includes("Resolves"), "buildTaskCommitMessage omits Resolves trailer when issueNumber is absent");
|
|
1397
1308
|
}
|
|
1398
1309
|
|
|
1399
1310
|
// ─── runPreMergeCheck: skips when no package.json ────────────────────────
|
|
1400
1311
|
|
|
1401
|
-
|
|
1402
|
-
{
|
|
1312
|
+
test('runPreMergeCheck: skips when no package.json', () => {
|
|
1403
1313
|
const repo = initBranchTestRepo();
|
|
1404
1314
|
// No package.json created — auto-detect should skip gracefully
|
|
1405
1315
|
const svc = new GitServiceImpl(repo, { pre_merge_check: true });
|
|
1406
1316
|
const result: PreMergeCheckResult = svc.runPreMergeCheck();
|
|
1407
1317
|
|
|
1408
|
-
|
|
1409
|
-
|
|
1318
|
+
assert.deepStrictEqual(result.passed, true, "runPreMergeCheck passes when no package.json (skip)");
|
|
1319
|
+
assert.deepStrictEqual(result.skipped, true, "runPreMergeCheck skips when no package.json found");
|
|
1410
1320
|
|
|
1411
1321
|
rmSync(repo, { recursive: true, force: true });
|
|
1412
|
-
}
|
|
1322
|
+
});
|
|
1413
1323
|
|
|
1414
1324
|
// ─── autoCommit: symlinked .gsd does NOT stage milestone artifacts (#2247) ──
|
|
1415
1325
|
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
{
|
|
1326
|
+
test('autoCommit: symlinked .gsd does NOT stage milestone artifacts (#2247)', () => {
|
|
1419
1327
|
// When .gsd is a symlink (external state project), .gsd/ files live outside
|
|
1420
1328
|
// the repo by design. smartStage() must NOT force-stage them into git — the
|
|
1421
1329
|
// .gitignore exclusion is correct and intentional.
|
|
@@ -1444,21 +1352,14 @@ async function main(): Promise<void> {
|
|
|
1444
1352
|
|
|
1445
1353
|
const svc = new GitServiceImpl(repo);
|
|
1446
1354
|
const msg = svc.autoCommit("complete-milestone", "M009");
|
|
1447
|
-
|
|
1355
|
+
assert.ok(msg !== null, "symlink autoCommit: commit succeeds");
|
|
1448
1356
|
|
|
1449
1357
|
const committed = run("git show --name-only HEAD", repo);
|
|
1450
|
-
|
|
1451
|
-
|
|
1358
|
+
assert.ok(committed.includes("src/feature.ts"), "symlink autoCommit: source file committed");
|
|
1359
|
+
assert.ok(!committed.includes(".gsd/milestones/"),
|
|
1452
1360
|
"symlink autoCommit: .gsd/milestones/ files are NOT staged (external state stays external)");
|
|
1453
1361
|
|
|
1454
1362
|
try { rmSync(repo, { recursive: true, force: true }); } catch {}
|
|
1455
1363
|
try { rmSync(externalGsd, { recursive: true, force: true }); } catch {}
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
report();
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
|
-
main().catch((error) => {
|
|
1462
|
-
console.error(error);
|
|
1463
|
-
process.exit(1);
|
|
1364
|
+
});
|
|
1464
1365
|
});
|