- {handlePos && (
-
-
e.preventDefault()}
- className="flex items-center justify-center w-5 h-6 cursor-pointer rounded hover:bg-muted"
- >
-
-
-
{
- if (editor) {
- savedBlockSelRef.current = blockSelectionKey.getState(editor.view.state) ?? null;
- }
- }}
- onClick={onHandleClick}
- onDragStart={onHandleDragStart}
- className="flex items-center justify-center w-5 h-6 cursor-grab rounded hover:bg-muted"
- >
-
-
-
- )}
-
+
+
+
+
);
}
diff --git a/packages/web/src/components/editor/slash-command-items.ts b/packages/web/src/components/editor/slash-command-items.ts
index bb48a67..a51029f 100644
--- a/packages/web/src/components/editor/slash-command-items.ts
+++ b/packages/web/src/components/editor/slash-command-items.ts
@@ -43,6 +43,12 @@ export const slashCommandItems: SlashCommandItem[] = [
description: "Ordered list",
action: (editor) => editor.chain().focus().toggleOrderedList().run(),
},
+ {
+ label: "Inline Code",
+ icon: "`c`",
+ description: "Inline code (Cmd+E)",
+ action: (editor) => editor.chain().focus().toggleCode().run(),
+ },
{
label: "Code Block",
icon: "<>",
diff --git a/packages/web/src/components/execution/BreakdownSection.tsx b/packages/web/src/components/execution/BreakdownSection.tsx
index 533496d..3950992 100644
--- a/packages/web/src/components/execution/BreakdownSection.tsx
+++ b/packages/web/src/components/execution/BreakdownSection.tsx
@@ -1,22 +1,23 @@
import { useCallback, useMemo } from "react";
-import { Loader2, Sparkles } from "lucide-react";
+import { Loader2, Plus, Sparkles } from "lucide-react";
import { Button } from "@/components/ui/button";
import { trpc } from "@/lib/trpc";
import { useSpawnMutation } from "@/hooks/useSpawnMutation";
+import { ContentProposalReview } from "@/components/editor/ContentProposalReview";
interface BreakdownSectionProps {
initiativeId: string;
phasesLoaded: boolean;
phases: Array<{ status: string }>;
+ onAddPhase?: () => void;
}
export function BreakdownSection({
initiativeId,
phasesLoaded,
phases,
+ onAddPhase,
}: BreakdownSectionProps) {
- const utils = trpc.useUtils();
-
// Breakdown agent tracking
const agentsQuery = trpc.listAgents.useQuery();
const allAgents = agentsQuery.data ?? [];
@@ -25,7 +26,7 @@ export function BreakdownSection({
.filter(
(a) =>
a.mode === "breakdown" &&
- a.taskId === initiativeId &&
+ a.initiativeId === initiativeId &&
["running", "waiting_for_input", "idle"].includes(a.status),
)
.sort(
@@ -37,27 +38,55 @@ export function BreakdownSection({
const isBreakdownRunning = breakdownAgent?.status === "running";
+ // Query proposals when we have a completed breakdown agent
+ const proposalsQuery = trpc.listProposals.useQuery(
+ { agentId: breakdownAgent?.id ?? "" },
+ { enabled: !!breakdownAgent && breakdownAgent.status === "idle" },
+ );
+ const pendingProposals = useMemo(
+ () => (proposalsQuery.data ?? []).filter((p) => p.status === "pending"),
+ [proposalsQuery.data],
+ );
+
+ const dismissMutation = trpc.dismissAgent.useMutation();
+
const breakdownSpawn = useSpawnMutation(trpc.spawnArchitectBreakdown.useMutation, {
- onSuccess: () => {
- void utils.listAgents.invalidate();
- },
- showToast: false, // We show our own error UI
+ showToast: false,
});
const handleBreakdown = useCallback(() => {
breakdownSpawn.spawn({ initiativeId });
}, [initiativeId, breakdownSpawn]);
- // Don't render if we have phases
- if (phasesLoaded && phases.length > 0) {
- return null;
- }
+ const handleDismiss = useCallback(() => {
+ if (!breakdownAgent) return;
+ dismissMutation.mutate({ id: breakdownAgent.id });
+ }, [breakdownAgent, dismissMutation]);
// Don't render during loading
if (!phasesLoaded) {
return null;
}
+ // If phases exist and no pending proposals to review, hide section
+ if (phases.length > 0 && pendingProposals.length === 0) {
+ return null;
+ }
+
+ // Show proposal review when breakdown agent completed with pending proposals
+ if (breakdownAgent?.status === "idle" && pendingProposals.length > 0) {
+ return (
+
+
+
+ );
+ }
+
return (
No phases yet
@@ -67,18 +96,34 @@ export function BreakdownSection({
Breaking down initiative...
) : (
-
+
+
+ {onAddPhase && (
+ <>
+
or
+
+ >
+ )}
+
)}
{breakdownSpawn.isError && (
@@ -87,4 +132,4 @@ export function BreakdownSection({
)}
);
-}
\ No newline at end of file
+}
diff --git a/packages/web/src/components/execution/ExecutionContext.tsx b/packages/web/src/components/execution/ExecutionContext.tsx
index 100c69e..1c7e291 100644
--- a/packages/web/src/components/execution/ExecutionContext.tsx
+++ b/packages/web/src/components/execution/ExecutionContext.tsx
@@ -21,9 +21,8 @@ export interface FlatTaskEntry {
export interface PhaseData {
id: string;
initiativeId: string;
- number: number;
name: string;
- description: string | null;
+ content: string | null;
status: string;
createdAt: string | Date;
updatedAt: string | Date;
diff --git a/packages/web/src/components/execution/PhaseActions.tsx b/packages/web/src/components/execution/PhaseActions.tsx
index 17a39c2..bbb98ff 100644
--- a/packages/web/src/components/execution/PhaseActions.tsx
+++ b/packages/web/src/components/execution/PhaseActions.tsx
@@ -1,60 +1,73 @@
import { useCallback, useMemo } from "react";
-import { Loader2 } from "lucide-react";
+import { Loader2, Plus, Sparkles } from "lucide-react";
import { Button } from "@/components/ui/button";
import { trpc } from "@/lib/trpc";
interface PhaseActionsProps {
initiativeId: string;
phases: Array<{ id: string; status: string }>;
+ onAddPhase: () => void;
+ phasesWithoutTasks: string[];
+ decomposeAgentByPhase: Map