feat: Add agent preview integration with auto-teardown and simplified commands

- Add agentId label to preview containers (cw.agent-id) for tracking
- Add startForAgent/stopByAgentId methods to PreviewManager
- Auto-teardown: previews torn down on agent:stopped event
- Conditional preview prompt injection for execute/refine/discuss agents
- Agent-simplified CLI: cw preview start/stop --agent <id>
- cw preview setup command with --auto mode for guided config generation
- hasPreviewConfig hint on cw project register output
- New tRPC procedures: startPreviewForAgent, stopPreviewByAgent
This commit is contained in:
Lukas May
2026-03-05 15:39:15 +01:00
parent 66605da30d
commit ebe186bd5e
10 changed files with 381 additions and 22 deletions

View File

@@ -37,9 +37,10 @@ import type {
ProcessCrashedEvent,
} from '../events/index.js';
import { writeInputFiles } from './file-io.js';
import { buildWorkspaceLayout, buildInterAgentCommunication } from './prompts/index.js';
import { buildWorkspaceLayout, buildInterAgentCommunication, buildPreviewInstructions } from './prompts/index.js';
import { getProvider } from './providers/registry.js';
import { createModuleLogger } from '../logger/index.js';
import { getProjectCloneDir } from '../git/project-clones.js';
import { join } from 'node:path';
import { unlink, readFile, writeFile as writeFileAsync } from 'node:fs/promises';
import { existsSync } from 'node:fs';
@@ -282,7 +283,15 @@ export class MultiProviderAgentManager implements AgentManager {
// 3a. Append inter-agent communication instructions with actual agent ID
prompt = prompt + buildInterAgentCommunication(agentId, mode);
// 3b. Write input files (after agent creation so we can include agentId/agentName)
// 3b. Append preview deployment instructions if applicable
if (['execute', 'refine', 'discuss'].includes(mode) && initiativeId) {
const shouldInject = await this.shouldInjectPreviewInstructions(initiativeId);
if (shouldInject) {
prompt = prompt + buildPreviewInstructions(agentId);
}
}
// 3c. Write input files (after agent creation so we can include agentId/agentName)
if (options.inputContext) {
await writeInputFiles({ agentWorkdir: agentCwd, ...options.inputContext, agentId, agentName: alias });
log.debug({ alias }, 'input files written');
@@ -1038,6 +1047,23 @@ export class MultiProviderAgentManager implements AgentManager {
}
}
/**
* Check whether preview instructions should be injected for this initiative.
* Returns true if exactly one project linked and it has .cw-preview.yml.
*/
private async shouldInjectPreviewInstructions(initiativeId: string): Promise<boolean> {
try {
const projects = await this.projectRepository.findProjectsByInitiativeId(initiativeId);
if (projects.length !== 1) return false;
const project = projects[0];
const cloneDir = join(this.workspaceRoot, getProjectCloneDir(project.name, project.id));
return existsSync(join(cloneDir, '.cw-preview.yml'));
} catch {
return false;
}
}
/**
* Convert database agent record to AgentInfo.
*/

View File

@@ -14,3 +14,4 @@ export { buildRefinePrompt } from './refine.js';
export { buildChatPrompt } from './chat.js';
export type { ChatHistoryEntry } from './chat.js';
export { buildWorkspaceLayout } from './workspace.js';
export { buildPreviewInstructions } from './preview.js';

View File

@@ -0,0 +1,37 @@
/**
* Preview Deployment Prompt Instructions
*
* Conditional prompt section injected when the agent's initiative has
* a project with `.cw-preview.yml`. Provides prefilled commands using
* the agent's own ID so the server can resolve everything else.
*/
export function buildPreviewInstructions(agentId: string): string {
return `
<preview_deployments>
This project supports preview deployments via Docker. You can spin up a running
instance to verify your changes visually or explore the app.
## Start a Preview
cw preview start --agent ${agentId}
Automatically uses your worktree (dev mode with hot reload). The URL is printed
to stdout (e.g. http://abc123.localhost:9100).
## Check Preview Status
cw preview list
## Stop a Preview
cw preview stop --agent ${agentId}
## When to Use
- After implementing a UI change, spin up a preview to verify rendering.
- After API changes, verify the frontend still works end-to-end.
- To explore the existing app state via Chrome DevTools or browser.
## When NOT to Use
- Backend-only changes with no visual component — run tests instead.
- If Docker is not available (the command will fail gracefully).
</preview_deployments>`;
}