@promptwheel/cli 0.6.0
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/README.md +215 -0
- package/dist/bin/promptwheel.d.ts +17 -0
- package/dist/bin/promptwheel.d.ts.map +1 -0
- package/dist/bin/promptwheel.js +90 -0
- package/dist/bin/promptwheel.js.map +1 -0
- package/dist/commands/auto-auth.d.ts +26 -0
- package/dist/commands/auto-auth.d.ts.map +1 -0
- package/dist/commands/auto-auth.js +216 -0
- package/dist/commands/auto-auth.js.map +1 -0
- package/dist/commands/auto-ci-mode.d.ts +9 -0
- package/dist/commands/auto-ci-mode.d.ts.map +1 -0
- package/dist/commands/auto-ci-mode.js +176 -0
- package/dist/commands/auto-ci-mode.js.map +1 -0
- package/dist/commands/solo-analytics.d.ts +6 -0
- package/dist/commands/solo-analytics.d.ts.map +1 -0
- package/dist/commands/solo-analytics.js +267 -0
- package/dist/commands/solo-analytics.js.map +1 -0
- package/dist/commands/solo-auto.d.ts +6 -0
- package/dist/commands/solo-auto.d.ts.map +1 -0
- package/dist/commands/solo-auto.js +135 -0
- package/dist/commands/solo-auto.js.map +1 -0
- package/dist/commands/solo-daemon.d.ts +12 -0
- package/dist/commands/solo-daemon.d.ts.map +1 -0
- package/dist/commands/solo-daemon.js +177 -0
- package/dist/commands/solo-daemon.js.map +1 -0
- package/dist/commands/solo-exec.d.ts +6 -0
- package/dist/commands/solo-exec.d.ts.map +1 -0
- package/dist/commands/solo-exec.js +656 -0
- package/dist/commands/solo-exec.js.map +1 -0
- package/dist/commands/solo-inspect.d.ts +6 -0
- package/dist/commands/solo-inspect.d.ts.map +1 -0
- package/dist/commands/solo-inspect.js +765 -0
- package/dist/commands/solo-inspect.js.map +1 -0
- package/dist/commands/solo-lifecycle.d.ts +6 -0
- package/dist/commands/solo-lifecycle.d.ts.map +1 -0
- package/dist/commands/solo-lifecycle.js +226 -0
- package/dist/commands/solo-lifecycle.js.map +1 -0
- package/dist/commands/solo-nudge.d.ts +6 -0
- package/dist/commands/solo-nudge.d.ts.map +1 -0
- package/dist/commands/solo-nudge.js +49 -0
- package/dist/commands/solo-nudge.js.map +1 -0
- package/dist/commands/solo-qa.d.ts +6 -0
- package/dist/commands/solo-qa.d.ts.map +1 -0
- package/dist/commands/solo-qa.js +253 -0
- package/dist/commands/solo-qa.js.map +1 -0
- package/dist/commands/solo-trajectory.d.ts +6 -0
- package/dist/commands/solo-trajectory.d.ts.map +1 -0
- package/dist/commands/solo-trajectory.js +268 -0
- package/dist/commands/solo-trajectory.js.map +1 -0
- package/dist/commands/solo.d.ts +11 -0
- package/dist/commands/solo.d.ts.map +1 -0
- package/dist/commands/solo.js +52 -0
- package/dist/commands/solo.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/artifacts.d.ts +136 -0
- package/dist/lib/artifacts.d.ts.map +1 -0
- package/dist/lib/artifacts.js +147 -0
- package/dist/lib/artifacts.js.map +1 -0
- package/dist/lib/codebase-index.d.ts +5 -0
- package/dist/lib/codebase-index.d.ts.map +1 -0
- package/dist/lib/codebase-index.js +5 -0
- package/dist/lib/codebase-index.js.map +1 -0
- package/dist/lib/cycle-context.d.ts +62 -0
- package/dist/lib/cycle-context.d.ts.map +1 -0
- package/dist/lib/cycle-context.js +141 -0
- package/dist/lib/cycle-context.js.map +1 -0
- package/dist/lib/daemon-fork.d.ts +39 -0
- package/dist/lib/daemon-fork.d.ts.map +1 -0
- package/dist/lib/daemon-fork.js +164 -0
- package/dist/lib/daemon-fork.js.map +1 -0
- package/dist/lib/daemon-notifier.d.ts +29 -0
- package/dist/lib/daemon-notifier.d.ts.map +1 -0
- package/dist/lib/daemon-notifier.js +147 -0
- package/dist/lib/daemon-notifier.js.map +1 -0
- package/dist/lib/daemon.d.ts +75 -0
- package/dist/lib/daemon.d.ts.map +1 -0
- package/dist/lib/daemon.js +265 -0
- package/dist/lib/daemon.js.map +1 -0
- package/dist/lib/dedup-memory.d.ts +46 -0
- package/dist/lib/dedup-memory.d.ts.map +1 -0
- package/dist/lib/dedup-memory.js +190 -0
- package/dist/lib/dedup-memory.js.map +1 -0
- package/dist/lib/dedup.d.ts +37 -0
- package/dist/lib/dedup.d.ts.map +1 -0
- package/dist/lib/dedup.js +85 -0
- package/dist/lib/dedup.js.map +1 -0
- package/dist/lib/display-adapter-log.d.ts +26 -0
- package/dist/lib/display-adapter-log.d.ts.map +1 -0
- package/dist/lib/display-adapter-log.js +63 -0
- package/dist/lib/display-adapter-log.js.map +1 -0
- package/dist/lib/display-adapter-spinner.d.ts +28 -0
- package/dist/lib/display-adapter-spinner.d.ts.map +1 -0
- package/dist/lib/display-adapter-spinner.js +93 -0
- package/dist/lib/display-adapter-spinner.js.map +1 -0
- package/dist/lib/display-adapter-tui.d.ts +32 -0
- package/dist/lib/display-adapter-tui.d.ts.map +1 -0
- package/dist/lib/display-adapter-tui.js +77 -0
- package/dist/lib/display-adapter-tui.js.map +1 -0
- package/dist/lib/display-adapter.d.ts +40 -0
- package/dist/lib/display-adapter.d.ts.map +1 -0
- package/dist/lib/display-adapter.js +9 -0
- package/dist/lib/display-adapter.js.map +1 -0
- package/dist/lib/doctor.d.ts +45 -0
- package/dist/lib/doctor.d.ts.map +1 -0
- package/dist/lib/doctor.js +382 -0
- package/dist/lib/doctor.js.map +1 -0
- package/dist/lib/exclusion-index.d.ts +50 -0
- package/dist/lib/exclusion-index.d.ts.map +1 -0
- package/dist/lib/exclusion-index.js +249 -0
- package/dist/lib/exclusion-index.js.map +1 -0
- package/dist/lib/exec.d.ts +24 -0
- package/dist/lib/exec.d.ts.map +1 -0
- package/dist/lib/exec.js +295 -0
- package/dist/lib/exec.js.map +1 -0
- package/dist/lib/execution-backends/claude.d.ts +27 -0
- package/dist/lib/execution-backends/claude.d.ts.map +1 -0
- package/dist/lib/execution-backends/claude.js +161 -0
- package/dist/lib/execution-backends/claude.js.map +1 -0
- package/dist/lib/execution-backends/codex.d.ts +28 -0
- package/dist/lib/execution-backends/codex.d.ts.map +1 -0
- package/dist/lib/execution-backends/codex.js +216 -0
- package/dist/lib/execution-backends/codex.js.map +1 -0
- package/dist/lib/execution-backends/index.d.ts +10 -0
- package/dist/lib/execution-backends/index.d.ts.map +1 -0
- package/dist/lib/execution-backends/index.js +9 -0
- package/dist/lib/execution-backends/index.js.map +1 -0
- package/dist/lib/execution-backends/kimi.d.ts +25 -0
- package/dist/lib/execution-backends/kimi.d.ts.map +1 -0
- package/dist/lib/execution-backends/kimi.js +76 -0
- package/dist/lib/execution-backends/kimi.js.map +1 -0
- package/dist/lib/execution-backends/types.d.ts +38 -0
- package/dist/lib/execution-backends/types.d.ts.map +1 -0
- package/dist/lib/execution-backends/types.js +5 -0
- package/dist/lib/execution-backends/types.js.map +1 -0
- package/dist/lib/failure-classifier.d.ts +11 -0
- package/dist/lib/failure-classifier.d.ts.map +1 -0
- package/dist/lib/failure-classifier.js +24 -0
- package/dist/lib/failure-classifier.js.map +1 -0
- package/dist/lib/file-cooldown.d.ts +9 -0
- package/dist/lib/file-cooldown.d.ts.map +1 -0
- package/dist/lib/file-cooldown.js +75 -0
- package/dist/lib/file-cooldown.js.map +1 -0
- package/dist/lib/formulas.d.ts +52 -0
- package/dist/lib/formulas.d.ts.map +1 -0
- package/dist/lib/formulas.js +123 -0
- package/dist/lib/formulas.js.map +1 -0
- package/dist/lib/git.d.ts +9 -0
- package/dist/lib/git.d.ts.map +1 -0
- package/dist/lib/git.js +60 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/goals.d.ts +59 -0
- package/dist/lib/goals.d.ts.map +1 -0
- package/dist/lib/goals.js +216 -0
- package/dist/lib/goals.js.map +1 -0
- package/dist/lib/guidelines.d.ts +32 -0
- package/dist/lib/guidelines.d.ts.map +1 -0
- package/dist/lib/guidelines.js +102 -0
- package/dist/lib/guidelines.js.map +1 -0
- package/dist/lib/learnings.d.ts +65 -0
- package/dist/lib/learnings.d.ts.map +1 -0
- package/dist/lib/learnings.js +193 -0
- package/dist/lib/learnings.js.map +1 -0
- package/dist/lib/logger.d.ts +17 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +42 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/meta-learnings.d.ts +27 -0
- package/dist/lib/meta-learnings.d.ts.map +1 -0
- package/dist/lib/meta-learnings.js +270 -0
- package/dist/lib/meta-learnings.js.map +1 -0
- package/dist/lib/metrics.d.ts +48 -0
- package/dist/lib/metrics.d.ts.map +1 -0
- package/dist/lib/metrics.js +107 -0
- package/dist/lib/metrics.js.map +1 -0
- package/dist/lib/openai-local-execution.d.ts +29 -0
- package/dist/lib/openai-local-execution.d.ts.map +1 -0
- package/dist/lib/openai-local-execution.js +282 -0
- package/dist/lib/openai-local-execution.js.map +1 -0
- package/dist/lib/project-metadata/csharp.d.ts +6 -0
- package/dist/lib/project-metadata/csharp.d.ts.map +1 -0
- package/dist/lib/project-metadata/csharp.js +19 -0
- package/dist/lib/project-metadata/csharp.js.map +1 -0
- package/dist/lib/project-metadata/elixir.d.ts +6 -0
- package/dist/lib/project-metadata/elixir.d.ts.map +1 -0
- package/dist/lib/project-metadata/elixir.js +23 -0
- package/dist/lib/project-metadata/elixir.js.map +1 -0
- package/dist/lib/project-metadata/go.d.ts +6 -0
- package/dist/lib/project-metadata/go.d.ts.map +1 -0
- package/dist/lib/project-metadata/go.js +30 -0
- package/dist/lib/project-metadata/go.js.map +1 -0
- package/dist/lib/project-metadata/index.d.ts +13 -0
- package/dist/lib/project-metadata/index.d.ts.map +1 -0
- package/dist/lib/project-metadata/index.js +111 -0
- package/dist/lib/project-metadata/index.js.map +1 -0
- package/dist/lib/project-metadata/java.d.ts +6 -0
- package/dist/lib/project-metadata/java.d.ts.map +1 -0
- package/dist/lib/project-metadata/java.js +37 -0
- package/dist/lib/project-metadata/java.js.map +1 -0
- package/dist/lib/project-metadata/node.d.ts +6 -0
- package/dist/lib/project-metadata/node.d.ts.map +1 -0
- package/dist/lib/project-metadata/node.js +135 -0
- package/dist/lib/project-metadata/node.js.map +1 -0
- package/dist/lib/project-metadata/php.d.ts +6 -0
- package/dist/lib/project-metadata/php.d.ts.map +1 -0
- package/dist/lib/project-metadata/php.js +29 -0
- package/dist/lib/project-metadata/php.js.map +1 -0
- package/dist/lib/project-metadata/python.d.ts +6 -0
- package/dist/lib/project-metadata/python.d.ts.map +1 -0
- package/dist/lib/project-metadata/python.js +79 -0
- package/dist/lib/project-metadata/python.js.map +1 -0
- package/dist/lib/project-metadata/ruby.d.ts +6 -0
- package/dist/lib/project-metadata/ruby.d.ts.map +1 -0
- package/dist/lib/project-metadata/ruby.js +38 -0
- package/dist/lib/project-metadata/ruby.js.map +1 -0
- package/dist/lib/project-metadata/rust.d.ts +6 -0
- package/dist/lib/project-metadata/rust.d.ts.map +1 -0
- package/dist/lib/project-metadata/rust.js +33 -0
- package/dist/lib/project-metadata/rust.js.map +1 -0
- package/dist/lib/project-metadata/swift.d.ts +6 -0
- package/dist/lib/project-metadata/swift.d.ts.map +1 -0
- package/dist/lib/project-metadata/swift.js +19 -0
- package/dist/lib/project-metadata/swift.js.map +1 -0
- package/dist/lib/project-metadata/types.d.ts +37 -0
- package/dist/lib/project-metadata/types.d.ts.map +1 -0
- package/dist/lib/project-metadata/types.js +5 -0
- package/dist/lib/project-metadata/types.js.map +1 -0
- package/dist/lib/proposal-review.d.ts +9 -0
- package/dist/lib/proposal-review.d.ts.map +1 -0
- package/dist/lib/proposal-review.js +9 -0
- package/dist/lib/proposal-review.js.map +1 -0
- package/dist/lib/providers/claude.d.ts +6 -0
- package/dist/lib/providers/claude.d.ts.map +1 -0
- package/dist/lib/providers/claude.js +21 -0
- package/dist/lib/providers/claude.js.map +1 -0
- package/dist/lib/providers/codex.d.ts +6 -0
- package/dist/lib/providers/codex.d.ts.map +1 -0
- package/dist/lib/providers/codex.js +26 -0
- package/dist/lib/providers/codex.js.map +1 -0
- package/dist/lib/providers/index.d.ts +22 -0
- package/dist/lib/providers/index.d.ts.map +1 -0
- package/dist/lib/providers/index.js +39 -0
- package/dist/lib/providers/index.js.map +1 -0
- package/dist/lib/providers/kimi.d.ts +6 -0
- package/dist/lib/providers/kimi.d.ts.map +1 -0
- package/dist/lib/providers/kimi.js +22 -0
- package/dist/lib/providers/kimi.js.map +1 -0
- package/dist/lib/providers/openai-local.d.ts +8 -0
- package/dist/lib/providers/openai-local.d.ts.map +1 -0
- package/dist/lib/providers/openai-local.js +30 -0
- package/dist/lib/providers/openai-local.js.map +1 -0
- package/dist/lib/providers/types.d.ts +37 -0
- package/dist/lib/providers/types.d.ts.map +1 -0
- package/dist/lib/providers/types.js +5 -0
- package/dist/lib/providers/types.js.map +1 -0
- package/dist/lib/qa-stats.d.ts +113 -0
- package/dist/lib/qa-stats.d.ts.map +1 -0
- package/dist/lib/qa-stats.js +311 -0
- package/dist/lib/qa-stats.js.map +1 -0
- package/dist/lib/retention.d.ts +125 -0
- package/dist/lib/retention.d.ts.map +1 -0
- package/dist/lib/retention.js +767 -0
- package/dist/lib/retention.js.map +1 -0
- package/dist/lib/run-history.d.ts +52 -0
- package/dist/lib/run-history.d.ts.map +1 -0
- package/dist/lib/run-history.js +116 -0
- package/dist/lib/run-history.js.map +1 -0
- package/dist/lib/run-state.d.ts +129 -0
- package/dist/lib/run-state.d.ts.map +1 -0
- package/dist/lib/run-state.js +312 -0
- package/dist/lib/run-state.js.map +1 -0
- package/dist/lib/scope.d.ts +8 -0
- package/dist/lib/scope.d.ts.map +1 -0
- package/dist/lib/scope.js +8 -0
- package/dist/lib/scope.js.map +1 -0
- package/dist/lib/scout-prompt-builder.d.ts +22 -0
- package/dist/lib/scout-prompt-builder.d.ts.map +1 -0
- package/dist/lib/scout-prompt-builder.js +97 -0
- package/dist/lib/scout-prompt-builder.js.map +1 -0
- package/dist/lib/sectors.d.ts +21 -0
- package/dist/lib/sectors.d.ts.map +1 -0
- package/dist/lib/sectors.js +96 -0
- package/dist/lib/sectors.js.map +1 -0
- package/dist/lib/selection.d.ts +35 -0
- package/dist/lib/selection.d.ts.map +1 -0
- package/dist/lib/selection.js +110 -0
- package/dist/lib/selection.js.map +1 -0
- package/dist/lib/session-report.d.ts +26 -0
- package/dist/lib/session-report.d.ts.map +1 -0
- package/dist/lib/session-report.js +143 -0
- package/dist/lib/session-report.js.map +1 -0
- package/dist/lib/solo-auto-between-cycles.d.ts +10 -0
- package/dist/lib/solo-auto-between-cycles.d.ts.map +1 -0
- package/dist/lib/solo-auto-between-cycles.js +577 -0
- package/dist/lib/solo-auto-between-cycles.js.map +1 -0
- package/dist/lib/solo-auto-execute.d.ts +22 -0
- package/dist/lib/solo-auto-execute.d.ts.map +1 -0
- package/dist/lib/solo-auto-execute.js +530 -0
- package/dist/lib/solo-auto-execute.js.map +1 -0
- package/dist/lib/solo-auto-filter.d.ts +14 -0
- package/dist/lib/solo-auto-filter.d.ts.map +1 -0
- package/dist/lib/solo-auto-filter.js +311 -0
- package/dist/lib/solo-auto-filter.js.map +1 -0
- package/dist/lib/solo-auto-finalize.d.ts +6 -0
- package/dist/lib/solo-auto-finalize.d.ts.map +1 -0
- package/dist/lib/solo-auto-finalize.js +242 -0
- package/dist/lib/solo-auto-finalize.js.map +1 -0
- package/dist/lib/solo-auto-init-qa.d.ts +23 -0
- package/dist/lib/solo-auto-init-qa.d.ts.map +1 -0
- package/dist/lib/solo-auto-init-qa.js +183 -0
- package/dist/lib/solo-auto-init-qa.js.map +1 -0
- package/dist/lib/solo-auto-planning.d.ts +40 -0
- package/dist/lib/solo-auto-planning.d.ts.map +1 -0
- package/dist/lib/solo-auto-planning.js +171 -0
- package/dist/lib/solo-auto-planning.js.map +1 -0
- package/dist/lib/solo-auto-scout.d.ts +18 -0
- package/dist/lib/solo-auto-scout.d.ts.map +1 -0
- package/dist/lib/solo-auto-scout.js +269 -0
- package/dist/lib/solo-auto-scout.js.map +1 -0
- package/dist/lib/solo-auto-state.d.ts +20 -0
- package/dist/lib/solo-auto-state.d.ts.map +1 -0
- package/dist/lib/solo-auto-state.js +859 -0
- package/dist/lib/solo-auto-state.js.map +1 -0
- package/dist/lib/solo-auto-types.d.ts +197 -0
- package/dist/lib/solo-auto-types.d.ts.map +1 -0
- package/dist/lib/solo-auto-types.js +11 -0
- package/dist/lib/solo-auto-types.js.map +1 -0
- package/dist/lib/solo-auto-utils.d.ts +23 -0
- package/dist/lib/solo-auto-utils.d.ts.map +1 -0
- package/dist/lib/solo-auto-utils.js +53 -0
- package/dist/lib/solo-auto-utils.js.map +1 -0
- package/dist/lib/solo-auto.d.ts +25 -0
- package/dist/lib/solo-auto.d.ts.map +1 -0
- package/dist/lib/solo-auto.js +345 -0
- package/dist/lib/solo-auto.js.map +1 -0
- package/dist/lib/solo-ci.d.ts +84 -0
- package/dist/lib/solo-ci.d.ts.map +1 -0
- package/dist/lib/solo-ci.js +306 -0
- package/dist/lib/solo-ci.js.map +1 -0
- package/dist/lib/solo-config.d.ts +242 -0
- package/dist/lib/solo-config.d.ts.map +1 -0
- package/dist/lib/solo-config.js +354 -0
- package/dist/lib/solo-config.js.map +1 -0
- package/dist/lib/solo-cycle-formula.d.ts +36 -0
- package/dist/lib/solo-cycle-formula.d.ts.map +1 -0
- package/dist/lib/solo-cycle-formula.js +90 -0
- package/dist/lib/solo-cycle-formula.js.map +1 -0
- package/dist/lib/solo-git.d.ts +87 -0
- package/dist/lib/solo-git.d.ts.map +1 -0
- package/dist/lib/solo-git.js +365 -0
- package/dist/lib/solo-git.js.map +1 -0
- package/dist/lib/solo-hints.d.ts +32 -0
- package/dist/lib/solo-hints.d.ts.map +1 -0
- package/dist/lib/solo-hints.js +98 -0
- package/dist/lib/solo-hints.js.map +1 -0
- package/dist/lib/solo-prompt-builder.d.ts +12 -0
- package/dist/lib/solo-prompt-builder.d.ts.map +1 -0
- package/dist/lib/solo-prompt-builder.js +53 -0
- package/dist/lib/solo-prompt-builder.js.map +1 -0
- package/dist/lib/solo-qa-retry.d.ts +43 -0
- package/dist/lib/solo-qa-retry.d.ts.map +1 -0
- package/dist/lib/solo-qa-retry.js +125 -0
- package/dist/lib/solo-qa-retry.js.map +1 -0
- package/dist/lib/solo-remote.d.ts +14 -0
- package/dist/lib/solo-remote.d.ts.map +1 -0
- package/dist/lib/solo-remote.js +48 -0
- package/dist/lib/solo-remote.js.map +1 -0
- package/dist/lib/solo-session-summary.d.ts +52 -0
- package/dist/lib/solo-session-summary.d.ts.map +1 -0
- package/dist/lib/solo-session-summary.js +188 -0
- package/dist/lib/solo-session-summary.js.map +1 -0
- package/dist/lib/solo-stdin.d.ts +33 -0
- package/dist/lib/solo-stdin.d.ts.map +1 -0
- package/dist/lib/solo-stdin.js +299 -0
- package/dist/lib/solo-stdin.js.map +1 -0
- package/dist/lib/solo-ticket-qa.d.ts +19 -0
- package/dist/lib/solo-ticket-qa.d.ts.map +1 -0
- package/dist/lib/solo-ticket-qa.js +68 -0
- package/dist/lib/solo-ticket-qa.js.map +1 -0
- package/dist/lib/solo-ticket-types.d.ts +146 -0
- package/dist/lib/solo-ticket-types.d.ts.map +1 -0
- package/dist/lib/solo-ticket-types.js +26 -0
- package/dist/lib/solo-ticket-types.js.map +1 -0
- package/dist/lib/solo-ticket.d.ts +12 -0
- package/dist/lib/solo-ticket.d.ts.map +1 -0
- package/dist/lib/solo-ticket.js +192 -0
- package/dist/lib/solo-ticket.js.map +1 -0
- package/dist/lib/solo-utils.d.ts +130 -0
- package/dist/lib/solo-utils.d.ts.map +1 -0
- package/dist/lib/solo-utils.js +277 -0
- package/dist/lib/solo-utils.js.map +1 -0
- package/dist/lib/spindle/failure-patterns.d.ts +15 -0
- package/dist/lib/spindle/failure-patterns.d.ts.map +1 -0
- package/dist/lib/spindle/failure-patterns.js +22 -0
- package/dist/lib/spindle/failure-patterns.js.map +1 -0
- package/dist/lib/spindle/format.d.ts +9 -0
- package/dist/lib/spindle/format.d.ts.map +1 -0
- package/dist/lib/spindle/format.js +37 -0
- package/dist/lib/spindle/format.js.map +1 -0
- package/dist/lib/spindle/index.d.ts +33 -0
- package/dist/lib/spindle/index.d.ts.map +1 -0
- package/dist/lib/spindle/index.js +231 -0
- package/dist/lib/spindle/index.js.map +1 -0
- package/dist/lib/spindle/oscillation.d.ts +17 -0
- package/dist/lib/spindle/oscillation.d.ts.map +1 -0
- package/dist/lib/spindle/oscillation.js +96 -0
- package/dist/lib/spindle/oscillation.js.map +1 -0
- package/dist/lib/spindle/repetition.d.ts +16 -0
- package/dist/lib/spindle/repetition.d.ts.map +1 -0
- package/dist/lib/spindle/repetition.js +52 -0
- package/dist/lib/spindle/repetition.js.map +1 -0
- package/dist/lib/spindle/similarity.d.ts +14 -0
- package/dist/lib/spindle/similarity.d.ts.map +1 -0
- package/dist/lib/spindle/similarity.js +58 -0
- package/dist/lib/spindle/similarity.js.map +1 -0
- package/dist/lib/spindle/types.d.ts +97 -0
- package/dist/lib/spindle/types.d.ts.map +1 -0
- package/dist/lib/spindle/types.js +46 -0
- package/dist/lib/spindle/types.js.map +1 -0
- package/dist/lib/spinner.d.ts +41 -0
- package/dist/lib/spinner.d.ts.map +1 -0
- package/dist/lib/spinner.js +186 -0
- package/dist/lib/spinner.js.map +1 -0
- package/dist/lib/taste-profile.d.ts +26 -0
- package/dist/lib/taste-profile.d.ts.map +1 -0
- package/dist/lib/taste-profile.js +121 -0
- package/dist/lib/taste-profile.js.map +1 -0
- package/dist/lib/ticket-steps/index.d.ts +14 -0
- package/dist/lib/ticket-steps/index.d.ts.map +1 -0
- package/dist/lib/ticket-steps/index.js +13 -0
- package/dist/lib/ticket-steps/index.js.map +1 -0
- package/dist/lib/ticket-steps/step-agent.d.ts +6 -0
- package/dist/lib/ticket-steps/step-agent.d.ts.map +1 -0
- package/dist/lib/ticket-steps/step-agent.js +122 -0
- package/dist/lib/ticket-steps/step-agent.js.map +1 -0
- package/dist/lib/ticket-steps/step-cleanup.d.ts +6 -0
- package/dist/lib/ticket-steps/step-cleanup.d.ts.map +1 -0
- package/dist/lib/ticket-steps/step-cleanup.js +11 -0
- package/dist/lib/ticket-steps/step-cleanup.js.map +1 -0
- package/dist/lib/ticket-steps/step-commit.d.ts +6 -0
- package/dist/lib/ticket-steps/step-commit.d.ts.map +1 -0
- package/dist/lib/ticket-steps/step-commit.js +31 -0
- package/dist/lib/ticket-steps/step-commit.js.map +1 -0
- package/dist/lib/ticket-steps/step-pr.d.ts +6 -0
- package/dist/lib/ticket-steps/step-pr.d.ts.map +1 -0
- package/dist/lib/ticket-steps/step-pr.js +38 -0
- package/dist/lib/ticket-steps/step-pr.js.map +1 -0
- package/dist/lib/ticket-steps/step-push.d.ts +6 -0
- package/dist/lib/ticket-steps/step-push.d.ts.map +1 -0
- package/dist/lib/ticket-steps/step-push.js +35 -0
- package/dist/lib/ticket-steps/step-push.js.map +1 -0
- package/dist/lib/ticket-steps/step-qa.d.ts +6 -0
- package/dist/lib/ticket-steps/step-qa.d.ts.map +1 -0
- package/dist/lib/ticket-steps/step-qa.js +300 -0
- package/dist/lib/ticket-steps/step-qa.js.map +1 -0
- package/dist/lib/ticket-steps/step-scope.d.ts +6 -0
- package/dist/lib/ticket-steps/step-scope.d.ts.map +1 -0
- package/dist/lib/ticket-steps/step-scope.js +121 -0
- package/dist/lib/ticket-steps/step-scope.js.map +1 -0
- package/dist/lib/ticket-steps/step-spindle.d.ts +9 -0
- package/dist/lib/ticket-steps/step-spindle.d.ts.map +1 -0
- package/dist/lib/ticket-steps/step-spindle.js +160 -0
- package/dist/lib/ticket-steps/step-spindle.js.map +1 -0
- package/dist/lib/ticket-steps/step-worktree.d.ts +6 -0
- package/dist/lib/ticket-steps/step-worktree.d.ts.map +1 -0
- package/dist/lib/ticket-steps/step-worktree.js +157 -0
- package/dist/lib/ticket-steps/step-worktree.js.map +1 -0
- package/dist/lib/ticket-steps/types.d.ts +70 -0
- package/dist/lib/ticket-steps/types.d.ts.map +1 -0
- package/dist/lib/ticket-steps/types.js +8 -0
- package/dist/lib/ticket-steps/types.js.map +1 -0
- package/dist/lib/tool-command-map.d.ts +11 -0
- package/dist/lib/tool-command-map.d.ts.map +1 -0
- package/dist/lib/tool-command-map.js +24 -0
- package/dist/lib/tool-command-map.js.map +1 -0
- package/dist/lib/trajectory-generate.d.ts +24 -0
- package/dist/lib/trajectory-generate.d.ts.map +1 -0
- package/dist/lib/trajectory-generate.js +163 -0
- package/dist/lib/trajectory-generate.js.map +1 -0
- package/dist/lib/trajectory.d.ts +20 -0
- package/dist/lib/trajectory.d.ts.map +1 -0
- package/dist/lib/trajectory.js +104 -0
- package/dist/lib/trajectory.js.map +1 -0
- package/dist/lib/trigger-config.d.ts +12 -0
- package/dist/lib/trigger-config.d.ts.map +1 -0
- package/dist/lib/trigger-config.js +37 -0
- package/dist/lib/trigger-config.js.map +1 -0
- package/dist/lib/update-check.d.ts +28 -0
- package/dist/lib/update-check.d.ts.map +1 -0
- package/dist/lib/update-check.js +178 -0
- package/dist/lib/update-check.js.map +1 -0
- package/dist/lib/wave-scheduling.d.ts +18 -0
- package/dist/lib/wave-scheduling.d.ts.map +1 -0
- package/dist/lib/wave-scheduling.js +29 -0
- package/dist/lib/wave-scheduling.js.map +1 -0
- package/dist/tui/app.d.ts +17 -0
- package/dist/tui/app.d.ts.map +1 -0
- package/dist/tui/app.js +139 -0
- package/dist/tui/app.js.map +1 -0
- package/dist/tui/index.d.ts +10 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +9 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/poller.d.ts +42 -0
- package/dist/tui/poller.d.ts.map +1 -0
- package/dist/tui/poller.js +62 -0
- package/dist/tui/poller.js.map +1 -0
- package/dist/tui/screens/auto.d.ts +85 -0
- package/dist/tui/screens/auto.d.ts.map +1 -0
- package/dist/tui/screens/auto.js +440 -0
- package/dist/tui/screens/auto.js.map +1 -0
- package/dist/tui/screens/overview.d.ts +9 -0
- package/dist/tui/screens/overview.d.ts.map +1 -0
- package/dist/tui/screens/overview.js +189 -0
- package/dist/tui/screens/overview.js.map +1 -0
- package/dist/tui/state.d.ts +93 -0
- package/dist/tui/state.d.ts.map +1 -0
- package/dist/tui/state.js +169 -0
- package/dist/tui/state.js.map +1 -0
- package/dist/tui/ticket-output-buffer.d.ts +23 -0
- package/dist/tui/ticket-output-buffer.d.ts.map +1 -0
- package/dist/tui/ticket-output-buffer.js +60 -0
- package/dist/tui/ticket-output-buffer.js.map +1 -0
- package/dist/tui/types.d.ts +18 -0
- package/dist/tui/types.d.ts.map +1 -0
- package/dist/tui/types.js +5 -0
- package/dist/tui/types.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,859 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AutoSessionState — mutable context object for runAutoMode.
|
|
3
|
+
* Replaces ~55 closure variables with a single passable struct.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'node:fs';
|
|
6
|
+
import * as path from 'node:path';
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
const _require = createRequire(import.meta.url);
|
|
10
|
+
const CLI_VERSION = _require('../../package.json').version;
|
|
11
|
+
import { spawnSync } from 'node:child_process';
|
|
12
|
+
import { projects } from '@promptwheel/core/repos';
|
|
13
|
+
import { createGitService } from './git.js';
|
|
14
|
+
import { getAdapter, isInitialized, initSolo, loadConfig, createScoutDeps, } from './solo-config.js';
|
|
15
|
+
import { runPreflightChecks } from './solo-utils.js';
|
|
16
|
+
import { readRunState } from './run-state.js';
|
|
17
|
+
import { getCycleFormula as getCycleFormulaImpl, getCycleCategories as getCycleCategoriesImpl } from './solo-cycle-formula.js';
|
|
18
|
+
import { createMilestoneBranch, cleanupMilestone, pushAndPrMilestone, ensureDirectBranch, cleanupMergedDirectBranch, } from './solo-git.js';
|
|
19
|
+
import { startInteractiveConsole } from './solo-stdin.js';
|
|
20
|
+
import { loadGuidelines } from './guidelines.js';
|
|
21
|
+
import { loadLearnings } from './learnings.js';
|
|
22
|
+
import { loadDedupMemory, } from './dedup-memory.js';
|
|
23
|
+
import { pruneStaleWorktrees, pruneStaleBranches, pruneStaleCodexSessions, gitWorktreePrune, acquireSessionLock, releaseSessionLock } from './retention.js';
|
|
24
|
+
import { resetQaStatsForSession } from './qa-stats.js';
|
|
25
|
+
import { buildCodebaseIndex, } from './codebase-index.js';
|
|
26
|
+
import { detectProjectMetadata, formatMetadataForPrompt } from './project-metadata/index.js';
|
|
27
|
+
import { DEFAULT_AUTO_CONFIG } from './solo-config.js';
|
|
28
|
+
import { loadOrBuildSectors, pickNextSector, } from './sectors.js';
|
|
29
|
+
import { loadTasteProfile } from './taste-profile.js';
|
|
30
|
+
import { loadGoals, measureGoals, pickGoalByGap, recordGoalMeasurement, } from './goals.js';
|
|
31
|
+
import { loadTrajectoryState, loadTrajectory, } from './trajectory.js';
|
|
32
|
+
import { getNextStep as getTrajectoryNextStep } from '@promptwheel/core/trajectory/shared';
|
|
33
|
+
import { SpinnerDisplayAdapter } from './display-adapter-spinner.js';
|
|
34
|
+
import { LogDisplayAdapter } from './display-adapter-log.js';
|
|
35
|
+
import { initMetrics, metric } from './metrics.js';
|
|
36
|
+
/** Parse CLI options into resolved values. Loads formula if specified. */
|
|
37
|
+
async function resolveOptions(options) {
|
|
38
|
+
let activeFormula = null;
|
|
39
|
+
if (options.formula) {
|
|
40
|
+
const { loadFormula, listFormulas } = await import('./formulas.js');
|
|
41
|
+
activeFormula = loadFormula(options.formula);
|
|
42
|
+
if (!activeFormula) {
|
|
43
|
+
const available = listFormulas();
|
|
44
|
+
console.error(chalk.red(`✗ Formula not found: ${options.formula}`));
|
|
45
|
+
console.error(chalk.gray(` Available formulas: ${available.map(f => f.name).join(', ')}`));
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
console.log(chalk.cyan(`📜 Using formula: ${activeFormula.name}`));
|
|
49
|
+
console.log(chalk.gray(` ${activeFormula.description}`));
|
|
50
|
+
if (activeFormula.prompt) {
|
|
51
|
+
console.log(chalk.gray(` Prompt: ${activeFormula.prompt.slice(0, 80)}...`));
|
|
52
|
+
}
|
|
53
|
+
console.log();
|
|
54
|
+
}
|
|
55
|
+
const hoursValue = options.hours ? parseFloat(options.hours) : 0;
|
|
56
|
+
const minutesValue = options.minutes ? parseFloat(options.minutes) : 0;
|
|
57
|
+
const totalMinutes = (hoursValue * 60 + minutesValue) || undefined;
|
|
58
|
+
const maxCycles = options.cycles ? parseInt(options.cycles, 10) : 999;
|
|
59
|
+
const explicitWheel = options.wheel || options.continuous;
|
|
60
|
+
const impliedWheel = totalMinutes !== undefined || (options.cycles && maxCycles > 1);
|
|
61
|
+
const runMode = (explicitWheel || impliedWheel) ? 'wheel' : 'planning';
|
|
62
|
+
const endTime = totalMinutes ? Date.now() + (totalMinutes * 60 * 1000) : undefined;
|
|
63
|
+
const defaultMaxPrs = runMode === 'wheel' ? 999 : 3;
|
|
64
|
+
const maxPrs = parseInt(options.maxPrs || String(activeFormula?.maxPrs ?? defaultMaxPrs), 10);
|
|
65
|
+
const minConfidence = parseInt(options.minConfidence || String(activeFormula?.minConfidence ?? DEFAULT_AUTO_CONFIG.minConfidence), 10);
|
|
66
|
+
const useDraft = options.draft !== false;
|
|
67
|
+
const batchSize = options.batchSize ? parseInt(options.batchSize, 10) : undefined;
|
|
68
|
+
const milestoneMode = batchSize !== undefined && batchSize > 0;
|
|
69
|
+
const userScope = options.scope || activeFormula?.scope;
|
|
70
|
+
const parallelExplicit = options.parallel !== undefined && options.parallel !== '3';
|
|
71
|
+
return {
|
|
72
|
+
activeFormula, totalMinutes, maxCycles, runMode, endTime,
|
|
73
|
+
maxPrs, minConfidence, useDraft, batchSize, milestoneMode,
|
|
74
|
+
userScope, parallelExplicit,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Set up the execution environment: find repo, acquire lock, clean up stale
|
|
79
|
+
* resources, run setup command, QA baseline, preflight checks.
|
|
80
|
+
*/
|
|
81
|
+
async function initEnvironment(options, resolved) {
|
|
82
|
+
const git = createGitService();
|
|
83
|
+
const repoRoot = await git.findRepoRoot(process.cwd());
|
|
84
|
+
if (!repoRoot) {
|
|
85
|
+
console.error(chalk.red('✗ Not a git repository'));
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
initMetrics(repoRoot);
|
|
89
|
+
metric('session', 'started', { codex: !!options.codex, hours: options.hours });
|
|
90
|
+
// Session lock
|
|
91
|
+
const lockResult = acquireSessionLock(repoRoot);
|
|
92
|
+
if (!lockResult.acquired) {
|
|
93
|
+
console.error(chalk.red('✗ Another PromptWheel session is already running in this repo'));
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
if (lockResult.stalePid) {
|
|
97
|
+
console.log(chalk.gray(` Cleaned up stale session lock (PID ${lockResult.stalePid})`));
|
|
98
|
+
}
|
|
99
|
+
const releaseLock = () => releaseSessionLock(repoRoot);
|
|
100
|
+
process.on('exit', releaseLock);
|
|
101
|
+
// Clean up stale resources
|
|
102
|
+
gitWorktreePrune(repoRoot);
|
|
103
|
+
const prunedWorktrees = pruneStaleWorktrees(repoRoot);
|
|
104
|
+
if (prunedWorktrees > 0) {
|
|
105
|
+
console.log(chalk.gray(` Cleaned up ${prunedWorktrees} stale worktree(s)`));
|
|
106
|
+
}
|
|
107
|
+
const prunedBranches = pruneStaleBranches(repoRoot, 7);
|
|
108
|
+
if (prunedBranches > 0) {
|
|
109
|
+
console.log(chalk.gray(` Cleaned up ${prunedBranches} stale branch(es)`));
|
|
110
|
+
}
|
|
111
|
+
const prunedCodexSessions = pruneStaleCodexSessions(7);
|
|
112
|
+
if (prunedCodexSessions > 0) {
|
|
113
|
+
console.log(chalk.gray(` Cleaned up ${prunedCodexSessions} stale codex session(s)`));
|
|
114
|
+
}
|
|
115
|
+
resetQaStatsForSession(repoRoot);
|
|
116
|
+
let config = loadConfig(repoRoot);
|
|
117
|
+
// Project setup command
|
|
118
|
+
if (config?.setup && !options.dryRun) {
|
|
119
|
+
console.log(chalk.gray(` Running setup: ${config.setup}`));
|
|
120
|
+
try {
|
|
121
|
+
const { execSync } = await import('node:child_process');
|
|
122
|
+
execSync(config.setup, { cwd: repoRoot, timeout: 300_000, stdio: 'pipe' });
|
|
123
|
+
console.log(chalk.green(' ✓ Setup complete'));
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
127
|
+
console.log(chalk.yellow(` ⚠ Setup failed: ${msg.split('\n')[0]}`));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// QA baseline
|
|
131
|
+
let cachedQaBaseline = null;
|
|
132
|
+
if (config?.qa?.commands?.length && !options.dryRun) {
|
|
133
|
+
const { initQaBaseline } = await import('./solo-auto-init-qa.js');
|
|
134
|
+
const qaResult = await initQaBaseline(repoRoot, config, {
|
|
135
|
+
qaFix: !!options.qaFix,
|
|
136
|
+
codex: options.codex,
|
|
137
|
+
codexModel: options.codexModel,
|
|
138
|
+
dryRun: options.dryRun,
|
|
139
|
+
});
|
|
140
|
+
config = qaResult.config;
|
|
141
|
+
cachedQaBaseline = qaResult.qaBaseline;
|
|
142
|
+
}
|
|
143
|
+
// Auto-init if needed (before .gitignore and dirty check so the
|
|
144
|
+
// auto-committed .gitignore doesn't trip the "uncommitted changes" error)
|
|
145
|
+
if (!isInitialized(repoRoot)) {
|
|
146
|
+
console.log(chalk.cyan('First run — initializing PromptWheel...'));
|
|
147
|
+
const { detectedQa } = await initSolo(repoRoot);
|
|
148
|
+
if (detectedQa.length > 0) {
|
|
149
|
+
console.log(chalk.green(` ✓ Detected QA: ${detectedQa.map(q => q.name).join(', ')}`));
|
|
150
|
+
}
|
|
151
|
+
console.log(chalk.green(' ✓ Ready'));
|
|
152
|
+
console.log();
|
|
153
|
+
}
|
|
154
|
+
// Ensure .promptwheel is in .gitignore
|
|
155
|
+
const gitignorePath = path.join(repoRoot, '.gitignore');
|
|
156
|
+
if (fs.existsSync(gitignorePath)) {
|
|
157
|
+
const giContent = fs.readFileSync(gitignorePath, 'utf-8');
|
|
158
|
+
if (!giContent.includes('.promptwheel')) {
|
|
159
|
+
fs.appendFileSync(gitignorePath, '\n# PromptWheel local state\n.promptwheel/\n');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Check working tree
|
|
163
|
+
const statusResult = spawnSync('git', ['status', '--porcelain'], { cwd: repoRoot });
|
|
164
|
+
const statusLines = statusResult.stdout?.toString().trim().split('\n').filter(Boolean) || [];
|
|
165
|
+
const modifiedFiles = statusLines.filter(line => !line.startsWith('??'));
|
|
166
|
+
if (modifiedFiles.length > 0 && !options.dryRun) {
|
|
167
|
+
const onlyGitignore = modifiedFiles.length === 1 &&
|
|
168
|
+
modifiedFiles[0].trim().endsWith('.gitignore');
|
|
169
|
+
if (onlyGitignore) {
|
|
170
|
+
const giPath = path.join(repoRoot, '.gitignore');
|
|
171
|
+
const content = fs.readFileSync(giPath, 'utf-8');
|
|
172
|
+
if (content.includes('.promptwheel')) {
|
|
173
|
+
spawnSync('git', ['add', '.gitignore'], { cwd: repoRoot });
|
|
174
|
+
spawnSync('git', ['commit', '-m', 'chore: add .promptwheel to .gitignore'], { cwd: repoRoot });
|
|
175
|
+
console.log(chalk.gray(' Auto-committed .gitignore update'));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
console.error(chalk.red('✗ Working tree has uncommitted changes'));
|
|
180
|
+
console.error(chalk.gray(' Commit or stash your changes first'));
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Preflight — delivery mode isn't resolved yet (needs autoConf), so check
|
|
185
|
+
// the raw CLI flags. Config-level delivery defaults to 'direct' which
|
|
186
|
+
// doesn't need PR capabilities, so CLI flags are sufficient here.
|
|
187
|
+
const willCreatePrs = resolved.milestoneMode || options.deliveryMode === 'pr' || options.deliveryMode === 'auto-merge' || options.directFinalize === 'pr';
|
|
188
|
+
const preflight = await runPreflightChecks(repoRoot, { needsPr: willCreatePrs });
|
|
189
|
+
if (!preflight.ok) {
|
|
190
|
+
console.error(chalk.red(`✗ ${preflight.error}`));
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
for (const warning of preflight.warnings) {
|
|
194
|
+
console.log(chalk.yellow(`⚠ ${warning}`));
|
|
195
|
+
}
|
|
196
|
+
const autoConf = { ...DEFAULT_AUTO_CONFIG, ...config?.auto };
|
|
197
|
+
const adapter = await getAdapter(repoRoot);
|
|
198
|
+
return { repoRoot, config, autoConf, cachedQaBaseline, adapter };
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Load all session data from disk: formulas, guidelines, learnings, dedup
|
|
202
|
+
* memory, codebase index, metadata, sectors, goals, backend settings.
|
|
203
|
+
*/
|
|
204
|
+
async function loadSessionData(options, resolved, repoRoot, config, autoConf, cachedQaBaseline, adapter) {
|
|
205
|
+
// Formulas for deep scan and docs audit
|
|
206
|
+
let deepFormula = null;
|
|
207
|
+
let docsAuditFormula = null;
|
|
208
|
+
if (!resolved.activeFormula) {
|
|
209
|
+
const { loadFormula: loadF } = await import('./formulas.js');
|
|
210
|
+
if (resolved.runMode === 'wheel') {
|
|
211
|
+
deepFormula = loadF('deep');
|
|
212
|
+
}
|
|
213
|
+
if (options.docsAudit !== false) {
|
|
214
|
+
docsAuditFormula = loadF('docs-audit');
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Guidelines
|
|
218
|
+
const guidelinesBackend = [options.scoutBackend, options.executeBackend].find(b => b && b !== 'claude') ?? 'claude';
|
|
219
|
+
const guidelinesOpts = {
|
|
220
|
+
backend: guidelinesBackend,
|
|
221
|
+
autoCreate: config?.auto?.autoCreateGuidelines !== false,
|
|
222
|
+
customPath: config?.auto?.guidelinesPath || undefined,
|
|
223
|
+
};
|
|
224
|
+
const guidelines = loadGuidelines(repoRoot, guidelinesOpts);
|
|
225
|
+
const guidelinesRefreshInterval = config?.auto?.guidelinesRefreshCycles ?? 10;
|
|
226
|
+
if (guidelines) {
|
|
227
|
+
console.log(chalk.gray(` Guidelines loaded: ${guidelines.source}`));
|
|
228
|
+
}
|
|
229
|
+
// Learnings
|
|
230
|
+
const allLearnings = autoConf.learningsEnabled
|
|
231
|
+
? loadLearnings(repoRoot, autoConf.learningsDecayRate) : [];
|
|
232
|
+
if (allLearnings.length > 0) {
|
|
233
|
+
console.log(chalk.gray(` Learnings loaded: ${allLearnings.length}`));
|
|
234
|
+
}
|
|
235
|
+
// Wheel health summary
|
|
236
|
+
{
|
|
237
|
+
const { getQualityRate } = await import('./run-state.js');
|
|
238
|
+
const qualityRate = getQualityRate(repoRoot);
|
|
239
|
+
const qualityPct = Math.round(qualityRate * 100);
|
|
240
|
+
const confValue = autoConf.minConfidence ?? 20;
|
|
241
|
+
const baselineFailing = cachedQaBaseline
|
|
242
|
+
? [...cachedQaBaseline.values()].filter(v => !v).length
|
|
243
|
+
: 0;
|
|
244
|
+
const qualityColor = qualityRate < 0.5 ? chalk.yellow : chalk.gray;
|
|
245
|
+
const healthParts = [`Quality rate: ${qualityPct}%`, `Confidence: ${confValue}`];
|
|
246
|
+
if (baselineFailing > 0)
|
|
247
|
+
healthParts.push(`Baseline failing: ${baselineFailing}`);
|
|
248
|
+
console.log(qualityColor(` ${healthParts.join(' | ')}`));
|
|
249
|
+
}
|
|
250
|
+
// Backend settings
|
|
251
|
+
const activeBackendName = options.scoutBackend ?? 'claude';
|
|
252
|
+
const backendConf = activeBackendName === 'codex' ? autoConf.codex : autoConf.claude;
|
|
253
|
+
const { getProvider: getProviderDefaults } = await import('./providers/index.js');
|
|
254
|
+
const activeProviderDefaults = getProviderDefaults(activeBackendName);
|
|
255
|
+
const batchTokenBudget = options.batchTokenBudget
|
|
256
|
+
? parseInt(options.batchTokenBudget, 10)
|
|
257
|
+
: (backendConf?.batchTokenBudget ?? autoConf.batchTokenBudget ?? activeProviderDefaults.defaultBatchTokenBudget);
|
|
258
|
+
const scoutConcurrency = options.scoutConcurrency
|
|
259
|
+
? parseInt(options.scoutConcurrency, 10)
|
|
260
|
+
: (backendConf?.scoutConcurrency ?? autoConf.scoutConcurrency ?? activeProviderDefaults.defaultScoutConcurrency);
|
|
261
|
+
const scoutTimeoutMs = options.scoutTimeout
|
|
262
|
+
? parseInt(options.scoutTimeout, 10) * 1000
|
|
263
|
+
: (autoConf.scoutTimeoutMs ?? activeProviderDefaults.defaultScoutTimeoutMs);
|
|
264
|
+
const maxScoutFiles = options.maxScoutFiles
|
|
265
|
+
? parseInt(options.maxScoutFiles, 10)
|
|
266
|
+
: autoConf.maxFilesPerCycle;
|
|
267
|
+
// Dedup memory
|
|
268
|
+
const dedupMemory = loadDedupMemory(repoRoot);
|
|
269
|
+
if (dedupMemory.length > 0) {
|
|
270
|
+
console.log(chalk.gray(` Dedup memory loaded: ${dedupMemory.length} titles`));
|
|
271
|
+
}
|
|
272
|
+
// Codebase index
|
|
273
|
+
const excludeDirs = ['node_modules', 'dist', 'build', '.git', '.promptwheel', 'coverage', '__pycache__'];
|
|
274
|
+
let codebaseIndex = null;
|
|
275
|
+
try {
|
|
276
|
+
codebaseIndex = buildCodebaseIndex(repoRoot, excludeDirs, true);
|
|
277
|
+
console.log(chalk.gray(` Codebase index: ${codebaseIndex.modules.length} modules, ${codebaseIndex.untested_modules.length} untested, ${codebaseIndex.large_files.length} hotspots`));
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
// Non-fatal
|
|
281
|
+
}
|
|
282
|
+
// Project metadata
|
|
283
|
+
const projectMeta = detectProjectMetadata(repoRoot);
|
|
284
|
+
const metadataBlock = formatMetadataForPrompt(projectMeta);
|
|
285
|
+
if (projectMeta.languages.length > 0) {
|
|
286
|
+
console.log(chalk.gray(` Project: ${projectMeta.languages.join(', ')}${projectMeta.framework ? ` / ${projectMeta.framework}` : ''}${projectMeta.test_runner ? ` / ${projectMeta.test_runner.name}` : ''}`));
|
|
287
|
+
}
|
|
288
|
+
// Auto-prune
|
|
289
|
+
try {
|
|
290
|
+
const { pruneAllAsync: pruneAllAsyncFn, getRetentionConfig } = await import('./retention.js');
|
|
291
|
+
const retentionConfig = getRetentionConfig(config);
|
|
292
|
+
const pruneReport = await pruneAllAsyncFn(repoRoot, retentionConfig, adapter);
|
|
293
|
+
if (pruneReport.totalPruned > 0) {
|
|
294
|
+
console.log(chalk.gray(` Pruned ${pruneReport.totalPruned} stale item(s)`));
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
// Non-fatal
|
|
299
|
+
}
|
|
300
|
+
// Sectors
|
|
301
|
+
let sectorState = null;
|
|
302
|
+
if (codebaseIndex) {
|
|
303
|
+
try {
|
|
304
|
+
sectorState = loadOrBuildSectors(repoRoot, codebaseIndex.modules);
|
|
305
|
+
console.log(chalk.gray(` Sectors loaded: ${sectorState.sectors.length} sector(s)`));
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
// Non-fatal
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// Taste profile
|
|
312
|
+
const tasteProfile = loadTasteProfile(repoRoot);
|
|
313
|
+
// Goals
|
|
314
|
+
const goals = loadGoals(repoRoot);
|
|
315
|
+
let activeGoal = null;
|
|
316
|
+
let activeGoalMeasurement = null;
|
|
317
|
+
if (goals.length > 0 && !options.formula) {
|
|
318
|
+
console.log(chalk.cyan(`🎯 Goals loaded: ${goals.length}`));
|
|
319
|
+
const measurements = measureGoals(goals, repoRoot);
|
|
320
|
+
for (const m of measurements) {
|
|
321
|
+
if (m.current !== null) {
|
|
322
|
+
const arrow = m.direction === 'up' ? '↑' : '↓';
|
|
323
|
+
const statusIcon = m.met ? '✓' : '○';
|
|
324
|
+
console.log(chalk.gray(` ${statusIcon} ${m.goalName}: ${m.current} ${arrow} ${m.target}${m.met ? ' (met)' : ` (gap: ${m.gapPercent}%)`}`));
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
console.log(chalk.yellow(` ⚠ ${m.goalName}: measurement failed${m.error ? ` — ${m.error}` : ''}`));
|
|
328
|
+
}
|
|
329
|
+
recordGoalMeasurement(repoRoot, m);
|
|
330
|
+
}
|
|
331
|
+
const picked = pickGoalByGap(measurements);
|
|
332
|
+
if (picked) {
|
|
333
|
+
activeGoal = goals.find(g => g.name === picked.goalName) ?? null;
|
|
334
|
+
activeGoalMeasurement = picked;
|
|
335
|
+
console.log(chalk.cyan(` → Active goal: ${picked.goalName} (gap: ${picked.gapPercent}%)`));
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
const allMet = measurements.every(m => m.met);
|
|
339
|
+
if (allMet) {
|
|
340
|
+
console.log(chalk.green(` ✓ All goals met!`));
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
console.log();
|
|
344
|
+
}
|
|
345
|
+
// Trajectories
|
|
346
|
+
let activeTrajectory = null;
|
|
347
|
+
let activeTrajectoryState = null;
|
|
348
|
+
let currentTrajectoryStep = null;
|
|
349
|
+
{
|
|
350
|
+
const trajState = loadTrajectoryState(repoRoot);
|
|
351
|
+
if (trajState && !trajState.paused) {
|
|
352
|
+
const traj = loadTrajectory(repoRoot, trajState.trajectoryName);
|
|
353
|
+
if (traj) {
|
|
354
|
+
activeTrajectory = traj;
|
|
355
|
+
activeTrajectoryState = trajState;
|
|
356
|
+
const nextStep = getTrajectoryNextStep(traj, trajState.stepStates);
|
|
357
|
+
if (nextStep) {
|
|
358
|
+
currentTrajectoryStep = nextStep;
|
|
359
|
+
activeTrajectoryState.currentStepId = nextStep.id;
|
|
360
|
+
const completed = traj.steps.filter(s => trajState.stepStates[s.id]?.status === 'completed').length;
|
|
361
|
+
console.log(chalk.cyan(`📐 Trajectory: ${traj.name} — step ${completed + 1}/${traj.steps.length}: ${nextStep.title}`));
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
console.log(chalk.green(` ✓ Trajectory "${traj.name}" — all steps complete`));
|
|
365
|
+
activeTrajectory = null;
|
|
366
|
+
activeTrajectoryState = null;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return {
|
|
372
|
+
deepFormula, docsAuditFormula, guidelines, guidelinesOpts, guidelinesRefreshInterval,
|
|
373
|
+
allLearnings, dedupMemory, codebaseIndex, excludeDirs, metadataBlock,
|
|
374
|
+
sectorState, tasteProfile, goals, activeGoal, activeGoalMeasurement,
|
|
375
|
+
activeTrajectory, activeTrajectoryState, currentTrajectoryStep,
|
|
376
|
+
batchTokenBudget, scoutConcurrency, scoutTimeoutMs, maxScoutFiles, activeBackendName,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
/** Initialize external dependencies: project, scout deps, backends, base branch. */
|
|
380
|
+
async function initDependencies(options, repoRoot, autoConf, adapter) {
|
|
381
|
+
const project = await projects.ensureForRepo(adapter, {
|
|
382
|
+
name: path.basename(repoRoot),
|
|
383
|
+
rootPath: repoRoot,
|
|
384
|
+
});
|
|
385
|
+
const deps = createScoutDeps(adapter, { verbose: options.verbose });
|
|
386
|
+
const { getProvider } = await import('./providers/index.js');
|
|
387
|
+
let scoutBackend;
|
|
388
|
+
let executionBackend;
|
|
389
|
+
const scoutBackendName = options.scoutBackend ?? 'claude';
|
|
390
|
+
const execBackendName = options.executeBackend ?? 'claude';
|
|
391
|
+
const modelForBackend = (name) => {
|
|
392
|
+
if (name === 'codex')
|
|
393
|
+
return options.codexModel;
|
|
394
|
+
if (name === 'kimi')
|
|
395
|
+
return options.kimiModel;
|
|
396
|
+
if (name === 'openai-local')
|
|
397
|
+
return options.localModel;
|
|
398
|
+
return undefined;
|
|
399
|
+
};
|
|
400
|
+
const apiKeyForBackend = (name) => {
|
|
401
|
+
const provider = getProvider(name);
|
|
402
|
+
return provider.apiKeyEnvVar ? process.env[provider.apiKeyEnvVar] : undefined;
|
|
403
|
+
};
|
|
404
|
+
if (scoutBackendName !== 'claude') {
|
|
405
|
+
if (scoutBackendName === 'codex' && options.codexMcp) {
|
|
406
|
+
const { CodexMcpScoutBackend } = await import('@promptwheel/core/scout');
|
|
407
|
+
scoutBackend = new CodexMcpScoutBackend({ apiKey: process.env.OPENAI_API_KEY, model: options.codexModel });
|
|
408
|
+
console.log(chalk.cyan(' Scout: Codex MCP (persistent session)'));
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
const scoutProvider = getProvider(scoutBackendName);
|
|
412
|
+
scoutBackend = await scoutProvider.createScoutBackend({
|
|
413
|
+
apiKey: apiKeyForBackend(scoutBackendName),
|
|
414
|
+
model: modelForBackend(scoutBackendName),
|
|
415
|
+
baseUrl: scoutBackendName === 'openai-local' ? options.localUrl : undefined,
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (execBackendName !== 'claude') {
|
|
420
|
+
const execProvider = getProvider(execBackendName);
|
|
421
|
+
executionBackend = await execProvider.createExecutionBackend({
|
|
422
|
+
apiKey: apiKeyForBackend(execBackendName),
|
|
423
|
+
model: modelForBackend(execBackendName),
|
|
424
|
+
unsafeBypassSandbox: options.codexUnsafeFullAccess,
|
|
425
|
+
baseUrl: execBackendName === 'openai-local' ? options.localUrl : undefined,
|
|
426
|
+
maxIterations: options.localMaxIterations ? parseInt(options.localMaxIterations, 10) : undefined,
|
|
427
|
+
});
|
|
428
|
+
if (!autoConf.timeoutMultiplier) {
|
|
429
|
+
autoConf.timeoutMultiplier = 1.5;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
// Detect base branch
|
|
433
|
+
let detectedBaseBranch = 'master';
|
|
434
|
+
try {
|
|
435
|
+
const { gitExec } = await import('./solo-git.js');
|
|
436
|
+
const remoteHead = (await gitExec('git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null || echo "refs/remotes/origin/master"', { cwd: repoRoot })).trim();
|
|
437
|
+
detectedBaseBranch = remoteHead.replace('refs/remotes/origin/', '');
|
|
438
|
+
}
|
|
439
|
+
catch {
|
|
440
|
+
// Fall back to master
|
|
441
|
+
}
|
|
442
|
+
return { project, deps, scoutBackend, executionBackend, detectedBaseBranch };
|
|
443
|
+
}
|
|
444
|
+
/** Initialize milestone or direct branches. */
|
|
445
|
+
async function initBranches(options, resolved, deliveryMode, directBranch, repoRoot, detectedBaseBranch) {
|
|
446
|
+
let milestoneBranch;
|
|
447
|
+
let milestoneWorktreePath;
|
|
448
|
+
let milestoneNumber = 0;
|
|
449
|
+
if (!options.dryRun) {
|
|
450
|
+
if (resolved.milestoneMode) {
|
|
451
|
+
const ms = await createMilestoneBranch(repoRoot, detectedBaseBranch);
|
|
452
|
+
milestoneBranch = ms.milestoneBranch;
|
|
453
|
+
milestoneWorktreePath = ms.milestoneWorktreePath;
|
|
454
|
+
milestoneNumber = 1;
|
|
455
|
+
console.log(chalk.cyan(`Milestone branch: ${milestoneBranch}`));
|
|
456
|
+
console.log();
|
|
457
|
+
}
|
|
458
|
+
else if (deliveryMode === 'direct') {
|
|
459
|
+
const cleaned = await cleanupMergedDirectBranch(repoRoot, directBranch);
|
|
460
|
+
if (cleaned)
|
|
461
|
+
console.log(chalk.gray(` Cleaned up merged direct branch: ${directBranch}`));
|
|
462
|
+
await ensureDirectBranch(repoRoot, directBranch, detectedBaseBranch);
|
|
463
|
+
console.log(chalk.cyan(`Direct branch: ${directBranch}`));
|
|
464
|
+
console.log();
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return { milestoneBranch, milestoneWorktreePath, milestoneNumber };
|
|
468
|
+
}
|
|
469
|
+
/** Print the session header to console. */
|
|
470
|
+
function printSessionHeader(resolved, deliveryMode, directBranch, directFinalize, autoConf, cachedQaBaseline, getCycleFormula, getCycleCategories) {
|
|
471
|
+
const { runMode, totalMinutes, endTime, userScope, milestoneMode, batchSize, maxPrs, useDraft } = resolved;
|
|
472
|
+
const initialCategories = getCycleCategories(getCycleFormula(1));
|
|
473
|
+
{
|
|
474
|
+
console.log(chalk.blue(`🧵 PromptWheel Auto v${CLI_VERSION}`));
|
|
475
|
+
console.log();
|
|
476
|
+
if (runMode === 'wheel') {
|
|
477
|
+
console.log(chalk.gray(' Mode: Wheel (Ctrl+C to stop gracefully)'));
|
|
478
|
+
if (totalMinutes) {
|
|
479
|
+
const endDate = new Date(endTime);
|
|
480
|
+
const budgetLabel = totalMinutes < 60
|
|
481
|
+
? `${Math.round(totalMinutes)} minutes`
|
|
482
|
+
: totalMinutes % 60 === 0
|
|
483
|
+
? `${totalMinutes / 60} hours`
|
|
484
|
+
: `${Math.floor(totalMinutes / 60)}h ${Math.round(totalMinutes % 60)}m`;
|
|
485
|
+
console.log(chalk.gray(` Time budget: ${budgetLabel} (until ${endDate.toLocaleTimeString()})`));
|
|
486
|
+
if ((totalMinutes ?? 0) >= 360) {
|
|
487
|
+
console.log(chalk.gray(` Tip: For always-on improvement, try: promptwheel solo daemon start`));
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
console.log(chalk.gray(' Mode: Planning (scout all → roadmap → approve → execute)'));
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
console.log(chalk.gray(` Scope: ${userScope || (runMode === 'wheel' ? 'rotating' : 'all sectors')}`));
|
|
496
|
+
const catDisplay = initialCategories.allow.join(', ');
|
|
497
|
+
const baselineFailCount = cachedQaBaseline
|
|
498
|
+
? [...cachedQaBaseline.values()].filter(v => !v).length
|
|
499
|
+
: 0;
|
|
500
|
+
if (baselineFailCount > 0 && !initialCategories.allow.includes('fix')) {
|
|
501
|
+
console.log(chalk.gray(` Categories: ${catDisplay} (+fix for baseline healing)`));
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
console.log(chalk.gray(` Categories: ${catDisplay}`));
|
|
505
|
+
}
|
|
506
|
+
{
|
|
507
|
+
const finalizeLabel = directFinalize === 'none' ? 'no PR' : directFinalize;
|
|
508
|
+
console.log(chalk.gray(` Delivery: ${deliveryMode}${deliveryMode === 'direct' ? ` (branch: ${directBranch}, finalize: ${finalizeLabel})` : ''}`));
|
|
509
|
+
}
|
|
510
|
+
if (milestoneMode) {
|
|
511
|
+
console.log(chalk.gray(` Milestone mode: batch size ${batchSize}, max PRs ${maxPrs}`));
|
|
512
|
+
console.log(chalk.gray(` Draft PRs: ${useDraft ? 'yes' : 'no'}`));
|
|
513
|
+
}
|
|
514
|
+
else if (deliveryMode === 'pr' || deliveryMode === 'auto-merge') {
|
|
515
|
+
console.log(chalk.gray(` Max PRs: ${maxPrs}`));
|
|
516
|
+
}
|
|
517
|
+
console.log();
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Patch closures on state that need a back-reference to the state object.
|
|
521
|
+
* Called after the state object is constructed.
|
|
522
|
+
*/
|
|
523
|
+
function patchStateClosures(state, shutdownRef) {
|
|
524
|
+
// Redirect shutdown handler to read/write state flags directly.
|
|
525
|
+
Object.assign(shutdownRef, { shutdownRequested: state.shutdownRequested, currentlyProcessing: state.currentlyProcessing });
|
|
526
|
+
// Reassigning shutdownRef won't work here (local binding), so the caller
|
|
527
|
+
// passes the original object and we need to redirect at the call site.
|
|
528
|
+
// Instead, the caller will do: shutdownRef = state; after this call.
|
|
529
|
+
// Patch formula helpers to read from state
|
|
530
|
+
const stateFormulaCtx = () => ({
|
|
531
|
+
activeFormula: state.activeFormula,
|
|
532
|
+
sessionPhase: state.sessionPhase,
|
|
533
|
+
deepFormula: state.deepFormula,
|
|
534
|
+
docsAuditFormula: state.docsAuditFormula,
|
|
535
|
+
isContinuous: state.runMode === 'wheel',
|
|
536
|
+
repoRoot: state.repoRoot,
|
|
537
|
+
options: state.options,
|
|
538
|
+
config: state.config,
|
|
539
|
+
sectorProductionFileCount: state.currentSectorId
|
|
540
|
+
? state.sectorState?.sectors.find(s => s.path === state.currentSectorId)?.productionFileCount
|
|
541
|
+
: undefined,
|
|
542
|
+
});
|
|
543
|
+
state.getCycleFormula = (cycle) => {
|
|
544
|
+
if (state.activeGoal && !state.options.formula) {
|
|
545
|
+
return state.activeGoal;
|
|
546
|
+
}
|
|
547
|
+
return getCycleFormulaImpl(stateFormulaCtx(), cycle);
|
|
548
|
+
};
|
|
549
|
+
state.getCycleCategories = (formula) => getCycleCategoriesImpl(stateFormulaCtx(), formula);
|
|
550
|
+
// Milestone helpers
|
|
551
|
+
state.finalizeMilestone = async () => {
|
|
552
|
+
if (!state.milestoneMode || !state.milestoneBranch || !state.milestoneWorktreePath)
|
|
553
|
+
return;
|
|
554
|
+
if (state.milestoneTicketCount === 0)
|
|
555
|
+
return;
|
|
556
|
+
console.log(chalk.cyan(`\nFinalizing milestone #${state.milestoneNumber} (${state.milestoneTicketCount} tickets)...`));
|
|
557
|
+
const prUrl = await pushAndPrMilestone(state.repoRoot, state.milestoneBranch, state.milestoneWorktreePath, state.milestoneNumber, state.milestoneTicketCount, [...state.milestoneTicketSummaries]);
|
|
558
|
+
if (prUrl) {
|
|
559
|
+
state.allPrUrls.push(prUrl);
|
|
560
|
+
console.log(chalk.green(` ✓ Milestone PR: ${prUrl}`));
|
|
561
|
+
}
|
|
562
|
+
else {
|
|
563
|
+
console.log(chalk.yellow(` ⚠ Milestone pushed but PR creation failed`));
|
|
564
|
+
}
|
|
565
|
+
state.totalMilestonePrs++;
|
|
566
|
+
};
|
|
567
|
+
state.startNewMilestone = async () => {
|
|
568
|
+
if (!state.milestoneMode)
|
|
569
|
+
return;
|
|
570
|
+
await cleanupMilestone(state.repoRoot);
|
|
571
|
+
state.milestoneTicketCount = 0;
|
|
572
|
+
state.milestoneTicketSummaries.length = 0;
|
|
573
|
+
const ms = await createMilestoneBranch(state.repoRoot, state.detectedBaseBranch);
|
|
574
|
+
state.milestoneBranch = ms.milestoneBranch;
|
|
575
|
+
state.milestoneWorktreePath = ms.milestoneWorktreePath;
|
|
576
|
+
state.milestoneNumber++;
|
|
577
|
+
console.log(chalk.cyan(`New milestone branch: ${state.milestoneBranch}`));
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
/** Start the interactive console (wheel mode only, not in daemon mode). */
|
|
581
|
+
function initInteractiveConsole(state) {
|
|
582
|
+
if (state.runMode !== 'wheel' || state.options.daemon)
|
|
583
|
+
return;
|
|
584
|
+
state.interactiveConsole = startInteractiveConsole({
|
|
585
|
+
repoRoot: state.repoRoot,
|
|
586
|
+
onQuit: () => {
|
|
587
|
+
state.shutdownRequested = true;
|
|
588
|
+
},
|
|
589
|
+
onStatus: () => {
|
|
590
|
+
const elapsed = Math.floor((Date.now() - state.startTime) / 1000);
|
|
591
|
+
const mins = Math.floor(elapsed / 60);
|
|
592
|
+
const secs = elapsed % 60;
|
|
593
|
+
console.log(chalk.cyan('\n 📊 Session Status:'));
|
|
594
|
+
console.log(chalk.gray(` Cycle: ${state.cycleCount}`));
|
|
595
|
+
console.log(chalk.gray(` Elapsed: ${mins}m ${secs}s`));
|
|
596
|
+
if (state.milestoneMode) {
|
|
597
|
+
console.log(chalk.gray(` Tickets this milestone: ${state.milestoneTicketCount}`));
|
|
598
|
+
console.log(chalk.gray(` Milestone PRs: ${state.totalMilestonePrs}/${state.maxPrs}`));
|
|
599
|
+
}
|
|
600
|
+
else if (state.deliveryMode === 'direct') {
|
|
601
|
+
console.log(chalk.gray(` Completed tickets: ${state.completedDirectTickets.length}`));
|
|
602
|
+
}
|
|
603
|
+
else {
|
|
604
|
+
console.log(chalk.gray(` PRs created: ${state.totalPrsCreated}/${state.maxPrs}`));
|
|
605
|
+
}
|
|
606
|
+
console.log(chalk.gray(` Failed: ${state.totalFailed}`));
|
|
607
|
+
if (state.endTime) {
|
|
608
|
+
const remaining = Math.max(0, Math.floor((state.endTime - Date.now()) / 60000));
|
|
609
|
+
console.log(chalk.gray(` Time remaining: ${remaining}m`));
|
|
610
|
+
}
|
|
611
|
+
console.log();
|
|
612
|
+
},
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
// ── Init ────────────────────────────────────────────────────────────────────
|
|
616
|
+
export async function initSession(options) {
|
|
617
|
+
const resolved = await resolveOptions(options);
|
|
618
|
+
const env = await initEnvironment(options, resolved);
|
|
619
|
+
const { repoRoot, config, autoConf, cachedQaBaseline, adapter } = env;
|
|
620
|
+
const sessionData = await loadSessionData(options, resolved, repoRoot, config, autoConf, cachedQaBaseline, adapter);
|
|
621
|
+
const depsResult = await initDependencies(options, repoRoot, autoConf, adapter);
|
|
622
|
+
// Shutdown handler — mutable reference that gets redirected to state after construction
|
|
623
|
+
let shutdownRef = {
|
|
624
|
+
shutdownRequested: false,
|
|
625
|
+
currentlyProcessing: false,
|
|
626
|
+
};
|
|
627
|
+
const shutdownHandler = () => {
|
|
628
|
+
if (shutdownRef.shutdownRequested) {
|
|
629
|
+
console.log(chalk.red('\nForce quit. Exiting immediately.'));
|
|
630
|
+
process.exit(1);
|
|
631
|
+
}
|
|
632
|
+
shutdownRef.shutdownRequested = true;
|
|
633
|
+
if (shutdownRef.currentlyProcessing) {
|
|
634
|
+
console.log(chalk.yellow('\nShutdown requested. Finishing current ticket then finalizing...'));
|
|
635
|
+
}
|
|
636
|
+
else {
|
|
637
|
+
console.log(chalk.yellow('\nShutdown requested. Finalizing session...'));
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
// In daemon mode, the daemon loop handles signals itself
|
|
641
|
+
if (!options.daemon) {
|
|
642
|
+
process.on('SIGINT', shutdownHandler);
|
|
643
|
+
process.on('SIGTERM', shutdownHandler);
|
|
644
|
+
}
|
|
645
|
+
// Temporary formula helpers for header printing (before state exists)
|
|
646
|
+
const sessionPhase = 'deep';
|
|
647
|
+
const tmpFormulaCtx = () => ({
|
|
648
|
+
activeFormula: resolved.activeFormula,
|
|
649
|
+
sessionPhase,
|
|
650
|
+
deepFormula: sessionData.deepFormula,
|
|
651
|
+
docsAuditFormula: sessionData.docsAuditFormula,
|
|
652
|
+
isContinuous: resolved.runMode === 'wheel',
|
|
653
|
+
repoRoot,
|
|
654
|
+
options,
|
|
655
|
+
config,
|
|
656
|
+
sectorProductionFileCount: undefined,
|
|
657
|
+
});
|
|
658
|
+
const tmpGetCycleFormula = (cycle) => getCycleFormulaImpl(tmpFormulaCtx(), cycle);
|
|
659
|
+
const tmpGetCycleCategories = (formula) => getCycleCategoriesImpl(tmpFormulaCtx(), formula);
|
|
660
|
+
// Delivery mode — need autoConf for defaults
|
|
661
|
+
const deliveryMode = options.deliveryMode ?? autoConf.deliveryMode ?? 'direct';
|
|
662
|
+
const directBranch = options.directBranch ?? autoConf.directBranch ?? 'promptwheel-direct';
|
|
663
|
+
const directFinalize = options.directFinalize ?? autoConf.directFinalize ?? 'merge';
|
|
664
|
+
printSessionHeader(resolved, deliveryMode, directBranch, directFinalize, autoConf, cachedQaBaseline, tmpGetCycleFormula, tmpGetCycleCategories);
|
|
665
|
+
const branches = await initBranches(options, resolved, deliveryMode, directBranch, repoRoot, depsResult.detectedBaseBranch);
|
|
666
|
+
// Display adapter
|
|
667
|
+
let displayAdapter;
|
|
668
|
+
if (options.daemon) {
|
|
669
|
+
displayAdapter = new LogDisplayAdapter();
|
|
670
|
+
}
|
|
671
|
+
else {
|
|
672
|
+
const useTui = options.tui !== false && process.stdout.isTTY;
|
|
673
|
+
displayAdapter = new SpinnerDisplayAdapter();
|
|
674
|
+
if (useTui) {
|
|
675
|
+
const { TuiDisplayAdapter } = await import('./display-adapter-tui.js');
|
|
676
|
+
displayAdapter = new TuiDisplayAdapter({
|
|
677
|
+
repoRoot,
|
|
678
|
+
onQuit: () => { shutdownRef.shutdownRequested = true; },
|
|
679
|
+
onStatus: () => {
|
|
680
|
+
// Will be patched after state is created
|
|
681
|
+
},
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
const pullInterval = config?.auto?.pullEveryNCycles ?? 5;
|
|
686
|
+
const pullPolicy = config?.auto?.pullPolicy ?? 'halt';
|
|
687
|
+
// Build state object
|
|
688
|
+
const state = {
|
|
689
|
+
options,
|
|
690
|
+
config,
|
|
691
|
+
autoConf,
|
|
692
|
+
repoRoot,
|
|
693
|
+
activeFormula: resolved.activeFormula,
|
|
694
|
+
deepFormula: sessionData.deepFormula,
|
|
695
|
+
docsAuditFormula: sessionData.docsAuditFormula,
|
|
696
|
+
currentFormulaName: 'default',
|
|
697
|
+
runMode: resolved.runMode,
|
|
698
|
+
totalMinutes: resolved.totalMinutes,
|
|
699
|
+
endTime: resolved.endTime,
|
|
700
|
+
startTime: Date.now(),
|
|
701
|
+
maxPrs: resolved.maxPrs,
|
|
702
|
+
maxCycles: resolved.maxCycles,
|
|
703
|
+
minConfidence: resolved.minConfidence,
|
|
704
|
+
useDraft: resolved.useDraft,
|
|
705
|
+
milestoneMode: resolved.milestoneMode,
|
|
706
|
+
batchSize: resolved.batchSize,
|
|
707
|
+
milestoneBranch: branches.milestoneBranch,
|
|
708
|
+
milestoneWorktreePath: branches.milestoneWorktreePath,
|
|
709
|
+
milestoneTicketCount: 0,
|
|
710
|
+
milestoneNumber: branches.milestoneNumber,
|
|
711
|
+
totalMilestonePrs: 0,
|
|
712
|
+
milestoneTicketSummaries: [],
|
|
713
|
+
deliveryMode,
|
|
714
|
+
directBranch,
|
|
715
|
+
directFinalize,
|
|
716
|
+
completedDirectTickets: [],
|
|
717
|
+
allTraceAnalyses: [],
|
|
718
|
+
totalPrsCreated: 0,
|
|
719
|
+
totalFailed: 0,
|
|
720
|
+
cycleCount: 0,
|
|
721
|
+
allPrUrls: [],
|
|
722
|
+
totalMergedPrs: 0,
|
|
723
|
+
totalClosedPrs: 0,
|
|
724
|
+
pendingPrUrls: [],
|
|
725
|
+
sectorState: sessionData.sectorState,
|
|
726
|
+
currentSectorId: null,
|
|
727
|
+
currentSectorCycle: 0,
|
|
728
|
+
sessionScannedSectors: new Set(),
|
|
729
|
+
effectiveMinConfidence: autoConf.minConfidence ?? 20,
|
|
730
|
+
consecutiveLowYieldCycles: 0,
|
|
731
|
+
sessionPhase,
|
|
732
|
+
allTicketOutcomes: [],
|
|
733
|
+
cycleOutcomes: [],
|
|
734
|
+
prMetaMap: new Map(),
|
|
735
|
+
guidelines: sessionData.guidelines,
|
|
736
|
+
guidelinesOpts: sessionData.guidelinesOpts,
|
|
737
|
+
guidelinesRefreshInterval: sessionData.guidelinesRefreshInterval,
|
|
738
|
+
allLearnings: sessionData.allLearnings,
|
|
739
|
+
dedupMemory: sessionData.dedupMemory,
|
|
740
|
+
codebaseIndex: sessionData.codebaseIndex,
|
|
741
|
+
excludeDirs: sessionData.excludeDirs,
|
|
742
|
+
metadataBlock: sessionData.metadataBlock,
|
|
743
|
+
tasteProfile: sessionData.tasteProfile,
|
|
744
|
+
goals: sessionData.goals,
|
|
745
|
+
activeGoal: sessionData.activeGoal,
|
|
746
|
+
activeGoalMeasurement: sessionData.activeGoalMeasurement,
|
|
747
|
+
activeTrajectory: sessionData.activeTrajectory,
|
|
748
|
+
activeTrajectoryState: sessionData.activeTrajectoryState,
|
|
749
|
+
currentTrajectoryStep: sessionData.currentTrajectoryStep,
|
|
750
|
+
qaBaseline: cachedQaBaseline,
|
|
751
|
+
batchTokenBudget: sessionData.batchTokenBudget,
|
|
752
|
+
scoutConcurrency: sessionData.scoutConcurrency,
|
|
753
|
+
scoutTimeoutMs: sessionData.scoutTimeoutMs,
|
|
754
|
+
maxScoutFiles: sessionData.maxScoutFiles,
|
|
755
|
+
activeBackendName: sessionData.activeBackendName,
|
|
756
|
+
scoutBackend: depsResult.scoutBackend,
|
|
757
|
+
executionBackend: depsResult.executionBackend,
|
|
758
|
+
adapter,
|
|
759
|
+
project: depsResult.project,
|
|
760
|
+
deps: depsResult.deps,
|
|
761
|
+
detectedBaseBranch: depsResult.detectedBaseBranch,
|
|
762
|
+
shutdownRequested: shutdownRef.shutdownRequested,
|
|
763
|
+
currentlyProcessing: false,
|
|
764
|
+
pullInterval,
|
|
765
|
+
pullPolicy,
|
|
766
|
+
cyclesSinceLastPull: 0,
|
|
767
|
+
scoutRetries: 0,
|
|
768
|
+
scoutedDirs: [],
|
|
769
|
+
parallelExplicit: resolved.parallelExplicit,
|
|
770
|
+
userScope: resolved.userScope,
|
|
771
|
+
interactiveConsole: undefined,
|
|
772
|
+
displayAdapter,
|
|
773
|
+
getCycleFormula: null,
|
|
774
|
+
getCycleCategories: null,
|
|
775
|
+
finalizeMilestone: null,
|
|
776
|
+
startNewMilestone: null,
|
|
777
|
+
};
|
|
778
|
+
// Redirect shutdown handler to state
|
|
779
|
+
shutdownRef = state;
|
|
780
|
+
// Patch closures that need state reference
|
|
781
|
+
patchStateClosures(state, shutdownRef);
|
|
782
|
+
// Start interactive console
|
|
783
|
+
initInteractiveConsole(state);
|
|
784
|
+
return state;
|
|
785
|
+
}
|
|
786
|
+
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
787
|
+
export function shouldContinue(state) {
|
|
788
|
+
if (state.shutdownRequested)
|
|
789
|
+
return false;
|
|
790
|
+
// PR limits only apply to PR-based workflows, not direct mode
|
|
791
|
+
if (state.milestoneMode) {
|
|
792
|
+
if (state.totalMilestonePrs >= state.maxPrs)
|
|
793
|
+
return false;
|
|
794
|
+
}
|
|
795
|
+
else if (state.deliveryMode === 'pr' || state.deliveryMode === 'auto-merge') {
|
|
796
|
+
if (state.totalPrsCreated >= state.maxPrs)
|
|
797
|
+
return false;
|
|
798
|
+
}
|
|
799
|
+
// Direct mode: no PR limit, just time/cycles
|
|
800
|
+
if (state.endTime && Date.now() >= state.endTime)
|
|
801
|
+
return false;
|
|
802
|
+
if (state.cycleCount >= state.maxCycles && state.runMode !== 'wheel')
|
|
803
|
+
return false;
|
|
804
|
+
return true;
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Check if a sector has files modified since its last scan.
|
|
808
|
+
* Uses `git diff --name-only` against the sector's scope.
|
|
809
|
+
*/
|
|
810
|
+
function sectorHasChanges(repoRoot, sector) {
|
|
811
|
+
if (sector.lastScannedAt === 0)
|
|
812
|
+
return true; // never scanned = always scan
|
|
813
|
+
try {
|
|
814
|
+
const sinceDate = new Date(sector.lastScannedAt).toISOString();
|
|
815
|
+
const result = spawnSync('git', ['log', '--since', sinceDate, '--name-only', '--pretty=format:', '--', `${sector.path}/**`], {
|
|
816
|
+
cwd: repoRoot,
|
|
817
|
+
encoding: 'utf-8',
|
|
818
|
+
timeout: 5000,
|
|
819
|
+
});
|
|
820
|
+
const changedFiles = (result.stdout ?? '').trim();
|
|
821
|
+
return changedFiles.length > 0;
|
|
822
|
+
}
|
|
823
|
+
catch {
|
|
824
|
+
return true; // on error, assume changes exist
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
export function getNextScope(state) {
|
|
828
|
+
if (state.userScope)
|
|
829
|
+
return state.userScope;
|
|
830
|
+
if (state.sectorState) {
|
|
831
|
+
const rs = readRunState(state.repoRoot);
|
|
832
|
+
state.currentSectorCycle = rs.totalCycles;
|
|
833
|
+
// Keep picking sectors until we find one with changes (or unscanned)
|
|
834
|
+
const tried = new Set();
|
|
835
|
+
while (tried.size < state.sectorState.sectors.length) {
|
|
836
|
+
const pick = pickNextSector(state.sectorState, state.currentSectorCycle);
|
|
837
|
+
if (!pick)
|
|
838
|
+
break;
|
|
839
|
+
if (tried.has(pick.sector.path))
|
|
840
|
+
break; // looped back
|
|
841
|
+
tried.add(pick.sector.path);
|
|
842
|
+
// Always scan each sector at least once per session; after that, only on changes
|
|
843
|
+
const scannedThisSession = state.sessionScannedSectors.has(pick.sector.path);
|
|
844
|
+
if (pick.sector.scanCount === 0 || !scannedThisSession || sectorHasChanges(state.repoRoot, pick.sector)) {
|
|
845
|
+
state.sessionScannedSectors.add(pick.sector.path);
|
|
846
|
+
state.currentSectorId = pick.sector.path;
|
|
847
|
+
return pick.scope;
|
|
848
|
+
}
|
|
849
|
+
// Mark as "just scanned" so pickNextSector moves to the next one
|
|
850
|
+
pick.sector.lastScannedCycle = state.currentSectorCycle;
|
|
851
|
+
}
|
|
852
|
+
// All sectors scanned and no changes detected
|
|
853
|
+
state.currentSectorId = null;
|
|
854
|
+
return null;
|
|
855
|
+
}
|
|
856
|
+
state.currentSectorId = null;
|
|
857
|
+
return '**';
|
|
858
|
+
}
|
|
859
|
+
//# sourceMappingURL=solo-auto-state.js.map
|