diff options
| author | soryu <soryu@soryu.co> | 2026-04-28 21:26:11 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-28 21:26:11 +0100 |
| commit | 5bde7c2d7e099fd9c8b2615602ab1d096bd9b6be (patch) | |
| tree | d605f7c02472f67a88f1c71c9258c1bf0823b44a /frontend/src/components/document/nodes/StepsDiagramComponent.tsx | |
| parent | d1fdfb140cc440664f77a24886172f9976a05a31 (diff) | |
| download | soryu-5bde7c2d7e099fd9c8b2615602ab1d096bd9b6be.tar.gz soryu-5bde7c2d7e099fd9c8b2615602ab1d096bd9b6be.zip | |
revert PRs #93-#98; enforce strict-linear-DAG + mandatory directive verify (#100)
* revert: roll back PRs #93-#98 to pre-Lexical baseline
Reverts the entire chain of directive document UI work and the homepage redesign,
restoring the working tree to the state at 3679ceb (before c8b169d / PR #93).
PRs reverted:
- #93 c8b169d feat: Document UI for directive orchestration with Lexical editor
- #94 d6f01a6 fix: compilation error and warnings already merged via PR #93
- #95 5aa3faf fix: resolve compilation error and warnings in Rust backend
- #97 d513f93 feat: document UI with contract blocks, expandable logs, and interaction controls
- #96 6366941 feat: Redesign homepage with professional PC-98 styling
- #98 d1fdfb1 feat: revert broken directive PRs, re-implement Lexical document orchestrator
The directive Document UI experiments produced fragile output and merge artifacts;
follow-up commits in this PR change orchestration to favor strictly linear DAGs and
add goal/conflict verification so future runs do not require this kind of cleanup.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(directive): strict-linear-DAG planning + mandatory `directive verify`
Tightens directive orchestration so the final PR almost never needs a hand-merge:
1. Planning prompts now strongly bias toward strictly linear DAGs.
Parallel steps are reserved for genuinely independent work (e.g. disjoint
modules); the default for "in doubt" is sequential. Linear chains inherit
each previous step's worktree, so the final merge is typically just a
rebase against the base branch.
2. New CLI command `makima directive verify` does a local in-memory
`git merge-tree` of HEAD against `<remote>/<base>` and exits non-zero
with a list of conflicting files if the PR would not merge cleanly.
Pure-local — no API call, no working-tree mutation.
3. Completion / PR-creation prompts now mandate three pre-push checks:
a. build (`cargo check` and/or `tsc --noEmit`),
b. `makima directive verify --base <base_branch>` must exit 0, and
c. an explicit goal-alignment self-check against the diff.
The orchestrator is told NOT to push, create the PR, or call
`makima directive update` until all three pass. Skipping any of them
is documented as a directive failure.
The combination means that with a linear DAG the final PR-creation task
should almost never see a real conflict — when it does, that is treated as
a planning bug to escalate rather than something to paper over with
`-X theirs`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(frontend): TS errors pre-existing on master
- TaskSlideOutPanel: declare missing `selectedFileDiff` / `selectedFilePath`
state hooks that were referenced everywhere but never created, and
re-balance the JSX so the `<>...</>` fragment in the non-diff branch is
closed (the previous indentation/braces would not parse).
- api.ts: add a `getWorktreeDiff` thin wrapper around `getTaskDiff` so
TaskDetail's per-file click handler type-checks (the per-file slice is a
future improvement; today both return the full task diff).
- WorktreeFilesPanel: remove unused `isClickable` local; the gating already
reads `onFileClick` directly inline.
Run after revert: `npx tsc --noEmit` exits 0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'frontend/src/components/document/nodes/StepsDiagramComponent.tsx')
| -rw-r--r-- | frontend/src/components/document/nodes/StepsDiagramComponent.tsx | 239 |
1 files changed, 0 insertions, 239 deletions
diff --git a/frontend/src/components/document/nodes/StepsDiagramComponent.tsx b/frontend/src/components/document/nodes/StepsDiagramComponent.tsx deleted file mode 100644 index ac1cb83..0000000 --- a/frontend/src/components/document/nodes/StepsDiagramComponent.tsx +++ /dev/null @@ -1,239 +0,0 @@ -import React, { useEffect, useState, useRef, useCallback } from 'react'; -import { getDirective, DirectiveStep, DirectiveWithSteps } from '../../../services/directiveApi'; -import { StepLogFeed } from './StepLogFeed'; -import './StepsDiagram.css'; - -interface StepsDiagramComponentProps { - directiveId: string; - onExpandContract?: (step: DirectiveStep) => void; -} - -type StepStatus = 'pending' | 'ready' | 'running' | 'completed' | 'failed' | 'skipped'; - -const STATUS_LABELS: Record<string, string> = { - pending: 'Queued', - ready: 'Ready', - running: 'Executing', - completed: 'Fulfilled', - failed: 'Failed', - skipped: 'Skipped', -}; - -function formatTime(dateStr: string): string { - if (!dateStr) return ''; - const d = new Date(dateStr); - return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); -} - -interface StepCardProps { - step: DirectiveStep; - isExpanded: boolean; - onToggleExpand: () => void; - onCollapse: () => void; -} - -function StepCard({ step, isExpanded, onToggleExpand, onCollapse }: StepCardProps) { - const status = (step.status || 'pending').toLowerCase() as StepStatus; - const hasTask = !!step.taskId || !!step.contractId; - const canExpand = hasTask && ['running', 'completed', 'failed'].includes(status); - - return ( - <div className={`steps-diagram-card steps-diagram-card--${status} ${isExpanded ? 'steps-diagram-card--expanded' : ''}`}> - <div - className={`steps-diagram-card-header ${canExpand ? 'steps-diagram-card-header--clickable' : ''}`} - onClick={canExpand ? onToggleExpand : undefined} - role={canExpand ? 'button' : undefined} - tabIndex={canExpand ? 0 : undefined} - onKeyDown={canExpand ? (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onToggleExpand(); } } : undefined} - > - <span className="steps-diagram-card-name">{step.name}</span> - <div className="steps-diagram-card-header-right"> - <span className={`steps-diagram-status-badge steps-diagram-status-badge--${status}`}> - {STATUS_LABELS[status] || status} - </span> - {canExpand && ( - <span className={`steps-diagram-expand-icon ${isExpanded ? 'expanded' : ''}`}> - ▶ - </span> - )} - </div> - </div> - {step.description && !isExpanded && ( - <p className="steps-diagram-card-desc">{step.description}</p> - )} - <div className="steps-diagram-card-footer"> - <span className="steps-diagram-card-index">#{step.orderIndex}</span> - {status === 'running' && ( - <span className="steps-diagram-card-progress">In progress...</span> - )} - {status === 'completed' && step.completedAt && ( - <span className="steps-diagram-card-time"> - Completed {formatTime(step.completedAt)} - </span> - )} - </div> - - {/* Expandable log feed */} - {isExpanded && hasTask && ( - <StepLogFeed - taskId={step.taskId || step.contractId} - stepName={step.name} - stepStatus={status} - onCollapse={onCollapse} - /> - )} - </div> - ); -} - -export function StepsDiagramComponent({ directiveId, onExpandContract }: StepsDiagramComponentProps) { - const [steps, setSteps] = useState<DirectiveStep[]>([]); - const [directiveStatus, setDirectiveStatus] = useState<string>(''); - const [loading, setLoading] = useState(true); - const [error, setError] = useState<string | null>(null); - const [expandedStepId, setExpandedStepId] = useState<string | null>(null); - const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null); - const prevStepCountRef = useRef(0); - - const fetchSteps = useCallback(async () => { - try { - const data: DirectiveWithSteps = await getDirective(directiveId); - setSteps(data.steps || []); - setDirectiveStatus(data.status || ''); - setError(null); - } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to load contracts'); - } finally { - setLoading(false); - } - }, [directiveId]); - - useEffect(() => { - fetchSteps(); - intervalRef.current = setInterval(fetchSteps, 5000); - return () => { - if (intervalRef.current) clearInterval(intervalRef.current); - }; - }, [fetchSteps]); - - // Track when new steps appear for animation - useEffect(() => { - prevStepCountRef.current = steps.length; - }, [steps.length]); - - // Keyboard shortcut: Escape to collapse expanded step - useEffect(() => { - const handler = (e: KeyboardEvent) => { - if (e.key === 'Escape' && expandedStepId) { - setExpandedStepId(null); - } - }; - document.addEventListener('keydown', handler); - return () => document.removeEventListener('keydown', handler); - }, [expandedStepId]); - - const toggleExpand = useCallback((stepId: string) => { - setExpandedStepId(prev => prev === stepId ? null : stepId); - }, []); - - const collapseExpanded = useCallback(() => { - setExpandedStepId(null); - }, []); - - const completedCount = steps.filter(s => s.status?.toLowerCase() === 'completed').length; - const totalCount = steps.length; - const isActive = ['active', 'running', 'planning'].includes(directiveStatus.toLowerCase()); - const isBuilding = isActive && steps.length === 0; - - // Group steps by orderIndex - const groupedSteps: Map<number, DirectiveStep[]> = new Map(); - const sortedSteps = [...steps].sort((a, b) => a.orderIndex - b.orderIndex); - for (const step of sortedSteps) { - const idx = step.orderIndex; - if (!groupedSteps.has(idx)) groupedSteps.set(idx, []); - groupedSteps.get(idx)!.push(step); - } - const orderGroups = Array.from(groupedSteps.entries()).sort((a, b) => a[0] - b[0]); - - if (loading) { - return ( - <div className="steps-diagram" contentEditable={false}> - <div className="steps-diagram-header"> - <span className="steps-diagram-header-title">Contract Steps</span> - <span className="steps-diagram-header-author">Authored by Makima</span> - </div> - <div className="steps-diagram-loading"> - <div className="steps-diagram-spinner" /> - <span>Loading contracts...</span> - </div> - </div> - ); - } - - if (error) { - return ( - <div className="steps-diagram" contentEditable={false}> - <div className="steps-diagram-header"> - <span className="steps-diagram-header-title">Contract Steps</span> - <span className="steps-diagram-header-author">Authored by Makima</span> - </div> - <div className="steps-diagram-error">Failed to load contracts: {error}</div> - </div> - ); - } - - return ( - <div className={`steps-diagram ${expandedStepId ? 'steps-diagram--has-expanded' : ''}`} contentEditable={false}> - <div className="steps-diagram-header"> - <div className="steps-diagram-header-left"> - <span className="steps-diagram-header-title">Contract Steps</span> - {totalCount > 0 && ( - <span className="steps-diagram-header-count"> - {completedCount}/{totalCount} fulfilled - </span> - )} - </div> - <span className="steps-diagram-header-author">Authored by Makima</span> - </div> - - {isBuilding && ( - <div className="steps-diagram-planning"> - <div className="steps-diagram-planning-dots"> - <span /><span /><span /> - </div> - <span>Makima is drafting contracts...</span> - </div> - )} - - {totalCount === 0 && !isBuilding && ( - <div className="steps-diagram-empty">No contract steps defined yet.</div> - )} - - {totalCount > 0 && ( - <div className="steps-diagram-dag"> - {orderGroups.map(([orderIndex, groupSteps], groupIdx) => ( - <React.Fragment key={orderIndex}> - {groupIdx > 0 && ( - <div className="steps-diagram-arrow"> - <div className="steps-diagram-arrow-line" /> - <div className="steps-diagram-arrow-head" /> - </div> - )} - <div className="steps-diagram-group"> - {groupSteps.map((step) => ( - <StepCard - key={step.id} - step={step} - isExpanded={expandedStepId === step.id} - onToggleExpand={() => toggleExpand(step.id)} - onCollapse={collapseExpanded} - /> - ))} - </div> - </React.Fragment> - ))} - </div> - )} - </div> - ); -} |
