diff --git a/apps/web/src/components/slice-one/slice-one-page.tsx b/apps/web/src/components/slice-one/slice-one-page.tsx deleted file mode 100644 index 019ce87..0000000 --- a/apps/web/src/components/slice-one/slice-one-page.tsx +++ /dev/null @@ -1,887 +0,0 @@ -import { projectWorkNotices } from "@code/primitives/work"; -import { - Conversation, - ConversationContent, -} from "@code/ui/components/ai-elements/conversation"; -import { Button } from "@code/ui/components/button"; -import { - AlertTriangle, - ChevronRight, - Check, - FileCode2, - FolderGit2, - Hammer, - LoaderCircle, - Menu, - MessageSquareText, - ImagePlus, - Play, - RotateCcw, - ScrollText, - Send, - Sparkles, - Settings, - X, -} from "lucide-react"; -import { useMemo, useRef, useState } from "react"; - -import { PendingChatAttachments } from "@/components/chat/chat-attachments"; -import { ChatMessage } from "@/components/chat/chat-message"; -import { ChatThinkingResponse } from "@/components/chat/chat-thinking-response"; -import { useChatImages } from "@/hooks/chat/use-chat-images"; -import { useSliceOne } from "@/hooks/slice-one/use-slice-one"; -import { useVisualViewportStyle } from "@/hooks/slice-one/use-visual-viewport"; -import { - buildSliceOneTimeline, - findSourceMessageTarget, -} from "@/lib/slice-one/presentation"; - -type SliceWork = NonNullable["works"]>[number]; -const EMPTY_WORKS: readonly SliceWork[] = []; - -type SliceArtifact = NonNullable< - NonNullable[number] ->; - -interface ArtifactMetadata { - readonly changedFiles?: readonly string[]; -} - -const parseArtifactMetadata = (artifact: SliceArtifact): ArtifactMetadata => { - if (!artifact.metadataJson) { - return {}; - } - try { - return JSON.parse(artifact.metadataJson) as ArtifactMetadata; - } catch { - return {}; - } -}; - -const changedFilesFor = (artifact: SliceArtifact): readonly string[] => - parseArtifactMetadata(artifact).changedFiles ?? []; - -interface WorkCardProps { - readonly onSourceSelect: (rawText: string) => void; - readonly work: SliceWork; - readonly slice: SliceOneState; -} - -const starterDefinition = (work: SliceWork) => ({ - acceptanceCriteria: ["The requested outcome is observable and documented"], - affectedUsers: ["Project users"], - assumptions: [], - constraints: [], - desiredOutcome: work.objective, - inScope: [work.objective], - outOfScope: ["Unrelated product changes"], - problem: work.objective, - questions: [], - requiredArtifacts: ["Simulation activity and terminal outcome"], - risk: "medium", -}); - -const starterDesign = (work: SliceWork) => ({ - architectureSummary: - "Validate the approved Definition, then exercise one deterministic fake slice.", - callFlowDelta: [ - "Work -> Run -> Attempt -> normalized events -> terminal outcome", - ], - concerns: [], - evidenceRequirements: ["Terminal Run classification"], - fileTreeDelta: [], - impactMap: { - files: [], - modules: [], - risks: [], - summary: "Compact vertical-slice simulation", - }, - invariants: [ - "Simulation never claims implementation", - "Every Attempt reaches a terminal classification", - ], - keyInterfaces: ["HarnessRuntime", "AttemptOutcome"], - slices: [ - { - codeBoundaries: ["workExecution"], - dependsOn: [], - evidenceRequirements: ["Normalized activity events"], - id: "slice-1", - objective: work.objective, - observableBehavior: "A terminal fake Run is visible", - reviewRequired: false, - title: "Deterministic simulation", - verification: ["Run completes with a terminal classification"], - }, - ], - tradeoffs: ["Fake runtime proves contract before sandbox integration"], -}); - -// oxlint-disable-next-line complexity -- the expanded card intentionally keeps the three review sections together. -const WorkCard = ({ onSourceSelect, work, slice }: WorkCardProps) => { - const [sourcesOpen, setSourcesOpen] = useState(false); - const [expanded, setExpanded] = useState(false); - const [logsOpen, setLogsOpen] = useState(false); - const sources = work.signals.flatMap((signal) => signal.sources); - const { definition } = work; - const { design } = work; - const [latestRun] = work.runs; - return ( -
-
- - - -
-

- Proposed Work -

-

- {work.title} -

-

- {work.objective} -

-
-
- - - {sourcesOpen ? ( -
- {sources.map((source) => ( - - ))} -
- ) : null} - {expanded ? ( -
-
-

- Outcome -

-

{work.objective}

-

- Risk: {definition?.risk ?? "not defined"} -

- {definition?.questions?.length ? ( -

- { - definition.questions.filter( - (question) => question.status === "open" - ).length - }{" "} - open question(s) -

- ) : null} -
- {work.status === "proposed" ? ( - - ) : null} - {work.status === "defining" ? ( - - ) : null} - {work.status === "awaiting-definition-approval" && - work.definitionVersion ? ( - - ) : null} -
-
-
-

- Design -

-

- {design?.architectureSummary ?? "No Design Packet yet."} -

- {design?.slices?.map((item) => ( -

- {item.title}: {item.observableBehavior} -

- ))} -
- {work.status === "designing" ? ( - - ) : null} - {work.status === "awaiting-design-approval" && - work.definitionApprovalVersion && - work.designVersion ? ( - - ) : null} -
-
-
-

- Build -

- {slice.operationError ? ( -

- - - {slice.operationError.message} - - -

- ) : null} - {latestRun ? ( -
-

- {latestRun.executionKind === "real" - ? "AgentOS" - : "Simulation"}{" "} - run {latestRun.status}:{" "} - {latestRun.terminalSummary ?? - latestRun.terminalClassification ?? - "activity is still arriving"} -

- {latestRun.baseRevision ? ( -

- {latestRun.baseRevision.slice(0, 8)} →{" "} - {latestRun.candidateRevision?.slice(0, 8) ?? "working"} -

- ) : null} - {latestRun.artifacts?.map((artifact) => { - const changedFiles = changedFilesFor(artifact); - return ( -
- {artifact.uri ? ( - - {artifact.title} - - ) : ( -

{artifact.title}

- )} - {changedFiles.length > 0 ? ( -
    - {changedFiles.map((file) => ( -
  • - - {file} -
  • - ))} -
- ) : null} -
- ); - })} - {latestRun.attemptEvents && - latestRun.attemptEvents.length > 0 ? ( -
- {(logsOpen - ? latestRun.attemptEvents - : latestRun.attemptEvents.slice(-3) - ).map((item) => ( -

- {item.message} -

- ))} - {latestRun.attemptEvents.length > 3 ? ( - - ) : null} -
- ) : null} -
- ) : ( -

No implementation Run yet.

- )} -
- {work.status === "ready" ? ( - - ) : null} - {work.status === "ready" ? ( - - ) : null} - {latestRun?.status === "running" ? ( - - ) : null} - {latestRun?.executionKind !== "real" && - latestRun?.status === "terminal" && - latestRun.terminalClassification === "RetryableFailure" ? ( - - ) : null} -
-
-
- ) : null} -
- ); -}; - -const ConversationLoading = () => ( - - - - - Loading conversation… - -); - -const ConversationEmptyState = () => ( -
-
- -

What should move forward?

-

- Describe an outcome or problem. Casual conversation stays conversation. -

-
-
-); -type SliceOneState = ReturnType; - -const ProjectsLoading = () => ( -
- -
-); -const ConnectProject = ({ slice }: { slice: SliceOneState }) => ( -
-
{ - event.preventDefault(); - void slice.connectRepository(); - }} - > - - - -

Connect one project

-

- Slice 1 turns actionable conversation into proposed Work with exact - provenance. -

- slice.setRepository(event.target.value)} - placeholder="https://github.com/owner/repository" - required - value={slice.repository} - /> - {slice.error ? ( -

{slice.error.message}

- ) : null} - -
-
-); - -// oxlint-disable-next-line complexity -- this page coordinates the existing mobile shell without owning domain logic. -export const SliceOnePage = () => { - const slice = useSliceOne(); - const viewportStyle = useVisualViewportStyle(); - const [draft, setDraft] = useState(""); - const attachments = useChatImages(); - const imageInput = useRef(null); - const [drawerOpen, setDrawerOpen] = useState(false); - const [settingsOpen, setSettingsOpen] = useState(false); - const [giteaUrl, setGiteaUrl] = useState("https://git.openputer.com"); - const [giteaUsername, setGiteaUsername] = useState(""); - const [giteaToken, setGiteaToken] = useState(""); - const [highlightedMessageId, setHighlightedMessageId] = useState(); - const highlightTimer = useRef | null>(null); - const works = slice.works ?? EMPTY_WORKS; - const workById = useMemo( - () => new Map(works.map((work) => [String(work._id), work])), - [works] - ); - const notices = useMemo(() => projectWorkNotices(works), [works]); - const timeline = useMemo( - () => buildSliceOneTimeline(slice.agent.messages, notices), - [notices, slice.agent.messages] - ); - const busy = - slice.agent.status === "submitted" || slice.agent.status === "streaming"; - - const revealSourceMessage = (rawText: string) => { - const messageId = findSourceMessageTarget(slice.agent.messages, rawText); - if (!messageId) { - return; - } - setDrawerOpen(false); - setHighlightedMessageId(messageId); - if (highlightTimer.current) { - clearTimeout(highlightTimer.current); - } - requestAnimationFrame(() => { - document - .querySelector(`#${CSS.escape(`slice-message-${messageId}`)}`) - ?.scrollIntoView({ behavior: "smooth", block: "center" }); - }); - highlightTimer.current = setTimeout( - () => setHighlightedMessageId(undefined), - 1800 - ); - }; - - if (slice.projects === undefined) { - return ; - } - - if (!slice.selectedProject) { - return ; - } - - const send = async () => { - const message = draft.trim(); - if (!message || busy) { - return; - } - await slice.agent.sendMessage(message, { - images: attachments.images.map((image) => image.file), - }); - setDraft(""); - attachments.clear(); - }; - - return ( -
-
-
-
- -

- Conversation to proposed Work -

-
- - - {settingsOpen ? ( -
-
-

Project Git

- -
-

- {slice.projectGitConnection - ? `${slice.projectGitConnection.provider} · ${slice.projectGitConnection.serverUrl}` - : "No Git credentials attached"} -

- {slice.operationError ? ( -

- - - {slice.operationError.message} - - -

- ) : null} -
- - -
-
- setGiteaUrl(event.target.value)} - value={giteaUrl} - /> - setGiteaUsername(event.target.value)} - placeholder="Username (optional)" - value={giteaUsername} - /> - setGiteaToken(event.target.value)} - placeholder="Personal access token" - type="password" - value={giteaToken} - /> - -
-
- ) : null} -
- - - {!slice.agent.historyReady && timeline.length === 0 ? ( - - ) : null} - {slice.agent.historyReady && timeline.length === 0 ? ( - - ) : null} - {timeline.map((item) => { - if (item.kind === "work") { - const work = workById.get(item.notice.workId); - return work ? ( -
-

- Work proposed from this conversation -

- -
- ) : null; - } - return ( -
- -
- ); - })} - {slice.agent.status === "submitted" ? ( - - ) : null} -
-
-
- {attachments.images.length > 0 ? ( -
- -
- ) : null} - {slice.agent.error ? ( -

- {slice.agent.error.message} -

- ) : null} - {attachments.error ? ( -

- {attachments.error} -

- ) : null} -
- { - attachments.addFiles(event.target.files); - event.target.value = ""; - }} - ref={imageInput} - type="file" - /> - -