agent-session-replayer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +239 -0
- package/dist/chunk-QE3DOXM4.js +142 -0
- package/dist/chunk-QE3DOXM4.js.map +1 -0
- package/dist/index.cjs +573 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +427 -0
- package/dist/index.js.map +1 -0
- package/dist/schema.cjs +169 -0
- package/dist/schema.cjs.map +1 -0
- package/dist/schema.d.cts +67 -0
- package/dist/schema.d.ts +67 -0
- package/dist/schema.js +16 -0
- package/dist/schema.js.map +1 -0
- package/dist/styles.css +1 -0
- package/dist/types-DBa28H8n.d.cts +63 -0
- package/dist/types-DBa28H8n.d.ts +63 -0
- package/package.json +47 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/AgentSessionReplayer.tsx","../src/playback.ts","../src/validation.ts","../src/GitDiffBlock.tsx"],"sourcesContent":["export { AgentSessionReplayer } from \"./AgentSessionReplayer\";\nexport type {\n AgentActor,\n AgentBlockKind,\n AgentSessionBlock,\n AgentSession,\n AgentSessionColors,\n AgentSessionEvent,\n AgentSessionReplayerProps,\n AgentEventType,\n AgentIdentity,\n} from \"./types\";\n","import {\n type CSSProperties,\n useCallback,\n useEffect,\n useMemo,\n useReducer,\n useRef,\n useState,\n} from \"react\";\nimport { initialPlaybackState, playbackReducer, revealEvent } from \"./playback\";\nimport { parseReplayerProps } from \"./validation\";\nimport { GitDiffBlock } from \"./GitDiffBlock\";\nimport type {\n AgentActor,\n AgentSessionBlock,\n AgentSession,\n AgentSessionColors,\n AgentSessionEvent,\n AgentSessionReplayerProps,\n} from \"./types\";\n\nconst DEFAULT_TYPING_SPEED = 110;\nconst DEFAULT_EVENT_DELAY = 500;\nconst COLLAPSE_DURATION_MS = 220;\nconst COLLAPSE_EASING = \"cubic-bezier(0.23, 1, 0.32, 1)\";\n\nconst colorVariables: Record<keyof AgentSessionColors, string> = {\n background: \"--asr-background\",\n surface: \"--asr-surface\",\n border: \"--asr-border\",\n text: \"--asr-text\",\n muted: \"--asr-muted\",\n implementer: \"--asr-implementer\",\n reviewer: \"--asr-reviewer\",\n success: \"--asr-success\",\n danger: \"--asr-danger\",\n focus: \"--asr-focus\",\n};\n\nfunction usePrefersReducedMotion(): boolean {\n const [reduced, setReduced] = useState(false);\n useEffect(() => {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") return;\n const query = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n const update = () => setReduced(query.matches);\n update();\n query.addEventListener?.(\"change\", update);\n return () => query.removeEventListener?.(\"change\", update);\n }, []);\n return reduced;\n}\n\nfunction Agent({ actor, active, agent }: { actor: AgentActor; active: boolean; agent: AgentSessionReplayerProps[\"agents\"][AgentActor] }) {\n return <div className={`asr-agent asr-agent--${actor} ${active ? \"asr-is-active\" : \"\"}`}>\n <span className=\"asr-agent-avatar\" aria-hidden=\"true\">✣</span>\n <div><strong>{agent.name}</strong> <span>{agent.role}</span><p>its context: {agent.context}</p></div>\n </div>;\n}\n\nfunction Block({ block }: { block: AgentSessionBlock }) {\n const codeLike = block.kind === \"code\" || block.kind === \"patch\" || block.kind === \"tool_output\";\n return <section className={`asr-chat-block asr-chat-block--${block.kind}`}>\n {block.title && <header><span>{block.kind.replace(\"_\", \" \")}</span>{block.title}</header>}\n {block.kind === \"git_diff\"\n ? <GitDiffBlock content={block.content} />\n : codeLike\n ? <pre><code>{block.content}</code></pre>\n : <p>{block.content}</p>}\n </section>;\n}\n\nfunction ExpandedEvent({ event, visibleEvent, typing }: { event: AgentSessionEvent; visibleEvent: AgentSessionEvent; typing: boolean }) {\n return <article className={`asr-expanded-event asr-expanded-event--${event.actor}`} aria-label={event.title}>\n <div className=\"asr-event-heading\"><span>{event.actor === \"implementer\" ? \"✣ claude\" : \"adversarial reviewer ✣\"}</span><strong>{event.title}</strong></div>\n <div className=\"asr-blocks\">{visibleEvent.blocks.map((block) => <Block block={block} key={block.id} />)}</div>\n {typing && <span className=\"asr-typing-caret\" aria-hidden=\"true\" />}\n </article>;\n}\n\nfunction EventSummaryContent({ event, index }: { event: AgentSessionEvent; index: number }) {\n return <>\n <span>{String(index + 1).padStart(2, \"0\")}</span>\n <strong>{event.title}</strong>\n <p>{event.summary}</p>\n <span className=\"asr-disclosure\" aria-hidden=\"true\">⌄</span>\n </>;\n}\n\nfunction EventSummaryRow({ event, index, contentId, onToggle, className = \"\" }: {\n event: AgentSessionEvent;\n index: number;\n contentId: string;\n onToggle: () => void;\n className?: string;\n}) {\n return <button\n type=\"button\"\n className={`asr-event-summary-row asr-event-summary-row--${event.actor}${className ? ` ${className}` : \"\"}`}\n aria-expanded=\"false\"\n aria-controls={contentId}\n aria-label={`Expand ${event.title}`}\n onClick={onToggle}\n >\n <EventSummaryContent event={event} index={index} />\n </button>;\n}\n\nfunction CompletedEvent({ event, index, expanded, onToggle }: {\n event: AgentSessionEvent;\n index: number;\n expanded: boolean;\n onToggle: () => void;\n}) {\n const contentId = `asr-event-${event.id}`;\n if (!expanded) {\n return <div className=\"asr-completed-event\">\n <EventSummaryRow event={event} index={index} contentId={contentId} onToggle={onToggle} />\n <div id={contentId} hidden />\n </div>;\n }\n\n return <article className={`asr-expanded-event asr-expanded-event--${event.actor}`} aria-label={event.title}>\n <button\n type=\"button\"\n className=\"asr-expanded-toggle\"\n aria-expanded=\"true\"\n aria-controls={contentId}\n aria-label={`Collapse ${event.title}`}\n onClick={onToggle}\n >\n <span>{event.actor === \"implementer\" ? \"✣ claude\" : \"adversarial reviewer ✣\"}</span>\n <strong>{event.title}</strong>\n <span className=\"asr-disclosure\" aria-hidden=\"true\">⌃</span>\n </button>\n <div className=\"asr-blocks\" id={contentId}>{event.blocks.map((block) => <Block block={block} key={block.id} />)}</div>\n </article>;\n}\n\nfunction CollapsingEvent({\n event,\n index,\n reduceMotion,\n onComplete,\n}: {\n event: AgentSessionEvent;\n index: number;\n reduceMotion: boolean;\n onComplete: () => void;\n}) {\n const shellRef = useRef<HTMLDivElement>(null);\n const expandedRef = useRef<HTMLDivElement>(null);\n const summaryRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const shell = shellRef.current;\n const expanded = expandedRef.current;\n const summary = summaryRef.current;\n if (!shell || !expanded || !summary) return;\n if (reduceMotion || typeof shell.animate !== \"function\") {\n onComplete();\n return;\n }\n\n let cancelled = false;\n const options: KeyframeAnimationOptions = {\n duration: COLLAPSE_DURATION_MS,\n easing: COLLAPSE_EASING,\n fill: \"forwards\",\n };\n const shellAnimation = shell.animate([\n { height: `${shell.scrollHeight}px` },\n { height: \"46px\" },\n ], options);\n const expandedAnimation = expanded.animate([\n { opacity: 1, transform: \"translateY(0)\" },\n { opacity: 0, transform: \"translateY(-6px)\" },\n ], options);\n const summaryAnimation = summary.animate([\n { opacity: 0, transform: \"translateY(6px)\" },\n { opacity: 1, transform: \"translateY(0)\" },\n ], options);\n\n void shellAnimation.finished\n .then(() => { if (!cancelled) onComplete(); })\n .catch(() => undefined);\n\n return () => {\n cancelled = true;\n shellAnimation.cancel();\n expandedAnimation.cancel();\n summaryAnimation.cancel();\n };\n }, [event.id, onComplete, reduceMotion]);\n\n return <div className=\"asr-collapse-shell\" ref={shellRef}>\n <div className=\"asr-collapse-expanded\" ref={expandedRef}>\n <ExpandedEvent event={event} visibleEvent={event} typing={false} />\n </div>\n <div className=\"asr-collapse-summary\" ref={summaryRef} aria-hidden=\"true\">\n <div className={`asr-event-summary-row asr-event-summary-row--${event.actor}`}>\n <EventSummaryContent event={event} index={index} />\n </div>\n </div>\n </div>;\n}\n\nexport function AgentSessionReplayer(props: AgentSessionReplayerProps) {\n const {\n agents,\n cases,\n typingSpeed,\n eventDelayMs,\n height,\n colors,\n caseIndex,\n initialCaseIndex,\n className,\n onCaseChange,\n onEventStart,\n onEventComplete,\n onCaseComplete,\n } = parseReplayerProps({\n ...props,\n typingSpeed: props.typingSpeed === undefined ? DEFAULT_TYPING_SPEED : props.typingSpeed,\n eventDelayMs: props.eventDelayMs === undefined ? DEFAULT_EVENT_DELAY : props.eventDelayMs,\n height: props.height === undefined ? 720 : props.height,\n initialCaseIndex: props.initialCaseIndex === undefined ? 0 : props.initialCaseIndex,\n });\n const controlled = caseIndex !== undefined;\n const [internalCaseIndex, setInternalCaseIndex] = useState(initialCaseIndex);\n const resolvedCaseIndex = controlled ? caseIndex : internalCaseIndex;\n const [state, dispatch] = useReducer(playbackReducer, undefined, initialPlaybackState);\n const [generation, bumpGeneration] = useReducer((value: number) => value + 1, 0);\n const [expandedEventIds, setExpandedEventIds] = useState<Set<string>>(() => new Set());\n const reduceMotion = usePrefersReducedMotion();\n const transcriptRef = useRef<HTMLDivElement>(null);\n const started = useRef(new Set<string>());\n const completed = useRef(new Set<string>());\n const completedCases = useRef(new Set<string>());\n const previousCase = useRef(resolvedCaseIndex);\n const activeCase = cases[resolvedCaseIndex]!;\n const caseChanged = previousCase.current !== resolvedCaseIndex;\n const eventIndex = caseChanged ? 0 : state.eventIndex;\n const revealOffset = caseChanged ? 0 : state.revealOffset;\n const phase = caseChanged ? \"typing\" : state.phase;\n const event = activeCase.events[eventIndex]!;\n const visibleEvent = useMemo(() => revealEvent(event, revealOffset), [event, revealOffset]);\n const finishCollapse = useCallback(() => {\n dispatch({ type: \"FINISH_COLLAPSE\", eventIndex });\n }, [eventIndex]);\n\n useEffect(() => {\n if (previousCase.current === resolvedCaseIndex) return;\n previousCase.current = resolvedCaseIndex;\n setExpandedEventIds(new Set());\n bumpGeneration();\n dispatch({ type: \"RESTART\" });\n }, [resolvedCaseIndex]);\n\n useEffect(() => {\n if (caseChanged) return;\n const key = `${generation}:${activeCase.id}:${event.id}`;\n if (!started.current.has(key)) {\n started.current.add(key);\n onEventStart?.(event, activeCase);\n }\n }, [activeCase, caseChanged, event, generation, onEventStart]);\n\n useEffect(() => {\n if (caseChanged) return;\n if (phase === \"typing\") {\n if (reduceMotion) {\n dispatch({ type: \"COMPLETE_EVENT\", item: activeCase, eventIndex });\n return;\n }\n const timer = window.setTimeout(() => dispatch({ type: \"TICK\", item: activeCase, eventIndex, amount: 1 }), 1000 / typingSpeed);\n return () => window.clearTimeout(timer);\n }\n if (phase === \"between-events\") {\n const timer = window.setTimeout(() => dispatch({ type: \"ADVANCE_EVENT\", eventIndex }), eventDelayMs);\n return () => window.clearTimeout(timer);\n }\n }, [activeCase, caseChanged, eventDelayMs, eventIndex, phase, reduceMotion, revealOffset, typingSpeed]);\n\n useEffect(() => {\n if (phase === \"typing\") return;\n const key = `${generation}:${activeCase.id}:${event.id}`;\n if (!completed.current.has(key)) {\n completed.current.add(key);\n onEventComplete?.(event, activeCase);\n }\n if (phase === \"case-complete\") {\n const caseKey = `${generation}:${activeCase.id}`;\n if (!completedCases.current.has(caseKey)) {\n completedCases.current.add(caseKey);\n onCaseComplete?.(activeCase);\n }\n }\n }, [activeCase, event, generation, onCaseComplete, onEventComplete, phase]);\n\n useEffect(() => {\n const transcript = transcriptRef.current;\n if (!transcript || transcript.scrollHeight <= transcript.clientHeight) return;\n transcript.scrollTo({ top: transcript.scrollHeight, behavior: reduceMotion ? \"auto\" : \"smooth\" });\n const bottomGap = transcript.scrollHeight - transcript.clientHeight - transcript.scrollTop;\n if (bottomGap > 1) transcript.scrollTop = transcript.scrollHeight;\n }, [eventIndex, reduceMotion, resolvedCaseIndex, revealOffset, visibleEvent.blocks.length]);\n\n const requestCase = (nextIndex: number) => {\n if (nextIndex === resolvedCaseIndex || nextIndex < 0 || nextIndex >= cases.length) return;\n if (!controlled) {\n setInternalCaseIndex(nextIndex);\n dispatch({ type: \"RESTART\" });\n }\n onCaseChange?.(nextIndex, cases[nextIndex]!);\n };\n\n const restart = () => {\n setExpandedEventIds(new Set());\n bumpGeneration();\n dispatch({ type: \"RESTART\" });\n };\n\n const toggleEvent = (eventId: string) => {\n setExpandedEventIds((current) => {\n const next = new Set(current);\n if (next.has(eventId)) next.delete(eventId);\n else next.add(eventId);\n return next;\n });\n };\n\n const style = {\n ...Object.fromEntries(Object.entries(colors ?? {}).map(([key, value]) => [colorVariables[key as keyof AgentSessionColors], value])),\n \"--asr-height\": `${height}px`,\n height: `${height}px`,\n } as CSSProperties;\n\n return <section data-agent-session-replayer className={`asr-root${className ? ` ${className}` : \"\"}`} style={style} aria-label=\"Two-agent review conversation\">\n <div className=\"asr-chat-stage\">\n <header className=\"asr-frame-header\">\n <div className=\"asr-workflow-line\"><span className=\"asr-brand\"><span>✣</span> Claude Code · Dynamic workflow</span><span className=\"asr-review-label\">Adversarial review</span></div>\n <p className=\"asr-case-summary\">{cases.length} bugs caught by adversarial review before merge</p>\n </header>\n <div className=\"asr-case-nav\">\n <div><span className=\"asr-case-progress\">Case {resolvedCaseIndex + 1} of {cases.length}</span><h2 className=\"asr-case-title\">{activeCase.title}</h2><span className=\"asr-repository\">{activeCase.repository} · {activeCase.branch} · {phase === \"case-complete\" ? \"Case complete\" : `Message ${eventIndex + 1} of ${activeCase.events.length}`}</span></div>\n <div className=\"asr-controls\" aria-label=\"Playback controls\">\n <button type=\"button\" onClick={() => requestCase(resolvedCaseIndex - 1)} disabled={resolvedCaseIndex === 0} aria-label=\"Previous case\">←</button>\n <button type=\"button\" onClick={restart} aria-label=\"Restart case\">Restart</button>\n <button type=\"button\" className=\"asr-next-button\" onClick={() => requestCase(resolvedCaseIndex + 1)} disabled={resolvedCaseIndex === cases.length - 1}>Next case →</button>\n </div>\n </div>\n <div className=\"asr-agent-row\"><Agent actor=\"implementer\" active={event.actor === \"implementer\"} agent={agents.implementer} /><Agent actor=\"reviewer\" active={event.actor === \"reviewer\"} agent={agents.reviewer} /></div>\n <div className=\"asr-transcript\" ref={transcriptRef}>\n {activeCase.events.slice(0, eventIndex).map((past, index) => <CompletedEvent event={past} index={index} expanded={expandedEventIds.has(past.id)} onToggle={() => toggleEvent(past.id)} key={past.id} />)}\n {phase === \"collapsing\" ? (\n <CollapsingEvent event={event} index={eventIndex} reduceMotion={reduceMotion} onComplete={finishCollapse} />\n ) : phase === \"between-events\" ? (\n <CompletedEvent event={event} index={eventIndex} expanded={expandedEventIds.has(event.id)} onToggle={() => toggleEvent(event.id)} key={event.id} />\n ) : (\n <div><ExpandedEvent event={event} visibleEvent={visibleEvent} typing={phase === \"typing\"} /></div>\n )}\n </div>\n <p className=\"asr-live-status\" aria-live=\"polite\">{phase === \"case-complete\" ? `${activeCase.title} complete.` : `Autoplaying ${event.title}.`}</p>\n <footer className=\"asr-footer\"><span>Scripted playback: each reviewer receives only the diff and is told to find how it is wrong. No live model is running.</span><a className=\"asr-watermark\" href=\"https://devos.ing\" target=\"_blank\" rel=\"noopener noreferrer\">devos</a></footer>\n </div>\n </section>;\n}\n","import type { AgentSession, AgentSessionEvent } from \"./types\";\n\nexport type PlaybackPhase = \"typing\" | \"collapsing\" | \"between-events\" | \"case-complete\";\nexport type PlaybackState = { eventIndex: number; revealOffset: number; phase: PlaybackPhase };\nexport const initialPlaybackState = (): PlaybackState => ({ eventIndex: 0, revealOffset: 0, phase: \"typing\" });\n\nexport const segmentGraphemes = (value: string): string[] => {\n if (typeof Intl.Segmenter === \"function\") return [...new Intl.Segmenter(undefined, { granularity: \"grapheme\" }).segment(value)].map(({ segment }) => segment);\n return Array.from(value);\n};\n\nexport const getEventText = (event: AgentSessionEvent): string => event.blocks.map((block) => `${block.title ? `${block.title}\\n` : \"\"}${block.content}`).join(\"\\n\");\nexport const getEventLength = (event: AgentSessionEvent): number => segmentGraphemes(getEventText(event)).length;\n\nexport const revealEvent = (event: AgentSessionEvent, offset: number): AgentSessionEvent => {\n let remaining = offset;\n const blocks = [];\n for (const block of event.blocks) {\n if (remaining <= 0) break;\n const titleParts = segmentGraphemes(block.title ?? \"\");\n const title = titleParts.slice(0, remaining).join(\"\");\n remaining = Math.max(0, remaining - titleParts.length - (block.title ? 1 : 0));\n const contentParts = segmentGraphemes(block.content);\n const content = contentParts.slice(0, remaining).join(\"\");\n remaining = Math.max(0, remaining - contentParts.length - 1);\n blocks.push({ ...block, title: block.title ? title : undefined, content });\n }\n return { ...event, blocks };\n};\n\nexport type PlaybackAction =\n | { type: \"TICK\"; item: AgentSession; eventIndex: number; amount: number }\n | { type: \"COMPLETE_EVENT\"; item: AgentSession; eventIndex: number }\n | { type: \"FINISH_COLLAPSE\"; eventIndex: number }\n | { type: \"ADVANCE_EVENT\"; eventIndex: number }\n | { type: \"RESTART\" };\n\nexport function playbackReducer(state: PlaybackState, action: PlaybackAction): PlaybackState {\n if (action.type === \"RESTART\") return initialPlaybackState();\n if (action.eventIndex !== state.eventIndex) return state;\n if (action.type === \"FINISH_COLLAPSE\") return state.phase === \"collapsing\" ? { ...state, phase: \"between-events\" } : state;\n if (action.type === \"ADVANCE_EVENT\") return state.phase === \"between-events\" ? { eventIndex: state.eventIndex + 1, revealOffset: 0, phase: \"typing\" } : state;\n if (state.phase !== \"typing\") return state;\n const event = action.item.events[state.eventIndex]!;\n const length = getEventLength(event);\n const revealOffset = action.type === \"COMPLETE_EVENT\" ? length : Math.min(length, state.revealOffset + action.amount);\n if (revealOffset < length) return { ...state, revealOffset };\n return { ...state, revealOffset, phase: state.eventIndex === action.item.events.length - 1 ? \"case-complete\" : \"collapsing\" };\n}\n","import { z } from \"zod\";\nimport type { AgentSessionContent, AgentSessionReplayerProps } from \"./types\";\n\nconst nonEmpty = z.string().min(1);\nconst actorSchema = z.enum([\"implementer\", \"reviewer\"]);\nconst eventTypeSchema = z.enum([\n \"task_received\", \"plan\", \"patch\", \"review_request\", \"review_start\",\n \"blocking_finding\", \"revision\", \"verification\", \"approval\",\n]);\nconst blockKindSchema = z.enum([\n \"message\", \"code\", \"tool_call\", \"tool_output\", \"finding\", \"patch\",\n \"git_diff\", \"status\", \"result\",\n]);\n\nconst agentSchema = z.object({\n id: nonEmpty,\n name: nonEmpty,\n role: nonEmpty,\n context: nonEmpty,\n}).strict();\n\nconst blockSchema = z.object({\n id: nonEmpty,\n kind: blockKindSchema,\n title: nonEmpty.optional(),\n content: nonEmpty,\n language: nonEmpty.optional(),\n}).strict();\n\nconst eventSchema = z.object({\n id: nonEmpty,\n type: eventTypeSchema,\n actor: actorSchema,\n title: nonEmpty,\n summary: nonEmpty,\n blocks: z.array(blockSchema).min(1)\n .describe(\"Block IDs must be unique within each event. The runtime parser enforces this constraint.\"),\n}).strict().superRefine((event, context) => {\n if (new Set(event.blocks.map(({ id }) => id)).size !== event.blocks.length) {\n context.addIssue({\n code: \"custom\",\n path: [\"blocks\"],\n message: \"Block IDs must be unique within an event\",\n });\n }\n});\n\nconst sessionSchema = z.object({\n id: nonEmpty,\n title: nonEmpty,\n summary: nonEmpty,\n repository: nonEmpty,\n branch: nonEmpty,\n events: z.array(eventSchema).min(1)\n .describe(\"Event IDs must be unique within each case. The runtime parser enforces this constraint.\"),\n}).strict().superRefine((session, context) => {\n if (new Set(session.events.map(({ id }) => id)).size !== session.events.length) {\n context.addIssue({\n code: \"custom\",\n path: [\"events\"],\n message: \"Event IDs must be unique within a case\",\n });\n }\n});\n\nconst colorsSchema = z.object({\n background: z.string().optional(),\n surface: z.string().optional(),\n border: z.string().optional(),\n text: z.string().optional(),\n muted: z.string().optional(),\n implementer: z.string().optional(),\n reviewer: z.string().optional(),\n success: z.string().optional(),\n danger: z.string().optional(),\n focus: z.string().optional(),\n}).strict();\n\nconst replayContentShape = {\n agents: z.object({ implementer: agentSchema, reviewer: agentSchema }).strict(),\n cases: z.array(sessionSchema).min(1)\n .describe(\"Case IDs must be unique across this array. The runtime parser enforces this constraint.\"),\n};\n\nfunction addReplayContentIssues(\n value: { cases: Array<{ id: string }> },\n context: z.RefinementCtx,\n) {\n if (new Set(value.cases.map(({ id }) => id)).size !== value.cases.length) {\n context.addIssue({ code: \"custom\", path: [\"cases\"], message: \"Case IDs must be unique\" });\n }\n}\n\nexport const replayContentSchema = z.object(replayContentShape)\n .strict()\n .superRefine(addReplayContentIssues);\n\nconst propsSchema = z.object({\n ...replayContentShape,\n typingSpeed: z.number().finite().positive(),\n eventDelayMs: z.number().finite().nonnegative(),\n height: z.number({ error: \"height must be greater than zero.\" })\n .refine((value) => Number.isFinite(value) && value > 0, \"height must be greater than zero.\"),\n colors: colorsSchema.optional(),\n caseIndex: z.number().int().nonnegative().optional(),\n initialCaseIndex: z.number().int().nonnegative(),\n className: z.string().optional(),\n onCaseChange: z.function().optional(),\n onEventStart: z.function().optional(),\n onEventComplete: z.function().optional(),\n onCaseComplete: z.function().optional(),\n}).strict().superRefine((props, context) => {\n addReplayContentIssues(props, context);\n\n for (const key of [\"caseIndex\", \"initialCaseIndex\"] as const) {\n const value = props[key];\n if (value !== undefined && value >= props.cases.length) {\n context.addIssue({\n code: \"custom\",\n path: [key],\n message: `${key} must reference an available case`,\n });\n }\n }\n});\n\ntype ParsedProps = AgentSessionReplayerProps & Required<Pick<AgentSessionReplayerProps,\n \"typingSpeed\" | \"eventDelayMs\" | \"height\" | \"initialCaseIndex\"\n>>;\n\nfunction formatPath(path: PropertyKey[]): string {\n const formatted = path.reduce<string>((result, part) => (\n typeof part === \"number\"\n ? `${result}[${part}]`\n : result ? `${result}.${String(part)}` : String(part)\n ), \"\");\n\n return formatted || \"$\";\n}\n\nexport function parseReplayerProps(value: unknown): ParsedProps {\n const result = propsSchema.safeParse(value);\n if (result.success) return result.data as ParsedProps;\n\n const details = result.error.issues\n .map((issue) => `${formatPath(issue.path)}: ${issue.message}`)\n .join(\"; \");\n throw new Error(`AgentSessionReplayer received invalid props: ${details}`);\n}\n\nexport function parseAgentSessionContent(value: unknown): AgentSessionContent {\n const result = replayContentSchema.safeParse(value);\n if (result.success) return result.data as AgentSessionContent;\n\n const details = result.error.issues\n .map((issue) => `${formatPath(issue.path)}: ${issue.message}`)\n .join(\"; \");\n throw new Error(`Replay content is invalid: ${details}`);\n}\n","import { Fragment } from \"react\";\n\nexport type GitDiffLineKind =\n | \"metadata\"\n | \"hunk\"\n | \"addition\"\n | \"removal\"\n | \"context\";\n\nconst METADATA_PREFIXES = [\n \"diff --git \",\n \"index \",\n \"new file mode \",\n \"deleted file mode \",\n \"similarity index \",\n \"rename from \",\n \"rename to \",\n \"--- \",\n \"+++ \",\n \"\\\\",\n] as const;\n\nexport function classifyGitDiffLine(line: string): GitDiffLineKind {\n if (METADATA_PREFIXES.some((prefix) => line.startsWith(prefix))) return \"metadata\";\n if (line.startsWith(\"@@\")) return \"hunk\";\n if (line.startsWith(\"+\")) return \"addition\";\n if (line.startsWith(\"-\")) return \"removal\";\n return \"context\";\n}\n\nexport function GitDiffBlock({ content }: { content: string }) {\n const lines = content.split(\"\\n\");\n\n return <pre className=\"asr-git-diff\"><code>{lines.map((line, index) => {\n const kind = classifyGitDiffLine(line);\n return <Fragment key={index}>\n <span className={`asr-git-diff-line asr-git-diff-line--${kind}`}>{line}</span>\n {index < lines.length - 1 ? \"\\n\" : null}\n </Fragment>;\n })}</code></pre>;\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { A as AgentSessionReplayerProps } from './types-DBa28H8n.cjs';
|
|
3
|
+
export { a as AgentActor, b as AgentBlockKind, c as AgentEventType, d as AgentIdentity, e as AgentSession, f as AgentSessionBlock, g as AgentSessionColors, h as AgentSessionEvent } from './types-DBa28H8n.cjs';
|
|
4
|
+
|
|
5
|
+
declare function AgentSessionReplayer(props: AgentSessionReplayerProps): react.JSX.Element;
|
|
6
|
+
|
|
7
|
+
export { AgentSessionReplayer, AgentSessionReplayerProps };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { A as AgentSessionReplayerProps } from './types-DBa28H8n.js';
|
|
3
|
+
export { a as AgentActor, b as AgentBlockKind, c as AgentEventType, d as AgentIdentity, e as AgentSession, f as AgentSessionBlock, g as AgentSessionColors, h as AgentSessionEvent } from './types-DBa28H8n.js';
|
|
4
|
+
|
|
5
|
+
declare function AgentSessionReplayer(props: AgentSessionReplayerProps): react.JSX.Element;
|
|
6
|
+
|
|
7
|
+
export { AgentSessionReplayer, AgentSessionReplayerProps };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseReplayerProps
|
|
3
|
+
} from "./chunk-QE3DOXM4.js";
|
|
4
|
+
|
|
5
|
+
// src/AgentSessionReplayer.tsx
|
|
6
|
+
import {
|
|
7
|
+
useCallback,
|
|
8
|
+
useEffect,
|
|
9
|
+
useMemo,
|
|
10
|
+
useReducer,
|
|
11
|
+
useRef,
|
|
12
|
+
useState
|
|
13
|
+
} from "react";
|
|
14
|
+
|
|
15
|
+
// src/playback.ts
|
|
16
|
+
var initialPlaybackState = () => ({ eventIndex: 0, revealOffset: 0, phase: "typing" });
|
|
17
|
+
var segmentGraphemes = (value) => {
|
|
18
|
+
if (typeof Intl.Segmenter === "function") return [...new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(value)].map(({ segment }) => segment);
|
|
19
|
+
return Array.from(value);
|
|
20
|
+
};
|
|
21
|
+
var getEventText = (event) => event.blocks.map((block) => `${block.title ? `${block.title}
|
|
22
|
+
` : ""}${block.content}`).join("\n");
|
|
23
|
+
var getEventLength = (event) => segmentGraphemes(getEventText(event)).length;
|
|
24
|
+
var revealEvent = (event, offset) => {
|
|
25
|
+
let remaining = offset;
|
|
26
|
+
const blocks = [];
|
|
27
|
+
for (const block of event.blocks) {
|
|
28
|
+
if (remaining <= 0) break;
|
|
29
|
+
const titleParts = segmentGraphemes(block.title ?? "");
|
|
30
|
+
const title = titleParts.slice(0, remaining).join("");
|
|
31
|
+
remaining = Math.max(0, remaining - titleParts.length - (block.title ? 1 : 0));
|
|
32
|
+
const contentParts = segmentGraphemes(block.content);
|
|
33
|
+
const content = contentParts.slice(0, remaining).join("");
|
|
34
|
+
remaining = Math.max(0, remaining - contentParts.length - 1);
|
|
35
|
+
blocks.push({ ...block, title: block.title ? title : void 0, content });
|
|
36
|
+
}
|
|
37
|
+
return { ...event, blocks };
|
|
38
|
+
};
|
|
39
|
+
function playbackReducer(state, action) {
|
|
40
|
+
if (action.type === "RESTART") return initialPlaybackState();
|
|
41
|
+
if (action.eventIndex !== state.eventIndex) return state;
|
|
42
|
+
if (action.type === "FINISH_COLLAPSE") return state.phase === "collapsing" ? { ...state, phase: "between-events" } : state;
|
|
43
|
+
if (action.type === "ADVANCE_EVENT") return state.phase === "between-events" ? { eventIndex: state.eventIndex + 1, revealOffset: 0, phase: "typing" } : state;
|
|
44
|
+
if (state.phase !== "typing") return state;
|
|
45
|
+
const event = action.item.events[state.eventIndex];
|
|
46
|
+
const length = getEventLength(event);
|
|
47
|
+
const revealOffset = action.type === "COMPLETE_EVENT" ? length : Math.min(length, state.revealOffset + action.amount);
|
|
48
|
+
if (revealOffset < length) return { ...state, revealOffset };
|
|
49
|
+
return { ...state, revealOffset, phase: state.eventIndex === action.item.events.length - 1 ? "case-complete" : "collapsing" };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/GitDiffBlock.tsx
|
|
53
|
+
import { Fragment } from "react";
|
|
54
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
55
|
+
var METADATA_PREFIXES = [
|
|
56
|
+
"diff --git ",
|
|
57
|
+
"index ",
|
|
58
|
+
"new file mode ",
|
|
59
|
+
"deleted file mode ",
|
|
60
|
+
"similarity index ",
|
|
61
|
+
"rename from ",
|
|
62
|
+
"rename to ",
|
|
63
|
+
"--- ",
|
|
64
|
+
"+++ ",
|
|
65
|
+
"\"
|
|
66
|
+
];
|
|
67
|
+
function classifyGitDiffLine(line) {
|
|
68
|
+
if (METADATA_PREFIXES.some((prefix) => line.startsWith(prefix))) return "metadata";
|
|
69
|
+
if (line.startsWith("@@")) return "hunk";
|
|
70
|
+
if (line.startsWith("+")) return "addition";
|
|
71
|
+
if (line.startsWith("-")) return "removal";
|
|
72
|
+
return "context";
|
|
73
|
+
}
|
|
74
|
+
function GitDiffBlock({ content }) {
|
|
75
|
+
const lines = content.split("\n");
|
|
76
|
+
return /* @__PURE__ */ jsx("pre", { className: "asr-git-diff", children: /* @__PURE__ */ jsx("code", { children: lines.map((line, index) => {
|
|
77
|
+
const kind = classifyGitDiffLine(line);
|
|
78
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
79
|
+
/* @__PURE__ */ jsx("span", { className: `asr-git-diff-line asr-git-diff-line--${kind}`, children: line }),
|
|
80
|
+
index < lines.length - 1 ? "\n" : null
|
|
81
|
+
] }, index);
|
|
82
|
+
}) }) });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/AgentSessionReplayer.tsx
|
|
86
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
87
|
+
var DEFAULT_TYPING_SPEED = 110;
|
|
88
|
+
var DEFAULT_EVENT_DELAY = 500;
|
|
89
|
+
var COLLAPSE_DURATION_MS = 220;
|
|
90
|
+
var COLLAPSE_EASING = "cubic-bezier(0.23, 1, 0.32, 1)";
|
|
91
|
+
var colorVariables = {
|
|
92
|
+
background: "--asr-background",
|
|
93
|
+
surface: "--asr-surface",
|
|
94
|
+
border: "--asr-border",
|
|
95
|
+
text: "--asr-text",
|
|
96
|
+
muted: "--asr-muted",
|
|
97
|
+
implementer: "--asr-implementer",
|
|
98
|
+
reviewer: "--asr-reviewer",
|
|
99
|
+
success: "--asr-success",
|
|
100
|
+
danger: "--asr-danger",
|
|
101
|
+
focus: "--asr-focus"
|
|
102
|
+
};
|
|
103
|
+
function usePrefersReducedMotion() {
|
|
104
|
+
const [reduced, setReduced] = useState(false);
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
107
|
+
const query = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
108
|
+
const update = () => setReduced(query.matches);
|
|
109
|
+
update();
|
|
110
|
+
query.addEventListener?.("change", update);
|
|
111
|
+
return () => query.removeEventListener?.("change", update);
|
|
112
|
+
}, []);
|
|
113
|
+
return reduced;
|
|
114
|
+
}
|
|
115
|
+
function Agent({ actor, active, agent }) {
|
|
116
|
+
return /* @__PURE__ */ jsxs2("div", { className: `asr-agent asr-agent--${actor} ${active ? "asr-is-active" : ""}`, children: [
|
|
117
|
+
/* @__PURE__ */ jsx2("span", { className: "asr-agent-avatar", "aria-hidden": "true", children: "\u2723" }),
|
|
118
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
119
|
+
/* @__PURE__ */ jsx2("strong", { children: agent.name }),
|
|
120
|
+
" ",
|
|
121
|
+
/* @__PURE__ */ jsx2("span", { children: agent.role }),
|
|
122
|
+
/* @__PURE__ */ jsxs2("p", { children: [
|
|
123
|
+
"its context: ",
|
|
124
|
+
agent.context
|
|
125
|
+
] })
|
|
126
|
+
] })
|
|
127
|
+
] });
|
|
128
|
+
}
|
|
129
|
+
function Block({ block }) {
|
|
130
|
+
const codeLike = block.kind === "code" || block.kind === "patch" || block.kind === "tool_output";
|
|
131
|
+
return /* @__PURE__ */ jsxs2("section", { className: `asr-chat-block asr-chat-block--${block.kind}`, children: [
|
|
132
|
+
block.title && /* @__PURE__ */ jsxs2("header", { children: [
|
|
133
|
+
/* @__PURE__ */ jsx2("span", { children: block.kind.replace("_", " ") }),
|
|
134
|
+
block.title
|
|
135
|
+
] }),
|
|
136
|
+
block.kind === "git_diff" ? /* @__PURE__ */ jsx2(GitDiffBlock, { content: block.content }) : codeLike ? /* @__PURE__ */ jsx2("pre", { children: /* @__PURE__ */ jsx2("code", { children: block.content }) }) : /* @__PURE__ */ jsx2("p", { children: block.content })
|
|
137
|
+
] });
|
|
138
|
+
}
|
|
139
|
+
function ExpandedEvent({ event, visibleEvent, typing }) {
|
|
140
|
+
return /* @__PURE__ */ jsxs2("article", { className: `asr-expanded-event asr-expanded-event--${event.actor}`, "aria-label": event.title, children: [
|
|
141
|
+
/* @__PURE__ */ jsxs2("div", { className: "asr-event-heading", children: [
|
|
142
|
+
/* @__PURE__ */ jsx2("span", { children: event.actor === "implementer" ? "\u2723 claude" : "adversarial reviewer \u2723" }),
|
|
143
|
+
/* @__PURE__ */ jsx2("strong", { children: event.title })
|
|
144
|
+
] }),
|
|
145
|
+
/* @__PURE__ */ jsx2("div", { className: "asr-blocks", children: visibleEvent.blocks.map((block) => /* @__PURE__ */ jsx2(Block, { block }, block.id)) }),
|
|
146
|
+
typing && /* @__PURE__ */ jsx2("span", { className: "asr-typing-caret", "aria-hidden": "true" })
|
|
147
|
+
] });
|
|
148
|
+
}
|
|
149
|
+
function EventSummaryContent({ event, index }) {
|
|
150
|
+
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
151
|
+
/* @__PURE__ */ jsx2("span", { children: String(index + 1).padStart(2, "0") }),
|
|
152
|
+
/* @__PURE__ */ jsx2("strong", { children: event.title }),
|
|
153
|
+
/* @__PURE__ */ jsx2("p", { children: event.summary }),
|
|
154
|
+
/* @__PURE__ */ jsx2("span", { className: "asr-disclosure", "aria-hidden": "true", children: "\u2304" })
|
|
155
|
+
] });
|
|
156
|
+
}
|
|
157
|
+
function EventSummaryRow({ event, index, contentId, onToggle, className = "" }) {
|
|
158
|
+
return /* @__PURE__ */ jsx2(
|
|
159
|
+
"button",
|
|
160
|
+
{
|
|
161
|
+
type: "button",
|
|
162
|
+
className: `asr-event-summary-row asr-event-summary-row--${event.actor}${className ? ` ${className}` : ""}`,
|
|
163
|
+
"aria-expanded": "false",
|
|
164
|
+
"aria-controls": contentId,
|
|
165
|
+
"aria-label": `Expand ${event.title}`,
|
|
166
|
+
onClick: onToggle,
|
|
167
|
+
children: /* @__PURE__ */ jsx2(EventSummaryContent, { event, index })
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
function CompletedEvent({ event, index, expanded, onToggle }) {
|
|
172
|
+
const contentId = `asr-event-${event.id}`;
|
|
173
|
+
if (!expanded) {
|
|
174
|
+
return /* @__PURE__ */ jsxs2("div", { className: "asr-completed-event", children: [
|
|
175
|
+
/* @__PURE__ */ jsx2(EventSummaryRow, { event, index, contentId, onToggle }),
|
|
176
|
+
/* @__PURE__ */ jsx2("div", { id: contentId, hidden: true })
|
|
177
|
+
] });
|
|
178
|
+
}
|
|
179
|
+
return /* @__PURE__ */ jsxs2("article", { className: `asr-expanded-event asr-expanded-event--${event.actor}`, "aria-label": event.title, children: [
|
|
180
|
+
/* @__PURE__ */ jsxs2(
|
|
181
|
+
"button",
|
|
182
|
+
{
|
|
183
|
+
type: "button",
|
|
184
|
+
className: "asr-expanded-toggle",
|
|
185
|
+
"aria-expanded": "true",
|
|
186
|
+
"aria-controls": contentId,
|
|
187
|
+
"aria-label": `Collapse ${event.title}`,
|
|
188
|
+
onClick: onToggle,
|
|
189
|
+
children: [
|
|
190
|
+
/* @__PURE__ */ jsx2("span", { children: event.actor === "implementer" ? "\u2723 claude" : "adversarial reviewer \u2723" }),
|
|
191
|
+
/* @__PURE__ */ jsx2("strong", { children: event.title }),
|
|
192
|
+
/* @__PURE__ */ jsx2("span", { className: "asr-disclosure", "aria-hidden": "true", children: "\u2303" })
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
),
|
|
196
|
+
/* @__PURE__ */ jsx2("div", { className: "asr-blocks", id: contentId, children: event.blocks.map((block) => /* @__PURE__ */ jsx2(Block, { block }, block.id)) })
|
|
197
|
+
] });
|
|
198
|
+
}
|
|
199
|
+
function CollapsingEvent({
|
|
200
|
+
event,
|
|
201
|
+
index,
|
|
202
|
+
reduceMotion,
|
|
203
|
+
onComplete
|
|
204
|
+
}) {
|
|
205
|
+
const shellRef = useRef(null);
|
|
206
|
+
const expandedRef = useRef(null);
|
|
207
|
+
const summaryRef = useRef(null);
|
|
208
|
+
useEffect(() => {
|
|
209
|
+
const shell = shellRef.current;
|
|
210
|
+
const expanded = expandedRef.current;
|
|
211
|
+
const summary = summaryRef.current;
|
|
212
|
+
if (!shell || !expanded || !summary) return;
|
|
213
|
+
if (reduceMotion || typeof shell.animate !== "function") {
|
|
214
|
+
onComplete();
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
let cancelled = false;
|
|
218
|
+
const options = {
|
|
219
|
+
duration: COLLAPSE_DURATION_MS,
|
|
220
|
+
easing: COLLAPSE_EASING,
|
|
221
|
+
fill: "forwards"
|
|
222
|
+
};
|
|
223
|
+
const shellAnimation = shell.animate([
|
|
224
|
+
{ height: `${shell.scrollHeight}px` },
|
|
225
|
+
{ height: "46px" }
|
|
226
|
+
], options);
|
|
227
|
+
const expandedAnimation = expanded.animate([
|
|
228
|
+
{ opacity: 1, transform: "translateY(0)" },
|
|
229
|
+
{ opacity: 0, transform: "translateY(-6px)" }
|
|
230
|
+
], options);
|
|
231
|
+
const summaryAnimation = summary.animate([
|
|
232
|
+
{ opacity: 0, transform: "translateY(6px)" },
|
|
233
|
+
{ opacity: 1, transform: "translateY(0)" }
|
|
234
|
+
], options);
|
|
235
|
+
void shellAnimation.finished.then(() => {
|
|
236
|
+
if (!cancelled) onComplete();
|
|
237
|
+
}).catch(() => void 0);
|
|
238
|
+
return () => {
|
|
239
|
+
cancelled = true;
|
|
240
|
+
shellAnimation.cancel();
|
|
241
|
+
expandedAnimation.cancel();
|
|
242
|
+
summaryAnimation.cancel();
|
|
243
|
+
};
|
|
244
|
+
}, [event.id, onComplete, reduceMotion]);
|
|
245
|
+
return /* @__PURE__ */ jsxs2("div", { className: "asr-collapse-shell", ref: shellRef, children: [
|
|
246
|
+
/* @__PURE__ */ jsx2("div", { className: "asr-collapse-expanded", ref: expandedRef, children: /* @__PURE__ */ jsx2(ExpandedEvent, { event, visibleEvent: event, typing: false }) }),
|
|
247
|
+
/* @__PURE__ */ jsx2("div", { className: "asr-collapse-summary", ref: summaryRef, "aria-hidden": "true", children: /* @__PURE__ */ jsx2("div", { className: `asr-event-summary-row asr-event-summary-row--${event.actor}`, children: /* @__PURE__ */ jsx2(EventSummaryContent, { event, index }) }) })
|
|
248
|
+
] });
|
|
249
|
+
}
|
|
250
|
+
function AgentSessionReplayer(props) {
|
|
251
|
+
const {
|
|
252
|
+
agents,
|
|
253
|
+
cases,
|
|
254
|
+
typingSpeed,
|
|
255
|
+
eventDelayMs,
|
|
256
|
+
height,
|
|
257
|
+
colors,
|
|
258
|
+
caseIndex,
|
|
259
|
+
initialCaseIndex,
|
|
260
|
+
className,
|
|
261
|
+
onCaseChange,
|
|
262
|
+
onEventStart,
|
|
263
|
+
onEventComplete,
|
|
264
|
+
onCaseComplete
|
|
265
|
+
} = parseReplayerProps({
|
|
266
|
+
...props,
|
|
267
|
+
typingSpeed: props.typingSpeed === void 0 ? DEFAULT_TYPING_SPEED : props.typingSpeed,
|
|
268
|
+
eventDelayMs: props.eventDelayMs === void 0 ? DEFAULT_EVENT_DELAY : props.eventDelayMs,
|
|
269
|
+
height: props.height === void 0 ? 720 : props.height,
|
|
270
|
+
initialCaseIndex: props.initialCaseIndex === void 0 ? 0 : props.initialCaseIndex
|
|
271
|
+
});
|
|
272
|
+
const controlled = caseIndex !== void 0;
|
|
273
|
+
const [internalCaseIndex, setInternalCaseIndex] = useState(initialCaseIndex);
|
|
274
|
+
const resolvedCaseIndex = controlled ? caseIndex : internalCaseIndex;
|
|
275
|
+
const [state, dispatch] = useReducer(playbackReducer, void 0, initialPlaybackState);
|
|
276
|
+
const [generation, bumpGeneration] = useReducer((value) => value + 1, 0);
|
|
277
|
+
const [expandedEventIds, setExpandedEventIds] = useState(() => /* @__PURE__ */ new Set());
|
|
278
|
+
const reduceMotion = usePrefersReducedMotion();
|
|
279
|
+
const transcriptRef = useRef(null);
|
|
280
|
+
const started = useRef(/* @__PURE__ */ new Set());
|
|
281
|
+
const completed = useRef(/* @__PURE__ */ new Set());
|
|
282
|
+
const completedCases = useRef(/* @__PURE__ */ new Set());
|
|
283
|
+
const previousCase = useRef(resolvedCaseIndex);
|
|
284
|
+
const activeCase = cases[resolvedCaseIndex];
|
|
285
|
+
const caseChanged = previousCase.current !== resolvedCaseIndex;
|
|
286
|
+
const eventIndex = caseChanged ? 0 : state.eventIndex;
|
|
287
|
+
const revealOffset = caseChanged ? 0 : state.revealOffset;
|
|
288
|
+
const phase = caseChanged ? "typing" : state.phase;
|
|
289
|
+
const event = activeCase.events[eventIndex];
|
|
290
|
+
const visibleEvent = useMemo(() => revealEvent(event, revealOffset), [event, revealOffset]);
|
|
291
|
+
const finishCollapse = useCallback(() => {
|
|
292
|
+
dispatch({ type: "FINISH_COLLAPSE", eventIndex });
|
|
293
|
+
}, [eventIndex]);
|
|
294
|
+
useEffect(() => {
|
|
295
|
+
if (previousCase.current === resolvedCaseIndex) return;
|
|
296
|
+
previousCase.current = resolvedCaseIndex;
|
|
297
|
+
setExpandedEventIds(/* @__PURE__ */ new Set());
|
|
298
|
+
bumpGeneration();
|
|
299
|
+
dispatch({ type: "RESTART" });
|
|
300
|
+
}, [resolvedCaseIndex]);
|
|
301
|
+
useEffect(() => {
|
|
302
|
+
if (caseChanged) return;
|
|
303
|
+
const key = `${generation}:${activeCase.id}:${event.id}`;
|
|
304
|
+
if (!started.current.has(key)) {
|
|
305
|
+
started.current.add(key);
|
|
306
|
+
onEventStart?.(event, activeCase);
|
|
307
|
+
}
|
|
308
|
+
}, [activeCase, caseChanged, event, generation, onEventStart]);
|
|
309
|
+
useEffect(() => {
|
|
310
|
+
if (caseChanged) return;
|
|
311
|
+
if (phase === "typing") {
|
|
312
|
+
if (reduceMotion) {
|
|
313
|
+
dispatch({ type: "COMPLETE_EVENT", item: activeCase, eventIndex });
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const timer = window.setTimeout(() => dispatch({ type: "TICK", item: activeCase, eventIndex, amount: 1 }), 1e3 / typingSpeed);
|
|
317
|
+
return () => window.clearTimeout(timer);
|
|
318
|
+
}
|
|
319
|
+
if (phase === "between-events") {
|
|
320
|
+
const timer = window.setTimeout(() => dispatch({ type: "ADVANCE_EVENT", eventIndex }), eventDelayMs);
|
|
321
|
+
return () => window.clearTimeout(timer);
|
|
322
|
+
}
|
|
323
|
+
}, [activeCase, caseChanged, eventDelayMs, eventIndex, phase, reduceMotion, revealOffset, typingSpeed]);
|
|
324
|
+
useEffect(() => {
|
|
325
|
+
if (phase === "typing") return;
|
|
326
|
+
const key = `${generation}:${activeCase.id}:${event.id}`;
|
|
327
|
+
if (!completed.current.has(key)) {
|
|
328
|
+
completed.current.add(key);
|
|
329
|
+
onEventComplete?.(event, activeCase);
|
|
330
|
+
}
|
|
331
|
+
if (phase === "case-complete") {
|
|
332
|
+
const caseKey = `${generation}:${activeCase.id}`;
|
|
333
|
+
if (!completedCases.current.has(caseKey)) {
|
|
334
|
+
completedCases.current.add(caseKey);
|
|
335
|
+
onCaseComplete?.(activeCase);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}, [activeCase, event, generation, onCaseComplete, onEventComplete, phase]);
|
|
339
|
+
useEffect(() => {
|
|
340
|
+
const transcript = transcriptRef.current;
|
|
341
|
+
if (!transcript || transcript.scrollHeight <= transcript.clientHeight) return;
|
|
342
|
+
transcript.scrollTo({ top: transcript.scrollHeight, behavior: reduceMotion ? "auto" : "smooth" });
|
|
343
|
+
const bottomGap = transcript.scrollHeight - transcript.clientHeight - transcript.scrollTop;
|
|
344
|
+
if (bottomGap > 1) transcript.scrollTop = transcript.scrollHeight;
|
|
345
|
+
}, [eventIndex, reduceMotion, resolvedCaseIndex, revealOffset, visibleEvent.blocks.length]);
|
|
346
|
+
const requestCase = (nextIndex) => {
|
|
347
|
+
if (nextIndex === resolvedCaseIndex || nextIndex < 0 || nextIndex >= cases.length) return;
|
|
348
|
+
if (!controlled) {
|
|
349
|
+
setInternalCaseIndex(nextIndex);
|
|
350
|
+
dispatch({ type: "RESTART" });
|
|
351
|
+
}
|
|
352
|
+
onCaseChange?.(nextIndex, cases[nextIndex]);
|
|
353
|
+
};
|
|
354
|
+
const restart = () => {
|
|
355
|
+
setExpandedEventIds(/* @__PURE__ */ new Set());
|
|
356
|
+
bumpGeneration();
|
|
357
|
+
dispatch({ type: "RESTART" });
|
|
358
|
+
};
|
|
359
|
+
const toggleEvent = (eventId) => {
|
|
360
|
+
setExpandedEventIds((current) => {
|
|
361
|
+
const next = new Set(current);
|
|
362
|
+
if (next.has(eventId)) next.delete(eventId);
|
|
363
|
+
else next.add(eventId);
|
|
364
|
+
return next;
|
|
365
|
+
});
|
|
366
|
+
};
|
|
367
|
+
const style = {
|
|
368
|
+
...Object.fromEntries(Object.entries(colors ?? {}).map(([key, value]) => [colorVariables[key], value])),
|
|
369
|
+
"--asr-height": `${height}px`,
|
|
370
|
+
height: `${height}px`
|
|
371
|
+
};
|
|
372
|
+
return /* @__PURE__ */ jsx2("section", { "data-agent-session-replayer": true, className: `asr-root${className ? ` ${className}` : ""}`, style, "aria-label": "Two-agent review conversation", children: /* @__PURE__ */ jsxs2("div", { className: "asr-chat-stage", children: [
|
|
373
|
+
/* @__PURE__ */ jsxs2("header", { className: "asr-frame-header", children: [
|
|
374
|
+
/* @__PURE__ */ jsxs2("div", { className: "asr-workflow-line", children: [
|
|
375
|
+
/* @__PURE__ */ jsxs2("span", { className: "asr-brand", children: [
|
|
376
|
+
/* @__PURE__ */ jsx2("span", { children: "\u2723" }),
|
|
377
|
+
" Claude Code \xB7 Dynamic workflow"
|
|
378
|
+
] }),
|
|
379
|
+
/* @__PURE__ */ jsx2("span", { className: "asr-review-label", children: "Adversarial review" })
|
|
380
|
+
] }),
|
|
381
|
+
/* @__PURE__ */ jsxs2("p", { className: "asr-case-summary", children: [
|
|
382
|
+
cases.length,
|
|
383
|
+
" bugs caught by adversarial review before merge"
|
|
384
|
+
] })
|
|
385
|
+
] }),
|
|
386
|
+
/* @__PURE__ */ jsxs2("div", { className: "asr-case-nav", children: [
|
|
387
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
388
|
+
/* @__PURE__ */ jsxs2("span", { className: "asr-case-progress", children: [
|
|
389
|
+
"Case ",
|
|
390
|
+
resolvedCaseIndex + 1,
|
|
391
|
+
" of ",
|
|
392
|
+
cases.length
|
|
393
|
+
] }),
|
|
394
|
+
/* @__PURE__ */ jsx2("h2", { className: "asr-case-title", children: activeCase.title }),
|
|
395
|
+
/* @__PURE__ */ jsxs2("span", { className: "asr-repository", children: [
|
|
396
|
+
activeCase.repository,
|
|
397
|
+
" \xB7 ",
|
|
398
|
+
activeCase.branch,
|
|
399
|
+
" \xB7 ",
|
|
400
|
+
phase === "case-complete" ? "Case complete" : `Message ${eventIndex + 1} of ${activeCase.events.length}`
|
|
401
|
+
] })
|
|
402
|
+
] }),
|
|
403
|
+
/* @__PURE__ */ jsxs2("div", { className: "asr-controls", "aria-label": "Playback controls", children: [
|
|
404
|
+
/* @__PURE__ */ jsx2("button", { type: "button", onClick: () => requestCase(resolvedCaseIndex - 1), disabled: resolvedCaseIndex === 0, "aria-label": "Previous case", children: "\u2190" }),
|
|
405
|
+
/* @__PURE__ */ jsx2("button", { type: "button", onClick: restart, "aria-label": "Restart case", children: "Restart" }),
|
|
406
|
+
/* @__PURE__ */ jsx2("button", { type: "button", className: "asr-next-button", onClick: () => requestCase(resolvedCaseIndex + 1), disabled: resolvedCaseIndex === cases.length - 1, children: "Next case \u2192" })
|
|
407
|
+
] })
|
|
408
|
+
] }),
|
|
409
|
+
/* @__PURE__ */ jsxs2("div", { className: "asr-agent-row", children: [
|
|
410
|
+
/* @__PURE__ */ jsx2(Agent, { actor: "implementer", active: event.actor === "implementer", agent: agents.implementer }),
|
|
411
|
+
/* @__PURE__ */ jsx2(Agent, { actor: "reviewer", active: event.actor === "reviewer", agent: agents.reviewer })
|
|
412
|
+
] }),
|
|
413
|
+
/* @__PURE__ */ jsxs2("div", { className: "asr-transcript", ref: transcriptRef, children: [
|
|
414
|
+
activeCase.events.slice(0, eventIndex).map((past, index) => /* @__PURE__ */ jsx2(CompletedEvent, { event: past, index, expanded: expandedEventIds.has(past.id), onToggle: () => toggleEvent(past.id) }, past.id)),
|
|
415
|
+
phase === "collapsing" ? /* @__PURE__ */ jsx2(CollapsingEvent, { event, index: eventIndex, reduceMotion, onComplete: finishCollapse }) : phase === "between-events" ? /* @__PURE__ */ jsx2(CompletedEvent, { event, index: eventIndex, expanded: expandedEventIds.has(event.id), onToggle: () => toggleEvent(event.id) }, event.id) : /* @__PURE__ */ jsx2("div", { children: /* @__PURE__ */ jsx2(ExpandedEvent, { event, visibleEvent, typing: phase === "typing" }) })
|
|
416
|
+
] }),
|
|
417
|
+
/* @__PURE__ */ jsx2("p", { className: "asr-live-status", "aria-live": "polite", children: phase === "case-complete" ? `${activeCase.title} complete.` : `Autoplaying ${event.title}.` }),
|
|
418
|
+
/* @__PURE__ */ jsxs2("footer", { className: "asr-footer", children: [
|
|
419
|
+
/* @__PURE__ */ jsx2("span", { children: "Scripted playback: each reviewer receives only the diff and is told to find how it is wrong. No live model is running." }),
|
|
420
|
+
/* @__PURE__ */ jsx2("a", { className: "asr-watermark", href: "https://devos.ing", target: "_blank", rel: "noopener noreferrer", children: "devos" })
|
|
421
|
+
] })
|
|
422
|
+
] }) });
|
|
423
|
+
}
|
|
424
|
+
export {
|
|
425
|
+
AgentSessionReplayer
|
|
426
|
+
};
|
|
427
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/AgentSessionReplayer.tsx","../src/playback.ts","../src/GitDiffBlock.tsx"],"sourcesContent":["import {\n type CSSProperties,\n useCallback,\n useEffect,\n useMemo,\n useReducer,\n useRef,\n useState,\n} from \"react\";\nimport { initialPlaybackState, playbackReducer, revealEvent } from \"./playback\";\nimport { parseReplayerProps } from \"./validation\";\nimport { GitDiffBlock } from \"./GitDiffBlock\";\nimport type {\n AgentActor,\n AgentSessionBlock,\n AgentSession,\n AgentSessionColors,\n AgentSessionEvent,\n AgentSessionReplayerProps,\n} from \"./types\";\n\nconst DEFAULT_TYPING_SPEED = 110;\nconst DEFAULT_EVENT_DELAY = 500;\nconst COLLAPSE_DURATION_MS = 220;\nconst COLLAPSE_EASING = \"cubic-bezier(0.23, 1, 0.32, 1)\";\n\nconst colorVariables: Record<keyof AgentSessionColors, string> = {\n background: \"--asr-background\",\n surface: \"--asr-surface\",\n border: \"--asr-border\",\n text: \"--asr-text\",\n muted: \"--asr-muted\",\n implementer: \"--asr-implementer\",\n reviewer: \"--asr-reviewer\",\n success: \"--asr-success\",\n danger: \"--asr-danger\",\n focus: \"--asr-focus\",\n};\n\nfunction usePrefersReducedMotion(): boolean {\n const [reduced, setReduced] = useState(false);\n useEffect(() => {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") return;\n const query = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n const update = () => setReduced(query.matches);\n update();\n query.addEventListener?.(\"change\", update);\n return () => query.removeEventListener?.(\"change\", update);\n }, []);\n return reduced;\n}\n\nfunction Agent({ actor, active, agent }: { actor: AgentActor; active: boolean; agent: AgentSessionReplayerProps[\"agents\"][AgentActor] }) {\n return <div className={`asr-agent asr-agent--${actor} ${active ? \"asr-is-active\" : \"\"}`}>\n <span className=\"asr-agent-avatar\" aria-hidden=\"true\">✣</span>\n <div><strong>{agent.name}</strong> <span>{agent.role}</span><p>its context: {agent.context}</p></div>\n </div>;\n}\n\nfunction Block({ block }: { block: AgentSessionBlock }) {\n const codeLike = block.kind === \"code\" || block.kind === \"patch\" || block.kind === \"tool_output\";\n return <section className={`asr-chat-block asr-chat-block--${block.kind}`}>\n {block.title && <header><span>{block.kind.replace(\"_\", \" \")}</span>{block.title}</header>}\n {block.kind === \"git_diff\"\n ? <GitDiffBlock content={block.content} />\n : codeLike\n ? <pre><code>{block.content}</code></pre>\n : <p>{block.content}</p>}\n </section>;\n}\n\nfunction ExpandedEvent({ event, visibleEvent, typing }: { event: AgentSessionEvent; visibleEvent: AgentSessionEvent; typing: boolean }) {\n return <article className={`asr-expanded-event asr-expanded-event--${event.actor}`} aria-label={event.title}>\n <div className=\"asr-event-heading\"><span>{event.actor === \"implementer\" ? \"✣ claude\" : \"adversarial reviewer ✣\"}</span><strong>{event.title}</strong></div>\n <div className=\"asr-blocks\">{visibleEvent.blocks.map((block) => <Block block={block} key={block.id} />)}</div>\n {typing && <span className=\"asr-typing-caret\" aria-hidden=\"true\" />}\n </article>;\n}\n\nfunction EventSummaryContent({ event, index }: { event: AgentSessionEvent; index: number }) {\n return <>\n <span>{String(index + 1).padStart(2, \"0\")}</span>\n <strong>{event.title}</strong>\n <p>{event.summary}</p>\n <span className=\"asr-disclosure\" aria-hidden=\"true\">⌄</span>\n </>;\n}\n\nfunction EventSummaryRow({ event, index, contentId, onToggle, className = \"\" }: {\n event: AgentSessionEvent;\n index: number;\n contentId: string;\n onToggle: () => void;\n className?: string;\n}) {\n return <button\n type=\"button\"\n className={`asr-event-summary-row asr-event-summary-row--${event.actor}${className ? ` ${className}` : \"\"}`}\n aria-expanded=\"false\"\n aria-controls={contentId}\n aria-label={`Expand ${event.title}`}\n onClick={onToggle}\n >\n <EventSummaryContent event={event} index={index} />\n </button>;\n}\n\nfunction CompletedEvent({ event, index, expanded, onToggle }: {\n event: AgentSessionEvent;\n index: number;\n expanded: boolean;\n onToggle: () => void;\n}) {\n const contentId = `asr-event-${event.id}`;\n if (!expanded) {\n return <div className=\"asr-completed-event\">\n <EventSummaryRow event={event} index={index} contentId={contentId} onToggle={onToggle} />\n <div id={contentId} hidden />\n </div>;\n }\n\n return <article className={`asr-expanded-event asr-expanded-event--${event.actor}`} aria-label={event.title}>\n <button\n type=\"button\"\n className=\"asr-expanded-toggle\"\n aria-expanded=\"true\"\n aria-controls={contentId}\n aria-label={`Collapse ${event.title}`}\n onClick={onToggle}\n >\n <span>{event.actor === \"implementer\" ? \"✣ claude\" : \"adversarial reviewer ✣\"}</span>\n <strong>{event.title}</strong>\n <span className=\"asr-disclosure\" aria-hidden=\"true\">⌃</span>\n </button>\n <div className=\"asr-blocks\" id={contentId}>{event.blocks.map((block) => <Block block={block} key={block.id} />)}</div>\n </article>;\n}\n\nfunction CollapsingEvent({\n event,\n index,\n reduceMotion,\n onComplete,\n}: {\n event: AgentSessionEvent;\n index: number;\n reduceMotion: boolean;\n onComplete: () => void;\n}) {\n const shellRef = useRef<HTMLDivElement>(null);\n const expandedRef = useRef<HTMLDivElement>(null);\n const summaryRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const shell = shellRef.current;\n const expanded = expandedRef.current;\n const summary = summaryRef.current;\n if (!shell || !expanded || !summary) return;\n if (reduceMotion || typeof shell.animate !== \"function\") {\n onComplete();\n return;\n }\n\n let cancelled = false;\n const options: KeyframeAnimationOptions = {\n duration: COLLAPSE_DURATION_MS,\n easing: COLLAPSE_EASING,\n fill: \"forwards\",\n };\n const shellAnimation = shell.animate([\n { height: `${shell.scrollHeight}px` },\n { height: \"46px\" },\n ], options);\n const expandedAnimation = expanded.animate([\n { opacity: 1, transform: \"translateY(0)\" },\n { opacity: 0, transform: \"translateY(-6px)\" },\n ], options);\n const summaryAnimation = summary.animate([\n { opacity: 0, transform: \"translateY(6px)\" },\n { opacity: 1, transform: \"translateY(0)\" },\n ], options);\n\n void shellAnimation.finished\n .then(() => { if (!cancelled) onComplete(); })\n .catch(() => undefined);\n\n return () => {\n cancelled = true;\n shellAnimation.cancel();\n expandedAnimation.cancel();\n summaryAnimation.cancel();\n };\n }, [event.id, onComplete, reduceMotion]);\n\n return <div className=\"asr-collapse-shell\" ref={shellRef}>\n <div className=\"asr-collapse-expanded\" ref={expandedRef}>\n <ExpandedEvent event={event} visibleEvent={event} typing={false} />\n </div>\n <div className=\"asr-collapse-summary\" ref={summaryRef} aria-hidden=\"true\">\n <div className={`asr-event-summary-row asr-event-summary-row--${event.actor}`}>\n <EventSummaryContent event={event} index={index} />\n </div>\n </div>\n </div>;\n}\n\nexport function AgentSessionReplayer(props: AgentSessionReplayerProps) {\n const {\n agents,\n cases,\n typingSpeed,\n eventDelayMs,\n height,\n colors,\n caseIndex,\n initialCaseIndex,\n className,\n onCaseChange,\n onEventStart,\n onEventComplete,\n onCaseComplete,\n } = parseReplayerProps({\n ...props,\n typingSpeed: props.typingSpeed === undefined ? DEFAULT_TYPING_SPEED : props.typingSpeed,\n eventDelayMs: props.eventDelayMs === undefined ? DEFAULT_EVENT_DELAY : props.eventDelayMs,\n height: props.height === undefined ? 720 : props.height,\n initialCaseIndex: props.initialCaseIndex === undefined ? 0 : props.initialCaseIndex,\n });\n const controlled = caseIndex !== undefined;\n const [internalCaseIndex, setInternalCaseIndex] = useState(initialCaseIndex);\n const resolvedCaseIndex = controlled ? caseIndex : internalCaseIndex;\n const [state, dispatch] = useReducer(playbackReducer, undefined, initialPlaybackState);\n const [generation, bumpGeneration] = useReducer((value: number) => value + 1, 0);\n const [expandedEventIds, setExpandedEventIds] = useState<Set<string>>(() => new Set());\n const reduceMotion = usePrefersReducedMotion();\n const transcriptRef = useRef<HTMLDivElement>(null);\n const started = useRef(new Set<string>());\n const completed = useRef(new Set<string>());\n const completedCases = useRef(new Set<string>());\n const previousCase = useRef(resolvedCaseIndex);\n const activeCase = cases[resolvedCaseIndex]!;\n const caseChanged = previousCase.current !== resolvedCaseIndex;\n const eventIndex = caseChanged ? 0 : state.eventIndex;\n const revealOffset = caseChanged ? 0 : state.revealOffset;\n const phase = caseChanged ? \"typing\" : state.phase;\n const event = activeCase.events[eventIndex]!;\n const visibleEvent = useMemo(() => revealEvent(event, revealOffset), [event, revealOffset]);\n const finishCollapse = useCallback(() => {\n dispatch({ type: \"FINISH_COLLAPSE\", eventIndex });\n }, [eventIndex]);\n\n useEffect(() => {\n if (previousCase.current === resolvedCaseIndex) return;\n previousCase.current = resolvedCaseIndex;\n setExpandedEventIds(new Set());\n bumpGeneration();\n dispatch({ type: \"RESTART\" });\n }, [resolvedCaseIndex]);\n\n useEffect(() => {\n if (caseChanged) return;\n const key = `${generation}:${activeCase.id}:${event.id}`;\n if (!started.current.has(key)) {\n started.current.add(key);\n onEventStart?.(event, activeCase);\n }\n }, [activeCase, caseChanged, event, generation, onEventStart]);\n\n useEffect(() => {\n if (caseChanged) return;\n if (phase === \"typing\") {\n if (reduceMotion) {\n dispatch({ type: \"COMPLETE_EVENT\", item: activeCase, eventIndex });\n return;\n }\n const timer = window.setTimeout(() => dispatch({ type: \"TICK\", item: activeCase, eventIndex, amount: 1 }), 1000 / typingSpeed);\n return () => window.clearTimeout(timer);\n }\n if (phase === \"between-events\") {\n const timer = window.setTimeout(() => dispatch({ type: \"ADVANCE_EVENT\", eventIndex }), eventDelayMs);\n return () => window.clearTimeout(timer);\n }\n }, [activeCase, caseChanged, eventDelayMs, eventIndex, phase, reduceMotion, revealOffset, typingSpeed]);\n\n useEffect(() => {\n if (phase === \"typing\") return;\n const key = `${generation}:${activeCase.id}:${event.id}`;\n if (!completed.current.has(key)) {\n completed.current.add(key);\n onEventComplete?.(event, activeCase);\n }\n if (phase === \"case-complete\") {\n const caseKey = `${generation}:${activeCase.id}`;\n if (!completedCases.current.has(caseKey)) {\n completedCases.current.add(caseKey);\n onCaseComplete?.(activeCase);\n }\n }\n }, [activeCase, event, generation, onCaseComplete, onEventComplete, phase]);\n\n useEffect(() => {\n const transcript = transcriptRef.current;\n if (!transcript || transcript.scrollHeight <= transcript.clientHeight) return;\n transcript.scrollTo({ top: transcript.scrollHeight, behavior: reduceMotion ? \"auto\" : \"smooth\" });\n const bottomGap = transcript.scrollHeight - transcript.clientHeight - transcript.scrollTop;\n if (bottomGap > 1) transcript.scrollTop = transcript.scrollHeight;\n }, [eventIndex, reduceMotion, resolvedCaseIndex, revealOffset, visibleEvent.blocks.length]);\n\n const requestCase = (nextIndex: number) => {\n if (nextIndex === resolvedCaseIndex || nextIndex < 0 || nextIndex >= cases.length) return;\n if (!controlled) {\n setInternalCaseIndex(nextIndex);\n dispatch({ type: \"RESTART\" });\n }\n onCaseChange?.(nextIndex, cases[nextIndex]!);\n };\n\n const restart = () => {\n setExpandedEventIds(new Set());\n bumpGeneration();\n dispatch({ type: \"RESTART\" });\n };\n\n const toggleEvent = (eventId: string) => {\n setExpandedEventIds((current) => {\n const next = new Set(current);\n if (next.has(eventId)) next.delete(eventId);\n else next.add(eventId);\n return next;\n });\n };\n\n const style = {\n ...Object.fromEntries(Object.entries(colors ?? {}).map(([key, value]) => [colorVariables[key as keyof AgentSessionColors], value])),\n \"--asr-height\": `${height}px`,\n height: `${height}px`,\n } as CSSProperties;\n\n return <section data-agent-session-replayer className={`asr-root${className ? ` ${className}` : \"\"}`} style={style} aria-label=\"Two-agent review conversation\">\n <div className=\"asr-chat-stage\">\n <header className=\"asr-frame-header\">\n <div className=\"asr-workflow-line\"><span className=\"asr-brand\"><span>✣</span> Claude Code · Dynamic workflow</span><span className=\"asr-review-label\">Adversarial review</span></div>\n <p className=\"asr-case-summary\">{cases.length} bugs caught by adversarial review before merge</p>\n </header>\n <div className=\"asr-case-nav\">\n <div><span className=\"asr-case-progress\">Case {resolvedCaseIndex + 1} of {cases.length}</span><h2 className=\"asr-case-title\">{activeCase.title}</h2><span className=\"asr-repository\">{activeCase.repository} · {activeCase.branch} · {phase === \"case-complete\" ? \"Case complete\" : `Message ${eventIndex + 1} of ${activeCase.events.length}`}</span></div>\n <div className=\"asr-controls\" aria-label=\"Playback controls\">\n <button type=\"button\" onClick={() => requestCase(resolvedCaseIndex - 1)} disabled={resolvedCaseIndex === 0} aria-label=\"Previous case\">←</button>\n <button type=\"button\" onClick={restart} aria-label=\"Restart case\">Restart</button>\n <button type=\"button\" className=\"asr-next-button\" onClick={() => requestCase(resolvedCaseIndex + 1)} disabled={resolvedCaseIndex === cases.length - 1}>Next case →</button>\n </div>\n </div>\n <div className=\"asr-agent-row\"><Agent actor=\"implementer\" active={event.actor === \"implementer\"} agent={agents.implementer} /><Agent actor=\"reviewer\" active={event.actor === \"reviewer\"} agent={agents.reviewer} /></div>\n <div className=\"asr-transcript\" ref={transcriptRef}>\n {activeCase.events.slice(0, eventIndex).map((past, index) => <CompletedEvent event={past} index={index} expanded={expandedEventIds.has(past.id)} onToggle={() => toggleEvent(past.id)} key={past.id} />)}\n {phase === \"collapsing\" ? (\n <CollapsingEvent event={event} index={eventIndex} reduceMotion={reduceMotion} onComplete={finishCollapse} />\n ) : phase === \"between-events\" ? (\n <CompletedEvent event={event} index={eventIndex} expanded={expandedEventIds.has(event.id)} onToggle={() => toggleEvent(event.id)} key={event.id} />\n ) : (\n <div><ExpandedEvent event={event} visibleEvent={visibleEvent} typing={phase === \"typing\"} /></div>\n )}\n </div>\n <p className=\"asr-live-status\" aria-live=\"polite\">{phase === \"case-complete\" ? `${activeCase.title} complete.` : `Autoplaying ${event.title}.`}</p>\n <footer className=\"asr-footer\"><span>Scripted playback: each reviewer receives only the diff and is told to find how it is wrong. No live model is running.</span><a className=\"asr-watermark\" href=\"https://devos.ing\" target=\"_blank\" rel=\"noopener noreferrer\">devos</a></footer>\n </div>\n </section>;\n}\n","import type { AgentSession, AgentSessionEvent } from \"./types\";\n\nexport type PlaybackPhase = \"typing\" | \"collapsing\" | \"between-events\" | \"case-complete\";\nexport type PlaybackState = { eventIndex: number; revealOffset: number; phase: PlaybackPhase };\nexport const initialPlaybackState = (): PlaybackState => ({ eventIndex: 0, revealOffset: 0, phase: \"typing\" });\n\nexport const segmentGraphemes = (value: string): string[] => {\n if (typeof Intl.Segmenter === \"function\") return [...new Intl.Segmenter(undefined, { granularity: \"grapheme\" }).segment(value)].map(({ segment }) => segment);\n return Array.from(value);\n};\n\nexport const getEventText = (event: AgentSessionEvent): string => event.blocks.map((block) => `${block.title ? `${block.title}\\n` : \"\"}${block.content}`).join(\"\\n\");\nexport const getEventLength = (event: AgentSessionEvent): number => segmentGraphemes(getEventText(event)).length;\n\nexport const revealEvent = (event: AgentSessionEvent, offset: number): AgentSessionEvent => {\n let remaining = offset;\n const blocks = [];\n for (const block of event.blocks) {\n if (remaining <= 0) break;\n const titleParts = segmentGraphemes(block.title ?? \"\");\n const title = titleParts.slice(0, remaining).join(\"\");\n remaining = Math.max(0, remaining - titleParts.length - (block.title ? 1 : 0));\n const contentParts = segmentGraphemes(block.content);\n const content = contentParts.slice(0, remaining).join(\"\");\n remaining = Math.max(0, remaining - contentParts.length - 1);\n blocks.push({ ...block, title: block.title ? title : undefined, content });\n }\n return { ...event, blocks };\n};\n\nexport type PlaybackAction =\n | { type: \"TICK\"; item: AgentSession; eventIndex: number; amount: number }\n | { type: \"COMPLETE_EVENT\"; item: AgentSession; eventIndex: number }\n | { type: \"FINISH_COLLAPSE\"; eventIndex: number }\n | { type: \"ADVANCE_EVENT\"; eventIndex: number }\n | { type: \"RESTART\" };\n\nexport function playbackReducer(state: PlaybackState, action: PlaybackAction): PlaybackState {\n if (action.type === \"RESTART\") return initialPlaybackState();\n if (action.eventIndex !== state.eventIndex) return state;\n if (action.type === \"FINISH_COLLAPSE\") return state.phase === \"collapsing\" ? { ...state, phase: \"between-events\" } : state;\n if (action.type === \"ADVANCE_EVENT\") return state.phase === \"between-events\" ? { eventIndex: state.eventIndex + 1, revealOffset: 0, phase: \"typing\" } : state;\n if (state.phase !== \"typing\") return state;\n const event = action.item.events[state.eventIndex]!;\n const length = getEventLength(event);\n const revealOffset = action.type === \"COMPLETE_EVENT\" ? length : Math.min(length, state.revealOffset + action.amount);\n if (revealOffset < length) return { ...state, revealOffset };\n return { ...state, revealOffset, phase: state.eventIndex === action.item.events.length - 1 ? \"case-complete\" : \"collapsing\" };\n}\n","import { Fragment } from \"react\";\n\nexport type GitDiffLineKind =\n | \"metadata\"\n | \"hunk\"\n | \"addition\"\n | \"removal\"\n | \"context\";\n\nconst METADATA_PREFIXES = [\n \"diff --git \",\n \"index \",\n \"new file mode \",\n \"deleted file mode \",\n \"similarity index \",\n \"rename from \",\n \"rename to \",\n \"--- \",\n \"+++ \",\n \"\\\\",\n] as const;\n\nexport function classifyGitDiffLine(line: string): GitDiffLineKind {\n if (METADATA_PREFIXES.some((prefix) => line.startsWith(prefix))) return \"metadata\";\n if (line.startsWith(\"@@\")) return \"hunk\";\n if (line.startsWith(\"+\")) return \"addition\";\n if (line.startsWith(\"-\")) return \"removal\";\n return \"context\";\n}\n\nexport function GitDiffBlock({ content }: { content: string }) {\n const lines = content.split(\"\\n\");\n\n return <pre className=\"asr-git-diff\"><code>{lines.map((line, index) => {\n const kind = classifyGitDiffLine(line);\n return <Fragment key={index}>\n <span className={`asr-git-diff-line asr-git-diff-line--${kind}`}>{line}</span>\n {index < lines.length - 1 ? \"\\n\" : null}\n </Fragment>;\n })}</code></pre>;\n}\n"],"mappings":"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","names":["Fragment","jsx","jsxs"]}
|