diff --git a/apps/server/agent/file-io.test.ts b/apps/server/agent/file-io.test.ts index ae0fb9a..96bc6a1 100644 --- a/apps/server/agent/file-io.test.ts +++ b/apps/server/agent/file-io.test.ts @@ -52,6 +52,7 @@ describe('writeInputFiles', () => { status: 'active', branch: 'cw/test-initiative', executionMode: 'review_per_phase', + qualityReview: false, createdAt: new Date('2026-01-01'), updatedAt: new Date('2026-01-02'), }; diff --git a/apps/server/cli/index.ts b/apps/server/cli/index.ts index 8fc0425..cda8766 100644 --- a/apps/server/cli/index.ts +++ b/apps/server/cli/index.ts @@ -1878,7 +1878,7 @@ See the Codewalkers documentation for .cw-preview.yml format and options.`; : `.cw-worktrees/${id}`; console.log(`Resolve conflicts in worktree: ${worktreePath}`); console.log('Conflicting files:'); - for (const f of errand.conflictFiles ?? []) { + for (const f of (errand as any).conflictFiles ?? []) { console.log(` ${f}`); } console.log('After resolving: stage and commit changes in the worktree, then run:'); diff --git a/apps/server/test/unit/headquarters.test.ts b/apps/server/test/unit/headquarters.test.ts index bc94e09..0176c5e 100644 --- a/apps/server/test/unit/headquarters.test.ts +++ b/apps/server/test/unit/headquarters.test.ts @@ -63,6 +63,7 @@ class MockAgentManager implements AgentManager { async delete(): Promise { throw new Error('Not implemented'); } async dismiss(): Promise { throw new Error('Not implemented'); } async resumeForConversation(): Promise { return false; } + async sendUserMessage(): Promise { throw new Error('Not implemented'); } } // ============================================================================= diff --git a/apps/server/test/unit/radar-procedures.test.ts b/apps/server/test/unit/radar-procedures.test.ts index d7acba6..01d642e 100644 --- a/apps/server/test/unit/radar-procedures.test.ts +++ b/apps/server/test/unit/radar-procedures.test.ts @@ -69,6 +69,7 @@ class MockAgentManager implements AgentManager { async delete(): Promise { throw new Error('Not implemented'); } async dismiss(): Promise { throw new Error('Not implemented'); } async resumeForConversation(): Promise { return false; } + async sendUserMessage(): Promise { throw new Error('Not implemented'); } } // ============================================================================= diff --git a/apps/server/trpc/router.ts b/apps/server/trpc/router.ts index 43ad5d3..9f24841 100644 --- a/apps/server/trpc/router.ts +++ b/apps/server/trpc/router.ts @@ -25,6 +25,7 @@ import { previewProcedures } from './routers/preview.js'; import { conversationProcedures } from './routers/conversation.js'; import { chatSessionProcedures } from './routers/chat-session.js'; import { headquartersProcedures } from './routers/headquarters.js'; +import { errandProcedures } from './routers/errand.js'; // Re-export tRPC primitives (preserves existing import paths) export { router, publicProcedure, middleware, createCallerFactory } from './trpc.js'; @@ -65,6 +66,7 @@ export const appRouter = router({ ...conversationProcedures(publicProcedure), ...chatSessionProcedures(publicProcedure), ...headquartersProcedures(publicProcedure), + ...errandProcedures(publicProcedure), }); export type AppRouter = typeof appRouter; diff --git a/apps/server/trpc/routers/errand.ts b/apps/server/trpc/routers/errand.ts index 57fb738..39b144c 100644 --- a/apps/server/trpc/routers/errand.ts +++ b/apps/server/trpc/routers/errand.ts @@ -350,12 +350,14 @@ export function errandProcedures(publicProcedure: ProcedureBuilder) { } // Remove worktree and branch (best-effort) - const project = await requireProjectRepository(ctx).findById(errand.projectId); - if (project) { - const clonePath = await resolveClonePath(project, ctx); - const worktreeManager = new SimpleGitWorktreeManager(clonePath); - try { await worktreeManager.remove(errand.id); } catch { /* no-op if already gone */ } - try { await requireBranchManager(ctx).deleteBranch(clonePath, errand.branch); } catch { /* no-op */ } + if (errand.projectId) { + const project = await requireProjectRepository(ctx).findById(errand.projectId); + if (project) { + const clonePath = await resolveClonePath(project, ctx); + const worktreeManager = new SimpleGitWorktreeManager(clonePath); + try { await worktreeManager.remove(errand.id); } catch { /* no-op if already gone */ } + try { await requireBranchManager(ctx).deleteBranch(clonePath, errand.branch); } catch { /* no-op */ } + } } await repo.delete(errand.id); @@ -426,12 +428,14 @@ export function errandProcedures(publicProcedure: ProcedureBuilder) { } // Remove worktree and branch (best-effort) - const project = await requireProjectRepository(ctx).findById(errand.projectId); - if (project) { - const clonePath = await resolveClonePath(project, ctx); - const worktreeManager = new SimpleGitWorktreeManager(clonePath); - try { await worktreeManager.remove(errand.id); } catch { /* no-op if already gone */ } - try { await branchManager.deleteBranch(clonePath, errand.branch); } catch { /* no-op */ } + if (errand.projectId) { + const project = await requireProjectRepository(ctx).findById(errand.projectId); + if (project) { + const clonePath = await resolveClonePath(project, ctx); + const worktreeManager = new SimpleGitWorktreeManager(clonePath); + try { await worktreeManager.remove(errand.id); } catch { /* no-op if already gone */ } + try { await branchManager.deleteBranch(clonePath, errand.branch); } catch { /* no-op */ } + } } const updated = await repo.update(input.id, { status: 'abandoned' });