@getpaseo/server 0.1.2
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/.env.example +20 -0
- package/README.md +107 -0
- package/agent-prompt.md +339 -0
- package/dist/scripts/daemon-runner.js +32 -0
- package/dist/scripts/daemon-runner.js.map +1 -0
- package/dist/scripts/dev-runner.js +19 -0
- package/dist/scripts/dev-runner.js.map +1 -0
- package/dist/scripts/mcp-stdio-socket-bridge-cli.mjs +62 -0
- package/dist/scripts/supervisor.js +95 -0
- package/dist/scripts/supervisor.js.map +1 -0
- package/dist/server/client/daemon-client.d.ts +383 -0
- package/dist/server/client/daemon-client.d.ts.map +1 -0
- package/dist/server/client/daemon-client.js +2443 -0
- package/dist/server/client/daemon-client.js.map +1 -0
- package/dist/server/server/agent/activity-curator.d.ts +8 -0
- package/dist/server/server/agent/activity-curator.d.ts.map +1 -0
- package/dist/server/server/agent/activity-curator.js +228 -0
- package/dist/server/server/agent/activity-curator.js.map +1 -0
- package/dist/server/server/agent/agent-management-mcp.d.ts +34 -0
- package/dist/server/server/agent/agent-management-mcp.d.ts.map +1 -0
- package/dist/server/server/agent/agent-management-mcp.js +619 -0
- package/dist/server/server/agent/agent-management-mcp.js.map +1 -0
- package/dist/server/server/agent/agent-manager.d.ts +182 -0
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -0
- package/dist/server/server/agent/agent-manager.js +1066 -0
- package/dist/server/server/agent/agent-manager.js.map +1 -0
- package/dist/server/server/agent/agent-metadata-generator.d.ts +29 -0
- package/dist/server/server/agent/agent-metadata-generator.d.ts.map +1 -0
- package/dist/server/server/agent/agent-metadata-generator.js +157 -0
- package/dist/server/server/agent/agent-metadata-generator.js.map +1 -0
- package/dist/server/server/agent/agent-projections.d.ts +12 -0
- package/dist/server/server/agent/agent-projections.d.ts.map +1 -0
- package/dist/server/server/agent/agent-projections.js +238 -0
- package/dist/server/server/agent/agent-projections.js.map +1 -0
- package/dist/server/server/agent/agent-response-loop.d.ts +32 -0
- package/dist/server/server/agent/agent-response-loop.d.ts.map +1 -0
- package/dist/server/server/agent/agent-response-loop.js +224 -0
- package/dist/server/server/agent/agent-response-loop.js.map +1 -0
- package/dist/server/server/agent/agent-sdk-types.d.ts +360 -0
- package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -0
- package/dist/server/server/agent/agent-sdk-types.js +2 -0
- package/dist/server/server/agent/agent-sdk-types.js.map +1 -0
- package/dist/server/server/agent/agent-storage.d.ts +187 -0
- package/dist/server/server/agent/agent-storage.d.ts.map +1 -0
- package/dist/server/server/agent/agent-storage.js +328 -0
- package/dist/server/server/agent/agent-storage.js.map +1 -0
- package/dist/server/server/agent/audio-utils.d.ts +3 -0
- package/dist/server/server/agent/audio-utils.d.ts.map +1 -0
- package/dist/server/server/agent/audio-utils.js +19 -0
- package/dist/server/server/agent/audio-utils.js.map +1 -0
- package/dist/server/server/agent/dictation-debug.d.ts +13 -0
- package/dist/server/server/agent/dictation-debug.d.ts.map +1 -0
- package/dist/server/server/agent/dictation-debug.js +50 -0
- package/dist/server/server/agent/dictation-debug.js.map +1 -0
- package/dist/server/server/agent/llm-openai.d.ts +7 -0
- package/dist/server/server/agent/llm-openai.d.ts.map +1 -0
- package/dist/server/server/agent/llm-openai.js +8 -0
- package/dist/server/server/agent/llm-openai.js.map +1 -0
- package/dist/server/server/agent/mcp-server.d.ts +26 -0
- package/dist/server/server/agent/mcp-server.d.ts.map +1 -0
- package/dist/server/server/agent/mcp-server.js +762 -0
- package/dist/server/server/agent/mcp-server.js.map +1 -0
- package/dist/server/server/agent/model-resolver.d.ts +11 -0
- package/dist/server/server/agent/model-resolver.d.ts.map +1 -0
- package/dist/server/server/agent/model-resolver.js +21 -0
- package/dist/server/server/agent/model-resolver.js.map +1 -0
- package/dist/server/server/agent/orchestrator-instructions.d.ts +7 -0
- package/dist/server/server/agent/orchestrator-instructions.d.ts.map +1 -0
- package/dist/server/server/agent/orchestrator-instructions.js +51 -0
- package/dist/server/server/agent/orchestrator-instructions.js.map +1 -0
- package/dist/server/server/agent/orchestrator.d.ts +12 -0
- package/dist/server/server/agent/orchestrator.d.ts.map +1 -0
- package/dist/server/server/agent/orchestrator.js +12 -0
- package/dist/server/server/agent/orchestrator.js.map +1 -0
- package/dist/server/server/agent/pcm16-resampler.d.ts +14 -0
- package/dist/server/server/agent/pcm16-resampler.d.ts.map +1 -0
- package/dist/server/server/agent/pcm16-resampler.js +63 -0
- package/dist/server/server/agent/pcm16-resampler.js.map +1 -0
- package/dist/server/server/agent/provider-launch-config.d.ts +139 -0
- package/dist/server/server/agent/provider-launch-config.d.ts.map +1 -0
- package/dist/server/server/agent/provider-launch-config.js +83 -0
- package/dist/server/server/agent/provider-launch-config.js.map +1 -0
- package/dist/server/server/agent/provider-manifest.d.ts +20 -0
- package/dist/server/server/agent/provider-manifest.d.ts.map +1 -0
- package/dist/server/server/agent/provider-manifest.js +97 -0
- package/dist/server/server/agent/provider-manifest.js.map +1 -0
- package/dist/server/server/agent/provider-registry.d.ts +18 -0
- package/dist/server/server/agent/provider-registry.d.ts.map +1 -0
- package/dist/server/server/agent/provider-registry.js +45 -0
- package/dist/server/server/agent/provider-registry.js.map +1 -0
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.d.ts +3 -0
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js +42 -0
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js.map +1 -0
- package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts +16 -0
- package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js +73 -0
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js.map +1 -0
- package/dist/server/server/agent/providers/claude-agent.d.ts +35 -0
- package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude-agent.js +2056 -0
- package/dist/server/server/agent/providers/claude-agent.js.map +1 -0
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts +13 -0
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts.map +1 -0
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js +67 -0
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js.map +1 -0
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts +15 -0
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts.map +1 -0
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js +640 -0
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js.map +1 -0
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +34 -0
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -0
- package/dist/server/server/agent/providers/codex-app-server-agent.js +2476 -0
- package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -0
- package/dist/server/server/agent/providers/codex-rollout-timeline.d.ts +9 -0
- package/dist/server/server/agent/providers/codex-rollout-timeline.d.ts.map +1 -0
- package/dist/server/server/agent/providers/codex-rollout-timeline.js +486 -0
- package/dist/server/server/agent/providers/codex-rollout-timeline.js.map +1 -0
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts +3 -0
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts.map +1 -0
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js +33 -0
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js.map +1 -0
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts +13 -0
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts.map +1 -0
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.js +75 -0
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.js.map +1 -0
- package/dist/server/server/agent/providers/opencode-agent.d.ts +37 -0
- package/dist/server/server/agent/providers/opencode-agent.d.ts.map +1 -0
- package/dist/server/server/agent/providers/opencode-agent.js +822 -0
- package/dist/server/server/agent/providers/opencode-agent.js.map +1 -0
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +1363 -0
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts.map +1 -0
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js +534 -0
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js.map +1 -0
- package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts +18 -0
- package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts.map +1 -0
- package/dist/server/server/agent/providers/tool-call-mapper-utils.js +119 -0
- package/dist/server/server/agent/providers/tool-call-mapper-utils.js.map +1 -0
- package/dist/server/server/agent/recordings-debug.d.ts +3 -0
- package/dist/server/server/agent/recordings-debug.d.ts.map +1 -0
- package/dist/server/server/agent/recordings-debug.js +19 -0
- package/dist/server/server/agent/recordings-debug.js.map +1 -0
- package/dist/server/server/agent/stt-debug.d.ts +10 -0
- package/dist/server/server/agent/stt-debug.d.ts.map +1 -0
- package/dist/server/server/agent/stt-debug.js +33 -0
- package/dist/server/server/agent/stt-debug.js.map +1 -0
- package/dist/server/server/agent/stt-manager.d.ts +32 -0
- package/dist/server/server/agent/stt-manager.d.ts.map +1 -0
- package/dist/server/server/agent/stt-manager.js +231 -0
- package/dist/server/server/agent/stt-manager.js.map +1 -0
- package/dist/server/server/agent/system-prompt.d.ts +3 -0
- package/dist/server/server/agent/system-prompt.d.ts.map +1 -0
- package/dist/server/server/agent/system-prompt.js +19 -0
- package/dist/server/server/agent/system-prompt.js.map +1 -0
- package/dist/server/server/agent/tool-name-normalization.d.ts +7 -0
- package/dist/server/server/agent/tool-name-normalization.d.ts.map +1 -0
- package/dist/server/server/agent/tool-name-normalization.js +45 -0
- package/dist/server/server/agent/tool-name-normalization.js.map +1 -0
- package/dist/server/server/agent/tts-debug.d.ts +8 -0
- package/dist/server/server/agent/tts-debug.d.ts.map +1 -0
- package/dist/server/server/agent/tts-debug.js +24 -0
- package/dist/server/server/agent/tts-debug.js.map +1 -0
- package/dist/server/server/agent/tts-manager.d.ts +33 -0
- package/dist/server/server/agent/tts-manager.d.ts.map +1 -0
- package/dist/server/server/agent/tts-manager.js +261 -0
- package/dist/server/server/agent/tts-manager.js.map +1 -0
- package/dist/server/server/agent/wait-for-agent-tracker.d.ts +15 -0
- package/dist/server/server/agent/wait-for-agent-tracker.d.ts.map +1 -0
- package/dist/server/server/agent/wait-for-agent-tracker.js +53 -0
- package/dist/server/server/agent/wait-for-agent-tracker.js.map +1 -0
- package/dist/server/server/allowed-hosts.d.ts +13 -0
- package/dist/server/server/allowed-hosts.d.ts.map +1 -0
- package/dist/server/server/allowed-hosts.js +94 -0
- package/dist/server/server/allowed-hosts.js.map +1 -0
- package/dist/server/server/bootstrap.d.ts +49 -0
- package/dist/server/server/bootstrap.d.ts.map +1 -0
- package/dist/server/server/bootstrap.js +483 -0
- package/dist/server/server/bootstrap.js.map +1 -0
- package/dist/server/server/config.d.ts +13 -0
- package/dist/server/server/config.d.ts.map +1 -0
- package/dist/server/server/config.js +84 -0
- package/dist/server/server/config.js.map +1 -0
- package/dist/server/server/connection-offer.d.ts +19 -0
- package/dist/server/server/connection-offer.d.ts.map +1 -0
- package/dist/server/server/connection-offer.js +60 -0
- package/dist/server/server/connection-offer.js.map +1 -0
- package/dist/server/server/daemon-keypair.d.ts +8 -0
- package/dist/server/server/daemon-keypair.d.ts.map +1 -0
- package/dist/server/server/daemon-keypair.js +40 -0
- package/dist/server/server/daemon-keypair.js.map +1 -0
- package/dist/server/server/dictation/dictation-stream-manager.d.ts +76 -0
- package/dist/server/server/dictation/dictation-stream-manager.d.ts.map +1 -0
- package/dist/server/server/dictation/dictation-stream-manager.js +481 -0
- package/dist/server/server/dictation/dictation-stream-manager.js.map +1 -0
- package/dist/server/server/exports.d.ts +11 -0
- package/dist/server/server/exports.d.ts.map +1 -0
- package/dist/server/server/exports.js +11 -0
- package/dist/server/server/exports.js.map +1 -0
- package/dist/server/server/file-download/token-store.d.ts +25 -0
- package/dist/server/server/file-download/token-store.d.ts.map +1 -0
- package/dist/server/server/file-download/token-store.js +40 -0
- package/dist/server/server/file-download/token-store.js.map +1 -0
- package/dist/server/server/file-explorer/service.d.ts +41 -0
- package/dist/server/server/file-explorer/service.d.ts.map +1 -0
- package/dist/server/server/file-explorer/service.js +163 -0
- package/dist/server/server/file-explorer/service.js.map +1 -0
- package/dist/server/server/index.d.ts +2 -0
- package/dist/server/server/index.d.ts.map +1 -0
- package/dist/server/server/index.js +90 -0
- package/dist/server/server/index.js.map +1 -0
- package/dist/server/server/json-utils.d.ts +11 -0
- package/dist/server/server/json-utils.d.ts.map +1 -0
- package/dist/server/server/json-utils.js +45 -0
- package/dist/server/server/json-utils.js.map +1 -0
- package/dist/server/server/logger.d.ts +12 -0
- package/dist/server/server/logger.d.ts.map +1 -0
- package/dist/server/server/logger.js +29 -0
- package/dist/server/server/logger.js.map +1 -0
- package/dist/server/server/messages.d.ts +9 -0
- package/dist/server/server/messages.d.ts.map +1 -0
- package/dist/server/server/messages.js +29 -0
- package/dist/server/server/messages.js.map +1 -0
- package/dist/server/server/pairing-offer.d.ts +16 -0
- package/dist/server/server/pairing-offer.d.ts.map +1 -0
- package/dist/server/server/pairing-offer.js +45 -0
- package/dist/server/server/pairing-offer.js.map +1 -0
- package/dist/server/server/pairing-qr.d.ts +7 -0
- package/dist/server/server/pairing-qr.d.ts.map +1 -0
- package/dist/server/server/pairing-qr.js +45 -0
- package/dist/server/server/pairing-qr.js.map +1 -0
- package/dist/server/server/paseo-home.d.ts +2 -0
- package/dist/server/server/paseo-home.d.ts.map +1 -0
- package/dist/server/server/paseo-home.js +19 -0
- package/dist/server/server/paseo-home.js.map +1 -0
- package/dist/server/server/path-utils.d.ts +3 -0
- package/dist/server/server/path-utils.d.ts.map +1 -0
- package/dist/server/server/path-utils.js +20 -0
- package/dist/server/server/path-utils.js.map +1 -0
- package/dist/server/server/persisted-config.d.ts +500 -0
- package/dist/server/server/persisted-config.d.ts.map +1 -0
- package/dist/server/server/persisted-config.js +212 -0
- package/dist/server/server/persisted-config.js.map +1 -0
- package/dist/server/server/persistence-hooks.d.ts +24 -0
- package/dist/server/server/persistence-hooks.d.ts.map +1 -0
- package/dist/server/server/persistence-hooks.js +60 -0
- package/dist/server/server/persistence-hooks.js.map +1 -0
- package/dist/server/server/pid-lock.d.ts +19 -0
- package/dist/server/server/pid-lock.d.ts.map +1 -0
- package/dist/server/server/pid-lock.js +115 -0
- package/dist/server/server/pid-lock.js.map +1 -0
- package/dist/server/server/push/push-service.d.ts +21 -0
- package/dist/server/server/push/push-service.d.ts.map +1 -0
- package/dist/server/server/push/push-service.js +68 -0
- package/dist/server/server/push/push-service.js.map +1 -0
- package/dist/server/server/push/token-store.d.ts +18 -0
- package/dist/server/server/push/token-store.d.ts.map +1 -0
- package/dist/server/server/push/token-store.js +70 -0
- package/dist/server/server/push/token-store.js.map +1 -0
- package/dist/server/server/relay-transport.d.ts +22 -0
- package/dist/server/server/relay-transport.d.ts.map +1 -0
- package/dist/server/server/relay-transport.js +374 -0
- package/dist/server/server/relay-transport.js.map +1 -0
- package/dist/server/server/server-id.d.ts +17 -0
- package/dist/server/server/server-id.d.ts.map +1 -0
- package/dist/server/server/server-id.js +63 -0
- package/dist/server/server/server-id.js.map +1 -0
- package/dist/server/server/session.d.ts +360 -0
- package/dist/server/server/session.d.ts.map +1 -0
- package/dist/server/server/session.js +4615 -0
- package/dist/server/server/session.js.map +1 -0
- package/dist/server/server/speech/audio.d.ts +10 -0
- package/dist/server/server/speech/audio.d.ts.map +1 -0
- package/dist/server/server/speech/audio.js +101 -0
- package/dist/server/server/speech/audio.js.map +1 -0
- package/dist/server/server/speech/providers/local/config.d.ts +26 -0
- package/dist/server/server/speech/providers/local/config.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/config.js +93 -0
- package/dist/server/server/speech/providers/local/config.js.map +1 -0
- package/dist/server/server/speech/providers/local/models.d.ts +12 -0
- package/dist/server/server/speech/providers/local/models.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/models.js +18 -0
- package/dist/server/server/speech/providers/local/models.js.map +1 -0
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.d.ts +24 -0
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.js +422 -0
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.js.map +1 -0
- package/dist/server/server/speech/providers/local/runtime.d.ts +30 -0
- package/dist/server/server/speech/providers/local/runtime.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/runtime.js +254 -0
- package/dist/server/server/speech/providers/local/runtime.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts +117 -0
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.js +166 -0
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts +17 -0
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.js +151 -0
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.d.ts +28 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js +68 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.d.ts +37 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.js +79 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.d.ts +7 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.js +11 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.d.ts +7 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js +44 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.d.ts +28 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js +131 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.d.ts +21 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js +132 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.d.ts +23 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.js +112 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.d.ts +23 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.js +140 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.d.ts +21 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js +95 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js.map +1 -0
- package/dist/server/server/speech/providers/openai/config.d.ts +22 -0
- package/dist/server/server/speech/providers/openai/config.d.ts.map +1 -0
- package/dist/server/server/speech/providers/openai/config.js +94 -0
- package/dist/server/server/speech/providers/openai/config.js.map +1 -0
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.d.ts +42 -0
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.d.ts.map +1 -0
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.js +165 -0
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.js.map +1 -0
- package/dist/server/server/speech/providers/openai/runtime.d.ts +27 -0
- package/dist/server/server/speech/providers/openai/runtime.d.ts.map +1 -0
- package/dist/server/server/speech/providers/openai/runtime.js +103 -0
- package/dist/server/server/speech/providers/openai/runtime.js.map +1 -0
- package/dist/server/server/speech/providers/openai/stt.d.ts +22 -0
- package/dist/server/server/speech/providers/openai/stt.d.ts.map +1 -0
- package/dist/server/server/speech/providers/openai/stt.js +208 -0
- package/dist/server/server/speech/providers/openai/stt.js.map +1 -0
- package/dist/server/server/speech/providers/openai/tts.d.ts +18 -0
- package/dist/server/server/speech/providers/openai/tts.d.ts.map +1 -0
- package/dist/server/server/speech/providers/openai/tts.js +46 -0
- package/dist/server/server/speech/providers/openai/tts.js.map +1 -0
- package/dist/server/server/speech/speech-config-resolver.d.ts +11 -0
- package/dist/server/server/speech/speech-config-resolver.d.ts.map +1 -0
- package/dist/server/server/speech/speech-config-resolver.js +64 -0
- package/dist/server/server/speech/speech-config-resolver.js.map +1 -0
- package/dist/server/server/speech/speech-provider.d.ts +59 -0
- package/dist/server/server/speech/speech-provider.d.ts.map +1 -0
- package/dist/server/server/speech/speech-provider.js +2 -0
- package/dist/server/server/speech/speech-provider.js.map +1 -0
- package/dist/server/server/speech/speech-runtime.d.ts +20 -0
- package/dist/server/server/speech/speech-runtime.d.ts.map +1 -0
- package/dist/server/server/speech/speech-runtime.js +119 -0
- package/dist/server/server/speech/speech-runtime.js.map +1 -0
- package/dist/server/server/speech/speech-types.d.ts +20 -0
- package/dist/server/server/speech/speech-types.d.ts.map +1 -0
- package/dist/server/server/speech/speech-types.js +7 -0
- package/dist/server/server/speech/speech-types.js.map +1 -0
- package/dist/server/server/terminal-mcp/index.d.ts +4 -0
- package/dist/server/server/terminal-mcp/index.d.ts.map +1 -0
- package/dist/server/server/terminal-mcp/index.js +3 -0
- package/dist/server/server/terminal-mcp/index.js.map +1 -0
- package/dist/server/server/terminal-mcp/server.d.ts +10 -0
- package/dist/server/server/terminal-mcp/server.d.ts.map +1 -0
- package/dist/server/server/terminal-mcp/server.js +217 -0
- package/dist/server/server/terminal-mcp/server.js.map +1 -0
- package/dist/server/server/terminal-mcp/terminal-manager.d.ts +123 -0
- package/dist/server/server/terminal-mcp/terminal-manager.d.ts.map +1 -0
- package/dist/server/server/terminal-mcp/terminal-manager.js +351 -0
- package/dist/server/server/terminal-mcp/terminal-manager.js.map +1 -0
- package/dist/server/server/terminal-mcp/tmux.d.ts +207 -0
- package/dist/server/server/terminal-mcp/tmux.d.ts.map +1 -0
- package/dist/server/server/terminal-mcp/tmux.js +924 -0
- package/dist/server/server/terminal-mcp/tmux.js.map +1 -0
- package/dist/server/server/types.d.ts +5 -0
- package/dist/server/server/types.d.ts.map +1 -0
- package/dist/server/server/types.js +3 -0
- package/dist/server/server/types.js.map +1 -0
- package/dist/server/server/utils/diff-highlighter.d.ts +52 -0
- package/dist/server/server/utils/diff-highlighter.d.ts.map +1 -0
- package/dist/server/server/utils/diff-highlighter.js +244 -0
- package/dist/server/server/utils/diff-highlighter.js.map +1 -0
- package/dist/server/server/utils/syntax-highlighter.d.ts +10 -0
- package/dist/server/server/utils/syntax-highlighter.d.ts.map +1 -0
- package/dist/server/server/utils/syntax-highlighter.js +141 -0
- package/dist/server/server/utils/syntax-highlighter.js.map +1 -0
- package/dist/server/server/voice-config.d.ts +14 -0
- package/dist/server/server/voice-config.d.ts.map +1 -0
- package/dist/server/server/voice-config.js +51 -0
- package/dist/server/server/voice-config.js.map +1 -0
- package/dist/server/server/voice-mcp-bridge-command.d.ts +17 -0
- package/dist/server/server/voice-mcp-bridge-command.d.ts.map +1 -0
- package/dist/server/server/voice-mcp-bridge-command.js +31 -0
- package/dist/server/server/voice-mcp-bridge-command.js.map +1 -0
- package/dist/server/server/voice-mcp-bridge.d.ts +18 -0
- package/dist/server/server/voice-mcp-bridge.d.ts.map +1 -0
- package/dist/server/server/voice-mcp-bridge.js +109 -0
- package/dist/server/server/voice-mcp-bridge.js.map +1 -0
- package/dist/server/server/voice-permission-policy.d.ts +4 -0
- package/dist/server/server/voice-permission-policy.d.ts.map +1 -0
- package/dist/server/server/voice-permission-policy.js +13 -0
- package/dist/server/server/voice-permission-policy.js.map +1 -0
- package/dist/server/server/voice-types.d.ts +17 -0
- package/dist/server/server/voice-types.d.ts.map +1 -0
- package/dist/server/server/voice-types.js +2 -0
- package/dist/server/server/voice-types.js.map +1 -0
- package/dist/server/server/websocket-server.d.ts +80 -0
- package/dist/server/server/websocket-server.d.ts.map +1 -0
- package/dist/server/server/websocket-server.js +447 -0
- package/dist/server/server/websocket-server.js.map +1 -0
- package/dist/server/shared/agent-lifecycle.d.ts +3 -0
- package/dist/server/shared/agent-lifecycle.d.ts.map +1 -0
- package/dist/server/shared/agent-lifecycle.js +8 -0
- package/dist/server/shared/agent-lifecycle.js.map +1 -0
- package/dist/server/shared/connection-offer.d.ts +62 -0
- package/dist/server/shared/connection-offer.d.ts.map +1 -0
- package/dist/server/shared/connection-offer.js +17 -0
- package/dist/server/shared/connection-offer.js.map +1 -0
- package/dist/server/shared/daemon-endpoints.d.ts +19 -0
- package/dist/server/shared/daemon-endpoints.d.ts.map +1 -0
- package/dist/server/shared/daemon-endpoints.js +98 -0
- package/dist/server/shared/daemon-endpoints.js.map +1 -0
- package/dist/server/shared/messages.d.ts +36729 -0
- package/dist/server/shared/messages.d.ts.map +1 -0
- package/dist/server/shared/messages.js +1666 -0
- package/dist/server/shared/messages.js.map +1 -0
- package/dist/server/shared/path-utils.d.ts +2 -0
- package/dist/server/shared/path-utils.d.ts.map +1 -0
- package/dist/server/shared/path-utils.js +16 -0
- package/dist/server/shared/path-utils.js.map +1 -0
- package/dist/server/shared/tool-call-display.d.ts +11 -0
- package/dist/server/shared/tool-call-display.d.ts.map +1 -0
- package/dist/server/shared/tool-call-display.js +82 -0
- package/dist/server/shared/tool-call-display.js.map +1 -0
- package/dist/server/terminal/terminal-manager.d.ts +14 -0
- package/dist/server/terminal/terminal-manager.d.ts.map +1 -0
- package/dist/server/terminal/terminal-manager.js +67 -0
- package/dist/server/terminal/terminal-manager.js.map +1 -0
- package/dist/server/terminal/terminal.d.ts +67 -0
- package/dist/server/terminal/terminal.d.ts.map +1 -0
- package/dist/server/terminal/terminal.js +190 -0
- package/dist/server/terminal/terminal.js.map +1 -0
- package/dist/server/utils/checkout-git.d.ts +138 -0
- package/dist/server/utils/checkout-git.d.ts.map +1 -0
- package/dist/server/utils/checkout-git.js +1079 -0
- package/dist/server/utils/checkout-git.js.map +1 -0
- package/dist/server/utils/path.d.ts +5 -0
- package/dist/server/utils/path.d.ts.map +1 -0
- package/dist/server/utils/path.js +15 -0
- package/dist/server/utils/path.js.map +1 -0
- package/dist/server/utils/project-icon.d.ts +39 -0
- package/dist/server/utils/project-icon.d.ts.map +1 -0
- package/dist/server/utils/project-icon.js +391 -0
- package/dist/server/utils/project-icon.js.map +1 -0
- package/dist/server/utils/worktree-metadata.d.ts +21 -0
- package/dist/server/utils/worktree-metadata.d.ts.map +1 -0
- package/dist/server/utils/worktree-metadata.js +74 -0
- package/dist/server/utils/worktree-metadata.js.map +1 -0
- package/dist/server/utils/worktree.d.ts +95 -0
- package/dist/server/utils/worktree.d.ts.map +1 -0
- package/dist/server/utils/worktree.js +568 -0
- package/dist/server/utils/worktree.js.map +1 -0
- package/package.json +108 -0
|
@@ -0,0 +1,1079 @@
|
|
|
1
|
+
import { exec, execFile, spawn } from "child_process";
|
|
2
|
+
import { promisify } from "util";
|
|
3
|
+
import { resolve, dirname, basename } from "path";
|
|
4
|
+
import { realpathSync } from "fs";
|
|
5
|
+
import { open as openFile, stat as statFile } from "fs/promises";
|
|
6
|
+
import { parseAndHighlightDiff } from "../server/utils/diff-highlighter.js";
|
|
7
|
+
import { isPaseoOwnedWorktreeCwd } from "./worktree.js";
|
|
8
|
+
import { requirePaseoWorktreeBaseRefName } from "./worktree-metadata.js";
|
|
9
|
+
const execAsync = promisify(exec);
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
|
+
const READ_ONLY_GIT_ENV = {
|
|
12
|
+
...process.env,
|
|
13
|
+
GIT_OPTIONAL_LOCKS: "0",
|
|
14
|
+
};
|
|
15
|
+
const SMALL_OUTPUT_MAX_BUFFER = 20 * 1024 * 1024; // 20MB
|
|
16
|
+
async function execGit(command, options) {
|
|
17
|
+
return execAsync(command, { ...options, maxBuffer: SMALL_OUTPUT_MAX_BUFFER });
|
|
18
|
+
}
|
|
19
|
+
async function spawnLimitedText(params) {
|
|
20
|
+
const accept = new Set(params.acceptExitCodes ?? [0]);
|
|
21
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
22
|
+
const child = spawn(params.cmd, params.args, {
|
|
23
|
+
cwd: params.cwd,
|
|
24
|
+
env: params.env,
|
|
25
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
26
|
+
});
|
|
27
|
+
const stdoutChunks = [];
|
|
28
|
+
let stdoutBytes = 0;
|
|
29
|
+
let truncated = false;
|
|
30
|
+
const stop = () => {
|
|
31
|
+
if (child.killed)
|
|
32
|
+
return;
|
|
33
|
+
try {
|
|
34
|
+
child.kill("SIGKILL");
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// ignore
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
child.stdout.on("data", (chunk) => {
|
|
41
|
+
if (truncated)
|
|
42
|
+
return;
|
|
43
|
+
stdoutBytes += chunk.length;
|
|
44
|
+
if (stdoutBytes > params.maxBytes) {
|
|
45
|
+
truncated = true;
|
|
46
|
+
stop();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
stdoutChunks.push(chunk);
|
|
50
|
+
});
|
|
51
|
+
// We don't buffer stderr (it can be large too). Keep it minimal for debugging.
|
|
52
|
+
let stderrPreview = "";
|
|
53
|
+
child.stderr.on("data", (chunk) => {
|
|
54
|
+
if (stderrPreview.length > 2048)
|
|
55
|
+
return;
|
|
56
|
+
stderrPreview += chunk.toString("utf8");
|
|
57
|
+
});
|
|
58
|
+
child.on("error", (error) => {
|
|
59
|
+
rejectPromise(error);
|
|
60
|
+
});
|
|
61
|
+
child.on("close", (code, signal) => {
|
|
62
|
+
if (code !== null && !accept.has(code) && !truncated) {
|
|
63
|
+
rejectPromise(new Error(`Command failed: ${params.cmd} ${params.args.join(" ")} (code ${code})\n${stderrPreview}`));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
resolvePromise({
|
|
67
|
+
text: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
68
|
+
truncated,
|
|
69
|
+
exitCode: code,
|
|
70
|
+
signal,
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async function listCheckoutFileChanges(cwd, ref) {
|
|
76
|
+
const changes = [];
|
|
77
|
+
const { stdout: nameStatusOut } = await execGit(`git diff --name-status ${ref}`, {
|
|
78
|
+
cwd,
|
|
79
|
+
env: READ_ONLY_GIT_ENV,
|
|
80
|
+
});
|
|
81
|
+
for (const line of nameStatusOut.split("\n").map((l) => l.trim()).filter(Boolean)) {
|
|
82
|
+
// `--name-status` uses TAB separators, which preserves filenames with spaces.
|
|
83
|
+
const tabParts = line.split("\t");
|
|
84
|
+
const rawStatus = (tabParts[0] ?? "").trim();
|
|
85
|
+
if (!rawStatus)
|
|
86
|
+
continue;
|
|
87
|
+
if (rawStatus.startsWith("R") || rawStatus.startsWith("C")) {
|
|
88
|
+
const oldPath = tabParts[1];
|
|
89
|
+
const newPath = tabParts[2];
|
|
90
|
+
if (newPath) {
|
|
91
|
+
changes.push({
|
|
92
|
+
path: newPath,
|
|
93
|
+
...(oldPath ? { oldPath } : {}),
|
|
94
|
+
status: rawStatus,
|
|
95
|
+
isNew: false,
|
|
96
|
+
isDeleted: false,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const path = tabParts[1];
|
|
102
|
+
if (!path)
|
|
103
|
+
continue;
|
|
104
|
+
const code = rawStatus[0];
|
|
105
|
+
changes.push({
|
|
106
|
+
path,
|
|
107
|
+
status: rawStatus,
|
|
108
|
+
isNew: code === "A",
|
|
109
|
+
isDeleted: code === "D",
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
const { stdout: untrackedOut } = await execGit("git ls-files --others --exclude-standard", {
|
|
113
|
+
cwd,
|
|
114
|
+
env: READ_ONLY_GIT_ENV,
|
|
115
|
+
});
|
|
116
|
+
for (const file of untrackedOut.split("\n").map((l) => l.trim()).filter(Boolean)) {
|
|
117
|
+
changes.push({
|
|
118
|
+
path: file,
|
|
119
|
+
status: "U",
|
|
120
|
+
isNew: true,
|
|
121
|
+
isDeleted: false,
|
|
122
|
+
isUntracked: true,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
// Deduplicate by path (prefer tracked status over untracked marker if both appear).
|
|
126
|
+
const byPath = new Map();
|
|
127
|
+
for (const change of changes) {
|
|
128
|
+
const existing = byPath.get(change.path);
|
|
129
|
+
if (!existing) {
|
|
130
|
+
byPath.set(change.path, change);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (existing.isUntracked && !change.isUntracked) {
|
|
134
|
+
byPath.set(change.path, change);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return Array.from(byPath.values());
|
|
138
|
+
}
|
|
139
|
+
async function tryResolveMergeBase(cwd, baseRef) {
|
|
140
|
+
try {
|
|
141
|
+
const { stdout } = await execGit(`git merge-base ${baseRef} HEAD`, { cwd, env: READ_ONLY_GIT_ENV });
|
|
142
|
+
const sha = stdout.trim();
|
|
143
|
+
return sha.length > 0 ? sha : null;
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async function tryGetNumstat(cwd, args) {
|
|
150
|
+
try {
|
|
151
|
+
const { text } = await spawnLimitedText({
|
|
152
|
+
cmd: "git",
|
|
153
|
+
args,
|
|
154
|
+
cwd,
|
|
155
|
+
env: READ_ONLY_GIT_ENV,
|
|
156
|
+
maxBytes: 64 * 1024,
|
|
157
|
+
acceptExitCodes: [0],
|
|
158
|
+
});
|
|
159
|
+
const line = text.trim().split("\n").map((l) => l.trim()).filter(Boolean)[0] ?? "";
|
|
160
|
+
if (!line)
|
|
161
|
+
return null;
|
|
162
|
+
const [aRaw, dRaw] = line.split(/\s+/);
|
|
163
|
+
if (!aRaw || !dRaw)
|
|
164
|
+
return null;
|
|
165
|
+
if (aRaw === "-" || dRaw === "-") {
|
|
166
|
+
return { additions: 0, deletions: 0, isBinary: true };
|
|
167
|
+
}
|
|
168
|
+
const additions = Number.parseInt(aRaw, 10);
|
|
169
|
+
const deletions = Number.parseInt(dRaw, 10);
|
|
170
|
+
if (Number.isNaN(additions) || Number.isNaN(deletions)) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
return { additions, deletions, isBinary: false };
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
export class NotGitRepoError extends Error {
|
|
180
|
+
constructor(cwd) {
|
|
181
|
+
super(`Not a git repository: ${cwd}`);
|
|
182
|
+
this.code = "NOT_GIT_REPO";
|
|
183
|
+
this.name = "NotGitRepoError";
|
|
184
|
+
this.cwd = cwd;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
export class MergeConflictError extends Error {
|
|
188
|
+
constructor(options) {
|
|
189
|
+
super(`Merge conflict while merging ${options.currentBranch} into ${options.baseRef}`);
|
|
190
|
+
this.name = "MergeConflictError";
|
|
191
|
+
this.baseRef = options.baseRef;
|
|
192
|
+
this.currentBranch = options.currentBranch;
|
|
193
|
+
this.conflictFiles = options.conflictFiles;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
export class MergeFromBaseConflictError extends Error {
|
|
197
|
+
constructor(options) {
|
|
198
|
+
super(`Merge conflict while merging ${options.baseRef} into ${options.currentBranch}. Please merge manually.`);
|
|
199
|
+
this.name = "MergeFromBaseConflictError";
|
|
200
|
+
this.baseRef = options.baseRef;
|
|
201
|
+
this.currentBranch = options.currentBranch;
|
|
202
|
+
this.conflictFiles = options.conflictFiles;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function isGitError(error) {
|
|
206
|
+
if (!(error instanceof Error)) {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
return /not a git repository/i.test(error.message) || /git repository/i.test(error.message);
|
|
210
|
+
}
|
|
211
|
+
async function requireGitRepo(cwd) {
|
|
212
|
+
try {
|
|
213
|
+
await execAsync("git rev-parse --git-dir", { cwd, env: READ_ONLY_GIT_ENV });
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
throw new NotGitRepoError(cwd);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async function getCurrentBranch(cwd) {
|
|
220
|
+
const { stdout } = await execAsync("git rev-parse --abbrev-ref HEAD", {
|
|
221
|
+
cwd,
|
|
222
|
+
env: READ_ONLY_GIT_ENV,
|
|
223
|
+
});
|
|
224
|
+
const branch = stdout.trim();
|
|
225
|
+
return branch.length > 0 ? branch : null;
|
|
226
|
+
}
|
|
227
|
+
async function getWorktreeRoot(cwd) {
|
|
228
|
+
try {
|
|
229
|
+
const { stdout } = await execAsync("git rev-parse --path-format=absolute --show-toplevel", { cwd, env: READ_ONLY_GIT_ENV });
|
|
230
|
+
const root = stdout.trim();
|
|
231
|
+
return root.length > 0 ? root : null;
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
async function getMainRepoRoot(cwd) {
|
|
238
|
+
const { stdout: commonDirOut } = await execAsync("git rev-parse --path-format=absolute --git-common-dir", { cwd, env: READ_ONLY_GIT_ENV });
|
|
239
|
+
const commonDir = commonDirOut.trim();
|
|
240
|
+
const normalized = realpathSync(commonDir);
|
|
241
|
+
if (basename(normalized) === ".git") {
|
|
242
|
+
return dirname(normalized);
|
|
243
|
+
}
|
|
244
|
+
const { stdout: worktreeOut } = await execAsync("git worktree list --porcelain", {
|
|
245
|
+
cwd,
|
|
246
|
+
env: READ_ONLY_GIT_ENV,
|
|
247
|
+
});
|
|
248
|
+
const worktrees = parseWorktreeList(worktreeOut);
|
|
249
|
+
const nonBareNonPaseo = worktrees.filter((wt) => !wt.isBare && !wt.path.includes("/.paseo/worktrees/"));
|
|
250
|
+
const childrenOfBareRepo = nonBareNonPaseo.filter((wt) => wt.path.startsWith(normalized + "/"));
|
|
251
|
+
const mainChild = childrenOfBareRepo.find((wt) => basename(wt.path) === "main");
|
|
252
|
+
return mainChild?.path ?? childrenOfBareRepo[0]?.path ?? nonBareNonPaseo[0]?.path ?? normalized;
|
|
253
|
+
}
|
|
254
|
+
function parseWorktreeList(output) {
|
|
255
|
+
const entries = [];
|
|
256
|
+
let current = null;
|
|
257
|
+
for (const line of output.split("\n")) {
|
|
258
|
+
const trimmed = line.trim();
|
|
259
|
+
if (!trimmed) {
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (trimmed.startsWith("worktree ")) {
|
|
263
|
+
if (current) {
|
|
264
|
+
entries.push(current);
|
|
265
|
+
}
|
|
266
|
+
current = { path: trimmed.slice("worktree ".length).trim() };
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (current && trimmed.startsWith("branch ")) {
|
|
270
|
+
current.branchRef = trimmed.slice("branch ".length).trim();
|
|
271
|
+
}
|
|
272
|
+
if (current && trimmed === "bare") {
|
|
273
|
+
current.isBare = true;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (current) {
|
|
277
|
+
entries.push(current);
|
|
278
|
+
}
|
|
279
|
+
return entries;
|
|
280
|
+
}
|
|
281
|
+
async function getWorktreePathForBranch(cwd, branchName) {
|
|
282
|
+
try {
|
|
283
|
+
const { stdout } = await execAsync("git worktree list --porcelain", {
|
|
284
|
+
cwd,
|
|
285
|
+
env: READ_ONLY_GIT_ENV,
|
|
286
|
+
});
|
|
287
|
+
const entries = parseWorktreeList(stdout);
|
|
288
|
+
const ref = branchName.startsWith("refs/heads/")
|
|
289
|
+
? branchName
|
|
290
|
+
: `refs/heads/${branchName}`;
|
|
291
|
+
return entries.find((entry) => entry.branchRef === ref)?.path ?? null;
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
export async function renameCurrentBranch(cwd, newName) {
|
|
298
|
+
await requireGitRepo(cwd);
|
|
299
|
+
const previousBranch = await getCurrentBranch(cwd);
|
|
300
|
+
if (!previousBranch || previousBranch === "HEAD") {
|
|
301
|
+
throw new Error("Cannot rename branch in detached HEAD state");
|
|
302
|
+
}
|
|
303
|
+
await execAsync(`git branch -m "${newName}"`, {
|
|
304
|
+
cwd,
|
|
305
|
+
});
|
|
306
|
+
const currentBranch = await getCurrentBranch(cwd);
|
|
307
|
+
return { previousBranch, currentBranch };
|
|
308
|
+
}
|
|
309
|
+
async function getConfiguredBaseRefForCwd(cwd, context) {
|
|
310
|
+
// Fast-path reject: non-worktree paths do not need expensive ownership checks.
|
|
311
|
+
if (!/[\\/]worktrees[\\/]/.test(cwd)) {
|
|
312
|
+
return { baseRef: null, isPaseoOwnedWorktree: false };
|
|
313
|
+
}
|
|
314
|
+
const ownership = await isPaseoOwnedWorktreeCwd(cwd, { paseoHome: context?.paseoHome });
|
|
315
|
+
if (!ownership.allowed) {
|
|
316
|
+
return { baseRef: null, isPaseoOwnedWorktree: false };
|
|
317
|
+
}
|
|
318
|
+
const worktreeRoot = (await getWorktreeRoot(cwd)) ?? cwd;
|
|
319
|
+
return {
|
|
320
|
+
baseRef: requirePaseoWorktreeBaseRefName(worktreeRoot),
|
|
321
|
+
isPaseoOwnedWorktree: true,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
async function isWorkingTreeDirty(cwd) {
|
|
325
|
+
const { stdout } = await execAsync("git status --porcelain", {
|
|
326
|
+
cwd,
|
|
327
|
+
env: READ_ONLY_GIT_ENV,
|
|
328
|
+
});
|
|
329
|
+
return stdout.trim().length > 0;
|
|
330
|
+
}
|
|
331
|
+
async function getOriginRemoteUrl(cwd) {
|
|
332
|
+
try {
|
|
333
|
+
const { stdout } = await execAsync("git config --get remote.origin.url", {
|
|
334
|
+
cwd,
|
|
335
|
+
env: READ_ONLY_GIT_ENV,
|
|
336
|
+
});
|
|
337
|
+
const url = stdout.trim();
|
|
338
|
+
return url.length > 0 ? url : null;
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
async function hasOriginRemote(cwd) {
|
|
345
|
+
const url = await getOriginRemoteUrl(cwd);
|
|
346
|
+
return url !== null;
|
|
347
|
+
}
|
|
348
|
+
async function resolveBaseRef(repoRoot) {
|
|
349
|
+
try {
|
|
350
|
+
const { stdout } = await execAsync("git symbolic-ref --quiet refs/remotes/origin/HEAD", {
|
|
351
|
+
cwd: repoRoot,
|
|
352
|
+
env: READ_ONLY_GIT_ENV,
|
|
353
|
+
});
|
|
354
|
+
const ref = stdout.trim();
|
|
355
|
+
if (ref) {
|
|
356
|
+
// Prefer a local branch name (e.g. "main") over the remote-tracking ref (e.g. "origin/main")
|
|
357
|
+
// so that status/diff/merge all operate against the same base ref.
|
|
358
|
+
const remoteShort = ref.replace(/^refs\/remotes\//, "");
|
|
359
|
+
const localName = remoteShort.startsWith("origin/")
|
|
360
|
+
? remoteShort.slice("origin/".length)
|
|
361
|
+
: remoteShort;
|
|
362
|
+
try {
|
|
363
|
+
await execAsync(`git show-ref --verify --quiet refs/heads/${localName}`, {
|
|
364
|
+
cwd: repoRoot,
|
|
365
|
+
env: READ_ONLY_GIT_ENV,
|
|
366
|
+
});
|
|
367
|
+
return localName;
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
return remoteShort;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
catch {
|
|
375
|
+
// ignore
|
|
376
|
+
}
|
|
377
|
+
const { stdout } = await execAsync("git branch --format='%(refname:short)'", {
|
|
378
|
+
cwd: repoRoot,
|
|
379
|
+
env: READ_ONLY_GIT_ENV,
|
|
380
|
+
});
|
|
381
|
+
const branches = stdout
|
|
382
|
+
.split("\n")
|
|
383
|
+
.map((line) => line.trim())
|
|
384
|
+
.filter((line) => line.length > 0);
|
|
385
|
+
if (branches.includes("main")) {
|
|
386
|
+
return "main";
|
|
387
|
+
}
|
|
388
|
+
if (branches.includes("master")) {
|
|
389
|
+
return "master";
|
|
390
|
+
}
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
function normalizeLocalBranchRefName(input) {
|
|
394
|
+
return input.startsWith("origin/") ? input.slice("origin/".length) : input;
|
|
395
|
+
}
|
|
396
|
+
async function doesGitRefExist(cwd, fullRef) {
|
|
397
|
+
try {
|
|
398
|
+
await execAsync(`git show-ref --verify --quiet ${fullRef}`, {
|
|
399
|
+
cwd,
|
|
400
|
+
env: READ_ONLY_GIT_ENV,
|
|
401
|
+
});
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
catch {
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
async function resolveBestBaseRefForMerge(cwd, normalizedBaseRef) {
|
|
409
|
+
const [hasLocal, hasOrigin] = await Promise.all([
|
|
410
|
+
doesGitRefExist(cwd, `refs/heads/${normalizedBaseRef}`),
|
|
411
|
+
doesGitRefExist(cwd, `refs/remotes/origin/${normalizedBaseRef}`),
|
|
412
|
+
]);
|
|
413
|
+
if (hasLocal && !hasOrigin) {
|
|
414
|
+
return normalizedBaseRef;
|
|
415
|
+
}
|
|
416
|
+
if (!hasLocal && hasOrigin) {
|
|
417
|
+
return `origin/${normalizedBaseRef}`;
|
|
418
|
+
}
|
|
419
|
+
if (!hasLocal && !hasOrigin) {
|
|
420
|
+
throw new Error(`Base branch not found locally or on origin: ${normalizedBaseRef}`);
|
|
421
|
+
}
|
|
422
|
+
// Both exist: choose the ref with more unique commits compared to the other.
|
|
423
|
+
try {
|
|
424
|
+
const { stdout } = await execAsync(`git rev-list --left-right --count ${normalizedBaseRef}...origin/${normalizedBaseRef}`, { cwd, env: READ_ONLY_GIT_ENV });
|
|
425
|
+
const [localOnlyRaw, originOnlyRaw] = stdout.trim().split(/\s+/);
|
|
426
|
+
const localOnly = Number.parseInt(localOnlyRaw ?? "0", 10);
|
|
427
|
+
const originOnly = Number.parseInt(originOnlyRaw ?? "0", 10);
|
|
428
|
+
if (!Number.isNaN(localOnly) && !Number.isNaN(originOnly) && originOnly > localOnly) {
|
|
429
|
+
return `origin/${normalizedBaseRef}`;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
catch {
|
|
433
|
+
// ignore and fall back to local
|
|
434
|
+
}
|
|
435
|
+
return normalizedBaseRef;
|
|
436
|
+
}
|
|
437
|
+
async function getAheadBehind(cwd, baseRef, currentBranch) {
|
|
438
|
+
const normalizedBaseRef = normalizeLocalBranchRefName(baseRef);
|
|
439
|
+
if (!normalizedBaseRef || !currentBranch || normalizedBaseRef === currentBranch) {
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
const { stdout } = await execAsync(`git rev-list --left-right --count ${normalizedBaseRef}...${currentBranch}`, { cwd, env: READ_ONLY_GIT_ENV });
|
|
443
|
+
const [behindRaw, aheadRaw] = stdout.trim().split(/\s+/);
|
|
444
|
+
const behind = Number.parseInt(behindRaw ?? "0", 10);
|
|
445
|
+
const ahead = Number.parseInt(aheadRaw ?? "0", 10);
|
|
446
|
+
if (Number.isNaN(behind) || Number.isNaN(ahead)) {
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
return { ahead, behind };
|
|
450
|
+
}
|
|
451
|
+
async function getAheadOfOrigin(cwd, currentBranch) {
|
|
452
|
+
if (!currentBranch) {
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
try {
|
|
456
|
+
const { stdout } = await execAsync(`git rev-list --count origin/${currentBranch}..${currentBranch}`, { cwd, env: READ_ONLY_GIT_ENV });
|
|
457
|
+
const count = Number.parseInt(stdout.trim(), 10);
|
|
458
|
+
return Number.isNaN(count) ? null : count;
|
|
459
|
+
}
|
|
460
|
+
catch {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
async function inspectCheckoutContext(cwd, context) {
|
|
465
|
+
try {
|
|
466
|
+
const root = await getWorktreeRoot(cwd);
|
|
467
|
+
if (!root) {
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
const [currentBranch, remoteUrl, configured] = await Promise.all([
|
|
471
|
+
getCurrentBranch(cwd),
|
|
472
|
+
getOriginRemoteUrl(cwd),
|
|
473
|
+
getConfiguredBaseRefForCwd(cwd, context),
|
|
474
|
+
]);
|
|
475
|
+
return {
|
|
476
|
+
worktreeRoot: root,
|
|
477
|
+
currentBranch,
|
|
478
|
+
remoteUrl,
|
|
479
|
+
configured,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
catch (error) {
|
|
483
|
+
if (isGitError(error)) {
|
|
484
|
+
return null;
|
|
485
|
+
}
|
|
486
|
+
throw error;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
const PER_FILE_DIFF_MAX_BYTES = 1024 * 1024; // 1MB
|
|
490
|
+
const TOTAL_DIFF_MAX_BYTES = 2 * 1024 * 1024; // 2MB
|
|
491
|
+
const UNTRACKED_BINARY_SNIFF_BYTES = 16 * 1024;
|
|
492
|
+
async function isLikelyBinaryFile(absolutePath) {
|
|
493
|
+
const handle = await openFile(absolutePath, "r");
|
|
494
|
+
try {
|
|
495
|
+
const buffer = Buffer.allocUnsafe(UNTRACKED_BINARY_SNIFF_BYTES);
|
|
496
|
+
const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
|
|
497
|
+
if (bytesRead === 0) {
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
let suspicious = 0;
|
|
501
|
+
for (let i = 0; i < bytesRead; i += 1) {
|
|
502
|
+
const byte = buffer[i];
|
|
503
|
+
if (byte === 0) {
|
|
504
|
+
return true;
|
|
505
|
+
}
|
|
506
|
+
// Treat control bytes as suspicious while allowing common whitespace.
|
|
507
|
+
if (byte < 7 || (byte > 14 && byte < 32) || byte === 127) {
|
|
508
|
+
suspicious += 1;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return suspicious / bytesRead > 0.3;
|
|
512
|
+
}
|
|
513
|
+
finally {
|
|
514
|
+
await handle.close();
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
async function inspectUntrackedFile(cwd, relativePath) {
|
|
518
|
+
const absolutePath = resolve(cwd, relativePath);
|
|
519
|
+
const metadata = await statFile(absolutePath);
|
|
520
|
+
if (!metadata.isFile()) {
|
|
521
|
+
return { stat: null, truncated: false };
|
|
522
|
+
}
|
|
523
|
+
if (await isLikelyBinaryFile(absolutePath)) {
|
|
524
|
+
return {
|
|
525
|
+
stat: { additions: 0, deletions: 0, isBinary: true },
|
|
526
|
+
truncated: false,
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
if (metadata.size > PER_FILE_DIFF_MAX_BYTES) {
|
|
530
|
+
return {
|
|
531
|
+
stat: { additions: 0, deletions: 0, isBinary: false },
|
|
532
|
+
truncated: true,
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
return {
|
|
536
|
+
stat: { additions: 0, deletions: 0, isBinary: false },
|
|
537
|
+
truncated: false,
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function buildPlaceholderParsedDiffFile(change, options) {
|
|
541
|
+
return {
|
|
542
|
+
path: change.path,
|
|
543
|
+
isNew: change.isNew,
|
|
544
|
+
isDeleted: change.isDeleted,
|
|
545
|
+
additions: options.stat?.additions ?? 0,
|
|
546
|
+
deletions: options.stat?.deletions ?? 0,
|
|
547
|
+
hunks: [],
|
|
548
|
+
status: options.status,
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
async function getPerFileDiffText(cwd, ref, change) {
|
|
552
|
+
if (change.isUntracked) {
|
|
553
|
+
try {
|
|
554
|
+
const inspected = await inspectUntrackedFile(cwd, change.path);
|
|
555
|
+
if (inspected.stat?.isBinary || inspected.truncated) {
|
|
556
|
+
return { text: "", truncated: inspected.truncated, stat: inspected.stat };
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
catch {
|
|
560
|
+
// Fall through to git diff path if metadata probing fails.
|
|
561
|
+
}
|
|
562
|
+
const result = await spawnLimitedText({
|
|
563
|
+
cmd: "git",
|
|
564
|
+
args: ["diff", "--no-index", "/dev/null", "--", change.path],
|
|
565
|
+
cwd,
|
|
566
|
+
env: READ_ONLY_GIT_ENV,
|
|
567
|
+
maxBytes: PER_FILE_DIFF_MAX_BYTES,
|
|
568
|
+
acceptExitCodes: [0, 1],
|
|
569
|
+
});
|
|
570
|
+
return {
|
|
571
|
+
text: result.text,
|
|
572
|
+
truncated: result.truncated,
|
|
573
|
+
stat: { additions: 0, deletions: 0, isBinary: false },
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
const stat = await tryGetNumstat(cwd, ["diff", "--numstat", ref, "--", change.path]);
|
|
577
|
+
if (stat?.isBinary) {
|
|
578
|
+
return { text: "", truncated: false, stat };
|
|
579
|
+
}
|
|
580
|
+
const result = await spawnLimitedText({
|
|
581
|
+
cmd: "git",
|
|
582
|
+
args: ["diff", ref, "--", change.path],
|
|
583
|
+
cwd,
|
|
584
|
+
env: READ_ONLY_GIT_ENV,
|
|
585
|
+
maxBytes: PER_FILE_DIFF_MAX_BYTES,
|
|
586
|
+
});
|
|
587
|
+
return { text: result.text, truncated: result.truncated, stat };
|
|
588
|
+
}
|
|
589
|
+
export async function getCheckoutStatus(cwd, context) {
|
|
590
|
+
const inspected = await inspectCheckoutContext(cwd, context);
|
|
591
|
+
if (!inspected) {
|
|
592
|
+
return { isGit: false };
|
|
593
|
+
}
|
|
594
|
+
const worktreeRoot = inspected.worktreeRoot;
|
|
595
|
+
const currentBranch = inspected.currentBranch;
|
|
596
|
+
const remoteUrl = inspected.remoteUrl;
|
|
597
|
+
const configured = inspected.configured;
|
|
598
|
+
const isDirty = await isWorkingTreeDirty(cwd);
|
|
599
|
+
const hasRemote = remoteUrl !== null;
|
|
600
|
+
const baseRef = configured.baseRef ?? (await resolveBaseRef(cwd));
|
|
601
|
+
const aheadBehind = baseRef && currentBranch ? await getAheadBehind(cwd, baseRef, currentBranch) : null;
|
|
602
|
+
const aheadOfOrigin = hasRemote && currentBranch ? await getAheadOfOrigin(cwd, currentBranch) : null;
|
|
603
|
+
if (configured.isPaseoOwnedWorktree) {
|
|
604
|
+
const mainRepoRoot = await getMainRepoRoot(cwd);
|
|
605
|
+
return {
|
|
606
|
+
isGit: true,
|
|
607
|
+
repoRoot: worktreeRoot,
|
|
608
|
+
mainRepoRoot,
|
|
609
|
+
currentBranch,
|
|
610
|
+
isDirty,
|
|
611
|
+
baseRef: configured.baseRef,
|
|
612
|
+
aheadBehind,
|
|
613
|
+
aheadOfOrigin,
|
|
614
|
+
hasRemote,
|
|
615
|
+
remoteUrl,
|
|
616
|
+
isPaseoOwnedWorktree: true,
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
return {
|
|
620
|
+
isGit: true,
|
|
621
|
+
repoRoot: worktreeRoot,
|
|
622
|
+
currentBranch,
|
|
623
|
+
isDirty,
|
|
624
|
+
baseRef,
|
|
625
|
+
aheadBehind,
|
|
626
|
+
aheadOfOrigin,
|
|
627
|
+
hasRemote,
|
|
628
|
+
remoteUrl,
|
|
629
|
+
isPaseoOwnedWorktree: false,
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
export async function getCheckoutStatusLite(cwd, context) {
|
|
633
|
+
const inspected = await inspectCheckoutContext(cwd, context);
|
|
634
|
+
if (!inspected) {
|
|
635
|
+
return {
|
|
636
|
+
isGit: false,
|
|
637
|
+
currentBranch: null,
|
|
638
|
+
remoteUrl: null,
|
|
639
|
+
isPaseoOwnedWorktree: false,
|
|
640
|
+
mainRepoRoot: null,
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
if (inspected.configured.isPaseoOwnedWorktree) {
|
|
644
|
+
return {
|
|
645
|
+
isGit: true,
|
|
646
|
+
currentBranch: inspected.currentBranch,
|
|
647
|
+
remoteUrl: inspected.remoteUrl,
|
|
648
|
+
isPaseoOwnedWorktree: true,
|
|
649
|
+
mainRepoRoot: await getMainRepoRoot(cwd),
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
return {
|
|
653
|
+
isGit: true,
|
|
654
|
+
currentBranch: inspected.currentBranch,
|
|
655
|
+
remoteUrl: inspected.remoteUrl,
|
|
656
|
+
isPaseoOwnedWorktree: false,
|
|
657
|
+
mainRepoRoot: null,
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
export async function getCheckoutDiff(cwd, compare, context) {
|
|
661
|
+
await requireGitRepo(cwd);
|
|
662
|
+
let refForDiff;
|
|
663
|
+
if (compare.mode === "uncommitted") {
|
|
664
|
+
refForDiff = "HEAD";
|
|
665
|
+
}
|
|
666
|
+
else {
|
|
667
|
+
const configured = await getConfiguredBaseRefForCwd(cwd, context);
|
|
668
|
+
const baseRef = configured.baseRef ?? compare.baseRef ?? (await resolveBaseRef(cwd));
|
|
669
|
+
if (!baseRef) {
|
|
670
|
+
return { diff: "" };
|
|
671
|
+
}
|
|
672
|
+
if (configured.isPaseoOwnedWorktree && compare.baseRef && compare.baseRef !== baseRef) {
|
|
673
|
+
throw new Error(`Base ref mismatch: expected ${baseRef}, got ${compare.baseRef}`);
|
|
674
|
+
}
|
|
675
|
+
const normalizedBaseRef = normalizeLocalBranchRefName(baseRef);
|
|
676
|
+
const bestBaseRef = await resolveBestBaseRefForMerge(cwd, normalizedBaseRef);
|
|
677
|
+
refForDiff = (await tryResolveMergeBase(cwd, bestBaseRef)) ?? bestBaseRef;
|
|
678
|
+
}
|
|
679
|
+
const changes = await listCheckoutFileChanges(cwd, refForDiff);
|
|
680
|
+
changes.sort((a, b) => {
|
|
681
|
+
if (a.path === b.path)
|
|
682
|
+
return 0;
|
|
683
|
+
return a.path < b.path ? -1 : 1;
|
|
684
|
+
});
|
|
685
|
+
const structured = [];
|
|
686
|
+
let diffText = "";
|
|
687
|
+
let diffBytes = 0;
|
|
688
|
+
const appendDiff = (text) => {
|
|
689
|
+
if (!text)
|
|
690
|
+
return;
|
|
691
|
+
if (diffBytes >= TOTAL_DIFF_MAX_BYTES)
|
|
692
|
+
return;
|
|
693
|
+
const buf = Buffer.from(text, "utf8");
|
|
694
|
+
if (diffBytes + buf.length <= TOTAL_DIFF_MAX_BYTES) {
|
|
695
|
+
diffText += text;
|
|
696
|
+
diffBytes += buf.length;
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
const remaining = TOTAL_DIFF_MAX_BYTES - diffBytes;
|
|
700
|
+
if (remaining > 0) {
|
|
701
|
+
diffText += buf.subarray(0, remaining).toString("utf8");
|
|
702
|
+
diffBytes = TOTAL_DIFF_MAX_BYTES;
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
for (const change of changes) {
|
|
706
|
+
const { text, truncated, stat } = await getPerFileDiffText(cwd, refForDiff, change);
|
|
707
|
+
if (!compare.includeStructured) {
|
|
708
|
+
if (stat?.isBinary) {
|
|
709
|
+
appendDiff(`# ${change.path}: binary diff omitted\n`);
|
|
710
|
+
}
|
|
711
|
+
else if (truncated) {
|
|
712
|
+
appendDiff(`# ${change.path}: diff too large omitted\n`);
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
appendDiff(text);
|
|
716
|
+
}
|
|
717
|
+
if (diffBytes >= TOTAL_DIFF_MAX_BYTES) {
|
|
718
|
+
break;
|
|
719
|
+
}
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
if (stat?.isBinary) {
|
|
723
|
+
structured.push(buildPlaceholderParsedDiffFile(change, { status: "binary", stat }));
|
|
724
|
+
appendDiff(`# ${change.path}: binary diff omitted\n`);
|
|
725
|
+
continue;
|
|
726
|
+
}
|
|
727
|
+
if (truncated) {
|
|
728
|
+
structured.push(buildPlaceholderParsedDiffFile(change, { status: "too_large", stat }));
|
|
729
|
+
appendDiff(`# ${change.path}: diff too large omitted\n`);
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
732
|
+
appendDiff(text);
|
|
733
|
+
const parsed = await parseAndHighlightDiff(text, cwd);
|
|
734
|
+
const parsedFile = parsed[0] ??
|
|
735
|
+
{
|
|
736
|
+
path: change.path,
|
|
737
|
+
isNew: change.isNew,
|
|
738
|
+
isDeleted: change.isDeleted,
|
|
739
|
+
additions: stat?.additions ?? 0,
|
|
740
|
+
deletions: stat?.deletions ?? 0,
|
|
741
|
+
hunks: [],
|
|
742
|
+
};
|
|
743
|
+
structured.push({
|
|
744
|
+
...parsedFile,
|
|
745
|
+
path: change.path,
|
|
746
|
+
isNew: change.isNew,
|
|
747
|
+
isDeleted: change.isDeleted,
|
|
748
|
+
status: "ok",
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
if (compare.includeStructured) {
|
|
752
|
+
return { diff: diffText, structured };
|
|
753
|
+
}
|
|
754
|
+
return { diff: diffText };
|
|
755
|
+
}
|
|
756
|
+
export async function commitChanges(cwd, options) {
|
|
757
|
+
await requireGitRepo(cwd);
|
|
758
|
+
if (options.addAll ?? true) {
|
|
759
|
+
await execFileAsync("git", ["add", "-A"], { cwd });
|
|
760
|
+
}
|
|
761
|
+
await execFileAsync("git", ["-c", "commit.gpgsign=false", "commit", "-m", options.message], {
|
|
762
|
+
cwd,
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
export async function commitAll(cwd, message) {
|
|
766
|
+
await commitChanges(cwd, { message, addAll: true });
|
|
767
|
+
}
|
|
768
|
+
export async function mergeToBase(cwd, options = {}, context) {
|
|
769
|
+
await requireGitRepo(cwd);
|
|
770
|
+
const currentBranch = await getCurrentBranch(cwd);
|
|
771
|
+
const configured = await getConfiguredBaseRefForCwd(cwd, context);
|
|
772
|
+
const baseRef = configured.baseRef ?? options.baseRef ?? (await resolveBaseRef(cwd));
|
|
773
|
+
if (!baseRef) {
|
|
774
|
+
throw new Error("Unable to determine base branch for merge");
|
|
775
|
+
}
|
|
776
|
+
if (configured.isPaseoOwnedWorktree && options.baseRef && options.baseRef !== baseRef) {
|
|
777
|
+
throw new Error(`Base ref mismatch: expected ${baseRef}, got ${options.baseRef}`);
|
|
778
|
+
}
|
|
779
|
+
if (!currentBranch) {
|
|
780
|
+
throw new Error("Unable to determine current branch for merge");
|
|
781
|
+
}
|
|
782
|
+
let normalizedBaseRef = baseRef;
|
|
783
|
+
normalizedBaseRef = normalizeLocalBranchRefName(normalizedBaseRef);
|
|
784
|
+
if (normalizedBaseRef === currentBranch) {
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
const currentWorktreeRoot = (await getWorktreeRoot(cwd)) ?? cwd;
|
|
788
|
+
const baseWorktree = await getWorktreePathForBranch(cwd, normalizedBaseRef);
|
|
789
|
+
const operationCwd = baseWorktree ?? currentWorktreeRoot;
|
|
790
|
+
const isSameCheckout = resolve(operationCwd) === resolve(currentWorktreeRoot);
|
|
791
|
+
const originalBranch = await getCurrentBranch(operationCwd);
|
|
792
|
+
const mode = options.mode ?? "merge";
|
|
793
|
+
try {
|
|
794
|
+
await execAsync(`git checkout ${normalizedBaseRef}`, { cwd: operationCwd });
|
|
795
|
+
if (mode === "squash") {
|
|
796
|
+
await execAsync(`git merge --squash ${currentBranch}`, { cwd: operationCwd });
|
|
797
|
+
const message = options.commitMessage ?? `Squash merge ${currentBranch} into ${normalizedBaseRef}`;
|
|
798
|
+
await execFileAsync("git", ["-c", "commit.gpgsign=false", "commit", "-m", message], { cwd: operationCwd });
|
|
799
|
+
}
|
|
800
|
+
else {
|
|
801
|
+
await execAsync(`git merge ${currentBranch}`, { cwd: operationCwd });
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
catch (error) {
|
|
805
|
+
const errorDetails = error instanceof Error
|
|
806
|
+
? `${error.message}\n${error.stderr ?? ""}\n${error.stdout ?? ""}`
|
|
807
|
+
: String(error);
|
|
808
|
+
try {
|
|
809
|
+
const [unmergedOutput, lsFilesOutput, statusOutput] = await Promise.all([
|
|
810
|
+
execAsync("git diff --name-only --diff-filter=U", { cwd: operationCwd }),
|
|
811
|
+
execAsync("git ls-files -u", { cwd: operationCwd }),
|
|
812
|
+
execAsync("git status --porcelain", { cwd: operationCwd }),
|
|
813
|
+
]);
|
|
814
|
+
const statusConflicts = statusOutput.stdout
|
|
815
|
+
.split("\n")
|
|
816
|
+
.map((line) => line.trim())
|
|
817
|
+
.filter(Boolean)
|
|
818
|
+
.filter((line) => /^(UU|AA|DD|AU|UA|UD|DU)\s/.test(line))
|
|
819
|
+
.map((line) => line.slice(3).trim());
|
|
820
|
+
const conflicts = [
|
|
821
|
+
...unmergedOutput.stdout
|
|
822
|
+
.split("\n")
|
|
823
|
+
.map((line) => line.trim())
|
|
824
|
+
.filter(Boolean),
|
|
825
|
+
...lsFilesOutput.stdout
|
|
826
|
+
.split("\n")
|
|
827
|
+
.map((line) => line.trim())
|
|
828
|
+
.filter(Boolean)
|
|
829
|
+
.map((line) => line.split("\t").pop()),
|
|
830
|
+
...statusConflicts,
|
|
831
|
+
].filter(Boolean);
|
|
832
|
+
const conflictDetected = conflicts.length > 0 || /CONFLICT|Automatic merge failed/i.test(errorDetails);
|
|
833
|
+
if (conflictDetected) {
|
|
834
|
+
try {
|
|
835
|
+
await execAsync("git merge --abort", { cwd: operationCwd });
|
|
836
|
+
}
|
|
837
|
+
catch {
|
|
838
|
+
// ignore
|
|
839
|
+
}
|
|
840
|
+
throw new MergeConflictError({
|
|
841
|
+
baseRef: normalizedBaseRef,
|
|
842
|
+
currentBranch,
|
|
843
|
+
conflictFiles: conflicts.length > 0 ? conflicts : [],
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
catch (innerError) {
|
|
848
|
+
if (innerError instanceof MergeConflictError) {
|
|
849
|
+
throw innerError;
|
|
850
|
+
}
|
|
851
|
+
// ignore detection failures
|
|
852
|
+
}
|
|
853
|
+
throw error;
|
|
854
|
+
}
|
|
855
|
+
finally {
|
|
856
|
+
if (isSameCheckout && originalBranch && originalBranch !== normalizedBaseRef) {
|
|
857
|
+
try {
|
|
858
|
+
await execAsync(`git checkout ${originalBranch}`, { cwd: operationCwd });
|
|
859
|
+
}
|
|
860
|
+
catch {
|
|
861
|
+
// ignore
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
export async function mergeFromBase(cwd, options = {}, context) {
|
|
867
|
+
await requireGitRepo(cwd);
|
|
868
|
+
const currentBranch = await getCurrentBranch(cwd);
|
|
869
|
+
if (!currentBranch || currentBranch === "HEAD") {
|
|
870
|
+
throw new Error("Unable to determine current branch for merge");
|
|
871
|
+
}
|
|
872
|
+
const configured = await getConfiguredBaseRefForCwd(cwd, context);
|
|
873
|
+
const baseRef = configured.baseRef ?? options.baseRef ?? (await resolveBaseRef(cwd));
|
|
874
|
+
if (!baseRef) {
|
|
875
|
+
throw new Error("Unable to determine base branch for merge");
|
|
876
|
+
}
|
|
877
|
+
if (configured.isPaseoOwnedWorktree && options.baseRef && options.baseRef !== baseRef) {
|
|
878
|
+
throw new Error(`Base ref mismatch: expected ${baseRef}, got ${options.baseRef}`);
|
|
879
|
+
}
|
|
880
|
+
const requireCleanTarget = options.requireCleanTarget ?? true;
|
|
881
|
+
if (requireCleanTarget) {
|
|
882
|
+
const { stdout } = await execAsync("git status --porcelain", {
|
|
883
|
+
cwd,
|
|
884
|
+
env: READ_ONLY_GIT_ENV,
|
|
885
|
+
});
|
|
886
|
+
if (stdout.trim().length > 0) {
|
|
887
|
+
throw new Error("Working directory has uncommitted changes.");
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
const normalizedBaseRef = normalizeLocalBranchRefName(baseRef);
|
|
891
|
+
const bestBaseRef = await resolveBestBaseRefForMerge(cwd, normalizedBaseRef);
|
|
892
|
+
if (bestBaseRef === currentBranch) {
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
try {
|
|
896
|
+
await execAsync(`git merge ${bestBaseRef}`, { cwd });
|
|
897
|
+
}
|
|
898
|
+
catch (error) {
|
|
899
|
+
const errorDetails = error instanceof Error
|
|
900
|
+
? `${error.message}\n${error.stderr ?? ""}\n${error.stdout ?? ""}`
|
|
901
|
+
: String(error);
|
|
902
|
+
try {
|
|
903
|
+
const [unmergedOutput, lsFilesOutput, statusOutput] = await Promise.all([
|
|
904
|
+
execAsync("git diff --name-only --diff-filter=U", { cwd }),
|
|
905
|
+
execAsync("git ls-files -u", { cwd }),
|
|
906
|
+
execAsync("git status --porcelain", { cwd }),
|
|
907
|
+
]);
|
|
908
|
+
const statusConflicts = statusOutput.stdout
|
|
909
|
+
.split("\n")
|
|
910
|
+
.map((line) => line.trim())
|
|
911
|
+
.filter(Boolean)
|
|
912
|
+
.filter((line) => /^(UU|AA|DD|AU|UA|UD|DU)\s/.test(line))
|
|
913
|
+
.map((line) => line.slice(3).trim());
|
|
914
|
+
const conflicts = [
|
|
915
|
+
...unmergedOutput.stdout
|
|
916
|
+
.split("\n")
|
|
917
|
+
.map((line) => line.trim())
|
|
918
|
+
.filter(Boolean),
|
|
919
|
+
...lsFilesOutput.stdout
|
|
920
|
+
.split("\n")
|
|
921
|
+
.map((line) => line.trim())
|
|
922
|
+
.filter(Boolean)
|
|
923
|
+
.map((line) => line.split("\t").pop()),
|
|
924
|
+
...statusConflicts,
|
|
925
|
+
].filter(Boolean);
|
|
926
|
+
const conflictDetected = conflicts.length > 0 || /CONFLICT|Automatic merge failed/i.test(errorDetails);
|
|
927
|
+
if (conflictDetected) {
|
|
928
|
+
try {
|
|
929
|
+
await execAsync("git merge --abort", { cwd });
|
|
930
|
+
}
|
|
931
|
+
catch {
|
|
932
|
+
// ignore
|
|
933
|
+
}
|
|
934
|
+
throw new MergeFromBaseConflictError({
|
|
935
|
+
baseRef: bestBaseRef,
|
|
936
|
+
currentBranch,
|
|
937
|
+
conflictFiles: conflicts.length > 0 ? conflicts : [],
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
catch (innerError) {
|
|
942
|
+
if (innerError instanceof MergeFromBaseConflictError) {
|
|
943
|
+
throw innerError;
|
|
944
|
+
}
|
|
945
|
+
// ignore detection failures
|
|
946
|
+
}
|
|
947
|
+
throw error;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
export async function pushCurrentBranch(cwd) {
|
|
951
|
+
await requireGitRepo(cwd);
|
|
952
|
+
const currentBranch = await getCurrentBranch(cwd);
|
|
953
|
+
if (!currentBranch || currentBranch === "HEAD") {
|
|
954
|
+
throw new Error("Unable to determine current branch for push");
|
|
955
|
+
}
|
|
956
|
+
const hasRemote = await hasOriginRemote(cwd);
|
|
957
|
+
if (!hasRemote) {
|
|
958
|
+
throw new Error("Remote 'origin' is not configured.");
|
|
959
|
+
}
|
|
960
|
+
await execAsync(`git push -u origin ${currentBranch}`, { cwd });
|
|
961
|
+
}
|
|
962
|
+
async function ensureGhAvailable(cwd) {
|
|
963
|
+
try {
|
|
964
|
+
await execAsync("gh --version", { cwd });
|
|
965
|
+
}
|
|
966
|
+
catch {
|
|
967
|
+
throw new Error("GitHub CLI (gh) is not available or not authenticated");
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
async function resolveGitHubRepo(cwd) {
|
|
971
|
+
try {
|
|
972
|
+
const { stdout } = await execAsync("git config --get remote.origin.url", {
|
|
973
|
+
cwd,
|
|
974
|
+
env: READ_ONLY_GIT_ENV,
|
|
975
|
+
});
|
|
976
|
+
const url = stdout.trim();
|
|
977
|
+
if (!url) {
|
|
978
|
+
return null;
|
|
979
|
+
}
|
|
980
|
+
let cleaned = url;
|
|
981
|
+
if (cleaned.startsWith("git@github.com:")) {
|
|
982
|
+
cleaned = cleaned.slice("git@github.com:".length);
|
|
983
|
+
}
|
|
984
|
+
else if (cleaned.startsWith("https://github.com/")) {
|
|
985
|
+
cleaned = cleaned.slice("https://github.com/".length);
|
|
986
|
+
}
|
|
987
|
+
else if (cleaned.startsWith("http://github.com/")) {
|
|
988
|
+
cleaned = cleaned.slice("http://github.com/".length);
|
|
989
|
+
}
|
|
990
|
+
else {
|
|
991
|
+
const marker = "github.com/";
|
|
992
|
+
const index = cleaned.indexOf(marker);
|
|
993
|
+
if (index !== -1) {
|
|
994
|
+
cleaned = cleaned.slice(index + marker.length);
|
|
995
|
+
}
|
|
996
|
+
else {
|
|
997
|
+
return null;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
if (cleaned.endsWith(".git")) {
|
|
1001
|
+
cleaned = cleaned.slice(0, -".git".length);
|
|
1002
|
+
}
|
|
1003
|
+
if (!cleaned.includes("/")) {
|
|
1004
|
+
return null;
|
|
1005
|
+
}
|
|
1006
|
+
return cleaned;
|
|
1007
|
+
}
|
|
1008
|
+
catch {
|
|
1009
|
+
// ignore
|
|
1010
|
+
}
|
|
1011
|
+
return null;
|
|
1012
|
+
}
|
|
1013
|
+
export async function createPullRequest(cwd, options) {
|
|
1014
|
+
await requireGitRepo(cwd);
|
|
1015
|
+
await ensureGhAvailable(cwd);
|
|
1016
|
+
const repo = await resolveGitHubRepo(cwd);
|
|
1017
|
+
if (!repo) {
|
|
1018
|
+
throw new Error("Unable to determine GitHub repo from git remote");
|
|
1019
|
+
}
|
|
1020
|
+
const head = options.head ?? (await getCurrentBranch(cwd));
|
|
1021
|
+
const configured = await getConfiguredBaseRefForCwd(cwd);
|
|
1022
|
+
const base = configured.baseRef ?? options.base ?? (await resolveBaseRef(cwd));
|
|
1023
|
+
if (!head) {
|
|
1024
|
+
throw new Error("Unable to determine head branch for PR");
|
|
1025
|
+
}
|
|
1026
|
+
if (!base) {
|
|
1027
|
+
throw new Error("Unable to determine base branch for PR");
|
|
1028
|
+
}
|
|
1029
|
+
const normalizedBase = normalizeLocalBranchRefName(base);
|
|
1030
|
+
if (configured.isPaseoOwnedWorktree && options.base && options.base !== base) {
|
|
1031
|
+
throw new Error(`Base ref mismatch: expected ${base}, got ${options.base}`);
|
|
1032
|
+
}
|
|
1033
|
+
await execAsync(`git push -u origin ${head}`, { cwd });
|
|
1034
|
+
const args = ["api", "-X", "POST", `repos/${repo}/pulls`, "-f", `title=${options.title}`];
|
|
1035
|
+
args.push("-f", `head=${head}`);
|
|
1036
|
+
args.push("-f", `base=${normalizedBase}`);
|
|
1037
|
+
if (options.body) {
|
|
1038
|
+
args.push("-f", `body=${options.body}`);
|
|
1039
|
+
}
|
|
1040
|
+
const { stdout } = await execFileAsync("gh", args, { cwd });
|
|
1041
|
+
const parsed = JSON.parse(stdout.trim());
|
|
1042
|
+
if (!parsed?.url || !parsed?.number) {
|
|
1043
|
+
throw new Error("GitHub CLI did not return PR url/number");
|
|
1044
|
+
}
|
|
1045
|
+
return { url: parsed.url, number: parsed.number };
|
|
1046
|
+
}
|
|
1047
|
+
export async function getPullRequestStatus(cwd) {
|
|
1048
|
+
await requireGitRepo(cwd);
|
|
1049
|
+
await ensureGhAvailable(cwd);
|
|
1050
|
+
const repo = await resolveGitHubRepo(cwd);
|
|
1051
|
+
const head = await getCurrentBranch(cwd);
|
|
1052
|
+
if (!repo || !head) {
|
|
1053
|
+
return null;
|
|
1054
|
+
}
|
|
1055
|
+
const owner = repo.split("/")[0];
|
|
1056
|
+
const { stdout } = await execFileAsync("gh", [
|
|
1057
|
+
"api",
|
|
1058
|
+
`repos/${repo}/pulls`,
|
|
1059
|
+
"-X",
|
|
1060
|
+
"GET",
|
|
1061
|
+
"-F",
|
|
1062
|
+
`head=${owner}:${head}`,
|
|
1063
|
+
"-F",
|
|
1064
|
+
"state=open",
|
|
1065
|
+
], { cwd });
|
|
1066
|
+
const parsed = JSON.parse(stdout.trim());
|
|
1067
|
+
const current = Array.isArray(parsed) && parsed.length > 0 ? parsed[0] : null;
|
|
1068
|
+
if (!current) {
|
|
1069
|
+
return null;
|
|
1070
|
+
}
|
|
1071
|
+
return {
|
|
1072
|
+
url: current.html_url ?? current.url,
|
|
1073
|
+
title: current.title,
|
|
1074
|
+
state: current.state,
|
|
1075
|
+
baseRefName: current.base?.ref ?? "",
|
|
1076
|
+
headRefName: current.head?.ref ?? head,
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
//# sourceMappingURL=checkout-git.js.map
|