From 538014eb30b1667df8a884666b77b61ce83c98bd Mon Sep 17 00:00:00 2001 From: Kareem Mazen Yaqoup <117186053+engkareeem@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:14:14 +0300 Subject: [PATCH 01/49] Enhance ScrollArea component to enforce block display for internal div, preventing horizontal growth. --- src/components/ui/scroll-area.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/ui/scroll-area.tsx b/src/components/ui/scroll-area.tsx index 367857e..2f6b2bb 100644 --- a/src/components/ui/scroll-area.tsx +++ b/src/components/ui/scroll-area.tsx @@ -24,6 +24,7 @@ function ScrollArea({ className={cn( "focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1", viewportClassName, + "*:!block", // Targets the internal div directly and forces block behavior instead of table to prevent horizantal growth )} > {children} From 7ddf4a180924ec0553a1a44d329f5f46b3acee36 Mon Sep 17 00:00:00 2001 From: Kareem Mazen Yaqoup <117186053+engkareeem@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:33:00 +0300 Subject: [PATCH 02/49] Refactor FloatingWorkflowGen component by replacing ScrollArea with a div for improved layout control and overflow handling. --- src/components/workflow/floating-workflow-gen.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/workflow/floating-workflow-gen.tsx b/src/components/workflow/floating-workflow-gen.tsx index 5617fb0..060d3dd 100644 --- a/src/components/workflow/floating-workflow-gen.tsx +++ b/src/components/workflow/floating-workflow-gen.tsx @@ -5,7 +5,6 @@ import { AlertCircle } from "lucide-react"; import { cn } from "@/lib/utils"; import { Textarea } from "@/components/ui/textarea"; import { Label } from "@/components/ui/label"; -import { ScrollArea } from "@/components/ui/scroll-area"; import UnsavedChangesDialog from "./unsaved-changes-dialog"; import { FloatingWorkflowGenActionsRow } from "./floating-workflow-gen/actions-row"; import { FloatingWorkflowGenCollapsedStatus } from "./floating-workflow-gen/collapsed-status"; @@ -250,7 +249,7 @@ export default function FloatingWorkflowGen() { /> - +
{/* ── Connection warning ──────────────────────────────── */} {!isConnected && ( @@ -338,7 +337,7 @@ export default function FloatingWorkflowGen() { onGenerate={handleGenerate} />
- +
)} From 0a922340302d1ac9c92968857d907818f181a0c3 Mon Sep 17 00:00:00 2001 From: Kareem Mazen Yaqoup <117186053+engkareeem@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:37:59 +0300 Subject: [PATCH 03/49] Fix ParallelAgentNode instruction displaying --- src/nodes/parallel-agent/node.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nodes/parallel-agent/node.tsx b/src/nodes/parallel-agent/node.tsx index 167e5ed..3f7aaf1 100644 --- a/src/nodes/parallel-agent/node.tsx +++ b/src/nodes/parallel-agent/node.tsx @@ -67,8 +67,8 @@ export const ParallelAgentNode = memo(function ParallelAgentNode({ id, data, sel >
{data.sharedInstructions?.trim() && ( -
- {truncate(data.sharedInstructions.trim(), 140)} +
+ {data.sharedInstructions.trim()}
)} From 4eb2f0f1937121f06aa8f24e6eabbb3add643733 Mon Sep 17 00:00:00 2001 From: Kareem Mazen Yaqoup <117186053+engkareeem@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:44:58 +0300 Subject: [PATCH 04/49] Refactor layout in FloatingWorkflowGen component by consolidating class names for improved styling consistency. --- src/components/workflow/floating-workflow-gen.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/workflow/floating-workflow-gen.tsx b/src/components/workflow/floating-workflow-gen.tsx index 060d3dd..b802284 100644 --- a/src/components/workflow/floating-workflow-gen.tsx +++ b/src/components/workflow/floating-workflow-gen.tsx @@ -249,8 +249,7 @@ export default function FloatingWorkflowGen() { />
-
-
+
{/* ── Connection warning ──────────────────────────────── */} {!isConnected && (
@@ -337,7 +336,6 @@ export default function FloatingWorkflowGen() { onGenerate={handleGenerate} />
-
)}
From 085d0a8d2dffc430b59cfb097e470373ff5460d8 Mon Sep 17 00:00:00 2001 From: Kareem Mazen Yaqoup <117186053+engkareeem@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:54:15 +0300 Subject: [PATCH 05/49] chore: add husky for pre-commit checks and update dependencies - Added husky to manage pre-commit hooks. - Created a pre-commit hook to run checks before commits. - Updated package.json to include husky as a dependency. --- .husky/pre-commit | 1 + bun.lock | 3 +++ package.json | 6 +++--- 3 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 .husky/pre-commit diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..4408be2 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +bun run check diff --git a/bun.lock b/bun.lock index d0630dd..45b9776 100644 --- a/bun.lock +++ b/bun.lock @@ -46,6 +46,7 @@ "bun-types": "^1.3.10", "eslint": "^9", "eslint-config-next": "16.1.7", + "husky": "^9.1.7", "shadcn": "^3.8.5", "tailwindcss": "^4", "tw-animate-css": "^1.4.0", @@ -1036,6 +1037,8 @@ "human-signals": ["human-signals@8.0.1", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="], + "husky": ["husky@9.1.7", "", { "bin": { "husky": "bin.js" } }, "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA=="], + "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], diff --git a/package.json b/package.json index 6638dcd..b2eec5c 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "check": "bun run typecheck && bun run lint && bun run test", "docker:up": "docker compose up --build", "docker:bun": "docker compose up --build", - "docker:down": "docker compose down" + "docker:down": "docker compose down", + "prepare": "husky" }, "dependencies": { "@dagrejs/dagre": "^2.0.4", @@ -52,8 +53,6 @@ "react-simple-code-editor": "^0.14.1", "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", - "@hocuspocus/provider": "^3.4.4", - "@hocuspocus/server": "^3.4.4", "yjs": "^13.6.30", "zod": "^4.3.6", "zundo": "^2.3.0", @@ -69,6 +68,7 @@ "bun-types": "^1.3.10", "eslint": "^9", "eslint-config-next": "16.1.7", + "husky": "^9.1.7", "shadcn": "^3.8.5", "tailwindcss": "^4", "tw-animate-css": "^1.4.0", From ad43fedefcdfc244b60ffe77857ccc3a8f9a0a4b Mon Sep 17 00:00:00 2001 From: Kareem Mazen Yaqoup <117186053+engkareeem@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:58:18 +0300 Subject: [PATCH 06/49] chore: enhance pre-commit hook with git stash functionality - Added git stash commands to save and restore changes during pre-commit checks. - Ensured that the exit code from the checks is preserved for proper error handling. --- .husky/pre-commit | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.husky/pre-commit b/.husky/pre-commit index 4408be2..16c317a 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1,8 @@ +git stash push --keep-index --include-untracked -m "pre-commit-stash" + bun run check +EXIT_CODE=$? + +git stash pop + +exit $EXIT_CODE From ccb41817dc9f3646ae940f0a3707dc12e2381b3a Mon Sep 17 00:00:00 2001 From: Kareem Mazen Yaqoup <117186053+engkareeem@users.noreply.github.com> Date: Sat, 18 Apr 2026 18:00:47 +0300 Subject: [PATCH 07/49] chore: improve pre-commit hook with additional checks and messaging - Added a condition to skip checks if no changes are staged. - Enhanced user feedback during the pre-commit process with clear messages for stashing, running checks, and restoring changes. - Ensured that the commit is blocked if any checks fail, providing better error handling.est --- .husky/pre-commit | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index 16c317a..c221265 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,8 +1,22 @@ +if git diff --cached --quiet; then + echo "No staged changes. Skipping checks." + exit 0 +fi + +echo "Stashing unstaged changes..." git stash push --keep-index --include-untracked -m "pre-commit-stash" +echo "Running checks (typecheck + lint + tests)..." bun run check EXIT_CODE=$? -git stash pop +echo "Restoring unstaged changes..." +git stash pop -q + +if [ $EXIT_CODE -ne 0 ]; then + echo "Pre-commit checks failed. Commit blocked." +else + echo "All checks passed. Proceeding with commit." +fi exit $EXIT_CODE From 8ab83f6e0c4186f8a7047332adc089b24dd9fc6b Mon Sep 17 00:00:00 2001 From: Kareem Mazen Yaqoup <117186053+engkareeem@users.noreply.github.com> Date: Sat, 18 Apr 2026 18:07:19 +0300 Subject: [PATCH 08/49] chore: refine pre-commit hook with improved cleanup logic - Introduced a cleanup function to restore unstaged changes after pre-commit checks. - Added a flag to track whether changes were stashed, enhancing the reliability of the process. - Improved messaging for better user feedback during the pre-commit workflow. --- .husky/pre-commit | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index c221265..0277d9e 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -3,15 +3,27 @@ if git diff --cached --quiet; then exit 0 fi +STASHED=0 + +cleanup() { + if [ $STASHED -eq 1 ]; then + echo "Restoring unstaged changes..." + git stash pop -q + STASHED=0 + fi +} + +trap cleanup EXIT INT TERM + echo "Stashing unstaged changes..." git stash push --keep-index --include-untracked -m "pre-commit-stash" +STASHED=1 echo "Running checks (typecheck + lint + tests)..." bun run check EXIT_CODE=$? -echo "Restoring unstaged changes..." -git stash pop -q +cleanup if [ $EXIT_CODE -ne 0 ]; then echo "Pre-commit checks failed. Commit blocked." From d88a269208b95dc43f706bd72ca2415e2c9f1deb Mon Sep 17 00:00:00 2001 From: Kareem Mazen Yaqoup <117186053+engkareeem@users.noreply.github.com> Date: Sat, 18 Apr 2026 18:17:49 +0300 Subject: [PATCH 09/49] chore: enhance pre-commit hook with completion message - Added a message to indicate the completion of checks in the pre-commit hook. - Improved user feedback during the pre-commit process for better clarity. --- .husky/pre-commit | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.husky/pre-commit b/.husky/pre-commit index 0277d9e..f66484e 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -21,6 +21,8 @@ STASHED=1 echo "Running checks (typecheck + lint + tests)..." bun run check +echo "Finished running checks." + EXIT_CODE=$? cleanup From 71ce8b2acf089643c0e50b60adf7fbfa5fad70bf Mon Sep 17 00:00:00 2001 From: Nasr Shaer Date: Sun, 19 Apr 2026 14:55:58 +0300 Subject: [PATCH 10/49] Add `/graphify-out` to `.gitignore` for excluding new output directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1c8bd7c..1f832c5 100644 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,4 @@ _workspace # Local runtime data stores (Brain / collab) /.nexus-brain/ /.nexus-collab/ +/graphify-out From 504ebba7847c350d413935f9d234db9dc0150a0d Mon Sep 17 00:00:00 2001 From: Nasr Shaer Date: Sun, 19 Apr 2026 15:00:28 +0300 Subject: [PATCH 11/49] Add model mapping for `claude-code` frontmatter in agent generator logic --- src/nodes/agent/generator.ts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/nodes/agent/generator.ts b/src/nodes/agent/generator.ts index 9f809cc..691c396 100644 --- a/src/nodes/agent/generator.ts +++ b/src/nodes/agent/generator.ts @@ -12,6 +12,21 @@ import { import type { SubAgentNodeData } from "./types"; import { SubAgentModel, SubAgentMemory } from "./types"; +/** + * Claude Code's `.claude/agents/*.md` frontmatter expects the short names + * `sonnet`, `opus`, `haiku`, or `inherit` — not the provider-prefixed ids + * (e.g. `github-copilot/claude-sonnet-4.6`) used elsewhere in the app. + * Returns null when the model can't be mapped to a Claude Code tier + * (non-Claude models) so the caller can omit the line. + */ +function mapModelForClaudeCode(model: string): string | null { + const lower = model.toLowerCase(); + if (lower.includes("haiku")) return "haiku"; + if (lower.includes("opus")) return "opus"; + if (lower.includes("sonnet")) return "sonnet"; + return null; +} + /** * Build the frontmatter + prompt content for a .opencode/agents/.md file. */ @@ -31,7 +46,12 @@ export function buildAgentFile( lines.push(`hidden: true`); if (d.model && d.model !== SubAgentModel.Inherit) { - lines.push(`model: ${d.model}`); + if (target === "claude-code") { + const mapped = mapModelForClaudeCode(d.model); + if (mapped) lines.push(`model: ${mapped}`); + } else { + lines.push(`model: ${d.model}`); + } } if (d.memory && d.memory !== SubAgentMemory.Default) { From 14a2a100f76354681bf3fb1a1e6f7f8afab427cb Mon Sep 17 00:00:00 2001 From: Nasr Shaer Date: Sun, 19 Apr 2026 15:26:15 +0300 Subject: [PATCH 12/49] Add `_workspace*` to `.gitignore` for excluding workspace-related directories --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1f832c5..3e0aba4 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,4 @@ _workspace /.nexus-brain/ /.nexus-collab/ /graphify-out +_workspace* From 2dabe5c9283022bb1dbc9486e787e837de821c54 Mon Sep 17 00:00:00 2001 From: Nasr Shaer Date: Sun, 19 Apr 2026 15:29:27 +0300 Subject: [PATCH 13/49] Introduce Edit mode in workflow generation with toggle support, tests, and AI-assisted editing logic. --- .../workflow/floating-workflow-gen.tsx | 67 ++++++++++++-- .../floating-workflow-gen/actions-row.tsx | 6 +- .../collapsed-status.tsx | 6 +- .../workflow/floating-workflow-gen/header.tsx | 6 +- .../floating-workflow-gen/mode-toggle.tsx | 61 +++++++++++++ .../workflow-gen/edit-message.test.ts | 88 +++++++++++++++++++ src/store/__tests__/workflow-gen/mode.test.ts | 43 +++++++++ .../workflow-gen/system-prompt.test.ts | 23 +++++ src/store/workflow-gen/edit-message.ts | 35 ++++++++ src/store/workflow-gen/index.ts | 5 +- src/store/workflow-gen/system-prompt.ts | 16 +++- src/store/workflow-gen/types.ts | 6 ++ src/store/workflow-gen/workflow-generator.ts | 43 +++++++-- 13 files changed, 383 insertions(+), 22 deletions(-) create mode 100644 src/components/workflow/floating-workflow-gen/mode-toggle.tsx create mode 100644 src/store/__tests__/workflow-gen/edit-message.test.ts create mode 100644 src/store/__tests__/workflow-gen/mode.test.ts create mode 100644 src/store/__tests__/workflow-gen/system-prompt.test.ts create mode 100644 src/store/workflow-gen/edit-message.ts diff --git a/src/components/workflow/floating-workflow-gen.tsx b/src/components/workflow/floating-workflow-gen.tsx index b802284..5b7f5fa 100644 --- a/src/components/workflow/floating-workflow-gen.tsx +++ b/src/components/workflow/floating-workflow-gen.tsx @@ -14,6 +14,7 @@ import { } from "./floating-workflow-gen/constants"; import { FloatingWorkflowGenExamplesSection } from "./floating-workflow-gen/examples-section"; import { FloatingWorkflowGenHeader } from "./floating-workflow-gen/header"; +import { FloatingWorkflowGenModeToggle } from "./floating-workflow-gen/mode-toggle"; import { FloatingWorkflowGenProjectContextToggle } from "./floating-workflow-gen/project-context-toggle"; import { FloatingWorkflowGenStatusPanel } from "./floating-workflow-gen/status-panel"; import { useFloatingWorkflowGenPosition } from "./floating-workflow-gen/use-floating-workflow-gen-position"; @@ -22,6 +23,7 @@ import { useOpenCodeStore } from "@/store/opencode"; import { useWorkflowStore } from "@/store/workflow"; import { useModels } from "@/hooks/use-models"; import { ModelSelect } from "@/nodes/shared/model-select"; +import { WorkflowNodeType } from "@/types/workflow"; import { toast } from "sonner"; @@ -33,6 +35,7 @@ export default function FloatingWorkflowGen() { const floating = useWorkflowGenStore((s) => s.floating); const collapsed = useWorkflowGenStore((s) => s.collapsed); const status = useWorkflowGenStore((s) => s.status); + const mode = useWorkflowGenStore((s) => s.mode); const prompt = useWorkflowGenStore((s) => s.prompt); const selectedModel = useWorkflowGenStore((s) => s.selectedModel); const parsedNodeCount = useWorkflowGenStore((s) => s.parsedNodeCount); @@ -42,6 +45,7 @@ export default function FloatingWorkflowGen() { const setPrompt = useWorkflowGenStore((s) => s.setPrompt); const setSelectedModel = useWorkflowGenStore((s) => s.setSelectedModel); + const setMode = useWorkflowGenStore((s) => s.setMode); const generate = useWorkflowGenStore((s) => s.generate); const cancel = useWorkflowGenStore((s) => s.cancel); const reset = useWorkflowGenStore((s) => s.reset); @@ -63,6 +67,17 @@ export default function FloatingWorkflowGen() { const isConnected = connectionStatus === "connected"; const currentProject = useOpenCodeStore((s) => s.currentProject); const needsSave = useWorkflowStore((s) => s.needsSave); + const workflowNodes = useWorkflowStore((s) => s.nodes); + const workflowEdges = useWorkflowStore((s) => s.edges); + + // The canvas has "user content" when it holds anything beyond the default + // start + end pair (or any edges). Edit mode is only useful in that case. + const hasContent = useMemo(() => { + const hasExtraNode = workflowNodes.some( + (n) => n.data?.type !== WorkflowNodeType.Start && n.data?.type !== WorkflowNodeType.End, + ); + return hasExtraNode || workflowEdges.length > 0; + }, [workflowNodes, workflowEdges]); const { groups } = useModels(); @@ -141,13 +156,26 @@ export default function FloatingWorkflowGen() { } }, [floating, collapsed]); + // If the panel opens on an empty canvas while Edit is selected, snap back + // to Generate. We do NOT auto-flip to Edit when content appears. + useEffect(() => { + if (floating && !hasContent && mode === "edit") { + setMode("generate"); + } + }, [floating, hasContent, mode, setMode]); + const runGenerate = useCallback(async () => { // Auto-collapse when generation starts so the user sees the canvas useWorkflowGenStore.setState({ collapsed: true }); + const startingMode = useWorkflowGenStore.getState().mode; await generate(); const newStatus = useWorkflowGenStore.getState().status; if (newStatus === "done") { - toast.success("Workflow generated successfully!"); + toast.success( + startingMode === "edit" + ? "Workflow edited successfully!" + : "Workflow generated successfully!", + ); } }, [generate]); @@ -206,6 +234,7 @@ export default function FloatingWorkflowGen() { isDone={isDone} tokenCount={tokenCount} parsedNodeCount={parsedNodeCount} + mode={mode} onToggleCollapsed={() => { toggleCollapsed(); requestAnimationFrame(() => resetPosition()); @@ -217,9 +246,17 @@ export default function FloatingWorkflowGen() { { void runGenerate(); }} @@ -233,6 +270,7 @@ export default function FloatingWorkflowGen() { isError={isError} tokenCount={tokenCount} parsedNodeCount={parsedNodeCount} + mode={mode} /> )} @@ -276,22 +314,36 @@ export default function FloatingWorkflowGen() { /> )} + {/* ── Mode toggle (Generate / Edit) ──────────────────── */} + + {/* ── Prompt input ───────────────────────────────────── */}