@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,68 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
export function executeGitCommand(args, workingDir, options = {}) {
|
|
5
|
+
return new Promise((resolve) => {
|
|
6
|
+
const git = spawn('git', args, {
|
|
7
|
+
cwd: workingDir,
|
|
8
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
9
|
+
env: options.env ? { ...process.env, ...options.env } : undefined,
|
|
10
|
+
});
|
|
11
|
+
let stdout = '';
|
|
12
|
+
let stderr = '';
|
|
13
|
+
let timedOut = false;
|
|
14
|
+
let overflowed = false;
|
|
15
|
+
const timer = options.timeoutMs
|
|
16
|
+
? setTimeout(() => { timedOut = true; git.kill(); }, options.timeoutMs)
|
|
17
|
+
: null;
|
|
18
|
+
git.stdout?.on('data', (data) => {
|
|
19
|
+
stdout += data.toString();
|
|
20
|
+
if (options.maxOutputBytes && stdout.length > options.maxOutputBytes && !overflowed) {
|
|
21
|
+
overflowed = true;
|
|
22
|
+
git.kill();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
git.stderr?.on('data', (data) => {
|
|
26
|
+
stderr += data.toString();
|
|
27
|
+
});
|
|
28
|
+
git.on('close', (code) => {
|
|
29
|
+
if (timer)
|
|
30
|
+
clearTimeout(timer);
|
|
31
|
+
if (timedOut) {
|
|
32
|
+
resolve({ stdout, stderr: `git ${args[0]} timed out after ${options.timeoutMs}ms`, exitCode: 1 });
|
|
33
|
+
}
|
|
34
|
+
else if (overflowed) {
|
|
35
|
+
resolve({ stdout, stderr: `git ${args[0]} output exceeded ${options.maxOutputBytes} bytes`, exitCode: 1 });
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
resolve({ stdout, stderr, exitCode: code ?? 1 });
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
git.on('error', (err) => {
|
|
42
|
+
if (timer)
|
|
43
|
+
clearTimeout(timer);
|
|
44
|
+
resolve({ stdout: '', stderr: err.message, exitCode: 1 });
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
export function spawnCheck(bin, args) {
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
|
+
const proc = spawn(bin, args, { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
51
|
+
proc.on('close', (code) => resolve(code === 0));
|
|
52
|
+
proc.on('error', () => resolve(false));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
export function spawnWithOutput(bin, args, cwd) {
|
|
56
|
+
return new Promise((resolve) => {
|
|
57
|
+
const proc = spawn(bin, args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
58
|
+
let stdout = '';
|
|
59
|
+
let stderr = '';
|
|
60
|
+
proc.stdout?.on('data', (d) => { stdout += d.toString(); });
|
|
61
|
+
proc.stderr?.on('data', (d) => { stderr += d.toString(); });
|
|
62
|
+
proc.on('close', (code) => resolve({ stdout, stderr, exitCode: code ?? 1 }));
|
|
63
|
+
proc.on('error', (err) => resolve({ stdout: '', stderr: err.message, exitCode: 1 }));
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
export function gitErrorText(result, fallback) {
|
|
67
|
+
return result.stderr || result.stdout || fallback;
|
|
68
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { loadSkillPrompt } from '../plan/agent-loader.js';
|
|
4
|
+
import { executeGitCommand } from './command.js';
|
|
5
|
+
import { classifyHaikuFailure, logCommitMessageEvent, spawnHaikuWithPrompt, truncateDiff } from './haiku.js';
|
|
6
|
+
import { extractCommitMessage, parseGitStatus } from './parsers.js';
|
|
7
|
+
import { gitFail, gitOk } from './types.js';
|
|
8
|
+
const haikuSucceeded = (r) => r.exitCode === 0 && r.stdout.trim().length > 0;
|
|
9
|
+
const RETRY_TERMINAL_REASONS = new Set(['binary_missing', 'auth', 'rate_limit']);
|
|
10
|
+
export const COMMIT_MESSAGE_SYSTEM_PROMPT = 'You are a commit message assistant. Respond with only the commit message — no preamble, no explanation, and never any Co-Authored-By or attribution lines.';
|
|
11
|
+
export function buildCommitMessagePrompt(workingDir, inputs) {
|
|
12
|
+
return loadSkillPrompt('commit-message', { recentCommits: inputs.recentCommits, stagedFiles: inputs.stagedFiles, diff: inputs.diff }, workingDir)
|
|
13
|
+
?? `You are generating a git commit message for the following staged changes.\n\nRECENT COMMIT MESSAGES (for style reference):\n${inputs.recentCommits}\n\nSTAGED FILES:\n${inputs.stagedFiles}\n\nDIFF OF STAGED CHANGES:\n${inputs.diff}\n\nGenerate a commit message: imperative mood, max 72 characters, focus on "why". Respond with ONLY the commit message. Never add Co-Authored-By or attribution lines.`;
|
|
14
|
+
}
|
|
15
|
+
export function classifyCommitMessageFailure(result) {
|
|
16
|
+
if (haikuSucceeded(result)) {
|
|
17
|
+
return { reason: 'empty_extraction', userMessage: 'Claude responded but no commit message could be extracted. Try again.' };
|
|
18
|
+
}
|
|
19
|
+
return classifyHaikuFailure(result);
|
|
20
|
+
}
|
|
21
|
+
export async function runHaikuForCommitMessage(prompt, systemPrompt, workingDir, meta) {
|
|
22
|
+
let result = await spawnHaikuWithPrompt(prompt, systemPrompt, workingDir);
|
|
23
|
+
let message = haikuSucceeded(result) ? extractCommitMessage(result.stdout) : '';
|
|
24
|
+
if (message)
|
|
25
|
+
return { result, attempts: 1, message };
|
|
26
|
+
const first = classifyCommitMessageFailure(result);
|
|
27
|
+
if (RETRY_TERMINAL_REASONS.has(first.reason))
|
|
28
|
+
return { result, attempts: 1, message: '' };
|
|
29
|
+
logCommitMessageEvent(workingDir, {
|
|
30
|
+
tabId: meta.tabId, attempt: 1, success: false, reason: first.reason,
|
|
31
|
+
exitCode: result.exitCode, timedOut: result.timedOut,
|
|
32
|
+
stderrTail: (result.stderr || '').trim().slice(-500),
|
|
33
|
+
stdoutTail: first.reason === 'empty_extraction' ? result.stdout.trim().slice(-300) : undefined,
|
|
34
|
+
latencyMs: Date.now() - meta.startedAt, diffBytes: meta.diffBytes, willRetry: true,
|
|
35
|
+
});
|
|
36
|
+
await new Promise(r => setTimeout(r, 500));
|
|
37
|
+
result = await spawnHaikuWithPrompt(prompt, systemPrompt, workingDir);
|
|
38
|
+
message = haikuSucceeded(result) ? extractCommitMessage(result.stdout) : '';
|
|
39
|
+
return { result, attempts: 2, message };
|
|
40
|
+
}
|
|
41
|
+
export async function generateStagedCommitMessage(args) {
|
|
42
|
+
const { cwd, tabId, startedAt, autoCommit } = args;
|
|
43
|
+
const statusResult = await executeGitCommand(['status', '--porcelain=v1'], cwd);
|
|
44
|
+
const { staged } = parseGitStatus(statusResult.stdout);
|
|
45
|
+
if (staged.length === 0) {
|
|
46
|
+
return gitFail('No staged changes to commit');
|
|
47
|
+
}
|
|
48
|
+
const diffResult = await executeGitCommand(['diff', '--cached'], cwd);
|
|
49
|
+
const logResult = await executeGitCommand(['log', '--oneline', '-5'], cwd);
|
|
50
|
+
const recentCommits = logResult.stdout.trim() || 'No recent commits';
|
|
51
|
+
const stagedFiles = staged.map(f => `${f.status} ${f.path}`).join('\n');
|
|
52
|
+
const diff = truncateDiff(diffResult.stdout);
|
|
53
|
+
const diffBytes = diffResult.stdout.length;
|
|
54
|
+
const prompt = buildCommitMessagePrompt(cwd, { recentCommits, stagedFiles, diff });
|
|
55
|
+
const { result, attempts, message: commitMessage } = await runHaikuForCommitMessage(prompt, COMMIT_MESSAGE_SYSTEM_PROMPT, cwd, { tabId, startedAt, diffBytes });
|
|
56
|
+
if (!commitMessage) {
|
|
57
|
+
const failure = classifyCommitMessageFailure(result);
|
|
58
|
+
logCommitMessageEvent(cwd, {
|
|
59
|
+
tabId, attempt: attempts, success: false, reason: failure.reason,
|
|
60
|
+
exitCode: result.exitCode, timedOut: result.timedOut,
|
|
61
|
+
stderrTail: (result.stderr || '').trim().slice(-500),
|
|
62
|
+
stdoutTail: failure.reason === 'empty_extraction' ? result.stdout.trim().slice(-300) : undefined,
|
|
63
|
+
latencyMs: Date.now() - startedAt, diffBytes,
|
|
64
|
+
});
|
|
65
|
+
console.error(`[git] commit-message failed (${failure.reason}):`, result.stderr || result.stdout.trim().slice(-300) || 'no output');
|
|
66
|
+
return gitFail(failure.userMessage);
|
|
67
|
+
}
|
|
68
|
+
logCommitMessageEvent(cwd, {
|
|
69
|
+
tabId, attempt: attempts, success: true,
|
|
70
|
+
latencyMs: Date.now() - startedAt, diffBytes, autoCommit,
|
|
71
|
+
messageLength: commitMessage.length,
|
|
72
|
+
});
|
|
73
|
+
return gitOk(commitMessage);
|
|
74
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { executeGitCommand } from './command.js';
|
|
6
|
+
import { parseCommitFiles, stripCoauthorLines } from './parsers.js';
|
|
7
|
+
import { gitFail, gitOk } from './types.js';
|
|
8
|
+
export async function readFileDiff({ cwd, path, staged }) {
|
|
9
|
+
const originalResult = await executeGitCommand(['show', `HEAD:${path}`], cwd);
|
|
10
|
+
const original = originalResult.exitCode === 0 ? originalResult.stdout : '';
|
|
11
|
+
let modified;
|
|
12
|
+
if (staged) {
|
|
13
|
+
const indexResult = await executeGitCommand(['show', `:${path}`], cwd);
|
|
14
|
+
modified = indexResult.exitCode === 0 ? indexResult.stdout : '';
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
const fullPath = join(cwd, path);
|
|
18
|
+
try {
|
|
19
|
+
modified = readFileSync(fullPath, 'utf-8');
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
modified = '';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return { original, modified };
|
|
26
|
+
}
|
|
27
|
+
async function readCommitFiles(hash, cwd) {
|
|
28
|
+
const isRoot = (await executeGitCommand(['rev-parse', `${hash}^`], cwd)).exitCode !== 0;
|
|
29
|
+
const extra = isRoot ? ['--root'] : [];
|
|
30
|
+
const numstatResult = await executeGitCommand(['diff-tree', '-r', '--numstat', '--no-commit-id', ...extra, hash], cwd);
|
|
31
|
+
const statusResult = await executeGitCommand(['diff-tree', '-r', '--name-status', '--no-commit-id', ...extra, hash], cwd);
|
|
32
|
+
return parseCommitFiles(numstatResult.stdout, statusResult.stdout);
|
|
33
|
+
}
|
|
34
|
+
export async function readCommitDetail({ cwd, hash }) {
|
|
35
|
+
const metaResult = await executeGitCommand([
|
|
36
|
+
'show', '-s', '--format=%H%x00%h%x00%s%x00%b%x00%an%x00%aI', hash
|
|
37
|
+
], cwd);
|
|
38
|
+
if (metaResult.exitCode !== 0) {
|
|
39
|
+
return gitFail(metaResult.stderr || 'Failed to get commit details');
|
|
40
|
+
}
|
|
41
|
+
const parts = metaResult.stdout.trim().split('\x00');
|
|
42
|
+
const subject = stripCoauthorLines(parts[2] || '') || parts[2] || '';
|
|
43
|
+
const files = await readCommitFiles(hash, cwd);
|
|
44
|
+
return gitOk({
|
|
45
|
+
hash: parts[0], shortHash: parts[1], subject,
|
|
46
|
+
body: stripCoauthorLines(parts[3] || '').trim(),
|
|
47
|
+
author: parts[4], date: parts[5], files,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export async function readCommitFileDiff({ cwd, hash, path }) {
|
|
51
|
+
const modifiedResult = await executeGitCommand(['show', `${hash}:${path}`], cwd);
|
|
52
|
+
const modified = modifiedResult.exitCode === 0 ? modifiedResult.stdout : '';
|
|
53
|
+
const originalResult = await executeGitCommand(['show', `${hash}^:${path}`], cwd);
|
|
54
|
+
const original = originalResult.exitCode === 0 ? originalResult.stdout : '';
|
|
55
|
+
return { original, modified };
|
|
56
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { appendFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { resolveClaudeCommand } from '../../engines/claude/claude-command.js';
|
|
7
|
+
import { spacePath } from '../space-layout.js';
|
|
8
|
+
export function truncateDiff(diff, maxLength = 8000) {
|
|
9
|
+
if (diff.length <= maxLength)
|
|
10
|
+
return diff;
|
|
11
|
+
const headSize = Math.floor(maxLength / 2);
|
|
12
|
+
const tailSize = Math.floor(maxLength * 0.44);
|
|
13
|
+
return `${diff.slice(0, headSize)}\n\n... [diff truncated] ...\n\n${diff.slice(-tailSize)}`;
|
|
14
|
+
}
|
|
15
|
+
export function spawnHaikuWithPrompt(prompt, systemPrompt, workingDir, timeoutMs = 90000) {
|
|
16
|
+
return new Promise((resolve) => {
|
|
17
|
+
const args = ['--print', '--model', 'haiku', '--system-prompt', systemPrompt];
|
|
18
|
+
const proc = spawn(resolveClaudeCommand(), args, { cwd: workingDir, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
19
|
+
let stdout = '';
|
|
20
|
+
let stderr = '';
|
|
21
|
+
let timedOut = false;
|
|
22
|
+
proc.stdout?.on('data', (d) => { stdout += d.toString(); });
|
|
23
|
+
proc.stderr?.on('data', (d) => { stderr += d.toString(); });
|
|
24
|
+
const timer = setTimeout(() => { timedOut = true; proc.kill(); }, timeoutMs);
|
|
25
|
+
proc.on('close', (code) => {
|
|
26
|
+
clearTimeout(timer);
|
|
27
|
+
resolve({ stdout, stderr, exitCode: code ?? 1, timedOut });
|
|
28
|
+
});
|
|
29
|
+
proc.on('error', (err) => {
|
|
30
|
+
clearTimeout(timer);
|
|
31
|
+
const enoent = err.code === 'ENOENT';
|
|
32
|
+
resolve({ stdout: '', stderr: enoent ? `claude: command not found (${err.message})` : err.message, exitCode: 1, timedOut: false });
|
|
33
|
+
});
|
|
34
|
+
proc.stdin?.on('error', () => { });
|
|
35
|
+
proc.stdin?.write(prompt);
|
|
36
|
+
proc.stdin?.end();
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
export function classifyHaikuFailure(result) {
|
|
40
|
+
const stderr = (result.stderr || '').toLowerCase();
|
|
41
|
+
const stdout = (result.stdout || '').toLowerCase();
|
|
42
|
+
const combined = `${stderr} ${stdout}`;
|
|
43
|
+
if (result.timedOut) {
|
|
44
|
+
return { reason: 'timeout', userMessage: 'Claude took too long to respond. Try again, or stage fewer files at once.' };
|
|
45
|
+
}
|
|
46
|
+
if (combined.includes('command not found') || combined.includes('enoent')) {
|
|
47
|
+
return { reason: 'binary_missing', userMessage: 'Claude Code was not found on the PATH minion started with or in its install locations. Install it (https://code.claude.com/docs/en/setup) and try again, or set CLAUDE_COMMAND to its full path and restart minion.' };
|
|
48
|
+
}
|
|
49
|
+
if (/not\s+(logged|signed)\s*in|not\s+authenticated|please\s+(log|sign)\s*in|api\s*key|unauthor/.test(combined)) {
|
|
50
|
+
return { reason: 'auth', userMessage: 'Claude CLI is not authenticated. Run `claude /login` in a terminal, then try again.' };
|
|
51
|
+
}
|
|
52
|
+
if (/rate\s*limit|usage\s*limit|429|too\s+many\s+requests/.test(combined)) {
|
|
53
|
+
return { reason: 'rate_limit', userMessage: 'Claude rate limit reached. Wait a minute and try again.' };
|
|
54
|
+
}
|
|
55
|
+
if (/overloaded|529|service\s+unavailable|503/.test(combined)) {
|
|
56
|
+
return { reason: 'overloaded', userMessage: "Claude is temporarily overloaded. Try again in a few seconds." };
|
|
57
|
+
}
|
|
58
|
+
if (result.exitCode === 0 && !result.stdout.trim()) {
|
|
59
|
+
return { reason: 'empty_output', userMessage: 'Claude returned an empty response. Try again.' };
|
|
60
|
+
}
|
|
61
|
+
const tail = (result.stderr || result.stdout || '').trim().slice(-200);
|
|
62
|
+
return { reason: 'unknown', userMessage: `Failed to generate commit message${tail ? `: ${tail}` : ''}` };
|
|
63
|
+
}
|
|
64
|
+
export function logCommitMessageEvent(workingDir, entry) {
|
|
65
|
+
try {
|
|
66
|
+
const logDir = spacePath(workingDir, 'logs');
|
|
67
|
+
if (!existsSync(logDir))
|
|
68
|
+
mkdirSync(logDir, { recursive: true });
|
|
69
|
+
const logFile = join(logDir, 'commit-message.jsonl');
|
|
70
|
+
const line = `${JSON.stringify({ timestamp: new Date().toISOString(), ...entry })}\n`;
|
|
71
|
+
appendFileSync(logFile, line, 'utf-8');
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
console.error('[git] failed to write commit-message log:', err);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { existsSync, realpathSync, watch } from 'node:fs';
|
|
4
|
+
import { basename, join, resolve } from 'node:path';
|
|
5
|
+
import { executeGitCommand } from './command.js';
|
|
6
|
+
import { listWorktrees } from './worktree-ops.js';
|
|
7
|
+
const DEBOUNCE_MS = 300;
|
|
8
|
+
const GIT_DIR_SPEC = {
|
|
9
|
+
recursive: false,
|
|
10
|
+
isRelevant: (filename) => filename === null || filename === 'HEAD' || filename === 'worktrees',
|
|
11
|
+
};
|
|
12
|
+
const WORKTREES_DIR_SPEC = {
|
|
13
|
+
recursive: true,
|
|
14
|
+
isRelevant: (filename) => filename === null || basename(filename) === 'HEAD',
|
|
15
|
+
};
|
|
16
|
+
function canonical(path) {
|
|
17
|
+
try {
|
|
18
|
+
return realpathSync(path);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return path;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function addTarget(targets, path) {
|
|
25
|
+
const key = canonical(path);
|
|
26
|
+
if (!targets.has(key))
|
|
27
|
+
targets.set(key, path);
|
|
28
|
+
}
|
|
29
|
+
async function resolveRepoDirs(dir) {
|
|
30
|
+
const result = await executeGitCommand(['rev-parse', '--path-format=absolute', '--git-dir', '--git-common-dir'], dir);
|
|
31
|
+
if (result.exitCode !== 0)
|
|
32
|
+
return null;
|
|
33
|
+
const [gitDir, commonDir] = result.stdout.split('\n').map((line) => line.trim());
|
|
34
|
+
if (!gitDir || !commonDir)
|
|
35
|
+
return null;
|
|
36
|
+
return { gitDir: canonical(resolve(dir, gitDir)), commonDir: canonical(resolve(dir, commonDir)) };
|
|
37
|
+
}
|
|
38
|
+
async function listWorktreePaths(dir) {
|
|
39
|
+
const listed = await listWorktrees({ cwd: dir });
|
|
40
|
+
if (!listed.ok)
|
|
41
|
+
return [];
|
|
42
|
+
return listed.value.filter((wt) => !wt.isBare && !wt.prunable).map((wt) => wt.path);
|
|
43
|
+
}
|
|
44
|
+
async function readBranch(dir) {
|
|
45
|
+
const result = await executeGitCommand(['rev-parse', '--abbrev-ref', 'HEAD'], dir);
|
|
46
|
+
if (result.exitCode !== 0)
|
|
47
|
+
return null;
|
|
48
|
+
return result.stdout.trim() || null;
|
|
49
|
+
}
|
|
50
|
+
export class GitHeadWatcher {
|
|
51
|
+
workingDir;
|
|
52
|
+
hooks;
|
|
53
|
+
watchers = new Map();
|
|
54
|
+
debounceTimer = null;
|
|
55
|
+
lastKnownBranch = null;
|
|
56
|
+
lastKnownWorktreeBranches = new Map();
|
|
57
|
+
chain = Promise.resolve();
|
|
58
|
+
pendingPass = null;
|
|
59
|
+
started = false;
|
|
60
|
+
constructor(workingDir, hooks) {
|
|
61
|
+
this.workingDir = workingDir;
|
|
62
|
+
this.hooks = hooks;
|
|
63
|
+
}
|
|
64
|
+
start() {
|
|
65
|
+
if (this.started)
|
|
66
|
+
return;
|
|
67
|
+
this.started = true;
|
|
68
|
+
this.retrack();
|
|
69
|
+
}
|
|
70
|
+
startWorktreeWatcher() {
|
|
71
|
+
this.retrack();
|
|
72
|
+
}
|
|
73
|
+
retrack() {
|
|
74
|
+
void this.checkNow();
|
|
75
|
+
}
|
|
76
|
+
checkNow() {
|
|
77
|
+
if (!this.pendingPass) {
|
|
78
|
+
this.pendingPass = this.enqueue(() => {
|
|
79
|
+
this.pendingPass = null;
|
|
80
|
+
return this.runPass();
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return this.pendingPass;
|
|
84
|
+
}
|
|
85
|
+
stop() {
|
|
86
|
+
for (const watcher of this.watchers.values())
|
|
87
|
+
watcher.close();
|
|
88
|
+
this.watchers.clear();
|
|
89
|
+
if (this.debounceTimer) {
|
|
90
|
+
clearTimeout(this.debounceTimer);
|
|
91
|
+
this.debounceTimer = null;
|
|
92
|
+
}
|
|
93
|
+
this.started = false;
|
|
94
|
+
}
|
|
95
|
+
enqueue(task) {
|
|
96
|
+
const run = this.chain.then(task);
|
|
97
|
+
this.chain = run.catch(() => undefined);
|
|
98
|
+
return run;
|
|
99
|
+
}
|
|
100
|
+
async runPass() {
|
|
101
|
+
if (!this.started)
|
|
102
|
+
return;
|
|
103
|
+
try {
|
|
104
|
+
const plan = await this.scan();
|
|
105
|
+
await this.checkMainBranch();
|
|
106
|
+
await this.checkWorktreeBranches(plan.targets);
|
|
107
|
+
this.syncWatchers(plan);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async scan() {
|
|
113
|
+
const plan = { gitDirs: new Set(), worktreesDirs: new Set(), targets: new Map() };
|
|
114
|
+
const repoDirs = new Map();
|
|
115
|
+
for (const dir of this.dirsInPlay()) {
|
|
116
|
+
const repo = await resolveRepoDirs(dir);
|
|
117
|
+
if (!repo)
|
|
118
|
+
continue;
|
|
119
|
+
plan.gitDirs.add(repo.gitDir);
|
|
120
|
+
plan.worktreesDirs.add(join(repo.commonDir, 'worktrees'));
|
|
121
|
+
if (!repoDirs.has(repo.commonDir))
|
|
122
|
+
repoDirs.set(repo.commonDir, dir);
|
|
123
|
+
addTarget(plan.targets, dir);
|
|
124
|
+
}
|
|
125
|
+
for (const dir of repoDirs.values()) {
|
|
126
|
+
for (const path of await listWorktreePaths(dir))
|
|
127
|
+
addTarget(plan.targets, path);
|
|
128
|
+
}
|
|
129
|
+
plan.targets.delete(canonical(this.workingDir));
|
|
130
|
+
return plan;
|
|
131
|
+
}
|
|
132
|
+
dirsInPlay() {
|
|
133
|
+
const dirs = new Set([this.workingDir]);
|
|
134
|
+
for (const [, dir] of this.hooks.trackedWorktrees())
|
|
135
|
+
dirs.add(dir);
|
|
136
|
+
for (const dir of this.hooks.trackedRepoRoots())
|
|
137
|
+
dirs.add(dir);
|
|
138
|
+
return [...dirs];
|
|
139
|
+
}
|
|
140
|
+
async checkMainBranch() {
|
|
141
|
+
const branch = await readBranch(this.workingDir);
|
|
142
|
+
if (!branch)
|
|
143
|
+
return;
|
|
144
|
+
const last = this.lastKnownBranch;
|
|
145
|
+
this.lastKnownBranch = branch;
|
|
146
|
+
if (last === null || last === branch)
|
|
147
|
+
return;
|
|
148
|
+
this.hooks.onMainBranchChanged(this.workingDir, branch);
|
|
149
|
+
}
|
|
150
|
+
async checkWorktreeBranches(targets) {
|
|
151
|
+
for (const [key, path] of targets) {
|
|
152
|
+
try {
|
|
153
|
+
await this.checkWorktreeBranch(key, path);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
for (const key of this.lastKnownWorktreeBranches.keys()) {
|
|
159
|
+
if (!targets.has(key))
|
|
160
|
+
this.lastKnownWorktreeBranches.delete(key);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
async checkWorktreeBranch(key, path) {
|
|
164
|
+
const branch = await readBranch(path);
|
|
165
|
+
if (!branch || branch === 'HEAD')
|
|
166
|
+
return;
|
|
167
|
+
const last = this.lastKnownWorktreeBranches.get(key);
|
|
168
|
+
this.lastKnownWorktreeBranches.set(key, branch);
|
|
169
|
+
if (last === undefined || last === branch)
|
|
170
|
+
return;
|
|
171
|
+
this.hooks.onWorktreeBranchChanged(this.labelFor(key), path, branch);
|
|
172
|
+
}
|
|
173
|
+
labelFor(key) {
|
|
174
|
+
for (const [label, dir] of this.hooks.trackedWorktrees()) {
|
|
175
|
+
if (canonical(dir) === key)
|
|
176
|
+
return label;
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
syncWatchers(plan) {
|
|
181
|
+
if (!this.started)
|
|
182
|
+
return;
|
|
183
|
+
const wanted = new Map();
|
|
184
|
+
for (const gitDir of plan.gitDirs)
|
|
185
|
+
wanted.set(gitDir, GIT_DIR_SPEC);
|
|
186
|
+
for (const dir of plan.worktreesDirs) {
|
|
187
|
+
if (existsSync(dir))
|
|
188
|
+
wanted.set(dir, WORKTREES_DIR_SPEC);
|
|
189
|
+
}
|
|
190
|
+
for (const path of this.watchers.keys()) {
|
|
191
|
+
if (!wanted.has(path))
|
|
192
|
+
this.dropWatcher(path);
|
|
193
|
+
}
|
|
194
|
+
for (const [path, spec] of wanted) {
|
|
195
|
+
if (!this.watchers.has(path))
|
|
196
|
+
this.addWatcher(path, spec);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
addWatcher(path, spec) {
|
|
200
|
+
try {
|
|
201
|
+
const watcher = watch(path, { recursive: spec.recursive }, (_event, filename) => {
|
|
202
|
+
if (spec.isRelevant(filename))
|
|
203
|
+
this.debounce();
|
|
204
|
+
});
|
|
205
|
+
watcher.on('error', () => this.dropWatcher(path));
|
|
206
|
+
this.watchers.set(path, watcher);
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
dropWatcher(path) {
|
|
212
|
+
const watcher = this.watchers.get(path);
|
|
213
|
+
if (!watcher)
|
|
214
|
+
return;
|
|
215
|
+
watcher.close();
|
|
216
|
+
this.watchers.delete(path);
|
|
217
|
+
}
|
|
218
|
+
debounce() {
|
|
219
|
+
if (this.debounceTimer)
|
|
220
|
+
clearTimeout(this.debounceTimer);
|
|
221
|
+
this.debounceTimer = setTimeout(() => {
|
|
222
|
+
this.debounceTimer = null;
|
|
223
|
+
void this.checkNow();
|
|
224
|
+
}, DEBOUNCE_MS);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
export * from './branch-ops.js';
|
|
4
|
+
export * from './command.js';
|
|
5
|
+
export * from './commit-message.js';
|
|
6
|
+
export * from './diff-ops.js';
|
|
7
|
+
export * from './haiku.js';
|
|
8
|
+
export { GitHeadWatcher } from './head-watcher.js';
|
|
9
|
+
export * from './log-ops.js';
|
|
10
|
+
export * from './merge-ops.js';
|
|
11
|
+
export * from './parsers.js';
|
|
12
|
+
export * from './remote-ops.js';
|
|
13
|
+
export * from './status-ops.js';
|
|
14
|
+
export * from './suggestion-ops.js';
|
|
15
|
+
export * from './tag-ops.js';
|
|
16
|
+
export * from './types.js';
|
|
17
|
+
export * from './worktree-ops.js';
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
5
|
+
import { executeGitCommand, gitErrorText } from './command.js';
|
|
6
|
+
import { buildGitLogArgs, parseLogEntries, parseWorktreePorcelain } from './parsers.js';
|
|
7
|
+
import { gitFail, gitOk } from './types.js';
|
|
8
|
+
import { isInsideGitRepo } from './worktree-ops.js';
|
|
9
|
+
export async function readLog({ cwd, limit, skip, search }) {
|
|
10
|
+
const args = buildGitLogArgs({ limit, skip, search });
|
|
11
|
+
const result = await executeGitCommand(args, cwd);
|
|
12
|
+
if (result.exitCode !== 0) {
|
|
13
|
+
return gitFail(gitErrorText(result, 'Failed to get log'));
|
|
14
|
+
}
|
|
15
|
+
const allEntries = parseLogEntries(result.stdout);
|
|
16
|
+
const hasMore = allEntries.length > limit;
|
|
17
|
+
return gitOk({ entries: hasMore ? allEntries.slice(0, limit) : allEntries, hasMore });
|
|
18
|
+
}
|
|
19
|
+
const SKIP_DIRS = ['node_modules', 'vendor', '.git'];
|
|
20
|
+
function shouldSkipDir(name) {
|
|
21
|
+
return name.startsWith('.') || SKIP_DIRS.includes(name);
|
|
22
|
+
}
|
|
23
|
+
async function getRepoBranch(repoPath) {
|
|
24
|
+
const result = await executeGitCommand(['rev-parse', '--abbrev-ref', 'HEAD'], repoPath);
|
|
25
|
+
return result.exitCode === 0 ? result.stdout.trim() : undefined;
|
|
26
|
+
}
|
|
27
|
+
async function getRepoWorktrees(repoPath) {
|
|
28
|
+
const result = await executeGitCommand(['worktree', 'list', '--porcelain'], repoPath);
|
|
29
|
+
return result.exitCode === 0 ? parseWorktreePorcelain(result.stdout) : undefined;
|
|
30
|
+
}
|
|
31
|
+
async function scanForGitRepos(dir, depth, maxDepth, repos) {
|
|
32
|
+
if (depth > maxDepth)
|
|
33
|
+
return;
|
|
34
|
+
let entries;
|
|
35
|
+
try {
|
|
36
|
+
entries = readdirSync(dir);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
for (const name of entries) {
|
|
42
|
+
if (shouldSkipDir(name))
|
|
43
|
+
continue;
|
|
44
|
+
const fullPath = join(dir, name);
|
|
45
|
+
const gitPath = join(fullPath, '.git');
|
|
46
|
+
if (existsSync(gitPath)) {
|
|
47
|
+
repos.push({ path: fullPath, name, branch: await getRepoBranch(fullPath), worktrees: await getRepoWorktrees(fullPath) });
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
await scanForGitRepos(fullPath, depth + 1, maxDepth, repos);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export async function discoverRepos({ cwd }) {
|
|
55
|
+
const repos = [];
|
|
56
|
+
const rootIsGitRepo = existsSync(join(cwd, '.git'));
|
|
57
|
+
if (rootIsGitRepo) {
|
|
58
|
+
repos.push({
|
|
59
|
+
path: cwd,
|
|
60
|
+
name: cwd.split('/').pop() || cwd,
|
|
61
|
+
branch: await getRepoBranch(cwd),
|
|
62
|
+
worktrees: await getRepoWorktrees(cwd),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
await scanForGitRepos(cwd, 1, 3, repos);
|
|
67
|
+
}
|
|
68
|
+
return { repos, rootIsGitRepo };
|
|
69
|
+
}
|
|
70
|
+
export async function isValidWorktreePath(targetPath, cwd) {
|
|
71
|
+
const result = await executeGitCommand(['worktree', 'list', '--porcelain'], cwd);
|
|
72
|
+
if (result.exitCode !== 0)
|
|
73
|
+
return false;
|
|
74
|
+
const resolvedTarget = resolve(targetPath);
|
|
75
|
+
for (const line of result.stdout.split('\n')) {
|
|
76
|
+
if (line.startsWith('worktree ')) {
|
|
77
|
+
const wtPath = resolve(line.slice(9).trim());
|
|
78
|
+
if (wtPath === resolvedTarget)
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
export async function resolveGitDirectory({ cwd, directory, allowCustom }) {
|
|
85
|
+
const resolvedDir = resolve(directory);
|
|
86
|
+
const resolvedWorkingDir = resolve(cwd);
|
|
87
|
+
if (resolvedDir !== resolvedWorkingDir) {
|
|
88
|
+
const { repos } = await discoverRepos({ cwd });
|
|
89
|
+
const isDiscovered = repos.some((repo) => resolve(repo.path) === resolvedDir || (repo.worktrees ?? []).some((wt) => resolve(wt.path) === resolvedDir));
|
|
90
|
+
if (!isDiscovered && !(allowCustom && (await isInsideGitRepo(resolvedDir)))) {
|
|
91
|
+
return gitFail('Access denied: path outside project directory');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return gitOk({ directory: resolvedDir, isValid: existsSync(join(resolvedDir, '.git')) });
|
|
95
|
+
}
|
|
96
|
+
export function isGitRepoRoot(dir) {
|
|
97
|
+
return existsSync(join(dir, '.git'));
|
|
98
|
+
}
|