rivet-design 0.17.4 → 0.17.5
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/bin/rivet.js +0 -16
- package/dist/agent-variants/SessionStore.d.ts +0 -239
- package/dist/agent-variants/SessionStore.d.ts.map +1 -1
- package/dist/agent-variants/SessionStore.js +10 -368
- package/dist/agent-variants/SessionStore.js.map +1 -1
- package/dist/agent-variants/VariantWorkspaceManager.d.ts +0 -10
- package/dist/agent-variants/VariantWorkspaceManager.d.ts.map +1 -1
- package/dist/agent-variants/VariantWorkspaceManager.js +0 -17
- package/dist/agent-variants/VariantWorkspaceManager.js.map +1 -1
- package/dist/agent-variants/WorkerExecutorService.d.ts +1 -105
- package/dist/agent-variants/WorkerExecutorService.d.ts.map +1 -1
- package/dist/agent-variants/WorkerExecutorService.js +11 -182
- package/dist/agent-variants/WorkerExecutorService.js.map +1 -1
- package/dist/agent-variants/WorktreeOrchestrator.d.ts +0 -597
- package/dist/agent-variants/WorktreeOrchestrator.d.ts.map +1 -1
- package/dist/agent-variants/WorktreeOrchestrator.js +4 -1273
- package/dist/agent-variants/WorktreeOrchestrator.js.map +1 -1
- package/dist/agent-variants/WorktreeOrchestrator.testHelpers.d.ts +0 -6
- package/dist/agent-variants/WorktreeOrchestrator.testHelpers.d.ts.map +1 -1
- package/dist/agent-variants/WorktreeOrchestrator.testHelpers.js +0 -23
- package/dist/agent-variants/WorktreeOrchestrator.testHelpers.js.map +1 -1
- package/dist/agent-variants/briefContent.d.ts +0 -11
- package/dist/agent-variants/briefContent.d.ts.map +1 -1
- package/dist/agent-variants/briefContent.js +0 -12
- package/dist/agent-variants/briefContent.js.map +1 -1
- package/dist/agent-variants/contextAssets.d.ts +0 -3
- package/dist/agent-variants/contextAssets.d.ts.map +1 -1
- package/dist/agent-variants/contextAssets.js +0 -3
- package/dist/agent-variants/contextAssets.js.map +1 -1
- package/dist/agent-variants/contracts.d.ts +4 -492
- package/dist/agent-variants/contracts.d.ts.map +1 -1
- package/dist/agent-variants/contracts.js +0 -165
- package/dist/agent-variants/contracts.js.map +1 -1
- package/dist/agent-variants/createProjectArtifacts.d.ts +0 -17
- package/dist/agent-variants/createProjectArtifacts.d.ts.map +1 -1
- package/dist/agent-variants/createProjectArtifacts.js +0 -10
- package/dist/agent-variants/createProjectArtifacts.js.map +1 -1
- package/dist/agent-variants/diffQa.d.ts +0 -1
- package/dist/agent-variants/diffQa.d.ts.map +1 -1
- package/dist/agent-variants/diffQa.js +0 -1
- package/dist/agent-variants/diffQa.js.map +1 -1
- package/dist/agent-variants/directionAuthoring.d.ts +0 -13
- package/dist/agent-variants/directionAuthoring.d.ts.map +1 -1
- package/dist/agent-variants/directionAuthoring.js +12 -46
- package/dist/agent-variants/directionAuthoring.js.map +1 -1
- package/dist/agent-variants/elementRefToTarget.d.ts +0 -17
- package/dist/agent-variants/elementRefToTarget.d.ts.map +1 -1
- package/dist/agent-variants/elementRefToTarget.js +0 -17
- package/dist/agent-variants/elementRefToTarget.js.map +1 -1
- package/dist/agent-variants/generatedDestination.d.ts +0 -3
- package/dist/agent-variants/generatedDestination.d.ts.map +1 -1
- package/dist/agent-variants/generatedDestination.js +0 -3
- package/dist/agent-variants/generatedDestination.js.map +1 -1
- package/dist/agent-variants/previewQa.d.ts +0 -6
- package/dist/agent-variants/previewQa.d.ts.map +1 -1
- package/dist/agent-variants/previewQa.js +0 -5
- package/dist/agent-variants/previewQa.js.map +1 -1
- package/dist/agent-variants/runLabel.d.ts +0 -15
- package/dist/agent-variants/runLabel.d.ts.map +1 -1
- package/dist/agent-variants/runLabel.js +0 -19
- package/dist/agent-variants/runLabel.js.map +1 -1
- package/dist/agent-variants/runPlan.d.ts +3 -84
- package/dist/agent-variants/runPlan.d.ts.map +1 -1
- package/dist/agent-variants/runPlan.js +0 -51
- package/dist/agent-variants/runPlan.js.map +1 -1
- package/dist/agent-variants/sourceContext.d.ts +0 -10
- package/dist/agent-variants/sourceContext.d.ts.map +1 -1
- package/dist/agent-variants/sourceContext.js +0 -36
- package/dist/agent-variants/sourceContext.js.map +1 -1
- package/dist/agent-variants/variantContext.d.ts +0 -6
- package/dist/agent-variants/variantContext.d.ts.map +1 -1
- package/dist/agent-variants/variantContext.js +0 -9
- package/dist/agent-variants/variantContext.js.map +1 -1
- package/dist/agent-variants/videoKeyframes.d.ts +0 -7
- package/dist/agent-variants/videoKeyframes.d.ts.map +1 -1
- package/dist/agent-variants/videoKeyframes.js +0 -7
- package/dist/agent-variants/videoKeyframes.js.map +1 -1
- package/dist/agent-variants/workItemBriefing.d.ts +0 -21
- package/dist/agent-variants/workItemBriefing.d.ts.map +1 -1
- package/dist/agent-variants/workItemBriefing.js +0 -49
- package/dist/agent-variants/workItemBriefing.js.map +1 -1
- package/dist/agent-variants/workerRuntime.d.ts +1 -137
- package/dist/agent-variants/workerRuntime.d.ts.map +1 -1
- package/dist/agent-variants/workerRuntime.js +8 -147
- package/dist/agent-variants/workerRuntime.js.map +1 -1
- package/dist/cli/browser.d.ts +0 -1
- package/dist/cli/browser.d.ts.map +1 -1
- package/dist/cli/browser.js +0 -1
- package/dist/cli/browser.js.map +1 -1
- package/dist/cli/callerRunnerPaths.d.ts +0 -50
- package/dist/cli/callerRunnerPaths.d.ts.map +1 -1
- package/dist/cli/callerRunnerPaths.js +0 -59
- package/dist/cli/callerRunnerPaths.js.map +1 -1
- package/dist/cli/client.d.ts +0 -18
- package/dist/cli/client.d.ts.map +1 -1
- package/dist/cli/client.js +0 -28
- package/dist/cli/client.js.map +1 -1
- package/dist/cli/commandNames.d.ts +0 -7
- package/dist/cli/commandNames.d.ts.map +1 -1
- package/dist/cli/commandNames.js +0 -7
- package/dist/cli/commandNames.js.map +1 -1
- package/dist/cli/commands/auth.d.ts +0 -6
- package/dist/cli/commands/auth.d.ts.map +1 -1
- package/dist/cli/commands/auth.js +0 -6
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/elementSelector.d.ts +0 -6
- package/dist/cli/commands/elementSelector.d.ts.map +1 -1
- package/dist/cli/commands/elementSelector.js +0 -7
- package/dist/cli/commands/elementSelector.js.map +1 -1
- package/dist/cli/commands/evidence.d.ts +0 -6
- package/dist/cli/commands/evidence.d.ts.map +1 -1
- package/dist/cli/commands/evidence.js +0 -6
- package/dist/cli/commands/evidence.js.map +1 -1
- package/dist/cli/commands/libraryOpen.d.ts +0 -1
- package/dist/cli/commands/libraryOpen.d.ts.map +1 -1
- package/dist/cli/commands/libraryOpen.js +0 -4
- package/dist/cli/commands/libraryOpen.js.map +1 -1
- package/dist/cli/commands/mcpServe.d.ts +0 -24
- package/dist/cli/commands/mcpServe.d.ts.map +1 -1
- package/dist/cli/commands/mcpServe.js +31 -102
- package/dist/cli/commands/mcpServe.js.map +1 -1
- package/dist/cli/commands/open.d.ts +0 -8
- package/dist/cli/commands/open.d.ts.map +1 -1
- package/dist/cli/commands/open.js +0 -57
- package/dist/cli/commands/open.js.map +1 -1
- package/dist/cli/commands/reference.d.ts +0 -5
- package/dist/cli/commands/reference.d.ts.map +1 -1
- package/dist/cli/commands/reference.js +0 -27
- package/dist/cli/commands/reference.js.map +1 -1
- package/dist/cli/commands/serve.d.ts +0 -5
- package/dist/cli/commands/serve.d.ts.map +1 -1
- package/dist/cli/commands/serve.js +0 -34
- package/dist/cli/commands/serve.js.map +1 -1
- package/dist/cli/commands/shared.d.ts +0 -16
- package/dist/cli/commands/shared.d.ts.map +1 -1
- package/dist/cli/commands/shared.js +0 -19
- package/dist/cli/commands/shared.js.map +1 -1
- package/dist/cli/commands/status.d.ts +0 -6
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +0 -11
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/stop.d.ts +0 -5
- package/dist/cli/commands/stop.d.ts.map +1 -1
- package/dist/cli/commands/stop.js +0 -6
- package/dist/cli/commands/stop.js.map +1 -1
- package/dist/cli/commands/update.d.ts +0 -1
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +0 -1
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/commands/variants.d.ts +0 -1
- package/dist/cli/commands/variants.d.ts.map +1 -1
- package/dist/cli/commands/variants.js +0 -31
- package/dist/cli/commands/variants.js.map +1 -1
- package/dist/cli/commands/wait.d.ts +0 -21
- package/dist/cli/commands/wait.d.ts.map +1 -1
- package/dist/cli/commands/wait.js +0 -23
- package/dist/cli/commands/wait.js.map +1 -1
- package/dist/cli/entry.d.ts +0 -10
- package/dist/cli/entry.d.ts.map +1 -1
- package/dist/cli/entry.js +0 -13
- package/dist/cli/entry.js.map +1 -1
- package/dist/cli/envelope.d.ts +1 -25
- package/dist/cli/envelope.d.ts.map +1 -1
- package/dist/cli/envelope.js +0 -19
- package/dist/cli/envelope.js.map +1 -1
- package/dist/cli/flags.d.ts +0 -7
- package/dist/cli/flags.d.ts.map +1 -1
- package/dist/cli/flags.js +0 -7
- package/dist/cli/flags.js.map +1 -1
- package/dist/cli/handoff.d.ts +0 -33
- package/dist/cli/handoff.d.ts.map +1 -1
- package/dist/cli/handoff.js +0 -42
- package/dist/cli/handoff.js.map +1 -1
- package/dist/cli/handoffStore.d.ts +0 -11
- package/dist/cli/handoffStore.d.ts.map +1 -1
- package/dist/cli/handoffStore.js +0 -10
- package/dist/cli/handoffStore.js.map +1 -1
- package/dist/cli/hostWorkNextAction.d.ts +0 -11
- package/dist/cli/hostWorkNextAction.d.ts.map +1 -1
- package/dist/cli/hostWorkNextAction.js +0 -4
- package/dist/cli/hostWorkNextAction.js.map +1 -1
- package/dist/cli/io.d.ts +0 -9
- package/dist/cli/io.d.ts.map +1 -1
- package/dist/cli/io.js +0 -1
- package/dist/cli/io.js.map +1 -1
- package/dist/cli/resolveDefaultNodeEnv.d.ts +0 -5
- package/dist/cli/resolveDefaultNodeEnv.d.ts.map +1 -1
- package/dist/cli/resolveDefaultNodeEnv.js +0 -5
- package/dist/cli/resolveDefaultNodeEnv.js.map +1 -1
- package/dist/cli/router.d.ts +0 -21
- package/dist/cli/router.d.ts.map +1 -1
- package/dist/cli/router.js +0 -46
- package/dist/cli/router.js.map +1 -1
- package/dist/cli/runnerSelection.d.ts +0 -58
- package/dist/cli/runnerSelection.d.ts.map +1 -1
- package/dist/cli/runnerSelection.js +0 -16
- package/dist/cli/runnerSelection.js.map +1 -1
- package/dist/cli/serverHandshake.d.ts +0 -36
- package/dist/cli/serverHandshake.d.ts.map +1 -1
- package/dist/cli/serverHandshake.js +0 -29
- package/dist/cli/serverHandshake.js.map +1 -1
- package/dist/cli/serverUnavailable.d.ts +0 -1
- package/dist/cli/serverUnavailable.d.ts.map +1 -1
- package/dist/cli/serverUnavailable.js +0 -1
- package/dist/cli/serverUnavailable.js.map +1 -1
- package/dist/cli/serverVersion.d.ts +0 -22
- package/dist/cli/serverVersion.d.ts.map +1 -1
- package/dist/cli/serverVersion.js +0 -12
- package/dist/cli/serverVersion.js.map +1 -1
- package/dist/cli/telemetry.d.ts +0 -4
- package/dist/cli/telemetry.d.ts.map +1 -1
- package/dist/cli/telemetry.js +0 -4
- package/dist/cli/telemetry.js.map +1 -1
- package/dist/config/evaluateFlags.d.ts +0 -4
- package/dist/config/evaluateFlags.d.ts.map +1 -1
- package/dist/config/evaluateFlags.js +0 -11
- package/dist/config/evaluateFlags.js.map +1 -1
- package/dist/config/featureFlagUserKey.d.ts +0 -3
- package/dist/config/featureFlagUserKey.d.ts.map +1 -1
- package/dist/config/featureFlagUserKey.js +0 -3
- package/dist/config/featureFlagUserKey.js.map +1 -1
- package/dist/config/flags.d.ts +0 -14
- package/dist/config/flags.d.ts.map +1 -1
- package/dist/config/flags.js +0 -27
- package/dist/config/flags.js.map +1 -1
- package/dist/config/proxy.d.ts +0 -3
- package/dist/config/proxy.d.ts.map +1 -1
- package/dist/config/proxy.js +0 -11
- package/dist/config/proxy.js.map +1 -1
- package/dist/config/telemetry.d.ts +0 -13
- package/dist/config/telemetry.d.ts.map +1 -1
- package/dist/config/telemetry.js +0 -13
- package/dist/config/telemetry.js.map +1 -1
- package/dist/config/telemetryContract.d.ts +0 -1
- package/dist/config/telemetryContract.d.ts.map +1 -1
- package/dist/config/telemetryContract.js +0 -1
- package/dist/config/telemetryContract.js.map +1 -1
- package/dist/hosts/workerDefaults.d.ts +0 -69
- package/dist/hosts/workerDefaults.d.ts.map +1 -1
- package/dist/hosts/workerDefaults.js +0 -68
- package/dist/hosts/workerDefaults.js.map +1 -1
- package/dist/index-core.d.ts.map +1 -1
- package/dist/index-core.js +0 -2
- package/dist/index-core.js.map +1 -1
- package/dist/index.d.ts +0 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -105
- package/dist/index.js.map +1 -1
- package/dist/install/allowlists.d.ts +0 -32
- package/dist/install/allowlists.d.ts.map +1 -1
- package/dist/install/allowlists.js +0 -44
- package/dist/install/allowlists.js.map +1 -1
- package/dist/install/automaticCliUpdate.d.ts +0 -6
- package/dist/install/automaticCliUpdate.d.ts.map +1 -1
- package/dist/install/automaticCliUpdate.js +0 -13
- package/dist/install/automaticCliUpdate.js.map +1 -1
- package/dist/install/channelCli.d.ts +0 -1
- package/dist/install/channelCli.d.ts.map +1 -1
- package/dist/install/channelCli.js +0 -3
- package/dist/install/channelCli.js.map +1 -1
- package/dist/install/channelManager.d.ts +0 -14
- package/dist/install/channelManager.d.ts.map +1 -1
- package/dist/install/channelManager.js +0 -22
- package/dist/install/channelManager.js.map +1 -1
- package/dist/install/codexGuidance.d.ts +0 -1
- package/dist/install/codexGuidance.d.ts.map +1 -1
- package/dist/install/codexGuidance.js +0 -7
- package/dist/install/codexGuidance.js.map +1 -1
- package/dist/install/globalBootstrap.d.ts +0 -25
- package/dist/install/globalBootstrap.d.ts.map +1 -1
- package/dist/install/globalBootstrap.js +0 -10
- package/dist/install/globalBootstrap.js.map +1 -1
- package/dist/install/harnesses.d.ts +0 -66
- package/dist/install/harnesses.d.ts.map +1 -1
- package/dist/install/harnesses.js +0 -60
- package/dist/install/harnesses.js.map +1 -1
- package/dist/install/installationChannel.d.ts +0 -1
- package/dist/install/installationChannel.d.ts.map +1 -1
- package/dist/install/installationChannel.js +0 -1
- package/dist/install/installationChannel.js.map +1 -1
- package/dist/install/legacyMcp.d.ts +0 -23
- package/dist/install/legacyMcp.d.ts.map +1 -1
- package/dist/install/legacyMcp.js +3 -46
- package/dist/install/legacyMcp.js.map +1 -1
- package/dist/install/mcpRegistration.d.ts +0 -41
- package/dist/install/mcpRegistration.d.ts.map +1 -1
- package/dist/install/mcpRegistration.js +2 -70
- package/dist/install/mcpRegistration.js.map +1 -1
- package/dist/library/HubClient.d.ts +0 -2
- package/dist/library/HubClient.d.ts.map +1 -1
- package/dist/library/HubClient.js +0 -4
- package/dist/library/HubClient.js.map +1 -1
- package/dist/library/HubServer.d.ts +0 -1
- package/dist/library/HubServer.d.ts.map +1 -1
- package/dist/library/HubServer.js +0 -1
- package/dist/library/HubServer.js.map +1 -1
- package/dist/library/StaticPreviewServer.d.ts +0 -1
- package/dist/library/StaticPreviewServer.d.ts.map +1 -1
- package/dist/library/StaticPreviewServer.js +0 -1
- package/dist/library/StaticPreviewServer.js.map +1 -1
- package/dist/library/http.d.ts +0 -2
- package/dist/library/http.d.ts.map +1 -1
- package/dist/library/http.js +0 -2
- package/dist/library/http.js.map +1 -1
- package/dist/library/importFiles.d.ts +0 -6
- package/dist/library/importFiles.d.ts.map +1 -1
- package/dist/library/importFiles.js +45 -11
- package/dist/library/importFiles.js.map +1 -1
- package/dist/mcp/changeBatchClassification.d.ts +0 -40
- package/dist/mcp/changeBatchClassification.d.ts.map +1 -1
- package/dist/mcp/changeBatchClassification.js +0 -34
- package/dist/mcp/changeBatchClassification.js.map +1 -1
- package/dist/prompts/commentVariationPrompts.d.ts +0 -5
- package/dist/prompts/commentVariationPrompts.d.ts.map +1 -1
- package/dist/prompts/commentVariationPrompts.js +0 -5
- package/dist/prompts/commentVariationPrompts.js.map +1 -1
- package/dist/prototype-host.js +0 -15
- package/dist/prototype-host.js.map +1 -1
- package/dist/proxy-middleware/preview-bridge.d.ts +0 -2
- package/dist/proxy-middleware/preview-bridge.d.ts.map +1 -1
- package/dist/proxy-middleware/preview-bridge.js +0 -2
- package/dist/proxy-middleware/preview-bridge.js.map +1 -1
- package/dist/proxy-middleware/preview-connections.d.ts +0 -1
- package/dist/proxy-middleware/preview-connections.d.ts.map +1 -1
- package/dist/proxy-middleware/preview-connections.js +0 -1
- package/dist/proxy-middleware/preview-connections.js.map +1 -1
- package/dist/proxy-middleware/proxy-config.d.ts +0 -12
- package/dist/proxy-middleware/proxy-config.d.ts.map +1 -1
- package/dist/proxy-middleware/proxy-config.js +2 -49
- package/dist/proxy-middleware/proxy-config.js.map +1 -1
- package/dist/routes/account.d.ts +0 -1
- package/dist/routes/account.d.ts.map +1 -1
- package/dist/routes/account.js +0 -2
- package/dist/routes/account.js.map +1 -1
- package/dist/routes/agentVariants.d.ts +0 -15
- package/dist/routes/agentVariants.d.ts.map +1 -1
- package/dist/routes/agentVariants.js +6 -320
- package/dist/routes/agentVariants.js.map +1 -1
- package/dist/routes/cli.d.ts +0 -17
- package/dist/routes/cli.d.ts.map +1 -1
- package/dist/routes/cli.js +0 -13
- package/dist/routes/cli.js.map +1 -1
- package/dist/routes/emptyStatePage.d.ts +0 -12
- package/dist/routes/emptyStatePage.d.ts.map +1 -1
- package/dist/routes/emptyStatePage.js +0 -12
- package/dist/routes/emptyStatePage.js.map +1 -1
- package/dist/routes/git.d.ts.map +1 -1
- package/dist/routes/git.js +0 -13
- package/dist/routes/git.js.map +1 -1
- package/dist/routes/inlineStartTracker.d.ts +0 -16
- package/dist/routes/inlineStartTracker.d.ts.map +1 -1
- package/dist/routes/inlineStartTracker.js.map +1 -1
- package/dist/routes/integrations.d.ts +0 -6
- package/dist/routes/integrations.d.ts.map +1 -1
- package/dist/routes/integrations.js +0 -6
- package/dist/routes/integrations.js.map +1 -1
- package/dist/routes/library/app.d.ts +0 -1
- package/dist/routes/library/app.d.ts.map +1 -1
- package/dist/routes/library/app.js +0 -1
- package/dist/routes/library/app.js.map +1 -1
- package/dist/routes/library/index.d.ts +0 -1
- package/dist/routes/library/index.d.ts.map +1 -1
- package/dist/routes/library/index.js +0 -1
- package/dist/routes/library/index.js.map +1 -1
- package/dist/routes/library/middleware.d.ts +0 -3
- package/dist/routes/library/middleware.d.ts.map +1 -1
- package/dist/routes/library/middleware.js +0 -4
- package/dist/routes/library/middleware.js.map +1 -1
- package/dist/routes/library/navigation.d.ts +0 -1
- package/dist/routes/library/navigation.d.ts.map +1 -1
- package/dist/routes/library/navigation.js +0 -1
- package/dist/routes/library/navigation.js.map +1 -1
- package/dist/routes/library/projects.d.ts +0 -1
- package/dist/routes/library/projects.d.ts.map +1 -1
- package/dist/routes/library/projects.js +0 -1
- package/dist/routes/library/projects.js.map +1 -1
- package/dist/routes/library/staticPreview.d.ts +0 -1
- package/dist/routes/library/staticPreview.d.ts.map +1 -1
- package/dist/routes/library/staticPreview.js +0 -1
- package/dist/routes/library/staticPreview.js.map +1 -1
- package/dist/routes/library/variants.d.ts +0 -1
- package/dist/routes/library/variants.d.ts.map +1 -1
- package/dist/routes/library/variants.js +0 -1
- package/dist/routes/library/variants.js.map +1 -1
- package/dist/routes/mcp.d.ts +0 -3
- package/dist/routes/mcp.d.ts.map +1 -1
- package/dist/routes/mcp.js +0 -5
- package/dist/routes/mcp.js.map +1 -1
- package/dist/routes/prototypeHost.d.ts +0 -2
- package/dist/routes/prototypeHost.d.ts.map +1 -1
- package/dist/routes/prototypeHost.js +6 -32
- package/dist/routes/prototypeHost.js.map +1 -1
- package/dist/routes/static.d.ts +0 -3
- package/dist/routes/static.d.ts.map +1 -1
- package/dist/routes/static.js +0 -6
- package/dist/routes/static.js.map +1 -1
- package/dist/routes/support.d.ts +0 -3
- package/dist/routes/support.d.ts.map +1 -1
- package/dist/routes/support.js +0 -3
- package/dist/routes/support.js.map +1 -1
- package/dist/server.d.ts +0 -42
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1 -129
- package/dist/server.js.map +1 -1
- package/dist/services/AuthService.d.ts +0 -76
- package/dist/services/AuthService.d.ts.map +1 -1
- package/dist/services/AuthService.js +0 -112
- package/dist/services/AuthService.js.map +1 -1
- package/dist/services/BrowserAgentClient.d.ts +1 -21
- package/dist/services/BrowserAgentClient.d.ts.map +1 -1
- package/dist/services/BrowserAgentClient.js +0 -10
- package/dist/services/BrowserAgentClient.js.map +1 -1
- package/dist/services/BundleStore.d.ts +0 -18
- package/dist/services/BundleStore.d.ts.map +1 -1
- package/dist/services/BundleStore.js +0 -10
- package/dist/services/BundleStore.js.map +1 -1
- package/dist/services/CliLogForwarder.d.ts +0 -26
- package/dist/services/CliLogForwarder.d.ts.map +1 -1
- package/dist/services/CliLogForwarder.js +1 -33
- package/dist/services/CliLogForwarder.js.map +1 -1
- package/dist/services/CommitMessageGenerator.d.ts +0 -6
- package/dist/services/CommitMessageGenerator.d.ts.map +1 -1
- package/dist/services/CommitMessageGenerator.js +0 -3
- package/dist/services/CommitMessageGenerator.js.map +1 -1
- package/dist/services/ComponentSearchService.d.ts +2 -16
- package/dist/services/ComponentSearchService.d.ts.map +1 -1
- package/dist/services/ComponentSearchService.js +2 -56
- package/dist/services/ComponentSearchService.js.map +1 -1
- package/dist/services/ConfigManager.d.ts +0 -113
- package/dist/services/ConfigManager.d.ts.map +1 -1
- package/dist/services/ConfigManager.js +0 -101
- package/dist/services/ConfigManager.js.map +1 -1
- package/dist/services/DependencyPreparationService.d.ts +0 -6
- package/dist/services/DependencyPreparationService.d.ts.map +1 -1
- package/dist/services/DependencyPreparationService.js +0 -22
- package/dist/services/DependencyPreparationService.js.map +1 -1
- package/dist/services/DevServerRuntimeService.d.ts +0 -20
- package/dist/services/DevServerRuntimeService.d.ts.map +1 -1
- package/dist/services/DevServerRuntimeService.js +0 -46
- package/dist/services/DevServerRuntimeService.js.map +1 -1
- package/dist/services/FeatureFlagService.d.ts +0 -15
- package/dist/services/FeatureFlagService.d.ts.map +1 -1
- package/dist/services/FeatureFlagService.js +0 -23
- package/dist/services/FeatureFlagService.js.map +1 -1
- package/dist/services/GatewayClient.d.ts +0 -27
- package/dist/services/GatewayClient.d.ts.map +1 -1
- package/dist/services/GatewayClient.js +0 -25
- package/dist/services/GatewayClient.js.map +1 -1
- package/dist/services/HistoryReplayService.d.ts +0 -31
- package/dist/services/HistoryReplayService.d.ts.map +1 -1
- package/dist/services/HistoryReplayService.js +2 -55
- package/dist/services/HistoryReplayService.js.map +1 -1
- package/dist/services/HubDiscovery.d.ts +0 -8
- package/dist/services/HubDiscovery.d.ts.map +1 -1
- package/dist/services/HubDiscovery.js +0 -8
- package/dist/services/HubDiscovery.js.map +1 -1
- package/dist/services/HubNavigation.d.ts +0 -6
- package/dist/services/HubNavigation.d.ts.map +1 -1
- package/dist/services/HubNavigation.js +5 -8
- package/dist/services/HubNavigation.js.map +1 -1
- package/dist/services/IntegrationsClient.d.ts +0 -34
- package/dist/services/IntegrationsClient.d.ts.map +1 -1
- package/dist/services/IntegrationsClient.js +0 -27
- package/dist/services/IntegrationsClient.js.map +1 -1
- package/dist/services/LocalGitService.d.ts +0 -57
- package/dist/services/LocalGitService.d.ts.map +1 -1
- package/dist/services/LocalGitService.js +4 -85
- package/dist/services/LocalGitService.js.map +1 -1
- package/dist/services/MCPOnboardingTelemetry.d.ts +0 -9
- package/dist/services/MCPOnboardingTelemetry.d.ts.map +1 -1
- package/dist/services/MCPOnboardingTelemetry.js +0 -9
- package/dist/services/MCPOnboardingTelemetry.js.map +1 -1
- package/dist/services/MCPVariantsTelemetry.d.ts +0 -2
- package/dist/services/MCPVariantsTelemetry.d.ts.map +1 -1
- package/dist/services/MCPVariantsTelemetry.js +0 -2
- package/dist/services/MCPVariantsTelemetry.js.map +1 -1
- package/dist/services/OperatingSystemServices.d.ts +0 -12
- package/dist/services/OperatingSystemServices.d.ts.map +1 -1
- package/dist/services/OperatingSystemServices.js +0 -7
- package/dist/services/OperatingSystemServices.js.map +1 -1
- package/dist/services/PRTitleGenerator.d.ts +0 -7
- package/dist/services/PRTitleGenerator.d.ts.map +1 -1
- package/dist/services/PRTitleGenerator.js +0 -3
- package/dist/services/PRTitleGenerator.js.map +1 -1
- package/dist/services/ProjectCardPreviews.d.ts +0 -5
- package/dist/services/ProjectCardPreviews.d.ts.map +1 -1
- package/dist/services/ProjectCardPreviews.js +0 -5
- package/dist/services/ProjectCardPreviews.js.map +1 -1
- package/dist/services/ProjectDetectionService.d.ts +0 -4
- package/dist/services/ProjectDetectionService.d.ts.map +1 -1
- package/dist/services/ProjectDetectionService.js +2 -44
- package/dist/services/ProjectDetectionService.js.map +1 -1
- package/dist/services/ProjectFolderPicker.d.ts +0 -3
- package/dist/services/ProjectFolderPicker.d.ts.map +1 -1
- package/dist/services/ProjectFolderPicker.js +0 -4
- package/dist/services/ProjectFolderPicker.js.map +1 -1
- package/dist/services/ProjectImport.d.ts +0 -1
- package/dist/services/ProjectImport.d.ts.map +1 -1
- package/dist/services/ProjectImport.js +0 -3
- package/dist/services/ProjectImport.js.map +1 -1
- package/dist/services/ProjectLibrary.d.ts +0 -18
- package/dist/services/ProjectLibrary.d.ts.map +1 -1
- package/dist/services/ProjectLibrary.js +0 -20
- package/dist/services/ProjectLibrary.js.map +1 -1
- package/dist/services/ProjectMetadataStore.d.ts +0 -73
- package/dist/services/ProjectMetadataStore.d.ts.map +1 -1
- package/dist/services/ProjectMetadataStore.js +0 -90
- package/dist/services/ProjectMetadataStore.js.map +1 -1
- package/dist/services/ProjectPackageManager.d.ts +0 -12
- package/dist/services/ProjectPackageManager.d.ts.map +1 -1
- package/dist/services/ProjectPackageManager.js +0 -16
- package/dist/services/ProjectPackageManager.js.map +1 -1
- package/dist/services/ProjectRegistry.d.ts +0 -16
- package/dist/services/ProjectRegistry.d.ts.map +1 -1
- package/dist/services/ProjectRegistry.js +0 -18
- package/dist/services/ProjectRegistry.js.map +1 -1
- package/dist/services/ProjectRuntimeService.d.ts +0 -4
- package/dist/services/ProjectRuntimeService.d.ts.map +1 -1
- package/dist/services/ProjectRuntimeService.js +0 -5
- package/dist/services/ProjectRuntimeService.js.map +1 -1
- package/dist/services/ProjectScreenshotService.d.ts +0 -5
- package/dist/services/ProjectScreenshotService.d.ts.map +1 -1
- package/dist/services/ProjectScreenshotService.js +0 -6
- package/dist/services/ProjectScreenshotService.js.map +1 -1
- package/dist/services/ProjectStorage.d.ts +0 -4
- package/dist/services/ProjectStorage.d.ts.map +1 -1
- package/dist/services/ProjectStorage.js +0 -4
- package/dist/services/ProjectStorage.js.map +1 -1
- package/dist/services/PrototypeBuildService.d.ts +1 -23
- package/dist/services/PrototypeBuildService.d.ts.map +1 -1
- package/dist/services/PrototypeBuildService.js +6 -31
- package/dist/services/PrototypeBuildService.js.map +1 -1
- package/dist/services/PrototypeDeployService.d.ts +0 -20
- package/dist/services/PrototypeDeployService.d.ts.map +1 -1
- package/dist/services/PrototypeDeployService.js +1 -24
- package/dist/services/PrototypeDeployService.js.map +1 -1
- package/dist/services/RequestAuthContext.d.ts +0 -5
- package/dist/services/RequestAuthContext.d.ts.map +1 -1
- package/dist/services/RequestAuthContext.js +0 -5
- package/dist/services/RequestAuthContext.js.map +1 -1
- package/dist/services/SessionBridgeService.d.ts.map +1 -1
- package/dist/services/SessionBridgeService.js +0 -2
- package/dist/services/SessionBridgeService.js.map +1 -1
- package/dist/services/SessionService.d.ts +0 -4
- package/dist/services/SessionService.d.ts.map +1 -1
- package/dist/services/SessionService.js +1 -22
- package/dist/services/SessionService.js.map +1 -1
- package/dist/services/StaticFileService.d.ts +0 -9
- package/dist/services/StaticFileService.d.ts.map +1 -1
- package/dist/services/StaticFileService.js +0 -11
- package/dist/services/StaticFileService.js.map +1 -1
- package/dist/services/StaticLibraryPreviews.d.ts +0 -3
- package/dist/services/StaticLibraryPreviews.d.ts.map +1 -1
- package/dist/services/StaticLibraryPreviews.js +0 -3
- package/dist/services/StaticLibraryPreviews.js.map +1 -1
- package/dist/services/StaticPreviewServer.d.ts +0 -16
- package/dist/services/StaticPreviewServer.d.ts.map +1 -1
- package/dist/services/StaticPreviewServer.js +2 -28
- package/dist/services/StaticPreviewServer.js.map +1 -1
- package/dist/services/SupabaseAuthService.d.ts +0 -11
- package/dist/services/SupabaseAuthService.d.ts.map +1 -1
- package/dist/services/SupabaseAuthService.js +0 -11
- package/dist/services/SupabaseAuthService.js.map +1 -1
- package/dist/services/SupportTicketService.d.ts +0 -4
- package/dist/services/SupportTicketService.d.ts.map +1 -1
- package/dist/services/SupportTicketService.js +0 -4
- package/dist/services/SupportTicketService.js.map +1 -1
- package/dist/services/TelemetryService.d.ts +0 -182
- package/dist/services/TelemetryService.d.ts.map +1 -1
- package/dist/services/TelemetryService.js +0 -193
- package/dist/services/TelemetryService.js.map +1 -1
- package/dist/services/TreeStore.d.ts +0 -72
- package/dist/services/TreeStore.d.ts.map +1 -1
- package/dist/services/TreeStore.js +0 -93
- package/dist/services/TreeStore.js.map +1 -1
- package/dist/services/VariantGenerationService.d.ts +0 -32
- package/dist/services/VariantGenerationService.d.ts.map +1 -1
- package/dist/services/VariantGenerationService.js +5 -62
- package/dist/services/VariantGenerationService.js.map +1 -1
- package/dist/services/VariantHistoryService.d.ts +0 -114
- package/dist/services/VariantHistoryService.d.ts.map +1 -1
- package/dist/services/VariantHistoryService.js +2 -144
- package/dist/services/VariantHistoryService.js.map +1 -1
- package/dist/services/VariantRunService.d.ts +0 -31
- package/dist/services/VariantRunService.d.ts.map +1 -1
- package/dist/services/VariantRunService.js +0 -35
- package/dist/services/VariantRunService.js.map +1 -1
- package/dist/services/VariantsRuntime.d.ts +0 -3
- package/dist/services/VariantsRuntime.d.ts.map +1 -1
- package/dist/services/VariantsRuntime.js +0 -5
- package/dist/services/VariantsRuntime.js.map +1 -1
- package/dist/services/WorktreeManager.d.ts +0 -217
- package/dist/services/WorktreeManager.d.ts.map +1 -1
- package/dist/services/WorktreeManager.js +3 -321
- package/dist/services/WorktreeManager.js.map +1 -1
- package/dist/services/accessTokenRefresh.d.ts +0 -25
- package/dist/services/accessTokenRefresh.d.ts.map +1 -1
- package/dist/services/accessTokenRefresh.js +0 -25
- package/dist/services/accessTokenRefresh.js.map +1 -1
- package/dist/services/adapters/TailwindTokenAdapter.d.ts +0 -29
- package/dist/services/adapters/TailwindTokenAdapter.d.ts.map +1 -1
- package/dist/services/adapters/TailwindTokenAdapter.js +1 -46
- package/dist/services/adapters/TailwindTokenAdapter.js.map +1 -1
- package/dist/services/createAgentVariantsOrchestrator.d.ts +0 -18
- package/dist/services/createAgentVariantsOrchestrator.d.ts.map +1 -1
- package/dist/services/createAgentVariantsOrchestrator.js +0 -22
- package/dist/services/createAgentVariantsOrchestrator.js.map +1 -1
- package/dist/services/extractors/CSSVariableExtractor.d.ts +0 -25
- package/dist/services/extractors/CSSVariableExtractor.d.ts.map +1 -1
- package/dist/services/extractors/CSSVariableExtractor.js +1 -42
- package/dist/services/extractors/CSSVariableExtractor.js.map +1 -1
- package/dist/services/historyRoots.d.ts +0 -12
- package/dist/services/historyRoots.d.ts.map +1 -1
- package/dist/services/historyRoots.js +0 -13
- package/dist/services/historyRoots.js.map +1 -1
- package/dist/services/libraryErrors.d.ts +0 -1
- package/dist/services/libraryErrors.d.ts.map +1 -1
- package/dist/services/libraryErrors.js +0 -1
- package/dist/services/libraryErrors.js.map +1 -1
- package/dist/services/pendingLogin.d.ts +0 -13
- package/dist/services/pendingLogin.d.ts.map +1 -1
- package/dist/services/pendingLogin.js +0 -3
- package/dist/services/pendingLogin.js.map +1 -1
- package/dist/services/staticProjectTarget.d.ts +0 -4
- package/dist/services/staticProjectTarget.d.ts.map +1 -1
- package/dist/services/staticProjectTarget.js +0 -4
- package/dist/services/staticProjectTarget.js.map +1 -1
- package/dist/services/staticStarter.d.ts +0 -20
- package/dist/services/staticStarter.d.ts.map +1 -1
- package/dist/services/staticStarter.js +0 -20
- package/dist/services/staticStarter.js.map +1 -1
- package/dist/services/templates/designCatalog.d.ts +0 -11
- package/dist/services/templates/designCatalog.d.ts.map +1 -1
- package/dist/services/templates/designCatalog.js +0 -26
- package/dist/services/templates/designCatalog.js.map +1 -1
- package/dist/services/templates/viteReactTs.d.ts +0 -26
- package/dist/services/templates/viteReactTs.d.ts.map +1 -1
- package/dist/services/templates/viteReactTs.js +0 -20
- package/dist/services/templates/viteReactTs.js.map +1 -1
- package/dist/storage/library/BundleMetadataStore.d.ts +0 -16
- package/dist/storage/library/BundleMetadataStore.d.ts.map +1 -1
- package/dist/storage/library/BundleMetadataStore.js +0 -17
- package/dist/storage/library/BundleMetadataStore.js.map +1 -1
- package/dist/storage/library/CoordinatorRecords.d.ts +0 -9
- package/dist/storage/library/CoordinatorRecords.d.ts.map +1 -1
- package/dist/storage/library/CoordinatorRecords.js +0 -9
- package/dist/storage/library/CoordinatorRecords.js.map +1 -1
- package/dist/storage/library/ProjectPreviewCache.d.ts +0 -4
- package/dist/storage/library/ProjectPreviewCache.d.ts.map +1 -1
- package/dist/storage/library/ProjectPreviewCache.js +0 -4
- package/dist/storage/library/ProjectPreviewCache.js.map +1 -1
- package/dist/storage/library/ProjectRecords.d.ts +0 -17
- package/dist/storage/library/ProjectRecords.d.ts.map +1 -1
- package/dist/storage/library/ProjectRecords.js +0 -17
- package/dist/storage/library/ProjectRecords.js.map +1 -1
- package/dist/storage/library/database.d.ts +0 -3
- package/dist/storage/library/database.d.ts.map +1 -1
- package/dist/storage/library/database.js +0 -3
- package/dist/storage/library/database.js.map +1 -1
- package/dist/storage/library/migrations.d.ts +0 -2
- package/dist/storage/library/migrations.d.ts.map +1 -1
- package/dist/storage/library/migrations.js +0 -2
- package/dist/storage/library/migrations.js.map +1 -1
- package/dist/storage/library/sourcePresentation.d.ts +0 -1
- package/dist/storage/library/sourcePresentation.d.ts.map +1 -1
- package/dist/storage/library/sourcePresentation.js +0 -1
- package/dist/storage/library/sourcePresentation.js.map +1 -1
- package/dist/storage/project-metadata/ProjectMetadataRecords.d.ts +0 -11
- package/dist/storage/project-metadata/ProjectMetadataRecords.d.ts.map +1 -1
- package/dist/storage/project-metadata/ProjectMetadataRecords.js +0 -13
- package/dist/storage/project-metadata/ProjectMetadataRecords.js.map +1 -1
- package/dist/storage/project-metadata/database.d.ts +0 -1
- package/dist/storage/project-metadata/database.d.ts.map +1 -1
- package/dist/storage/project-metadata/database.js +0 -7
- package/dist/storage/project-metadata/database.js.map +1 -1
- package/dist/storage/project-metadata/migrations.d.ts +0 -42
- package/dist/storage/project-metadata/migrations.d.ts.map +1 -1
- package/dist/storage/project-metadata/migrations.js +0 -41
- package/dist/storage/project-metadata/migrations.js.map +1 -1
- package/dist/types/account.d.ts +0 -1
- package/dist/types/account.d.ts.map +1 -1
- package/dist/types/change-request-types.d.ts +0 -167
- package/dist/types/change-request-types.d.ts.map +1 -1
- package/dist/types/change-types.d.ts +0 -1
- package/dist/types/change-types.d.ts.map +1 -1
- package/dist/types/change-types.js +0 -1
- package/dist/types/change-types.js.map +1 -1
- package/dist/types/project-library.d.ts +0 -1
- package/dist/types/project-library.d.ts.map +1 -1
- package/dist/types/style-manipulation-types.d.ts +0 -69
- package/dist/types/style-manipulation-types.d.ts.map +1 -1
- package/dist/types/style-manipulation-types.js +0 -26
- package/dist/types/style-manipulation-types.js.map +1 -1
- package/dist/types/token-types.d.ts +0 -30
- package/dist/types/token-types.d.ts.map +1 -1
- package/dist/types/token-types.js +0 -1
- package/dist/types/token-types.js.map +1 -1
- package/dist/types/variant-history.d.ts +0 -39
- package/dist/types/variant-history.d.ts.map +1 -1
- package/dist/utils/branchNames.d.ts +0 -1
- package/dist/utils/branchNames.d.ts.map +1 -1
- package/dist/utils/branchNames.js +0 -2
- package/dist/utils/branchNames.js.map +1 -1
- package/dist/utils/cloneOrCopyDirSync.d.ts +0 -12
- package/dist/utils/cloneOrCopyDirSync.d.ts.map +1 -1
- package/dist/utils/cloneOrCopyDirSync.js +0 -16
- package/dist/utils/cloneOrCopyDirSync.js.map +1 -1
- package/dist/utils/devServerCommand.d.ts +0 -23
- package/dist/utils/devServerCommand.d.ts.map +1 -1
- package/dist/utils/devServerCommand.js +0 -24
- package/dist/utils/devServerCommand.js.map +1 -1
- package/dist/utils/devServerError.d.ts +0 -16
- package/dist/utils/devServerError.d.ts.map +1 -1
- package/dist/utils/devServerError.js +0 -17
- package/dist/utils/devServerError.js.map +1 -1
- package/dist/utils/displayLocale.d.ts +0 -2
- package/dist/utils/displayLocale.d.ts.map +1 -1
- package/dist/utils/displayLocale.js +0 -2
- package/dist/utils/displayLocale.js.map +1 -1
- package/dist/utils/elementFileHintSignals.d.ts +0 -5
- package/dist/utils/elementFileHintSignals.d.ts.map +1 -1
- package/dist/utils/elementFileHintSignals.js +0 -5
- package/dist/utils/elementFileHintSignals.js.map +1 -1
- package/dist/utils/formatElementTargetingContext.d.ts +0 -6
- package/dist/utils/formatElementTargetingContext.d.ts.map +1 -1
- package/dist/utils/formatElementTargetingContext.js +3 -9
- package/dist/utils/formatElementTargetingContext.js.map +1 -1
- package/dist/utils/hostAgentEnv.d.ts +0 -17
- package/dist/utils/hostAgentEnv.d.ts.map +1 -1
- package/dist/utils/hostAgentEnv.js +0 -17
- package/dist/utils/hostAgentEnv.js.map +1 -1
- package/dist/utils/htmlDocument.d.ts +0 -5
- package/dist/utils/htmlDocument.d.ts.map +1 -1
- package/dist/utils/htmlDocument.js +2 -7
- package/dist/utils/htmlDocument.js.map +1 -1
- package/dist/utils/internalGitIdentity.d.ts +0 -5
- package/dist/utils/internalGitIdentity.d.ts.map +1 -1
- package/dist/utils/internalGitIdentity.js +0 -5
- package/dist/utils/internalGitIdentity.js.map +1 -1
- package/dist/utils/logger.d.ts +0 -5
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +2 -19
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/loginShellPath.d.ts +0 -9
- package/dist/utils/loginShellPath.d.ts.map +1 -1
- package/dist/utils/loginShellPath.js +0 -69
- package/dist/utils/loginShellPath.js.map +1 -1
- package/dist/utils/loopback.d.ts +0 -1
- package/dist/utils/loopback.d.ts.map +1 -1
- package/dist/utils/loopback.js +0 -1
- package/dist/utils/loopback.js.map +1 -1
- package/dist/utils/pid.d.ts +0 -1
- package/dist/utils/pid.d.ts.map +1 -1
- package/dist/utils/pid.js +0 -1
- package/dist/utils/pid.js.map +1 -1
- package/dist/utils/portUtils.d.ts +0 -15
- package/dist/utils/portUtils.d.ts.map +1 -1
- package/dist/utils/portUtils.js +0 -21
- package/dist/utils/portUtils.js.map +1 -1
- package/dist/utils/queueAccess.d.ts +0 -9
- package/dist/utils/queueAccess.d.ts.map +1 -1
- package/dist/utils/queueAccess.js +0 -9
- package/dist/utils/queueAccess.js.map +1 -1
- package/dist/utils/skillWriter.d.ts +0 -17
- package/dist/utils/skillWriter.d.ts.map +1 -1
- package/dist/utils/skillWriter.js +0 -20
- package/dist/utils/skillWriter.js.map +1 -1
- package/dist/utils/skills/claude-skill.d.ts +0 -5
- package/dist/utils/skills/claude-skill.d.ts.map +1 -1
- package/dist/utils/skills/claude-skill.js +0 -5
- package/dist/utils/skills/claude-skill.js.map +1 -1
- package/dist/utils/skills/cli-guidance.d.ts +0 -8
- package/dist/utils/skills/cli-guidance.d.ts.map +1 -1
- package/dist/utils/skills/cli-guidance.js +0 -8
- package/dist/utils/skills/cli-guidance.js.map +1 -1
- package/dist/utils/skills/cursor-rules.d.ts +0 -6
- package/dist/utils/skills/cursor-rules.d.ts.map +1 -1
- package/dist/utils/skills/cursor-rules.js +0 -6
- package/dist/utils/skills/cursor-rules.js.map +1 -1
- package/dist/utils/variantPreviewPort.d.ts +0 -3
- package/dist/utils/variantPreviewPort.d.ts.map +1 -1
- package/dist/utils/variantPreviewPort.js +0 -3
- package/dist/utils/variantPreviewPort.js.map +1 -1
- package/dist/utils/windowPlacement.d.ts +0 -4
- package/dist/utils/windowPlacement.d.ts.map +1 -1
- package/dist/utils/windowPlacement.js +0 -4
- package/dist/utils/windowPlacement.js.map +1 -1
- package/package.json +12 -13
- package/scripts/verify-node-version.cjs +0 -3
- package/src/ui/dist/assets/{LibraryApp-qbLqcNxM.js → LibraryApp-x6PbzlGr.js} +1 -1
- package/src/ui/dist/assets/{main-touv07Dk.js → main-BW1Odsqp.js} +75 -75
- package/src/ui/dist/assets/main-DDQRZm89.css +1 -0
- package/src/ui/dist/index.html +2 -2
- package/dist/utils/skills/describe-motion-protocol.d.ts +0 -10
- package/dist/utils/skills/describe-motion-protocol.d.ts.map +0 -1
- package/dist/utils/skills/describe-motion-protocol.js +0 -231
- package/dist/utils/skills/describe-motion-protocol.js.map +0 -1
- package/src/ui/dist/assets/main-BUZjlAHd.css +0 -1
|
@@ -75,44 +75,14 @@ const FALLBACK_DIRECTION_FOCI = [
|
|
|
75
75
|
'Explore tactile depth, layering, and purposeful interaction cues.',
|
|
76
76
|
'Reduce the concept to its most essential typography and geometry.',
|
|
77
77
|
];
|
|
78
|
-
// Upper bound on waiting for in-flight history persists during session
|
|
79
|
-
// teardown. Generous enough for a full-repo snapshot on a large project;
|
|
80
|
-
// small enough that a wedged git subprocess (which has its own 120s block
|
|
81
|
-
// timeout) can't make commit/cancel appear hung.
|
|
82
78
|
const SETTLE_PERSISTS_TEARDOWN_TIMEOUT_MS = 20_000;
|
|
83
|
-
// Sentinel port for deriving a persist-time serve recipe when the dev server
|
|
84
|
-
// hasn't booted yet: resolved into the command, then reverse-substituted to
|
|
85
|
-
// the ${PORT} placeholder. Digit-boundary-guarded substitution means only an
|
|
86
|
-
// exact standalone occurrence is replaced, and 65535 never appears in any
|
|
87
|
-
// framework's default invocation.
|
|
88
79
|
const RECIPE_PORT_SENTINEL = 65535;
|
|
89
|
-
// Fresh worktrees run the Vite React template, whose dev server defaults to
|
|
90
|
-
// 5173. Used as the scan start when allocating a fresh variant's preview port.
|
|
91
80
|
const FRESH_DEV_SERVER_DEFAULT_PORT = 5173;
|
|
92
|
-
// Startup attempts for a variant's dev server. Attempt 2 covers a transient
|
|
93
|
-
// early exit (with a dependency install first when the output shows
|
|
94
|
-
// module-resolution errors); attempt 3 leaves room for one more port step
|
|
95
|
-
// when a collision persists. Early exits fail fast, so extra attempts cost
|
|
96
|
-
// little wall clock.
|
|
97
81
|
const DEV_SERVER_START_MAX_ATTEMPTS = 3;
|
|
98
|
-
// Auto-restarts allowed after a READY dev server crashes (see the exit
|
|
99
|
-
// handler in startVariantDevServer). Two rescues cover transient crashes;
|
|
100
|
-
// a third crash means the build is genuinely broken, so stop looping.
|
|
101
82
|
const DEV_SERVER_MAX_AUTO_RESTARTS = 2;
|
|
102
|
-
// Grace before an auto-restart so a crashing process's port and file locks
|
|
103
|
-
// are actually released first.
|
|
104
83
|
const DEV_SERVER_RESTART_DELAY_MS = 1_000;
|
|
105
84
|
const DESIGN_CONTEXT_ROUTE_SEGMENT = 'design-md';
|
|
106
85
|
const DESIGN_CONTEXT_VIEW_SEGMENT = 'view';
|
|
107
|
-
// Hard ceiling on worktree provisioning so a slow/large host project can never
|
|
108
|
-
// stall the `start_variants` / `approve_variant_briefs` tool call indefinitely.
|
|
109
|
-
// Existing-project provisioning clones the host working tree once per variant
|
|
110
|
-
// (`git worktree add` + untracked-file copy), so its cost scales with repo
|
|
111
|
-
// size — a big monorepo (or a React Native tree with native build dirs) used to
|
|
112
|
-
// hang the call for 15+ minutes with no signal. With this bound the call fails
|
|
113
|
-
// fast and legibly instead. Per-git-op hangs are already caught by simple-git's
|
|
114
|
-
// block timeout in WorktreeManager; this is the cross-op backstop. Override via
|
|
115
|
-
// env for unusually large repos.
|
|
116
86
|
const DEFAULT_PROVISION_TIMEOUT_MS = 540_000;
|
|
117
87
|
const PROVISION_TIMEOUT_MS = (() => {
|
|
118
88
|
const raw = process.env.RIVET_VARIANTS_PROVISION_TIMEOUT_MS;
|
|
@@ -121,10 +91,6 @@ const PROVISION_TIMEOUT_MS = (() => {
|
|
|
121
91
|
? parsed
|
|
122
92
|
: DEFAULT_PROVISION_TIMEOUT_MS;
|
|
123
93
|
})();
|
|
124
|
-
// Active variant dev servers are useful only while the Rivet app is being used.
|
|
125
|
-
// Reclaim them after app/API silence so abandoned sessions do not pin one child
|
|
126
|
-
// process per succeeded variant forever. The session state and worktrees stay
|
|
127
|
-
// intact; only live preview ports are cleared.
|
|
128
94
|
const DEFAULT_ACTIVE_VARIANT_SERVER_IDLE_TTL_MS = 30 * 60 * 1000;
|
|
129
95
|
const ACTIVE_VARIANT_SERVER_IDLE_TTL_MS = (() => {
|
|
130
96
|
const raw = process.env.RIVET_ACTIVE_VARIANT_SERVER_IDLE_TTL_MS;
|
|
@@ -133,7 +99,6 @@ const ACTIVE_VARIANT_SERVER_IDLE_TTL_MS = (() => {
|
|
|
133
99
|
? parsed
|
|
134
100
|
: DEFAULT_ACTIVE_VARIANT_SERVER_IDLE_TTL_MS;
|
|
135
101
|
})();
|
|
136
|
-
/** Sentinel so callers can distinguish a provisioning timeout from other errors. */
|
|
137
102
|
class ProvisionTimeoutError extends Error {
|
|
138
103
|
timeoutMs;
|
|
139
104
|
constructor(timeoutMs) {
|
|
@@ -142,12 +107,6 @@ class ProvisionTimeoutError extends Error {
|
|
|
142
107
|
this.name = 'ProvisionTimeoutError';
|
|
143
108
|
}
|
|
144
109
|
}
|
|
145
|
-
/**
|
|
146
|
-
* Reject with `ProvisionTimeoutError` if `work` hasn't settled within
|
|
147
|
-
* `timeoutMs`. The underlying work is NOT cancellable (git/fs I/O), so it may
|
|
148
|
-
* keep running after we reject — callers should best-effort clean up partial
|
|
149
|
-
* state. The timer is unref'd so it never keeps the process alive on its own.
|
|
150
|
-
*/
|
|
151
110
|
function withProvisionTimeout(work, timeoutMs) {
|
|
152
111
|
let timer;
|
|
153
112
|
const timeout = new Promise((_, reject) => {
|
|
@@ -157,11 +116,6 @@ function withProvisionTimeout(work, timeoutMs) {
|
|
|
157
116
|
});
|
|
158
117
|
return Promise.race([work, timeout]).finally(() => clearTimeout(timer));
|
|
159
118
|
}
|
|
160
|
-
/**
|
|
161
|
-
* File types an agent-authored asset plan may copy into a generated preview.
|
|
162
|
-
* This allowlist protects an agent-controlled path; caller-selected context
|
|
163
|
-
* assets use the separate, type-neutral delivery path.
|
|
164
|
-
*/
|
|
165
119
|
const ALLOWED_INERT_ASSET_EXTENSIONS = new Set([
|
|
166
120
|
'.glb',
|
|
167
121
|
'.gltf',
|
|
@@ -191,13 +145,6 @@ const ALLOWED_INERT_ASSET_EXTENSIONS = new Set([
|
|
|
191
145
|
'.eot',
|
|
192
146
|
'.pdf',
|
|
193
147
|
]);
|
|
194
|
-
/**
|
|
195
|
-
* Reject paths that traverse through a "sensitive" directory anywhere
|
|
196
|
-
* in their ancestry — `.ssh`, `.aws`, `.config`, `.gnupg`, etc. Even if
|
|
197
|
-
* a copy passes the extension allowlist, an agent-controlled source
|
|
198
|
-
* resolving inside `~/.ssh/` is almost certainly an exfiltration
|
|
199
|
-
* attempt rather than a legitimate asset reference.
|
|
200
|
-
*/
|
|
201
148
|
const SENSITIVE_PATH_SEGMENTS = new Set([
|
|
202
149
|
'.ssh',
|
|
203
150
|
'.aws',
|
|
@@ -214,14 +161,9 @@ const SENSITIVE_PATH_SEGMENTS = new Set([
|
|
|
214
161
|
'credentials',
|
|
215
162
|
]);
|
|
216
163
|
function hasSensitivePathSegment(absolutePath) {
|
|
217
|
-
// Split on any path separator; check each segment case-insensitively.
|
|
218
164
|
const segments = absolutePath.split(/[/\\]/).filter(Boolean);
|
|
219
165
|
return segments.some((segment) => SENSITIVE_PATH_SEGMENTS.has(segment.toLowerCase()));
|
|
220
166
|
}
|
|
221
|
-
/**
|
|
222
|
-
* Returns true when `absolutePath` is the root itself or one of its
|
|
223
|
-
* descendants after both paths have been resolved.
|
|
224
|
-
*/
|
|
225
167
|
function isPathWithinRoot(absolutePath, root) {
|
|
226
168
|
const relative = path_1.default.relative(root, absolutePath);
|
|
227
169
|
return (relative === '' ||
|
|
@@ -229,25 +171,6 @@ function isPathWithinRoot(absolutePath, root) {
|
|
|
229
171
|
!relative.startsWith('..') &&
|
|
230
172
|
!path_1.default.isAbsolute(relative)));
|
|
231
173
|
}
|
|
232
|
-
/**
|
|
233
|
-
* Copy one agent-planned asset file into a variant worktree at the
|
|
234
|
-
* project-relative `destination`. The agent decides routing
|
|
235
|
-
* (`destination` like `public/assets/avatar.glb`) so all variants share
|
|
236
|
-
* a consistent layout. Fails loudly when the source is missing or the
|
|
237
|
-
* destination tries to escape the worktree — silent fallbacks here
|
|
238
|
-
* would re-introduce the broken-asset failure mode this routing is
|
|
239
|
-
* supposed to prevent.
|
|
240
|
-
*
|
|
241
|
-
* Security: `entry.source` comes from `report_source_plan` and is
|
|
242
|
-
* agent-controlled. To prevent a prompt-injected source plan from
|
|
243
|
-
* exfiltrating arbitrary readable host files (SSH keys, dotfiles,
|
|
244
|
-
* cloud credentials, project secrets) into the generated app, the
|
|
245
|
-
* source must (1) be an absolute path that resolves via realpath
|
|
246
|
-
* (no traversal, no symlinks pointing outside the resolved location),
|
|
247
|
-
* (2) be a regular file (not a device, socket, fifo, or directory),
|
|
248
|
-
* (3) live under the approved asset root, (4) have an extension on the
|
|
249
|
-
* asset allowlist.
|
|
250
|
-
*/
|
|
251
174
|
function copyAssetIntoWorktree(worktreePath, entry, assetSourceRoot) {
|
|
252
175
|
if (!assetSourceRoot) {
|
|
253
176
|
throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetPlan.source requires an approved asset root before copying '${entry.source}'`);
|
|
@@ -255,14 +178,6 @@ function copyAssetIntoWorktree(worktreePath, entry, assetSourceRoot) {
|
|
|
255
178
|
if (!path_1.default.isAbsolute(assetSourceRoot)) {
|
|
256
179
|
throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetSourceRoot must be an absolute path, got '${assetSourceRoot}'`);
|
|
257
180
|
}
|
|
258
|
-
// A relative source is resolved against the approved asset root. The
|
|
259
|
-
// agent-facing protocol requires the source to live under that root but not
|
|
260
|
-
// to be absolute, and the root path is internal to Rivet (a staged context
|
|
261
|
-
// bundle) — so a relative name such as 'avatar.glb' is the natural, safe
|
|
262
|
-
// form. Every downstream guard (symlink, extension, within-root, sensitive
|
|
263
|
-
// segments) runs against this resolved absolute path, so the resolution
|
|
264
|
-
// cannot widen what is copyable: a relative `..` escape still fails the
|
|
265
|
-
// within-root check below.
|
|
266
181
|
const absoluteSource = path_1.default.isAbsolute(entry.source)
|
|
267
182
|
? entry.source
|
|
268
183
|
: path_1.default.resolve(assetSourceRoot, entry.source);
|
|
@@ -270,10 +185,6 @@ function copyAssetIntoWorktree(worktreePath, entry, assetSourceRoot) {
|
|
|
270
185
|
if (!ALLOWED_INERT_ASSET_EXTENSIONS.has(ext)) {
|
|
271
186
|
throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetPlan.source extension '${ext || '(none)'}' is not on the allowlist (got '${entry.source}'). Only inert media/font/document assets may be copied.`);
|
|
272
187
|
}
|
|
273
|
-
// lstat first: a symlink whose target lies outside the source path
|
|
274
|
-
// could otherwise smuggle in arbitrary files. Reject symlinks outright;
|
|
275
|
-
// realpath would resolve them but the user-visible intent of an
|
|
276
|
-
// assetPlan entry is to name a concrete file.
|
|
277
188
|
let lstat;
|
|
278
189
|
try {
|
|
279
190
|
lstat = fs_1.default.lstatSync(absoluteSource);
|
|
@@ -287,9 +198,6 @@ function copyAssetIntoWorktree(worktreePath, entry, assetSourceRoot) {
|
|
|
287
198
|
if (!lstat.isFile()) {
|
|
288
199
|
throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetPlan.source must be a regular file: ${entry.source}`);
|
|
289
200
|
}
|
|
290
|
-
// Resolve realpath as additional defense: even with no symlinks at the
|
|
291
|
-
// leaf, an intermediate directory could be a symlink. Cross-check the
|
|
292
|
-
// file kind on the resolved path.
|
|
293
201
|
let resolvedSource;
|
|
294
202
|
try {
|
|
295
203
|
resolvedSource = fs_1.default.realpathSync(absoluteSource);
|
|
@@ -308,24 +216,9 @@ function copyAssetIntoWorktree(worktreePath, entry, assetSourceRoot) {
|
|
|
308
216
|
if (!resolvedStat.isFile()) {
|
|
309
217
|
throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetPlan.source resolved target must be a regular file: ${entry.source}`);
|
|
310
218
|
}
|
|
311
|
-
// Containment is the security boundary and must be checked before any
|
|
312
|
-
// sensitive-segment scan. The approved asset root is system-chosen and
|
|
313
|
-
// trusted (a staged context bundle), and its realpath can legitimately
|
|
314
|
-
// pass through a "sensitive" segment that is NOT agent-controlled — on
|
|
315
|
-
// macOS `fs.realpathSync(os.tmpdir())` resolves to `/private/var/folders/...`,
|
|
316
|
-
// so the temp-staged root contains `private`. A symlinked intermediate dir
|
|
317
|
-
// that forwards into a sensitive ancestor (e.g. `<asset-root>/avatar -> ~/.ssh`)
|
|
318
|
-
// pushes the realpath OUTSIDE the root and is rejected here.
|
|
319
219
|
if (!isPathWithinRoot(resolvedSource, resolvedAssetSourceRoot)) {
|
|
320
220
|
throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetPlan.source must stay inside the approved asset root: ${entry.source}`);
|
|
321
221
|
}
|
|
322
|
-
// Sensitive-segment defense, scoped to the agent-controlled portion BELOW
|
|
323
|
-
// the trusted root. Only this relative remainder is chosen by the agent's
|
|
324
|
-
// source plan, so a sensitive segment it introduces under the root (a real
|
|
325
|
-
// `<asset-root>/.ssh/key.glb`, or a within-root symlink that realpaths into
|
|
326
|
-
// one) is still refused, while the trusted root prefix is never scanned.
|
|
327
|
-
// `resolvedSource` is the fully symlink-resolved real path, so the scan
|
|
328
|
-
// covers what the file actually resolves to, not just its literal name.
|
|
329
222
|
const relativeResolvedSource = path_1.default.relative(resolvedAssetSourceRoot, resolvedSource);
|
|
330
223
|
if (hasSensitivePathSegment(relativeResolvedSource)) {
|
|
331
224
|
throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetPlan.source traverses a sensitive directory and is refused: ${entry.source}`);
|
|
@@ -343,7 +236,6 @@ function copyAssetIntoWorktree(worktreePath, entry, assetSourceRoot) {
|
|
|
343
236
|
fs_1.default.copyFileSync(resolvedSource, absDest);
|
|
344
237
|
}
|
|
345
238
|
const defaultPreviewQaRunner = ({ html }) => (0, previewQa_1.runPreviewQa)({ html });
|
|
346
|
-
/** Disabled-reason copy for a variant whose preview cannot be opened. */
|
|
347
239
|
const buildViewDisabledReason = (args) => {
|
|
348
240
|
if (args.status === 'failed') {
|
|
349
241
|
return args.qa?.summary ?? 'Generation failed';
|
|
@@ -367,11 +259,9 @@ const DESIGN_CREATION_ACTION_RE = /\b(create|build|design|make|redesign|refresh|
|
|
|
367
259
|
const DESIGN_CREATION_SURFACE_RE = /\b(home\s?page|landing page|dashboard|screen|site|website|app|page|ui|interface|component|hero)\b/i;
|
|
368
260
|
const NON_VISUAL_CHANGE_RE = /\b(api|backend|database|event|lint|query|server|test|tracking|typecheck)\b/i;
|
|
369
261
|
const DIFF_CAPTURE_FAILURE_SUMMARY = 'Unable to verify the generated design diff; regenerate this variant so Rivet can confirm source changes.';
|
|
370
|
-
/** Separates invalid worker output from a Rivet check that could not run. */
|
|
371
262
|
const qaFailureErrorCode = (qa) => qa.issues.some((issue) => issue.kind === 'verification_unavailable')
|
|
372
263
|
? 'VARIANT_VERIFICATION_UNAVAILABLE'
|
|
373
264
|
: 'VARIANT_QA_FAILED';
|
|
374
|
-
/** Identifies a repair-triggering completion across transport retries. */
|
|
375
265
|
const repairCompletionKey = (args) => JSON.stringify([args.workItemId, args.leaseId, args.attempt, 'succeeded']);
|
|
376
266
|
const briefLabelKey = (value) => value.trim().toLowerCase().replace(/\s+/g, ' ');
|
|
377
267
|
const truncateBriefLabel = (value) => {
|
|
@@ -452,17 +342,6 @@ const isDesignCreationCodeGenInput = (input, prompt) => {
|
|
|
452
342
|
return (DESIGN_CREATION_ACTION_RE.test(text) &&
|
|
453
343
|
DESIGN_CREATION_SURFACE_RE.test(text));
|
|
454
344
|
};
|
|
455
|
-
/**
|
|
456
|
-
* Wraps SessionStore for the operations that have side effects: approve
|
|
457
|
-
* (provision worktrees), reportComplete (capture diff), commit (apply picked
|
|
458
|
-
* output), cancel (teardown). Pure read paths bypass and call SessionStore
|
|
459
|
-
* directly.
|
|
460
|
-
*
|
|
461
|
-
* This is the terminal-native variant of the orchestrator: the user picks
|
|
462
|
-
* a single brief upfront, so there's only ever one code-gen item per
|
|
463
|
-
* session and no live preview / proxy retarget. Once the agent reports
|
|
464
|
-
* the variant succeeded, the CLI can commit the chosen output directly.
|
|
465
|
-
*/
|
|
466
345
|
class AgentVariantsOrchestrator {
|
|
467
346
|
store;
|
|
468
347
|
worktrees;
|
|
@@ -479,31 +358,9 @@ class AgentVariantsOrchestrator {
|
|
|
479
358
|
activeVariantServerIdleTtlMs;
|
|
480
359
|
devServerRestartDelayMs;
|
|
481
360
|
resources = new Map();
|
|
482
|
-
/**
|
|
483
|
-
* Committed dev servers from prior sessions that survived teardown. The
|
|
484
|
-
* orchestrator outlives any single session — once a new session starts, the
|
|
485
|
-
* prior committed dev server is no longer needed (the next session opens
|
|
486
|
-
* its own preview chip), so stop it before the new session's first preview
|
|
487
|
-
* goes live. Keyed by sessionId for diagnostics; values are kept alive
|
|
488
|
-
* intentionally between commit and next `propose` / `shutdown`.
|
|
489
|
-
*/
|
|
490
361
|
lingeringCommittedDevServers = new Map();
|
|
491
|
-
/**
|
|
492
|
-
* Per-session in-flight commit chain. Two overlapping commitVariant calls
|
|
493
|
-
* would otherwise both pass the `getVariantPick` idempotency check (the
|
|
494
|
-
* pick isn't recorded until after `applyDiffToProject`) and double-invoke
|
|
495
|
-
* `git apply` — which corrupts the working tree on the second run. The
|
|
496
|
-
* chain serializes commits per session so the second caller waits for the
|
|
497
|
-
* first to finish and then hits the idempotency check (returning
|
|
498
|
-
* `duplicate: true` for the same variantId, or `PENDING_CHANGE_CONFLICT`
|
|
499
|
-
* for a different one).
|
|
500
|
-
*/
|
|
501
362
|
inflightCommits = new Map();
|
|
502
|
-
/** Most recent agent-variants sessionId — read by the iframe chip via
|
|
503
|
-
* GET /api/variants/active. Cleared on cancel or commit. */
|
|
504
363
|
activeSessionId = null;
|
|
505
|
-
/** Push channel for the iframe chip's SSE subscription. Emits an
|
|
506
|
-
* ActiveSnapshot on every state change so the chip never has to poll. */
|
|
507
364
|
events = new events_1.EventEmitter();
|
|
508
365
|
constructor(deps) {
|
|
509
366
|
this.store = deps.store;
|
|
@@ -526,11 +383,7 @@ class AgentVariantsOrchestrator {
|
|
|
526
383
|
this.devServerRestartDelayMs =
|
|
527
384
|
deps.devServerRestartDelayMs ?? DEV_SERVER_RESTART_DELAY_MS;
|
|
528
385
|
}
|
|
529
|
-
// --- Pure delegations (no side effects) ---------------------------------
|
|
530
386
|
propose(args) {
|
|
531
|
-
// A new session means any lingering committed dev server from a prior
|
|
532
|
-
// session is no longer needed — the next session opens its own preview.
|
|
533
|
-
// Best-effort stop; failures here don't block propose.
|
|
534
387
|
void this.stopLingeringCommittedDevServers().catch((err) => {
|
|
535
388
|
log.warn('Stopping lingering committed dev servers failed', err);
|
|
536
389
|
});
|
|
@@ -577,36 +430,18 @@ class AgentVariantsOrchestrator {
|
|
|
577
430
|
this.emitChange();
|
|
578
431
|
return result;
|
|
579
432
|
}
|
|
580
|
-
/** Returns the most recent agent-variants sessionId (or null). */
|
|
581
433
|
getActiveSessionId() {
|
|
582
434
|
return this.activeSessionId;
|
|
583
435
|
}
|
|
584
|
-
/** Subscribe to active-snapshot pushes. Returns an unsubscribe fn. */
|
|
585
436
|
subscribeToEvents(listener) {
|
|
586
437
|
this.events.on('change', listener);
|
|
587
438
|
return () => {
|
|
588
439
|
this.events.off('change', listener);
|
|
589
440
|
};
|
|
590
441
|
}
|
|
591
|
-
/** Number of live Rivet UI clients subscribed to the variants SSE stream.
|
|
592
|
-
* A subscribed client means a Rivet page is open in the browser. */
|
|
593
442
|
uiClientCount = 0;
|
|
594
|
-
/** Wall-clock of the last UI-client connect/disconnect. `hasUiClients`
|
|
595
|
-
* treats a very recent disconnect as still-connected to ride out the brief
|
|
596
|
-
* gap when an EventSource drops and auto-reconnects (default retry ~3s) —
|
|
597
|
-
* otherwise a `propose`/`start` landing in that window reads zero clients
|
|
598
|
-
* and spawns a duplicate browser tab. */
|
|
599
443
|
lastUiClientActivityAt = 0;
|
|
600
|
-
/** Grace window covering an EventSource reconnect (its default retry is ~3s;
|
|
601
|
-
* the SSE heartbeat is 30s). Long enough to span a reconnect, short enough
|
|
602
|
-
* that a genuine page close frees the "reopen on next propose" path quickly. */
|
|
603
444
|
static UI_CLIENT_GRACE_MS = 6000;
|
|
604
|
-
/**
|
|
605
|
-
* Register a live Rivet UI client (called when the variants SSE stream opens).
|
|
606
|
-
* Returns a release fn to call on disconnect. Used as the "a Rivet page is
|
|
607
|
-
* already open" signal so the MCP server can avoid spawning a duplicate tab
|
|
608
|
-
* every time the variants flow re-enters an already-active editor session.
|
|
609
|
-
*/
|
|
610
445
|
registerUiClient() {
|
|
611
446
|
this.uiClientCount += 1;
|
|
612
447
|
this.lastUiClientActivityAt = Date.now();
|
|
@@ -620,8 +455,6 @@ class AgentVariantsOrchestrator {
|
|
|
620
455
|
this.lastUiClientActivityAt = Date.now();
|
|
621
456
|
};
|
|
622
457
|
}
|
|
623
|
-
/** True when at least one Rivet UI page is currently connected — or one
|
|
624
|
-
* disconnected within the grace window (an EventSource mid-reconnect). */
|
|
625
458
|
hasUiClients() {
|
|
626
459
|
if (this.uiClientCount > 0)
|
|
627
460
|
return true;
|
|
@@ -630,21 +463,17 @@ class AgentVariantsOrchestrator {
|
|
|
630
463
|
return (Date.now() - this.lastUiClientActivityAt <
|
|
631
464
|
AgentVariantsOrchestrator.UI_CLIENT_GRACE_MS);
|
|
632
465
|
}
|
|
633
|
-
/** @effect Records activity for the current variants session, if one exists. */
|
|
634
466
|
touchActiveSession() {
|
|
635
467
|
if (!this.activeSessionId)
|
|
636
468
|
return;
|
|
637
469
|
this.touchSession(this.activeSessionId);
|
|
638
470
|
}
|
|
639
|
-
/** @effect Resets idle cleanup for active variant preview servers. */
|
|
640
471
|
touchSession(sessionId) {
|
|
641
472
|
const resources = this.resources.get(sessionId);
|
|
642
473
|
if (!resources || resources.cleanupStarted)
|
|
643
474
|
return;
|
|
644
475
|
this.scheduleActivePreviewIdleTimer(resources);
|
|
645
476
|
}
|
|
646
|
-
/** Build the snapshot the chip cares about. Reads from SessionStore +
|
|
647
|
-
* per-resource state; safe to call at any time. */
|
|
648
477
|
buildActiveSnapshot() {
|
|
649
478
|
const sessionId = this.activeSessionId;
|
|
650
479
|
if (!sessionId || !this.store.hasSession(sessionId)) {
|
|
@@ -683,22 +512,12 @@ class AgentVariantsOrchestrator {
|
|
|
683
512
|
...(workerRuntime ? { workerRuntime } : {}),
|
|
684
513
|
};
|
|
685
514
|
}
|
|
686
|
-
/** Record which worker runtime this session's current batch leases to —
|
|
687
|
-
* called by the generation services right after the lease-owner decision
|
|
688
|
-
* so `variants start`/status can answer "what is running these?". */
|
|
689
515
|
setWorkerRuntime(sessionId, summary) {
|
|
690
516
|
if (!this.store.hasSession(sessionId))
|
|
691
517
|
return;
|
|
692
518
|
this.store.setWorkerRuntime(sessionId, summary);
|
|
693
|
-
// Push a fresh snapshot to SSE subscribers: startUnified/requestWork
|
|
694
|
-
// already emitted before this setter ran, and without an emit here a
|
|
695
|
-
// subscribed client would not see workerRuntime until the next state
|
|
696
|
-
// transition (possibly the first worker completion).
|
|
697
519
|
this.emitChange();
|
|
698
520
|
}
|
|
699
|
-
/** User reference files stored in the work item's context bundle (uploaded
|
|
700
|
-
* or copied local images). Surfaced on the snapshot so briefings can point
|
|
701
|
-
* workers at the files directly — one Read instead of a bundle walk. */
|
|
702
521
|
static contextFilesOf(context) {
|
|
703
522
|
const files = (context?.userContext ?? [])
|
|
704
523
|
.filter((source) => source.transport === 'file')
|
|
@@ -1050,8 +869,6 @@ class AgentVariantsOrchestrator {
|
|
|
1050
869
|
if (projectContext.variantContext) {
|
|
1051
870
|
(0, variantContext_1.writeVariantContextBundle)(projectContext.variantContext);
|
|
1052
871
|
}
|
|
1053
|
-
// Source-context quality is now measured off the raw context bundle plus
|
|
1054
|
-
// the action metadata the agent reported, not the legacy summary fields.
|
|
1055
872
|
const bundle = projectContext.kind === 'fresh'
|
|
1056
873
|
? projectContext.variantContext
|
|
1057
874
|
: undefined;
|
|
@@ -1113,9 +930,6 @@ class AgentVariantsOrchestrator {
|
|
|
1113
930
|
}
|
|
1114
931
|
throw error;
|
|
1115
932
|
}
|
|
1116
|
-
// Record lease times so variant_completed can report lease→report
|
|
1117
|
-
// duration. (We don't fire a separate code_gen_leased event — the
|
|
1118
|
-
// funnel signal we care about is per-variant completion duration.)
|
|
1119
933
|
const resources = this.resources.get(args.sessionId);
|
|
1120
934
|
if (resources) {
|
|
1121
935
|
const now = Date.now();
|
|
@@ -1125,10 +939,6 @@ class AgentVariantsOrchestrator {
|
|
|
1125
939
|
}
|
|
1126
940
|
this.writeLeasedWorkItemBriefings(args.sessionId, result.leasedWorkItems.map((item) => item.id));
|
|
1127
941
|
this.trackRefinementLeased({ sessionId: args.sessionId, lease: result });
|
|
1128
|
-
// Decorate each leased item's input with the worktreePath provisioned
|
|
1129
|
-
// by approve(). The skill instructs agents to write files to
|
|
1130
|
-
// `input.worktreePath` — without this decoration that field would be
|
|
1131
|
-
// missing and the agent would have no idea where to edit.
|
|
1132
942
|
const decorated = {
|
|
1133
943
|
...result,
|
|
1134
944
|
leasedWorkItems: result.leasedWorkItems.map((item) => {
|
|
@@ -1145,7 +955,6 @@ class AgentVariantsOrchestrator {
|
|
|
1145
955
|
this.emitChange();
|
|
1146
956
|
return decorated;
|
|
1147
957
|
}
|
|
1148
|
-
/** @effect Copies caller-supplied context assets into each leased workspace. */
|
|
1149
958
|
materializeContextAssets(sessionId, items) {
|
|
1150
959
|
const resources = this.ensureResources(sessionId);
|
|
1151
960
|
for (const item of items) {
|
|
@@ -1166,10 +975,6 @@ class AgentVariantsOrchestrator {
|
|
|
1166
975
|
resources.contextAssets.set(item.id, (0, contextAssets_1.materializeContextAssets)({ assets, workspace, previewKind }));
|
|
1167
976
|
}
|
|
1168
977
|
}
|
|
1169
|
-
/**
|
|
1170
|
-
* @effect Records how an existing project's worktrees will be previewed so
|
|
1171
|
-
* context assets receive references that resolve on that serving surface.
|
|
1172
|
-
*/
|
|
1173
978
|
async resolveContextAssetPreviewKind(sessionId) {
|
|
1174
979
|
const resources = this.ensureResources(sessionId);
|
|
1175
980
|
try {
|
|
@@ -1182,13 +987,6 @@ class AgentVariantsOrchestrator {
|
|
|
1182
987
|
log.warn(`Failed to resolve context asset preview kind for ${sessionId}; using dev-server references`, error);
|
|
1183
988
|
}
|
|
1184
989
|
}
|
|
1185
|
-
/**
|
|
1186
|
-
* @effect Writes each leased implementation item's server-authored briefing
|
|
1187
|
-
* BESIDE its workspace so the coordinating host dispatches workers with a
|
|
1188
|
-
* short pointer prompt instead of composing prose per worker. Best-effort:
|
|
1189
|
-
* a briefing write failure never blocks the lease (the host guidance's
|
|
1190
|
-
* packet fields still carry the same data).
|
|
1191
|
-
*/
|
|
1192
990
|
writeLeasedWorkItemBriefings(sessionId, leasedWorkItemIds) {
|
|
1193
991
|
if (leasedWorkItemIds.length === 0)
|
|
1194
992
|
return;
|
|
@@ -1218,13 +1016,9 @@ class AgentVariantsOrchestrator {
|
|
|
1218
1016
|
}
|
|
1219
1017
|
}
|
|
1220
1018
|
}
|
|
1221
|
-
/** @effect Assigns isolated, server-owned artifact workspaces to leased static work. */
|
|
1222
1019
|
ensureStaticWorkspaces(sessionId, items) {
|
|
1223
1020
|
const resources = this.ensureResources(sessionId);
|
|
1224
1021
|
const projectContext = this.store.getProjectContext(sessionId);
|
|
1225
|
-
// This lane provisions by copying the source artifact tree (vary forks) or
|
|
1226
|
-
// seeding an entry file — it bypasses provisionWorktrees, so it gets its
|
|
1227
|
-
// own provisioning telemetry here.
|
|
1228
1022
|
const provisionStartedAt = Date.now();
|
|
1229
1023
|
let assignedCount = 0;
|
|
1230
1024
|
for (const item of items) {
|
|
@@ -1271,7 +1065,6 @@ class AgentVariantsOrchestrator {
|
|
|
1271
1065
|
});
|
|
1272
1066
|
}
|
|
1273
1067
|
}
|
|
1274
|
-
/** Reads a completed static artifact while enforcing its assigned directory boundary. */
|
|
1275
1068
|
readAssignedStaticArtifact(sessionId, workItemId) {
|
|
1276
1069
|
const workspaceManager = this.resources.get(sessionId)?.workspaceManager;
|
|
1277
1070
|
if (!workspaceManager) {
|
|
@@ -1281,15 +1074,7 @@ class AgentVariantsOrchestrator {
|
|
|
1281
1074
|
}
|
|
1282
1075
|
beginStaticPreviewRefinements(args) {
|
|
1283
1076
|
const seenVariantIds = new Set();
|
|
1284
|
-
// Targets whose in-place refinement could neither be created nor folded
|
|
1285
|
-
// into a pending one (e.g. the variant was already sent). We finish the
|
|
1286
|
-
// batch's other targets, then RETURN these so the caller can surface them
|
|
1287
|
-
// in its response — rather than throwing (which would break the agent poll
|
|
1288
|
-
// and lose the already-consumed batch) or silently dropping them.
|
|
1289
1077
|
const droppedRefinements = [];
|
|
1290
|
-
// Work items THIS batch created, so the caller can tell the agent to lease
|
|
1291
|
-
// exactly these — letting concurrent runs (several watchers) each pick up
|
|
1292
|
-
// their own batch instead of one greedily leasing everything.
|
|
1293
1078
|
const createdWorkItemIds = [];
|
|
1294
1079
|
for (const target of args.targets) {
|
|
1295
1080
|
if (seenVariantIds.has(target.variantId))
|
|
@@ -1310,9 +1095,6 @@ class AgentVariantsOrchestrator {
|
|
|
1310
1095
|
});
|
|
1311
1096
|
const currentHtml = this.getStaticPreviewHtml(args.sessionId, target.variantId);
|
|
1312
1097
|
if (target.count == null) {
|
|
1313
|
-
// Plain Apply (no variantRequest) → refine the variant IN PLACE: one
|
|
1314
|
-
// edit that overwrites the source, no new sibling cards. Only an
|
|
1315
|
-
// explicit "Vary" (which carries a count) fans out new variants.
|
|
1316
1098
|
try {
|
|
1317
1099
|
const refineItem = this.store.createRefineVariantWorkItem({
|
|
1318
1100
|
sessionId: args.sessionId,
|
|
@@ -1327,8 +1109,6 @@ class AgentVariantsOrchestrator {
|
|
|
1327
1109
|
createdWorkItemIds.push(refineItem.id);
|
|
1328
1110
|
}
|
|
1329
1111
|
catch (error) {
|
|
1330
|
-
// A refinement is already queued for this variant — fold the newer
|
|
1331
|
-
// instruction in rather than dropping it (mirrors the apply queue).
|
|
1332
1112
|
if (error instanceof errors_1.AgentVariantsError &&
|
|
1333
1113
|
error.code === 'PENDING_CHANGE_CONFLICT') {
|
|
1334
1114
|
const folded = this.store.appendPendingRefineVariantInstruction({
|
|
@@ -1338,8 +1118,6 @@ class AgentVariantsOrchestrator {
|
|
|
1338
1118
|
fidelity: target.fidelity,
|
|
1339
1119
|
});
|
|
1340
1120
|
if (!folded) {
|
|
1341
|
-
// Nothing to fold into — the conflict is terminal (the variant
|
|
1342
|
-
// was already sent / is no longer editable). Don't swallow it.
|
|
1343
1121
|
droppedRefinements.push({
|
|
1344
1122
|
variantId: target.variantId,
|
|
1345
1123
|
reason: error.message,
|
|
@@ -1359,9 +1137,6 @@ class AgentVariantsOrchestrator {
|
|
|
1359
1137
|
}
|
|
1360
1138
|
continue;
|
|
1361
1139
|
}
|
|
1362
|
-
// "Vary" fans out: create `count` NEW sibling variants seeded from the
|
|
1363
|
-
// source HTML + instruction, rather than overwriting the source in place.
|
|
1364
|
-
// The agent leases them through the standard request-work path.
|
|
1365
1140
|
try {
|
|
1366
1141
|
const forks = this.store.createForkedStaticPreviewWorkItems({
|
|
1367
1142
|
sessionId: args.sessionId,
|
|
@@ -1379,11 +1154,6 @@ class AgentVariantsOrchestrator {
|
|
|
1379
1154
|
createdWorkItemIds.push(...forks.map((item) => item.id));
|
|
1380
1155
|
}
|
|
1381
1156
|
catch (error) {
|
|
1382
|
-
// Terminal conflict — the source is no longer editable, or a variant
|
|
1383
|
-
// was already sent for this session (the fork path has nothing to fold
|
|
1384
|
-
// into). Surface it structurally like the in-place branch instead of
|
|
1385
|
-
// throwing, which would break the agent poll AND lose this batch (the
|
|
1386
|
-
// server already consumed it from the FIFO before calling us).
|
|
1387
1157
|
if (error instanceof errors_1.AgentVariantsError &&
|
|
1388
1158
|
(error.code === 'PENDING_CHANGE_CONFLICT' ||
|
|
1389
1159
|
error.code === 'VARIANT_NOT_EDITABLE')) {
|
|
@@ -1410,24 +1180,6 @@ class AgentVariantsOrchestrator {
|
|
|
1410
1180
|
this.emitChange();
|
|
1411
1181
|
return { droppedRefinements, createdWorkItemIds };
|
|
1412
1182
|
}
|
|
1413
|
-
/**
|
|
1414
|
-
* Adopt a PAST variant (from a prior session's persisted history) into the
|
|
1415
|
-
* active session, rehydrating it from its on-disk static snapshot so the
|
|
1416
|
-
* comment / refine / Vary machinery treats it as a live, first-class variant.
|
|
1417
|
-
*
|
|
1418
|
-
* Triggered when the user makes their first edit on a selected past direction.
|
|
1419
|
-
* The store appends an already-`succeeded` `static_preview` work item keyed by
|
|
1420
|
-
* the past identity (idempotent); this method registers the matching static-
|
|
1421
|
-
* preview record so {@link getStaticPreviewHtml}, {@link getVariants}
|
|
1422
|
-
* (preview.kind = 'static_artifact', view enabled), and the
|
|
1423
|
-
* `/api/variants/:sid/static/:vid` routes all light up exactly as they do for a
|
|
1424
|
-
* freshly-generated static_preview variant.
|
|
1425
|
-
*
|
|
1426
|
-
* `filesDir` is the absolute path to the persisted `files/` snapshot and
|
|
1427
|
-
* `entryPath` is its selected HTML document. Returns the stable active-session
|
|
1428
|
-
* `workItemId` so the caller can route the triggering edit to it, plus whether
|
|
1429
|
-
* it was already adopted.
|
|
1430
|
-
*/
|
|
1431
1183
|
async adoptPastVariant(args) {
|
|
1432
1184
|
const { assetBase, hasAssets } = await this.resolveAdoptedStaticPreviewFiles(args.filesDir, args.entryPath);
|
|
1433
1185
|
const append = this.store.appendAdoptedStaticVariant({
|
|
@@ -1445,8 +1197,6 @@ class AgentVariantsOrchestrator {
|
|
|
1445
1197
|
requestedCount: 1,
|
|
1446
1198
|
sourceVariantId: args.source.variantId,
|
|
1447
1199
|
});
|
|
1448
|
-
// Register (or re-register, harmlessly) the static-preview record so the
|
|
1449
|
-
// snapshot surfaces the adopted variant as a static_artifact.
|
|
1450
1200
|
const resources = this.ensureResources(args.sessionId);
|
|
1451
1201
|
resources.staticPreviews.set(append.workItemId, {
|
|
1452
1202
|
workItemId: append.workItemId,
|
|
@@ -1471,11 +1221,6 @@ class AgentVariantsOrchestrator {
|
|
|
1471
1221
|
alreadyAdopted: !append.created,
|
|
1472
1222
|
};
|
|
1473
1223
|
}
|
|
1474
|
-
/**
|
|
1475
|
-
* Rehydrate a static history variant into the current active session when it
|
|
1476
|
-
* can still accept edits; otherwise create a replacement active session whose
|
|
1477
|
-
* only visible direction is the selected history artifact.
|
|
1478
|
-
*/
|
|
1479
1224
|
async bootstrapPastVariantSession(args) {
|
|
1480
1225
|
const usableSessionId = this.getUsableActiveSessionId();
|
|
1481
1226
|
if (usableSessionId) {
|
|
@@ -1556,12 +1301,6 @@ class AgentVariantsOrchestrator {
|
|
|
1556
1301
|
}
|
|
1557
1302
|
return { assetBase, hasAssets };
|
|
1558
1303
|
}
|
|
1559
|
-
/**
|
|
1560
|
-
* True when the variant is an HTML-only static_preview work item. Adopted past
|
|
1561
|
-
* variants and fresh `static_preview` variants both qualify. Existing-project
|
|
1562
|
-
* `code_gen` variants can still expose a static artifact for preview, but Vary
|
|
1563
|
-
* must keep those on the worktree-backed code_gen append path.
|
|
1564
|
-
*/
|
|
1565
1304
|
isStaticPreviewVariant(sessionId, workItemId) {
|
|
1566
1305
|
try {
|
|
1567
1306
|
return (this.store.getWorkItemKind(sessionId, workItemId) === 'static_preview');
|
|
@@ -1570,11 +1309,6 @@ class AgentVariantsOrchestrator {
|
|
|
1570
1309
|
return false;
|
|
1571
1310
|
}
|
|
1572
1311
|
}
|
|
1573
|
-
/**
|
|
1574
|
-
* Resolve the history source for a forked Vary row. If the immediate parent
|
|
1575
|
-
* is an adopted past direction, collapse against that original history row;
|
|
1576
|
-
* otherwise collapse against the same-session parent variant.
|
|
1577
|
-
*/
|
|
1578
1312
|
resolveHistoryParentVariant(sessionId, sourceVariantId) {
|
|
1579
1313
|
if (!sourceVariantId)
|
|
1580
1314
|
return undefined;
|
|
@@ -1641,10 +1375,6 @@ class AgentVariantsOrchestrator {
|
|
|
1641
1375
|
workItemCount: 1,
|
|
1642
1376
|
instructionLength: args.instruction.length,
|
|
1643
1377
|
});
|
|
1644
|
-
// Lease the just-created refine item by id. A generic
|
|
1645
|
-
// requestWork({ requestedLeaseCount: 1 }) takes the first leasable item in
|
|
1646
|
-
// work-item order, which could be an unrelated still-pending static_preview
|
|
1647
|
-
// rather than this refinement.
|
|
1648
1378
|
return this.requestWork({
|
|
1649
1379
|
sessionId: args.sessionId,
|
|
1650
1380
|
leaseOwner: args.leaseOwner,
|
|
@@ -1657,7 +1387,6 @@ class AgentVariantsOrchestrator {
|
|
|
1657
1387
|
getWorkItemInput(sessionId, workItemId) {
|
|
1658
1388
|
return this.store.getWorkItemInput(sessionId, workItemId);
|
|
1659
1389
|
}
|
|
1660
|
-
/** Returns status after orchestration QA and refinement post-processing. */
|
|
1661
1390
|
getWorkItemStatus(sessionId, workItemId) {
|
|
1662
1391
|
return this.store.getWorkItemStatus(sessionId, workItemId);
|
|
1663
1392
|
}
|
|
@@ -1674,16 +1403,10 @@ class AgentVariantsOrchestrator {
|
|
|
1674
1403
|
const resources = this.resources.get(sessionId);
|
|
1675
1404
|
return this.store.getVariants(sessionId).map((variant) => {
|
|
1676
1405
|
const port = this.getDevServerPort(sessionId, variant.workItemId);
|
|
1677
|
-
// Captured worktree diff (existing-project code_gen). Surfaced as a
|
|
1678
|
-
// changed-files count so a diff-only variant (no dev server / static
|
|
1679
|
-
// artifact) still reads as a real result in the panel.
|
|
1680
1406
|
const capturedDiff = resources?.worktrees.get(variant.workItemId)?.diff;
|
|
1681
1407
|
const changedFilesCount = typeof capturedDiff === 'string' && capturedDiff.length > 0
|
|
1682
1408
|
? countDiffFiles(capturedDiff)
|
|
1683
1409
|
: undefined;
|
|
1684
|
-
// For fresh sessions, static_preview items ARE the variants — look up
|
|
1685
|
-
// directly by workItemId. Fall back to briefId search for existing-project
|
|
1686
|
-
// sessions where code_gen items were paired with companion static_preview items.
|
|
1687
1410
|
const staticPreview = resources?.staticPreviews.get(variant.workItemId) ??
|
|
1688
1411
|
this.getStaticPreviewByBriefId(sessionId, variant.briefId);
|
|
1689
1412
|
let preview;
|
|
@@ -1694,11 +1417,6 @@ class AgentVariantsOrchestrator {
|
|
|
1694
1417
|
};
|
|
1695
1418
|
}
|
|
1696
1419
|
else if (!port) {
|
|
1697
|
-
// handleSucceededReport is fire-and-forget so staticPreviews may not be
|
|
1698
|
-
// populated yet when getVariants is called (e.g. in the terminal response).
|
|
1699
|
-
// item.output is set synchronously by store.reportComplete, so it's always
|
|
1700
|
-
// available. Read it directly as a fallback so previewUrls in terminal
|
|
1701
|
-
// responses include the variant that just triggered terminal state.
|
|
1702
1420
|
try {
|
|
1703
1421
|
const output = this.store.getWorkItemOutput(sessionId, variant.workItemId);
|
|
1704
1422
|
if (typeof output?.html === 'string' && output.html.length > 0) {
|
|
@@ -1709,7 +1427,6 @@ class AgentVariantsOrchestrator {
|
|
|
1709
1427
|
}
|
|
1710
1428
|
}
|
|
1711
1429
|
catch {
|
|
1712
|
-
/* work item may not exist in edge cases */
|
|
1713
1430
|
}
|
|
1714
1431
|
}
|
|
1715
1432
|
if (!preview && port) {
|
|
@@ -1719,9 +1436,6 @@ class AgentVariantsOrchestrator {
|
|
|
1719
1436
|
const isSucceeded = variant.status === 'succeeded';
|
|
1720
1437
|
const qaFailed = qa?.status === 'failed';
|
|
1721
1438
|
const canView = Boolean(preview) || (isSucceeded && Boolean(port));
|
|
1722
|
-
// A succeeded variant with no live preview whose dev server we tried and
|
|
1723
|
-
// failed to start: surface the cause so the UI can show an accurate
|
|
1724
|
-
// per-direction message instead of the generic disconnected overlay.
|
|
1725
1439
|
const previewFailure = resources?.previewFailures.get(variant.workItemId);
|
|
1726
1440
|
const previewUnavailable = !canView && isSucceeded && previewFailure
|
|
1727
1441
|
? {
|
|
@@ -1765,36 +1479,19 @@ class AgentVariantsOrchestrator {
|
|
|
1765
1479
|
hasSession(sessionId) {
|
|
1766
1480
|
return this.store.hasSession(sessionId);
|
|
1767
1481
|
}
|
|
1768
|
-
/** Read the projectContext for a session — used by Express routes that
|
|
1769
|
-
* build the chip snapshot via `stateForSession`. */
|
|
1770
1482
|
getProjectContext(sessionId) {
|
|
1771
1483
|
return this.store.getProjectContext(sessionId);
|
|
1772
1484
|
}
|
|
1773
|
-
/** Resolve a worktree path for a code-gen work item, if provisioned. */
|
|
1774
1485
|
getWorktreePath(sessionId, workItemId) {
|
|
1775
1486
|
return this.resources.get(sessionId)?.worktrees.get(workItemId)
|
|
1776
1487
|
?.worktreePath;
|
|
1777
1488
|
}
|
|
1778
|
-
/**
|
|
1779
|
-
* Resolve the project cwd inside a worktree so subdirectory projects run
|
|
1780
|
-
* from the same repo-relative location.
|
|
1781
|
-
*/
|
|
1782
1489
|
getProjectCwdInWorktree(worktreePath) {
|
|
1783
1490
|
return this.worktrees.getProjectCwdInWorktree(worktreePath);
|
|
1784
1491
|
}
|
|
1785
|
-
/** Resolve the dev server port for a code-gen work item, if running. */
|
|
1786
1492
|
getDevServerPort(sessionId, workItemId) {
|
|
1787
1493
|
return this.resources.get(sessionId)?.worktrees.get(workItemId)?.port;
|
|
1788
1494
|
}
|
|
1789
|
-
/**
|
|
1790
|
-
* Restores a Rivet-owned preview after idle reclamation or an explicit retry
|
|
1791
|
-
* of a failed start. Reuses the saved worktree without leasing generation work.
|
|
1792
|
-
*
|
|
1793
|
-
* @effect Clears the idle marker and prior crash budget, starts the worktree
|
|
1794
|
-
* dev server, and emits preview-state snapshots.
|
|
1795
|
-
* @deps Uses the live session resources, project context, and dev-server
|
|
1796
|
-
* manager owned by this orchestrator.
|
|
1797
|
-
*/
|
|
1798
1495
|
async restoreVariantPreview(sessionId, workItemId, options = {}) {
|
|
1799
1496
|
const resources = this.resources.get(sessionId);
|
|
1800
1497
|
const record = resources?.worktrees.get(workItemId);
|
|
@@ -1836,10 +1533,6 @@ class AgentVariantsOrchestrator {
|
|
|
1836
1533
|
record.previewRestoration = undefined;
|
|
1837
1534
|
}
|
|
1838
1535
|
}
|
|
1839
|
-
/**
|
|
1840
|
-
* @effect Resolves the dev server port for a preview request and refreshes
|
|
1841
|
-
* active-preview retention for that session while the port is still live.
|
|
1842
|
-
*/
|
|
1843
1536
|
resolveDevServerPortForPreview(sessionId, workItemId) {
|
|
1844
1537
|
const port = this.getDevServerPort(sessionId, workItemId);
|
|
1845
1538
|
if (typeof port === 'number') {
|
|
@@ -1847,14 +1540,6 @@ class AgentVariantsOrchestrator {
|
|
|
1847
1540
|
}
|
|
1848
1541
|
return port;
|
|
1849
1542
|
}
|
|
1850
|
-
/**
|
|
1851
|
-
* True work-item kind for a variant, or undefined when the session/item is
|
|
1852
|
-
* unknown. This is the authoritative routing signal for Vary/refine intakes:
|
|
1853
|
-
* an existing-project `code_gen` variant materialized as a static preview
|
|
1854
|
-
* (registerExistingStaticPreview) DISPLAYS as `static_artifact` and serves
|
|
1855
|
-
* HTML, but must fork via the code_gen/worktree path — HTML presence is not
|
|
1856
|
-
* a valid discriminator.
|
|
1857
|
-
*/
|
|
1858
1543
|
getVariantWorkItemKind(sessionId, workItemId) {
|
|
1859
1544
|
try {
|
|
1860
1545
|
return this.store.getWorkItemKind(sessionId, workItemId);
|
|
@@ -1864,9 +1549,6 @@ class AgentVariantsOrchestrator {
|
|
|
1864
1549
|
}
|
|
1865
1550
|
}
|
|
1866
1551
|
getStaticPreviewHtml(sessionId, workItemId) {
|
|
1867
|
-
// Primary: read the materialized entry from the variant's per-variant
|
|
1868
|
-
// directory (written by handleSucceededReport). The directory is the source
|
|
1869
|
-
// of truth for the static deliverable.
|
|
1870
1552
|
const preview = this.resources
|
|
1871
1553
|
.get(sessionId)
|
|
1872
1554
|
?.staticPreviews.get(workItemId);
|
|
@@ -1877,12 +1559,8 @@ class AgentVariantsOrchestrator {
|
|
|
1877
1559
|
return fromDisk;
|
|
1878
1560
|
}
|
|
1879
1561
|
catch {
|
|
1880
|
-
// fall through to the work-item output fallback below
|
|
1881
1562
|
}
|
|
1882
1563
|
}
|
|
1883
|
-
// Fallback: read directly from the work item's stored output — available
|
|
1884
|
-
// as soon as reportComplete runs, before handleSucceededReport fires (so
|
|
1885
|
-
// the per-variant directory may not exist yet).
|
|
1886
1564
|
try {
|
|
1887
1565
|
const output = this.store.getWorkItemOutput(sessionId, workItemId);
|
|
1888
1566
|
return typeof output?.html === 'string' && output.html.length > 0
|
|
@@ -1893,38 +1571,20 @@ class AgentVariantsOrchestrator {
|
|
|
1893
1571
|
return undefined;
|
|
1894
1572
|
}
|
|
1895
1573
|
}
|
|
1896
|
-
/** Resolve the DESIGN.md markdown behind an artifact link. */
|
|
1897
1574
|
getDesignContextMarkdown(sessionId, artifactId) {
|
|
1898
1575
|
const artifact = findDesignContextArtifact(this.store.getProjectContext(sessionId), artifactId);
|
|
1899
1576
|
return artifact?.content;
|
|
1900
1577
|
}
|
|
1901
|
-
/** Build the rendered DesignMD document for an artifact link. */
|
|
1902
1578
|
getDesignContextViewerHtml(sessionId, artifactId) {
|
|
1903
1579
|
const artifact = findDesignContextArtifact(this.store.getProjectContext(sessionId), artifactId);
|
|
1904
1580
|
return artifact ? buildDesignContextViewerDocument(artifact) : undefined;
|
|
1905
1581
|
}
|
|
1906
|
-
/**
|
|
1907
|
-
* `true` when the variant has a non-empty `assetBase` — i.e. its inlined
|
|
1908
|
-
* HTML references sibling files served by the asset route. The route
|
|
1909
|
-
* uses this to decide whether to inject a `<base href>` (only needed
|
|
1910
|
-
* when relative URLs in the HTML must resolve against the asset
|
|
1911
|
-
* sub-path). Self-contained HTML keeps its natural URL resolution.
|
|
1912
|
-
*/
|
|
1913
1582
|
hasStaticPreviewAssets(sessionId, workItemId) {
|
|
1914
1583
|
const record = this.resources
|
|
1915
1584
|
.get(sessionId)
|
|
1916
1585
|
?.staticPreviews.get(workItemId);
|
|
1917
1586
|
return Boolean(record?.hasAssets);
|
|
1918
1587
|
}
|
|
1919
|
-
/**
|
|
1920
|
-
* Resolve an absolute, sandboxed path for a sibling asset that the
|
|
1921
|
-
* variant's inlined HTML references (e.g. `./avatar.glb`, `./hero.png`).
|
|
1922
|
-
* Returns `undefined` when the variant has no `assetBase`, the requested
|
|
1923
|
-
* path escapes the base (path traversal), or the file does not exist.
|
|
1924
|
-
*
|
|
1925
|
-
* Used by the `/api/variants/:sessionId/static/:variantId/<asset>` route
|
|
1926
|
-
* to serve assets from the agent's on-disk variant workspace pre-commit.
|
|
1927
|
-
*/
|
|
1928
1588
|
resolveStaticPreviewAssetPath(sessionId, workItemId, requestedPath) {
|
|
1929
1589
|
const record = this.resources
|
|
1930
1590
|
.get(sessionId)
|
|
@@ -1933,12 +1593,6 @@ class AgentVariantsOrchestrator {
|
|
|
1933
1593
|
return undefined;
|
|
1934
1594
|
if (!requestedPath || requestedPath.length === 0)
|
|
1935
1595
|
return undefined;
|
|
1936
|
-
// Resolve against the variant's own directory first so any asset the agent
|
|
1937
|
-
// actually wrote/modified wins. Only when the worktree clone lacks the file
|
|
1938
|
-
// do we fall back to the host project root — that recovers git-ignored or
|
|
1939
|
-
// binary assets the worktree provisioning couldn't carry over, which the
|
|
1940
|
-
// original preview already serves (see `assetFallbackBase`). Both roots are
|
|
1941
|
-
// held to the identical traversal/realpath/hardlink sandbox.
|
|
1942
1596
|
return (resolveAssetWithinBase(record.assetBase, requestedPath) ??
|
|
1943
1597
|
(record.assetFallbackBase
|
|
1944
1598
|
? resolveAssetWithinBase(record.assetFallbackBase, requestedPath)
|
|
@@ -1955,7 +1609,6 @@ class AgentVariantsOrchestrator {
|
|
|
1955
1609
|
const safeWorkItemId = encodeURIComponent(workItemId);
|
|
1956
1610
|
return `/api/variants/${safeSessionId}/static/${safeWorkItemId}`;
|
|
1957
1611
|
}
|
|
1958
|
-
// --- Mutation wrappers (state + side effects) ---------------------------
|
|
1959
1612
|
async approve(args) {
|
|
1960
1613
|
const result = this.store.approve(args);
|
|
1961
1614
|
const resources = this.ensureResources(args.sessionId);
|
|
@@ -1976,11 +1629,6 @@ class AgentVariantsOrchestrator {
|
|
|
1976
1629
|
workItemIds,
|
|
1977
1630
|
});
|
|
1978
1631
|
this.emitChange();
|
|
1979
|
-
// Await provisioning before returning so request_work always sees a
|
|
1980
|
-
// populated worktreePath on each leased item. Provisioning creates a
|
|
1981
|
-
// git worktree and copies dependencies for each variant, and the
|
|
1982
|
-
// agent has nothing useful to do between approve and request_work
|
|
1983
|
-
// anyway — running them serially is the contract the skill assumes.
|
|
1984
1632
|
try {
|
|
1985
1633
|
if (projectContext.kind === 'existing') {
|
|
1986
1634
|
await this.resolveContextAssetPreviewKind(args.sessionId);
|
|
@@ -1994,50 +1642,18 @@ class AgentVariantsOrchestrator {
|
|
|
1994
1642
|
}
|
|
1995
1643
|
return result;
|
|
1996
1644
|
}
|
|
1997
|
-
/**
|
|
1998
|
-
* Unified one-call kickoff that collapses propose → report_briefs →
|
|
1999
|
-
* approve. Uses AI-authored briefs supplied by agent callers, with a
|
|
2000
|
-
* deterministic prompt-derived fallback for human-direct calls, and
|
|
2001
|
-
* immediately approves so the session lands in `work_items_ready`.
|
|
2002
|
-
*
|
|
2003
|
-
* Supports both existing-project sessions (spawns code_gen work items
|
|
2004
|
-
* for the agent to lease) and zero-to-one sessions (spawns
|
|
2005
|
-
* static_preview work items; the server runs scaffold_base in the
|
|
2006
|
-
* background). This is the single-call path; source-grounded zero-to-one
|
|
2007
|
-
* sessions (source URLs / inspiration extraction) run through `propose`
|
|
2008
|
-
* instead so the source-research flow can gate generation — start_variants
|
|
2009
|
-
* routes them there. This method does not run source research.
|
|
2010
|
-
*
|
|
2011
|
-
* Host-agnostic: no LLM calls happen here. The agent (Claude Code,
|
|
2012
|
-
* Cursor, Codex) generates the label and code when it leases the
|
|
2013
|
-
* work items via continue_variants(action="request_work").
|
|
2014
|
-
*/
|
|
2015
1645
|
async startUnified(args) {
|
|
2016
1646
|
const count = args.briefs?.length ?? args.count ?? contracts_1.DEFAULT_VARIANT_COUNT;
|
|
2017
1647
|
const projectContext = args.projectContext ?? {
|
|
2018
1648
|
kind: 'existing',
|
|
2019
1649
|
};
|
|
2020
1650
|
const designContextCount = projectContext.designContext?.length ?? 0;
|
|
2021
|
-
// Fresh source-grounded sessions (a captured context bundle on a fresh
|
|
2022
|
-
// project) must run through `propose` so the source-research/source_plan
|
|
2023
|
-
// flow gates generation; start_variants routes them there before reaching
|
|
2024
|
-
// here, so this guard is an internal invariant. Existing-project sessions
|
|
2025
|
-
// keep the single-call path even with a bundle — they have no source_plan
|
|
2026
|
-
// stage, and the bundle's raw context is threaded straight into code_gen.
|
|
2027
|
-
// Brief-driven fresh starts are exempt for the same reason: the caller
|
|
2028
|
-
// already did its source research when it authored the briefs, so the
|
|
2029
|
-
// bundle is raw worker context (reference images), not research input.
|
|
2030
1651
|
const isSourceGrounded = projectContext.kind === 'fresh' &&
|
|
2031
1652
|
Boolean(projectContext.variantContext) &&
|
|
2032
1653
|
!args.briefs?.length;
|
|
2033
1654
|
if (isSourceGrounded) {
|
|
2034
1655
|
throw new errors_1.AgentVariantsError('INVALID_STAGE_ACTION', 'Source-grounded sessions must run through the source-research flow (propose), not the single-call startUnified path.');
|
|
2035
1656
|
}
|
|
2036
|
-
// A second "Vary" on an existing project that still has a live session
|
|
2037
|
-
// ACCUMULATES into that session instead of starting a fresh one that
|
|
2038
|
-
// would orphan the prior variants (and overwrite `activeSessionId`, so
|
|
2039
|
-
// the RHS would only ever show the latest batch). Gated to existing
|
|
2040
|
-
// projects so fresh 0→1 generation is unaffected.
|
|
2041
1657
|
const appendSessionId = args.allowAccumulate &&
|
|
2042
1658
|
projectContext.kind === 'existing' &&
|
|
2043
1659
|
projectContext.projectPath
|
|
@@ -2075,8 +1691,6 @@ class AgentVariantsOrchestrator {
|
|
|
2075
1691
|
};
|
|
2076
1692
|
const { createdWorkItemIds } = this.store.appendCodeGenVariants({
|
|
2077
1693
|
...forkArgs,
|
|
2078
|
-
// Fork parent (Vary on a variant): seeds each new worktree from the
|
|
2079
|
-
// parent's tree instead of the base tree. Absent for a plain append.
|
|
2080
1694
|
...(args.sourceVariantId
|
|
2081
1695
|
? { sourceVariantId: args.sourceVariantId }
|
|
2082
1696
|
: {}),
|
|
@@ -2115,8 +1729,6 @@ class AgentVariantsOrchestrator {
|
|
|
2115
1729
|
projectContext,
|
|
2116
1730
|
runLabel: args.runLabel,
|
|
2117
1731
|
...(args.fidelity ? { fidelity: args.fidelity } : {}),
|
|
2118
|
-
// Briefs land via reportBriefs immediately below — never enter the
|
|
2119
|
-
// source-plan stage, even for a fresh session carrying a bundle.
|
|
2120
1732
|
hasPreparedBriefs: true,
|
|
2121
1733
|
...(args.sessionId ? { sessionId: args.sessionId } : {}),
|
|
2122
1734
|
});
|
|
@@ -2147,18 +1759,11 @@ class AgentVariantsOrchestrator {
|
|
|
2147
1759
|
});
|
|
2148
1760
|
sessionId = proposeResult.sessionId;
|
|
2149
1761
|
scaffoldBaseWorkItemId = approveResult.scaffoldBaseWorkItemId ?? null;
|
|
2150
|
-
// For existing-project sessions, approve() returns the new code_gen
|
|
2151
|
-
// ids in codeGenWorkItemIds. For zero-to-one, approve() spawns
|
|
2152
|
-
// static_preview items instead — those ids aren't in codeGenWorkItemIds,
|
|
2153
|
-
// so read them out of the active-variants snapshot which covers both
|
|
2154
|
-
// kinds. Snapshot order mirrors brief order (insertion order).
|
|
2155
1762
|
variantIds =
|
|
2156
1763
|
projectContext.kind === 'fresh'
|
|
2157
1764
|
? this.store.getVariants(sessionId).map((v) => v.workItemId)
|
|
2158
1765
|
: approveResult.codeGenWorkItemIds;
|
|
2159
1766
|
}
|
|
2160
|
-
// Stamp the UI correlation id so the panel maps its optimistic placeholders
|
|
2161
|
-
// to these real cards (the same mechanism the static-preview fork uses).
|
|
2162
1767
|
if (args.requestId) {
|
|
2163
1768
|
this.store.assignVariantRequestId(sessionId, variantIds, args.requestId);
|
|
2164
1769
|
}
|
|
@@ -2192,8 +1797,6 @@ class AgentVariantsOrchestrator {
|
|
|
2192
1797
|
const lease = this.requestWork({
|
|
2193
1798
|
sessionId,
|
|
2194
1799
|
leaseOwner: args.leaseOwner,
|
|
2195
|
-
// Append: lease ONLY the new batch so a still-leasable prior item
|
|
2196
|
-
// (e.g. a re-leased one) isn't swept into this Vary's lease.
|
|
2197
1800
|
...(appendSessionId ? { workItemIds: variantIds } : {}),
|
|
2198
1801
|
});
|
|
2199
1802
|
leaseId = lease.leaseId;
|
|
@@ -2209,15 +1812,6 @@ class AgentVariantsOrchestrator {
|
|
|
2209
1812
|
leasedWorkItems,
|
|
2210
1813
|
};
|
|
2211
1814
|
}
|
|
2212
|
-
/**
|
|
2213
|
-
* Build the per-variant briefs for a unified start. Supplied briefs keep
|
|
2214
|
-
* meaningful direction labels, while duplicate or empty labels are made
|
|
2215
|
-
* unique against the visible session rows. The fallback derives a short
|
|
2216
|
-
* run-intent label from the prompt (e.g. "make it brighter" →
|
|
2217
|
-
* "Brighter 1/2/…") rather than an indistinct "Variant N". `uniqueBriefIds`
|
|
2218
|
-
* is set for the append path so the new batch's briefIds can't collide with
|
|
2219
|
-
* the live session's existing ones.
|
|
2220
|
-
*/
|
|
2221
1815
|
buildUnifiedBriefs(args) {
|
|
2222
1816
|
const briefId = (i) => args.uniqueBriefIds ? `v-${(0, crypto_1.randomUUID)().slice(0, 8)}` : `v${i + 1}`;
|
|
2223
1817
|
const runLabel = args.runLabel?.trim() || (0, runLabel_1.deriveRunLabel)(args.prompt);
|
|
@@ -2247,13 +1841,6 @@ class AgentVariantsOrchestrator {
|
|
|
2247
1841
|
body: synthesizeUnifiedBriefBody(args.prompt, i + 1, args.count),
|
|
2248
1842
|
}, i));
|
|
2249
1843
|
}
|
|
2250
|
-
/**
|
|
2251
|
-
* The active sessionId IF it is an existing-project session for `projectPath`
|
|
2252
|
-
* that can still accept appended variants — i.e. not committed, not
|
|
2253
|
-
* cancelled/failed. Returns null otherwise, so start_variants falls back to
|
|
2254
|
-
* creating a fresh session (first Vary, a different project, or after the
|
|
2255
|
-
* prior session was committed/cancelled).
|
|
2256
|
-
*/
|
|
2257
1844
|
getAppendableExistingSessionId(projectPath) {
|
|
2258
1845
|
const sessionId = this.activeSessionId;
|
|
2259
1846
|
if (!sessionId || !this.store.hasSession(sessionId))
|
|
@@ -2268,7 +1855,6 @@ class AgentVariantsOrchestrator {
|
|
|
2268
1855
|
return null;
|
|
2269
1856
|
return sessionId;
|
|
2270
1857
|
}
|
|
2271
|
-
/** @effect Registers a provisioned git worktree with runtime and workspace state. */
|
|
2272
1858
|
async registerWorktreeWorkspace(resources, record) {
|
|
2273
1859
|
let projectPath = record.worktreePath;
|
|
2274
1860
|
try {
|
|
@@ -2284,15 +1870,6 @@ class AgentVariantsOrchestrator {
|
|
|
2284
1870
|
projectPath,
|
|
2285
1871
|
});
|
|
2286
1872
|
}
|
|
2287
|
-
/**
|
|
2288
|
-
* Provision a worktree for each appended existing-project variant. Mirrors
|
|
2289
|
-
* {@link provisionExistingWorktrees} but only for the newly appended ids, and
|
|
2290
|
-
* passes a per-batch `instanceKeyPrefix` so the new worktree dirs do not
|
|
2291
|
-
* collide with the first batch's `${sessionId}-${i}` paths.
|
|
2292
|
-
*/
|
|
2293
|
-
/** Emits provisioning started/completed/failed telemetry around `run` for
|
|
2294
|
-
* the vary-fork/append lanes that bypass provisionWorktrees (and its
|
|
2295
|
-
* telemetry). Rethrows failures untouched. */
|
|
2296
1873
|
async withProvisioningTelemetry(args, run) {
|
|
2297
1874
|
const startedAt = Date.now();
|
|
2298
1875
|
this.telemetry.track('agent_variants.provisioning_started', {
|
|
@@ -2347,11 +1924,6 @@ class AgentVariantsOrchestrator {
|
|
|
2347
1924
|
})));
|
|
2348
1925
|
});
|
|
2349
1926
|
}
|
|
2350
|
-
/**
|
|
2351
|
-
* Provision worktrees for a code_gen Vary forked from a parent variant.
|
|
2352
|
-
* Copies the parent's worktree tree so each sibling starts from the parent's
|
|
2353
|
-
* diff rather than git HEAD / Original.
|
|
2354
|
-
*/
|
|
2355
1927
|
async provisionForkedFromVariantWorktrees(sessionId, sourceVariantId, workItemIds) {
|
|
2356
1928
|
if (workItemIds.length === 0)
|
|
2357
1929
|
return;
|
|
@@ -2359,13 +1931,14 @@ class AgentVariantsOrchestrator {
|
|
|
2359
1931
|
if (!sourcePath) {
|
|
2360
1932
|
throw new errors_1.AgentVariantsError('VARIANT_NOT_EDITABLE', `Cannot fork from variant ${sourceVariantId}: no worktree path`);
|
|
2361
1933
|
}
|
|
2362
|
-
|
|
1934
|
+
const forkWorktreesFrom = this.worktrees.forkWorktreesFrom?.bind(this.worktrees);
|
|
1935
|
+
if (!forkWorktreesFrom) {
|
|
2363
1936
|
throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', 'worktreeManager does not implement forkWorktreesFrom');
|
|
2364
1937
|
}
|
|
2365
1938
|
await this.withProvisioningTelemetry({ sessionId, kind: 'forked_variant', variantCount: workItemIds.length }, async () => {
|
|
2366
1939
|
const resources = this.ensureResources(sessionId);
|
|
2367
1940
|
const instanceKeyPrefix = `f${(0, crypto_1.randomUUID)().slice(0, 8)}-`;
|
|
2368
|
-
const paths = await withProvisionTimeout(
|
|
1941
|
+
const paths = await withProvisionTimeout(forkWorktreesFrom(sourcePath, sessionId, workItemIds.length, instanceKeyPrefix), this.provisionTimeoutMs);
|
|
2369
1942
|
await Promise.all(workItemIds.map((id, index) => this.registerWorktreeWorkspace(resources, {
|
|
2370
1943
|
workItemId: id,
|
|
2371
1944
|
worktreePath: paths[index],
|
|
@@ -2373,15 +1946,7 @@ class AgentVariantsOrchestrator {
|
|
|
2373
1946
|
});
|
|
2374
1947
|
}
|
|
2375
1948
|
async reportComplete(args) {
|
|
2376
|
-
// Phase-timing anchor: lease→report (agent work) vs report→recorded
|
|
2377
|
-
// (QA gate + post-processing) are attributed separately on
|
|
2378
|
-
// `variant_completed` so latency work can tell them apart.
|
|
2379
1949
|
const reportReceivedAt = Date.now();
|
|
2380
|
-
// Cooperative abort short-circuit: if the work item was removed/cancelled
|
|
2381
|
-
// while in flight (delete-while-loading, cancel_variant, session cancel),
|
|
2382
|
-
// skip the schema and QA gates entirely — there is no point validating or
|
|
2383
|
-
// QA-ing output we are about to discard — and hand back the store's
|
|
2384
|
-
// `aborted` signal so the agent stops this work item now.
|
|
2385
1950
|
if (this.store.hasSession(args.sessionId) &&
|
|
2386
1951
|
this.store.isWorkItemAborted(args.sessionId, args.workItemId)) {
|
|
2387
1952
|
return this.store.reportComplete(args);
|
|
@@ -2405,9 +1970,6 @@ class AgentVariantsOrchestrator {
|
|
|
2405
1970
|
output: this.readAssignedStaticArtifact(args.sessionId, args.workItemId),
|
|
2406
1971
|
}
|
|
2407
1972
|
: args;
|
|
2408
|
-
// Contract validation keeps internal callers that provide an explicit
|
|
2409
|
-
// static output honest. Host workers complete assigned artifacts without
|
|
2410
|
-
// transporting the HTML through this report.
|
|
2411
1973
|
if (resolvedArgs.status === 'succeeded' &&
|
|
2412
1974
|
this.store.hasSession(args.sessionId) &&
|
|
2413
1975
|
(workItemKind === 'static_preview' ||
|
|
@@ -2425,27 +1987,15 @@ class AgentVariantsOrchestrator {
|
|
|
2425
1987
|
}
|
|
2426
1988
|
throw new errors_1.AgentVariantsError('SCHEMA_VALIDATION_FAILED', `${workItemKind} output.html must be a string and non-empty when explicit output is provided. Host workers should write the assigned index.html instead.`);
|
|
2427
1989
|
}
|
|
2428
|
-
// Check Rivet-owned output integrity synchronously before recording
|
|
2429
|
-
// success. A terminal failure uses `VARIANT_QA_FAILED` so the variant never
|
|
2430
|
-
// reaches `ready` and `getVariants` can disable its commit action.
|
|
2431
1990
|
const qaStartedAt = Date.now();
|
|
2432
1991
|
const qaEval = workItemKind === 'refine_variant'
|
|
2433
1992
|
? null
|
|
2434
1993
|
: await this.evaluateQaForReport(resolvedArgs);
|
|
2435
1994
|
const qaMs = qaEval === null ? null : Date.now() - qaStartedAt;
|
|
2436
|
-
// A `retry` verdict re-leases the variant for one structural repair instead
|
|
2437
|
-
// of recording success, so short-circuit the normal record path.
|
|
2438
1995
|
if (qaEval?.decision === 'retry') {
|
|
2439
1996
|
return this.handleQaRegenRetry(resolvedArgs, qaEval.qa);
|
|
2440
1997
|
}
|
|
2441
1998
|
let effectiveArgs = qaEval?.decision === 'fail_terminal' ? qaEval.overrideArgs : resolvedArgs;
|
|
2442
|
-
// For a successful refine_variant, swap the refined static preview into
|
|
2443
|
-
// place and persist history BEFORE recording success in the store. This
|
|
2444
|
-
// keeps the user-visible `refinement.status: succeeded` (and the snapshot
|
|
2445
|
-
// emitted below) from ever being observable while the variant still serves
|
|
2446
|
-
// stale HTML. If post-processing throws, convert the report to `failed` so
|
|
2447
|
-
// the agent/UI surface the failure instead of a success pointing at
|
|
2448
|
-
// unrefreshed output.
|
|
2449
1999
|
if (workItemKind === 'refine_variant' &&
|
|
2450
2000
|
effectiveArgs.status === 'succeeded') {
|
|
2451
2001
|
try {
|
|
@@ -2492,9 +2042,6 @@ class AgentVariantsOrchestrator {
|
|
|
2492
2042
|
throw error;
|
|
2493
2043
|
}
|
|
2494
2044
|
this.emitChange();
|
|
2495
|
-
// Per-variant telemetry on terminal item statuses (skip 'running'
|
|
2496
|
-
// heartbeats and the brief work item — only code_gen / scaffold_base
|
|
2497
|
-
// matter for the funnel).
|
|
2498
2045
|
if (effectiveArgs.status === 'succeeded' ||
|
|
2499
2046
|
effectiveArgs.status === 'failed' ||
|
|
2500
2047
|
effectiveArgs.status === 'cancelled') {
|
|
@@ -2503,11 +2050,8 @@ class AgentVariantsOrchestrator {
|
|
|
2503
2050
|
const durationMs = leasedAt !== undefined ? Date.now() - leasedAt : null;
|
|
2504
2051
|
const approveStartedAt = resources?.approveStartedAt;
|
|
2505
2052
|
const approveToCompleteMs = approveStartedAt !== undefined ? Date.now() - approveStartedAt : null;
|
|
2506
|
-
// Byte size of generated output for HTML vs full-stack comparison.
|
|
2507
2053
|
const outputBytes = estimateOutputBytes(effectiveArgs.output);
|
|
2508
2054
|
const projectContextKind = this.store.getProjectContext(args.sessionId).kind;
|
|
2509
|
-
// Execution mode mirrors the host work-item snapshot derivation so
|
|
2510
|
-
// prod latency can finally segment vary vs create vs refine.
|
|
2511
2055
|
const mode = workItemKind !== undefined && isImplementationWorkItemKind(workItemKind)
|
|
2512
2056
|
? this.store.isVaryForkWorkItem(args.sessionId, args.workItemId)
|
|
2513
2057
|
? 'vary'
|
|
@@ -2523,15 +2067,11 @@ class AgentVariantsOrchestrator {
|
|
|
2523
2067
|
approveToCompleteMs,
|
|
2524
2068
|
kind: workItemKind ?? null,
|
|
2525
2069
|
mode,
|
|
2526
|
-
// Phase split of `durationMs`: agent work vs server-side gating.
|
|
2527
2070
|
leaseToReportMs: leasedAt !== undefined ? reportReceivedAt - leasedAt : null,
|
|
2528
2071
|
reportProcessingMs: Date.now() - reportReceivedAt,
|
|
2529
2072
|
qaMs,
|
|
2530
2073
|
hasError: Boolean(effectiveArgs.error),
|
|
2531
2074
|
errorCode: effectiveArgs.error?.code ?? null,
|
|
2532
|
-
// Failure detail + API status ride the event so field failures are
|
|
2533
|
-
// diagnosable from telemetry alone (the July 2026 EXECUTOR_WORKER_FAILED
|
|
2534
|
-
// incident took an hour of forensics for want of these).
|
|
2535
2075
|
errorMessage: effectiveArgs.error?.message ?? null,
|
|
2536
2076
|
errorApiStatus: effectiveArgs.error?.apiErrorStatus ?? null,
|
|
2537
2077
|
isScaffold: resources?.scaffoldBaseWorkItemId === args.workItemId,
|
|
@@ -2617,10 +2157,6 @@ class AgentVariantsOrchestrator {
|
|
|
2617
2157
|
log.error(`handleSucceededReport failed for ${args.sessionId}/${args.workItemId}`, err);
|
|
2618
2158
|
});
|
|
2619
2159
|
}
|
|
2620
|
-
// Teardown is deferred to commitVariant / cancel. Terminal stage just
|
|
2621
|
-
// means all variants are done; the user still needs to review and pick
|
|
2622
|
-
// one. Resources (worktrees + captured diffs) live until that pick lands
|
|
2623
|
-
// on the bridge.
|
|
2624
2160
|
return result;
|
|
2625
2161
|
}
|
|
2626
2162
|
async cancel(args) {
|
|
@@ -2651,13 +2187,6 @@ class AgentVariantsOrchestrator {
|
|
|
2651
2187
|
});
|
|
2652
2188
|
return result;
|
|
2653
2189
|
}
|
|
2654
|
-
/**
|
|
2655
|
-
* Cancel a single variant within a session. Siblings continue. Idempotent
|
|
2656
|
-
* on terminal states. Per-variant worktree teardown is deferred to a
|
|
2657
|
-
* follow-up; the lease is released, so requestWork won't re-surface this
|
|
2658
|
-
* variant and the agent's report_variant_complete for it (if it lands
|
|
2659
|
-
* after cancellation) is rejected by the stale-lease check.
|
|
2660
|
-
*/
|
|
2661
2190
|
async cancelVariant(args) {
|
|
2662
2191
|
const result = this.store.cancelWorkItem({
|
|
2663
2192
|
sessionId: args.sessionId,
|
|
@@ -2687,12 +2216,6 @@ class AgentVariantsOrchestrator {
|
|
|
2687
2216
|
alreadyTerminal: result.alreadyTerminal,
|
|
2688
2217
|
};
|
|
2689
2218
|
}
|
|
2690
|
-
/**
|
|
2691
|
-
* Remove a variant from the UI. Hides it from the active snapshot for good
|
|
2692
|
-
* (it's filtered out of progress/summary/terminal accounting too) while
|
|
2693
|
-
* retaining it in `.rivet/variants/` with status `removed` so the work is
|
|
2694
|
-
* kept, never rendered again. Mirrors `cancelVariant`'s shape; idempotent.
|
|
2695
|
-
*/
|
|
2696
2219
|
async removeVariant(args) {
|
|
2697
2220
|
const result = this.store.removeWorkItem({
|
|
2698
2221
|
sessionId: args.sessionId,
|
|
@@ -2720,13 +2243,6 @@ class AgentVariantsOrchestrator {
|
|
|
2720
2243
|
alreadyRemoved: result.alreadyRemoved,
|
|
2721
2244
|
};
|
|
2722
2245
|
}
|
|
2723
|
-
/**
|
|
2724
|
-
* Rename a variant's user-visible title. Patches the in-memory work item so
|
|
2725
|
-
* the next snapshot carries the new label, persists it to the variant's
|
|
2726
|
-
* `.rivet/variants/` manifest (best-effort — a never-persisted variant simply
|
|
2727
|
-
* skips the disk write), and pushes the updated snapshot over SSE. Mirrors
|
|
2728
|
-
* `removeVariant`'s shape.
|
|
2729
|
-
*/
|
|
2730
2246
|
async renameVariant(args) {
|
|
2731
2247
|
const result = this.store.renameWorkItem({
|
|
2732
2248
|
sessionId: args.sessionId,
|
|
@@ -2737,7 +2253,6 @@ class AgentVariantsOrchestrator {
|
|
|
2737
2253
|
source: 'mcp',
|
|
2738
2254
|
sessionId: args.sessionId,
|
|
2739
2255
|
variantId: args.variantId,
|
|
2740
|
-
// Telemetry policy: never the raw agent/user label text, only its length.
|
|
2741
2256
|
labelLength: args.label.length,
|
|
2742
2257
|
sessionStage: result.sessionStage,
|
|
2743
2258
|
});
|
|
@@ -2752,10 +2267,6 @@ class AgentVariantsOrchestrator {
|
|
|
2752
2267
|
sessionStage: result.sessionStage,
|
|
2753
2268
|
};
|
|
2754
2269
|
}
|
|
2755
|
-
/**
|
|
2756
|
-
* Rename a run folder: re-home one request batch in a single store pass,
|
|
2757
|
-
* persist each affected manifest best-effort, and push one updated snapshot.
|
|
2758
|
-
*/
|
|
2759
2270
|
async renameRun(args) {
|
|
2760
2271
|
const result = this.store.renameRun({
|
|
2761
2272
|
sessionId: args.sessionId,
|
|
@@ -2766,7 +2277,6 @@ class AgentVariantsOrchestrator {
|
|
|
2766
2277
|
this.telemetry.track('agent_variants.run_renamed', {
|
|
2767
2278
|
source: 'mcp',
|
|
2768
2279
|
sessionId: args.sessionId,
|
|
2769
|
-
// Telemetry policy: never the raw label text, only its length.
|
|
2770
2280
|
runLabelLength: args.label.length,
|
|
2771
2281
|
renamedCount: result.workItemIds.length,
|
|
2772
2282
|
sessionStage: result.sessionStage,
|
|
@@ -2785,18 +2295,7 @@ class AgentVariantsOrchestrator {
|
|
|
2785
2295
|
sessionStage: result.sessionStage,
|
|
2786
2296
|
};
|
|
2787
2297
|
}
|
|
2788
|
-
/**
|
|
2789
|
-
* User has reviewed the rendered variants and picked one. Look up the
|
|
2790
|
-
* captured diff or generated project, apply it to the destination, and record
|
|
2791
|
-
* the pick. Idempotent on (sessionId, variantId): repeating the call returns
|
|
2792
|
-
* duplicate=true without applying again.
|
|
2793
|
-
*/
|
|
2794
2298
|
async commitVariant(args) {
|
|
2795
|
-
// Serialize per-session so two overlapping commits can't both run
|
|
2796
|
-
// `applyDiffToProject` (or the fresh rename) before the first records
|
|
2797
|
-
// its pick. The second caller waits for the first to settle, then runs
|
|
2798
|
-
// commitVariantImpl which hits the idempotency check in
|
|
2799
|
-
// `getVariantPick` / `recordVariantPick`.
|
|
2800
2299
|
const prior = this.inflightCommits.get(args.sessionId);
|
|
2801
2300
|
const run = (async () => {
|
|
2802
2301
|
if (prior) {
|
|
@@ -2825,17 +2324,8 @@ class AgentVariantsOrchestrator {
|
|
|
2825
2324
|
}
|
|
2826
2325
|
}
|
|
2827
2326
|
async commitVariantImpl(args) {
|
|
2828
|
-
// Idempotent path — SessionStore.recordVariantPick is the source of truth
|
|
2829
|
-
// for which variant the user picked. If the same variant is being
|
|
2830
|
-
// committed again, replay the previously stored envelope's metadata
|
|
2831
|
-
// without going back through resources (which may have been torn down).
|
|
2832
2327
|
const existingPick = this.store.getVariantPick(args.sessionId);
|
|
2833
2328
|
if (existingPick && existingPick.variantId === args.variantId) {
|
|
2834
|
-
// Retry-safe history flip. If the first commit attempt applied
|
|
2835
|
-
// successfully but the history-persist task crashed, the chosen variant
|
|
2836
|
-
// stays at `completed` instead of `committed` on disk. Re-run the flip on
|
|
2837
|
-
// every duplicate attempt; the terminal-status guard in `markStatus`
|
|
2838
|
-
// makes this safely idempotent.
|
|
2839
2329
|
const projectContext = this.store.getProjectContext(args.sessionId);
|
|
2840
2330
|
let historyProjectPath;
|
|
2841
2331
|
if (projectContext.kind === 'fresh') {
|
|
@@ -2861,9 +2351,6 @@ class AgentVariantsOrchestrator {
|
|
|
2861
2351
|
log.warn(`persistVariantHistoryAtCommit (duplicate retry) failed for session ${args.sessionId}`, err);
|
|
2862
2352
|
});
|
|
2863
2353
|
}
|
|
2864
|
-
// If the committed dev/static server is still running (either tracked
|
|
2865
|
-
// on resources, or handed off to the lingering registry), surface its
|
|
2866
|
-
// URL so a retry restores the iframe to the live project.
|
|
2867
2354
|
const lingering = this.lingeringCommittedDevServers.get(args.sessionId);
|
|
2868
2355
|
const live = this.resources.get(args.sessionId)?.committedDevServer;
|
|
2869
2356
|
const replayPort = lingering?.port ?? live?.port;
|
|
@@ -2898,19 +2385,9 @@ class AgentVariantsOrchestrator {
|
|
|
2898
2385
|
let envelopeDestination;
|
|
2899
2386
|
let changedFilesCount;
|
|
2900
2387
|
let runnablePaths;
|
|
2901
|
-
// Port of the committed dev/static server, when one was spawned during
|
|
2902
|
-
// this commit. Surfaced on the response as `previewUrl` so the UI can
|
|
2903
|
-
// restore the iframe to the committed project without falling through to
|
|
2904
|
-
// the auto-static fallback.
|
|
2905
2388
|
let committedPreviewPort;
|
|
2906
2389
|
if (projectContext.kind === 'fresh') {
|
|
2907
2390
|
const destinationPath = projectContext.workspacePath;
|
|
2908
|
-
// Realpath the destination ONCE for both the empty-check (below) and
|
|
2909
|
-
// the static_preview flatten step (further down). Computing it twice
|
|
2910
|
-
// could diverge if the path's realpath status changes between calls
|
|
2911
|
-
// (e.g. the directory was a symlink during the empty check but got
|
|
2912
|
-
// resolved between then and `mkdirSync`). `undefined` means realpath
|
|
2913
|
-
// failed — caller branches treat that as "no canonical form known".
|
|
2914
2391
|
let realDestination;
|
|
2915
2392
|
try {
|
|
2916
2393
|
realDestination = fs_1.default.realpathSync(destinationPath);
|
|
@@ -2918,34 +2395,13 @@ class AgentVariantsOrchestrator {
|
|
|
2918
2395
|
catch {
|
|
2919
2396
|
realDestination = undefined;
|
|
2920
2397
|
}
|
|
2921
|
-
// Read the commit policy off the canonical run plan rather than
|
|
2922
|
-
// re-deriving from executionPlan.mode. `materialize_project` is the
|
|
2923
|
-
// vite_app lane (rename/copy the whole worktree); `write_static_site`
|
|
2924
|
-
// is the static_preview lane (inline HTML + sibling assets).
|
|
2925
2398
|
const commitPolicy = (0, runPlan_1.resolveRunPlanPolicy)(projectContext).commit;
|
|
2926
2399
|
const isViteApp = commitPolicy === 'materialize_project';
|
|
2927
|
-
// vite_app: strict emptiness check — that lane renames a worktree into
|
|
2928
|
-
// destinationPath and would clobber user files.
|
|
2929
|
-
// static_preview: the agent intentionally wrote sibling assets under
|
|
2930
|
-
// workspacePath (via `output.assetBase`) before reporting succeeded —
|
|
2931
|
-
// those per-variant subdirs ARE the deliverable. Allow exactly the
|
|
2932
|
-
// assetBase entries known to this session; anything else still
|
|
2933
|
-
// triggers DESTINATION_NOT_EMPTY.
|
|
2934
2400
|
if (isViteApp) {
|
|
2935
2401
|
this.assertDestinationAvailable(destinationPath);
|
|
2936
2402
|
}
|
|
2937
2403
|
else {
|
|
2938
|
-
// Compare assetBase entries (which are realpath'd by
|
|
2939
|
-
// resolveStaticPreviewAssetBase) against the realpath'd destination
|
|
2940
|
-
// — on macOS `/tmp` is a symlink to `/private/tmp`, and a raw
|
|
2941
|
-
// string comparison would falsely reject every entry.
|
|
2942
2404
|
const compareBase = realDestination ?? destinationPath;
|
|
2943
|
-
// When ANY variant's assetBase is the destination itself (the agent
|
|
2944
|
-
// wrote files directly at the workspace root rather than under a
|
|
2945
|
-
// per-variant subdir), the empty-check would treat the agent's own
|
|
2946
|
-
// deliverable as foreign content. Skip the check in that case — the
|
|
2947
|
-
// workspace IS the deliverable; commit will overwrite index.html
|
|
2948
|
-
// below.
|
|
2949
2405
|
const anyAssetBaseIsDestination = [
|
|
2950
2406
|
...resources.staticPreviews.values(),
|
|
2951
2407
|
].some((sp) => sp.assetBase === compareBase);
|
|
@@ -2960,16 +2416,6 @@ class AgentVariantsOrchestrator {
|
|
|
2960
2416
|
}
|
|
2961
2417
|
}
|
|
2962
2418
|
if (isViteApp) {
|
|
2963
|
-
// Vite_app: the deliverable is the entire variant worktree, not a
|
|
2964
|
-
// single HTML file. When the worktree lives on the same volume as
|
|
2965
|
-
// the destination (the common case — provisionFreshWorktrees scaffolds
|
|
2966
|
-
// under destinationParent/.rivet-variants/) we can rename it into
|
|
2967
|
-
// place. That moves the entire tree — including the materialized
|
|
2968
|
-
// node_modules — in O(1) with no copy, and the rename is atomic.
|
|
2969
|
-
// For cross-volume cases (user passed a destinationParent on a
|
|
2970
|
-
// different mount than the .rivet-variants dir, e.g. tests stubbing
|
|
2971
|
-
// workspacePath to a tmp dir), fall back to the recursive-copy +
|
|
2972
|
-
// background-install path so the feature still works.
|
|
2973
2419
|
const record = resources.worktrees.get(args.variantId);
|
|
2974
2420
|
if (!record) {
|
|
2975
2421
|
throw new errors_1.AgentVariantsError('WORK_ITEM_NOT_FOUND', `Unknown variantId ${args.variantId} for session ${args.sessionId}`);
|
|
@@ -2978,18 +2424,6 @@ class AgentVariantsOrchestrator {
|
|
|
2978
2424
|
let isDependencyInstallRequired = false;
|
|
2979
2425
|
try {
|
|
2980
2426
|
if (areSameVolume(record.worktreePath, destinationPath)) {
|
|
2981
|
-
// Vite's dev server writes its module cache to `<worktreePath>/.vite/`
|
|
2982
|
-
// and recreates that directory on the fly whenever it's missing. If
|
|
2983
|
-
// we rename a worktree out from under a running dev server, Vite
|
|
2984
|
-
// will materialize an empty `.vite/` shell back at the OLD path —
|
|
2985
|
-
// leaving behind orphan stub dirs in `.rivet-variants/` and
|
|
2986
|
-
// confusing later cleanup. Stop every variant's dev server first
|
|
2987
|
-
// (including the chosen variant, which is about to move) so no
|
|
2988
|
-
// process is holding the old paths open during the rename.
|
|
2989
|
-
//
|
|
2990
|
-
// We stop them eagerly here rather than relying on teardownSession
|
|
2991
|
-
// because teardown runs AFTER the rename — too late to prevent the
|
|
2992
|
-
// stub-dir race.
|
|
2993
2427
|
await this.stopAllDevServersForSession(resources);
|
|
2994
2428
|
isDependencyInstallRequired = await resolveNodeModulesSymlink(record.worktreePath);
|
|
2995
2429
|
await this.renameWorktreeIntoDestination(record.worktreePath, destinationPath);
|
|
@@ -3005,21 +2439,6 @@ class AgentVariantsOrchestrator {
|
|
|
3005
2439
|
}
|
|
3006
2440
|
changedFilesCount = countWorktreeFiles(destinationPath);
|
|
3007
2441
|
if (!usedRename) {
|
|
3008
|
-
// Cross-volume fallback: materializeProject excludes node_modules
|
|
3009
|
-
// so we have to re-install at the destination. Don't await the
|
|
3010
|
-
// install — the agent's commit_variant call should return
|
|
3011
|
-
// immediately — but chain the dev-server start to it so the iframe
|
|
3012
|
-
// recovers without manual intervention once deps are ready.
|
|
3013
|
-
//
|
|
3014
|
-
// NOTE: `committedPreviewPort` stays undefined on this branch by
|
|
3015
|
-
// design — the install + start sequence takes minutes, far longer
|
|
3016
|
-
// than the response can wait. The iframe's `switchPreviewPort`
|
|
3017
|
-
// callback (invoked from `startCommittedDevServer` when the
|
|
3018
|
-
// server finally comes up) retargets the proxy then, so the
|
|
3019
|
-
// iframe reaches the new server without the URL being on the
|
|
3020
|
-
// commit response. The response surface stays `previewUrl?:` (the
|
|
3021
|
-
// field is optional) and consumers fall back to the proxy
|
|
3022
|
-
// upstream when it's absent.
|
|
3023
2442
|
void this.installDependencies(destinationPath)
|
|
3024
2443
|
.then(() => this.startCommittedDevServer({
|
|
3025
2444
|
resources,
|
|
@@ -3033,9 +2452,6 @@ class AgentVariantsOrchestrator {
|
|
|
3033
2452
|
await this.installDependencies(destinationPath);
|
|
3034
2453
|
}
|
|
3035
2454
|
if (usedRename) {
|
|
3036
|
-
// Preserve the unchosen variants as runnable siblings of the
|
|
3037
|
-
// chosen project. Best-effort: failures here log and continue so
|
|
3038
|
-
// a partial history never blocks the commit handoff.
|
|
3039
2455
|
try {
|
|
3040
2456
|
runnablePaths = this.preserveUnchosenVariants({
|
|
3041
2457
|
sessionId: args.sessionId,
|
|
@@ -3046,12 +2462,6 @@ class AgentVariantsOrchestrator {
|
|
|
3046
2462
|
catch (err) {
|
|
3047
2463
|
log.warn(`preserveUnchosenVariants failed for session ${args.sessionId}; continuing without history`, err);
|
|
3048
2464
|
}
|
|
3049
|
-
// Stopped every dev server pre-rename to dodge the .vite/ stub-dir
|
|
3050
|
-
// race. The iframe is still pointed at the (now-dead) chosen
|
|
3051
|
-
// variant's port via the proxy, so without a fresh server at the
|
|
3052
|
-
// destination the user would see "preview disconnected" the moment
|
|
3053
|
-
// they commit. Spawn one and retarget the proxy. Best-effort: if
|
|
3054
|
-
// it fails, the user can `npm run dev` themselves at destination.
|
|
3055
2465
|
committedPreviewPort = await this.startCommittedDevServer({
|
|
3056
2466
|
resources,
|
|
3057
2467
|
destinationPath,
|
|
@@ -3069,18 +2479,7 @@ class AgentVariantsOrchestrator {
|
|
|
3069
2479
|
envelopeDestination = destinationPath;
|
|
3070
2480
|
}
|
|
3071
2481
|
else {
|
|
3072
|
-
// Static_preview: HTML is the entire deliverable. Write index.html.
|
|
3073
|
-
// Prefer the in-memory record; fall back to the persisted history at
|
|
3074
|
-
// `<workspacePath>/.rivet/variants/<sessionId>/<variantId>/files/index.html`
|
|
3075
|
-
// so a process restart between report_variant_complete and commit
|
|
3076
|
-
// doesn't strand the variant.
|
|
3077
2482
|
const staticPreview = resources.staticPreviews.get(args.variantId);
|
|
3078
|
-
// Resolve the committed index.html before the flatten step below
|
|
3079
|
-
// moves/removes the per-variant dir. `getStaticPreviewHtml` reads the
|
|
3080
|
-
// materialized `<dir>/index.html` and falls back to the work-item's
|
|
3081
|
-
// stored output (the reported HTML) when the on-disk file is missing
|
|
3082
|
-
// or empty — so a failed materialization still commits real content
|
|
3083
|
-
// rather than an empty file.
|
|
3084
2483
|
const htmlFromDir = staticPreview
|
|
3085
2484
|
? this.getStaticPreviewHtml(args.sessionId, args.variantId)
|
|
3086
2485
|
: undefined;
|
|
@@ -3094,21 +2493,6 @@ class AgentVariantsOrchestrator {
|
|
|
3094
2493
|
}
|
|
3095
2494
|
try {
|
|
3096
2495
|
fs_1.default.mkdirSync(destinationPath, { recursive: true });
|
|
3097
|
-
// If the chosen variant has an `assetBase` subdir under
|
|
3098
|
-
// destinationPath (e.g. `<workspace>/var-1` containing
|
|
3099
|
-
// `avatar.glb`), move its contents up to the destination root so
|
|
3100
|
-
// the committed HTML can reference them as `./avatar.glb`. Then
|
|
3101
|
-
// delete every OTHER static_preview record's assetBase — the
|
|
3102
|
-
// unchosen variants' sibling assets are no longer relevant once
|
|
3103
|
-
// the user picked. Both steps run before the canonical index.html
|
|
3104
|
-
// is written so the chosen variant's on-disk index.html (if any)
|
|
3105
|
-
// gets overwritten by the inlined version below.
|
|
3106
|
-
// assetBase entries are realpath'd; compare against the realpath
|
|
3107
|
-
// of destinationPath so symlink-stripped paths line up (macOS:
|
|
3108
|
-
// `/tmp` → `/private/tmp`). `realDestination` was computed once
|
|
3109
|
-
// at the top of the fresh branch — re-realpath in case `mkdirSync`
|
|
3110
|
-
// above just created the directory (the initial computation may
|
|
3111
|
-
// have returned undefined when the dir didn't yet exist).
|
|
3112
2496
|
let flattenBase = realDestination;
|
|
3113
2497
|
if (!flattenBase) {
|
|
3114
2498
|
try {
|
|
@@ -3119,32 +2503,17 @@ class AgentVariantsOrchestrator {
|
|
|
3119
2503
|
}
|
|
3120
2504
|
}
|
|
3121
2505
|
const chosenAssetBase = staticPreview?.assetBase;
|
|
3122
|
-
// Skip flattening when assetBase IS the destination — the agent
|
|
3123
|
-
// wrote files directly at the workspace root, so there's no subdir
|
|
3124
|
-
// to flatten. Only move when assetBase is a strict descendant.
|
|
3125
2506
|
if (chosenAssetBase &&
|
|
3126
2507
|
isStrictlyInside(chosenAssetBase, flattenBase)) {
|
|
3127
2508
|
for (const entry of fs_1.default.readdirSync(chosenAssetBase)) {
|
|
3128
2509
|
const src = path_1.default.join(chosenAssetBase, entry);
|
|
3129
2510
|
const dst = path_1.default.join(flattenBase, entry);
|
|
3130
|
-
// Self-collision guard: when an agent names a child the same
|
|
3131
|
-
// as the parent dir (e.g. `var-1/var-1/`), `dst` resolves to
|
|
3132
|
-
// `chosenAssetBase` itself. The rmSync below would then delete
|
|
3133
|
-
// the parent — including every remaining entry we're about to
|
|
3134
|
-
// move — and the next iteration's `renameSync` would fail
|
|
3135
|
-
// with ENOENT. The agent's last attempted variant would also
|
|
3136
|
-
// be silently dropped. Skip this entry; we still rm the
|
|
3137
|
-
// parent at the end of the loop.
|
|
3138
2511
|
if (path_1.default.resolve(dst) === path_1.default.resolve(chosenAssetBase)) {
|
|
3139
2512
|
continue;
|
|
3140
2513
|
}
|
|
3141
2514
|
if (fs_1.default.existsSync(dst)) {
|
|
3142
2515
|
fs_1.default.rmSync(dst, { recursive: true, force: true });
|
|
3143
2516
|
}
|
|
3144
|
-
// Cross-volume safety: rename fails with EXDEV when src and
|
|
3145
|
-
// dst are on different mounts (possible when the user's
|
|
3146
|
-
// workspacePath crosses a symlink to another volume). Fall
|
|
3147
|
-
// back to recursive copy + remove so the commit doesn't die.
|
|
3148
2517
|
try {
|
|
3149
2518
|
fs_1.default.renameSync(src, dst);
|
|
3150
2519
|
}
|
|
@@ -3173,10 +2542,6 @@ class AgentVariantsOrchestrator {
|
|
|
3173
2542
|
throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `Failed to write static preview to ${destinationPath}: ${message}`);
|
|
3174
2543
|
}
|
|
3175
2544
|
changedFilesCount = countWorktreeFiles(destinationPath);
|
|
3176
|
-
// Spawn a static file server at destinationPath and retarget the
|
|
3177
|
-
// proxy so the iframe stays live across commit (parity with the
|
|
3178
|
-
// vite_app rename path). Best-effort: a failure leaves the iframe
|
|
3179
|
-
// showing "preview disconnected" but doesn't fail the commit.
|
|
3180
2545
|
committedPreviewPort = await this.startCommittedDevServer({
|
|
3181
2546
|
resources,
|
|
3182
2547
|
destinationPath,
|
|
@@ -3192,10 +2557,6 @@ class AgentVariantsOrchestrator {
|
|
|
3192
2557
|
}
|
|
3193
2558
|
}
|
|
3194
2559
|
else {
|
|
3195
|
-
// Existing project: diff against the user's repo. resolveEnv lives in
|
|
3196
|
-
// this branch only — fresh sessions don't have a user-supplied project
|
|
3197
|
-
// and the bridge.getProjectPath() it reads from would either be stale
|
|
3198
|
-
// or empty for them.
|
|
3199
2560
|
const env = await this.resolveEnv(args.sessionId);
|
|
3200
2561
|
const record = resources.worktrees.get(args.variantId);
|
|
3201
2562
|
if (!record) {
|
|
@@ -3205,8 +2566,6 @@ class AgentVariantsOrchestrator {
|
|
|
3205
2566
|
throw new errors_1.AgentVariantsError('INVALID_STAGE_ACTION', `Variant ${args.variantId} has no captured diff yet — wait for report_variant_complete(succeeded) first`);
|
|
3206
2567
|
}
|
|
3207
2568
|
changedFilesCount = countDiffFiles(record.diff);
|
|
3208
|
-
// Apply the diff to the user's working tree so the variant lands on the
|
|
3209
|
-
// current branch uncommitted.
|
|
3210
2569
|
if (!this.worktrees.applyDiffToProject) {
|
|
3211
2570
|
throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', 'WorktreeManager does not support applying diffs to the project tree');
|
|
3212
2571
|
}
|
|
@@ -3234,17 +2593,10 @@ class AgentVariantsOrchestrator {
|
|
|
3234
2593
|
changedFilesCount,
|
|
3235
2594
|
payload,
|
|
3236
2595
|
};
|
|
3237
|
-
// Record the pick in the SessionStore so future commitVariant calls with
|
|
3238
|
-
// the same variantId are idempotent and a different variantId returns
|
|
3239
|
-
// PENDING_CHANGE_CONFLICT (already picked).
|
|
3240
2596
|
this.store.recordVariantPick({
|
|
3241
2597
|
sessionId: args.sessionId,
|
|
3242
2598
|
envelope,
|
|
3243
2599
|
});
|
|
3244
|
-
// History: flip every persisted variant in this session to its terminal
|
|
3245
|
-
// status. Variants are persisted at code_gen success time; this patches
|
|
3246
|
-
// the status and destinationPath for the chosen one. Best-effort, never
|
|
3247
|
-
// blocks the commit.
|
|
3248
2600
|
const historyProjectPath = projectContext.kind === 'fresh'
|
|
3249
2601
|
? projectContext.workspacePath
|
|
3250
2602
|
: envelopeDestination;
|
|
@@ -3262,13 +2614,6 @@ class AgentVariantsOrchestrator {
|
|
|
3262
2614
|
log.warn(`persistVariantHistoryAtCommit failed for session ${args.sessionId}`, err);
|
|
3263
2615
|
}
|
|
3264
2616
|
resources.committedVariantIds.add(args.variantId);
|
|
3265
|
-
// For fresh `new-project` commits the committed variant IS the user's
|
|
3266
|
-
// final result — there's no dev server to fall back to. Keep the session
|
|
3267
|
-
// active so SSE keeps pushing snapshots with the chosen variant; the UI's
|
|
3268
|
-
// iframe stays on it instead of unmounting to about:blank (which would
|
|
3269
|
-
// surface a misleading "Preview isn't connected" overlay). For diff /
|
|
3270
|
-
// diff-applied commits the user moves on to their own dev server, so
|
|
3271
|
-
// clearing is correct — that's the original behavior preserved below.
|
|
3272
2617
|
if (this.activeSessionId === args.sessionId &&
|
|
3273
2618
|
payload.kind !== 'project-created') {
|
|
3274
2619
|
this.activeSessionId = null;
|
|
@@ -3288,9 +2633,6 @@ class AgentVariantsOrchestrator {
|
|
|
3288
2633
|
this.emitChange();
|
|
3289
2634
|
log.info(`Variant ${args.variantId} (${input.briefLabel}) committed by user`);
|
|
3290
2635
|
if (!args.skipTeardown) {
|
|
3291
|
-
// Once a variant is committed, the unpicked worktrees are no longer
|
|
3292
|
-
// useful. Schedule teardown in the background so the agent's
|
|
3293
|
-
// commit_variant call returns immediately.
|
|
3294
2636
|
void this.teardownSession(args.sessionId, 'committed').catch((err) => {
|
|
3295
2637
|
log.warn(`teardownSession after commit failed for ${args.sessionId}`, err);
|
|
3296
2638
|
});
|
|
@@ -3311,25 +2653,7 @@ class AgentVariantsOrchestrator {
|
|
|
3311
2653
|
async cleanupCommittedSession(sessionId) {
|
|
3312
2654
|
await this.teardownSession(sessionId, 'committed');
|
|
3313
2655
|
}
|
|
3314
|
-
|
|
3315
|
-
* Ensure the user-facing destination path can receive the new project.
|
|
3316
|
-
* Rejects when the path exists and is non-empty.
|
|
3317
|
-
*
|
|
3318
|
-
* `.rivet/` (pre-commit snapshots + history manifests) and `.gitignore`
|
|
3319
|
-
* (written by VariantHistoryService.ensureGitignore when variants persist
|
|
3320
|
-
* at success time) are both tolerated — neither is user-authored content
|
|
3321
|
-
* that would be clobbered by the materialize step.
|
|
3322
|
-
*/
|
|
3323
|
-
assertDestinationAvailable(destinationPath,
|
|
3324
|
-
/**
|
|
3325
|
-
* Top-level entries the caller knows it owns and can safely overwrite.
|
|
3326
|
-
* Used by the fresh static_preview commit path so a directory holding
|
|
3327
|
-
* only this session's per-variant `assetBase` subdirs still counts as
|
|
3328
|
-
* "available" — those came from the agent during generation. Any entry
|
|
3329
|
-
* NOT in this set (and not the standard `.rivet`/`.gitignore` exemptions)
|
|
3330
|
-
* still triggers DESTINATION_NOT_EMPTY.
|
|
3331
|
-
*/
|
|
3332
|
-
additionalAllowedEntries = new Set()) {
|
|
2656
|
+
assertDestinationAvailable(destinationPath, additionalAllowedEntries = new Set()) {
|
|
3333
2657
|
if (!fs_1.default.existsSync(destinationPath))
|
|
3334
2658
|
return;
|
|
3335
2659
|
const entries = fs_1.default.readdirSync(destinationPath);
|
|
@@ -3340,18 +2664,13 @@ class AgentVariantsOrchestrator {
|
|
|
3340
2664
|
return;
|
|
3341
2665
|
throw new errors_1.AgentVariantsError('DESTINATION_NOT_EMPTY', `Destination ${destinationPath} is not empty (${userVisibleEntries.length} entries) — refuse to materialize.`);
|
|
3342
2666
|
}
|
|
3343
|
-
/** Read the captured diff for a code-gen variant, if available. */
|
|
3344
2667
|
getVariantDiff(sessionId, variantId) {
|
|
3345
2668
|
return this.resources.get(sessionId)?.worktrees.get(variantId)?.diff;
|
|
3346
2669
|
}
|
|
3347
|
-
// --- Side-effect implementations ----------------------------------------
|
|
3348
2670
|
async provisionWorktrees(sessionId, approveResult) {
|
|
3349
2671
|
const projectContext = this.store.getProjectContext(sessionId);
|
|
3350
2672
|
const variantCount = approveResult.codeGenWorkItemIds.length +
|
|
3351
2673
|
(approveResult.scaffoldBaseWorkItemId ? 1 : 0);
|
|
3352
|
-
// Generated + static_preview provisions nothing (HTML is the deliverable)
|
|
3353
|
-
// — skip the timing/telemetry wrapper so the fast path stays untouched.
|
|
3354
|
-
// `provision: 'none'` is exactly the no-scaffold generated-static lane.
|
|
3355
2674
|
if ((0, runPlan_1.resolveRunPlanPolicy)(projectContext).provision === 'none') {
|
|
3356
2675
|
return;
|
|
3357
2676
|
}
|
|
@@ -3364,10 +2683,6 @@ class AgentVariantsOrchestrator {
|
|
|
3364
2683
|
});
|
|
3365
2684
|
const run = async () => {
|
|
3366
2685
|
if (projectContext.kind === 'fresh') {
|
|
3367
|
-
// Fresh + vite_app: provision a Vite skeleton per variant and copy the
|
|
3368
|
-
// agent-planned assetPlan files before the agent leases its code_gen
|
|
3369
|
-
// items. (Background `npm install` is dispatched inside and is NOT
|
|
3370
|
-
// awaited here — the timeout bounds worktree creation, not install.)
|
|
3371
2686
|
await this.provisionFreshWorktrees(sessionId, approveResult, projectContext);
|
|
3372
2687
|
return;
|
|
3373
2688
|
}
|
|
@@ -3398,9 +2713,6 @@ class AgentVariantsOrchestrator {
|
|
|
3398
2713
|
? err.code
|
|
3399
2714
|
: 'PROVISION_FAILED',
|
|
3400
2715
|
});
|
|
3401
|
-
// Cancel synchronously before cleanup so a retry does not see this
|
|
3402
|
-
// failed session as active. cancel() schedules teardown without blocking
|
|
3403
|
-
// the provisioning error on git cleanup.
|
|
3404
2716
|
void this.cancel({ sessionId, reason: 'provisioning_failed' }).catch((teardownErr) => {
|
|
3405
2717
|
log.warn(`cleanup after provisioning failure for ${sessionId} failed`, teardownErr);
|
|
3406
2718
|
});
|
|
@@ -3415,10 +2727,6 @@ class AgentVariantsOrchestrator {
|
|
|
3415
2727
|
throw err;
|
|
3416
2728
|
}
|
|
3417
2729
|
}
|
|
3418
|
-
/**
|
|
3419
|
-
* Existing-project flow: clone the user's repo N times via git worktree.
|
|
3420
|
-
* Waits for source and dependency copies before making work available.
|
|
3421
|
-
*/
|
|
3422
2730
|
async provisionExistingWorktrees(sessionId, approveResult) {
|
|
3423
2731
|
const resources = this.ensureResources(sessionId);
|
|
3424
2732
|
const totalCount = approveResult.codeGenWorkItemIds.length +
|
|
@@ -3445,19 +2753,6 @@ class AgentVariantsOrchestrator {
|
|
|
3445
2753
|
});
|
|
3446
2754
|
}
|
|
3447
2755
|
}
|
|
3448
|
-
/**
|
|
3449
|
-
* Fresh-project flow: scaffold one template per variant + DESIGN.md per
|
|
3450
|
-
* slot synchronously (fast — just file writes + git init), then dispatch a
|
|
3451
|
-
* background `npm install` task per worktree. Returns immediately so the
|
|
3452
|
-
* `approve_variant_briefs` MCP tool doesn't time out on cold installs.
|
|
3453
|
-
*
|
|
3454
|
-
* On install success: `sessionStore.completeInternal(scaffold_base)` runs,
|
|
3455
|
-
* which unblocks the dependent code_gen items.
|
|
3456
|
-
*
|
|
3457
|
-
* On install failure: the scaffold_base work item is marked failed via
|
|
3458
|
-
* `failInternal`, which cascades DEPENDENCY_FAILED to all dependent
|
|
3459
|
-
* code_gen items so the session degrades cleanly.
|
|
3460
|
-
*/
|
|
3461
2756
|
async provisionFreshWorktrees(sessionId, approveResult, projectContext) {
|
|
3462
2757
|
const resources = this.ensureResources(sessionId);
|
|
3463
2758
|
const scaffoldId = approveResult.scaffoldBaseWorkItemId;
|
|
@@ -3484,33 +2779,14 @@ class AgentVariantsOrchestrator {
|
|
|
3484
2779
|
designContext: summarizeDesignContext(designContext),
|
|
3485
2780
|
});
|
|
3486
2781
|
log.info(`Provisioning ${codeGenIds.length} fresh worktree(s) for session ${sessionId}`);
|
|
3487
|
-
// destinationParent for fresh worktrees: the user's workspace root
|
|
3488
|
-
// (sibling to `.rivet/`). Keeping the worktree on the same volume as
|
|
3489
|
-
// the materialize destination turns commit into a directory rename
|
|
3490
|
-
// instead of a recursive copy. `path.dirname(workspacePath)` *used*
|
|
3491
|
-
// to equal `workspaceRoot`, but after nesting subprojects under
|
|
3492
|
-
// `<workspaceRoot>/.rivet/<slug>/` the dirname is now `.rivet/`,
|
|
3493
|
-
// which would stage worktrees inside `.rivet/.rivet-variants/`.
|
|
3494
|
-
// Use workspaceRoot directly so staging lives at
|
|
3495
|
-
// `<workspaceRoot>/.rivet-variants/` as originally intended.
|
|
3496
2782
|
const destinationParent = projectContext.workspaceRoot;
|
|
3497
2783
|
const paths = await createFresh.call(this.worktrees, sessionId, codeGenIds.length, viteReactTs_1.VITE_REACT_TS_TEMPLATE, designContext, destinationParent);
|
|
3498
2784
|
resources.scaffoldBaseWorkItemId = scaffoldId;
|
|
3499
2785
|
resources.freshDestinationParent = destinationParent;
|
|
3500
|
-
// Each code_gen item maps 1:1 to a fresh worktree. The scaffold_base
|
|
3501
|
-
// work item is internal — no dedicated worktree.
|
|
3502
2786
|
await Promise.all(codeGenIds.map((workItemId, index) => this.registerWorktreeWorkspace(resources, {
|
|
3503
2787
|
workItemId,
|
|
3504
2788
|
worktreePath: paths[index],
|
|
3505
2789
|
})));
|
|
3506
|
-
// Copy agent-planned assets (e.g. avatar.glb) into each worktree so
|
|
3507
|
-
// generated code can reference them via plan.referenceAs. Done before
|
|
3508
|
-
// the background install so the assets are on disk by the time the
|
|
3509
|
-
// agent leases its code_gen item.
|
|
3510
|
-
// If copy throws (e.g. source asset deleted between planning and
|
|
3511
|
-
// provisioning), fail scaffold_base immediately so dependent code_gen
|
|
3512
|
-
// items cascade DEPENDENCY_FAILED instead of leaving the session
|
|
3513
|
-
// permanently stuck in `work_items_ready`.
|
|
3514
2790
|
const assetPlan = projectContext.executionPlan?.assetPlan ?? [];
|
|
3515
2791
|
if (assetPlan.length > 0) {
|
|
3516
2792
|
try {
|
|
@@ -3542,18 +2818,10 @@ class AgentVariantsOrchestrator {
|
|
|
3542
2818
|
return;
|
|
3543
2819
|
}
|
|
3544
2820
|
}
|
|
3545
|
-
// Background install: don't await. The orchestrator finishes the
|
|
3546
|
-
// approve→provision call immediately; the agent polls for scaffold
|
|
3547
|
-
// completion via continue_variants(action='check').
|
|
3548
2821
|
void this.runBackgroundInstall(sessionId, scaffoldId, paths, scaffoldStartedAt).catch((err) => {
|
|
3549
2822
|
log.error(`runBackgroundInstall failed for session ${sessionId}`, err);
|
|
3550
2823
|
});
|
|
3551
2824
|
}
|
|
3552
|
-
/**
|
|
3553
|
-
* Run `npm install` in parallel across all fresh worktrees. On all-success,
|
|
3554
|
-
* mark scaffold_base succeeded via `completeInternal`. On any failure,
|
|
3555
|
-
* mark scaffold_base failed via `failInternal` and emit telemetry.
|
|
3556
|
-
*/
|
|
3557
2825
|
async runBackgroundInstall(sessionId, scaffoldWorkItemId, worktreePaths, scaffoldStartedAt) {
|
|
3558
2826
|
const installStartedAt = Date.now();
|
|
3559
2827
|
try {
|
|
@@ -3563,8 +2831,6 @@ class AgentVariantsOrchestrator {
|
|
|
3563
2831
|
})));
|
|
3564
2832
|
}
|
|
3565
2833
|
catch (err) {
|
|
3566
|
-
// Teardown aborts in-flight preparation; a cancelled session is not a
|
|
3567
|
-
// scaffold failure.
|
|
3568
2834
|
const resources = this.resources.get(sessionId);
|
|
3569
2835
|
if (!resources || resources.cleanupStarted)
|
|
3570
2836
|
return;
|
|
@@ -3606,12 +2872,6 @@ class AgentVariantsOrchestrator {
|
|
|
3606
2872
|
variantCount: worktreePaths.length,
|
|
3607
2873
|
});
|
|
3608
2874
|
}
|
|
3609
|
-
/**
|
|
3610
|
-
* Checks succeeded implementation reports before they reach the store.
|
|
3611
|
-
* Static previews must contain a structurally complete local artifact;
|
|
3612
|
-
* applicable existing-project variants must contain an added diff. Returns
|
|
3613
|
-
* a pass, a single repair retry, or a terminal integrity failure.
|
|
3614
|
-
*/
|
|
3615
2875
|
async evaluateQaForReport(args) {
|
|
3616
2876
|
if (args.status !== 'succeeded')
|
|
3617
2877
|
return null;
|
|
@@ -3619,15 +2879,12 @@ class AgentVariantsOrchestrator {
|
|
|
3619
2879
|
return null;
|
|
3620
2880
|
const projectContext = this.store.getProjectContext(args.sessionId);
|
|
3621
2881
|
const kind = this.store.getWorkItemKind(args.sessionId, args.workItemId);
|
|
3622
|
-
// Existing-project code_gen has no owned preview document to inspect. Its
|
|
3623
|
-
// structural contract is a captured diff containing added source content.
|
|
3624
2882
|
if (projectContext.kind !== 'fresh') {
|
|
3625
2883
|
if (kind === 'code_gen') {
|
|
3626
2884
|
return this.evaluateExistingCodeGenQa(args);
|
|
3627
2885
|
}
|
|
3628
2886
|
return null;
|
|
3629
2887
|
}
|
|
3630
|
-
// Resolve the objective base QA for this deliverable kind.
|
|
3631
2888
|
let baseQa = null;
|
|
3632
2889
|
const checkedSource = undefined;
|
|
3633
2890
|
if (kind === 'static_preview') {
|
|
@@ -3637,8 +2894,6 @@ class AgentVariantsOrchestrator {
|
|
|
3637
2894
|
baseQa = await this.runPreviewQaSafely(args, parsed.html);
|
|
3638
2895
|
}
|
|
3639
2896
|
else if (kind === 'code_gen') {
|
|
3640
|
-
// Fresh vite_app variants run agent-authored dev-server code. No
|
|
3641
|
-
// preview document to inspect — behave exactly as before.
|
|
3642
2897
|
return null;
|
|
3643
2898
|
}
|
|
3644
2899
|
else {
|
|
@@ -3656,7 +2911,6 @@ class AgentVariantsOrchestrator {
|
|
|
3656
2911
|
},
|
|
3657
2912
|
};
|
|
3658
2913
|
}
|
|
3659
|
-
// Synthesize a passing base verdict for vite_app (no objective layer).
|
|
3660
2914
|
const passedBase = baseQa ?? {
|
|
3661
2915
|
status: 'passed',
|
|
3662
2916
|
issues: [],
|
|
@@ -3740,8 +2994,6 @@ class AgentVariantsOrchestrator {
|
|
|
3740
2994
|
},
|
|
3741
2995
|
};
|
|
3742
2996
|
}
|
|
3743
|
-
/** Run the injected preview QA runner, converting a thrown runner into a
|
|
3744
|
-
* failed `VariantQaResult` (mirrors the prior inline behavior). */
|
|
3745
2997
|
async runPreviewQaSafely(args, html) {
|
|
3746
2998
|
try {
|
|
3747
2999
|
return await this.previewQaRunner({
|
|
@@ -3768,11 +3020,6 @@ class AgentVariantsOrchestrator {
|
|
|
3768
3020
|
memoizeQa(sessionId, workItemId, qa) {
|
|
3769
3021
|
this.ensureResources(sessionId).qaResults.set(workItemId, qa);
|
|
3770
3022
|
}
|
|
3771
|
-
/**
|
|
3772
|
-
* Handle a `retry` QA verdict: consume the agent's report, re-open the
|
|
3773
|
-
* variant work item so it can be re-leased and regenerated against the QA
|
|
3774
|
-
* notes, and record that it has now used its single retry.
|
|
3775
|
-
*/
|
|
3776
3023
|
async handleQaRegenRetry(args, qa) {
|
|
3777
3024
|
const resources = this.ensureResources(args.sessionId);
|
|
3778
3025
|
const result = this.store.requeueForRegeneration({
|
|
@@ -3794,11 +3041,6 @@ class AgentVariantsOrchestrator {
|
|
|
3794
3041
|
overall: null,
|
|
3795
3042
|
});
|
|
3796
3043
|
this.emitChange();
|
|
3797
|
-
// Carry the requeue signal + critique so the tool layer can tell the agent
|
|
3798
|
-
// to re-lease and regenerate. The store result is an opaque
|
|
3799
|
-
// `waiting_for_results` (the variant is pending again); on its own that is
|
|
3800
|
-
// indistinguishable from a sibling still in flight, so the agent would
|
|
3801
|
-
// otherwise abandon the variant and the session would stall at ready:0.
|
|
3802
3044
|
const completionResult = { ...result, requeuedForRegeneration: true, qa };
|
|
3803
3045
|
resources.repairCompletionResults.set(repairCompletionKey(args), completionResult);
|
|
3804
3046
|
return completionResult;
|
|
@@ -3817,16 +3059,6 @@ class AgentVariantsOrchestrator {
|
|
|
3817
3059
|
args.record.pendingAutoRestart !== args.autoRestartTimer;
|
|
3818
3060
|
return Boolean(resources && !resources.cleanupStarted && !isAutoRestartCancelled);
|
|
3819
3061
|
};
|
|
3820
|
-
// Bring up a dev server in the variant's worktree so the user can cycle
|
|
3821
|
-
// through live variants in the iframe via the chip. Failures here are
|
|
3822
|
-
// logged but non-fatal — the user can still pick by reading the diff.
|
|
3823
|
-
//
|
|
3824
|
-
// Pick a sensible port near the framework's default (3000 for Next, 5173
|
|
3825
|
-
// for Vite) and inject it via PORT + the CLI flag (see buildDevServerCommand)
|
|
3826
|
-
// so the server actually binds it — that's what moves a preview off a port
|
|
3827
|
-
// the user's own dev server already holds instead of colliding on it. On a
|
|
3828
|
-
// retry we scan past the port we just tried, so a transient race or a
|
|
3829
|
-
// briefly-held port resolves onto the next free one.
|
|
3830
3062
|
const previewStartedAt = Date.now();
|
|
3831
3063
|
const projectContextKind = args.isFresh ? 'fresh' : 'existing';
|
|
3832
3064
|
trackPreviewStarted(this.telemetry, {
|
|
@@ -3838,13 +3070,9 @@ class AgentVariantsOrchestrator {
|
|
|
3838
3070
|
const startPort = await this.resolveDevServerStartPort(args.sessionId, args.isFresh);
|
|
3839
3071
|
let scanFrom = startPort;
|
|
3840
3072
|
const maxAttempts = DEV_SERVER_START_MAX_ATTEMPTS;
|
|
3841
|
-
// At most one install-then-retry per start: a second missing-module exit
|
|
3842
|
-
// after a fresh install means the install can't fix it.
|
|
3843
3073
|
let installRetried = false;
|
|
3844
3074
|
let lastDev;
|
|
3845
3075
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
3846
|
-
// Teardown can begin while a prior attempt waits for dependency
|
|
3847
|
-
// installation. Do not start more work against a removed worktree.
|
|
3848
3076
|
if (!canContinueStart())
|
|
3849
3077
|
return undefined;
|
|
3850
3078
|
let port;
|
|
@@ -3855,10 +3083,6 @@ class AgentVariantsOrchestrator {
|
|
|
3855
3083
|
if (!canContinueStart())
|
|
3856
3084
|
return undefined;
|
|
3857
3085
|
const proc = await this.worktrees.startDevServer(dev.cwd, port, dev.cmd, dev.args, dev.env);
|
|
3858
|
-
// The boot can outlive the session (a cancel during the readiness
|
|
3859
|
-
// wait, or during an auto-restart's delay). At this point the child
|
|
3860
|
-
// isn't on the record yet, so teardown's stop loop can't see it —
|
|
3861
|
-
// kill it here instead of leaking an orphaned dev server.
|
|
3862
3086
|
if (!canContinueStart()) {
|
|
3863
3087
|
log.info(`Variant ${args.workItemId} dev server booted after preview cleanup; stopping it`);
|
|
3864
3088
|
void this.worktrees.stopDevServer(proc).catch(() => undefined);
|
|
@@ -3870,16 +3094,6 @@ class AgentVariantsOrchestrator {
|
|
|
3870
3094
|
args.record.port = port;
|
|
3871
3095
|
args.record.devServerProcess = proc;
|
|
3872
3096
|
args.record.devCommand = dev;
|
|
3873
|
-
// If the dev server dies on its own (crash, OOM, Vite hard-fail),
|
|
3874
|
-
// clear the port so the iframe stops routing the chip onto a dead
|
|
3875
|
-
// socket, then bring a replacement up automatically. A ready server
|
|
3876
|
-
// that later crashes is almost always recoverable by a clean restart
|
|
3877
|
-
// (transient OOM, watcher crash, HMR wedge) — without one, every such
|
|
3878
|
-
// crash surfaced as a permanent "preview unavailable" plus a burst of
|
|
3879
|
-
// upstream_lost noise until the user regenerated the variant. The
|
|
3880
|
-
// restart budget keeps a genuinely broken build (crash loop) from
|
|
3881
|
-
// restarting forever. Intentional stops clear `devServerProcess`
|
|
3882
|
-
// before killing, so the guard below filters them out.
|
|
3883
3097
|
proc.once('exit', (code, signal) => {
|
|
3884
3098
|
if (args.record.devServerProcess !== proc)
|
|
3885
3099
|
return;
|
|
@@ -3898,8 +3112,6 @@ class AgentVariantsOrchestrator {
|
|
|
3898
3112
|
args.record.devServerAutoRestarts = restartsUsed + 1;
|
|
3899
3113
|
this.emitChange();
|
|
3900
3114
|
const timer = setTimeout(() => {
|
|
3901
|
-
// Re-check: the session may have been torn down while the
|
|
3902
|
-
// restart was pending — don't spawn into a cleaned-up worktree.
|
|
3903
3115
|
const current = this.resources.get(args.sessionId);
|
|
3904
3116
|
if (!current ||
|
|
3905
3117
|
current.cleanupStarted ||
|
|
@@ -3927,8 +3139,6 @@ class AgentVariantsOrchestrator {
|
|
|
3927
3139
|
});
|
|
3928
3140
|
this.emitChange();
|
|
3929
3141
|
});
|
|
3930
|
-
// A prior failure record (startup failure before a successful retry,
|
|
3931
|
-
// idle reclaim, crash before this restart) is now stale.
|
|
3932
3142
|
this.resources
|
|
3933
3143
|
.get(args.sessionId)
|
|
3934
3144
|
?.previewFailures.delete(args.workItemId);
|
|
@@ -3957,16 +3167,6 @@ class AgentVariantsOrchestrator {
|
|
|
3957
3167
|
const devErr = (0, devServerError_1.isDevServerStartError)(err) ? err : undefined;
|
|
3958
3168
|
const portInUse = devErr?.portInUse ?? false;
|
|
3959
3169
|
const reason = devErr?.reason ?? 'unknown';
|
|
3960
|
-
// Classify what a retry can actually fix:
|
|
3961
|
-
// - port_in_use: a fresh port fixes it (also step past unmatched
|
|
3962
|
-
// collision messages via the blanket exited retry below).
|
|
3963
|
-
// - missing/stale dependencies (module-resolution errors in the
|
|
3964
|
-
// output): an install fixes it — install, then retry once.
|
|
3965
|
-
// - any other early exit: retry once; exits fail fast, so one clean
|
|
3966
|
-
// attempt is cheap insurance against transient races (fs churn from
|
|
3967
|
-
// sibling provisioning, npm cache contention).
|
|
3968
|
-
// - timeout / spawn_error / missing_dev_script: deterministic; a
|
|
3969
|
-
// retry just doubles the wait, so fail with the actionable cause.
|
|
3970
3170
|
const missingDepsOutput = (0, devServerError_1.isMissingDependencyOutput)(devErr?.detail ?? '');
|
|
3971
3171
|
const missingDeps = missingDepsOutput &&
|
|
3972
3172
|
reason === 'exited' &&
|
|
@@ -3975,8 +3175,6 @@ class AgentVariantsOrchestrator {
|
|
|
3975
3175
|
canInstallWithoutTouchingHost(lastDev.cwd);
|
|
3976
3176
|
const willRetry = attempt < maxAttempts &&
|
|
3977
3177
|
(portInUse || missingDeps || (reason === 'exited' && attempt === 1));
|
|
3978
|
-
// Next attempt scans past the port we just tried so we don't re-pick a
|
|
3979
|
-
// port that's persistently held (vs. a transient race that freed it).
|
|
3980
3178
|
scanFrom = (port ?? scanFrom) + 1;
|
|
3981
3179
|
log.warn(`Failed to start dev server for variant ${args.workItemId} on port ${port ?? 'unallocated'} ` +
|
|
3982
3180
|
`(attempt ${attempt}/${maxAttempts}, reason=${reason}, portInUse=${portInUse}, missingDeps=${missingDeps})` +
|
|
@@ -4020,9 +3218,6 @@ class AgentVariantsOrchestrator {
|
|
|
4020
3218
|
}
|
|
4021
3219
|
continue;
|
|
4022
3220
|
}
|
|
4023
|
-
// Record the failure so getVariants can tell the UI this direction's
|
|
4024
|
-
// preview couldn't start (and why), then push a snapshot so the chip
|
|
4025
|
-
// updates from "loading" to the accurate per-direction message.
|
|
4026
3221
|
this.resources
|
|
4027
3222
|
.get(args.sessionId)
|
|
4028
3223
|
?.previewFailures.set(args.workItemId, {
|
|
@@ -4034,10 +3229,6 @@ class AgentVariantsOrchestrator {
|
|
|
4034
3229
|
errorCode = 'DEPENDENCY_INSTALL_FAILED';
|
|
4035
3230
|
if (reason === 'missing_dev_script')
|
|
4036
3231
|
errorCode = 'DEV_SCRIPT_MISSING';
|
|
4037
|
-
// Telemetry gets structured classification only — never the raw
|
|
4038
|
-
// output tail, which routinely carries absolute project paths and
|
|
4039
|
-
// source frames (see AGENTS.md "What NEVER to capture"). The full
|
|
4040
|
-
// tail still reaches the local logs via `err` above.
|
|
4041
3232
|
trackFreshDevServerFailed(this.telemetry, {
|
|
4042
3233
|
sessionId: args.sessionId,
|
|
4043
3234
|
variantId: args.workItemId,
|
|
@@ -4065,9 +3256,6 @@ class AgentVariantsOrchestrator {
|
|
|
4065
3256
|
return undefined;
|
|
4066
3257
|
}
|
|
4067
3258
|
finally {
|
|
4068
|
-
// Hand the reservation back whether the dev server bound the port
|
|
4069
|
-
// (now visible to the listener check, so the reservation is redundant),
|
|
4070
|
-
// it failed (port free again), or we're about to retry on the next port.
|
|
4071
3259
|
if (port !== undefined)
|
|
4072
3260
|
this.worktrees.releasePort?.(port);
|
|
4073
3261
|
}
|
|
@@ -4095,12 +3283,6 @@ class AgentVariantsOrchestrator {
|
|
|
4095
3283
|
assetBase: staticPreview.assetBase,
|
|
4096
3284
|
projectContext,
|
|
4097
3285
|
});
|
|
4098
|
-
// Materialize the variant into a per-variant directory so every
|
|
4099
|
-
// static variant is directory-backed (the same shape as the
|
|
4100
|
-
// worktree-based variants). Reuse the agent's assetBase dir when it
|
|
4101
|
-
// wrote sibling assets; otherwise create a Rivet-managed per-variant
|
|
4102
|
-
// dir under workspacePath. `staticPreview.html` is the complete built
|
|
4103
|
-
// document (html + css + js), written as index.html.
|
|
4104
3286
|
const workspacePath = projectContext.kind === 'fresh'
|
|
4105
3287
|
? projectContext.workspacePath
|
|
4106
3288
|
: undefined;
|
|
@@ -4123,16 +3305,10 @@ class AgentVariantsOrchestrator {
|
|
|
4123
3305
|
}
|
|
4124
3306
|
try {
|
|
4125
3307
|
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
4126
|
-
// Realpath the dir so it lines up with the realpath'd destination
|
|
4127
|
-
// the commit emptiness-check compares against (macOS symlinks
|
|
4128
|
-
// `/var` → `/private/var`). `resolveStaticPreviewAssetBase`
|
|
4129
|
-
// already realpaths the agent-provided case; do the same for the
|
|
4130
|
-
// Rivet-created dir.
|
|
4131
3308
|
try {
|
|
4132
3309
|
dir = fs_1.default.realpathSync(dir);
|
|
4133
3310
|
}
|
|
4134
3311
|
catch {
|
|
4135
|
-
// keep the un-realpath'd path if realpath fails
|
|
4136
3312
|
}
|
|
4137
3313
|
fs_1.default.writeFileSync(path_1.default.join(dir, 'index.html'), staticPreview.html, 'utf8');
|
|
4138
3314
|
}
|
|
@@ -4153,8 +3329,6 @@ class AgentVariantsOrchestrator {
|
|
|
4153
3329
|
resources.workspaceManager.removeArtifactWorkspace(workItemId);
|
|
4154
3330
|
}
|
|
4155
3331
|
if (this.store.getProjectContext(sessionId).kind === 'fresh') {
|
|
4156
|
-
// History at `<workspacePath>/.rivet/variants/<sessionId>/<variantId>/`
|
|
4157
|
-
// is the on-disk record for this generated project.
|
|
4158
3332
|
this.trackHistoryPersist(this.persistCompletedFreshVariant({
|
|
4159
3333
|
sessionId,
|
|
4160
3334
|
workItemId,
|
|
@@ -4185,8 +3359,6 @@ class AgentVariantsOrchestrator {
|
|
|
4185
3359
|
log.warn(`No worktree record for ${sessionId}/${workItemId}; skipping diff capture`);
|
|
4186
3360
|
return;
|
|
4187
3361
|
}
|
|
4188
|
-
// scaffold_base sets up the base for dependent code_gen items. No diff
|
|
4189
|
-
// to capture from it — its result is the disk state of the worktree.
|
|
4190
3362
|
if (resources.scaffoldBaseWorkItemId === workItemId) {
|
|
4191
3363
|
log.info(`scaffold_base ${workItemId} succeeded; awaiting dependent code-gen`);
|
|
4192
3364
|
return;
|
|
@@ -4202,14 +3374,6 @@ class AgentVariantsOrchestrator {
|
|
|
4202
3374
|
catch (err) {
|
|
4203
3375
|
log.warn(`getDiff failed for ${record.worktreePath}`, err);
|
|
4204
3376
|
}
|
|
4205
|
-
// History: persist every completed variant immediately to
|
|
4206
|
-
// `<projectPath>/.rivet/variants/`. Existing projects pass the captured
|
|
4207
|
-
// diff (or an empty string when capture itself failed — the variant
|
|
4208
|
-
// still succeeded code-gen-wise, and the history row is the only
|
|
4209
|
-
// record the UI has). Fresh-project variants copy their worktree
|
|
4210
|
-
// (vite_app) or the staged HTML (static_preview). Best-effort — a
|
|
4211
|
-
// failure here must never block dev-server startup or the user's pick
|
|
4212
|
-
// flow.
|
|
4213
3377
|
if (!isFresh) {
|
|
4214
3378
|
this.trackHistoryPersist(this.persistCompletedExistingVariant({
|
|
4215
3379
|
sessionId,
|
|
@@ -4227,19 +3391,8 @@ class AgentVariantsOrchestrator {
|
|
|
4227
3391
|
log.warn(`persistCompletedFreshVariant failed for ${sessionId}/${workItemId}`, err);
|
|
4228
3392
|
}));
|
|
4229
3393
|
}
|
|
4230
|
-
// Static existing-mode projects (framework='static', no dev command) have
|
|
4231
|
-
// no per-variant dev server to proxy the iframe at. Serve the variant's
|
|
4232
|
-
// materialized static files directly — the same renderer the chip/iframe
|
|
4233
|
-
// already uses for fresh static_preview variants — so the variant is
|
|
4234
|
-
// viewable/cyclable instead of being silently stuck on "Preview is
|
|
4235
|
-
// unavailable for this variant". When this succeeds there is no dev server
|
|
4236
|
-
// to bring up, so skip the proxy path below.
|
|
4237
3394
|
if (!isFresh) {
|
|
4238
3395
|
const staticPreview = await this.registerExistingStaticPreview(sessionId, workItemId, record);
|
|
4239
|
-
// Existing projects resolve their preview surface at success time (the
|
|
4240
|
-
// one genuinely-late axis of the run plan): a framework='static' project
|
|
4241
|
-
// materializes static files → static_artifact and needs no dev server;
|
|
4242
|
-
// anything else falls through to the dev-server proxy below.
|
|
4243
3396
|
if (staticPreview !== 'not_static') {
|
|
4244
3397
|
this.emitChange();
|
|
4245
3398
|
return;
|
|
@@ -4273,17 +3426,8 @@ class AgentVariantsOrchestrator {
|
|
|
4273
3426
|
assetBase: parsed.assetBase,
|
|
4274
3427
|
projectContext: this.store.getProjectContext(args.sessionId),
|
|
4275
3428
|
});
|
|
4276
|
-
// A refinement that only rewrites HTML won't re-declare an assetBase, but
|
|
4277
|
-
// the refined markup can still reference the original sibling assets
|
|
4278
|
-
// (images, GLB, fonts). Fall back to the variant's existing asset base so
|
|
4279
|
-
// those relative URLs keep resolving instead of 404ing after the swap.
|
|
4280
3429
|
const previousRecord = resources.staticPreviews.get(input.variantId);
|
|
4281
3430
|
const dir = resolvedAssetBase ?? previousRecord?.assetBase;
|
|
4282
|
-
// Re-materialize index.html in the per-variant dir FIRST. The directory is
|
|
4283
|
-
// the source of truth (`getStaticPreviewHtml` reads it disk-first), so the
|
|
4284
|
-
// write must succeed before we swap any in-memory / stored-output state to
|
|
4285
|
-
// the refined HTML. If it fails we throw — converting to a `failed` report
|
|
4286
|
-
// rather than a success that still serves the pre-refine document on disk.
|
|
4287
3431
|
if (dir) {
|
|
4288
3432
|
try {
|
|
4289
3433
|
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
@@ -4293,9 +3437,6 @@ class AgentVariantsOrchestrator {
|
|
|
4293
3437
|
throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `Failed to materialize refined static preview for ${input.variantId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
4294
3438
|
}
|
|
4295
3439
|
}
|
|
4296
|
-
// Swap the served preview to the refined HTML. Runs before
|
|
4297
|
-
// store.reportComplete so any failure above converts to a `failed` report
|
|
4298
|
-
// rather than a success pointing at unrefreshed output.
|
|
4299
3440
|
this.store.replaceWorkItemOutput(args.sessionId, input.variantId, {
|
|
4300
3441
|
...parsed,
|
|
4301
3442
|
...(dir ? { assetBase: dir } : {}),
|
|
@@ -4317,10 +3458,6 @@ class AgentVariantsOrchestrator {
|
|
|
4317
3458
|
targetWorkItemId: input.variantId,
|
|
4318
3459
|
});
|
|
4319
3460
|
}
|
|
4320
|
-
// History persistence is best-effort, mirroring handleSucceededReport's
|
|
4321
|
-
// fire-and-forget persistence for freshly completed variants. A failure
|
|
4322
|
-
// here (e.g. a transient filesystem race) must not fail the refinement or
|
|
4323
|
-
// discard the already-serving refined HTML.
|
|
4324
3461
|
try {
|
|
4325
3462
|
await this.persistCompletedFreshVariant({
|
|
4326
3463
|
sessionId: args.sessionId,
|
|
@@ -4330,22 +3467,10 @@ class AgentVariantsOrchestrator {
|
|
|
4330
3467
|
catch (err) {
|
|
4331
3468
|
log.warn(`persistCompletedFreshVariant failed for refined variant ${input.variantId} (session ${args.sessionId}); preview already swapped`, err);
|
|
4332
3469
|
}
|
|
4333
|
-
// The caller (reportComplete) emits the change after recording success so
|
|
4334
|
-
// the snapshot reflects both the swapped HTML and refinement.status.
|
|
4335
3470
|
}
|
|
4336
|
-
/** The worktree/dev-server manager this orchestrator boots previews with.
|
|
4337
|
-
* Exposed so HistoryReplayService shares the SAME instance: the
|
|
4338
|
-
* reserved-but-not-yet-bound port set is per-instance, and a second
|
|
4339
|
-
* manager scanning the same range can hand a live variant's pending port
|
|
4340
|
-
* to a replay (EADDRINUSE for the loser). */
|
|
4341
3471
|
get devServerManager() {
|
|
4342
3472
|
return this.worktrees;
|
|
4343
3473
|
}
|
|
4344
|
-
/** In-flight fire-and-forget history persists. Tree-store snapshots spawn
|
|
4345
|
-
* git subprocesses, so these can outlive the microtask flushes that used
|
|
4346
|
-
* to be enough to drain them — {@link teardownSession} (and the test
|
|
4347
|
-
* helpers' settleBackgroundWork) await {@link settleHistoryPersists}
|
|
4348
|
-
* instead of racing the writes. */
|
|
4349
3474
|
pendingHistoryPersists = new Set();
|
|
4350
3475
|
trackHistoryPersist(persist) {
|
|
4351
3476
|
this.pendingHistoryPersists.add(persist);
|
|
@@ -4355,20 +3480,11 @@ class AgentVariantsOrchestrator {
|
|
|
4355
3480
|
this.pendingHistoryPersists.delete(persist);
|
|
4356
3481
|
});
|
|
4357
3482
|
}
|
|
4358
|
-
/** Await every in-flight history persist, including ones that start while
|
|
4359
|
-
* draining (a refine can persist mid-settle). */
|
|
4360
3483
|
async settleHistoryPersists() {
|
|
4361
3484
|
while (this.pendingHistoryPersists.size > 0) {
|
|
4362
3485
|
await Promise.allSettled([...this.pendingHistoryPersists]);
|
|
4363
3486
|
}
|
|
4364
3487
|
}
|
|
4365
|
-
/**
|
|
4366
|
-
* Persist a completed existing-project code_gen variant into
|
|
4367
|
-
* `<env.projectPath>/.rivet/variants/<sessionId>/<variantId>/`. Called from
|
|
4368
|
-
* `handleSucceededReport` once the worktree diff has been captured but
|
|
4369
|
-
* before the user picks. Status is `completed` until `commitVariant` or a
|
|
4370
|
-
* cancellation transitions it.
|
|
4371
|
-
*/
|
|
4372
3488
|
async persistCompletedExistingVariant(args) {
|
|
4373
3489
|
const projectContext = this.store.getProjectContext(args.sessionId);
|
|
4374
3490
|
if (projectContext.kind !== 'existing')
|
|
@@ -4396,13 +3512,7 @@ class AgentVariantsOrchestrator {
|
|
|
4396
3512
|
}
|
|
4397
3513
|
const input = this.store.getWorkItemInput(args.sessionId, args.workItemId);
|
|
4398
3514
|
const sessionPrompt = this.store.getPrompt(args.sessionId);
|
|
4399
|
-
// Tree-store snapshot inputs (dual-write). The snapshot root is the
|
|
4400
|
-
// worktree root — the git root, per the tree-root contract — for EVERY
|
|
4401
|
-
// framework, not just static: this is what makes dev-server (Vite /
|
|
4402
|
-
// fullstack) variants replayable from history instead of diff-only.
|
|
4403
3515
|
const snapshotDir = record?.worktreePath;
|
|
4404
|
-
// Lazy per-session base snapshot from the host repo root. Best-effort:
|
|
4405
|
-
// resolution failure just means no base ref (variant commits still land).
|
|
4406
3516
|
let baseDir;
|
|
4407
3517
|
try {
|
|
4408
3518
|
baseDir = await this.worktrees.getGitRoot?.();
|
|
@@ -4412,9 +3522,6 @@ class AgentVariantsOrchestrator {
|
|
|
4412
3522
|
}
|
|
4413
3523
|
let serve;
|
|
4414
3524
|
if (sourceDir && record && staticEntryPath) {
|
|
4415
|
-
// Static framework: entryPath is relative to the snapshot root (the
|
|
4416
|
-
// worktree root), pointing into the nested project dir when the
|
|
4417
|
-
// project lives below the git root.
|
|
4418
3525
|
const entryPath = path_1.default.relative(record.worktreePath, path_1.default.join(sourceDir, staticEntryPath));
|
|
4419
3526
|
serve = { kind: 'static', entryPath };
|
|
4420
3527
|
}
|
|
@@ -4425,12 +3532,6 @@ class AgentVariantsOrchestrator {
|
|
|
4425
3532
|
};
|
|
4426
3533
|
}
|
|
4427
3534
|
else if (record) {
|
|
4428
|
-
// Persist fires at code-gen success, BEFORE the dev server boots (the
|
|
4429
|
-
// boot is what stashes record.devCommand/port) — so for the common
|
|
4430
|
-
// path the live invocation isn't available yet. Run the same
|
|
4431
|
-
// deterministic resolution the boot will use, against a sentinel port
|
|
4432
|
-
// that becomes the ${PORT} placeholder. No dependency install here —
|
|
4433
|
-
// resolveDevServerCommand is the side-effect-free half of the split.
|
|
4434
3535
|
try {
|
|
4435
3536
|
const dev = await this.resolveDevServerCommand(args.sessionId, record.worktreePath, RECIPE_PORT_SENTINEL, false);
|
|
4436
3537
|
serve = {
|
|
@@ -4470,22 +3571,6 @@ class AgentVariantsOrchestrator {
|
|
|
4470
3571
|
: {}),
|
|
4471
3572
|
});
|
|
4472
3573
|
}
|
|
4473
|
-
/**
|
|
4474
|
-
* Existing-mode `framework: 'static'` projects have no dev command, so there
|
|
4475
|
-
* is no per-variant dev server for the iframe to proxy. Register the variant's
|
|
4476
|
-
* materialized static site as a {@link StaticPreviewRecord} so the existing
|
|
4477
|
-
* static-file plumbing — the `/api/variants/:sid/static/:vid[/asset]` routes,
|
|
4478
|
-
* {@link getStaticPreviewHtml}, and {@link getVariants} (preview.kind=
|
|
4479
|
-
* 'static_artifact', view enabled) — all light up exactly as they do for
|
|
4480
|
-
* fresh `static_preview` variants. The entry HTML and its sibling assets are
|
|
4481
|
-
* served straight from the variant's worktree project root (session-scoped,
|
|
4482
|
-
* pre-commit; the persisted `.rivet/variants/.../files/` copy backs the
|
|
4483
|
-
* post-session history route separately).
|
|
4484
|
-
*
|
|
4485
|
-
* Returns `registered` when the static preview is ready, `unavailable` when
|
|
4486
|
-
* the project is static but its selected entry cannot be served, and
|
|
4487
|
-
* `not_static` when the caller should start a dev server instead.
|
|
4488
|
-
*/
|
|
4489
3574
|
async registerExistingStaticPreview(sessionId, workItemId, record) {
|
|
4490
3575
|
let env;
|
|
4491
3576
|
try {
|
|
@@ -4518,9 +3603,6 @@ class AgentVariantsOrchestrator {
|
|
|
4518
3603
|
log.warn(`registerExistingStaticPreview: project cwd failed for ${sessionId}/${workItemId}`, err);
|
|
4519
3604
|
return 'unavailable';
|
|
4520
3605
|
}
|
|
4521
|
-
// The materialized worktree IS the per-variant directory. Require its
|
|
4522
|
-
// selected entry to exist; the directory is then served directly (no
|
|
4523
|
-
// in-memory HTML copy — getStaticPreviewHtml reads it from here).
|
|
4524
3606
|
const entryFile = path_1.default.join(projectCwd, env.entryPath);
|
|
4525
3607
|
try {
|
|
4526
3608
|
await fs_1.default.promises.access(entryFile, fs_1.default.constants.R_OK);
|
|
@@ -4542,41 +3624,26 @@ class AgentVariantsOrchestrator {
|
|
|
4542
3624
|
});
|
|
4543
3625
|
return 'unavailable';
|
|
4544
3626
|
}
|
|
4545
|
-
// The dir must be realpath'd so resolveStaticPreviewAssetPath's sandbox
|
|
4546
|
-
// comparison lines up; sibling assets (css/js/images) then resolve from the
|
|
4547
|
-
// same static root the entry HTML lives in.
|
|
4548
3627
|
let dir;
|
|
4549
3628
|
try {
|
|
4550
3629
|
dir = fs_1.default.realpathSync(projectCwd);
|
|
4551
3630
|
}
|
|
4552
3631
|
catch {
|
|
4553
|
-
// Fall back to the un-realpath'd cwd; serving still works, only the
|
|
4554
|
-
// sandbox symlink-normalization is skipped.
|
|
4555
3632
|
dir = projectCwd;
|
|
4556
3633
|
}
|
|
4557
|
-
// Host project root, used as a read-only fallback for assets the worktree
|
|
4558
|
-
// clone is missing (git-ignored or binary files that `git worktree add` +
|
|
4559
|
-
// text-patch + untracked-copy can't carry). Without this the original
|
|
4560
|
-
// preview shows such an asset while the variant 404s. Realpath'd so the
|
|
4561
|
-
// sandbox containment check in `resolveAssetWithinBase` lines up.
|
|
4562
3634
|
let assetFallbackBase;
|
|
4563
3635
|
try {
|
|
4564
3636
|
const hostRealRoot = fs_1.default.realpathSync(env.projectPath);
|
|
4565
|
-
// Skip the fallback if it would collapse onto the worktree root (can't
|
|
4566
|
-
// happen in practice, but keeps the two roots genuinely distinct).
|
|
4567
3637
|
if (hostRealRoot !== dir)
|
|
4568
3638
|
assetFallbackBase = hostRealRoot;
|
|
4569
3639
|
}
|
|
4570
3640
|
catch {
|
|
4571
|
-
// No host root resolvable — serve worktree assets only.
|
|
4572
3641
|
}
|
|
4573
3642
|
resources.staticPreviews.set(workItemId, {
|
|
4574
3643
|
workItemId,
|
|
4575
3644
|
briefId: input.briefId,
|
|
4576
3645
|
entryPath: env.entryPath,
|
|
4577
3646
|
assetBase: dir,
|
|
4578
|
-
// Existing-mode static projects are real multi-file sites — assume
|
|
4579
|
-
// sibling assets so the preview route resolves relative URLs.
|
|
4580
3647
|
hasAssets: true,
|
|
4581
3648
|
...(assetFallbackBase ? { assetFallbackBase } : {}),
|
|
4582
3649
|
});
|
|
@@ -4592,25 +3659,10 @@ class AgentVariantsOrchestrator {
|
|
|
4592
3659
|
});
|
|
4593
3660
|
return 'registered';
|
|
4594
3661
|
}
|
|
4595
|
-
/**
|
|
4596
|
-
* Persist a completed fresh-project variant into
|
|
4597
|
-
* `<projectContext.workspacePath>/.rivet/variants/<sessionId>/<variantId>/`.
|
|
4598
|
-
* Called from `handleSucceededReport` right after the per-variant snapshot
|
|
4599
|
-
* lands on disk — for static_preview that's the `.rivet/<slug>/` snapshot
|
|
4600
|
-
* dir; for vite_app fresh variants it's the worktree itself. Status starts
|
|
4601
|
-
* as 'completed' and transitions to 'committed' / 'rejected' / 'cancelled'
|
|
4602
|
-
* via `markStatus` at commit or teardown time.
|
|
4603
|
-
*
|
|
4604
|
-
* Running at success time (rather than commit time) means the history panel
|
|
4605
|
-
* populates live as variants generate — including when the user never picks
|
|
4606
|
-
* one. Mirrors the existing-project persistCompletedExistingVariant flow.
|
|
4607
|
-
*/
|
|
4608
3662
|
async persistCompletedFreshVariant(args) {
|
|
4609
3663
|
const projectContext = this.store.getProjectContext(args.sessionId);
|
|
4610
3664
|
if (projectContext.kind !== 'fresh')
|
|
4611
3665
|
return;
|
|
4612
|
-
// Variant history lives in the generated project folder so reopening that
|
|
4613
|
-
// folder gives the history panel the same owner path that wrote it.
|
|
4614
3666
|
const historyProjectPath = projectContext.workspacePath;
|
|
4615
3667
|
const input = this.store.getWorkItemInput(args.sessionId, args.workItemId);
|
|
4616
3668
|
const sessionPrompt = this.store.getPrompt(args.sessionId);
|
|
@@ -4618,11 +3670,6 @@ class AgentVariantsOrchestrator {
|
|
|
4618
3670
|
const resources = this.resources.get(args.sessionId);
|
|
4619
3671
|
const worktreeRecord = resources?.worktrees.get(args.workItemId);
|
|
4620
3672
|
const staticPreview = resources?.staticPreviews.get(args.workItemId);
|
|
4621
|
-
// Vite_app deliverables are full scaffolded worktrees — pass the worktree
|
|
4622
|
-
// directory as sourceDir and let copyDirFiltered handle it (excludes
|
|
4623
|
-
// node_modules, .rivet, etc). Static_preview deliverables are inline HTML
|
|
4624
|
-
// captured in `resources.staticPreviews`; stage them in a tmp dir so the
|
|
4625
|
-
// existing copy path works without poking the user's workspace.
|
|
4626
3673
|
let sourceDir = null;
|
|
4627
3674
|
let tmpStagingDir = null;
|
|
4628
3675
|
if (worktreeRecord && fs_1.default.existsSync(worktreeRecord.worktreePath)) {
|
|
@@ -4631,7 +3678,6 @@ class AgentVariantsOrchestrator {
|
|
|
4631
3678
|
else if (staticPreview) {
|
|
4632
3679
|
tmpStagingDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), `rivet-variant-${args.workItemId}-`));
|
|
4633
3680
|
copyStaticPreviewDirectory(staticPreview.assetBase, tmpStagingDir);
|
|
4634
|
-
// Read the materialized index.html from the variant's per-variant dir.
|
|
4635
3681
|
let stagedHtml = '';
|
|
4636
3682
|
try {
|
|
4637
3683
|
stagedHtml = fs_1.default.readFileSync(path_1.default.join(staticPreview.assetBase, 'index.html'), 'utf8');
|
|
@@ -4647,10 +3693,6 @@ class AgentVariantsOrchestrator {
|
|
|
4647
3693
|
log.warn(`persistCompletedFreshVariant: no source for ${args.workItemId} (session ${args.sessionId}); skipping`);
|
|
4648
3694
|
return;
|
|
4649
3695
|
}
|
|
4650
|
-
// For static_preview, only `index.html` is a real deliverable — `brief.md`
|
|
4651
|
-
// is implementation-detail staging that we copy alongside it. Hardcode
|
|
4652
|
-
// the count so the history row matches what `commit_variant` reports
|
|
4653
|
-
// (always 1) instead of double-counting the brief.
|
|
4654
3696
|
const changedFilesCount = staticPreview ? 1 : countWorktreeFiles(sourceDir);
|
|
4655
3697
|
const preview = staticPreview
|
|
4656
3698
|
? { kind: 'static', entryPath: 'index.html' }
|
|
@@ -4662,12 +3704,6 @@ class AgentVariantsOrchestrator {
|
|
|
4662
3704
|
script: 'dev',
|
|
4663
3705
|
},
|
|
4664
3706
|
};
|
|
4665
|
-
// Tree-store serve contract. Fresh worktrees prefer the live record's
|
|
4666
|
-
// resolved invocation (stashed at dev-server start); the fallback recipe
|
|
4667
|
-
// mirrors resolveDevServer's fresh branch, which is fully deterministic
|
|
4668
|
-
// for the Vite template. Static previews serve their staged index.html.
|
|
4669
|
-
// Fresh sessions have no host project, so there is no base snapshot —
|
|
4670
|
-
// variant commits are root commits.
|
|
4671
3707
|
const serve = staticPreview
|
|
4672
3708
|
? { kind: 'static', entryPath: 'index.html' }
|
|
4673
3709
|
: worktreeRecord?.devCommand && worktreeRecord.port !== undefined
|
|
@@ -4730,10 +3766,6 @@ class AgentVariantsOrchestrator {
|
|
|
4730
3766
|
}
|
|
4731
3767
|
}
|
|
4732
3768
|
}
|
|
4733
|
-
/**
|
|
4734
|
-
* @effect Drains fresh-project history writes before commit moves or rewrites
|
|
4735
|
-
* the generated project folder.
|
|
4736
|
-
*/
|
|
4737
3769
|
async persistCompletedFreshVariantsForCommit(sessionId) {
|
|
4738
3770
|
const projectContext = this.store.getProjectContext(sessionId);
|
|
4739
3771
|
if (projectContext.kind !== 'fresh')
|
|
@@ -4753,14 +3785,6 @@ class AgentVariantsOrchestrator {
|
|
|
4753
3785
|
}
|
|
4754
3786
|
}
|
|
4755
3787
|
}
|
|
4756
|
-
/**
|
|
4757
|
-
* At commit time, flip persisted variant manifests to terminal statuses
|
|
4758
|
-
* ('committed' for the chosen, 'rejected' for the rest). Both existing- and
|
|
4759
|
-
* fresh-project variants have already been persisted at code_gen success
|
|
4760
|
-
* time, so this is a pure status update — no source-dir copy required.
|
|
4761
|
-
* Also records the destination path on the chosen variant so history can
|
|
4762
|
-
* surface "this variant became <path>".
|
|
4763
|
-
*/
|
|
4764
3788
|
async persistVariantHistoryAtCommit(args) {
|
|
4765
3789
|
const variants = this.store.getVariants(args.sessionId);
|
|
4766
3790
|
for (const variant of variants) {
|
|
@@ -4781,13 +3805,6 @@ class AgentVariantsOrchestrator {
|
|
|
4781
3805
|
});
|
|
4782
3806
|
}
|
|
4783
3807
|
}
|
|
4784
|
-
/**
|
|
4785
|
-
* Flip persisted variant manifests to status='cancelled' for every variant
|
|
4786
|
-
* in the session that was already snapshotted to disk. Fresh- and existing-
|
|
4787
|
-
* project variants both persist at success time now, so both need their
|
|
4788
|
-
* manifests flipped here. Best-effort — missing manifests are silently
|
|
4789
|
-
* skipped by VariantHistoryService.markStatus.
|
|
4790
|
-
*/
|
|
4791
3808
|
async markPersistedVariantsCancelled(sessionId) {
|
|
4792
3809
|
if (!this.store.hasSession(sessionId))
|
|
4793
3810
|
return;
|
|
@@ -4823,9 +3840,6 @@ class AgentVariantsOrchestrator {
|
|
|
4823
3840
|
const projectPath = await this.resolveHistoryProjectPath(sessionId);
|
|
4824
3841
|
if (!projectPath)
|
|
4825
3842
|
return;
|
|
4826
|
-
// No-ops (ENOENT) when the variant was never persisted — e.g. removing a
|
|
4827
|
-
// still-pending variant that produced no artifact. Completed variants have
|
|
4828
|
-
// a manifest, which flips to `removed` and is retained on disk.
|
|
4829
3843
|
await this.variantHistory.markStatus({
|
|
4830
3844
|
projectPath,
|
|
4831
3845
|
sessionId,
|
|
@@ -4839,9 +3853,6 @@ class AgentVariantsOrchestrator {
|
|
|
4839
3853
|
const projectPath = await this.resolveHistoryProjectPath(sessionId);
|
|
4840
3854
|
if (!projectPath)
|
|
4841
3855
|
return;
|
|
4842
|
-
// No-ops (ENOENT) when the variant has no manifest yet — e.g. renaming a
|
|
4843
|
-
// still-generating direction before its artifact lands. The in-memory
|
|
4844
|
-
// label still updates; the disk copy catches up when the variant persists.
|
|
4845
3856
|
await this.variantHistory.renameVariant({
|
|
4846
3857
|
projectPath,
|
|
4847
3858
|
sessionId,
|
|
@@ -4850,11 +3861,6 @@ class AgentVariantsOrchestrator {
|
|
|
4850
3861
|
runLabel,
|
|
4851
3862
|
});
|
|
4852
3863
|
}
|
|
4853
|
-
/**
|
|
4854
|
-
* Resolve the project path that owns `.rivet/variants/` for a session.
|
|
4855
|
-
* Existing sessions use the user's project. Fresh sessions use the generated
|
|
4856
|
-
* project folder. Must match what `persistCompletedFreshVariant` writes to.
|
|
4857
|
-
*/
|
|
4858
3864
|
async resolveHistoryProjectPath(sessionId) {
|
|
4859
3865
|
const projectContext = this.store.getProjectContext(sessionId);
|
|
4860
3866
|
if (projectContext.kind === 'fresh') {
|
|
@@ -4881,13 +3887,6 @@ class AgentVariantsOrchestrator {
|
|
|
4881
3887
|
return undefined;
|
|
4882
3888
|
}
|
|
4883
3889
|
}
|
|
4884
|
-
/**
|
|
4885
|
-
* The port to start scanning from when allocating a variant's preview dev
|
|
4886
|
-
* server. Fresh worktrees run the Vite template (5173); existing projects use
|
|
4887
|
-
* their detected framework's default (3000 for Next, etc.), falling back to
|
|
4888
|
-
* 3000 if detection fails. Scanning upward from here lands the preview on a
|
|
4889
|
-
* sensible, predictable port near the project's normal one.
|
|
4890
|
-
*/
|
|
4891
3890
|
async resolveDevServerStartPort(sessionId, isFresh) {
|
|
4892
3891
|
if (isFresh)
|
|
4893
3892
|
return FRESH_DEV_SERVER_DEFAULT_PORT;
|
|
@@ -4899,11 +3898,6 @@ class AgentVariantsOrchestrator {
|
|
|
4899
3898
|
return 3000;
|
|
4900
3899
|
}
|
|
4901
3900
|
}
|
|
4902
|
-
/**
|
|
4903
|
-
* Resolve dev server invocation for a worktree. Fresh-project worktrees
|
|
4904
|
-
* always use the Vite template's npm command at the worktree root; existing
|
|
4905
|
-
* projects defer to the user's framework/packageManager config.
|
|
4906
|
-
*/
|
|
4907
3901
|
async resolveDevServer(sessionId, worktreePath, port, isFresh) {
|
|
4908
3902
|
const resolved = await this.resolveDevServerCommand(sessionId, worktreePath, port, isFresh);
|
|
4909
3903
|
await this.ensureProjectDependencies({
|
|
@@ -4913,13 +3907,6 @@ class AgentVariantsOrchestrator {
|
|
|
4913
3907
|
});
|
|
4914
3908
|
return resolved;
|
|
4915
3909
|
}
|
|
4916
|
-
/**
|
|
4917
|
-
* Pure invocation resolution — no dependency installs, no side effects.
|
|
4918
|
-
* Split from {@link resolveDevServer} so history persistence can capture
|
|
4919
|
-
* the SAME deterministic resolution the boot path uses without booting:
|
|
4920
|
-
* persist fires at code-gen success, before the dev server starts, so the
|
|
4921
|
-
* live record's stashed command usually isn't available yet.
|
|
4922
|
-
*/
|
|
4923
3910
|
async resolveDevServerCommand(sessionId, worktreePath, port, isFresh) {
|
|
4924
3911
|
if (isFresh) {
|
|
4925
3912
|
return {
|
|
@@ -4943,9 +3930,6 @@ class AgentVariantsOrchestrator {
|
|
|
4943
3930
|
throw new Error('Static projects do not have a dev server command');
|
|
4944
3931
|
}
|
|
4945
3932
|
const cwd = await this.resolveExistingProjectCwd(sessionId, worktreePath, env);
|
|
4946
|
-
// Every branch below — including the production buildDevCommand recipes
|
|
4947
|
-
// from utils/devServerCommand.ts — invokes the package.json script named
|
|
4948
|
-
// by env.devCommand, so the preflight applies to all of them.
|
|
4949
3933
|
if (env.devCommand) {
|
|
4950
3934
|
assertDevScriptExists(cwd, env.devCommand);
|
|
4951
3935
|
}
|
|
@@ -4981,7 +3965,6 @@ class AgentVariantsOrchestrator {
|
|
|
4981
3965
|
packageManager,
|
|
4982
3966
|
};
|
|
4983
3967
|
}
|
|
4984
|
-
/** Prepares the direction's declared dependencies before each server start. */
|
|
4985
3968
|
async ensureProjectDependencies(args) {
|
|
4986
3969
|
if (!fs_1.default.existsSync(path_1.default.join(args.cwd, 'package.json')))
|
|
4987
3970
|
return;
|
|
@@ -4990,13 +3973,6 @@ class AgentVariantsOrchestrator {
|
|
|
4990
3973
|
signal: args.signal,
|
|
4991
3974
|
});
|
|
4992
3975
|
}
|
|
4993
|
-
/**
|
|
4994
|
-
* Resolve the dev-server working directory for an existing-project variant.
|
|
4995
|
-
* WorktreeManager is constructed around the editor/root project, but
|
|
4996
|
-
* `start_variants` can target a nested app (for example `examples/blog`).
|
|
4997
|
-
* In that case the worktree root is still the git root clone, while the dev
|
|
4998
|
-
* server must run from the nested project path.
|
|
4999
|
-
*/
|
|
5000
3976
|
async resolveExistingProjectCwd(sessionId, worktreePath, env) {
|
|
5001
3977
|
const fallback = await this.worktrees.getProjectCwdInWorktree(worktreePath);
|
|
5002
3978
|
try {
|
|
@@ -5014,16 +3990,6 @@ class AgentVariantsOrchestrator {
|
|
|
5014
3990
|
return fallback;
|
|
5015
3991
|
}
|
|
5016
3992
|
}
|
|
5017
|
-
/**
|
|
5018
|
-
* After the chosen variant has been renamed into `destinationPath`, move
|
|
5019
|
-
* each unchosen sibling worktree into a `<destinationParent>/<slug>-variants/NN-<label>/`
|
|
5020
|
-
* folder with its own prepared dependency installation. Writes a manifest documenting all 5 variants (the chosen
|
|
5021
|
-
* one with `folder: null` and `chosenPath: '../<slug>'`).
|
|
5022
|
-
*
|
|
5023
|
-
* Sets `vitePreservedSiblings = true` on session resources so the
|
|
5024
|
-
* subsequent teardown skips `cleanupFreshWorktrees` (which would otherwise
|
|
5025
|
-
* delete the just-preserved history). Dev servers still get stopped.
|
|
5026
|
-
*/
|
|
5027
3993
|
preserveUnchosenVariants(args) {
|
|
5028
3994
|
const resources = this.resources.get(args.sessionId);
|
|
5029
3995
|
const runnablePaths = new Map();
|
|
@@ -5059,8 +4025,6 @@ class AgentVariantsOrchestrator {
|
|
|
5059
4025
|
}
|
|
5060
4026
|
const record = resources.worktrees.get(variant.workItemId);
|
|
5061
4027
|
if (!record) {
|
|
5062
|
-
// No worktree (e.g. failed variant) — still list it in manifest with
|
|
5063
|
-
// null folder so the user can see why it's absent.
|
|
5064
4028
|
manifestEntries.push({
|
|
5065
4029
|
variantId: variant.workItemId,
|
|
5066
4030
|
label,
|
|
@@ -5089,8 +4053,6 @@ class AgentVariantsOrchestrator {
|
|
|
5089
4053
|
fs_1.default.renameSync(record.worktreePath, dest);
|
|
5090
4054
|
return dest;
|
|
5091
4055
|
})();
|
|
5092
|
-
// Update the in-memory record so teardown doesn't try to operate on
|
|
5093
|
-
// the stale path.
|
|
5094
4056
|
record.worktreePath = newPath;
|
|
5095
4057
|
runnablePaths.set(variant.workItemId, `${path_1.default.basename(historyDir)}/${folderName}`);
|
|
5096
4058
|
manifestEntries.push({
|
|
@@ -5129,22 +4091,7 @@ class AgentVariantsOrchestrator {
|
|
|
5129
4091
|
resources.vitePreservedSiblings = true;
|
|
5130
4092
|
return runnablePaths;
|
|
5131
4093
|
}
|
|
5132
|
-
/**
|
|
5133
|
-
* Rename `sourceWorktreePath` into `destinationPath`, then replace the
|
|
5134
|
-
* worktree's `.git` with a fresh-history init + initial commit. Matches
|
|
5135
|
-
* the historical materializeProject behavior of "user sees a fresh repo
|
|
5136
|
-
* at destinationPath" so we don't surprise them with a `rivet: variant
|
|
5137
|
-
* baseline` commit they didn't intend.
|
|
5138
|
-
*
|
|
5139
|
-
* The rename is the load-bearing operation: it moves the entire variant
|
|
5140
|
-
* tree (template files + materialized node_modules) in O(1) when the
|
|
5141
|
-
* source and destination share a volume. The git reset that follows is
|
|
5142
|
-
* best-effort housekeeping; a failure there leaves files in place.
|
|
5143
|
-
*/
|
|
5144
4094
|
async renameWorktreeIntoDestination(sourceWorktreePath, destinationPath) {
|
|
5145
|
-
// destinationPath must not exist for fs.rename to behave as a move.
|
|
5146
|
-
// assertDestinationAvailable already enforced that any existing directory
|
|
5147
|
-
// contains only `.rivet`, which we preserve across the move.
|
|
5148
4095
|
const destinationParent = path_1.default.dirname(destinationPath);
|
|
5149
4096
|
await fs_1.default.promises.mkdir(destinationParent, { recursive: true });
|
|
5150
4097
|
let preservedRivetParent;
|
|
@@ -5191,15 +4138,11 @@ class AgentVariantsOrchestrator {
|
|
|
5191
4138
|
force: true,
|
|
5192
4139
|
});
|
|
5193
4140
|
}
|
|
5194
|
-
// Replace the variant-baseline git history with a fresh init so the
|
|
5195
|
-
// user doesn't inherit a `rivet: variant baseline` commit.
|
|
5196
4141
|
const dotGit = path_1.default.join(destinationPath, '.git');
|
|
5197
4142
|
try {
|
|
5198
4143
|
fs_1.default.rmSync(dotGit, { recursive: true, force: true });
|
|
5199
4144
|
}
|
|
5200
4145
|
catch {
|
|
5201
|
-
// Best-effort — leaving the baseline .git is preferable to failing
|
|
5202
|
-
// the commit after we've moved the tree.
|
|
5203
4146
|
}
|
|
5204
4147
|
try {
|
|
5205
4148
|
const git = (0, simple_git_1.simpleGit)(destinationPath);
|
|
@@ -5217,22 +4160,12 @@ class AgentVariantsOrchestrator {
|
|
|
5217
4160
|
'Initial commit (created with Rivet)',
|
|
5218
4161
|
])
|
|
5219
4162
|
.catch(() => {
|
|
5220
|
-
// Best-effort: missing user identity or empty tree leaves the
|
|
5221
|
-
// commit step un-applied. Files are still in place.
|
|
5222
4163
|
});
|
|
5223
4164
|
}
|
|
5224
4165
|
catch (err) {
|
|
5225
4166
|
log.warn(`Initial git history setup at ${destinationPath} failed`, err);
|
|
5226
4167
|
}
|
|
5227
4168
|
}
|
|
5228
|
-
/**
|
|
5229
|
-
* Stop every variant dev server currently running for `resources`. Clears
|
|
5230
|
-
* the `devServerProcess` / `port` fields on each record so subsequent
|
|
5231
|
-
* teardown logic doesn't try to stop them a second time. Called from
|
|
5232
|
-
* `commitVariant` (vite_app rename path) BEFORE the worktree directory is
|
|
5233
|
-
* renamed — leaving Vite alive across the rename leaks empty `.vite/`
|
|
5234
|
-
* stub dirs at the old paths.
|
|
5235
|
-
*/
|
|
5236
4169
|
async stopAllDevServersForSession(resources) {
|
|
5237
4170
|
this.clearActivePreviewIdleTimer(resources);
|
|
5238
4171
|
const stops = [];
|
|
@@ -5271,7 +4204,6 @@ class AgentVariantsOrchestrator {
|
|
|
5271
4204
|
clearTimeout(resources.activePreviewIdleTimer);
|
|
5272
4205
|
resources.activePreviewIdleTimer = undefined;
|
|
5273
4206
|
}
|
|
5274
|
-
/** @effect Stops idle variant child processes and clears dead preview ports. */
|
|
5275
4207
|
async stopIdleVariantDevServers(sessionId) {
|
|
5276
4208
|
const resources = this.resources.get(sessionId);
|
|
5277
4209
|
if (!resources || resources.cleanupStarted)
|
|
@@ -5300,8 +4232,6 @@ class AgentVariantsOrchestrator {
|
|
|
5300
4232
|
}
|
|
5301
4233
|
log.info(`Reclaimed ${expiringWorkItemIds.length} idle variant preview(s) for session ${sessionId} ` +
|
|
5302
4234
|
`(${stoppedCount} running, ${pendingRestartCount} restarting)`);
|
|
5303
|
-
// The next selection restores only the requested Rivet-owned preview;
|
|
5304
|
-
// siblings remain stopped until the user asks to view them.
|
|
5305
4235
|
try {
|
|
5306
4236
|
this.switchPreviewPort?.(null);
|
|
5307
4237
|
}
|
|
@@ -5317,18 +4247,6 @@ class AgentVariantsOrchestrator {
|
|
|
5317
4247
|
resources.activePreviewIdleStop = stop;
|
|
5318
4248
|
await stop;
|
|
5319
4249
|
}
|
|
5320
|
-
/**
|
|
5321
|
-
* Spawn a fresh dev server at the user-facing destinationPath and retarget
|
|
5322
|
-
* the proxy so the iframe stays live across commit. Stores the process on
|
|
5323
|
-
* `resources.committedDevServer` so teardown can hand it off to the
|
|
5324
|
-
* lingering registry instead of killing it. Best-effort: a failure here is
|
|
5325
|
-
* non-fatal — the commit still succeeds; the user just has to run
|
|
5326
|
-
* `npm run dev` themselves to bring the preview back.
|
|
5327
|
-
*
|
|
5328
|
-
* `mode` selects the server flavor: `vite_app` spawns Vite via `npm run
|
|
5329
|
-
* dev`; `static_preview` spawns the in-tree static file server bound to
|
|
5330
|
-
* the destination directory (no install, no build, ~ms startup).
|
|
5331
|
-
*/
|
|
5332
4250
|
async startCommittedDevServer(args) {
|
|
5333
4251
|
const mode = args.mode ?? 'vite_app';
|
|
5334
4252
|
try {
|
|
@@ -5353,14 +4271,6 @@ class AgentVariantsOrchestrator {
|
|
|
5353
4271
|
port,
|
|
5354
4272
|
path: args.destinationPath,
|
|
5355
4273
|
};
|
|
5356
|
-
// Advertise the Rivet-owned server on devServerHealth so the iframe's
|
|
5357
|
-
// upstream probe stops reporting `ownership: 'none'`. Distinct from
|
|
5358
|
-
// switchPreviewPort: this updates health metadata, switchPreviewPort
|
|
5359
|
-
// retargets the proxy. Both fire here because the commit-handoff is
|
|
5360
|
-
// the only place Rivet legitimately takes ownership of the dev
|
|
5361
|
-
// server — variant cycling and cancel only retarget, they don't
|
|
5362
|
-
// touch health (which the user's external dev server owns during a
|
|
5363
|
-
// regular session).
|
|
5364
4274
|
try {
|
|
5365
4275
|
this.setCommittedDevServerHealth?.(port);
|
|
5366
4276
|
}
|
|
@@ -5381,19 +4291,9 @@ class AgentVariantsOrchestrator {
|
|
|
5381
4291
|
return undefined;
|
|
5382
4292
|
}
|
|
5383
4293
|
}
|
|
5384
|
-
/**
|
|
5385
|
-
* Stop any committed dev servers that were left alive past their session's
|
|
5386
|
-
* teardown. Called at the start of a new `propose` (so the next session's
|
|
5387
|
-
* preview doesn't compete with stale processes) and exposed for explicit
|
|
5388
|
-
* shutdown hooks. Best-effort: per-server failures are logged but don't
|
|
5389
|
-
* propagate.
|
|
5390
|
-
*/
|
|
5391
4294
|
async stopLingeringCommittedDevServers() {
|
|
5392
4295
|
const entries = [...this.lingeringCommittedDevServers.entries()];
|
|
5393
4296
|
this.lingeringCommittedDevServers.clear();
|
|
5394
|
-
// Clear the Rivet-owned-server advertisement on `devServerHealth` so the
|
|
5395
|
-
// probe doesn't keep reporting a port that's about to stop listening.
|
|
5396
|
-
// Safe to call even when no committed server existed for this process.
|
|
5397
4297
|
if (entries.length > 0) {
|
|
5398
4298
|
try {
|
|
5399
4299
|
this.setCommittedDevServerHealth?.(null);
|
|
@@ -5422,40 +4322,20 @@ class AgentVariantsOrchestrator {
|
|
|
5422
4322
|
log.info(`Tearing down session ${sessionId} (reason: ${reason})`);
|
|
5423
4323
|
resources.dependencyAbortController.abort();
|
|
5424
4324
|
await Promise.all([...resources.worktrees.values()].map((record) => DependencyPreparationService_1.previewDependencies.settle(record.worktreePath)));
|
|
5425
|
-
// Drain in-flight history persists BEFORE deleting worktrees: a tree
|
|
5426
|
-
// snapshot's `git add -A --work-tree <worktree>` racing the deletion
|
|
5427
|
-
// below doesn't fail — it stages whatever files remain, publishing a
|
|
5428
|
-
// silently truncated snapshot. The design doc's ordering constraint
|
|
5429
|
-
// ("tree committed before worktree teardown") is enforced here, not
|
|
5430
|
-
// just in tests. Best-effort with a bound: never let a wedged git call
|
|
5431
|
-
// stall teardown forever.
|
|
5432
4325
|
await Promise.race([
|
|
5433
4326
|
this.settleHistoryPersists(),
|
|
5434
4327
|
new Promise((resolve) => setTimeout(resolve, SETTLE_PERSISTS_TEARDOWN_TIMEOUT_MS)),
|
|
5435
4328
|
]);
|
|
5436
|
-
// Stop dev servers in parallel; ignore individual failures.
|
|
5437
|
-
// NOTE: For the fresh vite_app rename path, commitVariant already stopped
|
|
5438
|
-
// these dev servers BEFORE the rename (so Vite couldn't recreate `.vite/`
|
|
5439
|
-
// stub dirs at the old worktree paths). In that case devServerProcess is
|
|
5440
|
-
// already cleared and this loop is a no-op — exactly the desired behavior.
|
|
5441
4329
|
const stops = [...resources.worktrees.values()]
|
|
5442
4330
|
.filter((r) => r.devServerProcess)
|
|
5443
4331
|
.map((r) => this.worktrees
|
|
5444
4332
|
.stopDevServer(r.devServerProcess)
|
|
5445
4333
|
.catch((err) => log.warn(`stopDevServer failed for ${sessionId}/${r.workItemId}`, err)));
|
|
5446
4334
|
await Promise.all(stops);
|
|
5447
|
-
// The committed dev server (spawned at destinationPath after a fresh
|
|
5448
|
-
// vite_app commit) intentionally outlives this teardown — the iframe is
|
|
5449
|
-
// pointed at it via the proxy and the user just chose this project. Hand
|
|
5450
|
-
// it off to the lingering registry; it'll be stopped on the next
|
|
5451
|
-
// `propose` or explicit shutdown.
|
|
5452
4335
|
if (resources.committedDevServer && reason === 'committed') {
|
|
5453
4336
|
this.lingeringCommittedDevServers.set(sessionId, resources.committedDevServer);
|
|
5454
4337
|
}
|
|
5455
4338
|
else if (resources.committedDevServer) {
|
|
5456
|
-
// Non-committed teardown (cancel/shutdown) with a committed dev server
|
|
5457
|
-
// shouldn't happen in current code paths, but stop it defensively so we
|
|
5458
|
-
// don't leak procs.
|
|
5459
4339
|
try {
|
|
5460
4340
|
await this.worktrees.stopDevServer(resources.committedDevServer.proc);
|
|
5461
4341
|
}
|
|
@@ -5463,10 +4343,6 @@ class AgentVariantsOrchestrator {
|
|
|
5463
4343
|
log.warn(`stopDevServer for committed dev server (session ${sessionId}) failed`, err);
|
|
5464
4344
|
}
|
|
5465
4345
|
}
|
|
5466
|
-
// When a vite_app commit already moved the unchosen worktrees into a
|
|
5467
|
-
// sibling history dir, calling cleanupSession would re-delete them. Skip
|
|
5468
|
-
// the worktree removal step in that case — the move already cleared the
|
|
5469
|
-
// .rivet-variants/ entries for the chosen + preserved variants.
|
|
5470
4346
|
if (!resources.vitePreservedSiblings) {
|
|
5471
4347
|
try {
|
|
5472
4348
|
await this.worktrees.cleanupSession(sessionId, resources.freshDestinationParent);
|
|
@@ -5475,10 +4351,6 @@ class AgentVariantsOrchestrator {
|
|
|
5475
4351
|
log.warn(`cleanupSession (worktree removal) failed for ${sessionId}`, err);
|
|
5476
4352
|
}
|
|
5477
4353
|
}
|
|
5478
|
-
// Assigned static workspaces are always Rivet-owned, including existing-
|
|
5479
|
-
// project refinement work staged under `.rivet/variant-work` or /tmp.
|
|
5480
|
-
// Fresh staticPreviews are also Rivet staging unless commit already moved
|
|
5481
|
-
// the selected directory into the destination.
|
|
5482
4354
|
const ownedArtifactRoots = new Set(resources.workspaceManager.getOwnedArtifactRoots());
|
|
5483
4355
|
resources.workspaceManager.removeOwnedArtifactWorkspaces();
|
|
5484
4356
|
const staticDirectories = new Set();
|
|
@@ -5536,10 +4408,6 @@ class AgentVariantsOrchestrator {
|
|
|
5536
4408
|
}
|
|
5537
4409
|
}
|
|
5538
4410
|
exports.AgentVariantsOrchestrator = AgentVariantsOrchestrator;
|
|
5539
|
-
/** MCP bridges sometimes serialize the output field as a JSON string instead
|
|
5540
|
-
* of a parsed object. Normalize it before field-level inspection. */
|
|
5541
|
-
/** Rough byte-size of the agent's output. Used as a proxy for "how much
|
|
5542
|
-
* code did the agent write" when comparing HTML vs full-stack flows. */
|
|
5543
4411
|
function estimateOutputBytes(output) {
|
|
5544
4412
|
if (output === undefined || output === null)
|
|
5545
4413
|
return 0;
|
|
@@ -5563,28 +4431,11 @@ function normalizeOutput(output) {
|
|
|
5563
4431
|
}
|
|
5564
4432
|
return output;
|
|
5565
4433
|
}
|
|
5566
|
-
/**
|
|
5567
|
-
* `true` when `child` is a strict descendant of `parent` (resolved). Used by
|
|
5568
|
-
* the static_preview commit branch before rm/rename to make sure we never
|
|
5569
|
-
* touch anything outside the variant's workspace.
|
|
5570
|
-
*/
|
|
5571
4434
|
function isStrictlyInside(child, parent) {
|
|
5572
4435
|
const c = path_1.default.resolve(child);
|
|
5573
4436
|
const p = path_1.default.resolve(parent);
|
|
5574
4437
|
return c !== p && c.startsWith(p + path_1.default.sep);
|
|
5575
4438
|
}
|
|
5576
|
-
/**
|
|
5577
|
-
* Resolve `requestedPath` to an absolute, sandboxed file under `base`, or
|
|
5578
|
-
* `undefined` if it escapes the base, doesn't exist, isn't a regular file, or
|
|
5579
|
-
* is a hardlink. Shared by `resolveStaticPreviewAssetPath` across the variant's
|
|
5580
|
-
* own directory and the host-root fallback so both get identical containment.
|
|
5581
|
-
*
|
|
5582
|
-
* `base` is expected to be realpath'd by the caller. The requested target is
|
|
5583
|
-
* realpath'd here too — without it, a symlink planted under the base (e.g. via
|
|
5584
|
-
* a follow-up Write tool call) could pivot outside the sandbox. `requestedPath`
|
|
5585
|
-
* is used as Express delivered it (already URL-decoded); decoding again would
|
|
5586
|
-
* mangle filenames that legitimately contain `%` (e.g. `100%25.png` on disk).
|
|
5587
|
-
*/
|
|
5588
4439
|
function resolveAssetWithinBase(base, requestedPath) {
|
|
5589
4440
|
const target = path_1.default.resolve(base, '.' + path_1.default.sep + requestedPath);
|
|
5590
4441
|
if (target !== base && !target.startsWith(base + path_1.default.sep)) {
|
|
@@ -5604,11 +4455,6 @@ function resolveAssetWithinBase(base, requestedPath) {
|
|
|
5604
4455
|
const stat = fs_1.default.statSync(realTarget);
|
|
5605
4456
|
if (!stat.isFile())
|
|
5606
4457
|
return undefined;
|
|
5607
|
-
// Hardlinks aren't dereferenced by `realpath` — they ARE the file from a
|
|
5608
|
-
// path-resolution perspective, so the realpath check above can't detect
|
|
5609
|
-
// them. An agent could `ln /path/to/.env base/x.glb` (hardlink, not
|
|
5610
|
-
// symlink) and the resolver would happily serve the secret. Reject
|
|
5611
|
-
// anything with multiple links — legitimate assets always have nlink === 1.
|
|
5612
4458
|
if (stat.nlink !== 1)
|
|
5613
4459
|
return undefined;
|
|
5614
4460
|
return realTarget;
|
|
@@ -5617,19 +4463,6 @@ function resolveAssetWithinBase(base, requestedPath) {
|
|
|
5617
4463
|
return undefined;
|
|
5618
4464
|
}
|
|
5619
4465
|
}
|
|
5620
|
-
/**
|
|
5621
|
-
* Sandbox the agent's `output.assetBase` to a path inside the session
|
|
5622
|
-
* workspace. Accepts either an absolute path (used as-is after the
|
|
5623
|
-
* within-workspace check) or a path relative to the fresh-session
|
|
5624
|
-
* `workspacePath`. Returns `undefined` for non-fresh sessions, missing
|
|
5625
|
-
* directories, or paths that escape the workspace via `..` or symlinks.
|
|
5626
|
-
*
|
|
5627
|
-
* `assetBase` is agent-controlled, so a prompt-injected variant could point
|
|
5628
|
-
* it at a symlink whose real target is outside `workspacePath` — and the
|
|
5629
|
-
* asset endpoint would then happily serve files like `~/.ssh/id_rsa` or
|
|
5630
|
-
* `.env`. Resolving with `fs.realpathSync` collapses symlinks before the
|
|
5631
|
-
* containment check, so the check applies to the real target, not the link.
|
|
5632
|
-
*/
|
|
5633
4466
|
function resolveStaticPreviewAssetBase(args) {
|
|
5634
4467
|
if (!args.assetBase)
|
|
5635
4468
|
return undefined;
|
|
@@ -5638,23 +4471,6 @@ function resolveStaticPreviewAssetBase(args) {
|
|
|
5638
4471
|
let workspace;
|
|
5639
4472
|
let resolved;
|
|
5640
4473
|
try {
|
|
5641
|
-
// Defense against an agent that subverts the sandbox by replacing the
|
|
5642
|
-
// Rivet-created `workspacePath` directory with a symlink. Plain
|
|
5643
|
-
// `realpath` would silently follow that symlink and the containment
|
|
5644
|
-
// check below would then trust the wrong root.
|
|
5645
|
-
//
|
|
5646
|
-
// Two layers:
|
|
5647
|
-
// 1. `lstat` the workspacePath itself — if it's a symlink (rather
|
|
5648
|
-
// than a real directory Rivet created), reject outright. This
|
|
5649
|
-
// catches the obvious swap `ln -sf $HOME <workspacePath>` and the
|
|
5650
|
-
// subtler swap to a sibling like `<workspaceRoot>` itself
|
|
5651
|
-
// (which would pass any subsequent containment check based on
|
|
5652
|
-
// ancestor matching).
|
|
5653
|
-
// 2. realpath both and require the resolved workspacePath to be a
|
|
5654
|
-
// STRICT descendant of the resolved workspaceRoot — equal is not
|
|
5655
|
-
// enough (a symlink to workspaceRoot would otherwise be accepted
|
|
5656
|
-
// and the asset route would then serve files at the project
|
|
5657
|
-
// root, e.g. `.env`).
|
|
5658
4474
|
const wsStat = fs_1.default.lstatSync(args.projectContext.workspacePath);
|
|
5659
4475
|
if (wsStat.isSymbolicLink()) {
|
|
5660
4476
|
log.warn(`Static preview workspacePath ${args.projectContext.workspacePath} is a symlink — refusing assetBase`);
|
|
@@ -5716,11 +4532,6 @@ function buildStaticPreviewDocument(input) {
|
|
|
5716
4532
|
const style = input.css ? `<style>\n${input.css}\n</style>` : '';
|
|
5717
4533
|
const script = input.js ? `<script>\n${input.js}\n</script>` : '';
|
|
5718
4534
|
if (/<!doctype html>|<html[\s>]/i.test(input.html)) {
|
|
5719
|
-
// Full document: inject css before </head> and js before </body>. The
|
|
5720
|
-
// agent often passes a complete `<!doctype html>...` blob with css/js
|
|
5721
|
-
// alongside; without this they're silently dropped and the variant ships
|
|
5722
|
-
// unstyled and non-interactive. Falls back to appending to the end if
|
|
5723
|
-
// the closing tag isn't found.
|
|
5724
4535
|
let doc = input.html;
|
|
5725
4536
|
if (style) {
|
|
5726
4537
|
if (/<\/head>/i.test(doc)) {
|
|
@@ -5754,15 +4565,8 @@ ${input.html}
|
|
|
5754
4565
|
</html>`;
|
|
5755
4566
|
}
|
|
5756
4567
|
function countDiffFiles(diff) {
|
|
5757
|
-
// Each file in a unified diff starts with "diff --git ".
|
|
5758
4568
|
return (diff.match(/^diff --git /gm) ?? []).length;
|
|
5759
4569
|
}
|
|
5760
|
-
/**
|
|
5761
|
-
* Count source files under a materialized fresh-project destination,
|
|
5762
|
-
* skipping install artifacts (`node_modules`, `.git`, build outputs) so the
|
|
5763
|
-
* commit telemetry / chip count reflects the agent-visible surface area
|
|
5764
|
-
* rather than the install footprint.
|
|
5765
|
-
*/
|
|
5766
4570
|
function countWorktreeFiles(destinationPath) {
|
|
5767
4571
|
let count = 0;
|
|
5768
4572
|
const walk = (dir) => {
|
|
@@ -5795,8 +4599,6 @@ const enrichDesignSource = (design) => {
|
|
|
5795
4599
|
};
|
|
5796
4600
|
};
|
|
5797
4601
|
const toActiveProjectContext = (projectContext) => {
|
|
5798
|
-
// Source count + grounding are derived purely from the read-only context
|
|
5799
|
-
// bundle now that `sourceContext` intake is gone.
|
|
5800
4602
|
const sourceCount = projectContext.variantContext?.userContext.filter((source) => source.transport !== 'prompt').length ?? 0;
|
|
5801
4603
|
const hasSourceContextSummary = Boolean(sourceCount > 0 ||
|
|
5802
4604
|
(projectContext.variantContext?.rivetMetadata.length ?? 0) > 0);
|
|
@@ -5839,18 +4641,6 @@ const toActiveProjectContext = (projectContext) => {
|
|
|
5839
4641
|
: {}),
|
|
5840
4642
|
};
|
|
5841
4643
|
};
|
|
5842
|
-
/**
|
|
5843
|
-
* Resolve the user-facing supporting artifacts for a session.
|
|
5844
|
-
*
|
|
5845
|
-
* For 0→1 (`fresh`) sessions with a populated `designContext`, each slot is
|
|
5846
|
-
* turned into a `design_context` artifact that links to Rivet-hosted
|
|
5847
|
-
* DESIGN.md views:
|
|
5848
|
-
* - `slug` entries resolve bundled catalog markdown via the design catalog.
|
|
5849
|
-
* - `markdown` entries (Agent Browser / inspiration extractor output) carry
|
|
5850
|
-
* their stored markdown when the linked route is requested.
|
|
5851
|
-
* Slots whose markdown can't be resolved are skipped so the UI never renders
|
|
5852
|
-
* a metadata-only DESIGN.md row.
|
|
5853
|
-
*/
|
|
5854
4644
|
const buildSessionArtifacts = (sessionId, projectContext) => {
|
|
5855
4645
|
const artifacts = buildResolvedDesignContextArtifacts(projectContext);
|
|
5856
4646
|
return artifacts.map(({ content: _content, ...artifact }) => ({
|
|
@@ -6188,7 +4978,6 @@ const renderDesignMarkdown = (markdown, artifactLabel) => {
|
|
|
6188
4978
|
const headingText = headingMatch[2].trim();
|
|
6189
4979
|
const isDuplicateTitle = headingText === artifactLabel ||
|
|
6190
4980
|
headingText === `${artifactLabel} DESIGN.md`;
|
|
6191
|
-
// The viewer header already renders the artifact title.
|
|
6192
4981
|
if (level === 1 && !skippedFirstH1 && isDuplicateTitle) {
|
|
6193
4982
|
skippedFirstH1 = true;
|
|
6194
4983
|
return;
|
|
@@ -6230,14 +5019,6 @@ const escapeHtml = (value) => {
|
|
|
6230
5019
|
.replace(/"/g, '"')
|
|
6231
5020
|
.replace(/'/g, ''');
|
|
6232
5021
|
};
|
|
6233
|
-
/**
|
|
6234
|
-
* Resolve a per-variant design context entry into the raw DESIGN.md markdown
|
|
6235
|
-
* the worktree scaffolder writes, plus a small `designSource` descriptor for
|
|
6236
|
-
* the variant manifest. Slug entries resolve through the bundled catalog;
|
|
6237
|
-
* markdown entries (Agent Browser / inspiration extractor output) carry their
|
|
6238
|
-
* stored markdown verbatim. Returns null when the entry is missing or the
|
|
6239
|
-
* slug doesn't resolve to bundled markdown.
|
|
6240
|
-
*/
|
|
6241
5022
|
const resolveDesignArtifact = (entry) => {
|
|
6242
5023
|
if (!entry)
|
|
6243
5024
|
return null;
|
|
@@ -6462,7 +5243,6 @@ function copyStaticPreviewDirectory(src, dest) {
|
|
|
6462
5243
|
}
|
|
6463
5244
|
}
|
|
6464
5245
|
}
|
|
6465
|
-
/** Prepares an isolated project through its selected package manager. */
|
|
6466
5246
|
const defaultInstallDependencies = async (worktreePath, options) => {
|
|
6467
5247
|
await DependencyPreparationService_1.previewDependencies.prepare({
|
|
6468
5248
|
cwd: worktreePath,
|
|
@@ -6471,14 +5251,6 @@ const defaultInstallDependencies = async (worktreePath, options) => {
|
|
|
6471
5251
|
signal: options?.signal,
|
|
6472
5252
|
});
|
|
6473
5253
|
};
|
|
6474
|
-
/**
|
|
6475
|
-
* Turn the invocation a live dev server actually booted with into a
|
|
6476
|
-
* port-parameterized replay recipe. The resolution bakes the allocated port
|
|
6477
|
-
* into args/env (`--port <n>`, `PORT=<n>`) — storing that verbatim would
|
|
6478
|
-
* bake in a dead port, so occurrences of the port (digit-boundary-guarded so
|
|
6479
|
-
* incidental digit runs survive) become `${PORT}` for replay to substitute.
|
|
6480
|
-
* `cwd` is stored relative to the snapshot root per the tree-root contract.
|
|
6481
|
-
*/
|
|
6482
5254
|
const buildServeRecipeFromResolved = (snapshotRoot, dev, port) => {
|
|
6483
5255
|
const portPattern = new RegExp(`(?<![0-9])${port}(?![0-9])`, 'g');
|
|
6484
5256
|
const sub = (value) => value.replace(portPattern, '${PORT}');
|
|
@@ -6490,19 +5262,6 @@ const buildServeRecipeFromResolved = (snapshotRoot, dev, port) => {
|
|
|
6490
5262
|
envTemplate: Object.fromEntries(Object.entries(dev.env).map(([key, value]) => [key, sub(value)])),
|
|
6491
5263
|
};
|
|
6492
5264
|
};
|
|
6493
|
-
/**
|
|
6494
|
-
* Whether an install at `cwd` stays inside the Rivet-owned worktree.
|
|
6495
|
-
* A linked `node_modules` can point at another project's install; running a
|
|
6496
|
-
* package manager through it would mutate dependencies outside this worktree.
|
|
6497
|
-
* Install is safe only
|
|
6498
|
-
* when `node_modules` is absent (a nested standalone package — the install
|
|
6499
|
-
* creates a worktree-local dir) or a real directory owned by the worktree.
|
|
6500
|
-
*
|
|
6501
|
-
* Complements DependencyPreparationService.assertOwnedInstall rather than
|
|
6502
|
-
* duplicating it: this stricter check (any symlink, even one resolving
|
|
6503
|
-
* inside the worktree) decides whether an install RETRY is worth attempting,
|
|
6504
|
-
* while the service enforces containment on every install it runs.
|
|
6505
|
-
*/
|
|
6506
5265
|
const canInstallWithoutTouchingHost = (cwd) => {
|
|
6507
5266
|
try {
|
|
6508
5267
|
return !fs_1.default.lstatSync(path_1.default.join(cwd, 'node_modules')).isSymbolicLink();
|
|
@@ -6511,15 +5270,6 @@ const canInstallWithoutTouchingHost = (cwd) => {
|
|
|
6511
5270
|
return true;
|
|
6512
5271
|
}
|
|
6513
5272
|
};
|
|
6514
|
-
/**
|
|
6515
|
-
* Fail fast — before spawning anything — when the package.json at `cwd`
|
|
6516
|
-
* positively lacks the dev script we're about to invoke. Without this the
|
|
6517
|
-
* spawn exits with the package manager's "missing script" error after a full
|
|
6518
|
-
* boot round-trip and surfaces as an opaque `exited` failure; with it the
|
|
6519
|
-
* user gets an actionable message naming the scripts that DO exist. Missing
|
|
6520
|
-
* or unparseable package.json is NOT treated as a failure here — other paths
|
|
6521
|
-
* own those cases, and the spawn's own error is more specific.
|
|
6522
|
-
*/
|
|
6523
5273
|
const assertDevScriptExists = (cwd, scriptName) => {
|
|
6524
5274
|
let scripts;
|
|
6525
5275
|
try {
|
|
@@ -6548,16 +5298,6 @@ const assertDevScriptExists = (cwd, scriptName) => {
|
|
|
6548
5298
|
: '',
|
|
6549
5299
|
});
|
|
6550
5300
|
};
|
|
6551
|
-
/**
|
|
6552
|
-
* True when `a` and `b` (or the closest existing ancestor of each) live on
|
|
6553
|
-
* the same filesystem volume. Used by commitVariant to decide between an
|
|
6554
|
-
* O(1) rename and a recursive copy-with-reinstall fallback.
|
|
6555
|
-
*
|
|
6556
|
-
* `destinationPath` for fresh sessions does not exist yet (we'd fail the
|
|
6557
|
-
* "destination must be empty" guard otherwise), so we compare against its
|
|
6558
|
-
* parent directory which is guaranteed to exist (createZeroToOneTool either
|
|
6559
|
-
* created it or validated it).
|
|
6560
|
-
*/
|
|
6561
5301
|
function areSameVolume(a, b) {
|
|
6562
5302
|
try {
|
|
6563
5303
|
const statA = fs_1.default.statSync(a);
|
|
@@ -6569,7 +5309,6 @@ function areSameVolume(a, b) {
|
|
|
6569
5309
|
return false;
|
|
6570
5310
|
}
|
|
6571
5311
|
}
|
|
6572
|
-
/** Clears a borrowed install so a moved generated project prepares its own dependencies. */
|
|
6573
5312
|
async function resolveNodeModulesSymlink(worktreePath) {
|
|
6574
5313
|
const nodeModulesPath = path_1.default.join(worktreePath, 'node_modules');
|
|
6575
5314
|
try {
|
|
@@ -6611,16 +5350,8 @@ const defaultMaterializeProject = async (sourceWorktreePath, destinationPath) =>
|
|
|
6611
5350
|
'Initial commit (created with Rivet)',
|
|
6612
5351
|
])
|
|
6613
5352
|
.catch(() => {
|
|
6614
|
-
// Best-effort: a missing user identity or empty tree leaves the
|
|
6615
|
-
// commit step un-applied. The destination still has the files.
|
|
6616
5353
|
});
|
|
6617
5354
|
};
|
|
6618
|
-
/**
|
|
6619
|
-
* Synthesize a fallback brief body for a human-direct unified start slot.
|
|
6620
|
-
* Agent callers provide structured briefs before starting. Human-direct
|
|
6621
|
-
* batches get stable, slot-specific focus statements without another model
|
|
6622
|
-
* call so workers do not independently invent overlapping directions.
|
|
6623
|
-
*/
|
|
6624
5355
|
function synthesizeUnifiedBriefBody(prompt, index, total) {
|
|
6625
5356
|
const trimmed = prompt.trim().replace(/\s+/g, ' ').slice(0, 200);
|
|
6626
5357
|
const intent = trimmed.length > 0 ? trimmed : 'Create this variant';
|