@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,43 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
5
|
+
export function replaceYamlField(yaml, field, value) {
|
|
6
|
+
const regex = new RegExp(`^(${field}:\\s*).+$`, 'm');
|
|
7
|
+
if (regex.test(yaml)) {
|
|
8
|
+
return yaml.replace(regex, `$1${value}`);
|
|
9
|
+
}
|
|
10
|
+
return `${yaml}\n${field}: ${value}`;
|
|
11
|
+
}
|
|
12
|
+
export function replaceFrontMatterField(content, field, value) {
|
|
13
|
+
const fmMatch = content.match(/^(---\n)([\s\S]*?)(\n---)/);
|
|
14
|
+
if (!fmMatch)
|
|
15
|
+
return content;
|
|
16
|
+
const yaml = replaceYamlField(fmMatch[2], field, value);
|
|
17
|
+
return `${fmMatch[1]}${yaml}${fmMatch[3]}${content.slice(fmMatch[0].length)}`;
|
|
18
|
+
}
|
|
19
|
+
export function setFrontMatterField(filePath, field, value) {
|
|
20
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
21
|
+
const updated = replaceFrontMatterField(content, field, value);
|
|
22
|
+
writeFileSync(filePath, updated, 'utf-8');
|
|
23
|
+
}
|
|
24
|
+
export async function setFrontMatterFieldAsync(filePath, field, value) {
|
|
25
|
+
const content = await readFile(filePath, 'utf-8');
|
|
26
|
+
const updated = replaceFrontMatterField(content, field, value);
|
|
27
|
+
await writeFile(filePath, updated, 'utf-8');
|
|
28
|
+
}
|
|
29
|
+
export function checkAllAcceptanceCriteria(content) {
|
|
30
|
+
const sectionStart = content.indexOf('## Acceptance Criteria');
|
|
31
|
+
if (sectionStart === -1)
|
|
32
|
+
return content;
|
|
33
|
+
const afterHeader = content.indexOf('\n', sectionStart);
|
|
34
|
+
if (afterHeader === -1)
|
|
35
|
+
return content;
|
|
36
|
+
const nextSection = content.slice(afterHeader).search(/\n## /);
|
|
37
|
+
const sectionEnd = nextSection !== -1 ? afterHeader + nextSection : content.length;
|
|
38
|
+
const before = content.slice(0, afterHeader);
|
|
39
|
+
const section = content.slice(afterHeader, sectionEnd);
|
|
40
|
+
const after = content.slice(sectionEnd);
|
|
41
|
+
const updatedSection = section.replace(/^([-*]\s+)\[ \]/gm, '$1[x]');
|
|
42
|
+
return before + updatedSection + after;
|
|
43
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
export function resolveIsCodeTask(issue) {
|
|
4
|
+
if (issue.outputType === 'code')
|
|
5
|
+
return true;
|
|
6
|
+
if (issue.outputType === 'document')
|
|
7
|
+
return false;
|
|
8
|
+
const codeFiles = issue.filesToModify.filter(f => !f.match(/^Output:/i));
|
|
9
|
+
return codeFiles.length > 0;
|
|
10
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { normalizeSessionHistory, resolveHistoryPaths } from '../../cli/improvisation-history-store.js';
|
|
6
|
+
import { readLatestQualityDeltas, summarizeQualityDelta } from './quality-delta.js';
|
|
7
|
+
import { MAX_REVIEW_ATTEMPTS } from './types.js';
|
|
8
|
+
export function historyReaderFor(workingDir) {
|
|
9
|
+
return (sessionId) => {
|
|
10
|
+
const { historyPath } = resolveHistoryPaths(workingDir, sessionId);
|
|
11
|
+
try {
|
|
12
|
+
return normalizeSessionHistory(JSON.parse(readFileSync(historyPath, 'utf-8')), sessionId);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const sessionFactsMemo = new Map();
|
|
20
|
+
export function sessionFactsReaderFor(workingDir) {
|
|
21
|
+
const readHistory = historyReaderFor(workingDir);
|
|
22
|
+
return (sessionId) => {
|
|
23
|
+
const { historyPath } = resolveHistoryPaths(workingDir, sessionId);
|
|
24
|
+
let stamp;
|
|
25
|
+
try {
|
|
26
|
+
const stat = statSync(historyPath);
|
|
27
|
+
stamp = `${stat.mtimeMs}:${stat.size}`;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
const hit = sessionFactsMemo.get(historyPath);
|
|
33
|
+
if (hit && hit.stamp === stamp)
|
|
34
|
+
return hit.facts;
|
|
35
|
+
const facts = sessionFacts(readHistory(sessionId));
|
|
36
|
+
sessionFactsMemo.set(historyPath, { stamp, facts });
|
|
37
|
+
return facts;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const REVIEW_FILE_RE = /^(.+)-(\d+)\.json$/;
|
|
41
|
+
function toReviewAttempt(record) {
|
|
42
|
+
const checks = Array.isArray(record.checks) ? record.checks : [];
|
|
43
|
+
const attempt = {
|
|
44
|
+
reviewedAt: record.reviewedAt,
|
|
45
|
+
passed: !!record.passed,
|
|
46
|
+
failedChecks: checks.filter((c) => !c.passed).map((c) => String(c.name)),
|
|
47
|
+
};
|
|
48
|
+
if (typeof record.startedAt === 'string' && typeof record.finishedAt === 'string') {
|
|
49
|
+
attempt.startedAt = record.startedAt;
|
|
50
|
+
attempt.finishedAt = record.finishedAt;
|
|
51
|
+
const durationMs = Date.parse(record.finishedAt) - Date.parse(record.startedAt);
|
|
52
|
+
if (Number.isFinite(durationMs) && durationMs >= 0)
|
|
53
|
+
attempt.durationMs = durationMs;
|
|
54
|
+
}
|
|
55
|
+
return attempt;
|
|
56
|
+
}
|
|
57
|
+
export function readReviewAttempts(boardDir) {
|
|
58
|
+
const dir = join(boardDir, 'reviews');
|
|
59
|
+
let names;
|
|
60
|
+
try {
|
|
61
|
+
names = readdirSync(dir);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return new Map();
|
|
65
|
+
}
|
|
66
|
+
const files = [];
|
|
67
|
+
for (const name of names) {
|
|
68
|
+
const match = name.match(REVIEW_FILE_RE);
|
|
69
|
+
if (match)
|
|
70
|
+
files.push({ issueId: match[1], epochMs: Number(match[2]), name });
|
|
71
|
+
}
|
|
72
|
+
files.sort((a, b) => a.epochMs - b.epochMs);
|
|
73
|
+
const attempts = new Map();
|
|
74
|
+
for (const { issueId, name } of files) {
|
|
75
|
+
try {
|
|
76
|
+
const record = JSON.parse(readFileSync(join(dir, name), 'utf-8'));
|
|
77
|
+
if (!record || typeof record !== 'object' || record.issueId !== issueId)
|
|
78
|
+
continue;
|
|
79
|
+
const list = attempts.get(issueId) ?? [];
|
|
80
|
+
list.push(toReviewAttempt(record));
|
|
81
|
+
attempts.set(issueId, list);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return attempts;
|
|
87
|
+
}
|
|
88
|
+
function dispatchStart(sessionId, issueId) {
|
|
89
|
+
const prefix = 'improv-';
|
|
90
|
+
const suffix = `-pm-${issueId}`;
|
|
91
|
+
if (!sessionId.startsWith(prefix) || !sessionId.endsWith(suffix))
|
|
92
|
+
return null;
|
|
93
|
+
const ts = sessionId.slice(prefix.length, sessionId.length - suffix.length);
|
|
94
|
+
return /^\d+$/.test(ts) ? Number(ts) : null;
|
|
95
|
+
}
|
|
96
|
+
function sumPresent(items, pick) {
|
|
97
|
+
let sum;
|
|
98
|
+
for (const item of items) {
|
|
99
|
+
const value = pick(item);
|
|
100
|
+
if (value !== undefined)
|
|
101
|
+
sum = (sum ?? 0) + value;
|
|
102
|
+
}
|
|
103
|
+
return sum;
|
|
104
|
+
}
|
|
105
|
+
function finite(value) {
|
|
106
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
107
|
+
}
|
|
108
|
+
function sessionFacts(history) {
|
|
109
|
+
if (!history)
|
|
110
|
+
return {};
|
|
111
|
+
const movements = history.movements;
|
|
112
|
+
const facts = {
|
|
113
|
+
durationMs: sumPresent(movements, (m) => finite(m.durationMs)),
|
|
114
|
+
outputTokens: sumPresent(movements, (m) => finite(m.outputTokens)),
|
|
115
|
+
model: movements.map((m) => m.model).filter(Boolean).at(-1),
|
|
116
|
+
engine: movements.map((m) => m.engine).filter(Boolean).at(-1) ?? (movements.length > 0 ? history.engine : undefined),
|
|
117
|
+
};
|
|
118
|
+
for (const key of Object.keys(facts)) {
|
|
119
|
+
if (facts[key] === undefined)
|
|
120
|
+
delete facts[key];
|
|
121
|
+
}
|
|
122
|
+
return facts;
|
|
123
|
+
}
|
|
124
|
+
function readDispatches(issue, readFacts) {
|
|
125
|
+
const dispatches = [];
|
|
126
|
+
for (const entry of issue.outputHistory) {
|
|
127
|
+
const startMs = dispatchStart(entry.sessionId, issue.id);
|
|
128
|
+
if (startMs === null)
|
|
129
|
+
continue;
|
|
130
|
+
dispatches.push({
|
|
131
|
+
startMs,
|
|
132
|
+
dispatch: {
|
|
133
|
+
sessionId: entry.sessionId,
|
|
134
|
+
startedAt: new Date(startMs).toISOString(),
|
|
135
|
+
status: entry.status,
|
|
136
|
+
...readFacts(entry.sessionId),
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return dispatches.sort((a, b) => a.startMs - b.startMs).map((d) => d.dispatch);
|
|
141
|
+
}
|
|
142
|
+
function deriveIssueEffort(issue, sources) {
|
|
143
|
+
const dispatches = readDispatches(issue, sources.readFacts);
|
|
144
|
+
const reviewAttempts = sources.reviewAttempts.get(issue.id) ?? [];
|
|
145
|
+
if (dispatches.length === 0 && reviewAttempts.length === 0)
|
|
146
|
+
return null;
|
|
147
|
+
const models = [];
|
|
148
|
+
for (const dispatch of dispatches) {
|
|
149
|
+
if (dispatch.model && !models.includes(dispatch.model))
|
|
150
|
+
models.push(dispatch.model);
|
|
151
|
+
}
|
|
152
|
+
const implementationMs = sumPresent(dispatches, (d) => d.durationMs);
|
|
153
|
+
const reviewMs = sumPresent(reviewAttempts, (a) => a.durationMs);
|
|
154
|
+
const outputTokens = sumPresent(dispatches, (d) => d.outputTokens);
|
|
155
|
+
const delta = sources.qualityDeltas.get(issue.id);
|
|
156
|
+
return {
|
|
157
|
+
dispatches,
|
|
158
|
+
dispatchCount: dispatches.length,
|
|
159
|
+
reviewAttempts,
|
|
160
|
+
passedFirstTime: reviewAttempts[0]?.passed === true,
|
|
161
|
+
cancelledAtCap: issue.status === 'cancelled' && reviewAttempts.length >= MAX_REVIEW_ATTEMPTS,
|
|
162
|
+
...(implementationMs !== undefined ? { implementationMs } : {}),
|
|
163
|
+
...(reviewMs !== undefined ? { reviewMs } : {}),
|
|
164
|
+
...(outputTokens !== undefined ? { outputTokens } : {}),
|
|
165
|
+
models,
|
|
166
|
+
qualityDelta: delta ? summarizeQualityDelta(delta) : null,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
export function deriveIssueEfforts(boardDir, issues, readHistory) {
|
|
170
|
+
return deriveIssueEffortsFromFacts(boardDir, issues, (sessionId) => sessionFacts(readHistory(sessionId)));
|
|
171
|
+
}
|
|
172
|
+
export function deriveIssueEffortsFromFacts(boardDir, issues, readFacts) {
|
|
173
|
+
const sources = {
|
|
174
|
+
reviewAttempts: readReviewAttempts(boardDir),
|
|
175
|
+
qualityDeltas: readLatestQualityDeltas(boardDir),
|
|
176
|
+
readFacts,
|
|
177
|
+
};
|
|
178
|
+
const efforts = new Map();
|
|
179
|
+
for (const issue of issues)
|
|
180
|
+
efforts.set(issue.id, deriveIssueEffort(issue, sources));
|
|
181
|
+
return efforts;
|
|
182
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { activateBoard } from './board-config.js';
|
|
4
|
+
import { NO_SPECS_DIR_ERROR, parseBoardDirectory, parsePlanDirectory } from './parser.js';
|
|
5
|
+
export async function loadBoardIssues(pmDir, boardId, handlers) {
|
|
6
|
+
const boardState = parseBoardDirectory(pmDir, boardId);
|
|
7
|
+
if (!boardState) {
|
|
8
|
+
handlers.onError(`Board not found: ${boardId}`);
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
if (boardState.state.paused) {
|
|
12
|
+
handlers.onError('Board is paused');
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
if (boardState.board.status === 'draft') {
|
|
16
|
+
await activateBoard(pmDir, boardId, handlers.warn);
|
|
17
|
+
}
|
|
18
|
+
else if (boardState.board.status !== 'active') {
|
|
19
|
+
handlers.onError(`Board ${boardId} is not active (status: ${boardState.board.status})`);
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
return boardState.issues;
|
|
23
|
+
}
|
|
24
|
+
export function loadProjectIssues(workingDir, handlers) {
|
|
25
|
+
const fullState = parsePlanDirectory(workingDir);
|
|
26
|
+
if (!fullState) {
|
|
27
|
+
handlers.onError(NO_SPECS_DIR_ERROR);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
if (fullState.state.paused) {
|
|
31
|
+
handlers.onError('Project is paused');
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return fullState.issues;
|
|
35
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { specsDirOrDefault } from '../space-layout.js';
|
|
5
|
+
import { resolveAgentHints } from './agent-resolver.js';
|
|
6
|
+
import { resolveIsCodeTask } from './issue-classification.js';
|
|
7
|
+
const ATTEMPT_TAIL_CHARS = 800;
|
|
8
|
+
const QUALITY_GATE_EFFECT = {
|
|
9
|
+
off: 'no quality delta is recorded for this issue and the review gate does not see Quality.',
|
|
10
|
+
advise: 'the review gate sees a Quality delta (the analyzer findings your changes introduce) and the reviewer weighs it; nothing fails on the delta alone.',
|
|
11
|
+
block: 'the review gate sees a Quality delta (the analyzer findings your changes introduce), and any introduced finding that is critical or high, or in category security, secrets or dependencies, fails the review (check `quality_delta`).',
|
|
12
|
+
};
|
|
13
|
+
export function renderQualityGateSection(issue, gate, isCode) {
|
|
14
|
+
if (!gate)
|
|
15
|
+
return '';
|
|
16
|
+
const lines = ['', '## Quality gate', '', `This board's \`quality_gate\` is **${gate}** — ${QUALITY_GATE_EFFECT[gate]}`];
|
|
17
|
+
if (gate !== 'off') {
|
|
18
|
+
if (issue.reviewGate === 'none')
|
|
19
|
+
lines.push('This issue has `review_gate: none`, so no review reads its delta.');
|
|
20
|
+
else if (!isCode)
|
|
21
|
+
lines.push('This is a document issue, so no delta is recorded for it.');
|
|
22
|
+
}
|
|
23
|
+
lines.push('', 'The `quality_check_files` tool (MCP server `minionry-quality`) is attached to this session: call it with the working-directory-relative paths you changed to see their active findings (severity, category, path, line, title, suggestion, and whether each is new) before you finish, and fix what it reports where this issue\'s scope allows. It is read-only and persists nothing.');
|
|
24
|
+
return `\n${lines.join('\n')}`;
|
|
25
|
+
}
|
|
26
|
+
function describeAttemptOutcome(attempt) {
|
|
27
|
+
switch (attempt.outcome) {
|
|
28
|
+
case 'completed': return 'the run completed but the issue was not accepted';
|
|
29
|
+
case 'incomplete': return 'the run ended without finishing the issue';
|
|
30
|
+
case 'limit': return 'the run stopped on a usage limit';
|
|
31
|
+
case 'auth': return 'the run stopped on an authentication failure';
|
|
32
|
+
case 'error': return 'the run failed';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function renderPreviousAttemptSection(attempts) {
|
|
36
|
+
if (!attempts || attempts.length === 0)
|
|
37
|
+
return '';
|
|
38
|
+
const last = attempts[attempts.length - 1];
|
|
39
|
+
const minutes = Math.max(1, Math.round(last.durationMs / 60_000));
|
|
40
|
+
const lines = [
|
|
41
|
+
'',
|
|
42
|
+
'## Previous attempt',
|
|
43
|
+
`This issue was dispatched ${attempts.length} time${attempts.length === 1 ? '' : 's'} earlier in this run. The most recent attempt ran ${minutes} min and ${describeAttemptOutcome(last)}.`,
|
|
44
|
+
];
|
|
45
|
+
if (last.error)
|
|
46
|
+
lines.push(`- Recorded error: ${last.error.slice(0, 300)}`);
|
|
47
|
+
if (last.toolNames && last.toolNames.length > 0)
|
|
48
|
+
lines.push(`- Tools it used: ${last.toolNames.slice(0, 20).join(', ')}`);
|
|
49
|
+
if (last.outFile)
|
|
50
|
+
lines.push(`- Its output file (may be partial): ${last.outFile}`);
|
|
51
|
+
if (last.reviewFailures && last.reviewFailures.length > 0) {
|
|
52
|
+
lines.push('- The review that sent it back failed these checks:');
|
|
53
|
+
for (const check of last.reviewFailures) {
|
|
54
|
+
lines.push(` - ${check.name}: ${check.details.slice(0, 500)}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (last.tail) {
|
|
58
|
+
lines.push('', 'The end of its last response (a PRIOR attempt — verify against the files before trusting it):', '```', last.tail.slice(-ATTEMPT_TAIL_CHARS), '```');
|
|
59
|
+
}
|
|
60
|
+
lines.push('', 'Do not redo work the previous attempt already completed: read its output file and check the files it changed first, then continue from there. Address every failed review check above explicitly.');
|
|
61
|
+
return `\n${lines.join('\n')}`;
|
|
62
|
+
}
|
|
63
|
+
function renderAgentsSection(resolved) {
|
|
64
|
+
if (resolved.length === 0)
|
|
65
|
+
return '';
|
|
66
|
+
const matched = resolved.filter(r => r.resolvedName);
|
|
67
|
+
const unmatched = resolved.filter(r => !r.resolvedName);
|
|
68
|
+
const lines = ['', '## Suggested Agents'];
|
|
69
|
+
if (matched.length > 0) {
|
|
70
|
+
lines.push('Delegate the relevant portions of this work to these subagents using the Task tool (subagent_type = the agent name). Use them as primary executors when the work matches their expertise:');
|
|
71
|
+
for (const r of matched) {
|
|
72
|
+
const desc = r.info?.description ? ` — ${r.info.description}` : '';
|
|
73
|
+
const labelHint = r.hint.toLowerCase() !== (r.resolvedName ?? '').toLowerCase()
|
|
74
|
+
? ` (matched from "${r.hint}")`
|
|
75
|
+
: '';
|
|
76
|
+
lines.push(`- \`${r.resolvedName}\`${labelHint}${desc}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (unmatched.length > 0) {
|
|
80
|
+
lines.push('');
|
|
81
|
+
lines.push('Role hints with no installed subagent match — use the general-purpose agent (or your best judgment) for work in these areas:');
|
|
82
|
+
for (const r of unmatched) {
|
|
83
|
+
lines.push(`- ${r.hint}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return `\n${lines.join('\n')}`;
|
|
87
|
+
}
|
|
88
|
+
export function buildIssuePrompt(options) {
|
|
89
|
+
const { issue, workingDir, pmDir, boardDir, existingDocs, outputPath } = options;
|
|
90
|
+
const previousAttemptSection = renderPreviousAttemptSection(options.previousAttempts);
|
|
91
|
+
const criteria = issue.acceptanceCriteria
|
|
92
|
+
.map(c => `- [${c.checked ? 'x' : ' '}] ${c.text}`)
|
|
93
|
+
.join('\n');
|
|
94
|
+
const isCode = resolveIsCodeTask(issue);
|
|
95
|
+
const codeFiles = isCode ? issue.filesToModify.filter(f => !f.match(/^Output:/i)) : [];
|
|
96
|
+
const files = codeFiles.length > 0
|
|
97
|
+
? `\n## Files to Modify\n${codeFiles.map(f => `- ${f}`).join('\n')}`
|
|
98
|
+
: '';
|
|
99
|
+
const predecessorDocs = resolvePredecessorDocs(issue, existingDocs);
|
|
100
|
+
const predecessorSection = predecessorDocs.length > 0
|
|
101
|
+
? `\n## Predecessor Outputs\nRead these before starting — they contain context from upstream issues:\n${predecessorDocs.map(d => `- ${d}`).join('\n')}`
|
|
102
|
+
: '';
|
|
103
|
+
const agentSection = renderAgentsSection(resolveAgentHints(issue.agents, workingDir));
|
|
104
|
+
const qualityGateSection = renderQualityGateSection(issue, options.qualityGate, isCode);
|
|
105
|
+
const outDir = boardDir ? join(boardDir, 'out') : pmDir ? join(pmDir, 'out') : join(specsDirOrDefault(workingDir), 'out');
|
|
106
|
+
return `You are executing issue ${issue.id}: ${issue.title}.
|
|
107
|
+
|
|
108
|
+
## Project Directory
|
|
109
|
+
Working directory: ${workingDir}
|
|
110
|
+
Plan directory: ${pmDir || specsDirOrDefault(workingDir)}
|
|
111
|
+
|
|
112
|
+
## Issue Specification
|
|
113
|
+
|
|
114
|
+
**ID**: ${issue.id}
|
|
115
|
+
**Title**: ${issue.title}
|
|
116
|
+
**Type**: ${issue.type} | **Priority**: ${issue.priority} | **Estimate**: ${issue.estimate ?? 'unestimated'}
|
|
117
|
+
|
|
118
|
+
### Description
|
|
119
|
+
${issue.description}
|
|
120
|
+
|
|
121
|
+
### Acceptance Criteria
|
|
122
|
+
${criteria || 'No specific criteria defined.'}
|
|
123
|
+
|
|
124
|
+
### Technical Notes
|
|
125
|
+
${issue.technicalNotes || 'None'}
|
|
126
|
+
${files}${predecessorSection}${agentSection}${previousAttemptSection}${qualityGateSection}
|
|
127
|
+
|
|
128
|
+
## Your Task
|
|
129
|
+
|
|
130
|
+
1. Read the full issue spec at ${pmDir ? join(pmDir, issue.path) : issue.path}
|
|
131
|
+
${isCode ? `2. **Implement the code changes** in the source files listed under "Files to Modify". You MUST edit or create the actual source code files — the acceptance criteria describe what the code must do, not what to document. Read each target file first, then make the changes using Edit or Write.
|
|
132
|
+
3. After implementation, write a brief summary of what you changed to **${outputPath}**${predecessorDocs.length > 0 ? ' — this is the handoff artifact for downstream issues' : ''}
|
|
133
|
+
4. After writing output, update the issue front matter: change \`status: in_progress\` to \`status: in_review\`` : `2. Execute all acceptance criteria listed above
|
|
134
|
+
3. Write your output and results to **${outputPath}** — this is the handoff artifact for downstream issues
|
|
135
|
+
4. After writing output, update the issue front matter: change \`status: in_progress\` to \`status: in_review\``}
|
|
136
|
+
|
|
137
|
+
## Rules
|
|
138
|
+
|
|
139
|
+
- Stay within this issue's scope. Do not modify files outside your assigned scope.
|
|
140
|
+
- The issue's pointers and claims are a briefing, not ground truth: verify them against the actual code before building on them. If the code contradicts the issue, follow the code and record the discrepancy in your output file.
|
|
141
|
+
- The orchestrator manages STATE.md separately — do not edit STATE.md.
|
|
142
|
+
${isCode ? `- The output file is a summary of work done, NOT a substitute for implementation. You must modify the actual source code files listed in "Files to Modify". A review gate will verify the source files were changed.` : `- Write all significant output to ${outDir}/ so downstream issues can reference it.`}
|
|
143
|
+
- If you cannot complete the issue, leave status as \`in_progress\` and document what blocked you in the output file.`;
|
|
144
|
+
}
|
|
145
|
+
function resolvePredecessorDocs(issue, existingDocs) {
|
|
146
|
+
return issue.blockedBy
|
|
147
|
+
.map(bp => {
|
|
148
|
+
const blockerId = bp.replace(/^backlog\//, '').replace(/\.md$/, '');
|
|
149
|
+
return existingDocs.find(d => d.toLowerCase().includes(blockerId.toLowerCase()));
|
|
150
|
+
})
|
|
151
|
+
.filter(Boolean);
|
|
152
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { appendOutputHistoryEntry } from './issue-writer.js';
|
|
4
|
+
import { createPlanRunner } from './plan-runner-factory.js';
|
|
5
|
+
export async function runIssueWithRetry(config) {
|
|
6
|
+
const runner = createPlanRunner('issue', {
|
|
7
|
+
workingDir: config.workingDir,
|
|
8
|
+
prompt: config.prompt,
|
|
9
|
+
tabId: config.tabId,
|
|
10
|
+
engineId: config.engineId,
|
|
11
|
+
model: config.model,
|
|
12
|
+
effortLevel: config.effortLevel,
|
|
13
|
+
fastMode: config.fastMode,
|
|
14
|
+
stallWarningMs: config.stallWarningMs,
|
|
15
|
+
stallKillMs: config.stallKillMs,
|
|
16
|
+
stallHardCapMs: config.stallHardCapMs,
|
|
17
|
+
stallMaxExtensions: config.stallMaxExtensions,
|
|
18
|
+
outputCallback: config.outputCallback,
|
|
19
|
+
thinkingCallback: config.thinkingCallback,
|
|
20
|
+
toolUseCallback: config.toolUseCallback,
|
|
21
|
+
tokenUsageCallback: config.tokenUsageCallback,
|
|
22
|
+
verbose: true,
|
|
23
|
+
extraEnv: config.extraEnv,
|
|
24
|
+
abortSignal: config.abortSignal,
|
|
25
|
+
onRetry: (info) => {
|
|
26
|
+
config.outputCallback?.(`\n[PM-RETRY] Auto-retry ${info.retryNumber}/${info.maxRetries}: ${info.path} — ${info.reason}\n`);
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
const result = await runner.run();
|
|
30
|
+
if (config.appendHistory) {
|
|
31
|
+
const { pmDir, issuePath, issueId, issueTitle, execStart } = config.appendHistory;
|
|
32
|
+
const sessionId = `improv-${execStart}-pm-${issueId}`;
|
|
33
|
+
const status = result.completed && !result.error ? 'done' : 'failed';
|
|
34
|
+
await appendOutputHistoryEntry(pmDir, issuePath, {
|
|
35
|
+
sessionId,
|
|
36
|
+
title: issueTitle,
|
|
37
|
+
timestamp: new Date(execStart).toISOString(),
|
|
38
|
+
status,
|
|
39
|
+
}, (msg) => { config.outputCallback?.(`\n[PM-HISTORY] ${msg}\n`); });
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Minionry, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Minionry-Software
|
|
3
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { isAbsolute, relative, resolve } from 'node:path';
|
|
5
|
+
import { checkAllAcceptanceCriteria, setFrontMatterFieldAsync } from './front-matter.js';
|
|
6
|
+
const STATUS_LINE_PATTERN = /^status:\s*(\S+)/m;
|
|
7
|
+
export function extractIssueStatus(content) {
|
|
8
|
+
return content.match(STATUS_LINE_PATTERN)?.[1] ?? null;
|
|
9
|
+
}
|
|
10
|
+
export function validateIssuePath(issuePath, baseDir) {
|
|
11
|
+
const resolvedBase = resolve(baseDir);
|
|
12
|
+
const resolvedFull = resolve(resolvedBase, issuePath);
|
|
13
|
+
const rel = relative(resolvedBase, resolvedFull);
|
|
14
|
+
if (rel === '' || rel.startsWith('..') || isAbsolute(rel)) {
|
|
15
|
+
throw new Error(`Invalid issue path: path traversal detected in "${issuePath}"`);
|
|
16
|
+
}
|
|
17
|
+
return resolvedFull;
|
|
18
|
+
}
|
|
19
|
+
export async function updateIssueFrontMatter(pmDir, issuePath, newStatus, warn) {
|
|
20
|
+
try {
|
|
21
|
+
const fullPath = validateIssuePath(issuePath, pmDir);
|
|
22
|
+
await setFrontMatterFieldAsync(fullPath, 'status', newStatus);
|
|
23
|
+
if (newStatus === 'done') {
|
|
24
|
+
const content = await readFile(fullPath, 'utf-8');
|
|
25
|
+
const updated = checkAllAcceptanceCriteria(content);
|
|
26
|
+
if (updated !== content)
|
|
27
|
+
await writeFile(fullPath, updated, 'utf-8');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
warn(`Warning: failed to update issue front matter for ${issuePath}: ${errMsg(err)}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export async function revertIncompleteIssues(pmDir, issues, warn) {
|
|
35
|
+
for (const issue of issues) {
|
|
36
|
+
const fullPath = validateIssuePath(issue.path, pmDir);
|
|
37
|
+
try {
|
|
38
|
+
const content = await readFile(fullPath, 'utf-8');
|
|
39
|
+
if (extractIssueStatus(content) === 'in_progress') {
|
|
40
|
+
await updateIssueFrontMatter(pmDir, issue.path, issue.status, warn);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
warn(`Warning: failed to revert issue status: ${errMsg(err)}`, issue.id);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export async function appendCancellationNote(pmDir, issue, reason, warn) {
|
|
49
|
+
const fullPath = validateIssuePath(issue.path, pmDir);
|
|
50
|
+
try {
|
|
51
|
+
let content = await readFile(fullPath, 'utf-8');
|
|
52
|
+
const entry = `- Cancelled (${new Date().toISOString().split('T')[0]}): ${reason}`;
|
|
53
|
+
if (content.includes('## Activity')) {
|
|
54
|
+
content = content.replace(/## Activity/, `## Activity\n${entry}`);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
content += `\n\n## Activity\n${entry}`;
|
|
58
|
+
}
|
|
59
|
+
await writeFile(fullPath, content, 'utf-8');
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
warn(`Warning: failed to append cancellation note: ${errMsg(err)}`, issue.id);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export async function recoverStaleIssues(pmDir, issues, warn) {
|
|
66
|
+
const staleStatuses = new Set(['in_progress', 'in_review']);
|
|
67
|
+
const recovered = [];
|
|
68
|
+
for (const issue of issues) {
|
|
69
|
+
if (issue.type === 'epic')
|
|
70
|
+
continue;
|
|
71
|
+
if (staleStatuses.has(issue.status)) {
|
|
72
|
+
await updateIssueFrontMatter(pmDir, issue.path, 'todo', warn);
|
|
73
|
+
recovered.push(`${issue.id} (${issue.status} → todo)`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return recovered;
|
|
77
|
+
}
|
|
78
|
+
export async function appendOutputHistoryEntry(pmDir, issuePath, entry, warn) {
|
|
79
|
+
const fullPath = validateIssuePath(issuePath, pmDir);
|
|
80
|
+
try {
|
|
81
|
+
let content = await readFile(fullPath, 'utf-8');
|
|
82
|
+
const linkText = entry.title ?? entry.sessionId;
|
|
83
|
+
const line = `- ${entry.timestamp} — [${linkText}](minionry://output/${entry.sessionId}) — ${entry.status}`;
|
|
84
|
+
if (content.includes('## Output History')) {
|
|
85
|
+
content = content.replace(/(## Output History\n)([\s\S]*?)(\n## |\s*$)/, (_match, heading, existingBody, tail) => {
|
|
86
|
+
const body = existingBody.trimEnd();
|
|
87
|
+
const separator = body.length > 0 ? '\n' : '';
|
|
88
|
+
return `${heading}${body}${separator}\n${line}\n${tail}`;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
content = `${content.trimEnd()}\n\n## Output History\n\n${line}\n`;
|
|
93
|
+
}
|
|
94
|
+
await writeFile(fullPath, content, 'utf-8');
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
warn(`Warning: failed to append output history entry for ${issuePath}: ${errMsg(err)}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function errMsg(err) {
|
|
101
|
+
return err instanceof Error ? err.message : String(err);
|
|
102
|
+
}
|