@minionry/minion 0.7.36
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/LICENSE +14 -0
- package/PRIVACY.md +357 -0
- package/README.md +57 -0
- package/THIRD_PARTY_NOTICES.md +245 -0
- package/bin/branding.js +4 -0
- package/bin/commands/browser-install.js +483 -0
- package/bin/commands/create-sandbox.js +542 -0
- package/bin/commands/fingerprint.js +101 -0
- package/bin/commands/login.js +400 -0
- package/bin/commands/logout.js +93 -0
- package/bin/commands/minions.js +211 -0
- package/bin/commands/sandboxes.js +309 -0
- package/bin/commands/status.js +298 -0
- package/bin/commands/whoami.js +153 -0
- package/bin/launch-env.js +35 -0
- package/bin/machine-identity.js +221 -0
- package/bin/machine-layout.js +200 -0
- package/bin/minion.js +839 -0
- package/bin/platform-endpoints.js +8 -0
- package/bin/postinstall.js +52 -0
- package/bin/pty-doctor.js +326 -0
- package/bin/pty-locator.js +110 -0
- package/bin/pty-provision.js +186 -0
- package/bin/sandbox/Dockerfile +78 -0
- package/bin/sandbox/entrypoint.sh +14 -0
- package/bin/sandbox/install-repo.sh +53 -0
- package/bin/sandbox/seccomp-userns.json +883 -0
- package/bin/sandbox-config.js +306 -0
- package/dist/bin/machine-identity.js +221 -0
- package/dist/bin/machine-layout.js +200 -0
- package/dist/electron-host/agent-lease.js +141 -0
- package/dist/electron-host/dom-driver.js +642 -0
- package/dist/electron-host/ipc-protocol.js +89 -0
- package/dist/electron-host/js-driver.js +216 -0
- package/dist/electron-host/view-manager.js +254 -0
- package/dist/server/cli/engine-resume.js +49 -0
- package/dist/server/cli/eta-estimator.js +278 -0
- package/dist/server/cli/headless/background-activity.js +109 -0
- package/dist/server/cli/headless/claude-invoker-process.js +614 -0
- package/dist/server/cli/headless/claude-invoker-stall.js +150 -0
- package/dist/server/cli/headless/claude-invoker-stream.js +555 -0
- package/dist/server/cli/headless/claude-invoker-tools.js +148 -0
- package/dist/server/cli/headless/claude-invoker.js +151 -0
- package/dist/server/cli/headless/engine-availability.js +92 -0
- package/dist/server/cli/headless/engine-notice.js +185 -0
- package/dist/server/cli/headless/haiku-assessments.js +293 -0
- package/dist/server/cli/headless/headless-logger.js +75 -0
- package/dist/server/cli/headless/index.js +9 -0
- package/dist/server/cli/headless/mcp-config.js +314 -0
- package/dist/server/cli/headless/native-timeout-detector.js +72 -0
- package/dist/server/cli/headless/output-utils.js +71 -0
- package/dist/server/cli/headless/prompt-utils.js +82 -0
- package/dist/server/cli/headless/resilient-runner.js +326 -0
- package/dist/server/cli/headless/retry-strategies.js +292 -0
- package/dist/server/cli/headless/runner.js +245 -0
- package/dist/server/cli/headless/stall-assessor.js +295 -0
- package/dist/server/cli/headless/tool-watchdog.js +447 -0
- package/dist/server/cli/headless/types.js +18 -0
- package/dist/server/cli/history-portability.js +85 -0
- package/dist/server/cli/improvisation-attachments.js +99 -0
- package/dist/server/cli/improvisation-history-store.js +121 -0
- package/dist/server/cli/improvisation-movements.js +137 -0
- package/dist/server/cli/improvisation-output-queue.js +34 -0
- package/dist/server/cli/improvisation-retry.js +8 -0
- package/dist/server/cli/improvisation-session-manager.js +1016 -0
- package/dist/server/cli/improvisation-types.js +31 -0
- package/dist/server/cli/plan-lifecycle.js +72 -0
- package/dist/server/cli/prompt-builders.js +371 -0
- package/dist/server/cli/retry/retry-best-result.js +28 -0
- package/dist/server/cli/retry/retry-context-loss.js +75 -0
- package/dist/server/cli/retry/retry-recovery-strategies.js +213 -0
- package/dist/server/cli/retry/retry-resume-strategy.js +20 -0
- package/dist/server/cli/retry/retry-runner-factory.js +92 -0
- package/dist/server/cli/retry/retry-tool-results.js +22 -0
- package/dist/server/cli/retry/retry-types.js +3 -0
- package/dist/server/engines/EngineEvent.js +57 -0
- package/dist/server/engines/claude/ClaudeCodeEngine.js +316 -0
- package/dist/server/engines/claude/claude-command.js +32 -0
- package/dist/server/engines/codex/CodexEngine.js +469 -0
- package/dist/server/engines/codex/codex-auth.js +203 -0
- package/dist/server/engines/codex/codex-invoker.js +205 -0
- package/dist/server/engines/codex/codex-provision.js +215 -0
- package/dist/server/engines/credentials/credential-probe.js +88 -0
- package/dist/server/engines/credentials/model-profiles.js +249 -0
- package/dist/server/engines/credentials/provider-credentials.js +146 -0
- package/dist/server/engines/engine-event-stream.js +52 -0
- package/dist/server/engines/execution/engine-session.js +380 -0
- package/dist/server/engines/factory.js +42 -0
- package/dist/server/engines/hermes/HermesEngine.js +628 -0
- package/dist/server/engines/hermes/hermes-auth.js +159 -0
- package/dist/server/engines/hermes/hermes-gateway-home.js +271 -0
- package/dist/server/engines/hermes/hermes-invoker.js +350 -0
- package/dist/server/engines/hermes/hermes-provision.js +318 -0
- package/dist/server/engines/read-only.js +20 -0
- package/dist/server/engines/types.js +27 -0
- package/dist/server/handlers/company-execution-registry.js +67 -0
- package/dist/server/handlers/company-handlers.js +514 -0
- package/dist/server/handlers/company-triggers.js +189 -0
- package/dist/server/handlers/company-types.js +3 -0
- package/dist/server/index.js +244 -0
- package/dist/server/mcp/app-tools-bridge.js +110 -0
- package/dist/server/mcp/app-tools-mcp-server.js +99 -0
- package/dist/server/mcp/bouncer-integration.js +744 -0
- package/dist/server/mcp/browser-mcp-server.js +915 -0
- package/dist/server/mcp/browser-redaction.js +103 -0
- package/dist/server/mcp/classifier/BouncerClassifier.js +3 -0
- package/dist/server/mcp/classifier/ClaudeBouncerClassifier.js +212 -0
- package/dist/server/mcp/classifier/factory.js +124 -0
- package/dist/server/mcp/classifier/health.js +54 -0
- package/dist/server/mcp/classifier/telemetry.js +0 -0
- package/dist/server/mcp/company-patterns.js +104 -0
- package/dist/server/mcp/department-profiles.js +133 -0
- package/dist/server/mcp/quality-bridge.js +153 -0
- package/dist/server/mcp/quality-mcp-server.js +105 -0
- package/dist/server/mcp/security-analysis.js +384 -0
- package/dist/server/mcp/security-audit.js +152 -0
- package/dist/server/mcp/security-patterns.js +314 -0
- package/dist/server/mcp/server.js +194 -0
- package/dist/server/mcp/test-utils/agent-simulator.js +301 -0
- package/dist/server/mcp/test-utils/e2e-agent.js +103 -0
- package/dist/server/mcp/test-utils/e2e-capture.js +92 -0
- package/dist/server/mcp/test-utils/e2e-client.js +116 -0
- package/dist/server/mcp/test-utils/e2e-fixtures.js +87 -0
- package/dist/server/mcp/test-utils/e2e-gating.js +8 -0
- package/dist/server/mcp/test-utils/e2e-harness.js +8 -0
- package/dist/server/mcp/test-utils/e2e-scenarios.js +105 -0
- package/dist/server/routes/files.js +18 -0
- package/dist/server/routes/improvise.js +64 -0
- package/dist/server/routes/index.js +7 -0
- package/dist/server/routes/instances.js +41 -0
- package/dist/server/routes/internal.js +900 -0
- package/dist/server/routes/notifications.js +110 -0
- package/dist/server/server-setup.js +282 -0
- package/dist/server/services/agent-push.js +148 -0
- package/dist/server/services/analytics.js +197 -0
- package/dist/server/services/apps/build.js +249 -0
- package/dist/server/services/apps/greenlight.js +199 -0
- package/dist/server/services/apps/install.js +101 -0
- package/dist/server/services/apps/layout.js +35 -0
- package/dist/server/services/apps/serve.js +665 -0
- package/dist/server/services/apps/space-apps.js +248 -0
- package/dist/server/services/auth.js +48 -0
- package/dist/server/services/browser/chrome-sandbox.js +245 -0
- package/dist/server/services/browser/chromium-launch-spec.js +51 -0
- package/dist/server/services/browser/claude-reasoner.js +669 -0
- package/dist/server/services/browser/debug-log.js +3 -0
- package/dist/server/services/browser/driver-state.js +546 -0
- package/dist/server/services/browser/electron-provision.js +256 -0
- package/dist/server/services/browser/host-internal.js +245 -0
- package/dist/server/services/browser/host-mock.js +334 -0
- package/dist/server/services/browser/host-types.js +3 -0
- package/dist/server/services/browser/host.js +1067 -0
- package/dist/server/services/browser/index.js +4 -0
- package/dist/server/services/browser/ipc-client.js +354 -0
- package/dist/server/services/browser/pipewire-sink.js +199 -0
- package/dist/server/services/browser/preflight.js +590 -0
- package/dist/server/services/browser/reasoning-agent.js +659 -0
- package/dist/server/services/browser/sandbox-policy.js +169 -0
- package/dist/server/services/browser/stderr-noise-filter.js +26 -0
- package/dist/server/services/browser/telemetry.js +107 -0
- package/dist/server/services/browser/xvfb-supervisor.js +139 -0
- package/dist/server/services/browser-frame-policy.js +56 -0
- package/dist/server/services/client-id.js +32 -0
- package/dist/server/services/collab/registry.js +408 -0
- package/dist/server/services/collab/session.js +489 -0
- package/dist/server/services/collab/text-diff.js +28 -0
- package/dist/server/services/collab/types.js +19 -0
- package/dist/server/services/e2ee-group-key.js +197 -0
- package/dist/server/services/e2ee-identity.js +203 -0
- package/dist/server/services/file-explorer-ops.js +328 -0
- package/dist/server/services/file-transfer-zip.js +188 -0
- package/dist/server/services/files.js +111 -0
- package/dist/server/services/git/branch-ops.js +62 -0
- package/dist/server/services/git/command.js +68 -0
- package/dist/server/services/git/commit-message.js +74 -0
- package/dist/server/services/git/diff-ops.js +56 -0
- package/dist/server/services/git/haiku.js +76 -0
- package/dist/server/services/git/head-watcher.js +226 -0
- package/dist/server/services/git/index.js +17 -0
- package/dist/server/services/git/log-ops.js +98 -0
- package/dist/server/services/git/merge-ops.js +314 -0
- package/dist/server/services/git/parsers.js +401 -0
- package/dist/server/services/git/remote-ops.js +192 -0
- package/dist/server/services/git/status-ops.js +105 -0
- package/dist/server/services/git/suggestion-ops.js +80 -0
- package/dist/server/services/git/tag-ops.js +36 -0
- package/dist/server/services/git/types.js +4 -0
- package/dist/server/services/git/worktree-ops.js +114 -0
- package/dist/server/services/instances.js +337 -0
- package/dist/server/services/model-catalog.js +247 -0
- package/dist/server/services/observability/posthog.js +153 -0
- package/dist/server/services/pathUtils.js +114 -0
- package/dist/server/services/plan/agent-loader.js +97 -0
- package/dist/server/services/plan/agent-manager.js +363 -0
- package/dist/server/services/plan/agent-resolver.js +74 -0
- package/dist/server/services/plan/agents/assess-stall.md +33 -0
- package/dist/server/services/plan/agents/browser-planner.md +53 -0
- package/dist/server/services/plan/agents/browser-reasoner.md +114 -0
- package/dist/server/services/plan/agents/check-injection.md +95 -0
- package/dist/server/services/plan/agents/classify-error.md +30 -0
- package/dist/server/services/plan/agents/code-review.md +142 -0
- package/dist/server/services/plan/agents/commit-message.md +28 -0
- package/dist/server/services/plan/agents/detect-context-loss.md +30 -0
- package/dist/server/services/plan/agents/execute-issue.md +58 -0
- package/dist/server/services/plan/agents/fix-quality.md +25 -0
- package/dist/server/services/plan/agents/plan-coordinator.md +72 -0
- package/dist/server/services/plan/agents/pr-description.md +29 -0
- package/dist/server/services/plan/agents/retry-task.md +27 -0
- package/dist/server/services/plan/agents/review-code.md +38 -0
- package/dist/server/services/plan/agents/review-quality.md +45 -0
- package/dist/server/services/plan/agents/triage-findings.md +78 -0
- package/dist/server/services/plan/agents/verify-review.md +57 -0
- package/dist/server/services/plan/approval-evaluator.js +143 -0
- package/dist/server/services/plan/board-archive.js +102 -0
- package/dist/server/services/plan/board-config.js +108 -0
- package/dist/server/services/plan/board-export.js +214 -0
- package/dist/server/services/plan/composer-prompt.js +115 -0
- package/dist/server/services/plan/composer.js +664 -0
- package/dist/server/services/plan/config-installer.js +103 -0
- package/dist/server/services/plan/dependency-resolver.js +137 -0
- package/dist/server/services/plan/executor.js +696 -0
- package/dist/server/services/plan/front-matter.js +43 -0
- package/dist/server/services/plan/issue-classification.js +10 -0
- package/dist/server/services/plan/issue-effort.js +182 -0
- package/dist/server/services/plan/issue-loader.js +35 -0
- package/dist/server/services/plan/issue-prompt-builder.js +152 -0
- package/dist/server/services/plan/issue-retry.js +42 -0
- package/dist/server/services/plan/issue-writer.js +102 -0
- package/dist/server/services/plan/metrics-collector.js +272 -0
- package/dist/server/services/plan/output-manager.js +77 -0
- package/dist/server/services/plan/parser-core.js +435 -0
- package/dist/server/services/plan/parser-migration.js +108 -0
- package/dist/server/services/plan/parser.js +258 -0
- package/dist/server/services/plan/plan-runner-factory.js +68 -0
- package/dist/server/services/plan/pm-timeline.js +320 -0
- package/dist/server/services/plan/progress-log.js +101 -0
- package/dist/server/services/plan/prompt-builder.js +142 -0
- package/dist/server/services/plan/quality-delta.js +274 -0
- package/dist/server/services/plan/readiness-planner.js +34 -0
- package/dist/server/services/plan/review-gate.js +409 -0
- package/dist/server/services/plan/review-report.js +134 -0
- package/dist/server/services/plan/review-verdict-stream.js +161 -0
- package/dist/server/services/plan/state-reconciler.js +238 -0
- package/dist/server/services/plan/template-diff.js +175 -0
- package/dist/server/services/plan/template-instantiator.js +516 -0
- package/dist/server/services/plan/template-manifest.js +56 -0
- package/dist/server/services/plan/template-types.js +3 -0
- package/dist/server/services/plan/trigger-evaluator.js +211 -0
- package/dist/server/services/plan/types.js +3 -0
- package/dist/server/services/plan/watcher.js +73 -0
- package/dist/server/services/platform-credentials.js +56 -0
- package/dist/server/services/platform-e2ee.js +421 -0
- package/dist/server/services/platform-envelope.js +102 -0
- package/dist/server/services/platform-heartbeat.js +88 -0
- package/dist/server/services/platform-reconnect.js +60 -0
- package/dist/server/services/platform-token-lifecycle.js +95 -0
- package/dist/server/services/platform-url.js +17 -0
- package/dist/server/services/platform.js +656 -0
- package/dist/server/services/runtime-info.js +9 -0
- package/dist/server/services/schedule/agent-schedule-store.js +232 -0
- package/dist/server/services/schedule/agent-scheduler.js +323 -0
- package/dist/server/services/schedule/daily-timing.js +105 -0
- package/dist/server/services/schedule/quality-schedule-launch.js +11 -0
- package/dist/server/services/schedule/quality-schedule-store.js +211 -0
- package/dist/server/services/schedule/quality-scheduler.js +215 -0
- package/dist/server/services/schedule/run-bootstrap.js +329 -0
- package/dist/server/services/schedule/schedule-store.js +238 -0
- package/dist/server/services/schedule/schedule-wire.js +77 -0
- package/dist/server/services/schedule/scheduler.js +310 -0
- package/dist/server/services/schedule/template-source.js +97 -0
- package/dist/server/services/sdk/agent-sessions.js +264 -0
- package/dist/server/services/sdk/agents.js +557 -0
- package/dist/server/services/sdk/app-endpoints.js +48 -0
- package/dist/server/services/sdk/app-tools.js +303 -0
- package/dist/server/services/sdk/audit.js +48 -0
- package/dist/server/services/sdk/browser-transport.js +188 -0
- package/dist/server/services/sdk/browser.js +605 -0
- package/dist/server/services/sdk/composer.js +129 -0
- package/dist/server/services/sdk/connect.js +273 -0
- package/dist/server/services/sdk/consent-cooldown.js +31 -0
- package/dist/server/services/sdk/endpoint-url.js +141 -0
- package/dist/server/services/sdk/endpoints.js +314 -0
- package/dist/server/services/sdk/file-change-notify.js +36 -0
- package/dist/server/services/sdk/files-app.js +163 -0
- package/dist/server/services/sdk/files-search.js +131 -0
- package/dist/server/services/sdk/files-transfer.js +279 -0
- package/dist/server/services/sdk/files-workspace.js +233 -0
- package/dist/server/services/sdk/git.js +520 -0
- package/dist/server/services/sdk/grant-store.js +318 -0
- package/dist/server/services/sdk/host-ops.js +84 -0
- package/dist/server/services/sdk/inference-claude.js +214 -0
- package/dist/server/services/sdk/inference.js +247 -0
- package/dist/server/services/sdk/live-registry.js +42 -0
- package/dist/server/services/sdk/local-app-bindings.js +71 -0
- package/dist/server/services/sdk/pipeline.js +190 -0
- package/dist/server/services/sdk/pm-execute.js +228 -0
- package/dist/server/services/sdk/pm-planning-tap.js +29 -0
- package/dist/server/services/sdk/pm-schedule.js +165 -0
- package/dist/server/services/sdk/pm.js +634 -0
- package/dist/server/services/sdk/quality-change-notify.js +20 -0
- package/dist/server/services/sdk/quality-schedule.js +165 -0
- package/dist/server/services/sdk/quality.js +602 -0
- package/dist/server/services/sdk/rate-limits.js +198 -0
- package/dist/server/services/sdk/registry.js +597 -0
- package/dist/server/services/sdk/revoke.js +86 -0
- package/dist/server/services/sdk/run-profile.js +41 -0
- package/dist/server/services/sdk/sandbox.js +89 -0
- package/dist/server/services/sdk/storage.js +110 -0
- package/dist/server/services/sdk/streams.js +147 -0
- package/dist/server/services/sdk/terminal.js +201 -0
- package/dist/server/services/sdk/test-utils/workshop-browser-app.js +466 -0
- package/dist/server/services/sentry.js +99 -0
- package/dist/server/services/settings.js +374 -0
- package/dist/server/services/snippets/expander.js +87 -0
- package/dist/server/services/snippets/index.js +6 -0
- package/dist/server/services/snippets/loader.js +119 -0
- package/dist/server/services/snippets/parser.js +52 -0
- package/dist/server/services/snippets/types.js +3 -0
- package/dist/server/services/snippets/watcher.js +60 -0
- package/dist/server/services/space-layout.js +80 -0
- package/dist/server/services/system-prompts.js +219 -0
- package/dist/server/services/terminal/pty-manager.js +206 -0
- package/dist/server/services/terminal/pty-utils.js +150 -0
- package/dist/server/services/timeline/assembler.js +890 -0
- package/dist/server/services/timeline/contract.js +196 -0
- package/dist/server/services/timeline/index.js +4 -0
- package/dist/server/services/websocket/agent-schedule-handlers.js +217 -0
- package/dist/server/services/websocket/apps-handlers.js +399 -0
- package/dist/server/services/websocket/ask-user-question-bridge.js +112 -0
- package/dist/server/services/websocket/autocomplete-index.js +415 -0
- package/dist/server/services/websocket/autocomplete-match.js +243 -0
- package/dist/server/services/websocket/autocomplete.js +407 -0
- package/dist/server/services/websocket/browser-agent-runtime.js +208 -0
- package/dist/server/services/websocket/browser-device-profile.js +46 -0
- package/dist/server/services/websocket/browser-handlers.js +377 -0
- package/dist/server/services/websocket/browser-host-broadcast.js +179 -0
- package/dist/server/services/websocket/browser-ice-config.js +121 -0
- package/dist/server/services/websocket/browser-payloads.js +222 -0
- package/dist/server/services/websocket/browser-viewer-lifecycle.js +84 -0
- package/dist/server/services/websocket/browser-viewer-registry.js +118 -0
- package/dist/server/services/websocket/collab-broadcast.js +11 -0
- package/dist/server/services/websocket/collab-handlers.js +116 -0
- package/dist/server/services/websocket/commit-suggestion-service.js +132 -0
- package/dist/server/services/websocket/debug-log.js +38 -0
- package/dist/server/services/websocket/dispatch-util.js +10 -0
- package/dist/server/services/websocket/engine-auth-handlers.js +323 -0
- package/dist/server/services/websocket/engine-credential-watcher.js +83 -0
- package/dist/server/services/websocket/engine-profile-handlers.js +92 -0
- package/dist/server/services/websocket/file-definition-handlers.js +180 -0
- package/dist/server/services/websocket/file-download-handler.js +291 -0
- package/dist/server/services/websocket/file-explorer-handlers.js +291 -0
- package/dist/server/services/websocket/file-search-handlers.js +267 -0
- package/dist/server/services/websocket/file-share-handlers.js +328 -0
- package/dist/server/services/websocket/file-transfer-http.js +361 -0
- package/dist/server/services/websocket/file-upload-handler.js +267 -0
- package/dist/server/services/websocket/file-utils.js +346 -0
- package/dist/server/services/websocket/git-branch-handlers.js +90 -0
- package/dist/server/services/websocket/git-diff-handlers.js +59 -0
- package/dist/server/services/websocket/git-handlers.js +212 -0
- package/dist/server/services/websocket/git-head-watcher.js +85 -0
- package/dist/server/services/websocket/git-log-handlers.js +104 -0
- package/dist/server/services/websocket/git-pr-handlers.js +56 -0
- package/dist/server/services/websocket/git-tag-handlers.js +53 -0
- package/dist/server/services/websocket/git-utils.js +11 -0
- package/dist/server/services/websocket/git-worktree-handlers.js +521 -0
- package/dist/server/services/websocket/handler-context.js +113 -0
- package/dist/server/services/websocket/handler.js +1197 -0
- package/dist/server/services/websocket/index.js +5 -0
- package/dist/server/services/websocket/movement-written-files.js +26 -0
- package/dist/server/services/websocket/msg-id-tracker.js +48 -0
- package/dist/server/services/websocket/plan-board-handlers.js +410 -0
- package/dist/server/services/websocket/plan-execution-handlers.js +244 -0
- package/dist/server/services/websocket/plan-handlers.js +67 -0
- package/dist/server/services/websocket/plan-helpers.js +161 -0
- package/dist/server/services/websocket/plan-issue-handlers.js +168 -0
- package/dist/server/services/websocket/plan-sprint-handlers.js +190 -0
- package/dist/server/services/websocket/plan-transfer-handlers.js +310 -0
- package/dist/server/services/websocket/pm-timeline-broadcast.js +28 -0
- package/dist/server/services/websocket/post-session-scan.js +132 -0
- package/dist/server/services/websocket/prompt-queue-handlers.js +96 -0
- package/dist/server/services/websocket/quality-agent-cost.js +229 -0
- package/dist/server/services/websocket/quality-agent-notes.js +113 -0
- package/dist/server/services/websocket/quality-change-activity.js +187 -0
- package/dist/server/services/websocket/quality-complexity.js +345 -0
- package/dist/server/services/websocket/quality-dependencies.js +445 -0
- package/dist/server/services/websocket/quality-duplication.js +162 -0
- package/dist/server/services/websocket/quality-eta.js +65 -0
- package/dist/server/services/websocket/quality-fingerprint.js +104 -0
- package/dist/server/services/websocket/quality-grading.js +575 -0
- package/dist/server/services/websocket/quality-handlers.js +48 -0
- package/dist/server/services/websocket/quality-linting.js +270 -0
- package/dist/server/services/websocket/quality-operations.js +54 -0
- package/dist/server/services/websocket/quality-persistence.js +410 -0
- package/dist/server/services/websocket/quality-review-agent.js +526 -0
- package/dist/server/services/websocket/quality-run.js +220 -0
- package/dist/server/services/websocket/quality-secrets.js +0 -0
- package/dist/server/services/websocket/quality-service.js +775 -0
- package/dist/server/services/websocket/quality-tools.js +383 -0
- package/dist/server/services/websocket/quality-triage-agent.js +101 -0
- package/dist/server/services/websocket/quality-types.js +149 -0
- package/dist/server/services/websocket/recommended-answers.js +28 -0
- package/dist/server/services/websocket/schedule-handlers.js +197 -0
- package/dist/server/services/websocket/sdk-agent-host.js +569 -0
- package/dist/server/services/websocket/sdk-browser-host.js +459 -0
- package/dist/server/services/websocket/sdk-composer-host.js +10 -0
- package/dist/server/services/websocket/sdk-git-host.js +115 -0
- package/dist/server/services/websocket/sdk-handlers.js +242 -0
- package/dist/server/services/websocket/sdk-pm-execution-host.js +63 -0
- package/dist/server/services/websocket/sdk-pm-schedule-host.js +21 -0
- package/dist/server/services/websocket/sdk-quality-schedule-host.js +34 -0
- package/dist/server/services/websocket/sdk-terminal-host.js +140 -0
- package/dist/server/services/websocket/session-handlers.js +565 -0
- package/dist/server/services/websocket/session-history.js +335 -0
- package/dist/server/services/websocket/session-initialization.js +315 -0
- package/dist/server/services/websocket/session-registry.js +340 -0
- package/dist/server/services/websocket/session-role-directory.js +39 -0
- package/dist/server/services/websocket/settings-handlers.js +276 -0
- package/dist/server/services/websocket/skill-handlers.js +324 -0
- package/dist/server/services/websocket/skill-watcher.js +83 -0
- package/dist/server/services/websocket/snippet-handlers.js +261 -0
- package/dist/server/services/websocket/tab-broadcast.js +35 -0
- package/dist/server/services/websocket/tab-event-buffer.js +110 -0
- package/dist/server/services/websocket/tab-event-replay.js +47 -0
- package/dist/server/services/websocket/tab-handlers.js +211 -0
- package/dist/server/services/websocket/terminal-handlers.js +268 -0
- package/dist/server/services/websocket/types.js +96 -0
- package/dist/server/types/company-messages.js +102 -0
- package/dist/server/utils/agent-manager.js +202 -0
- package/dist/server/utils/console-timestamps.js +24 -0
- package/dist/server/utils/file-store.js +112 -0
- package/dist/server/utils/paths.js +28 -0
- package/dist/server/utils/port-manager.js +43 -0
- package/dist/server/utils/port.js +204 -0
- package/electron-host/dist/agent-lease.js +141 -0
- package/electron-host/dist/capture-recovery.js +77 -0
- package/electron-host/dist/codec-policy.js +37 -0
- package/electron-host/dist/controller-channel.js +60 -0
- package/electron-host/dist/controller-handlers.js +153 -0
- package/electron-host/dist/device-emulator.js +106 -0
- package/electron-host/dist/dom-driver.js +642 -0
- package/electron-host/dist/domain-registry.js +159 -0
- package/electron-host/dist/domain-validators.js +308 -0
- package/electron-host/dist/editable-focus-reporter.js +143 -0
- package/electron-host/dist/fake-peer.test-util.js +105 -0
- package/electron-host/dist/host-log.js +31 -0
- package/electron-host/dist/host-wire.js +11 -0
- package/electron-host/dist/input-router.js +421 -0
- package/electron-host/dist/ipc-protocol.js +89 -0
- package/electron-host/dist/ipc-server.js +193 -0
- package/electron-host/dist/js-driver.js +216 -0
- package/electron-host/dist/main-guards.js +70 -0
- package/electron-host/dist/main.js +716 -0
- package/electron-host/dist/roster-sync.js +87 -0
- package/electron-host/dist/rpc-context.js +1 -0
- package/electron-host/dist/rpc-tab-methods.js +138 -0
- package/electron-host/dist/rpc-webrtc-methods.js +121 -0
- package/electron-host/dist/screen-capture-cache.js +147 -0
- package/electron-host/dist/sdk-injector.js +166 -0
- package/electron-host/dist/sdp.js +102 -0
- package/electron-host/dist/session-surface.js +78 -0
- package/electron-host/dist/surface-sizing.js +59 -0
- package/electron-host/dist/view-manager.js +254 -0
- package/electron-host/dist/viewer-registry.js +46 -0
- package/electron-host/dist/viewer-session.js +288 -0
- package/electron-host/dist/webrtc-channels.js +14 -0
- package/electron-host/dist/webrtc-controller.js +57 -0
- package/electron-host/dist/webrtc-ice-filter.js +13 -0
- package/electron-host/dist/webrtc-peer.js +45 -0
- package/electron-host/package.json +12 -0
- package/electron-host/tsconfig.json +23 -0
- package/electron-host/webrtc-controller-preload.cjs +3 -0
- package/electron-host/webrtc-controller.html +14 -0
- package/package.json +85 -0
- package/vendor/e2ee/LICENSE +14 -0
- package/vendor/e2ee/package.json +14 -0
- package/vendor/e2ee/src/index.js +310 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
export function redactRemoteCredentials(remoteUrl) {
|
|
5
|
+
try {
|
|
6
|
+
const url = new URL(remoteUrl);
|
|
7
|
+
if (url.username || url.password) {
|
|
8
|
+
url.username = '';
|
|
9
|
+
url.password = '';
|
|
10
|
+
return url.toString();
|
|
11
|
+
}
|
|
12
|
+
return remoteUrl;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return remoteUrl;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function detectGitProvider(remoteUrl) {
|
|
19
|
+
if (remoteUrl.includes('github.com'))
|
|
20
|
+
return 'github';
|
|
21
|
+
if (remoteUrl.includes('gitlab.com') || remoteUrl.includes('gitlab'))
|
|
22
|
+
return 'gitlab';
|
|
23
|
+
return 'unknown';
|
|
24
|
+
}
|
|
25
|
+
const COAUTHOR_LINE_PATTERNS = [
|
|
26
|
+
/co-authored-by/i,
|
|
27
|
+
/authored-by:/i,
|
|
28
|
+
/generated with .*(claude|anthropic)/i,
|
|
29
|
+
/noreply@anthropic\.com/i,
|
|
30
|
+
];
|
|
31
|
+
export function stripCoauthorLines(message) {
|
|
32
|
+
const lines = message.split('\n');
|
|
33
|
+
const result = [];
|
|
34
|
+
for (let i = 0; i < lines.length; i++) {
|
|
35
|
+
if (COAUTHOR_LINE_PATTERNS.some(p => p.test(lines[i]))) {
|
|
36
|
+
if (result.length > 0 && result[result.length - 1].trim() === '') {
|
|
37
|
+
result.pop();
|
|
38
|
+
}
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
result.push(lines[i]);
|
|
42
|
+
}
|
|
43
|
+
if (result.length === 0)
|
|
44
|
+
return '';
|
|
45
|
+
return result.join('\n').trimEnd();
|
|
46
|
+
}
|
|
47
|
+
export function extractCommitMessage(rawOutput) {
|
|
48
|
+
const output = stripCoauthorLines(rawOutput.trim()).trim();
|
|
49
|
+
const patterns = [
|
|
50
|
+
/(?:here'?s?\s+(?:the\s+)?commit\s+message:?\s*\n+)([\s\S]+)/i,
|
|
51
|
+
/(?:commit\s+message:?\s*\n+)([\s\S]+)/i,
|
|
52
|
+
/(?:suggested\s+commit\s+message:?\s*\n+)([\s\S]+)/i,
|
|
53
|
+
];
|
|
54
|
+
for (const pattern of patterns) {
|
|
55
|
+
const match = output.match(pattern);
|
|
56
|
+
if (match?.[1]) {
|
|
57
|
+
return match[1].trim();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const paragraphs = output.split(/\n\n+/).filter(p => p.trim());
|
|
61
|
+
if (paragraphs.length <= 1) {
|
|
62
|
+
return output;
|
|
63
|
+
}
|
|
64
|
+
const firstParagraph = paragraphs[0].trim();
|
|
65
|
+
const firstLine = firstParagraph.split('\n')[0].trim();
|
|
66
|
+
const reasoningPatterns = [
|
|
67
|
+
/^(Now|Based|Looking|After|Here|Let me|I\s+(can|will|see|notice|'ll|would))/i,
|
|
68
|
+
/^The\s+\w+\s+(file|changes?|commit|diff)/i,
|
|
69
|
+
/\b(I can|I will|I'll|let me|analyzing|looking at)\b/i,
|
|
70
|
+
];
|
|
71
|
+
const looksLikeReasoning = reasoningPatterns.some(p => p.test(firstParagraph));
|
|
72
|
+
const firstLineTooLong = firstLine.length > 80;
|
|
73
|
+
const endsWithPeriod = firstLine.endsWith('.');
|
|
74
|
+
if (looksLikeReasoning || (firstLineTooLong && endsWithPeriod)) {
|
|
75
|
+
const commitMessage = paragraphs.slice(1).join('\n\n').trim();
|
|
76
|
+
const extractedFirstLine = commitMessage.split('\n')[0].trim();
|
|
77
|
+
if (extractedFirstLine.length > 0 && extractedFirstLine.length <= 100) {
|
|
78
|
+
return commitMessage;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (paragraphs.length >= 2) {
|
|
82
|
+
const secondParagraph = paragraphs[1].trim();
|
|
83
|
+
const secondFirstLine = secondParagraph.split('\n')[0].trim();
|
|
84
|
+
if (secondFirstLine.length <= 72 &&
|
|
85
|
+
/^[A-Z][a-z]/.test(secondFirstLine) &&
|
|
86
|
+
!secondFirstLine.endsWith('.')) {
|
|
87
|
+
return paragraphs.slice(1).join('\n\n').trim();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return output;
|
|
91
|
+
}
|
|
92
|
+
const ESCAPE_CHARS = {
|
|
93
|
+
'\\': '\\',
|
|
94
|
+
'"': '"',
|
|
95
|
+
'n': '\n',
|
|
96
|
+
't': '\t',
|
|
97
|
+
'r': '\r',
|
|
98
|
+
};
|
|
99
|
+
function isOctalEscape(str, i) {
|
|
100
|
+
return i + 3 < str.length &&
|
|
101
|
+
/[0-7]/.test(str[i + 1]) &&
|
|
102
|
+
/[0-7]{2}/.test(str.slice(i + 2, i + 4));
|
|
103
|
+
}
|
|
104
|
+
export function unquoteGitPath(path) {
|
|
105
|
+
if (!path.startsWith('"') || !path.endsWith('"')) {
|
|
106
|
+
return path;
|
|
107
|
+
}
|
|
108
|
+
const inner = path.slice(1, -1);
|
|
109
|
+
let result = '';
|
|
110
|
+
let i = 0;
|
|
111
|
+
while (i < inner.length) {
|
|
112
|
+
if (inner[i] !== '\\' || i + 1 >= inner.length) {
|
|
113
|
+
result += inner[i];
|
|
114
|
+
i++;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const next = inner[i + 1];
|
|
118
|
+
const escaped = ESCAPE_CHARS[next];
|
|
119
|
+
if (escaped !== undefined) {
|
|
120
|
+
result += escaped;
|
|
121
|
+
i += 2;
|
|
122
|
+
}
|
|
123
|
+
else if (isOctalEscape(inner, i)) {
|
|
124
|
+
result += String.fromCharCode(parseInt(inner.slice(i + 1, i + 4), 8));
|
|
125
|
+
i += 4;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
result += inner[i];
|
|
129
|
+
i++;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
export function parseGitStatus(porcelainOutput) {
|
|
135
|
+
const staged = [];
|
|
136
|
+
const unstaged = [];
|
|
137
|
+
const untracked = [];
|
|
138
|
+
const lines = porcelainOutput.split('\n').filter(line => line.length >= 4);
|
|
139
|
+
for (const line of lines) {
|
|
140
|
+
const indexStatus = line[0];
|
|
141
|
+
const workTreeStatus = line[1];
|
|
142
|
+
const rawPath = line.slice(3);
|
|
143
|
+
const path = unquoteGitPath(rawPath);
|
|
144
|
+
let filePath = path;
|
|
145
|
+
let originalPath;
|
|
146
|
+
if (rawPath.includes(' -> ')) {
|
|
147
|
+
const parts = rawPath.split(' -> ');
|
|
148
|
+
originalPath = unquoteGitPath(parts[0]);
|
|
149
|
+
filePath = unquoteGitPath(parts[1]);
|
|
150
|
+
}
|
|
151
|
+
if (indexStatus === '?' && workTreeStatus === '?') {
|
|
152
|
+
untracked.push({ path: filePath, status: '?', staged: false });
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (indexStatus !== ' ' && indexStatus !== '?') {
|
|
156
|
+
staged.push({ path: filePath, status: indexStatus, staged: true, originalPath });
|
|
157
|
+
}
|
|
158
|
+
if (workTreeStatus !== ' ' && workTreeStatus !== '?') {
|
|
159
|
+
unstaged.push({ path: filePath, status: workTreeStatus, staged: false, originalPath });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return { staged, unstaged, untracked };
|
|
163
|
+
}
|
|
164
|
+
export function parseAheadBehind(countOutput) {
|
|
165
|
+
const parts = countOutput.trim().split(/\s+/);
|
|
166
|
+
return {
|
|
167
|
+
ahead: parseInt(parts[0], 10) || 0,
|
|
168
|
+
behind: parseInt(parts[1], 10) || 0,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function applyWorktreePorcelainLine(line, worktrees, current) {
|
|
172
|
+
if (line.startsWith('worktree ')) {
|
|
173
|
+
if (current.path)
|
|
174
|
+
worktrees.push(current);
|
|
175
|
+
return { path: line.slice(9).trim(), isMain: false, isBare: false };
|
|
176
|
+
}
|
|
177
|
+
if (line.startsWith('HEAD '))
|
|
178
|
+
current.head = line.slice(5).trim();
|
|
179
|
+
else if (line.startsWith('branch '))
|
|
180
|
+
current.branch = line.slice(7).trim().replace('refs/heads/', '');
|
|
181
|
+
else if (line === 'bare')
|
|
182
|
+
current.isBare = true;
|
|
183
|
+
else if (line === 'prunable')
|
|
184
|
+
current.prunable = true;
|
|
185
|
+
return current;
|
|
186
|
+
}
|
|
187
|
+
export function parseWorktreePorcelain(stdout) {
|
|
188
|
+
const worktrees = [];
|
|
189
|
+
let current = {};
|
|
190
|
+
for (const line of stdout.split('\n')) {
|
|
191
|
+
current = applyWorktreePorcelainLine(line, worktrees, current);
|
|
192
|
+
}
|
|
193
|
+
if (current.path)
|
|
194
|
+
worktrees.push(current);
|
|
195
|
+
if (worktrees.length > 0)
|
|
196
|
+
worktrees[0].isMain = true;
|
|
197
|
+
return worktrees;
|
|
198
|
+
}
|
|
199
|
+
export function firstWorktreePath(porcelainOutput) {
|
|
200
|
+
const firstLine = porcelainOutput.split('\n').find(l => l.startsWith('worktree '));
|
|
201
|
+
return firstLine ? firstLine.slice(9).trim() : null;
|
|
202
|
+
}
|
|
203
|
+
export function findWorktreePathForBranch(porcelainOutput, branchName) {
|
|
204
|
+
let currentWtPath = '';
|
|
205
|
+
const fullRef = `refs/heads/${branchName}`;
|
|
206
|
+
for (const line of porcelainOutput.split('\n')) {
|
|
207
|
+
if (line.startsWith('worktree '))
|
|
208
|
+
currentWtPath = line.slice(9).trim();
|
|
209
|
+
if (line.startsWith('branch ') && line.slice(7).trim() === fullRef)
|
|
210
|
+
return currentWtPath;
|
|
211
|
+
}
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
export function deriveWorktreePath(baseDir, branchName) {
|
|
215
|
+
const repoName = baseDir.split('/').pop() || 'repo';
|
|
216
|
+
return join(dirname(baseDir), `${repoName}-worktrees`, branchName);
|
|
217
|
+
}
|
|
218
|
+
function applyBranchAbLine(line, summary) {
|
|
219
|
+
summary.hasUpstream = true;
|
|
220
|
+
const match = /^# branch\.ab \+(\d+) -(\d+)$/.exec(line);
|
|
221
|
+
if (!match)
|
|
222
|
+
return;
|
|
223
|
+
summary.ahead = parseInt(match[1], 10);
|
|
224
|
+
summary.behind = parseInt(match[2], 10);
|
|
225
|
+
}
|
|
226
|
+
function applyChangedEntryLine(line, summary) {
|
|
227
|
+
const xy = line.split(' ')[1] ?? '';
|
|
228
|
+
if (xy[0] && xy[0] !== '.')
|
|
229
|
+
summary.staged++;
|
|
230
|
+
if (xy[1] && xy[1] !== '.')
|
|
231
|
+
summary.unstaged++;
|
|
232
|
+
}
|
|
233
|
+
function applyStatusLine(line, summary) {
|
|
234
|
+
if (line.startsWith('# branch.ab '))
|
|
235
|
+
applyBranchAbLine(line, summary);
|
|
236
|
+
else if (line.startsWith('1 ') || line.startsWith('2 '))
|
|
237
|
+
applyChangedEntryLine(line, summary);
|
|
238
|
+
else if (line.startsWith('u '))
|
|
239
|
+
summary.unstaged++;
|
|
240
|
+
else if (line.startsWith('? '))
|
|
241
|
+
summary.untracked++;
|
|
242
|
+
}
|
|
243
|
+
export function parseWorktreeStatusSummary(porcelainV2) {
|
|
244
|
+
const summary = { staged: 0, unstaged: 0, untracked: 0, ahead: 0, behind: 0, hasUpstream: false };
|
|
245
|
+
for (const line of porcelainV2.split('\n')) {
|
|
246
|
+
applyStatusLine(line, summary);
|
|
247
|
+
}
|
|
248
|
+
return summary;
|
|
249
|
+
}
|
|
250
|
+
export const BRANCH_LIST_FORMAT = [
|
|
251
|
+
'%(refname:short)',
|
|
252
|
+
'%(objectname:short)',
|
|
253
|
+
'%(upstream:short)',
|
|
254
|
+
'%(HEAD)',
|
|
255
|
+
'%(committerdate:iso8601-strict)',
|
|
256
|
+
'%(upstream:track)',
|
|
257
|
+
].join('\t');
|
|
258
|
+
export function parseUpstreamTrack(token) {
|
|
259
|
+
const trimmed = token.trim();
|
|
260
|
+
if (trimmed === '[gone]')
|
|
261
|
+
return { ahead: 0, behind: 0, gone: true };
|
|
262
|
+
const ahead = /\[.*ahead (\d+)/.exec(trimmed);
|
|
263
|
+
const behind = /(?:\[|, )behind (\d+)/.exec(trimmed);
|
|
264
|
+
return {
|
|
265
|
+
ahead: ahead ? parseInt(ahead[1], 10) : 0,
|
|
266
|
+
behind: behind ? parseInt(behind[1], 10) : 0,
|
|
267
|
+
gone: false,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
export function parseBranchLine(line) {
|
|
271
|
+
const [name, shortHash, upstream, head, committerDate, track] = line.split('\t');
|
|
272
|
+
if (!name?.trim())
|
|
273
|
+
return null;
|
|
274
|
+
const trimmedName = name.trim();
|
|
275
|
+
const isRemote = trimmedName.includes('/') && (trimmedName.startsWith('origin/') || trimmedName.includes('remotes/'));
|
|
276
|
+
const hasUpstream = !!upstream?.trim();
|
|
277
|
+
const tracked = parseUpstreamTrack(track ?? '');
|
|
278
|
+
return {
|
|
279
|
+
name: trimmedName,
|
|
280
|
+
shortHash: shortHash?.trim() || '',
|
|
281
|
+
isRemote,
|
|
282
|
+
isCurrent: head?.trim() === '*',
|
|
283
|
+
upstream: upstream?.trim() || undefined,
|
|
284
|
+
lastCommitDate: committerDate?.trim() || undefined,
|
|
285
|
+
ahead: hasUpstream ? tracked.ahead : undefined,
|
|
286
|
+
behind: hasUpstream ? tracked.behind : undefined,
|
|
287
|
+
upstreamGone: tracked.gone || undefined,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
export function parseBranchList(stdout) {
|
|
291
|
+
return stdout.trim().split('\n')
|
|
292
|
+
.filter(line => line.trim())
|
|
293
|
+
.map(parseBranchLine)
|
|
294
|
+
.filter((b) => b !== null && b.name !== 'origin/HEAD');
|
|
295
|
+
}
|
|
296
|
+
const GIT_LOG_FORMAT = '%H%x00%h%x00%s%x00%an%x00%aI';
|
|
297
|
+
export function buildGitLogArgs(opts) {
|
|
298
|
+
const { limit, skip, search } = opts;
|
|
299
|
+
const args = ['log', `-${limit + 1}`, `--skip=${skip}`];
|
|
300
|
+
const term = search?.trim();
|
|
301
|
+
if (term) {
|
|
302
|
+
args.push('-i', '-F', `--grep=${term}`);
|
|
303
|
+
}
|
|
304
|
+
args.push(`--format=${GIT_LOG_FORMAT}`);
|
|
305
|
+
return args;
|
|
306
|
+
}
|
|
307
|
+
export function parseLogEntries(stdout) {
|
|
308
|
+
return stdout.trim().split('\n').filter(Boolean).map(line => {
|
|
309
|
+
const parts = line.split('\x00');
|
|
310
|
+
const cleanSubject = stripCoauthorLines(parts[2] || '') || parts[2] || '';
|
|
311
|
+
return { hash: parts[0], shortHash: parts[1], subject: cleanSubject, author: parts[3], date: parts[4] };
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
export const TAG_LIST_FORMAT = '%(refname:short)|%(objectname:short)|%(creatordate:iso-strict)|%(subject)';
|
|
315
|
+
export function parseTagList(stdout) {
|
|
316
|
+
return stdout.trim().split('\n')
|
|
317
|
+
.filter(line => line.trim())
|
|
318
|
+
.slice(0, 50)
|
|
319
|
+
.map(line => {
|
|
320
|
+
const parts = line.split('|');
|
|
321
|
+
return {
|
|
322
|
+
name: parts[0]?.trim() || '',
|
|
323
|
+
shortHash: parts[1]?.trim() || '',
|
|
324
|
+
date: parts[2]?.trim() || '',
|
|
325
|
+
message: parts[3]?.trim() || '',
|
|
326
|
+
};
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
function parseStatusLine(line) {
|
|
330
|
+
if (!line)
|
|
331
|
+
return { status: 'M' };
|
|
332
|
+
const parts = line.split('\t');
|
|
333
|
+
const status = (parts[0] || 'M').charAt(0);
|
|
334
|
+
const oldPath = (status === 'R' || status === 'C') && parts.length >= 3 ? parts[1] : undefined;
|
|
335
|
+
return { status, oldPath };
|
|
336
|
+
}
|
|
337
|
+
export function parseCommitFiles(numstatOutput, statusOutput) {
|
|
338
|
+
const numstatLines = numstatOutput.trim().split('\n').filter(Boolean);
|
|
339
|
+
const statusLines = statusOutput.trim().split('\n').filter(Boolean);
|
|
340
|
+
return numstatLines.map((line, i) => {
|
|
341
|
+
const numParts = line.split('\t');
|
|
342
|
+
const additions = numParts[0] === '-' ? 0 : parseInt(numParts[0], 10) || 0;
|
|
343
|
+
const deletions = numParts[1] === '-' ? 0 : parseInt(numParts[1], 10) || 0;
|
|
344
|
+
const { status, oldPath } = parseStatusLine(statusLines[i]);
|
|
345
|
+
return { path: numParts[2] || '', status, additions, deletions, ...(oldPath ? { oldPath } : {}) };
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
export function parseMergeTreeConflicts(stdout) {
|
|
349
|
+
return stdout.split('\n')
|
|
350
|
+
.filter(line => line.includes('CONFLICT'))
|
|
351
|
+
.map(line => {
|
|
352
|
+
const match = line.match(/CONFLICT.*:\s+(.+)/);
|
|
353
|
+
return match?.[1]?.trim() || line;
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
export function parseMergeTreeOid(stdout) {
|
|
357
|
+
return stdout.split('\n', 1)[0].trim();
|
|
358
|
+
}
|
|
359
|
+
export function parseMergeCommits(stdout) {
|
|
360
|
+
return stdout.trim().split('\n')
|
|
361
|
+
.filter(line => line.trim())
|
|
362
|
+
.map(line => {
|
|
363
|
+
const [hash, ...rest] = line.split('|');
|
|
364
|
+
return { hash: hash.trim(), message: rest.join('|').trim() };
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
export function parseOverwritePaths(stderr) {
|
|
368
|
+
const lines = stderr.split('\n');
|
|
369
|
+
const headerIdx = lines.findIndex(l => /your local changes to the following files would be overwritten/i.test(l) ||
|
|
370
|
+
/untracked working tree files would be overwritten/i.test(l));
|
|
371
|
+
if (headerIdx < 0)
|
|
372
|
+
return [];
|
|
373
|
+
const paths = [];
|
|
374
|
+
for (let i = headerIdx + 1; i < lines.length; i++) {
|
|
375
|
+
const line = lines[i];
|
|
376
|
+
const trimmed = line.trim();
|
|
377
|
+
if (!trimmed)
|
|
378
|
+
continue;
|
|
379
|
+
if (/^(merge with strategy|aborting|please commit)/i.test(trimmed))
|
|
380
|
+
break;
|
|
381
|
+
if (/^[\t ]/.test(line)) {
|
|
382
|
+
paths.push(trimmed);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return paths;
|
|
386
|
+
}
|
|
387
|
+
export function isSafeDiscardPath(p) {
|
|
388
|
+
if (typeof p !== 'string' || p.length === 0)
|
|
389
|
+
return false;
|
|
390
|
+
if (p === '.' || p === './')
|
|
391
|
+
return false;
|
|
392
|
+
if (p.startsWith('/') || p.startsWith('~'))
|
|
393
|
+
return false;
|
|
394
|
+
if (p.startsWith(':'))
|
|
395
|
+
return false;
|
|
396
|
+
if (p.split(/[/\\]/).includes('..'))
|
|
397
|
+
return false;
|
|
398
|
+
if (/[*?[\]]/.test(p))
|
|
399
|
+
return false;
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { loadSkillPrompt } from '../plan/agent-loader.js';
|
|
4
|
+
import { getPrBaseBranch, setPrBaseBranch } from '../settings.js';
|
|
5
|
+
import { executeGitCommand, spawnCheck, spawnWithOutput } from './command.js';
|
|
6
|
+
import { spawnHaikuWithPrompt, truncateDiff } from './haiku.js';
|
|
7
|
+
import { detectGitProvider, redactRemoteCredentials, stripCoauthorLines } from './parsers.js';
|
|
8
|
+
import { gitFail, gitOk } from './types.js';
|
|
9
|
+
async function getDefaultBranch(workingDir) {
|
|
10
|
+
const result = await executeGitCommand(['symbolic-ref', 'refs/remotes/origin/HEAD', '--short'], workingDir);
|
|
11
|
+
return result.exitCode === 0 ? result.stdout.trim().replace('origin/', '') : 'main';
|
|
12
|
+
}
|
|
13
|
+
async function checkGitCliStatus(provider) {
|
|
14
|
+
const cliBin = provider === 'github' ? 'gh' : provider === 'gitlab' ? 'glab' : null;
|
|
15
|
+
if (!cliBin)
|
|
16
|
+
return { hasGhCli: false, ghCliAuthenticated: false };
|
|
17
|
+
const installed = await spawnCheck(cliBin, ['--version']);
|
|
18
|
+
if (!installed)
|
|
19
|
+
return { hasGhCli: false, ghCliAuthenticated: false };
|
|
20
|
+
const authenticated = await spawnCheck(cliBin, ['auth', 'status']);
|
|
21
|
+
return { hasGhCli: true, ghCliAuthenticated: authenticated, ghCliBinary: cliBin };
|
|
22
|
+
}
|
|
23
|
+
async function listRemoteBranches(workingDir) {
|
|
24
|
+
const result = await executeGitCommand(['branch', '-r', '--list', 'origin/*'], workingDir);
|
|
25
|
+
if (result.exitCode !== 0)
|
|
26
|
+
return [];
|
|
27
|
+
return result.stdout.split('\n')
|
|
28
|
+
.map(line => line.trim())
|
|
29
|
+
.filter(line => line && !line.includes('->'))
|
|
30
|
+
.map(line => line.replace('origin/', ''))
|
|
31
|
+
.filter(Boolean)
|
|
32
|
+
.sort();
|
|
33
|
+
}
|
|
34
|
+
export async function readRemoteInfo({ cwd }) {
|
|
35
|
+
const remoteResult = await executeGitCommand(['remote', 'get-url', 'origin'], cwd);
|
|
36
|
+
if (remoteResult.exitCode !== 0) {
|
|
37
|
+
return { hasRemote: false };
|
|
38
|
+
}
|
|
39
|
+
const remoteUrl = remoteResult.stdout.trim();
|
|
40
|
+
const provider = detectGitProvider(remoteUrl);
|
|
41
|
+
const defaultBranch = await getDefaultBranch(cwd);
|
|
42
|
+
const branchResult = await executeGitCommand(['rev-parse', '--abbrev-ref', 'HEAD'], cwd);
|
|
43
|
+
const currentBranch = branchResult.exitCode === 0 ? branchResult.stdout.trim() : '';
|
|
44
|
+
const cliStatus = await checkGitCliStatus(provider);
|
|
45
|
+
const remoteBranches = await listRemoteBranches(cwd);
|
|
46
|
+
const preferredBaseBranch = getPrBaseBranch(remoteUrl) ?? undefined;
|
|
47
|
+
return {
|
|
48
|
+
hasRemote: true,
|
|
49
|
+
remoteUrl: redactRemoteCredentials(remoteUrl),
|
|
50
|
+
provider,
|
|
51
|
+
defaultBranch,
|
|
52
|
+
currentBranch,
|
|
53
|
+
...cliStatus,
|
|
54
|
+
remoteBranches,
|
|
55
|
+
preferredBaseBranch,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function detectPRCliBin(remoteUrl) {
|
|
59
|
+
const isGitHub = remoteUrl.includes('github.com');
|
|
60
|
+
const isGitLab = remoteUrl.includes('gitlab.com') || remoteUrl.includes('gitlab');
|
|
61
|
+
const cliBin = isGitHub ? 'gh' : isGitLab ? 'glab' : null;
|
|
62
|
+
return { cliBin, isGitHub, isGitLab };
|
|
63
|
+
}
|
|
64
|
+
async function ensureBranchPushed(headBranch, workingDir) {
|
|
65
|
+
const upstreamCheck = await executeGitCommand(['rev-parse', '--abbrev-ref', `${headBranch}@{u}`], workingDir);
|
|
66
|
+
const hasUpstream = upstreamCheck.exitCode === 0;
|
|
67
|
+
let needsPush = !hasUpstream;
|
|
68
|
+
if (hasUpstream) {
|
|
69
|
+
const aheadCheck = await executeGitCommand(['rev-list', '--count', `@{u}..HEAD`], workingDir);
|
|
70
|
+
needsPush = aheadCheck.exitCode === 0 && parseInt(aheadCheck.stdout.trim(), 10) > 0;
|
|
71
|
+
}
|
|
72
|
+
if (!needsPush)
|
|
73
|
+
return null;
|
|
74
|
+
const pushArgs = hasUpstream ? ['push'] : ['push', '-u', 'origin', headBranch];
|
|
75
|
+
const pushResult = await executeGitCommand(pushArgs, workingDir);
|
|
76
|
+
if (pushResult.exitCode !== 0) {
|
|
77
|
+
return `Failed to push branch before creating PR: ${pushResult.stderr || pushResult.stdout}`;
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
function classifyCliPRError(cliBin, result, headBranch) {
|
|
82
|
+
const combined = result.stderr + result.stdout;
|
|
83
|
+
const lower = combined.toLowerCase();
|
|
84
|
+
if (lower.includes('already exists')) {
|
|
85
|
+
const existingUrl = combined.match(/https?:\/\/\S+/);
|
|
86
|
+
return existingUrl
|
|
87
|
+
? `A pull request already exists for ${headBranch}: ${existingUrl[0]}`
|
|
88
|
+
: `A pull request already exists for ${headBranch}`;
|
|
89
|
+
}
|
|
90
|
+
if (lower.includes('auth') || lower.includes('401') || lower.includes('token') || lower.includes('log in')) {
|
|
91
|
+
return `${cliBin} is not authenticated. Run: ${cliBin} auth login`;
|
|
92
|
+
}
|
|
93
|
+
if (lower.includes('must first push') || lower.includes('failed to push') || lower.includes('no upstream')) {
|
|
94
|
+
return `Branch "${headBranch}" has not been pushed to remote. Push first, then create the PR.`;
|
|
95
|
+
}
|
|
96
|
+
return `${cliBin} failed: ${(result.stderr || result.stdout).trim()}`;
|
|
97
|
+
}
|
|
98
|
+
async function tryCliPRCreate(cliBin, opts, workingDir) {
|
|
99
|
+
if (!cliBin)
|
|
100
|
+
return { created: false };
|
|
101
|
+
const installed = await spawnCheck(cliBin, ['--version']);
|
|
102
|
+
if (!installed)
|
|
103
|
+
return { created: false };
|
|
104
|
+
const args = cliBin === 'gh'
|
|
105
|
+
? ['pr', 'create', '--title', opts.title]
|
|
106
|
+
: ['mr', 'create', '--title', opts.title, '--yes'];
|
|
107
|
+
if (opts.body)
|
|
108
|
+
args.push('--body', opts.body);
|
|
109
|
+
if (opts.baseBranch) {
|
|
110
|
+
args.push(cliBin === 'gh' ? '--base' : '--target-branch', opts.baseBranch);
|
|
111
|
+
}
|
|
112
|
+
if (opts.draft)
|
|
113
|
+
args.push('--draft');
|
|
114
|
+
const result = await spawnWithOutput(cliBin, args, workingDir);
|
|
115
|
+
if (result.exitCode === 0) {
|
|
116
|
+
const urlMatch = result.stdout.match(/https?:\/\/\S+/);
|
|
117
|
+
return { created: true, url: urlMatch ? urlMatch[0] : result.stdout.trim() };
|
|
118
|
+
}
|
|
119
|
+
return { created: false, error: classifyCliPRError(cliBin, result, opts.headBranch) };
|
|
120
|
+
}
|
|
121
|
+
function buildBrowserPRUrl(remoteUrl, headBranch, baseBranch, title, body, isGitHub, isGitLab) {
|
|
122
|
+
const sshMatch = remoteUrl.match(/[:/]([^/]+)\/([^/.]+)(?:\.git)?$/);
|
|
123
|
+
if (!sshMatch)
|
|
124
|
+
return '';
|
|
125
|
+
const [, owner, repo] = sshMatch;
|
|
126
|
+
const base = baseBranch || 'main';
|
|
127
|
+
if (isGitHub) {
|
|
128
|
+
return `https://github.com/${owner}/${repo}/compare/${base}...${headBranch}?expand=1&title=${encodeURIComponent(title)}${body ? `&body=${encodeURIComponent(body)}` : ''}`;
|
|
129
|
+
}
|
|
130
|
+
if (isGitLab) {
|
|
131
|
+
return `https://gitlab.com/${owner}/${repo}/-/merge_requests/new?merge_request[source_branch]=${headBranch}&merge_request[target_branch]=${base}&merge_request[title]=${encodeURIComponent(title)}`;
|
|
132
|
+
}
|
|
133
|
+
return '';
|
|
134
|
+
}
|
|
135
|
+
export async function createPullRequest({ cwd, title, body, baseBranch, draft }) {
|
|
136
|
+
const branchResult = await executeGitCommand(['rev-parse', '--abbrev-ref', 'HEAD'], cwd);
|
|
137
|
+
if (branchResult.exitCode !== 0) {
|
|
138
|
+
return gitFail('Failed to detect current branch');
|
|
139
|
+
}
|
|
140
|
+
const remoteResult = await executeGitCommand(['remote', 'get-url', 'origin'], cwd);
|
|
141
|
+
if (remoteResult.exitCode !== 0) {
|
|
142
|
+
return gitFail('No remote origin configured');
|
|
143
|
+
}
|
|
144
|
+
const headBranch = branchResult.stdout.trim();
|
|
145
|
+
const remoteUrl = remoteResult.stdout.trim();
|
|
146
|
+
const { cliBin, isGitHub, isGitLab } = detectPRCliBin(remoteUrl);
|
|
147
|
+
const pushError = await ensureBranchPushed(headBranch, cwd);
|
|
148
|
+
if (pushError) {
|
|
149
|
+
return gitFail(pushError);
|
|
150
|
+
}
|
|
151
|
+
const cliResult = await tryCliPRCreate(cliBin, { title, body, baseBranch, draft, headBranch }, cwd);
|
|
152
|
+
if (cliResult.created) {
|
|
153
|
+
if (baseBranch)
|
|
154
|
+
setPrBaseBranch(remoteUrl, baseBranch);
|
|
155
|
+
return gitOk({ url: cliResult.url, method: isGitHub ? 'gh' : 'glab' });
|
|
156
|
+
}
|
|
157
|
+
if (cliResult.error) {
|
|
158
|
+
return gitFail(cliResult.error);
|
|
159
|
+
}
|
|
160
|
+
const prUrl = buildBrowserPRUrl(remoteUrl, headBranch, baseBranch, title, body, isGitHub, isGitLab);
|
|
161
|
+
if (!prUrl) {
|
|
162
|
+
return gitFail('Could not determine remote URL format for PR creation');
|
|
163
|
+
}
|
|
164
|
+
if (baseBranch)
|
|
165
|
+
setPrBaseBranch(remoteUrl, baseBranch);
|
|
166
|
+
return gitOk({ url: prUrl, method: 'browser' });
|
|
167
|
+
}
|
|
168
|
+
const PR_DESCRIPTION_SYSTEM_PROMPT = 'You are a pull request description assistant. Respond with only the PR title and description, no preamble or explanation.';
|
|
169
|
+
export async function generatePrDescription({ cwd, baseBranch }) {
|
|
170
|
+
const remoteBase = `origin/${baseBranch}`;
|
|
171
|
+
const remoteRefCheck = await executeGitCommand(['rev-parse', '--verify', remoteBase], cwd);
|
|
172
|
+
const compareRef = remoteRefCheck.exitCode === 0 ? remoteBase : baseBranch;
|
|
173
|
+
const logResult = await executeGitCommand(['log', `${compareRef}..HEAD`, '--oneline'], cwd);
|
|
174
|
+
const commits = logResult.exitCode === 0 ? logResult.stdout.trim() : '';
|
|
175
|
+
if (!commits) {
|
|
176
|
+
return gitFail(`No commits found between ${baseBranch} and HEAD`);
|
|
177
|
+
}
|
|
178
|
+
const diffResult = await executeGitCommand(['diff', `${compareRef}...HEAD`], cwd);
|
|
179
|
+
const statResult = await executeGitCommand(['diff', `${compareRef}...HEAD`, '--stat'], cwd);
|
|
180
|
+
const filesChanged = statResult.exitCode === 0 ? statResult.stdout.trim() : '';
|
|
181
|
+
const diff = truncateDiff(diffResult.exitCode === 0 ? diffResult.stdout : '');
|
|
182
|
+
const prompt = loadSkillPrompt('pr-description', { baseBranch, commits, filesChanged, diff }, cwd)
|
|
183
|
+
?? `You are generating a pull request title and description.\n\nCOMMITS (${baseBranch}..HEAD):\n${commits}\n\nFILES CHANGED:\n${filesChanged}\n\nDIFF:\n${diff}\n\nGenerate PR title (imperative, <70 chars) then body with ## Summary (1-3 bullets). No emojis. Respond with ONLY the title and description.`;
|
|
184
|
+
const result = await spawnHaikuWithPrompt(prompt, PR_DESCRIPTION_SYSTEM_PROMPT, cwd);
|
|
185
|
+
if (result.exitCode !== 0 || !result.stdout.trim()) {
|
|
186
|
+
console.error('[WebSocketImproviseHandler] Claude PR description error:', result.stderr || 'No output');
|
|
187
|
+
return gitFail('Failed to generate PR description');
|
|
188
|
+
}
|
|
189
|
+
const output = stripCoauthorLines(result.stdout.trim());
|
|
190
|
+
const lines = output.split('\n');
|
|
191
|
+
return gitOk({ title: lines[0].trim(), body: lines.slice(1).join('\n').trim() });
|
|
192
|
+
}
|