specrails-desktop 2.55.0 → 2.55.1
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/cli/dist/args.js +80 -0
- package/cli/dist/desktop-client.js +125 -0
- package/cli/dist/desktop-control.js +339 -0
- package/cli/dist/format.js +45 -0
- package/cli/dist/help.js +68 -0
- package/cli/dist/output.js +47 -0
- package/cli/dist/run-command.js +340 -0
- package/cli/dist/specrails-desktop.js +41 -1107
- package/cli/dist/status.js +111 -0
- package/client/dist/assets/{ActivityFeedPage-ILXMZXcb.js → ActivityFeedPage-DmJcQpNe.js} +1 -1
- package/client/dist/assets/{AgentBrowserCapture-UcsupCy7.js → AgentBrowserCapture-NxBHrU-V.js} +1 -1
- package/client/dist/assets/{AgentModeAnalyticsPane-CQuxYh8B.js → AgentModeAnalyticsPane-CGAKTJfU.js} +2 -2
- package/client/dist/assets/{AgentModeCodePane-zPWbW7ei.js → AgentModeCodePane-DNSs5_oe.js} +2 -2
- package/client/dist/assets/{AgentModeJobsPane-CInByIdl.js → AgentModeJobsPane-DLoVYDnG.js} +1 -1
- package/client/dist/assets/{AgentsPage-BWvgxaBv.js → AgentsPage-CAzMn9Gg.js} +1 -1
- package/client/dist/assets/{AnalyticsPage-DP3jakv-.js → AnalyticsPage-C06KT4Y0.js} +1 -1
- package/client/dist/assets/{CodePage-BKXiwE5a.js → CodePage-aX1mxGyT.js} +1 -1
- package/client/dist/assets/{DesktopAnalyticsPage-DryJOaMz.js → DesktopAnalyticsPage-BtscfiQD.js} +1 -1
- package/client/dist/assets/{DocsDialog-BsCG9ksG.js → DocsDialog-CNOcXhp-.js} +1 -1
- package/client/dist/assets/{DocsPage-Cc-GeKYl.js → DocsPage-C2BugxaI.js} +1 -1
- package/client/dist/assets/{ExportDropdown-ClahJdDn.js → ExportDropdown-BVGKEgkd.js} +1 -1
- package/client/dist/assets/{InteractiveJobComposer-DfLF6N0f.js → InteractiveJobComposer-CCncBqNu.js} +1 -1
- package/client/dist/assets/{JobDetailModal-DHeur9YK.js → JobDetailModal-Cn_k3-RM.js} +1 -1
- package/client/dist/assets/{JobDetailPage-CraDKzeG.js → JobDetailPage-BogJFBsk.js} +1 -1
- package/client/dist/assets/{JobsPage-CcbuSwj7.js → JobsPage-DL4E8ZyU.js} +1 -1
- package/client/dist/assets/{LoopBuilderPage-BKtNp494.js → LoopBuilderPage-9L6URQLY.js} +1 -1
- package/client/dist/assets/{LoopPreviewModal-DbZd9isy.js → LoopPreviewModal-CAPqTIgL.js} +1 -1
- package/client/dist/assets/{LoopsPage-DEg6sIkG.js → LoopsPage-aU8dYw7L.js} +1 -1
- package/client/dist/assets/{MinimizedChatsContext-BGtEjWsc.js → MinimizedChatsContext-D3QzgV0B.js} +1 -1
- package/client/dist/assets/{PluginsPage-BVqSsPzL.js → PluginsPage-D_tsW9B5.js} +1 -1
- package/client/dist/assets/{ProjectSettingsDialog-CAjLgJAZ.js → ProjectSettingsDialog-_ZbNuspP.js} +1 -1
- package/client/dist/assets/{RepositoryDeliveries-DrcrxLe0.js → RepositoryDeliveries-Du2UCf1a.js} +1 -1
- package/client/dist/assets/{RepositoryScopeSelector-CAGY3xW6.js → RepositoryScopeSelector-hPGZNRBm.js} +1 -1
- package/client/dist/assets/ReviewPacketPage-CG-Dv0El.js +4 -0
- package/client/dist/assets/{TemplatePreviewModal-Bqs-9fhn.js → TemplatePreviewModal-C19H2b2o.js} +1 -1
- package/client/dist/assets/{TicketDetailModalContext-C0jQ5yOk.js → TicketDetailModalContext-DAK-NoK6.js} +1 -1
- package/client/dist/assets/{Trans-DtWlCJN9.js → Trans-DEbgkuAY.js} +1 -1
- package/client/dist/assets/{dashboard-CTfEtkqX.js → dashboard-B9uWNGO2.js} +1 -1
- package/client/dist/assets/{dashboard-DMklepmz.js → dashboard-BIwmO9wc.js} +1 -1
- package/client/dist/assets/{dashboard-DBAP2_SQ.js → dashboard-BV4vOZkR.js} +1 -1
- package/client/dist/assets/{dashboard-D40HP2ks.js → dashboard-Bf6MPVsM.js} +1 -1
- package/client/dist/assets/{dashboard-Csf1yGSN.js → dashboard-C8klWVvZ.js} +1 -1
- package/client/dist/assets/{dashboard-C29Qwa-L.js → dashboard-D1ORhPF0.js} +1 -1
- package/client/dist/assets/{dashboard-Cr4D8oMn.js → dashboard-DSubvs9x.js} +1 -1
- package/client/dist/assets/{dashboard-CSJzf5OT.js → dashboard-px_vlRx_.js} +1 -1
- package/client/dist/assets/{formatDistanceToNow-DYmvOA3R.js → formatDistanceToNow-Cc2u5FwQ.js} +1 -1
- package/client/dist/assets/{getTimezoneOffsetInMilliseconds-BAhW5E6V.js → getTimezoneOffsetInMilliseconds-BHm2U-w1.js} +1 -1
- package/client/dist/assets/{index-BfAZg5DG.js → index-BcligJ3-.js} +29 -29
- package/client/dist/assets/index-C51x61Bz.css +2 -0
- package/client/dist/assets/{jira-api-B27Za5FP.js → jira-api-DrGxiD9p.js} +1 -1
- package/client/dist/assets/packet-8nn9RsU7.js +1 -0
- package/client/dist/assets/packet-B0H15elv.js +1 -0
- package/client/dist/assets/packet-BQvBgrwh.js +1 -0
- package/client/dist/assets/packet-BR7mO0-a.js +1 -0
- package/client/dist/assets/packet-BgcQ6q_K.js +1 -0
- package/client/dist/assets/packet-D2s92Jnn.js +1 -0
- package/client/dist/assets/packet-YbtcD1HS.js +1 -0
- package/client/dist/assets/packet-c0Qj_9eX.js +1 -0
- package/client/dist/assets/{project-repositories-DixIZHTA.js → project-repositories-9Wzs0coQ.js} +1 -1
- package/client/dist/assets/{spending-BGmZBX5B.js → spending-T5GM7wpn.js} +1 -1
- package/client/dist/assets/{useDesktop-CPB4cnwI.js → useDesktop-QogiN0zR.js} +1 -1
- package/client/dist/assets/{useRuntimeRuns-DEQ9HdAM.js → useRuntimeRuns-Dqmz9fS9.js} +1 -1
- package/client/dist/assets/{useSharedWebSocket-DcPRKR8R.js → useSharedWebSocket-Dz-HI6De.js} +2 -2
- package/client/dist/index.html +17 -17
- package/docs/codex.md +5 -5
- package/docs/customizing.md +1 -1
- package/docs/gemini-cli-provider-study.md +14 -14
- package/docs/gemini-core-support-evaluation.md +1 -1
- package/docs/gemini.md +5 -5
- package/docs/internals/README.md +6 -2
- package/docs/internals/adding-a-provider.md +15 -15
- package/docs/internals/agent-runtime-framework-evaluation.md +8 -8
- package/docs/internals/api-reference.md +2 -2
- package/docs/internals/architecture.md +9 -9
- package/docs/internals/browser-capture-performance.md +3 -3
- package/docs/internals/code-explorer-story.md +2 -2
- package/docs/internals/companion-rails-as-loops-contract.md +2 -2
- package/docs/internals/embedded-browser-native-webview-evaluation.md +5 -5
- package/docs/internals/gemini-mcp-registration.md +2 -2
- package/docs/internals/global-artifacts-alignment-contract.md +1 -1
- package/docs/internals/global-artifacts-relocation-evaluation.md +1 -1
- package/docs/internals/interactive-jobs.md +8 -8
- package/docs/internals/legacy-implementation-notes.md +722 -0
- package/docs/internals/loop-step-log-explorer.md +8 -8
- package/docs/internals/mission-rail-cards.md +14 -14
- package/docs/internals/modular-architecture.md +107 -0
- package/docs/internals/profiles.md +1 -1
- package/docs/internals/project-builder.md +18 -18
- package/docs/internals/review-packet.md +8 -8
- package/docs/internals/safe-pr-review-flow.md +11 -11
- package/docs/internals/source-architecture.md +131 -0
- package/docs/internals/source-map.md +1354 -0
- package/docs/internals/spec-addenda.md +65 -9
- package/docs/internals/switch-to-agent-mode-design.md +11 -11
- package/docs/tracking-cost.md +1 -1
- package/package.json +5 -2
- package/server/dist/agent-mcp-config.js +1 -1
- package/server/dist/attachment-manager.js +1 -1
- package/server/dist/build-dirs.js +2 -2
- package/server/dist/config.js +0 -3
- package/server/dist/core-completion.js +1 -1
- package/server/dist/core-execution.js +1 -1
- package/server/dist/db/activity.js +39 -0
- package/server/dist/db/connection.js +41 -0
- package/server/dist/db/conversations.js +48 -0
- package/server/dist/db/jobs.js +251 -0
- package/server/dist/db/migrations.js +1521 -0
- package/server/dist/db/proposals.js +50 -0
- package/server/dist/db/settings.js +15 -0
- package/server/dist/db/stats.js +61 -0
- package/server/dist/db/telemetry.js +56 -0
- package/server/dist/db/templates.js +37 -0
- package/server/dist/db/types.js +2 -0
- package/server/dist/db.js +66 -2224
- package/server/dist/desktop-db.js +3 -3
- package/server/dist/desktop-router.js +8 -8
- package/server/dist/git-diagnostics.js +1 -1
- package/server/dist/index.js +11 -11
- package/server/dist/integration-branch.js +3 -14
- package/server/dist/jira/jira-issue-fields.js +0 -1
- package/server/dist/jira/jira-materializer.js +1 -1
- package/server/dist/jira/jira-sync-manager.js +1 -1
- package/server/dist/mcp/mcp-admin-router.js +1 -1
- package/server/dist/mcp/mcp-server.js +1 -1
- package/server/dist/mcp/tools/jobs.js +1 -1
- package/server/dist/mcp/tools/rails.js +2 -2
- package/server/dist/mcp/tools/specs.js +2 -2
- package/server/dist/mcp/tools/types.js +3 -3
- package/server/dist/mobile/mobile-gateway.js +1 -1
- package/server/dist/mobile/mobile-missions.js +1 -1
- package/server/dist/{desktop-analytics.js → modules/accounting/runtime/desktop-analytics.js} +2 -2
- package/server/dist/{pricing.js → modules/accounting/runtime/pricing.js} +1 -1
- package/server/dist/{result-event.js → modules/accounting/runtime/result-event.js} +3 -3
- package/server/dist/{spending.js → modules/accounting/runtime/spending.js} +0 -3
- package/server/dist/{telemetry-compactor.js → modules/accounting/runtime/telemetry-compactor.js} +1 -1
- package/server/dist/{telemetry-receiver.js → modules/accounting/runtime/telemetry-receiver.js} +2 -2
- package/server/dist/{agent-runtime-bridge.js → modules/agent-runtime/runtime/agent-runtime-bridge.js} +2 -2
- package/server/dist/{agent-runtime-controls.js → modules/agent-runtime/runtime/agent-runtime-controls.js} +7 -7
- package/server/dist/{agent-runtime-effective-config.js → modules/agent-runtime/runtime/agent-runtime-effective-config.js} +1 -1
- package/server/dist/{agent-runtime-loader.js → modules/agent-runtime/runtime/agent-runtime-loader.js} +3 -3
- package/server/dist/{agent-runtime-paths.js → modules/agent-runtime/runtime/agent-runtime-paths.js} +1 -1
- package/server/dist/{agent-runtime-settings-router.js → modules/agent-runtime/runtime/agent-runtime-settings-router.js} +2 -2
- package/server/dist/{agent-runtime-settings.js → modules/agent-runtime/runtime/agent-runtime-settings.js} +3 -3
- package/server/dist/{agent-runtime-settlement.js → modules/agent-runtime/runtime/agent-runtime-settlement.js} +6 -6
- package/server/dist/{agent-defaults.js → modules/agents/runtime/agent-defaults.js} +3 -3
- package/server/dist/{agent-generator.js → modules/agents/runtime/agent-generator.js} +7 -7
- package/server/dist/{agent-refine-manager.js → modules/agents/runtime/agent-refine-manager.js} +5 -5
- package/server/dist/{agent-store.js → modules/agents/runtime/agent-store.js} +1 -1
- package/server/dist/{profile-manager.js → modules/agents/runtime/profile-manager.js} +2 -2
- package/server/dist/{profiles-router.js → modules/agents/runtime/profiles-router.js} +5 -5
- package/server/dist/{browser-capture-manager.js → modules/browser/runtime/browser-capture-manager.js} +2 -4
- package/server/dist/{browser-playwright.js → modules/browser/runtime/browser-playwright.js} +1 -1
- package/server/dist/{blueprint-chat-manager.js → modules/builder/runtime/blueprint-chat-manager.js} +7 -7
- package/server/dist/{blueprint-commit.js → modules/builder/runtime/blueprint-commit.js} +8 -8
- package/server/dist/{blueprint-draft-parser.js → modules/builder/runtime/blueprint-draft-parser.js} +1 -1
- package/server/dist/{blueprint-generation.js → modules/builder/runtime/blueprint-generation.js} +1 -1
- package/server/dist/{blueprint-operator-prompt.js → modules/builder/runtime/blueprint-operator-prompt.js} +1 -1
- package/server/dist/{blueprint-router.js → modules/builder/runtime/blueprint-router.js} +3 -3
- package/server/dist/{blueprint-spec-quality.js → modules/builder/runtime/blueprint-spec-quality.js} +1 -1
- package/server/dist/{milestone-chain.js → modules/builder/runtime/milestone-chain.js} +1 -1
- package/server/dist/{milestone-progress.js → modules/builder/runtime/milestone-progress.js} +6 -6
- package/server/dist/{code-activity.js → modules/code/runtime/code-activity.js} +1 -1
- package/server/dist/{code-explorer-router.js → modules/code/runtime/code-explorer-router.js} +5 -5
- package/server/dist/{file-provenance.js → modules/code/runtime/file-provenance.js} +1 -1
- package/server/dist/{file-story-manager.js → modules/code/runtime/file-story-manager.js} +2 -2
- package/server/dist/{file-story.js → modules/code/runtime/file-story.js} +2 -2
- package/server/dist/{file-summary-generator.js → modules/code/runtime/file-summary-generator.js} +3 -3
- package/server/dist/{file-summary-manager.js → modules/code/runtime/file-summary-manager.js} +3 -3
- package/server/dist/{project-code-discovery.js → modules/code/runtime/project-code-discovery.js} +2 -2
- package/server/dist/modules/conversations/domain/draft-stream.js +91 -0
- package/server/dist/modules/conversations/domain/recovery-context.js +101 -0
- package/server/dist/modules/conversations/index.js +10 -0
- package/server/dist/{chat-manager.js → modules/conversations/runtime/chat-manager.js} +32 -216
- package/server/dist/{context-budget.js → modules/conversations/runtime/context-budget.js} +1 -1
- package/server/dist/{explore-cwd-manager.js → modules/conversations/runtime/explore-cwd-manager.js} +1 -1
- package/server/dist/{explore-smash.js → modules/conversations/runtime/explore-smash.js} +1 -1
- package/server/dist/{explore-stdin-session.js → modules/conversations/runtime/explore-stdin-session.js} +1 -1
- package/server/dist/modules/delivery/adapters/decisions/chains.js +138 -0
- package/server/dist/modules/delivery/adapters/decisions/contracts.js +2 -0
- package/server/dist/modules/delivery/adapters/decisions/create.js +234 -0
- package/server/dist/modules/delivery/adapters/decisions/discard.js +251 -0
- package/server/dist/modules/delivery/adapters/decisions/dispatch.js +107 -0
- package/server/dist/modules/delivery/adapters/decisions/evidence.js +205 -0
- package/server/dist/modules/delivery/adapters/decisions/merge-local.js +338 -0
- package/server/dist/modules/delivery/adapters/decisions/metadata.js +109 -0
- package/server/dist/modules/delivery/adapters/decisions/observations.js +260 -0
- package/server/dist/modules/delivery/adapters/decisions/ownership.js +83 -0
- package/server/dist/modules/delivery/adapters/decisions/publish.js +242 -0
- package/server/dist/modules/delivery/adapters/decisions/recovery.js +425 -0
- package/server/dist/modules/delivery/adapters/decisions/retry.js +112 -0
- package/server/dist/modules/delivery/adapters/decisions/transitions.js +94 -0
- package/server/dist/modules/delivery/domain/decision-policy.js +50 -0
- package/server/dist/modules/delivery/domain/state.js +2 -0
- package/server/dist/modules/delivery/index.js +7 -0
- package/server/dist/{active-pr-continuation.js → modules/delivery/runtime/active-pr-continuation.js} +2 -2
- package/server/dist/{delivery-evidence.js → modules/delivery/runtime/delivery-evidence.js} +3 -3
- package/server/dist/{multi-repo-bases.js → modules/delivery/runtime/multi-repo-bases.js} +1 -1
- package/server/dist/{multi-repo-checkout.js → modules/delivery/runtime/multi-repo-checkout.js} +4 -4
- package/server/dist/{multi-repo-delivery.js → modules/delivery/runtime/multi-repo-delivery.js} +4 -4
- package/server/dist/{multi-repo-execution.js → modules/delivery/runtime/multi-repo-execution.js} +8 -8
- package/server/dist/{pr-body.js → modules/delivery/runtime/pr-body.js} +1 -1
- package/server/dist/{pr-follow-up-scope.js → modules/delivery/runtime/pr-follow-up-scope.js} +2 -2
- package/server/dist/{pr-follow-up.js → modules/delivery/runtime/pr-follow-up.js} +1 -1
- package/server/dist/{pr-naming.js → modules/delivery/runtime/pr-naming.js} +1 -1
- package/server/dist/{pr-publisher.js → modules/delivery/runtime/pr-publisher.js} +2 -2
- package/server/dist/{rail-isolated-launch.js → modules/delivery/runtime/rail-isolated-launch.js} +29 -27
- package/server/dist/{rail-launch-parser.js → modules/delivery/runtime/rail-launch-parser.js} +2 -2
- package/server/dist/{rail-merge-orchestrator.js → modules/delivery/runtime/rail-merge-orchestrator.js} +5 -5
- package/server/dist/modules/delivery/runtime/rail-pr-decision.js +12 -0
- package/server/dist/{rail-pr-delivery.js → modules/delivery/runtime/rail-pr-delivery.js} +1 -1
- package/server/dist/{rail-pr-store.js → modules/delivery/runtime/rail-pr-store.js} +2 -2
- package/server/dist/{rail-pr-ticket-effects.js → modules/delivery/runtime/rail-pr-ticket-effects.js} +3 -3
- package/server/dist/{rail-worktree-release.js → modules/delivery/runtime/rail-worktree-release.js} +4 -4
- package/server/dist/{rails-router.js → modules/delivery/runtime/rails-router.js} +66 -67
- package/server/dist/{review-packet.js → modules/delivery/runtime/review-packet.js} +3 -3
- package/server/dist/modules/execution/adapters/budget-storage.js +21 -0
- package/server/dist/modules/execution/adapters/usage-reader.js +38 -0
- package/server/dist/modules/execution/application/enforce-budget.js +14 -0
- package/server/dist/modules/execution/application/record-job-invocations.js +64 -0
- package/server/dist/modules/execution/application/recover-job-usage.js +200 -0
- package/server/dist/modules/execution/domain/job-accounting.js +2 -0
- package/server/dist/modules/execution/domain/scheduling.js +24 -0
- package/server/dist/modules/execution/domain/usage.js +21 -0
- package/server/dist/modules/execution/index.js +14 -0
- package/server/dist/modules/execution/ports.js +2 -0
- package/server/dist/{accept-ladder.js → modules/execution/runtime/accept-ladder.js} +1 -1
- package/server/dist/{interactive-job-session.js → modules/execution/runtime/interactive-job-session.js} +11 -11
- package/server/dist/{job-phase-breakdown.js → modules/execution/runtime/job-phase-breakdown.js} +1 -1
- package/server/dist/{queue-manager.js → modules/execution/runtime/queue-manager.js} +74 -491
- package/server/dist/{revision-seed.js → modules/execution/runtime/revision-seed.js} +1 -1
- package/server/dist/{spawn-lifecycle.js → modules/execution/runtime/spawn-lifecycle.js} +3 -3
- package/server/dist/{stuck-run-detector.js → modules/execution/runtime/stuck-run-detector.js} +1 -1
- package/server/dist/{loop-command-catalog.js → modules/loops/runtime/loop-command-catalog.js} +1 -1
- package/server/dist/{loop-executors.js → modules/loops/runtime/loop-executors.js} +17 -17
- package/server/dist/{loop-factory.js → modules/loops/runtime/loop-factory.js} +2 -21
- package/server/dist/{loop-graph.js → modules/loops/runtime/loop-graph.js} +25 -0
- package/server/dist/{loop-role-engines.js → modules/loops/runtime/loop-role-engines.js} +4 -4
- package/server/dist/{loop-run-manager.js → modules/loops/runtime/loop-run-manager.js} +101 -26
- package/server/dist/{loop-runs-store.js → modules/loops/runtime/loop-runs-store.js} +1 -1
- package/server/dist/{loop-shell-invocation.js → modules/loops/runtime/loop-shell-invocation.js} +2 -2
- package/server/dist/{loop-step-idle.js → modules/loops/runtime/loop-step-idle.js} +1 -1
- package/server/dist/{loop-templates.js → modules/loops/runtime/loop-templates.js} +24 -29
- package/server/dist/{loops-router.js → modules/loops/runtime/loops-router.js} +2 -2
- package/server/dist/{agent-chat-manager.js → modules/missions/runtime/agent-chat-manager.js} +19 -19
- package/server/dist/{agent-chat-router.js → modules/missions/runtime/agent-chat-router.js} +6 -6
- package/server/dist/{agent-context-resolver.js → modules/missions/runtime/agent-context-resolver.js} +8 -8
- package/server/dist/{agent-fence-promotion.js → modules/missions/runtime/agent-fence-promotion.js} +1 -1
- package/server/dist/{agent-input-store.js → modules/missions/runtime/agent-input-store.js} +1 -1
- package/server/dist/{agent-operator-prompt.js → modules/missions/runtime/agent-operator-prompt.js} +17 -7
- package/server/dist/{agent-spec-framing.js → modules/missions/runtime/agent-spec-framing.js} +4 -4
- package/server/dist/{agent-steering.js → modules/missions/runtime/agent-steering.js} +1 -1
- package/server/dist/{mission-run-notify.js → modules/missions/runtime/mission-run-notify.js} +1 -1
- package/server/dist/modules/project-settings/adapters/http.js +24 -0
- package/server/dist/modules/project-settings/adapters/sqlite.js +120 -0
- package/server/dist/modules/project-settings/application.js +11 -0
- package/server/dist/modules/project-settings/domain.js +95 -0
- package/server/dist/modules/project-settings/index.js +11 -0
- package/server/dist/modules/project-settings/ports.js +2 -0
- package/server/dist/{contract-refine-runner.js → modules/specs/runtime/contract-refine-runner.js} +12 -12
- package/server/dist/{proposal-manager.js → modules/specs/runtime/proposal-manager.js} +8 -8
- package/server/dist/{smash-runner.js → modules/specs/runtime/smash-runner.js} +26 -58
- package/server/dist/{spec-addenda-core.js → modules/specs/runtime/spec-addenda-core.js} +2 -2
- package/server/dist/{spec-addenda.js → modules/specs/runtime/spec-addenda.js} +3 -3
- package/server/dist/{spec-launcher-manager.js → modules/specs/runtime/spec-launcher-manager.js} +8 -8
- package/server/dist/{spec-models.js → modules/specs/runtime/spec-models.js} +1 -1
- package/server/dist/{ticket-watcher.js → modules/specs/runtime/ticket-watcher.js} +1 -1
- package/server/dist/{background-process-control.js → modules/terminals/runtime/background-process-control.js} +1 -1
- package/server/dist/{background-process-service.js → modules/terminals/runtime/background-process-service.js} +3 -3
- package/server/dist/{background-process-store.js → modules/terminals/runtime/background-process-store.js} +1 -1
- package/server/dist/{background-windows-bootstrap.js → modules/terminals/runtime/background-windows-bootstrap.js} +3 -3
- package/server/dist/{terminal-manager.js → modules/terminals/runtime/terminal-manager.js} +3 -3
- package/server/dist/project-git.js +1 -1
- package/server/dist/project-profile-support.js +32 -0
- package/server/dist/project-registry.js +34 -40
- package/server/dist/project-router-background-processes.js +1 -1
- package/server/dist/project-router-chat.js +6 -6
- package/server/dist/project-router-git.js +1 -1
- package/server/dist/project-router-helpers.js +2 -2
- package/server/dist/project-router-jobs.js +14 -12
- package/server/dist/project-router-loop-runs.js +12 -12
- package/server/dist/project-router-settings.js +15 -75
- package/server/dist/project-router-setup.js +2 -2
- package/server/dist/project-router-spending.js +4 -4
- package/server/dist/project-router-terminals.js +4 -4
- package/server/dist/project-router-tickets.js +14 -14
- package/server/dist/project-router.js +13 -13
- package/server/dist/providers/codex-adapter.js +3 -3
- package/server/dist/providers/gemini-adapter.js +1 -1
- package/server/dist/providers/telemetry-env.js +55 -0
- package/server/dist/runtime-role-prompts-router.js +2 -2
- package/server/dist/setup-manager.js +2 -48
- package/server/dist/shared/git-branch-name.js +16 -0
- package/server/dist/transient-children.js +3 -3
- package/server/dist/util/distribute-int.js +33 -0
- package/client/dist/assets/ReviewPacketPage-D-UjTef3.js +0 -4
- package/client/dist/assets/index-BAtqmAZR.css +0 -2
- package/client/dist/assets/packet-CjS_478C.js +0 -1
- package/client/dist/assets/packet-D69dKsHN.js +0 -1
- package/client/dist/assets/packet-D9rU6Oxo.js +0 -1
- package/client/dist/assets/packet-DMDFoamg.js +0 -1
- package/client/dist/assets/packet-Dd2RMs1h.js +0 -1
- package/client/dist/assets/packet-DjC9OibC.js +0 -1
- package/client/dist/assets/packet-DwPtJoDz.js +0 -1
- package/client/dist/assets/packet-ceahDg8_.js +0 -1
- package/server/dist/rail-pr-decision.js +0 -2377
- package/server/dist/ticket-broadcast.js +0 -47
- /package/server/dist/{ai-invocations.js → modules/accounting/runtime/ai-invocations.js} +0 -0
- /package/server/dist/{codex-otel-bridge.js → modules/accounting/runtime/codex-otel-bridge.js} +0 -0
- /package/server/dist/{metrics.js → modules/accounting/runtime/metrics.js} +0 -0
- /package/server/dist/{telemetry-export.js → modules/accounting/runtime/telemetry-export.js} +0 -0
- /package/server/dist/{agent-runtime-accounting.js → modules/agent-runtime/runtime/agent-runtime-accounting.js} +0 -0
- /package/server/dist/{agent-runtime-controls-router.js → modules/agent-runtime/runtime/agent-runtime-controls-router.js} +0 -0
- /package/server/dist/{agent-runtime-events.js → modules/agent-runtime/runtime/agent-runtime-events.js} +0 -0
- /package/server/dist/{agent-runtime-history.js → modules/agent-runtime/runtime/agent-runtime-history.js} +0 -0
- /package/server/dist/{agent-runtime-metrics.js → modules/agent-runtime/runtime/agent-runtime-metrics.js} +0 -0
- /package/server/dist/{agent-runtime-package.js → modules/agent-runtime/runtime/agent-runtime-package.js} +0 -0
- /package/server/dist/{agent-runtime-repositories.js → modules/agent-runtime/runtime/agent-runtime-repositories.js} +0 -0
- /package/server/dist/{agent-runtime-verification-suggestions.js → modules/agent-runtime/runtime/agent-runtime-verification-suggestions.js} +0 -0
- /package/server/dist/{agent-refine-db.js → modules/agents/runtime/agent-refine-db.js} +0 -0
- /package/server/dist/{browser-capture-types.js → modules/browser/runtime/browser-capture-types.js} +0 -0
- /package/server/dist/{browser-context-pool.js → modules/browser/runtime/browser-context-pool.js} +0 -0
- /package/server/dist/{browser-network.js → modules/browser/runtime/browser-network.js} +0 -0
- /package/server/dist/{browser-viewport.js → modules/browser/runtime/browser-viewport.js} +0 -0
- /package/server/dist/{blueprint-render.js → modules/builder/runtime/blueprint-render.js} +0 -0
- /package/server/dist/{blueprint-spec-fixtures.js → modules/builder/runtime/blueprint-spec-fixtures.js} +0 -0
- /package/server/dist/{blueprint-store.js → modules/builder/runtime/blueprint-store.js} +0 -0
- /package/server/dist/{blueprint-types.js → modules/builder/runtime/blueprint-types.js} +0 -0
- /package/server/dist/{builder-cwd-manager.js → modules/builder/runtime/builder-cwd-manager.js} +0 -0
- /package/server/dist/{milestone-chain-store.js → modules/builder/runtime/milestone-chain-store.js} +0 -0
- /package/server/dist/{changes-reader.js → modules/code/runtime/changes-reader.js} +0 -0
- /package/server/dist/{context-scope.js → modules/conversations/runtime/context-scope.js} +0 -0
- /package/server/dist/{explore-contract-refine.js → modules/conversations/runtime/explore-contract-refine.js} +0 -0
- /package/server/dist/{explore-draft-title.js → modules/conversations/runtime/explore-draft-title.js} +0 -0
- /package/server/dist/{merge-manager.js → modules/delivery/runtime/merge-manager.js} +0 -0
- /package/server/dist/{multi-repo-execution-store.js → modules/delivery/runtime/multi-repo-execution-store.js} +0 -0
- /package/server/dist/{pr-lifecycle.js → modules/delivery/runtime/pr-lifecycle.js} +0 -0
- /package/server/dist/{rail-isolation.js → modules/delivery/runtime/rail-isolation.js} +0 -0
- /package/server/dist/{rail-pr-recovery-git.js → modules/delivery/runtime/rail-pr-recovery-git.js} +0 -0
- /package/server/dist/{rail-worktrees-store.js → modules/delivery/runtime/rail-worktrees-store.js} +0 -0
- /package/server/dist/{rails-store.js → modules/delivery/runtime/rails-store.js} +0 -0
- /package/server/dist/{job-listing.js → modules/execution/runtime/job-listing.js} +0 -0
- /package/server/dist/{job-spawn-idempotency.js → modules/execution/runtime/job-spawn-idempotency.js} +0 -0
- /package/server/dist/{run-duration-stats.js → modules/execution/runtime/run-duration-stats.js} +0 -0
- /package/server/dist/{verification-sentinel.js → modules/execution/runtime/verification-sentinel.js} +0 -0
- /package/server/dist/{loop-constants.js → modules/loops/runtime/loop-constants.js} +0 -0
- /package/server/dist/{loop-decider.js → modules/loops/runtime/loop-decider.js} +0 -0
- /package/server/dist/{loop-effect.js → modules/loops/runtime/loop-effect.js} +0 -0
- /package/server/dist/{loop-preview.js → modules/loops/runtime/loop-preview.js} +0 -0
- /package/server/dist/{loop-templates-ported.js → modules/loops/runtime/loop-templates-ported.js} +0 -0
- /package/server/dist/{loops-store.js → modules/loops/runtime/loops-store.js} +0 -0
- /package/server/dist/{agent-chat-registry.js → modules/missions/runtime/agent-chat-registry.js} +0 -0
- /package/server/dist/{agent-cwd-manager.js → modules/missions/runtime/agent-cwd-manager.js} +0 -0
- /package/server/dist/{agent-failure-briefing.js → modules/missions/runtime/agent-failure-briefing.js} +0 -0
- /package/server/dist/{agent-tier.js → modules/missions/runtime/agent-tier.js} +0 -0
- /package/server/dist/{spec-contract-prompt.js → modules/specs/runtime/spec-contract-prompt.js} +0 -0
- /package/server/dist/{spec-draft-parser.js → modules/specs/runtime/spec-draft-parser.js} +0 -0
- /package/server/dist/{ticket-store.js → modules/specs/runtime/ticket-store.js} +0 -0
- /package/server/dist/{terminal-marks-store.js → modules/terminals/runtime/terminal-marks-store.js} +0 -0
- /package/server/dist/{terminal-osc-parser.js → modules/terminals/runtime/terminal-osc-parser.js} +0 -0
- /package/server/dist/{terminal-settings.js → modules/terminals/runtime/terminal-settings.js} +0 -0
|
@@ -40,7 +40,7 @@ function buildRevisionSeed(input) {
|
|
|
40
40
|
const specs = (input.specSnapshot ?? []).length > 0
|
|
41
41
|
? (input.specSnapshot ?? []).map((entry) => [
|
|
42
42
|
`### #${entry.ticketId} ${entry.title ?? '(untitled)'}`,
|
|
43
|
-
entry.description ? clamp(entry.description, exports.SEED_SPEC_BODY_CAP) : '(no description recorded)',
|
|
43
|
+
...(input.includeSpecBody === false ? [] : [entry.description ? clamp(entry.description, exports.SEED_SPEC_BODY_CAP) : '(no description recorded)']),
|
|
44
44
|
].join('\n')).join('\n\n')
|
|
45
45
|
: input.ticketIds.map((id) => `### #${id}\n(spec text was not captured at launch)`).join('\n\n');
|
|
46
46
|
return [
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.runAiCliInvocation = runAiCliInvocation;
|
|
16
16
|
const node_readline_1 = require("node:readline");
|
|
17
|
-
const win_spawn_1 = require("
|
|
18
|
-
const cli_prompt_1 = require("
|
|
19
|
-
const runtime_1 = require("
|
|
17
|
+
const win_spawn_1 = require("../../../util/win-spawn");
|
|
18
|
+
const cli_prompt_1 = require("../../../util/cli-prompt");
|
|
19
|
+
const runtime_1 = require("../../../providers/runtime");
|
|
20
20
|
const STDERR_TAIL_CAP = 64 * 1024;
|
|
21
21
|
/**
|
|
22
22
|
* Run one AI-CLI invocation: spawn → stream → settle. Resolves exactly once on
|
package/server/dist/{stuck-run-detector.js → modules/execution/runtime/stuck-run-detector.js}
RENAMED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.StuckRunDetector = exports.STUCK_SWEEP_INTERVAL_MS = exports.STUCK_FLOOR_MS = void 0;
|
|
4
4
|
exports.resolveStuckThresholdMs = resolveStuckThresholdMs;
|
|
5
5
|
exports.findStuckCandidates = findStuckCandidates;
|
|
6
|
-
const loop_runs_store_1 = require("
|
|
6
|
+
const loop_runs_store_1 = require("../../loops/runtime/loop-runs-store");
|
|
7
7
|
/** Never notify sooner than this, however the threshold is configured. */
|
|
8
8
|
exports.STUCK_FLOOR_MS = 10 * 60 * 1000;
|
|
9
9
|
/** How often the sweep runs while the server is up. */
|
package/server/dist/{loop-command-catalog.js → modules/loops/runtime/loop-command-catalog.js}
RENAMED
|
@@ -26,7 +26,7 @@ exports.expandCommands = expandCommands;
|
|
|
26
26
|
exports.dominantTicketScope = dominantTicketScope;
|
|
27
27
|
exports.referencesClaudeOnlyCommand = referencesClaudeOnlyCommand;
|
|
28
28
|
exports.referencesUnsupportedProviderCommand = referencesUnsupportedProviderCommand;
|
|
29
|
-
const registry_1 = require("
|
|
29
|
+
const registry_1 = require("../../../providers/registry");
|
|
30
30
|
const loop_constants_1 = require("./loop-constants");
|
|
31
31
|
/** The autonomous prompt a `native` command (Freestyle) expands to for the
|
|
32
32
|
* LoopRunManager path. Factory Freestyle loops route to QueueManager's real
|
|
@@ -9,30 +9,30 @@ exports.createLoopExecutors = createLoopExecutors;
|
|
|
9
9
|
* from coverage; the engine's traversal/decision logic is unit-tested against
|
|
10
10
|
* fake executors in `loop-run-manager.test.ts`.
|
|
11
11
|
*/
|
|
12
|
-
const core_completion_1 = require("
|
|
13
|
-
const core_execution_1 = require("
|
|
14
|
-
const agent_runtime_bridge_1 = require("
|
|
15
|
-
const codex_spawn_1 = require("
|
|
12
|
+
const core_completion_1 = require("../../../core-completion");
|
|
13
|
+
const core_execution_1 = require("../../../core-execution");
|
|
14
|
+
const agent_runtime_bridge_1 = require("../../agent-runtime/runtime/agent-runtime-bridge");
|
|
15
|
+
const codex_spawn_1 = require("../../../plugins/codex-spawn");
|
|
16
16
|
const node_child_process_1 = require("node:child_process");
|
|
17
17
|
const node_crypto_1 = require("node:crypto");
|
|
18
18
|
const node_fs_1 = require("node:fs");
|
|
19
19
|
const node_path_1 = require("node:path");
|
|
20
|
-
const win_spawn_1 = require("
|
|
21
|
-
const providers_1 = require("
|
|
22
|
-
const registry_1 = require("
|
|
23
|
-
const workspace_manager_1 = require("
|
|
24
|
-
const claude_trust_1 = require("
|
|
25
|
-
const spawn_lifecycle_1 = require("
|
|
26
|
-
const result_event_1 = require("
|
|
27
|
-
const terminal_result_1 = require("
|
|
28
|
-
const claude_background_tasks_1 = require("
|
|
20
|
+
const win_spawn_1 = require("../../../util/win-spawn");
|
|
21
|
+
const providers_1 = require("../../../providers");
|
|
22
|
+
const registry_1 = require("../../../providers/registry");
|
|
23
|
+
const workspace_manager_1 = require("../../../workspace-manager");
|
|
24
|
+
const claude_trust_1 = require("../../../claude-trust");
|
|
25
|
+
const spawn_lifecycle_1 = require("../../execution/runtime/spawn-lifecycle");
|
|
26
|
+
const result_event_1 = require("../../accounting/runtime/result-event");
|
|
27
|
+
const terminal_result_1 = require("../../../providers/terminal-result");
|
|
28
|
+
const claude_background_tasks_1 = require("../../../providers/claude-background-tasks");
|
|
29
29
|
const loop_constants_1 = require("./loop-constants");
|
|
30
30
|
const loop_decider_1 = require("./loop-decider");
|
|
31
|
-
const rail_isolation_1 = require("
|
|
32
|
-
const repo_map_1 = require("
|
|
33
|
-
const feature_flags_1 = require("
|
|
31
|
+
const rail_isolation_1 = require("../../delivery/runtime/rail-isolation");
|
|
32
|
+
const repo_map_1 = require("../../../repo-map");
|
|
33
|
+
const feature_flags_1 = require("../../../feature-flags");
|
|
34
34
|
const loop_step_idle_1 = require("./loop-step-idle");
|
|
35
|
-
const runtime_1 = require("
|
|
35
|
+
const runtime_1 = require("../../../providers/runtime");
|
|
36
36
|
const loop_shell_invocation_1 = require("./loop-shell-invocation");
|
|
37
37
|
// Per-step wall-clock caps so a single hung step can't block the engine's
|
|
38
38
|
// overall deadline check (which only runs between nodes).
|
|
@@ -42,7 +42,7 @@ const SDD_QUICK_OPENSPEC_FACTORY = {
|
|
|
42
42
|
mode: 'loop',
|
|
43
43
|
graph: (0, loop_templates_1.opsxLifecycleGraph)(),
|
|
44
44
|
};
|
|
45
|
-
/**
|
|
45
|
+
/** Legacy persisted id. Resolves to Quick SDD; no Revision loop is listed or run. */
|
|
46
46
|
exports.FACTORY_REVISION_LOOP_ID = 'factory:revision';
|
|
47
47
|
exports.FACTORY_LOOPS = [
|
|
48
48
|
{
|
|
@@ -70,30 +70,11 @@ exports.FACTORY_LOOPS = [
|
|
|
70
70
|
requiredCapability: 'freestyle',
|
|
71
71
|
graph: (0, loop_templates_1.fixLoopGraph)(['{{cmd:freestyle}}'], GREEN_GOAL, FACTORY_MAX_ITERATIONS, FACTORY_LOOP_TIMEOUT_MIN, FACTORY_AI_STEP_TIMEOUT_MIN),
|
|
72
72
|
},
|
|
73
|
-
{
|
|
74
|
-
id: exports.FACTORY_REVISION_LOOP_ID,
|
|
75
|
-
name: 'Revision',
|
|
76
|
-
// Listed so the platform's behaviour is discoverable, but `launchable:false`:
|
|
77
|
-
// the app runs this itself when a user asks for a change to a delivery. Its
|
|
78
|
-
// prompt consumes `{{const:REVISION_REQUEST}}`, and an unresolved constant
|
|
79
|
-
// renders as an EMPTY string, so a hand-launched run would have a blank
|
|
80
|
-
// central instruction. The launch route refuses it; the prompt guards too.
|
|
81
|
-
launchable: false,
|
|
82
|
-
description: "Apply the ONE change the user asked for on top of work already delivered, then run one independent reviewer-owned verification gate and refine until green. No re-planning. Runs automatically when you ask for changes on a review — it is not started by hand.",
|
|
83
|
-
mode: 'loop',
|
|
84
|
-
// Revision is the ONLY factory loop that swaps the generic `{{cmd:verify}}`
|
|
85
|
-
// gate: `{{cmd:revision-verify}}` owns reviewer re-grading AND the full pass
|
|
86
|
-
// of record in ONE read-only step, so the mutator no longer runs sr-reviewer
|
|
87
|
-
// itself and no second repository-wide gate follows it. The trailing `true`
|
|
88
|
-
// makes verify/fix run in a FRESH provider session — the gate's verdict and
|
|
89
|
-
// its confidence artifact then describe the candidate on disk rather than
|
|
90
|
-
// the mutator's own account of it.
|
|
91
|
-
graph: (0, loop_templates_1.fixLoopGraph)(['{{cmd:revise}}'], GREEN_GOAL, FACTORY_MAX_ITERATIONS, FACTORY_LOOP_TIMEOUT_MIN, FACTORY_AI_STEP_TIMEOUT_MIN, '{{cmd:revision-verify}}', true),
|
|
92
|
-
},
|
|
93
73
|
SDD_QUICK_OPENSPEC_FACTORY,
|
|
94
74
|
];
|
|
95
75
|
const FACTORY_ALIASES = new Map([
|
|
96
76
|
['factory:openspec', SDD_QUICK_OPENSPEC_FACTORY],
|
|
77
|
+
[exports.FACTORY_REVISION_LOOP_ID, SDD_QUICK_OPENSPEC_FACTORY],
|
|
97
78
|
]);
|
|
98
79
|
const FACTORY_BY_ID = new Map([
|
|
99
80
|
...exports.FACTORY_LOOPS.map((f) => [f.id, f]),
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
exports.assertLoopShellRepositoryScope = assertLoopShellRepositoryScope;
|
|
14
|
+
exports.assertLoopFailureRecovery = assertLoopFailureRecovery;
|
|
14
15
|
exports.emptyLoopGraph = emptyLoopGraph;
|
|
15
16
|
exports.validateLoopGraph = validateLoopGraph;
|
|
16
17
|
exports.nodesById = nodesById;
|
|
@@ -27,6 +28,24 @@ function assertLoopShellRepositoryScope(graph, repositoryIds) {
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
}
|
|
31
|
+
/** Recovery is bounded and may only repeat a phase or repair artifacts before revalidation. */
|
|
32
|
+
function assertLoopFailureRecovery(graph) {
|
|
33
|
+
for (const node of graph.nodes) {
|
|
34
|
+
const recovery = node.data?.failureRecovery;
|
|
35
|
+
if (recovery === undefined)
|
|
36
|
+
continue;
|
|
37
|
+
const target = graph.nodes.find((candidate) => candidate.id === recovery?.target);
|
|
38
|
+
if (!recovery || node.data?.stopOnFailure !== true ||
|
|
39
|
+
!['ai-step', 'shell'].includes(node.type) ||
|
|
40
|
+
recovery.maxRetries !== 1 ||
|
|
41
|
+
(recovery.artifactOnly !== undefined && typeof recovery.artifactOnly !== 'boolean') ||
|
|
42
|
+
!target || (target.id !== node.id &&
|
|
43
|
+
!(node.type === 'shell' && target.type === 'ai-step' && recovery.artifactOnly === true)) ||
|
|
44
|
+
(recovery.artifactOnly === true && (target?.type !== 'ai-step' || target.data?.operation === 'core-implementation' || target.data?.stopOnFailure !== true))) {
|
|
45
|
+
throw new Error(`Invalid failure recovery for step ${node.id}: use one retry of this phase or an AI artifact repair.`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
30
49
|
/** A minimal, structurally-valid empty graph (used to seed a new Draft). */
|
|
31
50
|
function emptyLoopGraph() {
|
|
32
51
|
return { nodes: [], edges: [], config: { maxIterations: 10, timeoutMinutes: 30 } };
|
|
@@ -70,6 +89,12 @@ function validateLoopGraph(graph) {
|
|
|
70
89
|
errors.push({ code: 'INVALID_NODE', nodeId: node.id, message: 'A shell repositoryId must be a non-empty registered repository id.' });
|
|
71
90
|
}
|
|
72
91
|
}
|
|
92
|
+
try {
|
|
93
|
+
assertLoopFailureRecovery(graph);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
errors.push({ code: 'INVALID_NODE', message: error.message });
|
|
97
|
+
}
|
|
73
98
|
// ── Start cardinality ──────────────────────────────────────────────────────
|
|
74
99
|
const starts = nodes.filter((n) => n.type === 'start');
|
|
75
100
|
if (starts.length === 0) {
|
|
@@ -29,10 +29,10 @@ exports.resolveLoopRoleEngine = resolveLoopRoleEngine;
|
|
|
29
29
|
// `agent-runtime.json`; absent ⇒ every loop role inherits the project's primary.
|
|
30
30
|
const node_fs_1 = require("node:fs");
|
|
31
31
|
const node_path_1 = __importDefault(require("node:path"));
|
|
32
|
-
const providers_1 = require("
|
|
33
|
-
const spec_models_1 = require("
|
|
34
|
-
const workspace_resolution_1 = require("
|
|
35
|
-
const provider_selection_1 = require("
|
|
32
|
+
const providers_1 = require("../../../providers");
|
|
33
|
+
const spec_models_1 = require("../../specs/runtime/spec-models");
|
|
34
|
+
const workspace_resolution_1 = require("../../../workspace-resolution");
|
|
35
|
+
const provider_selection_1 = require("../../../provider-selection");
|
|
36
36
|
/** The rail engine value meaning "per-role engines, no flattening override". */
|
|
37
37
|
exports.ROLES_ENGINE = 'roles';
|
|
38
38
|
exports.LOOP_ROLES = ['verifier', 'decider'];
|
|
@@ -10,29 +10,31 @@ exports.seedChangeId = seedChangeId;
|
|
|
10
10
|
exports.openspecChangeState = openspecChangeState;
|
|
11
11
|
exports.extractChangeId = extractChangeId;
|
|
12
12
|
exports.recoverOrphanLoopStepAccounting = recoverOrphanLoopStepAccounting;
|
|
13
|
+
const crypto_1 = require("crypto");
|
|
14
|
+
const spec_addenda_core_1 = require("../../specs/runtime/spec-addenda-core");
|
|
13
15
|
const path_1 = __importDefault(require("path"));
|
|
14
16
|
const fs_1 = __importDefault(require("fs"));
|
|
15
|
-
const agent_runtime_events_1 = require("
|
|
16
|
-
const agent_runtime_settings_1 = require("
|
|
17
|
-
const multi_repo_execution_store_1 = require("
|
|
18
|
-
const win_spawn_1 = require("
|
|
19
|
-
const db_1 = require("
|
|
20
|
-
const interactive_job_session_1 = require("
|
|
17
|
+
const agent_runtime_events_1 = require("../../agent-runtime/runtime/agent-runtime-events");
|
|
18
|
+
const agent_runtime_settings_1 = require("../../agent-runtime/runtime/agent-runtime-settings");
|
|
19
|
+
const multi_repo_execution_store_1 = require("../../delivery/runtime/multi-repo-execution-store");
|
|
20
|
+
const win_spawn_1 = require("../../../util/win-spawn");
|
|
21
|
+
const db_1 = require("../../../db");
|
|
22
|
+
const interactive_job_session_1 = require("../../execution/runtime/interactive-job-session");
|
|
21
23
|
const loop_graph_1 = require("./loop-graph");
|
|
22
24
|
const loop_command_catalog_1 = require("./loop-command-catalog");
|
|
23
25
|
const loop_constants_1 = require("./loop-constants");
|
|
24
26
|
const loop_step_idle_1 = require("./loop-step-idle");
|
|
25
27
|
const loop_decider_1 = require("./loop-decider");
|
|
26
28
|
const loop_runs_store_1 = require("./loop-runs-store");
|
|
27
|
-
const ai_invocations_1 = require("
|
|
28
|
-
const provider_limit_1 = require("
|
|
29
|
-
const ids_1 = require("
|
|
30
|
-
const providers_1 = require("
|
|
31
|
-
const agent_runtime_accounting_1 = require("
|
|
32
|
-
const runtime_1 = require("
|
|
33
|
-
const result_event_1 = require("
|
|
34
|
-
const rails_store_1 = require("
|
|
35
|
-
const verification_sentinel_1 = require("
|
|
29
|
+
const ai_invocations_1 = require("../../accounting/runtime/ai-invocations");
|
|
30
|
+
const provider_limit_1 = require("../../../provider-limit");
|
|
31
|
+
const ids_1 = require("../../../ids");
|
|
32
|
+
const providers_1 = require("../../../providers");
|
|
33
|
+
const agent_runtime_accounting_1 = require("../../agent-runtime/runtime/agent-runtime-accounting");
|
|
34
|
+
const runtime_1 = require("../../../providers/runtime");
|
|
35
|
+
const result_event_1 = require("../../accounting/runtime/result-event");
|
|
36
|
+
const rails_store_1 = require("../../delivery/runtime/rails-store");
|
|
37
|
+
const verification_sentinel_1 = require("../../execution/runtime/verification-sentinel");
|
|
36
38
|
const IMPLEMENT_CMD_TOKEN_RE = /\{\{\s*cmd:(?:implement|batch)\s*\}\}/;
|
|
37
39
|
const IMPLEMENT_CMD_TEXT_RE = /(?:^|\s)(?:\/(?:specrails:|sr:)?(?:implement|batch-implement)|\$(?:implement|batch-implement))\b/;
|
|
38
40
|
const LOOP_BLOCKED_LINE_RE = /(?:^|\n)\s*LOOP_BLOCKED:\s*(.+?)(?:\n|$)/i;
|
|
@@ -141,9 +143,20 @@ function resolveRunVars(text, vars) {
|
|
|
141
143
|
return text.replace(RUN_TOKEN_RE, (_m, key) => vars[key] ?? '');
|
|
142
144
|
}
|
|
143
145
|
const CHANGE_NAME_RE = /^[a-z0-9][a-z0-9._-]{0,99}$/i;
|
|
144
|
-
/** The
|
|
145
|
-
*
|
|
146
|
+
/** The authoritative OpenSpec target for a launch.
|
|
147
|
+
* Addenda/delivery deltas get a run-specific name; ordinary launches use the
|
|
148
|
+
* follow-up's declared name, else the spec's `openspecChangeName`. */
|
|
146
149
|
function seedChangeId(req) {
|
|
150
|
+
if (req.addenda?.ids.length) {
|
|
151
|
+
// A new generation never picks an old/archived proposal, even when the
|
|
152
|
+
// ticket metadata still names it. Resuming the same run keeps its target.
|
|
153
|
+
const hash = (0, crypto_1.createHash)('sha256').update(JSON.stringify([req.runId, req.addenda.ids, req.addenda.briefing])).digest('hex').slice(0, 20);
|
|
154
|
+
return { id: `spec-addenda-${hash}`, source: 'addenda' };
|
|
155
|
+
}
|
|
156
|
+
if (req.constants?.REVISION_REQUEST) {
|
|
157
|
+
const hash = (0, crypto_1.createHash)('sha256').update(JSON.stringify([req.runId, req.constants.REVISION_REQUEST])).digest('hex').slice(0, 20);
|
|
158
|
+
return { id: `delivery-change-${hash}`, source: 'revision' };
|
|
159
|
+
}
|
|
147
160
|
const fromFollowUp = typeof req.followUp?.openspecChangeName === 'string' ? req.followUp.openspecChangeName.trim() : '';
|
|
148
161
|
if (fromFollowUp && CHANGE_NAME_RE.test(fromFollowUp))
|
|
149
162
|
return { id: fromFollowUp, source: 'followUp' };
|
|
@@ -605,6 +618,13 @@ class LoopRunManager {
|
|
|
605
618
|
// Later fresh steps must verify the admitted spec, even if its caller or
|
|
606
619
|
// backlog changes while the implementation is running.
|
|
607
620
|
req = { ...req, runtimeProviderOverride: (0, agent_runtime_settings_1.validateRuntimeProviderOverride)(req.runtimeProviderOverride), graph: structuredClone(req.graph) };
|
|
621
|
+
(0, loop_graph_1.assertLoopFailureRecovery)(req.graph);
|
|
622
|
+
if (req.addenda)
|
|
623
|
+
req = { ...req, addenda: structuredClone(req.addenda) };
|
|
624
|
+
if (req.followUp)
|
|
625
|
+
req = { ...req, followUp: structuredClone(req.followUp) };
|
|
626
|
+
if (req.constants)
|
|
627
|
+
req = { ...req, constants: structuredClone(req.constants) };
|
|
608
628
|
if (req.spec)
|
|
609
629
|
req = { ...req, spec: structuredClone(req.spec) };
|
|
610
630
|
if (req.executionManifest)
|
|
@@ -902,7 +922,7 @@ class LoopRunManager {
|
|
|
902
922
|
// change in one go (run 644eb404) never mentioned an active path, so the
|
|
903
923
|
// validate/archive shell steps refused to run and a green implementation
|
|
904
924
|
// settled `failed`. A step's own capture still wins when nothing is seeded.
|
|
905
|
-
const seededChangeId = seedChangeId(req);
|
|
925
|
+
const seededChangeId = seedChangeId({ ...req, runId });
|
|
906
926
|
if (seededChangeId) {
|
|
907
927
|
runVars.changeId = seededChangeId.id;
|
|
908
928
|
logLine(`↪ OpenSpec change id seeded from ${seededChangeId.source}: ${seededChangeId.id}`);
|
|
@@ -1087,6 +1107,27 @@ class LoopRunManager {
|
|
|
1087
1107
|
});
|
|
1088
1108
|
return decision;
|
|
1089
1109
|
};
|
|
1110
|
+
const recoveryCounts = new Map();
|
|
1111
|
+
let phaseRecovery;
|
|
1112
|
+
const recoverPhase = (node, detail, previousFailure) => {
|
|
1113
|
+
const policy = node.data?.failureRecovery;
|
|
1114
|
+
if (!policy || phaseRecovery || this._cancelled.has(runId) ||
|
|
1115
|
+
(recoveryCounts.get(node.id) ?? 0) >= policy.maxRetries)
|
|
1116
|
+
return undefined;
|
|
1117
|
+
recoveryCounts.set(node.id, (recoveryCounts.get(node.id) ?? 0) + 1);
|
|
1118
|
+
phaseRecovery = { failedId: node.id, target: policy.target, detail: truncate(detail, 4000), artifactOnly: policy.artifactOnly === true };
|
|
1119
|
+
passFailed = previousFailure;
|
|
1120
|
+
emitRunEvent('loop_phase_recovery', { nodeId: node.id, target: policy.target, attempt: recoveryCounts.get(node.id) });
|
|
1121
|
+
logLine(`↪ Recovering phase ${node.id} once; preserving completed phases and the current change.`);
|
|
1122
|
+
return policy.target;
|
|
1123
|
+
};
|
|
1124
|
+
const afterPhase = (nodeId, successor) => {
|
|
1125
|
+
if (phaseRecovery?.target !== nodeId)
|
|
1126
|
+
return successor;
|
|
1127
|
+
const failedId = phaseRecovery.failedId;
|
|
1128
|
+
phaseRecovery = undefined;
|
|
1129
|
+
return failedId === nodeId ? successor : failedId;
|
|
1130
|
+
};
|
|
1090
1131
|
const firstStepId = start ? req.graph.edges.find((e) => e.source === start.id)?.target : undefined;
|
|
1091
1132
|
try {
|
|
1092
1133
|
let nodeId = start?.id;
|
|
@@ -1144,16 +1185,24 @@ class LoopRunManager {
|
|
|
1144
1185
|
// NATIVE per-provider invocation (claude `/specrails:implement #<id>
|
|
1145
1186
|
// --yes`, codex `$implement #<id> --yes`) — then resolve `{{spec.*}}`
|
|
1146
1187
|
// data tokens and finally `{{const:*}}` library constants.
|
|
1147
|
-
const
|
|
1188
|
+
const priorPhaseFailure = passFailed;
|
|
1189
|
+
const repair = phaseRecovery?.target === node.id ? phaseRecovery : undefined;
|
|
1190
|
+
const rawTemplate = repair?.artifactOnly
|
|
1191
|
+
? 'Repair ONLY the OpenSpec artifacts at openspec/changes/{{run.changeId}}/ using the validation diagnostics below. Preserve requirements and acceptance criteria. Do not edit implementation code, run repository tests, archive, create a new change, or expand scope. {{const:GUARDRAILS}}'
|
|
1192
|
+
: String(node.data?.prompt ?? '');
|
|
1148
1193
|
const requiresCoreCompletion = node.data?.operation === 'core-implementation' || /\{\{\s*cmd:(?:implement|batch)\s*\}\}/.test(rawTemplate)
|
|
1149
1194
|
|| /^\s*(?:\/specrails:|\/skill:specrails-|\$)(?:implement|batch-implement)(?:\s|$)/.test(rawTemplate);
|
|
1150
|
-
const expanded = (0, loop_constants_1.resolveConstants)(resolveRunVars((0, loop_graph_1.interpolateSpec)((0, loop_command_catalog_1.expandCommands)(rawTemplate, { provider: nodeProvider, ticketIds: req.spec?.ticketIds, specId: req.spec?.id }),
|
|
1195
|
+
const expanded = (0, loop_constants_1.resolveConstants)(resolveRunVars((0, loop_graph_1.interpolateSpec)((0, loop_command_catalog_1.expandCommands)(rawTemplate, { provider: nodeProvider, ticketIds: req.spec?.ticketIds, specId: req.spec?.id }), seededChangeId && ['addenda', 'revision'].includes(seededChangeId.source)
|
|
1196
|
+
? { ...req.spec, openspecChangeName: seededChangeId.id } : req.spec), runVars), constMap);
|
|
1151
1197
|
// The follow-up briefing is APPENDED (after any slash command, which
|
|
1152
1198
|
// must lead the message) so it becomes part of the command's
|
|
1153
1199
|
// arguments for CLI providers and plain prompt text for the runner.
|
|
1154
1200
|
// The spec-addenda briefing rides the same slot: appended to every
|
|
1155
1201
|
// step so no phase can miss the iteration delta.
|
|
1156
|
-
const
|
|
1202
|
+
const deltaTarget = seededChangeId && ['addenda', 'revision'].includes(seededChangeId.source)
|
|
1203
|
+
? `DELTA OPENSPEC TARGET: ${seededChangeId.id}. Use ONLY openspec/changes/${seededChangeId.id}/. Create it if missing; the seeded name does not imply artifacts exist. Ignore the original spec/follow-up change name and unrelated active or archived changes. Inspect the current branch first. For delivered work, prepare artifacts and tasks ONLY for the attached addenda or delivery change request and preserve existing behavior outside this delta. For a spec with no delivered work, the scope is the full spec together with its addenda. Map each requested change to acceptance checks. Do not redo or archive the original proposal. Perform only the current phase on this exact change: preparation/repair edits artifacts only; implementation applies and verifies. The implementation phase must report every attached addendum with concrete files and test evidence before VERIFICATION: PASS.`
|
|
1204
|
+
: undefined;
|
|
1205
|
+
const base = [(0, multi_repo_execution_store_1.executionManifestPrompt)(req.executionManifest), withReviewContinuationContext(expanded, rawTemplate, req.spec), repair ? `PHASE RECOVERY: keep the same change and completed work. Correct only the remaining failure; do not repeat preparation or unaffected passing checks. Prior failure (diagnostic data):\n${repair.detail}` : undefined, req.followUp?.briefing, req.constants?.REVISION_REQUEST, deltaTarget, req.addenda?.briefing].filter(Boolean).join('\n\n');
|
|
1157
1206
|
// Inject the cross-iteration history only when there's no live session
|
|
1158
1207
|
// to carry it (a fresh pass) OR right after a Decider 'continue' (so the
|
|
1159
1208
|
// step sees the verdict). A mid-body resumed step already has it.
|
|
@@ -1330,7 +1379,11 @@ class LoopRunManager {
|
|
|
1330
1379
|
const blockedReason = aiStepBlockedReason(res.text);
|
|
1331
1380
|
const requiresVerification = node.data?.requireVerificationPass === true
|
|
1332
1381
|
|| /\{\{cmd:(?:verify|revision-verify|opsx:verify)\}\}/.test(rawTemplate);
|
|
1333
|
-
const
|
|
1382
|
+
const addendaReport = requiresVerification && req.addenda?.ids.length
|
|
1383
|
+
? (0, spec_addenda_core_1.parseSpecAddendaReport)(res.text, req.addenda.ids.map((id) => ({ id }))) : null;
|
|
1384
|
+
const addendaFailed = Boolean(requiresVerification && req.addenda?.ids.length
|
|
1385
|
+
&& req.addenda.ids.some((id) => !addendaReport?.some((line) => line.addendumId === id && line.verdict === 'applied' && line.files && line.tests)));
|
|
1386
|
+
const verificationFailed = addendaFailed || requiresVerification
|
|
1334
1387
|
&& (0, verification_sentinel_1.parseVerificationSentinel)(res.text).verdict !== 'pass';
|
|
1335
1388
|
const stepFailed = res.failed === true || zeroWork || blockedReason !== null || verificationFailed;
|
|
1336
1389
|
passFailed ||= res.failed === true || zeroWork || (verificationFailed && !blockedReason);
|
|
@@ -1339,7 +1392,7 @@ class LoopRunManager {
|
|
|
1339
1392
|
: blockedReason
|
|
1340
1393
|
? `blocked — ${blockedReason}`
|
|
1341
1394
|
: verificationFailed
|
|
1342
|
-
? 'verification did not finish with VERIFICATION: PASS'
|
|
1395
|
+
? addendaFailed ? 'addenda verification incomplete: every addendum requires an applied report with files and tests' : 'verification did not finish with VERIFICATION: PASS'
|
|
1343
1396
|
: res.failed ? 'provider invocation failed without a reported reason' : undefined);
|
|
1344
1397
|
// Make the failure reason land visibly INSIDE the step's log
|
|
1345
1398
|
// segment (the interactive session already surfaced its own note at
|
|
@@ -1364,9 +1417,24 @@ class LoopRunManager {
|
|
|
1364
1417
|
// session — plus zero-work); no exit code is exposed by the AI
|
|
1365
1418
|
// executors → null.
|
|
1366
1419
|
emitStepEnd({ status: stepFailed ? 'failed' : 'ok', durationMs: res.durationMs });
|
|
1420
|
+
if (req.graph.nodes.some((candidate) => candidate.data?.failureRecovery)) {
|
|
1421
|
+
emitRunEvent('loop_phase_metrics', {
|
|
1422
|
+
nodeId: node.id, stepIndex: stepNum, usageScope: 'final-attempt', recovery: !!repair, promptChars: prompt.length, outputChars: res.text.length,
|
|
1423
|
+
durationMs: res.durationMs ?? null, costUsd: res.cost ?? null, estimated: res.estimated ?? null,
|
|
1424
|
+
tokensIn: res.tokensIn ?? null, tokensOut: res.tokensOut ?? null,
|
|
1425
|
+
tokensCacheRead: res.tokensCacheRead ?? null, tokensCacheCreate: res.tokensCacheCreate ?? null,
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1367
1428
|
// Linear workflows may forbid later actions (such as archive) after
|
|
1368
1429
|
// a failed step. Verify/fix loops keep their existing recovery path.
|
|
1369
1430
|
if (node.data?.stopOnFailure === true && stepFailed) {
|
|
1431
|
+
const retryTarget = !res.failed && !res.resultIsError && !zeroWork && !blockedReason && verificationFailed
|
|
1432
|
+
? recoverPhase(node, `${stepErrorText}\n${res.text}`, priorPhaseFailure) : undefined;
|
|
1433
|
+
if (retryTarget) {
|
|
1434
|
+
aiSessionId = res.sessionId;
|
|
1435
|
+
nodeId = retryTarget;
|
|
1436
|
+
break;
|
|
1437
|
+
}
|
|
1370
1438
|
outcome = 'failed';
|
|
1371
1439
|
settled = true;
|
|
1372
1440
|
break;
|
|
@@ -1426,10 +1494,11 @@ class LoopRunManager {
|
|
|
1426
1494
|
else {
|
|
1427
1495
|
consecutiveAiFailures = 0;
|
|
1428
1496
|
}
|
|
1429
|
-
nodeId = succs[0]?.id;
|
|
1497
|
+
nodeId = afterPhase(node.id, succs[0]?.id);
|
|
1430
1498
|
break;
|
|
1431
1499
|
}
|
|
1432
1500
|
case 'shell': {
|
|
1501
|
+
const priorPhaseFailure = passFailed;
|
|
1433
1502
|
// Guard: refuse to run when a declared run-variable was never captured
|
|
1434
1503
|
// (e.g. an archive node whose `{{run.changeId}}` is empty) — running
|
|
1435
1504
|
// `openspec archive -y` against an unknown change would archive the
|
|
@@ -1461,7 +1530,7 @@ class LoopRunManager {
|
|
|
1461
1530
|
&& openspecChangeState(shellCwd, runVars.changeId) === 'archived') {
|
|
1462
1531
|
logLine(`Skipped: OpenSpec change ${runVars.changeId} is already archived (openspec/changes/archive) — nothing left to ${/\barchive\b/.test(rawCommand) ? 'archive' : 'validate'}.`);
|
|
1463
1532
|
emitStepEnd({ status: 'ok', exitCode: 0, durationMs: 0 });
|
|
1464
|
-
nodeId = succs[0]?.id;
|
|
1533
|
+
nodeId = afterPhase(node.id, succs[0]?.id);
|
|
1465
1534
|
break;
|
|
1466
1535
|
}
|
|
1467
1536
|
logLine(`$ ${command}`);
|
|
@@ -1481,11 +1550,17 @@ class LoopRunManager {
|
|
|
1481
1550
|
});
|
|
1482
1551
|
history.push(`Shell \`${command}\` exit=${sh.exitCode}: ${truncate(sh.stdout || sh.stderr)}`);
|
|
1483
1552
|
if (node.data?.stopOnFailure === true && sh.exitCode !== 0) {
|
|
1553
|
+
const retryTarget = sh.exitCode === 1
|
|
1554
|
+
? recoverPhase(node, `${command}\n${sh.stdout}\n${sh.stderr}`, priorPhaseFailure) : undefined;
|
|
1555
|
+
if (retryTarget) {
|
|
1556
|
+
nodeId = retryTarget;
|
|
1557
|
+
break;
|
|
1558
|
+
}
|
|
1484
1559
|
outcome = 'failed';
|
|
1485
1560
|
settled = true;
|
|
1486
1561
|
break;
|
|
1487
1562
|
}
|
|
1488
|
-
nodeId = succs[0]?.id;
|
|
1563
|
+
nodeId = afterPhase(node.id, succs[0]?.id);
|
|
1489
1564
|
break;
|
|
1490
1565
|
}
|
|
1491
1566
|
case 'decider': {
|
|
@@ -260,7 +260,7 @@ function getLoopRun(db, id) {
|
|
|
260
260
|
return db.prepare('SELECT * FROM loop_runs WHERE id = ?').get(id);
|
|
261
261
|
}
|
|
262
262
|
/** Activity-step count for one event, mirroring the client's deriveFrameActivity
|
|
263
|
-
* (../../client/src/lib/frame-activity.ts) so the seeded count matches the live
|
|
263
|
+
* (../../client/src/features/browser/lib/frame-activity.ts) so the seeded count matches the live
|
|
264
264
|
* "pasos" the Job panel shows. A single assistant frame may carry several
|
|
265
265
|
* parallel tool_use blocks → each counts. Non-activity events → 0. */
|
|
266
266
|
function activityStepCount(eventType, payload) {
|
package/server/dist/{loop-shell-invocation.js → modules/loops/runtime/loop-shell-invocation.js}
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.bundledLoopShellInvocation = bundledLoopShellInvocation;
|
|
4
|
-
const bundled_openspec_1 = require("
|
|
5
|
-
const path_resolver_1 = require("
|
|
4
|
+
const bundled_openspec_1 = require("../../../bundled-openspec");
|
|
5
|
+
const path_resolver_1 = require("../../../path-resolver");
|
|
6
6
|
/** Resolve the exact built-in archive operation without requiring a global CLI. */
|
|
7
7
|
function bundledLoopShellInvocation(command) {
|
|
8
8
|
const match = /^openspec archive ([A-Za-z0-9][A-Za-z0-9._-]*) -y$/.exec(command);
|
|
@@ -19,7 +19,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
19
19
|
exports.AI_STEP_STALLED_ERROR = exports.LOOP_STEP_IDLE_DEFAULT_MS = void 0;
|
|
20
20
|
exports._resetLoopStepIdleWarningForTests = _resetLoopStepIdleWarningForTests;
|
|
21
21
|
exports.resolveLoopStepIdleTimeoutMs = resolveLoopStepIdleTimeoutMs;
|
|
22
|
-
const stuck_run_detector_1 = require("
|
|
22
|
+
const stuck_run_detector_1 = require("../../execution/runtime/stuck-run-detector");
|
|
23
23
|
exports.LOOP_STEP_IDLE_DEFAULT_MS = 30 * 60 * 1000;
|
|
24
24
|
/** Error text the executors/engine attach to a stalled step result. */
|
|
25
25
|
exports.AI_STEP_STALLED_ERROR = 'AI step stalled';
|
|
@@ -128,56 +128,51 @@ function fixLoopGraph(mainPrompts, deciderGoal, maxIterations = 12, timeoutMinut
|
|
|
128
128
|
return { nodes, edges, config: { maxIterations, timeoutMinutes, ...(aiStepTimeoutMinutes != null ? { aiStepTimeoutMinutes } : {}) } };
|
|
129
129
|
}
|
|
130
130
|
// ── OpenSpec lifecycle loop ──────────────────────────────────────────────────
|
|
131
|
-
// Lightweight lifecycle: prepare → apply/test → validate artifacts → archive.
|
|
131
|
+
// Lightweight lifecycle: prepare → preflight → apply/test → validate artifacts → archive.
|
|
132
132
|
// CLI validation checks OpenSpec artifacts; Apply owns code tests and corrections.
|
|
133
133
|
const OPSX_FF_PROMPT = [
|
|
134
134
|
'{{cmd:opsx:ff}} {{spec.title}}',
|
|
135
|
-
'',
|
|
136
135
|
'{{spec.description}}',
|
|
137
|
-
'',
|
|
138
|
-
'
|
|
139
|
-
'',
|
|
140
|
-
'
|
|
141
|
-
'',
|
|
142
|
-
'
|
|
143
|
-
|
|
144
|
-
'Do NOT run `openspec archive` in this step, even if the implementation is complete: this loop validates and archives the change itself in later CLI steps, and an archived change makes those steps fail. Leave the change ACTIVE under openspec/changes/<name>/ and name that path in your final reply.',
|
|
145
|
-
'',
|
|
146
|
-
'Run fully unattended: make reasonable decisions to keep momentum and NEVER stop to ask — there is no human to answer. When something is unclear, pick the most sensible option, proceed, and note the assumption.',
|
|
147
|
-
].join('\n');
|
|
136
|
+
'Target: "{{run.changeId}}" takes precedence over ticket metadata "{{spec.openspecChangeName}}". CONTINUE that exact OpenSpec change if active; create it if missing. If both are blank, choose a new name. Do not select unrelated changes or create a duplicate.',
|
|
137
|
+
'Preparation ONLY: inspect the affected code and generate the required proposal/specs/design/tasks. Do not implement code or run the repository test suite in this phase.',
|
|
138
|
+
'OpenSpec artifacts are authoritative: map the full requested spec (or each delta/addendum on delivered work) to tasks and an observable acceptance check. Keep artifacts proportional to the change; reference unchanged contracts instead of rewriting them. Do not invent extra work.',
|
|
139
|
+
'Do NOT run `openspec archive` in this step. Leave the change ACTIVE and name that path in your final reply. Return a concise handoff: change path, affected files, decisions, and checks for Apply; do not repeat the spec or addendum bodies.',
|
|
140
|
+
'Work unattended within the requested scope. Record assumptions; report a genuine blocker instead of expanding scope.',
|
|
141
|
+
'{{const:GUARDRAILS}}',
|
|
142
|
+
].join('\n\n');
|
|
148
143
|
const OPSX_APPLY_PROMPT = [
|
|
149
|
-
'{{cmd:opsx:apply}}',
|
|
150
|
-
'',
|
|
151
|
-
'
|
|
152
|
-
'',
|
|
153
|
-
'
|
|
154
|
-
'',
|
|
155
|
-
'Run the relevant tests and configured checks for the changed behavior, correct failures, and confirm every required task and acceptance criterion is implemented. This step owns code verification; the later CLI validate only checks OpenSpec artifacts. Do not archive here — never run `openspec archive`; the loop archives the change in a later CLI step.',
|
|
144
|
+
'{{cmd:opsx:apply}} {{run.changeId}}',
|
|
145
|
+
'Implement the pending tasks of this exact change for "{{spec.title}}". Inspect the diff and tasks first; preserve completed work and keep edits within the requested scope.',
|
|
146
|
+
'Before editing code, confirm the artifacts describe the requested contract; amend the OpenSpec artifacts first if needed. Do not re-plan the original feature.',
|
|
147
|
+
'Run the relevant tests for each requested behavior and all repository-required checks. Expand testing for affected contracts or failures. Once checks pass, repeat them only after changes that could invalidate them; do not run unrelated optional suites.',
|
|
148
|
+
'Inspect the final diff for omissions and regressions, mark completed tasks, and report concrete file/check evidence for every attached addendum. CLI validation checks artifacts, not implementation. Do not archive here — never run `openspec archive`.',
|
|
156
149
|
'Finish with exactly `{{const:VERIFICATION_PASS}}` only after implementation and relevant checks succeed. Otherwise finish with `{{const:VERIFICATION_FAIL}} — <remaining work or failed checks>`.',
|
|
157
|
-
'
|
|
158
|
-
].join('\n');
|
|
150
|
+
'{{const:GUARDRAILS}}',
|
|
151
|
+
].join('\n\n');
|
|
159
152
|
/** The OpenSpec-lifecycle graph (see comment above). Exported for unit testing. */
|
|
160
153
|
function opsxLifecycleGraph() {
|
|
161
154
|
return {
|
|
162
155
|
nodes: [
|
|
163
156
|
{ id: 'start', type: 'start', position: { x: COL_X, y: 0 } },
|
|
164
|
-
{ id: 'ff', type: 'ai-step', position: { x: COL_X, y: ROW_GAP * 1 }, data: { label: 'opsx:ff', prompt: OPSX_FF_PROMPT } },
|
|
165
|
-
{ id: '
|
|
166
|
-
{ id: '
|
|
157
|
+
{ id: 'ff', type: 'ai-step', position: { x: COL_X, y: ROW_GAP * 1 }, data: { label: 'opsx:ff', prompt: OPSX_FF_PROMPT, stopOnFailure: true } },
|
|
158
|
+
{ id: 'preflight', type: 'shell', position: { x: COL_X, y: ROW_GAP * 2 }, data: { label: 'validate artifacts before implementation', stopOnFailure: true, command: 'openspec validate {{run.changeId}} --type change --strict --no-interactive', requireRunVars: ['changeId'], failureRecovery: { target: 'ff', maxRetries: 1, artifactOnly: true } } },
|
|
159
|
+
{ id: 'apply', type: 'ai-step', position: { x: COL_X, y: ROW_GAP * 3 }, data: { label: 'opsx:apply', prompt: OPSX_APPLY_PROMPT, requireVerificationPass: true, stopOnFailure: true, failureRecovery: { target: 'apply', maxRetries: 1 } } },
|
|
160
|
+
{ id: 'validate', type: 'shell', position: { x: COL_X, y: ROW_GAP * 4 }, data: { label: 'validate', stopOnFailure: true, command: 'openspec validate {{run.changeId}} --type change --strict --no-interactive', requireRunVars: ['changeId'], failureRecovery: { target: 'ff', maxRetries: 1, artifactOnly: true } } },
|
|
167
161
|
// Unattended archive: deterministic CLI, no AI, no prompt. `requireRunVars`
|
|
168
162
|
// makes the engine REFUSE to run if no change id was captured (never archive
|
|
169
163
|
// an unknown change); `openspec archive -y` syncs the main specs by default.
|
|
170
|
-
{ id: 'archive', type: 'shell', position: { x: COL_X, y: ROW_GAP *
|
|
171
|
-
{ id: 'done', type: 'end', position: { x: COL_X, y: ROW_GAP *
|
|
164
|
+
{ id: 'archive', type: 'shell', position: { x: COL_X, y: ROW_GAP * 5 }, data: { label: 'archive', stopOnFailure: true, failureRecovery: { target: 'archive', maxRetries: 1 }, command: 'openspec archive {{run.changeId}} -y', requireRunVars: ['changeId'] } },
|
|
165
|
+
{ id: 'done', type: 'end', position: { x: COL_X, y: ROW_GAP * 6 }, data: { outcome: 'success' } },
|
|
172
166
|
],
|
|
173
167
|
edges: [
|
|
174
168
|
{ id: 'e-start', source: 'start', target: 'ff' },
|
|
175
|
-
{ id: 'e-ff', source: 'ff', target: '
|
|
169
|
+
{ id: 'e-ff', source: 'ff', target: 'preflight' },
|
|
170
|
+
{ id: 'e-preflight', source: 'preflight', target: 'apply' },
|
|
176
171
|
{ id: 'e-apply', source: 'apply', target: 'validate' },
|
|
177
172
|
{ id: 'e-validate', source: 'validate', target: 'archive' },
|
|
178
173
|
{ id: 'e-archive', source: 'archive', target: 'done' },
|
|
179
174
|
],
|
|
180
|
-
//
|
|
175
|
+
// Phase recovery is bounded per failing node, without an AI Decider. Like the other built-ins,
|
|
181
176
|
// the run is UNTIMED (0 = no timeout) — apply can
|
|
182
177
|
// implement a whole change and must never be killed mid-flight.
|
|
183
178
|
config: { maxIterations: 3, timeoutMinutes: 0, aiStepTimeoutMinutes: 0 },
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.registerLoopsRoutes = registerLoopsRoutes;
|
|
4
|
-
const ids_1 = require("
|
|
5
|
-
const feature_flags_1 = require("
|
|
4
|
+
const ids_1 = require("../../../ids");
|
|
5
|
+
const feature_flags_1 = require("../../../feature-flags");
|
|
6
6
|
const loops_store_1 = require("./loops-store");
|
|
7
7
|
const loop_templates_1 = require("./loop-templates");
|
|
8
8
|
const loop_factory_1 = require("./loop-factory");
|