mstro-app 0.4.2 → 0.4.4
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/bin/mstro.js +119 -40
- package/dist/server/cli/headless/claude-invoker-process.d.ts +11 -0
- package/dist/server/cli/headless/claude-invoker-process.d.ts.map +1 -0
- package/dist/server/cli/headless/claude-invoker-process.js +140 -0
- package/dist/server/cli/headless/claude-invoker-process.js.map +1 -0
- package/dist/server/cli/headless/claude-invoker-stall.d.ts +40 -0
- package/dist/server/cli/headless/claude-invoker-stall.d.ts.map +1 -0
- package/dist/server/cli/headless/claude-invoker-stall.js +98 -0
- package/dist/server/cli/headless/claude-invoker-stall.js.map +1 -0
- package/dist/server/cli/headless/claude-invoker-stream.d.ts +44 -0
- package/dist/server/cli/headless/claude-invoker-stream.d.ts.map +1 -0
- package/dist/server/cli/headless/claude-invoker-stream.js +276 -0
- package/dist/server/cli/headless/claude-invoker-stream.js.map +1 -0
- package/dist/server/cli/headless/claude-invoker-tools.d.ts +21 -0
- package/dist/server/cli/headless/claude-invoker-tools.d.ts.map +1 -0
- package/dist/server/cli/headless/claude-invoker-tools.js +137 -0
- package/dist/server/cli/headless/claude-invoker-tools.js.map +1 -0
- package/dist/server/cli/headless/claude-invoker.d.ts +6 -4
- package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
- package/dist/server/cli/headless/claude-invoker.js +10 -804
- package/dist/server/cli/headless/claude-invoker.js.map +1 -1
- package/dist/server/cli/headless/haiku-assessments.d.ts +62 -0
- package/dist/server/cli/headless/haiku-assessments.d.ts.map +1 -0
- package/dist/server/cli/headless/haiku-assessments.js +281 -0
- package/dist/server/cli/headless/haiku-assessments.js.map +1 -0
- package/dist/server/cli/headless/headless-logger.d.ts +3 -2
- package/dist/server/cli/headless/headless-logger.d.ts.map +1 -1
- package/dist/server/cli/headless/headless-logger.js +28 -5
- package/dist/server/cli/headless/headless-logger.js.map +1 -1
- package/dist/server/cli/headless/native-timeout-detector.d.ts +44 -0
- package/dist/server/cli/headless/native-timeout-detector.d.ts.map +1 -0
- package/dist/server/cli/headless/native-timeout-detector.js +99 -0
- package/dist/server/cli/headless/native-timeout-detector.js.map +1 -0
- package/dist/server/cli/headless/stall-assessor.d.ts +2 -110
- package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
- package/dist/server/cli/headless/stall-assessor.js +65 -457
- package/dist/server/cli/headless/stall-assessor.js.map +1 -1
- package/dist/server/cli/headless/types.d.ts +4 -1
- package/dist/server/cli/headless/types.d.ts.map +1 -1
- package/dist/server/cli/improvisation-attachments.d.ts +21 -0
- package/dist/server/cli/improvisation-attachments.d.ts.map +1 -0
- package/dist/server/cli/improvisation-attachments.js +116 -0
- package/dist/server/cli/improvisation-attachments.js.map +1 -0
- package/dist/server/cli/improvisation-retry.d.ts +52 -0
- package/dist/server/cli/improvisation-retry.d.ts.map +1 -0
- package/dist/server/cli/improvisation-retry.js +434 -0
- package/dist/server/cli/improvisation-retry.js.map +1 -0
- package/dist/server/cli/improvisation-session-manager.d.ts +10 -266
- package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.js +117 -1079
- package/dist/server/cli/improvisation-session-manager.js.map +1 -1
- package/dist/server/cli/improvisation-types.d.ts +86 -0
- package/dist/server/cli/improvisation-types.d.ts.map +1 -0
- package/dist/server/cli/improvisation-types.js +10 -0
- package/dist/server/cli/improvisation-types.js.map +1 -0
- package/dist/server/cli/prompt-builders.d.ts +68 -0
- package/dist/server/cli/prompt-builders.d.ts.map +1 -0
- package/dist/server/cli/prompt-builders.js +312 -0
- package/dist/server/cli/prompt-builders.js.map +1 -0
- package/dist/server/index.js +33 -212
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/bouncer-haiku.d.ts +10 -0
- package/dist/server/mcp/bouncer-haiku.d.ts.map +1 -0
- package/dist/server/mcp/bouncer-haiku.js +152 -0
- package/dist/server/mcp/bouncer-haiku.js.map +1 -0
- package/dist/server/mcp/bouncer-integration.d.ts +3 -4
- package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
- package/dist/server/mcp/bouncer-integration.js +50 -196
- package/dist/server/mcp/bouncer-integration.js.map +1 -1
- package/dist/server/mcp/security-analysis.d.ts +38 -0
- package/dist/server/mcp/security-analysis.d.ts.map +1 -0
- package/dist/server/mcp/security-analysis.js +183 -0
- package/dist/server/mcp/security-analysis.js.map +1 -0
- package/dist/server/mcp/security-audit.d.ts +1 -1
- package/dist/server/mcp/security-audit.d.ts.map +1 -1
- package/dist/server/mcp/security-patterns.d.ts +1 -25
- package/dist/server/mcp/security-patterns.d.ts.map +1 -1
- package/dist/server/mcp/security-patterns.js +55 -260
- package/dist/server/mcp/security-patterns.js.map +1 -1
- package/dist/server/server-setup.d.ts +22 -0
- package/dist/server/server-setup.d.ts.map +1 -0
- package/dist/server/server-setup.js +101 -0
- package/dist/server/server-setup.js.map +1 -0
- package/dist/server/services/file-explorer-ops.d.ts +24 -0
- package/dist/server/services/file-explorer-ops.d.ts.map +1 -0
- package/dist/server/services/file-explorer-ops.js +211 -0
- package/dist/server/services/file-explorer-ops.js.map +1 -0
- package/dist/server/services/files.d.ts +2 -85
- package/dist/server/services/files.d.ts.map +1 -1
- package/dist/server/services/files.js +7 -427
- package/dist/server/services/files.js.map +1 -1
- package/dist/server/services/plan/composer.d.ts +1 -1
- package/dist/server/services/plan/composer.d.ts.map +1 -1
- package/dist/server/services/plan/composer.js +118 -32
- package/dist/server/services/plan/composer.js.map +1 -1
- package/dist/server/services/plan/config-installer.d.ts +25 -0
- package/dist/server/services/plan/config-installer.d.ts.map +1 -0
- package/dist/server/services/plan/config-installer.js +182 -0
- package/dist/server/services/plan/config-installer.js.map +1 -0
- package/dist/server/services/plan/dependency-resolver.d.ts +1 -1
- package/dist/server/services/plan/dependency-resolver.d.ts.map +1 -1
- package/dist/server/services/plan/dependency-resolver.js +4 -1
- package/dist/server/services/plan/dependency-resolver.js.map +1 -1
- package/dist/server/services/plan/executor.d.ts +38 -74
- package/dist/server/services/plan/executor.d.ts.map +1 -1
- package/dist/server/services/plan/executor.js +274 -460
- package/dist/server/services/plan/executor.js.map +1 -1
- package/dist/server/services/plan/front-matter.d.ts +18 -0
- package/dist/server/services/plan/front-matter.d.ts.map +1 -0
- package/dist/server/services/plan/front-matter.js +44 -0
- package/dist/server/services/plan/front-matter.js.map +1 -0
- package/dist/server/services/plan/output-manager.d.ts +22 -0
- package/dist/server/services/plan/output-manager.d.ts.map +1 -0
- package/dist/server/services/plan/output-manager.js +97 -0
- package/dist/server/services/plan/output-manager.js.map +1 -0
- package/dist/server/services/plan/parser-core.d.ts +20 -0
- package/dist/server/services/plan/parser-core.d.ts.map +1 -0
- package/dist/server/services/plan/parser-core.js +350 -0
- package/dist/server/services/plan/parser-core.js.map +1 -0
- package/dist/server/services/plan/parser-migration.d.ts +5 -0
- package/dist/server/services/plan/parser-migration.d.ts.map +1 -0
- package/dist/server/services/plan/parser-migration.js +124 -0
- package/dist/server/services/plan/parser-migration.js.map +1 -0
- package/dist/server/services/plan/parser.d.ts +11 -3
- package/dist/server/services/plan/parser.d.ts.map +1 -1
- package/dist/server/services/plan/parser.js +184 -369
- package/dist/server/services/plan/parser.js.map +1 -1
- package/dist/server/services/plan/prompt-builder.d.ts +17 -0
- package/dist/server/services/plan/prompt-builder.d.ts.map +1 -0
- package/dist/server/services/plan/prompt-builder.js +137 -0
- package/dist/server/services/plan/prompt-builder.js.map +1 -0
- package/dist/server/services/plan/review-gate.d.ts +28 -0
- package/dist/server/services/plan/review-gate.d.ts.map +1 -0
- package/dist/server/services/plan/review-gate.js +191 -0
- package/dist/server/services/plan/review-gate.js.map +1 -0
- package/dist/server/services/plan/state-reconciler.d.ts +1 -1
- package/dist/server/services/plan/state-reconciler.d.ts.map +1 -1
- package/dist/server/services/plan/state-reconciler.js +59 -7
- package/dist/server/services/plan/state-reconciler.js.map +1 -1
- package/dist/server/services/plan/types.d.ts +68 -0
- package/dist/server/services/plan/types.d.ts.map +1 -1
- package/dist/server/services/platform-credentials.d.ts +24 -0
- package/dist/server/services/platform-credentials.d.ts.map +1 -0
- package/dist/server/services/platform-credentials.js +68 -0
- package/dist/server/services/platform-credentials.js.map +1 -0
- package/dist/server/services/platform.d.ts +1 -31
- package/dist/server/services/platform.d.ts.map +1 -1
- package/dist/server/services/platform.js +11 -109
- package/dist/server/services/platform.js.map +1 -1
- package/dist/server/services/terminal/pty-manager.d.ts +7 -97
- package/dist/server/services/terminal/pty-manager.d.ts.map +1 -1
- package/dist/server/services/terminal/pty-manager.js +53 -266
- package/dist/server/services/terminal/pty-manager.js.map +1 -1
- package/dist/server/services/terminal/pty-utils.d.ts +57 -0
- package/dist/server/services/terminal/pty-utils.d.ts.map +1 -0
- package/dist/server/services/terminal/pty-utils.js +141 -0
- package/dist/server/services/terminal/pty-utils.js.map +1 -0
- package/dist/server/services/websocket/file-definition-handlers.d.ts +4 -0
- package/dist/server/services/websocket/file-definition-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/file-definition-handlers.js +153 -0
- package/dist/server/services/websocket/file-definition-handlers.js.map +1 -0
- package/dist/server/services/websocket/file-explorer-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/file-explorer-handlers.js +52 -391
- package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -1
- package/dist/server/services/websocket/file-search-handlers.d.ts +5 -0
- package/dist/server/services/websocket/file-search-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/file-search-handlers.js +238 -0
- package/dist/server/services/websocket/file-search-handlers.js.map +1 -0
- package/dist/server/services/websocket/file-utils.js +3 -3
- package/dist/server/services/websocket/file-utils.js.map +1 -1
- package/dist/server/services/websocket/git-branch-handlers.d.ts +7 -0
- package/dist/server/services/websocket/git-branch-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/git-branch-handlers.js +110 -0
- package/dist/server/services/websocket/git-branch-handlers.js.map +1 -0
- package/dist/server/services/websocket/git-diff-handlers.d.ts +6 -0
- package/dist/server/services/websocket/git-diff-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/git-diff-handlers.js +123 -0
- package/dist/server/services/websocket/git-diff-handlers.js.map +1 -0
- package/dist/server/services/websocket/git-handlers.d.ts +2 -31
- package/dist/server/services/websocket/git-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/git-handlers.js +35 -541
- package/dist/server/services/websocket/git-handlers.js.map +1 -1
- package/dist/server/services/websocket/git-log-handlers.d.ts +6 -0
- package/dist/server/services/websocket/git-log-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/git-log-handlers.js +128 -0
- package/dist/server/services/websocket/git-log-handlers.js.map +1 -0
- package/dist/server/services/websocket/git-pr-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/git-pr-handlers.js +13 -53
- package/dist/server/services/websocket/git-pr-handlers.js.map +1 -1
- package/dist/server/services/websocket/git-tag-handlers.d.ts +6 -0
- package/dist/server/services/websocket/git-tag-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/git-tag-handlers.js +76 -0
- package/dist/server/services/websocket/git-tag-handlers.js.map +1 -0
- package/dist/server/services/websocket/git-utils.d.ts +43 -0
- package/dist/server/services/websocket/git-utils.d.ts.map +1 -0
- package/dist/server/services/websocket/git-utils.js +201 -0
- package/dist/server/services/websocket/git-utils.js.map +1 -0
- package/dist/server/services/websocket/handler.d.ts +2 -0
- package/dist/server/services/websocket/handler.d.ts.map +1 -1
- package/dist/server/services/websocket/handler.js +37 -112
- package/dist/server/services/websocket/handler.js.map +1 -1
- package/dist/server/services/websocket/plan-board-handlers.d.ts +11 -0
- package/dist/server/services/websocket/plan-board-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/plan-board-handlers.js +218 -0
- package/dist/server/services/websocket/plan-board-handlers.js.map +1 -0
- package/dist/server/services/websocket/plan-execution-handlers.d.ts +9 -0
- package/dist/server/services/websocket/plan-execution-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/plan-execution-handlers.js +142 -0
- package/dist/server/services/websocket/plan-execution-handlers.js.map +1 -0
- package/dist/server/services/websocket/plan-handlers.d.ts +7 -2
- package/dist/server/services/websocket/plan-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/plan-handlers.js +21 -462
- package/dist/server/services/websocket/plan-handlers.js.map +1 -1
- package/dist/server/services/websocket/plan-helpers.d.ts +19 -0
- package/dist/server/services/websocket/plan-helpers.d.ts.map +1 -0
- package/dist/server/services/websocket/plan-helpers.js +199 -0
- package/dist/server/services/websocket/plan-helpers.js.map +1 -0
- package/dist/server/services/websocket/plan-issue-handlers.d.ts +12 -0
- package/dist/server/services/websocket/plan-issue-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/plan-issue-handlers.js +162 -0
- package/dist/server/services/websocket/plan-issue-handlers.js.map +1 -0
- package/dist/server/services/websocket/plan-sprint-handlers.d.ts +7 -0
- package/dist/server/services/websocket/plan-sprint-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/plan-sprint-handlers.js +206 -0
- package/dist/server/services/websocket/plan-sprint-handlers.js.map +1 -0
- package/dist/server/services/websocket/quality-complexity.d.ts +14 -0
- package/dist/server/services/websocket/quality-complexity.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-complexity.js +262 -0
- package/dist/server/services/websocket/quality-complexity.js.map +1 -0
- package/dist/server/services/websocket/quality-fix-agent.d.ts +16 -0
- package/dist/server/services/websocket/quality-fix-agent.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-fix-agent.js +140 -0
- package/dist/server/services/websocket/quality-fix-agent.js.map +1 -0
- package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-handlers.js +34 -346
- package/dist/server/services/websocket/quality-handlers.js.map +1 -1
- package/dist/server/services/websocket/quality-linting.d.ts +9 -0
- package/dist/server/services/websocket/quality-linting.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-linting.js +178 -0
- package/dist/server/services/websocket/quality-linting.js.map +1 -0
- package/dist/server/services/websocket/quality-review-agent.d.ts +19 -0
- package/dist/server/services/websocket/quality-review-agent.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-review-agent.js +206 -0
- package/dist/server/services/websocket/quality-review-agent.js.map +1 -0
- package/dist/server/services/websocket/quality-service.d.ts +3 -51
- package/dist/server/services/websocket/quality-service.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-service.js +9 -651
- package/dist/server/services/websocket/quality-service.js.map +1 -1
- package/dist/server/services/websocket/quality-tools.d.ts +23 -0
- package/dist/server/services/websocket/quality-tools.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-tools.js +208 -0
- package/dist/server/services/websocket/quality-tools.js.map +1 -0
- package/dist/server/services/websocket/quality-types.d.ts +59 -0
- package/dist/server/services/websocket/quality-types.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-types.js +101 -0
- package/dist/server/services/websocket/quality-types.js.map +1 -0
- package/dist/server/services/websocket/session-handlers.d.ts +3 -4
- package/dist/server/services/websocket/session-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/session-handlers.js +3 -378
- package/dist/server/services/websocket/session-handlers.js.map +1 -1
- package/dist/server/services/websocket/session-history.d.ts +4 -0
- package/dist/server/services/websocket/session-history.d.ts.map +1 -0
- package/dist/server/services/websocket/session-history.js +208 -0
- package/dist/server/services/websocket/session-history.js.map +1 -0
- package/dist/server/services/websocket/session-initialization.d.ts +5 -0
- package/dist/server/services/websocket/session-initialization.d.ts.map +1 -0
- package/dist/server/services/websocket/session-initialization.js +163 -0
- package/dist/server/services/websocket/session-initialization.js.map +1 -0
- package/dist/server/services/websocket/types.d.ts +12 -2
- package/dist/server/services/websocket/types.d.ts.map +1 -1
- package/package.json +1 -2
- package/server/cli/headless/claude-invoker-process.ts +204 -0
- package/server/cli/headless/claude-invoker-stall.ts +164 -0
- package/server/cli/headless/claude-invoker-stream.ts +353 -0
- package/server/cli/headless/claude-invoker-tools.ts +187 -0
- package/server/cli/headless/claude-invoker.ts +15 -1092
- package/server/cli/headless/haiku-assessments.ts +365 -0
- package/server/cli/headless/headless-logger.ts +26 -5
- package/server/cli/headless/native-timeout-detector.ts +117 -0
- package/server/cli/headless/stall-assessor.ts +65 -618
- package/server/cli/headless/types.ts +4 -1
- package/server/cli/improvisation-attachments.ts +148 -0
- package/server/cli/improvisation-retry.ts +602 -0
- package/server/cli/improvisation-session-manager.ts +140 -1349
- package/server/cli/improvisation-types.ts +98 -0
- package/server/cli/prompt-builders.ts +370 -0
- package/server/index.ts +35 -246
- package/server/mcp/bouncer-haiku.ts +182 -0
- package/server/mcp/bouncer-integration.ts +87 -248
- package/server/mcp/security-analysis.ts +217 -0
- package/server/mcp/security-audit.ts +1 -1
- package/server/mcp/security-patterns.ts +60 -283
- package/server/server-setup.ts +114 -0
- package/server/services/file-explorer-ops.ts +293 -0
- package/server/services/files.ts +20 -532
- package/server/services/plan/composer.ts +140 -35
- package/server/services/plan/config-installer.ts +187 -0
- package/server/services/plan/dependency-resolver.ts +4 -1
- package/server/services/plan/executor.ts +281 -488
- package/server/services/plan/front-matter.ts +48 -0
- package/server/services/plan/output-manager.ts +113 -0
- package/server/services/plan/parser-core.ts +406 -0
- package/server/services/plan/parser-migration.ts +128 -0
- package/server/services/plan/parser.ts +188 -394
- package/server/services/plan/prompt-builder.ts +161 -0
- package/server/services/plan/review-gate.ts +212 -0
- package/server/services/plan/state-reconciler.ts +68 -7
- package/server/services/plan/types.ts +101 -1
- package/server/services/platform-credentials.ts +83 -0
- package/server/services/platform.ts +16 -131
- package/server/services/terminal/pty-manager.ts +66 -313
- package/server/services/terminal/pty-utils.ts +176 -0
- package/server/services/websocket/file-definition-handlers.ts +165 -0
- package/server/services/websocket/file-explorer-handlers.ts +37 -452
- package/server/services/websocket/file-search-handlers.ts +291 -0
- package/server/services/websocket/file-utils.ts +3 -3
- package/server/services/websocket/git-branch-handlers.ts +130 -0
- package/server/services/websocket/git-diff-handlers.ts +140 -0
- package/server/services/websocket/git-handlers.ts +40 -625
- package/server/services/websocket/git-log-handlers.ts +149 -0
- package/server/services/websocket/git-pr-handlers.ts +17 -62
- package/server/services/websocket/git-tag-handlers.ts +91 -0
- package/server/services/websocket/git-utils.ts +230 -0
- package/server/services/websocket/handler.ts +39 -112
- package/server/services/websocket/plan-board-handlers.ts +277 -0
- package/server/services/websocket/plan-execution-handlers.ts +184 -0
- package/server/services/websocket/plan-handlers.ts +23 -544
- package/server/services/websocket/plan-helpers.ts +215 -0
- package/server/services/websocket/plan-issue-handlers.ts +204 -0
- package/server/services/websocket/plan-sprint-handlers.ts +252 -0
- package/server/services/websocket/quality-complexity.ts +294 -0
- package/server/services/websocket/quality-fix-agent.ts +181 -0
- package/server/services/websocket/quality-handlers.ts +36 -404
- package/server/services/websocket/quality-linting.ts +187 -0
- package/server/services/websocket/quality-review-agent.ts +246 -0
- package/server/services/websocket/quality-service.ts +11 -762
- package/server/services/websocket/quality-tools.ts +209 -0
- package/server/services/websocket/quality-types.ts +169 -0
- package/server/services/websocket/session-handlers.ts +5 -437
- package/server/services/websocket/session-history.ts +222 -0
- package/server/services/websocket/session-initialization.ts +209 -0
- package/server/services/websocket/types.ts +46 -2
|
@@ -1,160 +1,14 @@
|
|
|
1
1
|
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
2
2
|
// Licensed under the MIT License. See LICENSE file for details.
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { handleGitCheckout, handleGitCreateBranch, handleGitDeleteBranch, handleGitListBranches } from './git-branch-handlers.js';
|
|
4
|
+
import { handleGitCommitDiff, handleGitDiff, handleGitShowCommit } from './git-diff-handlers.js';
|
|
5
|
+
import { handleGitDiscoverRepos, handleGitLog, handleGitSetDirectory } from './git-log-handlers.js';
|
|
6
6
|
import { handleGitPRMessage } from './git-pr-handlers.js';
|
|
7
|
+
import { handleGitCreateTag, handleGitListTags, handleGitPushTag } from './git-tag-handlers.js';
|
|
8
|
+
import { executeGitCommand, parseGitStatus, sendGitError, spawnHaikuWithPrompt, stripCoauthorLines, truncateDiff } from './git-utils.js';
|
|
7
9
|
import { handleGitWorktreeMessage } from './git-worktree-handlers.js';
|
|
8
|
-
|
|
9
|
-
export
|
|
10
|
-
if (remoteUrl.includes('github.com'))
|
|
11
|
-
return 'github';
|
|
12
|
-
if (remoteUrl.includes('gitlab.com') || remoteUrl.includes('gitlab'))
|
|
13
|
-
return 'gitlab';
|
|
14
|
-
return 'unknown';
|
|
15
|
-
}
|
|
16
|
-
/** Execute a git command and return stdout */
|
|
17
|
-
export function executeGitCommand(args, workingDir) {
|
|
18
|
-
return new Promise((resolve) => {
|
|
19
|
-
const git = spawn('git', args, {
|
|
20
|
-
cwd: workingDir,
|
|
21
|
-
stdio: ['ignore', 'pipe', 'pipe']
|
|
22
|
-
});
|
|
23
|
-
let stdout = '';
|
|
24
|
-
let stderr = '';
|
|
25
|
-
git.stdout?.on('data', (data) => {
|
|
26
|
-
stdout += data.toString();
|
|
27
|
-
});
|
|
28
|
-
git.stderr?.on('data', (data) => {
|
|
29
|
-
stderr += data.toString();
|
|
30
|
-
});
|
|
31
|
-
git.on('close', (code) => {
|
|
32
|
-
resolve({ stdout, stderr, exitCode: code ?? 1 });
|
|
33
|
-
});
|
|
34
|
-
git.on('error', (err) => {
|
|
35
|
-
resolve({ stdout: '', stderr: err.message, exitCode: 1 });
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
/** Map of simple escape sequences to their character values */
|
|
40
|
-
const ESCAPE_CHARS = {
|
|
41
|
-
'\\': '\\',
|
|
42
|
-
'"': '"',
|
|
43
|
-
'n': '\n',
|
|
44
|
-
't': '\t',
|
|
45
|
-
'r': '\r',
|
|
46
|
-
};
|
|
47
|
-
/** Check if position i starts an octal escape sequence (\nnn) */
|
|
48
|
-
function isOctalEscape(str, i) {
|
|
49
|
-
return i + 3 < str.length &&
|
|
50
|
-
/[0-7]/.test(str[i + 1]) &&
|
|
51
|
-
/[0-7]{2}/.test(str.slice(i + 2, i + 4));
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Unquote a git-quoted path (C-style quoting)
|
|
55
|
-
*/
|
|
56
|
-
export function unquoteGitPath(path) {
|
|
57
|
-
if (!path.startsWith('"') || !path.endsWith('"')) {
|
|
58
|
-
return path;
|
|
59
|
-
}
|
|
60
|
-
const inner = path.slice(1, -1);
|
|
61
|
-
let result = '';
|
|
62
|
-
let i = 0;
|
|
63
|
-
while (i < inner.length) {
|
|
64
|
-
if (inner[i] !== '\\' || i + 1 >= inner.length) {
|
|
65
|
-
result += inner[i];
|
|
66
|
-
i++;
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
const next = inner[i + 1];
|
|
70
|
-
const escaped = ESCAPE_CHARS[next];
|
|
71
|
-
if (escaped !== undefined) {
|
|
72
|
-
result += escaped;
|
|
73
|
-
i += 2;
|
|
74
|
-
}
|
|
75
|
-
else if (isOctalEscape(inner, i)) {
|
|
76
|
-
result += String.fromCharCode(parseInt(inner.slice(i + 1, i + 4), 8));
|
|
77
|
-
i += 4;
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
result += inner[i];
|
|
81
|
-
i++;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return result;
|
|
85
|
-
}
|
|
86
|
-
/** Parse git status --porcelain output into structured format */
|
|
87
|
-
export function parseGitStatus(porcelainOutput) {
|
|
88
|
-
const staged = [];
|
|
89
|
-
const unstaged = [];
|
|
90
|
-
const untracked = [];
|
|
91
|
-
const lines = porcelainOutput.split('\n').filter(line => line.length >= 4);
|
|
92
|
-
for (const line of lines) {
|
|
93
|
-
const indexStatus = line[0];
|
|
94
|
-
const workTreeStatus = line[1];
|
|
95
|
-
const rawPath = line.slice(3);
|
|
96
|
-
const path = unquoteGitPath(rawPath);
|
|
97
|
-
let filePath = path;
|
|
98
|
-
let originalPath;
|
|
99
|
-
if (rawPath.includes(' -> ')) {
|
|
100
|
-
const parts = rawPath.split(' -> ');
|
|
101
|
-
originalPath = unquoteGitPath(parts[0]);
|
|
102
|
-
filePath = unquoteGitPath(parts[1]);
|
|
103
|
-
}
|
|
104
|
-
if (indexStatus === '?' && workTreeStatus === '?') {
|
|
105
|
-
untracked.push({ path: filePath, status: '?', staged: false });
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
if (indexStatus !== ' ' && indexStatus !== '?') {
|
|
109
|
-
staged.push({ path: filePath, status: indexStatus, staged: true, originalPath });
|
|
110
|
-
}
|
|
111
|
-
if (workTreeStatus !== ' ' && workTreeStatus !== '?') {
|
|
112
|
-
unstaged.push({ path: filePath, status: workTreeStatus, staged: false, originalPath });
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return { staged, unstaged, untracked };
|
|
116
|
-
}
|
|
117
|
-
/** Check if a binary runs successfully (exit code 0) */
|
|
118
|
-
export function spawnCheck(bin, args) {
|
|
119
|
-
return new Promise((resolve) => {
|
|
120
|
-
const proc = spawn(bin, args, { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
121
|
-
proc.on('close', (code) => resolve(code === 0));
|
|
122
|
-
proc.on('error', () => resolve(false));
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
/** Spawn a process and capture stdout/stderr */
|
|
126
|
-
export function spawnWithOutput(bin, args, cwd) {
|
|
127
|
-
return new Promise((resolve) => {
|
|
128
|
-
const proc = spawn(bin, args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
129
|
-
let stdout = '';
|
|
130
|
-
let stderr = '';
|
|
131
|
-
proc.stdout?.on('data', (d) => { stdout += d.toString(); });
|
|
132
|
-
proc.stderr?.on('data', (d) => { stderr += d.toString(); });
|
|
133
|
-
proc.on('close', (code) => resolve({ stdout, stderr, exitCode: code ?? 1 }));
|
|
134
|
-
proc.on('error', (err) => resolve({ stdout: '', stderr: err.message, exitCode: 1 }));
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Strip injected coauthor/attribution lines from a commit message.
|
|
139
|
-
*/
|
|
140
|
-
export function stripCoauthorLines(message) {
|
|
141
|
-
const lines = message.split('\n');
|
|
142
|
-
const markers = ['co-authored', 'authored-by', 'haiku', 'noreply@anthropic.com'];
|
|
143
|
-
const result = [];
|
|
144
|
-
for (let i = 0; i < lines.length; i++) {
|
|
145
|
-
const lower = lines[i].toLowerCase();
|
|
146
|
-
if (markers.some(m => lower.includes(m))) {
|
|
147
|
-
if (result.length > 0 && result[result.length - 1].trim() === '') {
|
|
148
|
-
result.pop();
|
|
149
|
-
}
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
result.push(lines[i]);
|
|
153
|
-
}
|
|
154
|
-
if (result.length === 0)
|
|
155
|
-
return '';
|
|
156
|
-
return result.join('\n').trimEnd();
|
|
157
|
-
}
|
|
10
|
+
// Re-export utilities for backward compatibility (git-pr-handlers, git-worktree-handlers import from here)
|
|
11
|
+
export { detectGitProvider, executeGitCommand, parseGitStatus, sendGitError, spawnCheck, spawnHaikuWithPrompt, spawnWithOutput, stripCoauthorLines, truncateDiff, unquoteGitPath } from './git-utils.js';
|
|
158
12
|
// PR message types that route to git-pr-handlers
|
|
159
13
|
const GIT_PR_TYPES = new Set([
|
|
160
14
|
'gitGetRemoteInfo', 'gitCreatePR', 'gitGeneratePRDescription',
|
|
@@ -192,6 +46,8 @@ export async function handleGitMessage(ctx, ws, msg, tabId, workingDir) {
|
|
|
192
46
|
gitCreateBranch: () => handleGitCreateBranch(ctx, ws, msg, tabId, gitDir),
|
|
193
47
|
gitDeleteBranch: () => handleGitDeleteBranch(ctx, ws, msg, tabId, gitDir),
|
|
194
48
|
gitDiff: () => handleGitDiff(ctx, ws, msg, tabId, gitDir),
|
|
49
|
+
gitShowCommit: () => handleGitShowCommit(ctx, ws, msg, tabId, gitDir),
|
|
50
|
+
gitCommitDiff: () => handleGitCommitDiff(ctx, ws, msg, tabId, gitDir),
|
|
195
51
|
gitListTags: () => handleGitListTags(ctx, ws, tabId, gitDir),
|
|
196
52
|
gitCreateTag: () => handleGitCreateTag(ctx, ws, msg, tabId, gitDir),
|
|
197
53
|
gitPushTag: () => handleGitPushTag(ctx, ws, msg, tabId, gitDir),
|
|
@@ -237,7 +93,7 @@ export async function handleGitStatus(ctx, ws, tabId, workingDir) {
|
|
|
237
93
|
ctx.send(ws, { type: 'gitStatus', tabId, data: response });
|
|
238
94
|
}
|
|
239
95
|
catch (error) {
|
|
240
|
-
ctx
|
|
96
|
+
sendGitError(ctx, ws, tabId, error);
|
|
241
97
|
}
|
|
242
98
|
}
|
|
243
99
|
async function handleGitStage(ctx, ws, msg, tabId, workingDir) {
|
|
@@ -257,7 +113,7 @@ async function handleGitStage(ctx, ws, msg, tabId, workingDir) {
|
|
|
257
113
|
ctx.send(ws, { type: 'gitStaged', tabId, data: { paths: paths || [] } });
|
|
258
114
|
}
|
|
259
115
|
catch (error) {
|
|
260
|
-
ctx
|
|
116
|
+
sendGitError(ctx, ws, tabId, error);
|
|
261
117
|
}
|
|
262
118
|
}
|
|
263
119
|
async function handleGitUnstage(ctx, ws, msg, tabId, workingDir) {
|
|
@@ -275,7 +131,7 @@ async function handleGitUnstage(ctx, ws, msg, tabId, workingDir) {
|
|
|
275
131
|
ctx.send(ws, { type: 'gitUnstaged', tabId, data: { paths } });
|
|
276
132
|
}
|
|
277
133
|
catch (error) {
|
|
278
|
-
ctx
|
|
134
|
+
sendGitError(ctx, ws, tabId, error);
|
|
279
135
|
}
|
|
280
136
|
}
|
|
281
137
|
async function handleGitCommit(ctx, ws, msg, tabId, workingDir) {
|
|
@@ -301,7 +157,7 @@ async function handleGitCommit(ctx, ws, msg, tabId, workingDir) {
|
|
|
301
157
|
handleGitStatus(ctx, ws, tabId, workingDir);
|
|
302
158
|
}
|
|
303
159
|
catch (error) {
|
|
304
|
-
ctx
|
|
160
|
+
sendGitError(ctx, ws, tabId, error);
|
|
305
161
|
}
|
|
306
162
|
}
|
|
307
163
|
async function handleGitCommitWithAI(ctx, ws, msg, tabId, workingDir) {
|
|
@@ -313,27 +169,17 @@ async function handleGitCommitWithAI(ctx, ws, msg, tabId, workingDir) {
|
|
|
313
169
|
return;
|
|
314
170
|
}
|
|
315
171
|
const diffResult = await executeGitCommand(['diff', '--cached'], workingDir);
|
|
316
|
-
const diff = diffResult.stdout;
|
|
317
172
|
const logResult = await executeGitCommand(['log', '--oneline', '-5'], workingDir);
|
|
318
|
-
const recentCommits = logResult.stdout.trim();
|
|
319
|
-
const tempDir = join(workingDir, '.mstro', 'tmp');
|
|
320
|
-
if (!existsSync(tempDir)) {
|
|
321
|
-
mkdirSync(tempDir, { recursive: true });
|
|
322
|
-
}
|
|
323
|
-
let truncatedDiff = diff;
|
|
324
|
-
if (diff.length > 8000) {
|
|
325
|
-
truncatedDiff = `${diff.slice(0, 4000)}\n\n... [diff truncated] ...\n\n${diff.slice(-3500)}`;
|
|
326
|
-
}
|
|
327
173
|
const prompt = `You are generating a git commit message for the following staged changes.
|
|
328
174
|
|
|
329
175
|
RECENT COMMIT MESSAGES (for style reference):
|
|
330
|
-
${
|
|
176
|
+
${logResult.stdout.trim() || 'No recent commits'}
|
|
331
177
|
|
|
332
178
|
STAGED FILES:
|
|
333
179
|
${staged.map(f => `${f.status} ${f.path}`).join('\n')}
|
|
334
180
|
|
|
335
181
|
DIFF OF STAGED CHANGES:
|
|
336
|
-
${
|
|
182
|
+
${truncateDiff(diffResult.stdout)}
|
|
337
183
|
|
|
338
184
|
Generate a commit message following these rules:
|
|
339
185
|
1. First line: imperative mood, max 72 characters (e.g., "Add user authentication", "Fix memory leak in parser")
|
|
@@ -343,64 +189,28 @@ Generate a commit message following these rules:
|
|
|
343
189
|
5. No emojis unless the repo already uses them
|
|
344
190
|
|
|
345
191
|
Respond with ONLY the commit message, nothing else.`;
|
|
346
|
-
const
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
let stdout = '';
|
|
360
|
-
let stderr = '';
|
|
361
|
-
claude.stdout?.on('data', (data) => {
|
|
362
|
-
stdout += data.toString();
|
|
363
|
-
});
|
|
364
|
-
claude.stderr?.on('data', (data) => {
|
|
365
|
-
stderr += data.toString();
|
|
366
|
-
});
|
|
367
|
-
claude.on('close', async (code) => {
|
|
368
|
-
try {
|
|
369
|
-
unlinkSync(promptFile);
|
|
370
|
-
}
|
|
371
|
-
catch {
|
|
372
|
-
// Ignore cleanup errors
|
|
373
|
-
}
|
|
374
|
-
if (code !== 0 || !stdout.trim()) {
|
|
375
|
-
console.error('[WebSocketImproviseHandler] Claude commit message error:', stderr || 'No output');
|
|
376
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: 'Failed to generate commit message' } });
|
|
192
|
+
const result = await spawnHaikuWithPrompt(prompt, 'You are a commit message assistant. Respond with only the commit message, no preamble or explanation.', workingDir);
|
|
193
|
+
if (result.exitCode !== 0 || !result.stdout.trim()) {
|
|
194
|
+
console.error('[WebSocketImproviseHandler] Claude commit message error:', result.stderr || 'No output');
|
|
195
|
+
ctx.send(ws, { type: 'gitError', tabId, data: { error: 'Failed to generate commit message' } });
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const commitMessage = extractCommitMessage(result.stdout.trim());
|
|
199
|
+
const autoCommit = !!msg.data?.autoCommit;
|
|
200
|
+
ctx.send(ws, { type: 'gitCommitMessage', tabId, data: { message: commitMessage, autoCommit } });
|
|
201
|
+
if (autoCommit) {
|
|
202
|
+
const commitResult = await executeGitCommand(['commit', '-m', commitMessage], workingDir);
|
|
203
|
+
if (commitResult.exitCode !== 0) {
|
|
204
|
+
ctx.send(ws, { type: 'gitError', tabId, data: { error: commitResult.stderr || commitResult.stdout || 'Failed to commit' } });
|
|
377
205
|
return;
|
|
378
206
|
}
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
ctx
|
|
382
|
-
|
|
383
|
-
const commitResult = await executeGitCommand(['commit', '-m', commitMessage], workingDir);
|
|
384
|
-
if (commitResult.exitCode !== 0) {
|
|
385
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: commitResult.stderr || commitResult.stdout || 'Failed to commit' } });
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
const hashResult = await executeGitCommand(['rev-parse', '--short', 'HEAD'], workingDir);
|
|
389
|
-
const hash = hashResult.stdout.trim();
|
|
390
|
-
ctx.send(ws, { type: 'gitCommitted', tabId, data: { hash, message: commitMessage } });
|
|
391
|
-
handleGitStatus(ctx, ws, tabId, workingDir);
|
|
392
|
-
}
|
|
393
|
-
});
|
|
394
|
-
claude.on('error', (err) => {
|
|
395
|
-
console.error('[WebSocketImproviseHandler] Failed to spawn Claude for commit:', err);
|
|
396
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: 'Failed to generate commit message' } });
|
|
397
|
-
});
|
|
398
|
-
setTimeout(() => {
|
|
399
|
-
claude.kill();
|
|
400
|
-
}, 30000);
|
|
207
|
+
const hashResult = await executeGitCommand(['rev-parse', '--short', 'HEAD'], workingDir);
|
|
208
|
+
ctx.send(ws, { type: 'gitCommitted', tabId, data: { hash: hashResult.stdout.trim(), message: commitMessage } });
|
|
209
|
+
handleGitStatus(ctx, ws, tabId, workingDir);
|
|
210
|
+
}
|
|
401
211
|
}
|
|
402
212
|
catch (error) {
|
|
403
|
-
ctx
|
|
213
|
+
sendGitError(ctx, ws, tabId, error);
|
|
404
214
|
}
|
|
405
215
|
}
|
|
406
216
|
function extractCommitMessage(output) {
|
|
@@ -462,7 +272,7 @@ async function handleGitPush(ctx, ws, tabId, workingDir) {
|
|
|
462
272
|
ctx.send(ws, { type: 'gitPushed', tabId, data: { output: result.stdout || result.stderr } });
|
|
463
273
|
}
|
|
464
274
|
catch (error) {
|
|
465
|
-
ctx
|
|
275
|
+
sendGitError(ctx, ws, tabId, error);
|
|
466
276
|
}
|
|
467
277
|
}
|
|
468
278
|
async function handleGitPull(ctx, ws, tabId, workingDir) {
|
|
@@ -475,323 +285,7 @@ async function handleGitPull(ctx, ws, tabId, workingDir) {
|
|
|
475
285
|
ctx.send(ws, { type: 'gitPulled', tabId, data: { output: result.stdout || result.stderr } });
|
|
476
286
|
}
|
|
477
287
|
catch (error) {
|
|
478
|
-
ctx
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
async function handleGitLog(ctx, ws, msg, tabId, workingDir) {
|
|
482
|
-
const limit = msg.data?.limit ?? 10;
|
|
483
|
-
try {
|
|
484
|
-
const result = await executeGitCommand([
|
|
485
|
-
'log',
|
|
486
|
-
`-${limit}`,
|
|
487
|
-
'--format=%H|%h|%s|%an|%aI'
|
|
488
|
-
], workingDir);
|
|
489
|
-
if (result.exitCode !== 0) {
|
|
490
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: result.stderr || result.stdout || 'Failed to get log' } });
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
const entries = result.stdout.trim().split('\n').filter(Boolean).map(line => {
|
|
494
|
-
const [hash, shortHash, subject, author, date] = line.split('|');
|
|
495
|
-
const cleanSubject = stripCoauthorLines(subject || '') || subject || '';
|
|
496
|
-
return { hash, shortHash, subject: cleanSubject, author, date };
|
|
497
|
-
});
|
|
498
|
-
ctx.send(ws, { type: 'gitLog', tabId, data: { entries } });
|
|
499
|
-
}
|
|
500
|
-
catch (error) {
|
|
501
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: error instanceof Error ? error.message : String(error) } });
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
/** Directories to skip when scanning for git repos */
|
|
505
|
-
const SKIP_DIRS = ['node_modules', 'vendor', '.git'];
|
|
506
|
-
function shouldSkipDir(name) {
|
|
507
|
-
return name.startsWith('.') || SKIP_DIRS.includes(name);
|
|
508
|
-
}
|
|
509
|
-
async function getRepoBranch(repoPath) {
|
|
510
|
-
const result = await executeGitCommand(['rev-parse', '--abbrev-ref', 'HEAD'], repoPath);
|
|
511
|
-
return result.exitCode === 0 ? result.stdout.trim() : undefined;
|
|
512
|
-
}
|
|
513
|
-
async function scanForGitRepos(dir, depth, maxDepth, repos) {
|
|
514
|
-
if (depth > maxDepth)
|
|
515
|
-
return;
|
|
516
|
-
let entries;
|
|
517
|
-
try {
|
|
518
|
-
entries = readdirSync(dir);
|
|
519
|
-
}
|
|
520
|
-
catch {
|
|
521
|
-
return;
|
|
522
|
-
}
|
|
523
|
-
for (const name of entries) {
|
|
524
|
-
if (shouldSkipDir(name))
|
|
525
|
-
continue;
|
|
526
|
-
const fullPath = join(dir, name);
|
|
527
|
-
const gitPath = join(fullPath, '.git');
|
|
528
|
-
if (existsSync(gitPath)) {
|
|
529
|
-
repos.push({ path: fullPath, name, branch: await getRepoBranch(fullPath) });
|
|
530
|
-
}
|
|
531
|
-
else {
|
|
532
|
-
await scanForGitRepos(fullPath, depth + 1, maxDepth, repos);
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
async function handleGitDiscoverRepos(ctx, ws, tabId, workingDir) {
|
|
537
|
-
try {
|
|
538
|
-
const repos = [];
|
|
539
|
-
const rootIsGitRepo = existsSync(join(workingDir, '.git'));
|
|
540
|
-
if (rootIsGitRepo) {
|
|
541
|
-
repos.push({
|
|
542
|
-
path: workingDir,
|
|
543
|
-
name: workingDir.split('/').pop() || workingDir,
|
|
544
|
-
branch: await getRepoBranch(workingDir),
|
|
545
|
-
});
|
|
546
|
-
}
|
|
547
|
-
else {
|
|
548
|
-
await scanForGitRepos(workingDir, 1, 3, repos);
|
|
549
|
-
}
|
|
550
|
-
const response = {
|
|
551
|
-
repos,
|
|
552
|
-
rootIsGitRepo,
|
|
553
|
-
selectedDirectory: ctx.gitDirectories.get(tabId) || null,
|
|
554
|
-
};
|
|
555
|
-
ctx.send(ws, { type: 'gitReposDiscovered', tabId, data: response });
|
|
556
|
-
}
|
|
557
|
-
catch (error) {
|
|
558
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: error instanceof Error ? error.message : String(error) } });
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
async function handleGitSetDirectory(ctx, ws, msg, tabId, workingDir) {
|
|
562
|
-
const directory = msg.data?.directory;
|
|
563
|
-
if (!directory) {
|
|
564
|
-
ctx.gitDirectories.delete(tabId);
|
|
565
|
-
const response = {
|
|
566
|
-
directory: workingDir,
|
|
567
|
-
isValid: existsSync(join(workingDir, '.git')),
|
|
568
|
-
};
|
|
569
|
-
ctx.send(ws, { type: 'gitDirectorySet', tabId, data: response });
|
|
570
|
-
handleGitStatus(ctx, ws, tabId, workingDir);
|
|
571
|
-
return;
|
|
572
|
-
}
|
|
573
|
-
const gitPath = join(directory, '.git');
|
|
574
|
-
const isValid = existsSync(gitPath);
|
|
575
|
-
if (isValid) {
|
|
576
|
-
ctx.gitDirectories.set(tabId, directory);
|
|
577
|
-
}
|
|
578
|
-
const response = {
|
|
579
|
-
directory,
|
|
580
|
-
isValid,
|
|
581
|
-
};
|
|
582
|
-
ctx.send(ws, { type: 'gitDirectorySet', tabId, data: response });
|
|
583
|
-
if (isValid) {
|
|
584
|
-
handleGitStatus(ctx, ws, tabId, directory);
|
|
585
|
-
handleGitLog(ctx, ws, { type: 'gitLog', data: { limit: 5 } }, tabId, directory);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
async function handleGitListBranches(ctx, ws, tabId, workingDir) {
|
|
589
|
-
try {
|
|
590
|
-
const result = await executeGitCommand(['branch', '-a', '--format=%(refname:short)|%(objectname:short)|%(upstream:short)|%(HEAD)'], workingDir);
|
|
591
|
-
if (result.exitCode !== 0) {
|
|
592
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: result.stderr || 'Failed to list branches' } });
|
|
593
|
-
return;
|
|
594
|
-
}
|
|
595
|
-
const currentBranchResult = await executeGitCommand(['rev-parse', '--abbrev-ref', 'HEAD'], workingDir);
|
|
596
|
-
const currentBranch = currentBranchResult.stdout.trim() || 'HEAD';
|
|
597
|
-
const branches = result.stdout.trim().split('\n')
|
|
598
|
-
.filter(line => line.trim())
|
|
599
|
-
.map(line => {
|
|
600
|
-
const [name, shortHash, upstream, head] = line.split('|');
|
|
601
|
-
const isRemote = name.includes('/') && (name.startsWith('origin/') || name.includes('remotes/'));
|
|
602
|
-
return {
|
|
603
|
-
name: name.trim(),
|
|
604
|
-
shortHash: shortHash?.trim() || '',
|
|
605
|
-
isRemote,
|
|
606
|
-
isCurrent: head?.trim() === '*',
|
|
607
|
-
upstream: upstream?.trim() || undefined,
|
|
608
|
-
};
|
|
609
|
-
})
|
|
610
|
-
.filter(b => b.name !== 'origin/HEAD');
|
|
611
|
-
ctx.send(ws, { type: 'gitBranchList', tabId, data: { branches, current: currentBranch } });
|
|
612
|
-
}
|
|
613
|
-
catch (error) {
|
|
614
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: error instanceof Error ? error.message : String(error) } });
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
async function handleGitCheckout(ctx, ws, msg, tabId, workingDir) {
|
|
618
|
-
try {
|
|
619
|
-
const { branch, create, startPoint } = msg.data || {};
|
|
620
|
-
if (!branch) {
|
|
621
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: 'Branch name is required' } });
|
|
622
|
-
return;
|
|
623
|
-
}
|
|
624
|
-
const statusResult = await executeGitCommand(['status', '--porcelain'], workingDir);
|
|
625
|
-
if (statusResult.stdout.trim()) {
|
|
626
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: 'Commit or stash changes before switching branches' } });
|
|
627
|
-
return;
|
|
628
|
-
}
|
|
629
|
-
const prevResult = await executeGitCommand(['rev-parse', '--abbrev-ref', 'HEAD'], workingDir);
|
|
630
|
-
const previous = prevResult.stdout.trim();
|
|
631
|
-
const args = create
|
|
632
|
-
? ['checkout', '-b', branch, ...(startPoint ? [startPoint] : [])]
|
|
633
|
-
: ['checkout', branch];
|
|
634
|
-
const result = await executeGitCommand(args, workingDir);
|
|
635
|
-
if (result.exitCode !== 0) {
|
|
636
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: result.stderr || 'Failed to checkout branch' } });
|
|
637
|
-
return;
|
|
638
|
-
}
|
|
639
|
-
ctx.send(ws, { type: 'gitCheckedOut', tabId, data: { branch, previous } });
|
|
640
|
-
handleGitStatus(ctx, ws, tabId, workingDir);
|
|
641
|
-
}
|
|
642
|
-
catch (error) {
|
|
643
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: error instanceof Error ? error.message : String(error) } });
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
async function handleGitCreateBranch(ctx, ws, msg, tabId, workingDir) {
|
|
647
|
-
try {
|
|
648
|
-
const { name, startPoint, checkout } = msg.data || {};
|
|
649
|
-
if (!name) {
|
|
650
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: 'Branch name is required' } });
|
|
651
|
-
return;
|
|
652
|
-
}
|
|
653
|
-
const args = ['branch', name, ...(startPoint ? [startPoint] : [])];
|
|
654
|
-
const result = await executeGitCommand(args, workingDir);
|
|
655
|
-
if (result.exitCode !== 0) {
|
|
656
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: result.stderr || 'Failed to create branch' } });
|
|
657
|
-
return;
|
|
658
|
-
}
|
|
659
|
-
const hashResult = await executeGitCommand(['rev-parse', '--short', name], workingDir);
|
|
660
|
-
if (checkout) {
|
|
661
|
-
await executeGitCommand(['checkout', name], workingDir);
|
|
662
|
-
}
|
|
663
|
-
ctx.send(ws, { type: 'gitBranchCreated', tabId, data: { name, hash: hashResult.stdout.trim() } });
|
|
664
|
-
}
|
|
665
|
-
catch (error) {
|
|
666
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: error instanceof Error ? error.message : String(error) } });
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
async function handleGitDeleteBranch(ctx, ws, msg, tabId, workingDir) {
|
|
670
|
-
try {
|
|
671
|
-
const { name, force } = msg.data || {};
|
|
672
|
-
if (!name) {
|
|
673
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: 'Branch name is required' } });
|
|
674
|
-
return;
|
|
675
|
-
}
|
|
676
|
-
const currentResult = await executeGitCommand(['rev-parse', '--abbrev-ref', 'HEAD'], workingDir);
|
|
677
|
-
if (currentResult.stdout.trim() === name) {
|
|
678
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: 'Cannot delete the currently checked out branch' } });
|
|
679
|
-
return;
|
|
680
|
-
}
|
|
681
|
-
const result = await executeGitCommand(['branch', force ? '-D' : '-d', name], workingDir);
|
|
682
|
-
if (result.exitCode !== 0) {
|
|
683
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: result.stderr || 'Failed to delete branch' } });
|
|
684
|
-
return;
|
|
685
|
-
}
|
|
686
|
-
ctx.send(ws, { type: 'gitBranchDeleted', tabId, data: { name } });
|
|
687
|
-
}
|
|
688
|
-
catch (error) {
|
|
689
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: error instanceof Error ? error.message : String(error) } });
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
async function handleGitDiff(ctx, ws, msg, tabId, workingDir) {
|
|
693
|
-
try {
|
|
694
|
-
const { path, staged } = msg.data || {};
|
|
695
|
-
if (!path) {
|
|
696
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: 'File path is required' } });
|
|
697
|
-
return;
|
|
698
|
-
}
|
|
699
|
-
const originalResult = await executeGitCommand(['show', `HEAD:${path}`], workingDir);
|
|
700
|
-
const original = originalResult.exitCode === 0 ? originalResult.stdout : '';
|
|
701
|
-
let modified;
|
|
702
|
-
if (staged) {
|
|
703
|
-
const indexResult = await executeGitCommand(['show', `:${path}`], workingDir);
|
|
704
|
-
modified = indexResult.exitCode === 0 ? indexResult.stdout : '';
|
|
705
|
-
}
|
|
706
|
-
else {
|
|
707
|
-
const fullPath = join(workingDir, path);
|
|
708
|
-
try {
|
|
709
|
-
modified = readFileSync(fullPath, 'utf-8');
|
|
710
|
-
}
|
|
711
|
-
catch {
|
|
712
|
-
modified = '';
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
ctx.send(ws, {
|
|
716
|
-
type: 'gitDiffResult',
|
|
717
|
-
tabId,
|
|
718
|
-
data: { path, original, modified, staged: !!staged },
|
|
719
|
-
});
|
|
720
|
-
}
|
|
721
|
-
catch (error) {
|
|
722
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: error instanceof Error ? error.message : String(error) } });
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
async function handleGitListTags(ctx, ws, tabId, workingDir) {
|
|
726
|
-
try {
|
|
727
|
-
const result = await executeGitCommand(['tag', '-l', '--sort=-creatordate', '--format=%(refname:short)|%(objectname:short)|%(creatordate:iso-strict)|%(subject)'], workingDir);
|
|
728
|
-
if (result.exitCode !== 0) {
|
|
729
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: result.stderr || 'Failed to list tags' } });
|
|
730
|
-
return;
|
|
731
|
-
}
|
|
732
|
-
const tags = result.stdout.trim().split('\n')
|
|
733
|
-
.filter(line => line.trim())
|
|
734
|
-
.slice(0, 50)
|
|
735
|
-
.map(line => {
|
|
736
|
-
const parts = line.split('|');
|
|
737
|
-
return {
|
|
738
|
-
name: parts[0]?.trim() || '',
|
|
739
|
-
shortHash: parts[1]?.trim() || '',
|
|
740
|
-
date: parts[2]?.trim() || '',
|
|
741
|
-
message: parts[3]?.trim() || '',
|
|
742
|
-
};
|
|
743
|
-
});
|
|
744
|
-
ctx.send(ws, { type: 'gitTagList', tabId, data: { tags } });
|
|
745
|
-
}
|
|
746
|
-
catch (error) {
|
|
747
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: error instanceof Error ? error.message : String(error) } });
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
async function handleGitCreateTag(ctx, ws, msg, tabId, workingDir) {
|
|
751
|
-
try {
|
|
752
|
-
const { name, message, commit } = msg.data || {};
|
|
753
|
-
if (!name) {
|
|
754
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: 'Tag name is required' } });
|
|
755
|
-
return;
|
|
756
|
-
}
|
|
757
|
-
if (/\s/.test(name) || name.includes('..')) {
|
|
758
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: 'Invalid tag name: no spaces or ".." allowed' } });
|
|
759
|
-
return;
|
|
760
|
-
}
|
|
761
|
-
const args = message
|
|
762
|
-
? ['tag', '-a', name, '-m', message, ...(commit ? [commit] : [])]
|
|
763
|
-
: ['tag', name, ...(commit ? [commit] : [])];
|
|
764
|
-
const result = await executeGitCommand(args, workingDir);
|
|
765
|
-
if (result.exitCode !== 0) {
|
|
766
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: result.stderr || 'Failed to create tag' } });
|
|
767
|
-
return;
|
|
768
|
-
}
|
|
769
|
-
const hashResult = await executeGitCommand(['rev-parse', '--short', name], workingDir);
|
|
770
|
-
ctx.send(ws, { type: 'gitTagCreated', tabId, data: { name, hash: hashResult.stdout.trim() } });
|
|
771
|
-
}
|
|
772
|
-
catch (error) {
|
|
773
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: error instanceof Error ? error.message : String(error) } });
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
async function handleGitPushTag(ctx, ws, msg, tabId, workingDir) {
|
|
777
|
-
try {
|
|
778
|
-
const { name, all } = msg.data || {};
|
|
779
|
-
const args = all
|
|
780
|
-
? ['push', 'origin', '--tags']
|
|
781
|
-
: ['push', 'origin', name];
|
|
782
|
-
if (!all && !name) {
|
|
783
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: 'Tag name is required' } });
|
|
784
|
-
return;
|
|
785
|
-
}
|
|
786
|
-
const result = await executeGitCommand(args, workingDir);
|
|
787
|
-
if (result.exitCode !== 0) {
|
|
788
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: result.stderr || 'Failed to push tag' } });
|
|
789
|
-
return;
|
|
790
|
-
}
|
|
791
|
-
ctx.send(ws, { type: 'gitTagPushed', tabId, data: { name: name || 'all', output: result.stderr || result.stdout } });
|
|
792
|
-
}
|
|
793
|
-
catch (error) {
|
|
794
|
-
ctx.send(ws, { type: 'gitError', tabId, data: { error: error instanceof Error ? error.message : String(error) } });
|
|
288
|
+
sendGitError(ctx, ws, tabId, error);
|
|
795
289
|
}
|
|
796
290
|
}
|
|
797
291
|
//# sourceMappingURL=git-handlers.js.map
|