gsd-pi 2.38.0-dev.eeb3520 → 2.39.0-dev.20aba06
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 +15 -11
- package/dist/app-paths.js +1 -1
- package/dist/cli.js +9 -0
- package/dist/extension-discovery.d.ts +5 -3
- package/dist/extension-discovery.js +14 -9
- package/dist/extension-registry.js +2 -2
- package/dist/remote-questions-config.js +2 -2
- package/dist/resource-loader.js +100 -3
- package/dist/resources/extensions/async-jobs/index.js +10 -0
- package/dist/resources/extensions/browser-tools/index.js +3 -1
- package/dist/resources/extensions/browser-tools/package.json +3 -1
- package/dist/resources/extensions/browser-tools/tools/verify.js +97 -0
- package/dist/resources/extensions/cmux/index.js +55 -1
- package/dist/resources/extensions/context7/package.json +1 -1
- package/dist/resources/extensions/get-secrets-from-user.js +5 -24
- package/dist/resources/extensions/github-sync/cli.js +284 -0
- package/dist/resources/extensions/github-sync/index.js +73 -0
- package/dist/resources/extensions/github-sync/mapping.js +67 -0
- package/dist/resources/extensions/github-sync/sync.js +424 -0
- package/dist/resources/extensions/github-sync/templates.js +118 -0
- package/dist/resources/extensions/github-sync/types.js +7 -0
- package/dist/resources/extensions/google-search/package.json +3 -1
- package/dist/resources/extensions/gsd/auto/session.js +6 -23
- package/dist/resources/extensions/gsd/auto-dashboard.js +7 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +8 -9
- package/dist/resources/extensions/gsd/auto-loop.js +923 -787
- package/dist/resources/extensions/gsd/auto-post-unit.js +107 -70
- package/dist/resources/extensions/gsd/auto-prompts.js +205 -51
- package/dist/resources/extensions/gsd/auto-start.js +19 -3
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +13 -5
- package/dist/resources/extensions/gsd/auto-worktree.js +3 -3
- package/dist/resources/extensions/gsd/auto.js +149 -100
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +126 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +233 -0
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +59 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +38 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +156 -0
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +46 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +300 -0
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +38 -0
- package/dist/resources/extensions/gsd/captures.js +9 -1
- package/dist/resources/extensions/gsd/commands/catalog.js +278 -0
- package/dist/resources/extensions/gsd/commands/context.js +84 -0
- package/dist/resources/extensions/gsd/commands/dispatcher.js +21 -0
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +72 -0
- package/dist/resources/extensions/gsd/commands/handlers/core.js +246 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +166 -0
- package/dist/resources/extensions/gsd/commands/handlers/parallel.js +94 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +102 -0
- package/dist/resources/extensions/gsd/commands/index.js +11 -0
- package/dist/resources/extensions/gsd/commands-extensions.js +3 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +17 -4
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
- package/dist/resources/extensions/gsd/commands.js +8 -1169
- package/dist/resources/extensions/gsd/context-budget.js +2 -10
- package/dist/resources/extensions/gsd/dashboard-overlay.js +9 -0
- package/dist/resources/extensions/gsd/detection.js +1 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -2
- package/dist/resources/extensions/gsd/doctor-checks.js +82 -0
- package/dist/resources/extensions/gsd/doctor-environment.js +78 -0
- package/dist/resources/extensions/gsd/doctor-format.js +15 -0
- package/dist/resources/extensions/gsd/doctor-proactive.js +80 -10
- package/dist/resources/extensions/gsd/doctor-providers.js +30 -11
- package/dist/resources/extensions/gsd/doctor.js +234 -12
- package/dist/resources/extensions/gsd/env-utils.js +29 -0
- package/dist/resources/extensions/gsd/exit-command.js +2 -1
- package/dist/resources/extensions/gsd/export-html.js +46 -0
- package/dist/resources/extensions/gsd/export.js +1 -1
- package/dist/resources/extensions/gsd/files.js +48 -9
- package/dist/resources/extensions/gsd/forensics.js +1 -1
- package/dist/resources/extensions/gsd/git-service.js +30 -12
- package/dist/resources/extensions/gsd/gitignore.js +16 -3
- package/dist/resources/extensions/gsd/guided-flow.js +149 -38
- package/dist/resources/extensions/gsd/health-widget-core.js +32 -70
- package/dist/resources/extensions/gsd/health-widget.js +4 -87
- package/dist/resources/extensions/gsd/index.js +4 -1111
- package/dist/resources/extensions/gsd/migrate/parsers.js +1 -1
- package/dist/resources/extensions/gsd/migrate-external.js +18 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +37 -0
- package/dist/resources/extensions/gsd/package.json +1 -1
- package/dist/resources/extensions/gsd/paths.js +3 -0
- package/dist/resources/extensions/gsd/preferences-models.js +0 -12
- package/dist/resources/extensions/gsd/preferences-types.js +1 -1
- package/dist/resources/extensions/gsd/preferences-validation.js +59 -11
- package/dist/resources/extensions/gsd/preferences.js +22 -11
- package/dist/resources/extensions/gsd/progress-score.js +20 -1
- package/dist/resources/extensions/gsd/prompt-loader.js +6 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -3
- package/dist/resources/extensions/gsd/prompts/forensics.md +121 -46
- package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
- 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/guided-plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -8
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +28 -11
- package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/dist/resources/extensions/gsd/repo-identity.js +21 -4
- package/dist/resources/extensions/gsd/resource-version.js +2 -1
- package/dist/resources/extensions/gsd/roadmap-mutations.js +24 -0
- package/dist/resources/extensions/gsd/state.js +42 -23
- package/dist/resources/extensions/gsd/templates/runtime.md +21 -0
- package/dist/resources/extensions/gsd/templates/task-plan.md +3 -0
- package/dist/resources/extensions/gsd/visualizer-data.js +27 -2
- package/dist/resources/extensions/gsd/visualizer-views.js +52 -0
- package/dist/resources/extensions/gsd/worktree.js +35 -16
- package/dist/resources/extensions/mcp-client/index.js +14 -1
- package/dist/resources/extensions/remote-questions/status.js +4 -1
- package/dist/resources/extensions/remote-questions/store.js +4 -1
- package/dist/resources/extensions/search-the-web/provider.js +2 -1
- package/dist/resources/extensions/shared/frontmatter.js +1 -1
- package/dist/resources/extensions/subagent/index.js +12 -3
- package/dist/resources/extensions/subagent/isolation.js +2 -1
- package/dist/resources/extensions/ttsr/rule-loader.js +2 -1
- package/dist/resources/extensions/universal-config/package.json +1 -1
- package/dist/welcome-screen.d.ts +13 -0
- package/dist/welcome-screen.js +97 -0
- package/package.json +1 -1
- package/packages/pi-ai/dist/utils/oauth/anthropic.js +2 -2
- package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -1
- package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -2
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +12 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +107 -24
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +205 -7
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.js +8 -4
- package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skill-tool.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js +70 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +8 -2
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +244 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +58 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +54 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js +63 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +38 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +15 -457
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +122 -23
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +223 -7
- package/packages/pi-coding-agent/src/core/package-manager.ts +8 -4
- package/packages/pi-coding-agent/src/core/skill-tool.test.ts +89 -0
- package/packages/pi-coding-agent/src/core/skills.ts +11 -2
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +302 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +59 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +68 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/model-controller.ts +71 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +37 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +18 -510
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/index.ts +11 -0
- package/src/resources/extensions/browser-tools/index.ts +3 -0
- package/src/resources/extensions/browser-tools/tools/verify.ts +117 -0
- package/src/resources/extensions/cmux/index.ts +57 -1
- package/src/resources/extensions/get-secrets-from-user.ts +5 -24
- package/src/resources/extensions/github-sync/cli.ts +364 -0
- package/src/resources/extensions/github-sync/index.ts +93 -0
- package/src/resources/extensions/github-sync/mapping.ts +81 -0
- package/src/resources/extensions/github-sync/sync.ts +556 -0
- package/src/resources/extensions/github-sync/templates.ts +183 -0
- package/src/resources/extensions/github-sync/tests/cli.test.ts +20 -0
- package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +39 -0
- package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
- package/src/resources/extensions/github-sync/tests/templates.test.ts +110 -0
- package/src/resources/extensions/github-sync/types.ts +47 -0
- package/src/resources/extensions/gsd/auto/session.ts +7 -25
- package/src/resources/extensions/gsd/auto-dashboard.ts +10 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +7 -9
- package/src/resources/extensions/gsd/auto-loop.ts +1285 -1138
- package/src/resources/extensions/gsd/auto-post-unit.ts +90 -46
- package/src/resources/extensions/gsd/auto-prompts.ts +250 -53
- package/src/resources/extensions/gsd/auto-start.ts +24 -3
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +15 -4
- package/src/resources/extensions/gsd/auto-worktree.ts +3 -3
- package/src/resources/extensions/gsd/auto.ts +152 -111
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +142 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +238 -0
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +90 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +46 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +167 -0
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +55 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +340 -0
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +51 -0
- package/src/resources/extensions/gsd/captures.ts +10 -1
- package/src/resources/extensions/gsd/commands/catalog.ts +301 -0
- package/src/resources/extensions/gsd/commands/context.ts +101 -0
- package/src/resources/extensions/gsd/commands/dispatcher.ts +32 -0
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +74 -0
- package/src/resources/extensions/gsd/commands/handlers/core.ts +274 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +169 -0
- package/src/resources/extensions/gsd/commands/handlers/parallel.ts +118 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +109 -0
- package/src/resources/extensions/gsd/commands/index.ts +14 -0
- package/src/resources/extensions/gsd/commands-extensions.ts +4 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +18 -3
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
- package/src/resources/extensions/gsd/commands.ts +10 -1307
- package/src/resources/extensions/gsd/context-budget.ts +2 -12
- package/src/resources/extensions/gsd/dashboard-overlay.ts +10 -0
- package/src/resources/extensions/gsd/detection.ts +2 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -2
- package/src/resources/extensions/gsd/doctor-checks.ts +75 -0
- package/src/resources/extensions/gsd/doctor-environment.ts +82 -1
- package/src/resources/extensions/gsd/doctor-format.ts +20 -0
- package/src/resources/extensions/gsd/doctor-proactive.ts +106 -10
- package/src/resources/extensions/gsd/doctor-providers.ts +30 -9
- package/src/resources/extensions/gsd/doctor-types.ts +16 -1
- package/src/resources/extensions/gsd/doctor.ts +243 -14
- package/src/resources/extensions/gsd/env-utils.ts +31 -0
- package/src/resources/extensions/gsd/exit-command.ts +2 -2
- package/src/resources/extensions/gsd/export-html.ts +51 -0
- package/src/resources/extensions/gsd/export.ts +1 -1
- package/src/resources/extensions/gsd/files.ts +51 -11
- package/src/resources/extensions/gsd/forensics.ts +1 -1
- package/src/resources/extensions/gsd/git-service.ts +44 -10
- package/src/resources/extensions/gsd/gitignore.ts +17 -3
- package/src/resources/extensions/gsd/guided-flow.ts +177 -44
- package/src/resources/extensions/gsd/health-widget-core.ts +28 -80
- package/src/resources/extensions/gsd/health-widget.ts +4 -89
- package/src/resources/extensions/gsd/index.ts +12 -1307
- package/src/resources/extensions/gsd/migrate/parsers.ts +1 -1
- package/src/resources/extensions/gsd/migrate-external.ts +18 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +37 -0
- package/src/resources/extensions/gsd/paths.ts +4 -0
- package/src/resources/extensions/gsd/preferences-models.ts +0 -12
- package/src/resources/extensions/gsd/preferences-types.ts +4 -4
- package/src/resources/extensions/gsd/preferences-validation.ts +51 -11
- package/src/resources/extensions/gsd/preferences.ts +25 -11
- package/src/resources/extensions/gsd/progress-score.ts +23 -0
- package/src/resources/extensions/gsd/prompt-loader.ts +7 -2
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/src/resources/extensions/gsd/prompts/execute-task.md +5 -3
- package/src/resources/extensions/gsd/prompts/forensics.md +121 -46
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
- 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/guided-plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/queue.md +4 -8
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +28 -11
- package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/src/resources/extensions/gsd/repo-identity.ts +23 -4
- package/src/resources/extensions/gsd/resource-version.ts +3 -1
- package/src/resources/extensions/gsd/roadmap-mutations.ts +29 -0
- package/src/resources/extensions/gsd/state.ts +39 -21
- package/src/resources/extensions/gsd/templates/runtime.md +21 -0
- package/src/resources/extensions/gsd/templates/task-plan.md +3 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +21 -18
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +135 -77
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/cmux.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +266 -0
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +86 -3
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +16 -54
- package/src/resources/extensions/gsd/tests/parsers.test.ts +131 -14
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -7
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +16 -16
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +16 -4
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +10 -10
- package/src/resources/extensions/gsd/tests/worktree.test.ts +47 -0
- package/src/resources/extensions/gsd/types.ts +18 -1
- package/src/resources/extensions/gsd/verification-evidence.ts +16 -0
- package/src/resources/extensions/gsd/visualizer-data.ts +52 -2
- package/src/resources/extensions/gsd/visualizer-views.ts +58 -0
- package/src/resources/extensions/gsd/worktree.ts +35 -15
- package/src/resources/extensions/mcp-client/index.ts +17 -1
- package/src/resources/extensions/remote-questions/status.ts +5 -1
- package/src/resources/extensions/remote-questions/store.ts +5 -1
- package/src/resources/extensions/search-the-web/provider.ts +2 -1
- package/src/resources/extensions/shared/frontmatter.ts +1 -1
- package/src/resources/extensions/subagent/index.ts +12 -3
- package/src/resources/extensions/subagent/isolation.ts +3 -1
- package/src/resources/extensions/ttsr/rule-loader.ts +3 -1
- package/dist/resources/extensions/gsd/prompt-compressor.js +0 -393
- package/dist/resources/extensions/gsd/semantic-chunker.js +0 -254
- package/dist/resources/extensions/gsd/summary-distiller.js +0 -212
- package/src/resources/extensions/gsd/prompt-compressor.ts +0 -508
- package/src/resources/extensions/gsd/semantic-chunker.ts +0 -336
- package/src/resources/extensions/gsd/summary-distiller.ts +0 -258
- package/src/resources/extensions/gsd/tests/context-compression.test.ts +0 -193
- package/src/resources/extensions/gsd/tests/prompt-compressor.test.ts +0 -529
- package/src/resources/extensions/gsd/tests/semantic-chunker.test.ts +0 -426
- package/src/resources/extensions/gsd/tests/summary-distiller.test.ts +0 -323
- package/src/resources/extensions/gsd/tests/token-optimization-benchmark.test.ts +0 -1272
- package/src/resources/extensions/gsd/tests/token-optimization-prefs.test.ts +0 -164
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin wrapper around the `gh` CLI.
|
|
3
|
+
*
|
|
4
|
+
* Every public function returns `GhResult<T>` — never throws.
|
|
5
|
+
* Uses `execFileSync` (not `execSync`) for safety.
|
|
6
|
+
*/
|
|
7
|
+
import { execFileSync } from "node:child_process";
|
|
8
|
+
function ok(data) {
|
|
9
|
+
return { ok: true, data };
|
|
10
|
+
}
|
|
11
|
+
function fail(error) {
|
|
12
|
+
return { ok: false, error };
|
|
13
|
+
}
|
|
14
|
+
// ─── gh Availability ────────────────────────────────────────────────────────
|
|
15
|
+
let _ghAvailable = null;
|
|
16
|
+
export function ghIsAvailable() {
|
|
17
|
+
if (_ghAvailable !== null)
|
|
18
|
+
return _ghAvailable;
|
|
19
|
+
try {
|
|
20
|
+
execFileSync("gh", ["--version"], {
|
|
21
|
+
encoding: "utf-8",
|
|
22
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
23
|
+
timeout: 5_000,
|
|
24
|
+
});
|
|
25
|
+
_ghAvailable = true;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
_ghAvailable = false;
|
|
29
|
+
}
|
|
30
|
+
return _ghAvailable;
|
|
31
|
+
}
|
|
32
|
+
/** Reset cached availability (for testing). */
|
|
33
|
+
export function _resetGhCache() {
|
|
34
|
+
_ghAvailable = null;
|
|
35
|
+
}
|
|
36
|
+
// ─── Rate Limit Check ───────────────────────────────────────────────────────
|
|
37
|
+
let _rateLimitCheckedAt = 0;
|
|
38
|
+
let _rateLimitOk = true;
|
|
39
|
+
const RATE_LIMIT_CHECK_INTERVAL_MS = 300_000; // 5 minutes
|
|
40
|
+
export function ghHasRateLimit(cwd) {
|
|
41
|
+
const now = Date.now();
|
|
42
|
+
if (now - _rateLimitCheckedAt < RATE_LIMIT_CHECK_INTERVAL_MS)
|
|
43
|
+
return _rateLimitOk;
|
|
44
|
+
_rateLimitCheckedAt = now;
|
|
45
|
+
try {
|
|
46
|
+
const raw = execFileSync("gh", ["api", "rate_limit", "--jq", ".rate.remaining"], {
|
|
47
|
+
cwd,
|
|
48
|
+
encoding: "utf-8",
|
|
49
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
50
|
+
timeout: 10_000,
|
|
51
|
+
}).trim();
|
|
52
|
+
const remaining = parseInt(raw, 10);
|
|
53
|
+
_rateLimitOk = Number.isFinite(remaining) && remaining >= 100;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Can't check — assume OK so we don't silently disable sync
|
|
57
|
+
_rateLimitOk = true;
|
|
58
|
+
}
|
|
59
|
+
return _rateLimitOk;
|
|
60
|
+
}
|
|
61
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
62
|
+
const GH_TIMEOUT = 15_000;
|
|
63
|
+
const MAX_BODY_LENGTH = 65_000;
|
|
64
|
+
function truncateBody(body) {
|
|
65
|
+
if (body.length <= MAX_BODY_LENGTH)
|
|
66
|
+
return body;
|
|
67
|
+
return body.slice(0, MAX_BODY_LENGTH) + "\n\n---\n*Body truncated (exceeded 65K characters)*";
|
|
68
|
+
}
|
|
69
|
+
function runGh(args, cwd) {
|
|
70
|
+
try {
|
|
71
|
+
const stdout = execFileSync("gh", args, {
|
|
72
|
+
cwd,
|
|
73
|
+
encoding: "utf-8",
|
|
74
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
75
|
+
timeout: GH_TIMEOUT,
|
|
76
|
+
}).trim();
|
|
77
|
+
return ok(stdout);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
81
|
+
return fail(msg);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function runGhJson(args, cwd) {
|
|
85
|
+
const result = runGh(args, cwd);
|
|
86
|
+
if (!result.ok)
|
|
87
|
+
return fail(result.error);
|
|
88
|
+
try {
|
|
89
|
+
return ok(JSON.parse(result.data));
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return fail(`Failed to parse JSON: ${result.data}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// ─── Repo Detection ─────────────────────────────────────────────────────────
|
|
96
|
+
export function ghDetectRepo(cwd) {
|
|
97
|
+
const result = runGh(["repo", "view", "--json", "nameWithOwner", "--jq", ".nameWithOwner"], cwd);
|
|
98
|
+
if (!result.ok)
|
|
99
|
+
return fail(result.error);
|
|
100
|
+
const repo = result.data.trim();
|
|
101
|
+
if (!repo || !repo.includes("/"))
|
|
102
|
+
return fail("Could not detect repo");
|
|
103
|
+
return ok(repo);
|
|
104
|
+
}
|
|
105
|
+
export function ghCreateIssue(cwd, opts) {
|
|
106
|
+
const args = [
|
|
107
|
+
"issue", "create",
|
|
108
|
+
"--repo", opts.repo,
|
|
109
|
+
"--title", opts.title,
|
|
110
|
+
"--body", truncateBody(opts.body),
|
|
111
|
+
];
|
|
112
|
+
if (opts.labels?.length) {
|
|
113
|
+
args.push("--label", opts.labels.join(","));
|
|
114
|
+
}
|
|
115
|
+
if (opts.milestone) {
|
|
116
|
+
args.push("--milestone", String(opts.milestone));
|
|
117
|
+
}
|
|
118
|
+
const result = runGh(args, cwd);
|
|
119
|
+
if (!result.ok)
|
|
120
|
+
return fail(result.error);
|
|
121
|
+
// gh issue create returns the URL; extract issue number
|
|
122
|
+
const match = result.data.match(/\/issues\/(\d+)/);
|
|
123
|
+
if (!match)
|
|
124
|
+
return fail(`Could not parse issue number from: ${result.data}`);
|
|
125
|
+
const issueNumber = parseInt(match[1], 10);
|
|
126
|
+
// If parent specified, add as sub-issue via GraphQL
|
|
127
|
+
if (opts.parentIssue) {
|
|
128
|
+
ghAddSubIssue(cwd, opts.repo, opts.parentIssue, issueNumber);
|
|
129
|
+
}
|
|
130
|
+
return ok(issueNumber);
|
|
131
|
+
}
|
|
132
|
+
export function ghCloseIssue(cwd, repo, issueNumber, comment) {
|
|
133
|
+
if (comment) {
|
|
134
|
+
ghAddComment(cwd, repo, issueNumber, comment);
|
|
135
|
+
}
|
|
136
|
+
const result = runGh(["issue", "close", String(issueNumber), "--repo", repo], cwd);
|
|
137
|
+
if (!result.ok)
|
|
138
|
+
return fail(result.error);
|
|
139
|
+
return ok(undefined);
|
|
140
|
+
}
|
|
141
|
+
export function ghAddComment(cwd, repo, issueNumber, body) {
|
|
142
|
+
const result = runGh(["issue", "comment", String(issueNumber), "--repo", repo, "--body", truncateBody(body)], cwd);
|
|
143
|
+
if (!result.ok)
|
|
144
|
+
return fail(result.error);
|
|
145
|
+
return ok(undefined);
|
|
146
|
+
}
|
|
147
|
+
// ─── Sub-Issues (GraphQL) ───────────────────────────────────────────────────
|
|
148
|
+
function ghAddSubIssue(cwd, repo, parentNumber, childNumber) {
|
|
149
|
+
// Get node IDs for both issues
|
|
150
|
+
const parentResult = runGhJson(["api", `repos/${repo}/issues/${parentNumber}`, "--jq", "{id: .node_id}"], cwd);
|
|
151
|
+
const childResult = runGhJson(["api", `repos/${repo}/issues/${childNumber}`, "--jq", "{id: .node_id}"], cwd);
|
|
152
|
+
if (!parentResult.ok || !childResult.ok) {
|
|
153
|
+
return fail("Could not resolve issue node IDs for sub-issue linking");
|
|
154
|
+
}
|
|
155
|
+
const mutation = `mutation { addSubIssue(input: { issueId: "${parentResult.data.id}", subIssueId: "${childResult.data.id}" }) { issue { id } } }`;
|
|
156
|
+
return runGh(["api", "graphql", "-f", `query=${mutation}`], cwd);
|
|
157
|
+
}
|
|
158
|
+
// ─── Milestones ─────────────────────────────────────────────────────────────
|
|
159
|
+
export function ghCreateMilestone(cwd, repo, title, description) {
|
|
160
|
+
const result = runGhJson([
|
|
161
|
+
"api", `repos/${repo}/milestones`,
|
|
162
|
+
"-X", "POST",
|
|
163
|
+
"-f", `title=${title}`,
|
|
164
|
+
"-f", `description=${truncateBody(description)}`,
|
|
165
|
+
"-f", "state=open",
|
|
166
|
+
"--jq", "{number: .number}",
|
|
167
|
+
], cwd);
|
|
168
|
+
if (!result.ok)
|
|
169
|
+
return fail(result.error);
|
|
170
|
+
return ok(result.data.number);
|
|
171
|
+
}
|
|
172
|
+
export function ghCloseMilestone(cwd, repo, milestoneNumber) {
|
|
173
|
+
const result = runGh([
|
|
174
|
+
"api", `repos/${repo}/milestones/${milestoneNumber}`,
|
|
175
|
+
"-X", "PATCH",
|
|
176
|
+
"-f", "state=closed",
|
|
177
|
+
], cwd);
|
|
178
|
+
if (!result.ok)
|
|
179
|
+
return fail(result.error);
|
|
180
|
+
return ok(undefined);
|
|
181
|
+
}
|
|
182
|
+
export function ghCreatePR(cwd, opts) {
|
|
183
|
+
const args = [
|
|
184
|
+
"pr", "create",
|
|
185
|
+
"--repo", opts.repo,
|
|
186
|
+
"--base", opts.base,
|
|
187
|
+
"--head", opts.head,
|
|
188
|
+
"--title", opts.title,
|
|
189
|
+
"--body", truncateBody(opts.body),
|
|
190
|
+
];
|
|
191
|
+
if (opts.draft)
|
|
192
|
+
args.push("--draft");
|
|
193
|
+
const result = runGh(args, cwd);
|
|
194
|
+
if (!result.ok)
|
|
195
|
+
return fail(result.error);
|
|
196
|
+
const match = result.data.match(/\/pull\/(\d+)/);
|
|
197
|
+
if (!match)
|
|
198
|
+
return fail(`Could not parse PR number from: ${result.data}`);
|
|
199
|
+
return ok(parseInt(match[1], 10));
|
|
200
|
+
}
|
|
201
|
+
export function ghMarkPRReady(cwd, repo, prNumber) {
|
|
202
|
+
const result = runGh(["pr", "ready", String(prNumber), "--repo", repo], cwd);
|
|
203
|
+
if (!result.ok)
|
|
204
|
+
return fail(result.error);
|
|
205
|
+
return ok(undefined);
|
|
206
|
+
}
|
|
207
|
+
export function ghMergePR(cwd, repo, prNumber, strategy = "squash") {
|
|
208
|
+
const args = [
|
|
209
|
+
"pr", "merge", String(prNumber),
|
|
210
|
+
"--repo", repo,
|
|
211
|
+
strategy === "squash" ? "--squash" : "--merge",
|
|
212
|
+
"--delete-branch",
|
|
213
|
+
];
|
|
214
|
+
const result = runGh(args, cwd);
|
|
215
|
+
if (!result.ok)
|
|
216
|
+
return fail(result.error);
|
|
217
|
+
return ok(undefined);
|
|
218
|
+
}
|
|
219
|
+
// ─── Projects v2 ────────────────────────────────────────────────────────────
|
|
220
|
+
export function ghAddToProject(cwd, repo, projectNumber, issueNumber) {
|
|
221
|
+
// Get the issue's node ID first
|
|
222
|
+
const issueResult = runGhJson(["api", `repos/${repo}/issues/${issueNumber}`, "--jq", "{id: .node_id}"], cwd);
|
|
223
|
+
if (!issueResult.ok)
|
|
224
|
+
return fail(issueResult.error);
|
|
225
|
+
// Get the project's node ID
|
|
226
|
+
const [owner] = repo.split("/");
|
|
227
|
+
const projectResult = runGhJson([
|
|
228
|
+
"api", "graphql",
|
|
229
|
+
"-f", `query=query { user(login: "${owner}") { projectV2(number: ${projectNumber}) { id } } }`,
|
|
230
|
+
"--jq", ".data.user.projectV2.id",
|
|
231
|
+
], cwd);
|
|
232
|
+
// Try org if user fails
|
|
233
|
+
let projectId;
|
|
234
|
+
if (projectResult.ok && projectResult.data?.id) {
|
|
235
|
+
projectId = projectResult.data.id;
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
const orgResult = runGhJson([
|
|
239
|
+
"api", "graphql",
|
|
240
|
+
"-f", `query=query { organization(login: "${owner}") { projectV2(number: ${projectNumber}) { id } } }`,
|
|
241
|
+
"--jq", ".data.organization.projectV2.id",
|
|
242
|
+
], cwd);
|
|
243
|
+
if (orgResult.ok)
|
|
244
|
+
projectId = orgResult.data?.id;
|
|
245
|
+
}
|
|
246
|
+
if (!projectId)
|
|
247
|
+
return fail("Could not find project");
|
|
248
|
+
const mutation = `mutation { addProjectV2ItemById(input: { projectId: "${projectId}", contentId: "${issueResult.data.id}" }) { item { id } } }`;
|
|
249
|
+
return runGh(["api", "graphql", "-f", `query=${mutation}`], cwd);
|
|
250
|
+
}
|
|
251
|
+
// ─── Branch Operations ──────────────────────────────────────────────────────
|
|
252
|
+
export function ghPushBranch(cwd, branch, setUpstream = true) {
|
|
253
|
+
const args = ["git", "push"];
|
|
254
|
+
if (setUpstream)
|
|
255
|
+
args.push("-u", "origin", branch);
|
|
256
|
+
else
|
|
257
|
+
args.push("origin", branch);
|
|
258
|
+
try {
|
|
259
|
+
execFileSync(args[0], args.slice(1), {
|
|
260
|
+
cwd,
|
|
261
|
+
encoding: "utf-8",
|
|
262
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
263
|
+
timeout: 30_000,
|
|
264
|
+
});
|
|
265
|
+
return ok(undefined);
|
|
266
|
+
}
|
|
267
|
+
catch (err) {
|
|
268
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
export function ghCreateBranch(cwd, branch, from) {
|
|
272
|
+
try {
|
|
273
|
+
execFileSync("git", ["branch", branch, from], {
|
|
274
|
+
cwd,
|
|
275
|
+
encoding: "utf-8",
|
|
276
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
277
|
+
timeout: 10_000,
|
|
278
|
+
});
|
|
279
|
+
return ok(undefined);
|
|
280
|
+
}
|
|
281
|
+
catch (err) {
|
|
282
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Sync extension for GSD.
|
|
3
|
+
*
|
|
4
|
+
* Opt-in extension that syncs GSD lifecycle events to GitHub:
|
|
5
|
+
* milestones → GH Milestones + tracking issues, slices → draft PRs,
|
|
6
|
+
* tasks → sub-issues with auto-close on commit.
|
|
7
|
+
*
|
|
8
|
+
* Integration happens via a single dynamic import in auto-post-unit.ts.
|
|
9
|
+
* This index registers a `/github-sync` command for manual bootstrap
|
|
10
|
+
* and status display.
|
|
11
|
+
*/
|
|
12
|
+
import { bootstrapSync } from "./sync.js";
|
|
13
|
+
import { loadSyncMapping } from "./mapping.js";
|
|
14
|
+
import { ghIsAvailable } from "./cli.js";
|
|
15
|
+
export default function (pi) {
|
|
16
|
+
pi.registerCommand("github-sync", {
|
|
17
|
+
description: "Bootstrap GitHub sync or show sync status",
|
|
18
|
+
handler: async (args, ctx) => {
|
|
19
|
+
const subcommand = args.trim().toLowerCase();
|
|
20
|
+
if (subcommand === "status") {
|
|
21
|
+
await showStatus(ctx);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (subcommand === "bootstrap" || subcommand === "") {
|
|
25
|
+
await runBootstrap(ctx);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
ctx.ui.notify("Usage: /github-sync [bootstrap|status]", "info");
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
async function showStatus(ctx) {
|
|
33
|
+
if (!ghIsAvailable()) {
|
|
34
|
+
ctx.ui.notify("GitHub sync: `gh` CLI not installed or not authenticated.", "warning");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const mapping = loadSyncMapping(ctx.cwd);
|
|
38
|
+
if (!mapping) {
|
|
39
|
+
ctx.ui.notify("GitHub sync: No sync mapping found. Run `/github-sync bootstrap` to initialize.", "info");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const milestoneCount = Object.keys(mapping.milestones).length;
|
|
43
|
+
const sliceCount = Object.keys(mapping.slices).length;
|
|
44
|
+
const taskCount = Object.keys(mapping.tasks).length;
|
|
45
|
+
const openMilestones = Object.values(mapping.milestones).filter(m => m.state === "open").length;
|
|
46
|
+
const openSlices = Object.values(mapping.slices).filter(s => s.state === "open").length;
|
|
47
|
+
const openTasks = Object.values(mapping.tasks).filter(t => t.state === "open").length;
|
|
48
|
+
ctx.ui.notify([
|
|
49
|
+
`GitHub sync: repo=${mapping.repo}`,
|
|
50
|
+
` Milestones: ${milestoneCount} (${openMilestones} open)`,
|
|
51
|
+
` Slices: ${sliceCount} (${openSlices} open)`,
|
|
52
|
+
` Tasks: ${taskCount} (${openTasks} open)`,
|
|
53
|
+
].join("\n"), "info");
|
|
54
|
+
}
|
|
55
|
+
async function runBootstrap(ctx) {
|
|
56
|
+
if (!ghIsAvailable()) {
|
|
57
|
+
ctx.ui.notify("GitHub sync: `gh` CLI not installed or not authenticated.", "warning");
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
ctx.ui.notify("GitHub sync: bootstrapping...", "info");
|
|
61
|
+
try {
|
|
62
|
+
const counts = await bootstrapSync(ctx.cwd);
|
|
63
|
+
if (counts.milestones === 0 && counts.slices === 0 && counts.tasks === 0) {
|
|
64
|
+
ctx.ui.notify("GitHub sync: everything already synced (or no milestones found).", "info");
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
ctx.ui.notify(`GitHub sync: created ${counts.milestones} milestone(s), ${counts.slices} slice(s), ${counts.tasks} task(s).`, "info");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
ctx.ui.notify(`GitHub sync bootstrap failed: ${err}`, "error");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence layer for the GitHub sync mapping.
|
|
3
|
+
*
|
|
4
|
+
* The mapping lives at `.gsd/github-sync.json` and tracks which GSD
|
|
5
|
+
* entities have been synced to which GitHub entities (issues, PRs,
|
|
6
|
+
* milestones) along with their numbers and sync timestamps.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { atomicWriteSync } from "../gsd/atomic-write.js";
|
|
11
|
+
const MAPPING_FILENAME = "github-sync.json";
|
|
12
|
+
function mappingPath(basePath) {
|
|
13
|
+
return join(basePath, ".gsd", MAPPING_FILENAME);
|
|
14
|
+
}
|
|
15
|
+
// ─── Load / Save ────────────────────────────────────────────────────────────
|
|
16
|
+
export function loadSyncMapping(basePath) {
|
|
17
|
+
const path = mappingPath(basePath);
|
|
18
|
+
if (!existsSync(path))
|
|
19
|
+
return null;
|
|
20
|
+
try {
|
|
21
|
+
const raw = readFileSync(path, "utf-8");
|
|
22
|
+
const parsed = JSON.parse(raw);
|
|
23
|
+
if (parsed?.version !== 1)
|
|
24
|
+
return null;
|
|
25
|
+
return parsed;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function saveSyncMapping(basePath, mapping) {
|
|
32
|
+
const path = mappingPath(basePath);
|
|
33
|
+
atomicWriteSync(path, JSON.stringify(mapping, null, 2) + "\n");
|
|
34
|
+
}
|
|
35
|
+
export function createEmptyMapping(repo) {
|
|
36
|
+
return {
|
|
37
|
+
version: 1,
|
|
38
|
+
repo,
|
|
39
|
+
milestones: {},
|
|
40
|
+
slices: {},
|
|
41
|
+
tasks: {},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// ─── Accessors ──────────────────────────────────────────────────────────────
|
|
45
|
+
export function getMilestoneRecord(mapping, mid) {
|
|
46
|
+
return mapping.milestones[mid] ?? null;
|
|
47
|
+
}
|
|
48
|
+
export function getSliceRecord(mapping, mid, sid) {
|
|
49
|
+
return mapping.slices[`${mid}/${sid}`] ?? null;
|
|
50
|
+
}
|
|
51
|
+
export function getTaskRecord(mapping, mid, sid, tid) {
|
|
52
|
+
return mapping.tasks[`${mid}/${sid}/${tid}`] ?? null;
|
|
53
|
+
}
|
|
54
|
+
export function getTaskIssueNumber(mapping, mid, sid, tid) {
|
|
55
|
+
const record = getTaskRecord(mapping, mid, sid, tid);
|
|
56
|
+
return record?.issueNumber ?? null;
|
|
57
|
+
}
|
|
58
|
+
// ─── Mutators ───────────────────────────────────────────────────────────────
|
|
59
|
+
export function setMilestoneRecord(mapping, mid, record) {
|
|
60
|
+
mapping.milestones[mid] = record;
|
|
61
|
+
}
|
|
62
|
+
export function setSliceRecord(mapping, mid, sid, record) {
|
|
63
|
+
mapping.slices[`${mid}/${sid}`] = record;
|
|
64
|
+
}
|
|
65
|
+
export function setTaskRecord(mapping, mid, sid, tid, record) {
|
|
66
|
+
mapping.tasks[`${mid}/${sid}/${tid}`] = record;
|
|
67
|
+
}
|