diff --git a/apps/server/trpc/routers/agent.ts b/apps/server/trpc/routers/agent.ts index 5be795d..74fdc50 100644 --- a/apps/server/trpc/routers/agent.ts +++ b/apps/server/trpc/routers/agent.ts @@ -167,10 +167,12 @@ export function agentProcedures(publicProcedure: ProcedureBuilder) { .query(async ({ ctx, input }): Promise => { const agentManager = requireAgentManager(ctx); const allAgents = await agentManager.list(); + // Surface discuss and refine agents — both work on initiative content + const CONTENT_MODES = ['discuss', 'refine']; const candidates = allAgents .filter( (a) => - a.mode === 'refine' && + CONTENT_MODES.includes(a.mode) && a.initiativeId === input.initiativeId && ['running', 'waiting_for_input', 'idle', 'crashed'].includes(a.status) && !a.userDismissedAt, diff --git a/apps/server/trpc/routers/initiative-activity.ts b/apps/server/trpc/routers/initiative-activity.ts index b9a11e9..7a55a74 100644 --- a/apps/server/trpc/routers/initiative-activity.ts +++ b/apps/server/trpc/routers/initiative-activity.ts @@ -35,7 +35,7 @@ export function deriveInitiativeActivity( } // Check for active architect agents BEFORE zero-phases check - // so auto-spawned discuss/plan/refine agents surface activity + // so architect agents (discuss/plan/detail/refine) surface activity const activeAgent = activeArchitectAgents?.find( a => a.initiativeId === initiative.id && (a.status === 'running' || a.status === 'waiting_for_input'), diff --git a/apps/server/trpc/routers/initiative.ts b/apps/server/trpc/routers/initiative.ts index 1718f5e..c0f2a47 100644 --- a/apps/server/trpc/routers/initiative.ts +++ b/apps/server/trpc/routers/initiative.ts @@ -7,7 +7,8 @@ import { z } from 'zod'; import type { ProcedureBuilder } from '../trpc.js'; import { requireAgentManager, requireInitiativeRepository, requireProjectRepository, requireTaskRepository } from './_helpers.js'; import { deriveInitiativeActivity } from './initiative-activity.js'; -import { buildDiscussPrompt } from '../../agent/prompts/index.js'; +import { buildRefinePrompt } from '../../agent/prompts/index.js'; +import type { PageForSerialization } from '../../agent/content-serializer.js'; export function initiativeProcedures(publicProcedure: ProcedureBuilder) { return { @@ -47,38 +48,57 @@ export function initiativeProcedures(publicProcedure: ProcedureBuilder) { await projectRepo.setInitiativeProjects(initiative.id, input.projectIds); } + // Create root page — seed with description as tiptap content if provided + const descriptionText = input.description?.trim(); + let rootPage: { id: string; parentPageId: string | null; title: string; content: string | null; sortOrder: number } | null = null; if (ctx.pageRepository) { - await ctx.pageRepository.create({ + const tiptapContent = descriptionText + ? JSON.stringify({ + type: 'doc', + content: descriptionText.split(/\n{2,}/).map(para => ({ + type: 'paragraph', + content: [{ type: 'text', text: para.trim() }], + })).filter(p => p.content[0].text), + }) + : null; + + rootPage = await ctx.pageRepository.create({ initiativeId: initiative.id, parentPageId: null, title: input.name, - content: null, + content: tiptapContent, sortOrder: 0, }); } - // Auto-spawn discuss agent when description is provided - if (input.description?.trim() && ctx.agentManager && ctx.taskRepository) { + // Auto-spawn refine agent when description is provided + if (descriptionText && rootPage && ctx.agentManager && ctx.taskRepository) { try { const taskRepo = requireTaskRepository(ctx); const agentManager = requireAgentManager(ctx); const task = await taskRepo.create({ initiativeId: initiative.id, - name: `Discuss: ${initiative.name}`, - description: input.description.trim(), - category: 'discuss', + name: `Refine: ${initiative.name}`, + description: descriptionText, + category: 'refine', status: 'in_progress', }); - const prompt = buildDiscussPrompt(); + const pages: PageForSerialization[] = [{ + id: rootPage.id, + parentPageId: null, + title: rootPage.title, + content: rootPage.content, + sortOrder: 0, + }]; agentManager.spawn({ taskId: task.id, - prompt, - mode: 'discuss', + prompt: buildRefinePrompt(), + mode: 'refine', initiativeId: initiative.id, - inputContext: { initiative, task }, + inputContext: { initiative, pages }, }); } catch { // Fire-and-forget — don't fail initiative creation if agent spawn fails diff --git a/apps/web/src/components/CreateInitiativeDialog.tsx b/apps/web/src/components/CreateInitiativeDialog.tsx index c0ec131..a025921 100644 --- a/apps/web/src/components/CreateInitiativeDialog.tsx +++ b/apps/web/src/components/CreateInitiativeDialog.tsx @@ -123,7 +123,7 @@ export function CreateInitiativeDialog({