@shipfox/client-logs 27.0.1 → 29.0.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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-type$colon$emit.log +0 -1
- package/CHANGELOG.md +10 -0
- package/dist/components/agent-session-rows.js +273 -232
- package/dist/components/agent-session-rows.js.map +1 -1
- package/dist/components/log-view.d.ts.map +1 -1
- package/dist/components/log-view.js +4 -1
- package/dist/components/log-view.js.map +1 -1
- package/dist/core/log-tree.d.ts.map +1 -1
- package/dist/core/log-tree.js +109 -123
- package/dist/core/log-tree.js.map +1 -1
- package/dist/hooks/api/step-logs.d.ts.map +1 -1
- package/dist/hooks/api/step-logs.js +51 -38
- package/dist/hooks/api/step-logs.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/components/agent-session-rows.tsx +259 -177
- package/src/components/log-view.tsx +7 -5
- package/src/core/log-tree.ts +117 -104
- package/src/hooks/api/step-logs.ts +73 -47
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/agent-session-rows.tsx"],"sourcesContent":["'use client';\n\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {\n LogContent,\n LogDisclosure,\n LogDisclosureContent,\n LogDisclosureTrigger,\n LogRow,\n} from '@shipfox/react-ui/log';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Fragment, useEffect, useState} from 'react';\nimport type {SessionViewRow, SessionViewRowMeta} from '#core/log-model.js';\n\nconst PREVIEW_CHAR_LIMIT = 1200;\nconst WORD_SUMMARY_CHAR_LIMIT = 5000;\nconst WHITESPACE = /\\s+/g;\nconst WORD_SEPARATOR = /\\s+/;\n\nexport interface AgentSessionRowsProps {\n rows: readonly SessionViewRow[];\n resolvedToolCallIds: ReadonlySet<string>;\n toolCallNames: ReadonlyMap<string, string>;\n indent: number;\n forceOpen?: boolean;\n}\n\nexport function AgentSessionRows({\n rows,\n resolvedToolCallIds,\n toolCallNames,\n indent,\n forceOpen = false,\n}: AgentSessionRowsProps) {\n return rows.map((row, index) => (\n <AgentSessionRowView\n // biome-ignore lint/suspicious/noArrayIndexKey: session rows are immutable and never reordered, so the index is stable; content keys would balloon to megabyte strings and collide on repeated id-less tool calls.\n key={`${row.kind}-${index}`}\n row={row}\n resolvedToolCallIds={resolvedToolCallIds}\n toolCallNames={toolCallNames}\n indent={indent}\n forceOpen={forceOpen}\n />\n ));\n}\n\nfunction AgentSessionRowView({\n row,\n resolvedToolCallIds,\n toolCallNames,\n indent,\n forceOpen,\n}: {\n row: SessionViewRow;\n resolvedToolCallIds: ReadonlySet<string>;\n toolCallNames: ReadonlyMap<string, string>;\n indent: number;\n forceOpen: boolean;\n}) {\n const [open, setOpen] = useState(false);\n useEffect(() => {\n if (forceOpen) setOpen(true);\n }, [forceOpen]);\n const disclosureProps = {open: forceOpen || open, onOpenChange: setOpen};\n\n switch (row.kind) {\n case 'message':\n return (\n <LogRow\n lineNumber={null}\n timestamp={new Date(row.timestamp)}\n indent={indent}\n tone={row.terminalFailure ? 'error' : 'default'}\n data-log-terminal-failure={row.terminalFailure ? 'true' : undefined}\n >\n <LogContent className=\"text-foreground-contrast-primary\">\n <span className=\"flex min-w-0 items-start gap-inline\">\n <MessageIcon role={row.role} terminalFailure={row.terminalFailure} />\n <span className=\"flex min-w-0 flex-1 flex-col gap-tight\">\n <span className=\"flex min-w-0 items-center gap-inline\">\n <MessageRoleLabel label={row.label} terminalFailure={row.terminalFailure} />\n <RowMetadata meta={row.meta} className=\"ml-auto flex-none\" />\n </span>\n <span className=\"block min-w-0\">\n <PreviewText text={row.text} />\n </span>\n </span>\n </span>\n </LogContent>\n </LogRow>\n );\n case 'thinking':\n return (\n <LogDisclosure indent={indent} {...disclosureProps}>\n <LogDisclosureTrigger\n summary={wordSummary(row.text)}\n timestamp={new Date(row.timestamp)}\n className=\"text-foreground-contrast-secondary\"\n >\n thinking\n </LogDisclosureTrigger>\n <LogDisclosureContent className=\"text-foreground-contrast-secondary\">\n <LogContent className=\"text-foreground-contrast-secondary\">\n <PreviewText text={row.text} />\n </LogContent>\n </LogDisclosureContent>\n </LogDisclosure>\n );\n case 'tool-call': {\n const awaitingResult = row.id != null && !resolvedToolCallIds.has(row.id);\n return (\n <LogDisclosure indent={indent} {...disclosureProps}>\n <LogDisclosureTrigger\n timestamp={new Date(row.timestamp)}\n summary={compactPreview(row.summary ?? row.input)}\n trailing={\n awaitingResult ? (\n <span className=\"inline-flex items-center gap-tight\">\n <Icon\n name=\"loader4Line\"\n className=\"size-12 motion-safe:animate-spin\"\n aria-hidden=\"true\"\n />\n awaiting result\n </span>\n ) : null\n }\n >\n <span className=\"inline-flex min-w-0 items-center gap-inline\">\n <Icon name=\"terminalBoxLine\" className=\"size-14 flex-none\" aria-hidden=\"true\" />\n <span className=\"truncate\">tool {row.name}</span>\n </span>\n </LogDisclosureTrigger>\n <LogDisclosureContent>\n {row.summary != null ? (\n <>\n <LogContent>\n <PreviewText text={row.summary} />\n </LogContent>\n <LogContent variant=\"code\">\n <PreviewText text={row.input} />\n </LogContent>\n </>\n ) : (\n <LogContent variant=\"code\">\n <PreviewText text={row.input} />\n </LogContent>\n )}\n </LogDisclosureContent>\n </LogDisclosure>\n );\n }\n case 'tool-result': {\n const toolName =\n row.toolName === 'tool'\n ? ((row.toolCallId != null ? toolCallNames.get(row.toolCallId) : undefined) ??\n '(unmatched)')\n : row.toolName;\n return (\n <LogDisclosure indent={indent} {...disclosureProps}>\n <LogDisclosureTrigger\n timestamp={new Date(row.timestamp)}\n summary={compactPreview(row.output)}\n trailing={\n <span\n className={cn(\n 'inline-flex items-center gap-tight',\n row.isError ? 'text-tag-error-icon' : 'text-foreground-contrast-secondary',\n )}\n >\n <Icon\n name={row.isError ? 'closeCircleLine' : 'checkLine'}\n className=\"size-12\"\n aria-hidden=\"true\"\n />\n {row.isError ? 'error' : 'ok'}\n </span>\n }\n >\n <span className=\"inline-flex min-w-0 items-center gap-inline\">\n <Icon name=\"terminalWindowLine\" className=\"size-14 flex-none\" aria-hidden=\"true\" />\n <span className=\"truncate\">result {toolName}</span>\n </span>\n </LogDisclosureTrigger>\n <LogDisclosureContent>\n <LogContent variant=\"code\" className=\"text-foreground-contrast-primary\">\n <PreviewText text={row.output} />\n </LogContent>\n </LogDisclosureContent>\n </LogDisclosure>\n );\n }\n case 'lifecycle':\n return (\n <LogRow\n lineNumber={null}\n timestamp={new Date(row.timestamp)}\n indent={indent}\n tone={row.tone}\n data-log-terminal-failure={row.terminalFailure ? 'true' : undefined}\n >\n <LogContent className=\"text-foreground-contrast-secondary\">\n <span className=\"inline-flex w-full items-center gap-inline\">\n <Icon name=\"informationLine\" className=\"size-14 flex-none\" aria-hidden=\"true\" />\n <span className=\"min-w-0\">\n <span className=\"font-medium\">{row.label}</span>\n {row.detail != null ? (\n <>\n {' · '}\n <span className=\"text-foreground-contrast-secondary\">{row.detail}</span>\n </>\n ) : null}\n </span>\n <span\n aria-hidden=\"true\"\n className=\"h-px flex-1 border-t border-dashed border-current opacity-30\"\n />\n <RowMetadata meta={row.meta} />\n </span>\n </LogContent>\n </LogRow>\n );\n case 'raw':\n return (\n <LogDisclosure indent={indent} {...disclosureProps}>\n <LogDisclosureTrigger\n timestamp={new Date(row.timestamp)}\n summary={compactPreview(row.raw)}\n className=\"text-foreground-contrast-primary\"\n >\n <span className=\"inline-flex min-w-0 items-center gap-inline\">\n <Icon\n name=\"errorWarningLine\"\n className=\"size-14 flex-none text-tag-warning-icon\"\n aria-hidden=\"true\"\n />\n <span className=\"truncate\">{row.label}</span>\n </span>\n </LogDisclosureTrigger>\n <LogDisclosureContent>\n <LogContent variant=\"code\">\n <PreviewText text={row.raw} />\n </LogContent>\n </LogDisclosureContent>\n </LogDisclosure>\n );\n default:\n return assertNever(row);\n }\n}\n\nfunction MessageIcon({role, terminalFailure}: {role: string; terminalFailure: boolean}) {\n const name = terminalFailure\n ? 'closeCircleLine'\n : role === 'user'\n ? 'userLine'\n : role === 'assistant'\n ? 'robot2Line'\n : 'message2Line';\n\n return (\n <Icon\n name={name}\n className={cn(\n 'mt-[2px] size-14 flex-none',\n terminalFailure ? 'text-tag-error-icon' : 'text-foreground-contrast-secondary',\n )}\n aria-hidden=\"true\"\n />\n );\n}\n\nfunction MessageRoleLabel({label, terminalFailure}: {label: string; terminalFailure: boolean}) {\n return (\n <span\n className={cn(\n 'min-w-0 font-code text-foreground-contrast-secondary',\n terminalFailure && 'text-foreground-contrast-primary',\n )}\n >\n <span className=\"truncate\">{label}</span>\n </span>\n );\n}\n\nfunction RowMetadata({meta, className}: {meta: readonly SessionViewRowMeta[]; className?: string}) {\n if (meta.length === 0) return null;\n\n const inlineMeta = meta.length === 1 && meta[0]?.inline !== false ? meta[0] : null;\n if (inlineMeta != null) {\n return (\n <span\n className={cn('font-code text-xs text-foreground-contrast-secondary', className)}\n title={`${inlineMeta.label}: ${inlineMeta.value}`}\n >\n {inlineMeta.value}\n </span>\n );\n }\n\n return (\n <span className={className}>\n <MetadataTrigger meta={meta} />\n </span>\n );\n}\n\nfunction MetadataTrigger({meta}: {meta: readonly SessionViewRowMeta[]}) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n className=\"inline-flex size-20 flex-none items-center justify-center rounded-4 text-foreground-contrast-secondary opacity-60 transition-opacity hover:bg-background-components-hover hover:text-foreground-contrast-primary hover:opacity-100 focus-visible:opacity-100 focus-visible:shadow-focus-inset group-hover/log-row:opacity-100\"\n aria-label=\"Show message metadata\"\n >\n <Icon name=\"informationLine\" className=\"size-12\" aria-hidden=\"true\" />\n </button>\n </TooltipTrigger>\n <TooltipContent align=\"end\" variant=\"inverted\" className=\"max-w-360 p-tight\">\n <span className=\"grid grid-cols-[max-content_minmax(0,1fr)] gap-x-[var(--space-inline)] gap-y-[var(--space-tight)] font-code text-xs\">\n {meta.map((item) => (\n <Fragment key={`${item.label}-${item.value}`}>\n <span className=\"text-foreground-contrast-secondary\">{item.label}</span>\n <span className=\"min-w-0 break-all text-foreground-contrast-primary\">\n {item.value}\n </span>\n </Fragment>\n ))}\n </span>\n </TooltipContent>\n </Tooltip>\n );\n}\n\nfunction PreviewText({text}: {text: string}) {\n const [expanded, setExpanded] = useState(false);\n const truncated = text.length > PREVIEW_CHAR_LIMIT;\n const visible = truncated && !expanded ? `${text.slice(0, PREVIEW_CHAR_LIMIT)}…` : text;\n\n return (\n <>\n {visible}\n {truncated ? (\n <button\n type=\"button\"\n aria-expanded={expanded}\n className=\"ms-inline inline-flex min-h-24 items-center rounded-4 px-tight font-display text-xs text-foreground-highlight-interactive focus-visible:shadow-focus-inset\"\n onClick={() => setExpanded((value) => !value)}\n >\n {expanded ? 'show less' : 'show more'}\n </button>\n ) : null}\n </>\n );\n}\n\nfunction compactPreview(value: string): string {\n // Normalize only a bounded head: tool output can be megabytes, and this runs\n // per render for every disclosure trigger.\n const head = value.length > 200 ? value.slice(0, 200) : value;\n const singleLine = head.replace(WHITESPACE, ' ').trim();\n if (singleLine.length <= 80) return singleLine;\n return `${singleLine.slice(0, 80)}…`;\n}\n\nfunction wordSummary(value: string): string {\n const truncated = value.length > WORD_SUMMARY_CHAR_LIMIT;\n const head = truncated ? value.slice(0, WORD_SUMMARY_CHAR_LIMIT) : value;\n const count = head.trim().split(WORD_SEPARATOR).filter(Boolean).length;\n const marker = truncated ? '+' : '';\n return `${count}${marker} ${count === 1 ? 'word' : 'words'}`;\n}\n\nfunction assertNever(value: never): never {\n throw new Error(`unexpected agent session row: ${JSON.stringify(value)}`);\n}\n"],"names":["Icon","LogContent","LogDisclosure","LogDisclosureContent","LogDisclosureTrigger","LogRow","Tooltip","TooltipContent","TooltipTrigger","cn","Fragment","useEffect","useState","PREVIEW_CHAR_LIMIT","WORD_SUMMARY_CHAR_LIMIT","WHITESPACE","WORD_SEPARATOR","AgentSessionRows","rows","resolvedToolCallIds","toolCallNames","indent","forceOpen","map","row","index","AgentSessionRowView","kind","open","setOpen","disclosureProps","onOpenChange","lineNumber","timestamp","Date","tone","terminalFailure","data-log-terminal-failure","undefined","className","span","MessageIcon","role","MessageRoleLabel","label","RowMetadata","meta","PreviewText","text","summary","wordSummary","awaitingResult","id","has","compactPreview","input","trailing","name","aria-hidden","variant","toolName","toolCallId","get","output","isError","detail","raw","assertNever","length","inlineMeta","inline","title","value","MetadataTrigger","asChild","button","type","aria-label","align","item","expanded","setExpanded","truncated","visible","slice","aria-expanded","onClick","head","singleLine","replace","trim","count","split","filter","Boolean","marker","Error","JSON","stringify"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/components/agent-session-rows.tsx"],"sourcesContent":["'use client';\n\nimport {Icon, type IconName} from '@shipfox/react-ui/icon';\nimport {\n LogContent,\n LogDisclosure,\n LogDisclosureContent,\n LogDisclosureTrigger,\n LogRow,\n} from '@shipfox/react-ui/log';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Fragment, useEffect, useState} from 'react';\nimport type {SessionViewRow, SessionViewRowMeta} from '#core/log-model.js';\n\nconst PREVIEW_CHAR_LIMIT = 1200;\nconst WORD_SUMMARY_CHAR_LIMIT = 5000;\nconst WHITESPACE = /\\s+/g;\nconst WORD_SEPARATOR = /\\s+/;\n\nexport interface AgentSessionRowsProps {\n rows: readonly SessionViewRow[];\n resolvedToolCallIds: ReadonlySet<string>;\n toolCallNames: ReadonlyMap<string, string>;\n indent: number;\n forceOpen?: boolean;\n}\n\nexport function AgentSessionRows({\n rows,\n resolvedToolCallIds,\n toolCallNames,\n indent,\n forceOpen = false,\n}: AgentSessionRowsProps) {\n return rows.map((row, index) => (\n <AgentSessionRowView\n // biome-ignore lint/suspicious/noArrayIndexKey: session rows are immutable and never reordered, so the index is stable; content keys would balloon to megabyte strings and collide on repeated id-less tool calls.\n key={`${row.kind}-${index}`}\n row={row}\n resolvedToolCallIds={resolvedToolCallIds}\n toolCallNames={toolCallNames}\n indent={indent}\n forceOpen={forceOpen}\n />\n ));\n}\n\nfunction AgentSessionRowView({\n row,\n resolvedToolCallIds,\n toolCallNames,\n indent,\n forceOpen,\n}: {\n row: SessionViewRow;\n resolvedToolCallIds: ReadonlySet<string>;\n toolCallNames: ReadonlyMap<string, string>;\n indent: number;\n forceOpen: boolean;\n}) {\n const [open, setOpen] = useState(false);\n useEffect(() => {\n if (forceOpen) setOpen(true);\n }, [forceOpen]);\n const disclosureProps = {open: forceOpen || open, onOpenChange: setOpen};\n\n switch (row.kind) {\n case 'message':\n return <SessionMessageRow row={row} indent={indent} />;\n case 'thinking':\n return <SessionThinkingRow row={row} indent={indent} disclosure={disclosureProps} />;\n case 'tool-call':\n return (\n <SessionToolCallRow\n row={row}\n indent={indent}\n disclosure={disclosureProps}\n resolvedToolCallIds={resolvedToolCallIds}\n />\n );\n case 'tool-result':\n return (\n <SessionToolResultRow\n row={row}\n indent={indent}\n disclosure={disclosureProps}\n toolCallNames={toolCallNames}\n />\n );\n case 'lifecycle':\n return <SessionLifecycleRow row={row} indent={indent} />;\n case 'raw':\n return <SessionRawRow row={row} indent={indent} disclosure={disclosureProps} />;\n default:\n return assertNever(row);\n }\n}\n\ntype DisclosureState = {open: boolean; onOpenChange: (open: boolean) => void};\n\nfunction SessionMessageRow({\n row,\n indent,\n}: {\n row: Extract<SessionViewRow, {kind: 'message'}>;\n indent: number;\n}) {\n return (\n <LogRow\n lineNumber={null}\n timestamp={new Date(row.timestamp)}\n indent={indent}\n tone={row.terminalFailure ? 'error' : 'default'}\n data-log-terminal-failure={row.terminalFailure ? 'true' : undefined}\n >\n <LogContent className=\"text-foreground-contrast-primary\">\n <span className=\"flex min-w-0 items-start gap-inline\">\n <MessageIcon role={row.role} terminalFailure={row.terminalFailure} />\n <span className=\"flex min-w-0 flex-1 flex-col gap-tight\">\n <span className=\"flex min-w-0 items-center gap-inline\">\n <MessageRoleLabel label={row.label} terminalFailure={row.terminalFailure} />\n <RowMetadata meta={row.meta} className=\"ml-auto flex-none\" />\n </span>\n <span className=\"block min-w-0\">\n <PreviewText text={row.text} />\n </span>\n </span>\n </span>\n </LogContent>\n </LogRow>\n );\n}\n\nfunction SessionThinkingRow({\n row,\n indent,\n disclosure,\n}: {\n row: Extract<SessionViewRow, {kind: 'thinking'}>;\n indent: number;\n disclosure: DisclosureState;\n}) {\n return (\n <LogDisclosure indent={indent} {...disclosure}>\n <LogDisclosureTrigger\n summary={wordSummary(row.text)}\n timestamp={new Date(row.timestamp)}\n className=\"text-foreground-contrast-secondary\"\n >\n thinking\n </LogDisclosureTrigger>\n <LogDisclosureContent className=\"text-foreground-contrast-secondary\">\n <LogContent className=\"text-foreground-contrast-secondary\">\n <PreviewText text={row.text} />\n </LogContent>\n </LogDisclosureContent>\n </LogDisclosure>\n );\n}\n\nfunction SessionToolCallRow({\n row,\n indent,\n disclosure,\n resolvedToolCallIds,\n}: {\n row: Extract<SessionViewRow, {kind: 'tool-call'}>;\n indent: number;\n disclosure: DisclosureState;\n resolvedToolCallIds: ReadonlySet<string>;\n}) {\n const awaitingResult = row.id != null && !resolvedToolCallIds.has(row.id);\n return (\n <LogDisclosure indent={indent} {...disclosure}>\n <LogDisclosureTrigger\n timestamp={new Date(row.timestamp)}\n summary={compactPreview(row.summary ?? row.input)}\n trailing={\n awaitingResult ? (\n <span className=\"inline-flex items-center gap-tight\">\n <Icon\n name=\"loader4Line\"\n className=\"size-12 motion-safe:animate-spin\"\n aria-hidden=\"true\"\n />\n awaiting result\n </span>\n ) : null\n }\n >\n <span className=\"inline-flex min-w-0 items-center gap-inline\">\n <Icon name=\"terminalBoxLine\" className=\"size-14 flex-none\" aria-hidden=\"true\" />\n <span className=\"truncate\">tool {row.name}</span>\n </span>\n </LogDisclosureTrigger>\n <LogDisclosureContent>\n {row.summary != null ? (\n <>\n <LogContent>\n <PreviewText text={row.summary} />\n </LogContent>\n <LogContent variant=\"code\">\n <PreviewText text={row.input} />\n </LogContent>\n </>\n ) : (\n <LogContent variant=\"code\">\n <PreviewText text={row.input} />\n </LogContent>\n )}\n </LogDisclosureContent>\n </LogDisclosure>\n );\n}\n\nfunction SessionToolResultRow({\n row,\n indent,\n disclosure,\n toolCallNames,\n}: {\n row: Extract<SessionViewRow, {kind: 'tool-result'}>;\n indent: number;\n disclosure: DisclosureState;\n toolCallNames: ReadonlyMap<string, string>;\n}) {\n const toolName =\n row.toolName === 'tool'\n ? ((row.toolCallId != null ? toolCallNames.get(row.toolCallId) : undefined) ?? '(unmatched)')\n : row.toolName;\n return (\n <LogDisclosure indent={indent} {...disclosure}>\n <LogDisclosureTrigger\n timestamp={new Date(row.timestamp)}\n summary={compactPreview(row.output)}\n trailing={\n <span\n className={cn(\n 'inline-flex items-center gap-tight',\n row.isError ? 'text-tag-error-icon' : 'text-foreground-contrast-secondary',\n )}\n >\n <Icon\n name={row.isError ? 'closeCircleLine' : 'checkLine'}\n className=\"size-12\"\n aria-hidden=\"true\"\n />\n {row.isError ? 'error' : 'ok'}\n </span>\n }\n >\n <span className=\"inline-flex min-w-0 items-center gap-inline\">\n <Icon name=\"terminalWindowLine\" className=\"size-14 flex-none\" aria-hidden=\"true\" />\n <span className=\"truncate\">result {toolName}</span>\n </span>\n </LogDisclosureTrigger>\n <LogDisclosureContent>\n <LogContent variant=\"code\" className=\"text-foreground-contrast-primary\">\n <PreviewText text={row.output} />\n </LogContent>\n </LogDisclosureContent>\n </LogDisclosure>\n );\n}\n\nfunction SessionLifecycleRow({\n row,\n indent,\n}: {\n row: Extract<SessionViewRow, {kind: 'lifecycle'}>;\n indent: number;\n}) {\n return (\n <LogRow\n lineNumber={null}\n timestamp={new Date(row.timestamp)}\n indent={indent}\n tone={row.tone}\n data-log-terminal-failure={row.terminalFailure ? 'true' : undefined}\n >\n <LogContent className=\"text-foreground-contrast-secondary\">\n <span className=\"inline-flex w-full items-center gap-inline\">\n <Icon name=\"informationLine\" className=\"size-14 flex-none\" aria-hidden=\"true\" />\n <span className=\"min-w-0\">\n <span className=\"font-medium\">{row.label}</span>\n {row.detail != null ? (\n <>\n {' · '}\n <span className=\"text-foreground-contrast-secondary\">{row.detail}</span>\n </>\n ) : null}\n </span>\n <span\n aria-hidden=\"true\"\n className=\"h-px flex-1 border-t border-dashed border-current opacity-30\"\n />\n <RowMetadata meta={row.meta} />\n </span>\n </LogContent>\n </LogRow>\n );\n}\n\nfunction SessionRawRow({\n row,\n indent,\n disclosure,\n}: {\n row: Extract<SessionViewRow, {kind: 'raw'}>;\n indent: number;\n disclosure: DisclosureState;\n}) {\n return (\n <LogDisclosure indent={indent} {...disclosure}>\n <LogDisclosureTrigger\n timestamp={new Date(row.timestamp)}\n summary={compactPreview(row.raw)}\n className=\"text-foreground-contrast-primary\"\n >\n <span className=\"inline-flex min-w-0 items-center gap-inline\">\n <Icon\n name=\"errorWarningLine\"\n className=\"size-14 flex-none text-tag-warning-icon\"\n aria-hidden=\"true\"\n />\n <span className=\"truncate\">{row.label}</span>\n </span>\n </LogDisclosureTrigger>\n <LogDisclosureContent>\n <LogContent variant=\"code\">\n <PreviewText text={row.raw} />\n </LogContent>\n </LogDisclosureContent>\n </LogDisclosure>\n );\n}\n\nfunction MessageIcon({role, terminalFailure}: {role: string; terminalFailure: boolean}) {\n let name: IconName = 'message2Line';\n if (terminalFailure) name = 'closeCircleLine';\n else if (role === 'user') name = 'userLine';\n else if (role === 'assistant') name = 'robot2Line';\n\n return (\n <Icon\n name={name}\n className={cn(\n 'mt-[2px] size-14 flex-none',\n terminalFailure ? 'text-tag-error-icon' : 'text-foreground-contrast-secondary',\n )}\n aria-hidden=\"true\"\n />\n );\n}\n\nfunction MessageRoleLabel({label, terminalFailure}: {label: string; terminalFailure: boolean}) {\n return (\n <span\n className={cn(\n 'min-w-0 font-code text-foreground-contrast-secondary',\n terminalFailure && 'text-foreground-contrast-primary',\n )}\n >\n <span className=\"truncate\">{label}</span>\n </span>\n );\n}\n\nfunction RowMetadata({meta, className}: {meta: readonly SessionViewRowMeta[]; className?: string}) {\n if (meta.length === 0) return null;\n\n const inlineMeta = meta.length === 1 && meta[0]?.inline !== false ? meta[0] : null;\n if (inlineMeta != null) {\n return (\n <span\n className={cn('font-code text-xs text-foreground-contrast-secondary', className)}\n title={`${inlineMeta.label}: ${inlineMeta.value}`}\n >\n {inlineMeta.value}\n </span>\n );\n }\n\n return (\n <span className={className}>\n <MetadataTrigger meta={meta} />\n </span>\n );\n}\n\nfunction MetadataTrigger({meta}: {meta: readonly SessionViewRowMeta[]}) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n className=\"inline-flex size-20 flex-none items-center justify-center rounded-4 text-foreground-contrast-secondary opacity-60 transition-opacity hover:bg-background-components-hover hover:text-foreground-contrast-primary hover:opacity-100 focus-visible:opacity-100 focus-visible:shadow-focus-inset group-hover/log-row:opacity-100\"\n aria-label=\"Show message metadata\"\n >\n <Icon name=\"informationLine\" className=\"size-12\" aria-hidden=\"true\" />\n </button>\n </TooltipTrigger>\n <TooltipContent align=\"end\" variant=\"inverted\" className=\"max-w-360 p-tight\">\n <span className=\"grid grid-cols-[max-content_minmax(0,1fr)] gap-x-[var(--space-inline)] gap-y-[var(--space-tight)] font-code text-xs\">\n {meta.map((item) => (\n <Fragment key={`${item.label}-${item.value}`}>\n <span className=\"text-foreground-contrast-secondary\">{item.label}</span>\n <span className=\"min-w-0 break-all text-foreground-contrast-primary\">\n {item.value}\n </span>\n </Fragment>\n ))}\n </span>\n </TooltipContent>\n </Tooltip>\n );\n}\n\nfunction PreviewText({text}: {text: string}) {\n const [expanded, setExpanded] = useState(false);\n const truncated = text.length > PREVIEW_CHAR_LIMIT;\n const visible = truncated && !expanded ? `${text.slice(0, PREVIEW_CHAR_LIMIT)}…` : text;\n\n return (\n <>\n {visible}\n {truncated ? (\n <button\n type=\"button\"\n aria-expanded={expanded}\n className=\"ms-inline inline-flex min-h-24 items-center rounded-4 px-tight font-display text-xs text-foreground-highlight-interactive focus-visible:shadow-focus-inset\"\n onClick={() => setExpanded((value) => !value)}\n >\n {expanded ? 'show less' : 'show more'}\n </button>\n ) : null}\n </>\n );\n}\n\nfunction compactPreview(value: string): string {\n // Normalize only a bounded head: tool output can be megabytes, and this runs\n // per render for every disclosure trigger.\n const head = value.length > 200 ? value.slice(0, 200) : value;\n const singleLine = head.replace(WHITESPACE, ' ').trim();\n if (singleLine.length <= 80) return singleLine;\n return `${singleLine.slice(0, 80)}…`;\n}\n\nfunction wordSummary(value: string): string {\n const truncated = value.length > WORD_SUMMARY_CHAR_LIMIT;\n const head = truncated ? value.slice(0, WORD_SUMMARY_CHAR_LIMIT) : value;\n const count = head.trim().split(WORD_SEPARATOR).filter(Boolean).length;\n const marker = truncated ? '+' : '';\n return `${count}${marker} ${count === 1 ? 'word' : 'words'}`;\n}\n\nfunction assertNever(value: never): never {\n throw new Error(`unexpected agent session row: ${JSON.stringify(value)}`);\n}\n"],"names":["Icon","LogContent","LogDisclosure","LogDisclosureContent","LogDisclosureTrigger","LogRow","Tooltip","TooltipContent","TooltipTrigger","cn","Fragment","useEffect","useState","PREVIEW_CHAR_LIMIT","WORD_SUMMARY_CHAR_LIMIT","WHITESPACE","WORD_SEPARATOR","AgentSessionRows","rows","resolvedToolCallIds","toolCallNames","indent","forceOpen","map","row","index","AgentSessionRowView","kind","open","setOpen","disclosureProps","onOpenChange","SessionMessageRow","SessionThinkingRow","disclosure","SessionToolCallRow","SessionToolResultRow","SessionLifecycleRow","SessionRawRow","assertNever","lineNumber","timestamp","Date","tone","terminalFailure","data-log-terminal-failure","undefined","className","span","MessageIcon","role","MessageRoleLabel","label","RowMetadata","meta","PreviewText","text","summary","wordSummary","awaitingResult","id","has","compactPreview","input","trailing","name","aria-hidden","variant","toolName","toolCallId","get","output","isError","detail","raw","length","inlineMeta","inline","title","value","MetadataTrigger","asChild","button","type","aria-label","align","item","expanded","setExpanded","truncated","visible","slice","aria-expanded","onClick","head","singleLine","replace","trim","count","split","filter","Boolean","marker","Error","JSON","stringify"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-view.d.ts","sourceRoot":"","sources":["../../src/components/log-view.tsx"],"names":[],"mappings":"AAGA,OAAO,EAA8B,KAAK,gBAAgB,EAAC,MAAM,uBAAuB,CAAC;AAEzF,OAAO,EAEL,KAAK,cAAc,EAKpB,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAclD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IACpC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC1C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,EAAE,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;CACvD;AAED,MAAM,WAAW,oBACf,SAAQ,IAAI,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM,GAAG,iBAAiB,GAAG,WAAW,CAAC;IACnF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,OAAO,CAAC,EACtB,OAAO,EACP,UAAkB,EAClB,IAAY,EACZ,eAAsB,EACtB,UAAuB,EACvB,iBAAyB,EACzB,eAAuB,EACvB,MAAW,EACX,QAAmB,EACnB,SAAS,EACT,QAAQ,GACT,EAAE,YAAY,+
|
|
1
|
+
{"version":3,"file":"log-view.d.ts","sourceRoot":"","sources":["../../src/components/log-view.tsx"],"names":[],"mappings":"AAGA,OAAO,EAA8B,KAAK,gBAAgB,EAAC,MAAM,uBAAuB,CAAC;AAEzF,OAAO,EAEL,KAAK,cAAc,EAKpB,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAclD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IACpC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC1C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,EAAE,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;CACvD;AAED,MAAM,WAAW,oBACf,SAAQ,IAAI,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM,GAAG,iBAAiB,GAAG,WAAW,CAAC;IACnF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,OAAO,CAAC,EACtB,OAAO,EACP,UAAkB,EAClB,IAAY,EACZ,eAAsB,EACtB,UAAuB,EACvB,iBAAyB,EACzB,eAAuB,EACvB,MAAW,EACX,QAAmB,EACnB,SAAS,EACT,QAAQ,GACT,EAAE,YAAY,+BA0Ed;AAED,wBAAgB,eAAe,CAAC,EAC9B,IAAQ,EACR,UAAkB,EAClB,IAAY,EACZ,eAAsB,EACtB,SAAS,GACV,EAAE,oBAAoB,+BAuBtB"}
|
|
@@ -30,7 +30,10 @@ export function LogView({ records, timestamps = 'off', wrap = false, showLineNum
|
|
|
30
30
|
]);
|
|
31
31
|
const noOutputState = normalizedSearch ? null : getNoOutputState(tree, emptyState);
|
|
32
32
|
const anchorRecordCount = records.length;
|
|
33
|
-
|
|
33
|
+
let searchStatus = null;
|
|
34
|
+
if (normalizedSearch) {
|
|
35
|
+
searchStatus = visibleNodes.length === 0 ? `No log lines match “${deferredSearch.trim()}”.` : `Log search updated for “${deferredSearch.trim()}”.`;
|
|
36
|
+
}
|
|
34
37
|
useEffect(()=>{
|
|
35
38
|
if (!anchorToFailure) return;
|
|
36
39
|
if (anchorRecordCount === 0) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/log-view.tsx"],"sourcesContent":["'use client';\n\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {LogContent, LogRow, LogRows, type LogTimestampMode} from '@shipfox/react-ui/log';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {\n type ReactNode,\n type UIEventHandler,\n useDeferredValue,\n useEffect,\n useMemo,\n useRef,\n} from 'react';\nimport type {LogRecord} from '#core/log-model.js';\nimport {buildLogSearchIndex, filterLogNodes} from '#core/log-search.js';\nimport {\n assertNever,\n buildLogTree,\n type LogNode,\n type LogTree,\n type MarkerLogRecord,\n} from '#core/log-tree.js';\nimport {AgentSessionRows} from './agent-session-rows.js';\nimport {LogGroup} from './log-group.js';\nimport {OutputLogRow} from './output-log-row.js';\nimport {CappedMarker, EndMarker, GapMarker, RunnerLostMarker} from './system-markers.js';\n\nexport interface LogViewProps {\n records: readonly LogRecord[];\n timestamps?: LogTimestampMode;\n wrap?: boolean;\n showLineNumbers?: boolean;\n emptyState?: 'complete' | 'pending';\n defaultGroupsOpen?: boolean;\n anchorToFailure?: boolean;\n search?: string;\n ariaLive?: 'off' | 'polite' | 'assertive';\n className?: string | undefined;\n onScroll?: UIEventHandler<HTMLDivElement> | undefined;\n}\n\nexport interface LogViewSkeletonProps\n extends Pick<LogViewProps, 'timestamps' | 'wrap' | 'showLineNumbers' | 'className'> {\n rows?: number;\n}\n\nexport function LogView({\n records,\n timestamps = 'off',\n wrap = false,\n showLineNumbers = true,\n emptyState = 'complete',\n defaultGroupsOpen = false,\n anchorToFailure = false,\n search = '',\n ariaLive = 'polite',\n className,\n onScroll,\n}: LogViewProps) {\n const rowsRef = useRef<HTMLDivElement>(null);\n const tree = useMemo(() => buildLogTree(records), [records]);\n const deferredSearch = useDeferredValue(search);\n const normalizedSearch = deferredSearch.trim().toLowerCase();\n const searchIndex = useMemo(() => buildLogSearchIndex(tree.nodes), [tree.nodes]);\n const visibleNodes = useMemo(\n () =>\n normalizedSearch ? filterLogNodes(tree.nodes, normalizedSearch, searchIndex) : tree.nodes,\n [normalizedSearch, searchIndex, tree.nodes],\n );\n const resolvedToolCalls = useMemo(() => collectResolvedToolCalls(tree.nodes), [tree.nodes]);\n const noOutputState = normalizedSearch ? null : getNoOutputState(tree, emptyState);\n const anchorRecordCount = records.length;\n const searchStatus = normalizedSearch\n ? visibleNodes.length === 0\n ? `No log lines match “${deferredSearch.trim()}”.`\n : `Log search updated for “${deferredSearch.trim()}”.`\n : null;\n\n useEffect(() => {\n if (!anchorToFailure) return;\n if (anchorRecordCount === 0) return;\n\n const frame = scheduleAnimationFrame(() => {\n const rows = rowsRef.current;\n if (!rows) return;\n\n const failure = rows.querySelector<HTMLElement>('[data-log-terminal-failure=\"true\"]');\n if (failure) {\n failure.scrollIntoView({block: 'center'});\n return;\n }\n\n rows.scrollTop = rows.scrollHeight;\n });\n\n return () => cancelScheduledFrame(frame);\n }, [anchorToFailure, anchorRecordCount]);\n\n return (\n <>\n {searchStatus ? (\n <div role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {searchStatus}\n </div>\n ) : null}\n <LogRows\n ref={rowsRef}\n timestamps={timestamps}\n wrap={wrap}\n showLineNumbers={showLineNumbers}\n aria-live={normalizedSearch ? 'off' : ariaLive}\n className={className}\n onScroll={onScroll}\n {...(tree.originTs != null ? {timestampOrigin: new Date(tree.originTs)} : {})}\n >\n {noOutputState ? <NoOutputRow state={noOutputState} /> : null}\n {normalizedSearch && visibleNodes.length === 0 ? (\n <NoSearchMatchesRow query={deferredSearch.trim()} />\n ) : null}\n {renderNodes(\n visibleNodes,\n 0,\n tree,\n defaultGroupsOpen,\n Boolean(normalizedSearch),\n resolvedToolCalls,\n )}\n </LogRows>\n </>\n );\n}\n\nexport function LogViewSkeleton({\n rows = 5,\n timestamps = 'off',\n wrap = false,\n showLineNumbers = true,\n className,\n}: LogViewSkeletonProps) {\n const widths = ['w-[62%]', 'w-[44%]', 'w-[74%]', 'w-[36%]', 'w-[55%]'];\n const skeletonRows = getSkeletonRows(rows);\n\n return (\n <LogRows\n timestamps={timestamps}\n wrap={wrap}\n showLineNumbers={showLineNumbers}\n className={className}\n role=\"presentation\"\n aria-live=\"off\"\n aria-hidden=\"true\"\n >\n {skeletonRows.map((row) => (\n <LogRow key={row.id} lineNumber={row.lineNumber}>\n <Skeleton\n className={`my-[4px] h-12 ${widths[(row.lineNumber - 1) % widths.length] ?? 'w-[48%]'}`}\n />\n </LogRow>\n ))}\n </LogRows>\n );\n}\n\nfunction getSkeletonRows(rows: number): {id: string; lineNumber: number}[] {\n return Array.from({length: rows}, (_, index) => {\n const lineNumber = index + 1;\n return {id: `log-view-skeleton-row-${lineNumber}`, lineNumber};\n });\n}\n\nfunction getNoOutputState(\n tree: LogTree,\n emptyState: NonNullable<LogViewProps['emptyState']>,\n): LogViewProps['emptyState'] | null {\n if (tree.nodes.length === 0) return emptyState;\n\n if (tree.lineCount !== 0) return null;\n if (tree.nodes.length !== 1) return null;\n\n const [node] = tree.nodes;\n if (node?.kind === 'marker' && node.record.type === 'end') return 'complete';\n\n return null;\n}\n\nfunction NoOutputRow({state}: {state: NonNullable<LogViewProps['emptyState']>}) {\n const copy =\n state === 'pending'\n ? {\n title: 'No output yet',\n detail: 'New lines will appear here as the step writes them.',\n }\n : {\n title: 'Step produced no output',\n detail: 'This log stream closed without session entries or process output.',\n };\n\n return (\n <LogRow lineNumber={null}>\n <LogContent className=\"text-foreground-contrast-secondary\">\n <span className=\"inline-flex min-w-0 items-center gap-inline\">\n <Icon name=\"info\" className=\"size-14 flex-none\" aria-hidden=\"true\" />\n <span className=\"min-w-0\">\n <span className=\"font-medium\">{copy.title}</span>\n {' · '}\n <span className=\"text-foreground-contrast-secondary\">{copy.detail}</span>\n </span>\n </span>\n </LogContent>\n </LogRow>\n );\n}\n\nfunction NoSearchMatchesRow({query}: {query: string}) {\n return (\n <LogRow lineNumber={null}>\n <LogContent className=\"text-foreground-contrast-secondary\">\n <span className=\"inline-flex min-w-0 items-center gap-inline\">\n <Icon name=\"searchLine\" className=\"size-14 flex-none\" aria-hidden=\"true\" />\n <span>No log lines match “{query}”.</span>\n </span>\n </LogContent>\n </LogRow>\n );\n}\n\nfunction renderNodes(\n nodes: readonly LogNode[],\n depth: number,\n tree: LogTree,\n defaultGroupsOpen: boolean,\n forceOpen: boolean,\n resolvedToolCalls: ResolvedToolCalls,\n): ReactNode[] {\n // `node.seq` is the stable, unique render key (see `LogNodeBase`): a concatenated\n // multi-step/retry stream can repeat a `group_id` or a marker's `(type, ts)` at one\n // level, which a key derived from those fields would collide on.\n return nodes.map((node): ReactNode => {\n switch (node.kind) {\n case 'output':\n return (\n <OutputLogRow\n key={node.seq}\n record={node.record}\n lineNumber={node.lineNumber}\n indent={depth}\n />\n );\n case 'group':\n return (\n <LogGroup\n key={node.seq}\n node={node}\n depth={depth}\n terminated={tree.terminated}\n defaultOpen={defaultGroupsOpen}\n forceOpen={forceOpen}\n >\n {renderNodes(\n node.children,\n depth + 1,\n tree,\n defaultGroupsOpen,\n forceOpen,\n resolvedToolCalls,\n )}\n </LogGroup>\n );\n case 'marker':\n return <MarkerRow key={node.seq} record={node.record} tree={tree} />;\n case 'session':\n return (\n <AgentSessionRows\n key={node.seq}\n rows={[node.record.row]}\n resolvedToolCallIds={resolvedToolCalls.ids}\n toolCallNames={resolvedToolCalls.names}\n indent={depth}\n forceOpen={forceOpen}\n />\n );\n default:\n return assertNever(node);\n }\n });\n}\n\ninterface ResolvedToolCalls {\n ids: ReadonlySet<string>;\n names: ReadonlyMap<string, string>;\n}\n\nfunction collectResolvedToolCalls(nodes: readonly LogNode[]): ResolvedToolCalls {\n const ids = new Set<string>();\n const names = new Map<string, string>();\n collectResolvedToolCallsInto(nodes, ids, names);\n return {ids, names};\n}\n\nfunction collectResolvedToolCallsInto(\n nodes: readonly LogNode[],\n ids: Set<string>,\n names: Map<string, string>,\n): void {\n for (const node of nodes) {\n switch (node.kind) {\n case 'session':\n if (node.record.row.kind === 'tool-call' && node.record.row.id != null) {\n names.set(node.record.row.id, node.record.row.name);\n } else if (node.record.row.kind === 'tool-result' && node.record.row.toolCallId != null) {\n ids.add(node.record.row.toolCallId);\n }\n break;\n case 'group':\n collectResolvedToolCallsInto(node.children, ids, names);\n break;\n case 'output':\n case 'marker':\n break;\n default:\n assertNever(node);\n }\n }\n}\n\nfunction scheduleAnimationFrame(callback: FrameRequestCallback): number {\n if (typeof globalThis.requestAnimationFrame === 'function') {\n return globalThis.requestAnimationFrame(callback);\n }\n return window.setTimeout(() => callback(Date.now()), 0);\n}\n\nfunction cancelScheduledFrame(frame: number) {\n if (typeof globalThis.cancelAnimationFrame === 'function') {\n globalThis.cancelAnimationFrame(frame);\n return;\n }\n window.clearTimeout(frame);\n}\n\nfunction MarkerRow({record, tree}: {record: MarkerLogRecord; tree: LogTree}): ReactNode {\n switch (record.type) {\n case 'end':\n return (\n <EndMarker\n record={record}\n lineCount={tree.lineCount}\n durationMs={tree.originTs != null ? record.ts - tree.originTs : null}\n />\n );\n case 'gap':\n return <GapMarker record={record} />;\n case 'capped':\n return <CappedMarker record={record} />;\n case 'runner_lost':\n return <RunnerLostMarker record={record} />;\n default:\n return assertNever(record);\n }\n}\n"],"names":["Icon","LogContent","LogRow","LogRows","Skeleton","useDeferredValue","useEffect","useMemo","useRef","buildLogSearchIndex","filterLogNodes","assertNever","buildLogTree","AgentSessionRows","LogGroup","OutputLogRow","CappedMarker","EndMarker","GapMarker","RunnerLostMarker","LogView","records","timestamps","wrap","showLineNumbers","emptyState","defaultGroupsOpen","anchorToFailure","search","ariaLive","className","onScroll","rowsRef","tree","deferredSearch","normalizedSearch","trim","toLowerCase","searchIndex","nodes","visibleNodes","resolvedToolCalls","collectResolvedToolCalls","noOutputState","getNoOutputState","anchorRecordCount","length","searchStatus","frame","scheduleAnimationFrame","rows","current","failure","querySelector","scrollIntoView","block","scrollTop","scrollHeight","cancelScheduledFrame","div","role","aria-live","aria-atomic","ref","originTs","timestampOrigin","Date","NoOutputRow","state","NoSearchMatchesRow","query","renderNodes","Boolean","LogViewSkeleton","widths","skeletonRows","getSkeletonRows","aria-hidden","map","row","lineNumber","id","Array","from","_","index","lineCount","node","kind","record","type","copy","title","detail","span","name","depth","forceOpen","indent","seq","terminated","defaultOpen","children","MarkerRow","resolvedToolCallIds","ids","toolCallNames","names","Set","Map","collectResolvedToolCallsInto","set","toolCallId","add","callback","globalThis","requestAnimationFrame","window","setTimeout","now","cancelAnimationFrame","clearTimeout","durationMs","ts"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/components/log-view.tsx"],"sourcesContent":["'use client';\n\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {LogContent, LogRow, LogRows, type LogTimestampMode} from '@shipfox/react-ui/log';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {\n type ReactNode,\n type UIEventHandler,\n useDeferredValue,\n useEffect,\n useMemo,\n useRef,\n} from 'react';\nimport type {LogRecord} from '#core/log-model.js';\nimport {buildLogSearchIndex, filterLogNodes} from '#core/log-search.js';\nimport {\n assertNever,\n buildLogTree,\n type LogNode,\n type LogTree,\n type MarkerLogRecord,\n} from '#core/log-tree.js';\nimport {AgentSessionRows} from './agent-session-rows.js';\nimport {LogGroup} from './log-group.js';\nimport {OutputLogRow} from './output-log-row.js';\nimport {CappedMarker, EndMarker, GapMarker, RunnerLostMarker} from './system-markers.js';\n\nexport interface LogViewProps {\n records: readonly LogRecord[];\n timestamps?: LogTimestampMode;\n wrap?: boolean;\n showLineNumbers?: boolean;\n emptyState?: 'complete' | 'pending';\n defaultGroupsOpen?: boolean;\n anchorToFailure?: boolean;\n search?: string;\n ariaLive?: 'off' | 'polite' | 'assertive';\n className?: string | undefined;\n onScroll?: UIEventHandler<HTMLDivElement> | undefined;\n}\n\nexport interface LogViewSkeletonProps\n extends Pick<LogViewProps, 'timestamps' | 'wrap' | 'showLineNumbers' | 'className'> {\n rows?: number;\n}\n\nexport function LogView({\n records,\n timestamps = 'off',\n wrap = false,\n showLineNumbers = true,\n emptyState = 'complete',\n defaultGroupsOpen = false,\n anchorToFailure = false,\n search = '',\n ariaLive = 'polite',\n className,\n onScroll,\n}: LogViewProps) {\n const rowsRef = useRef<HTMLDivElement>(null);\n const tree = useMemo(() => buildLogTree(records), [records]);\n const deferredSearch = useDeferredValue(search);\n const normalizedSearch = deferredSearch.trim().toLowerCase();\n const searchIndex = useMemo(() => buildLogSearchIndex(tree.nodes), [tree.nodes]);\n const visibleNodes = useMemo(\n () =>\n normalizedSearch ? filterLogNodes(tree.nodes, normalizedSearch, searchIndex) : tree.nodes,\n [normalizedSearch, searchIndex, tree.nodes],\n );\n const resolvedToolCalls = useMemo(() => collectResolvedToolCalls(tree.nodes), [tree.nodes]);\n const noOutputState = normalizedSearch ? null : getNoOutputState(tree, emptyState);\n const anchorRecordCount = records.length;\n let searchStatus: string | null = null;\n if (normalizedSearch) {\n searchStatus =\n visibleNodes.length === 0\n ? `No log lines match “${deferredSearch.trim()}”.`\n : `Log search updated for “${deferredSearch.trim()}”.`;\n }\n\n useEffect(() => {\n if (!anchorToFailure) return;\n if (anchorRecordCount === 0) return;\n\n const frame = scheduleAnimationFrame(() => {\n const rows = rowsRef.current;\n if (!rows) return;\n\n const failure = rows.querySelector<HTMLElement>('[data-log-terminal-failure=\"true\"]');\n if (failure) {\n failure.scrollIntoView({block: 'center'});\n return;\n }\n\n rows.scrollTop = rows.scrollHeight;\n });\n\n return () => cancelScheduledFrame(frame);\n }, [anchorToFailure, anchorRecordCount]);\n\n return (\n <>\n {searchStatus ? (\n <div role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {searchStatus}\n </div>\n ) : null}\n <LogRows\n ref={rowsRef}\n timestamps={timestamps}\n wrap={wrap}\n showLineNumbers={showLineNumbers}\n aria-live={normalizedSearch ? 'off' : ariaLive}\n className={className}\n onScroll={onScroll}\n {...(tree.originTs != null ? {timestampOrigin: new Date(tree.originTs)} : {})}\n >\n {noOutputState ? <NoOutputRow state={noOutputState} /> : null}\n {normalizedSearch && visibleNodes.length === 0 ? (\n <NoSearchMatchesRow query={deferredSearch.trim()} />\n ) : null}\n {renderNodes(\n visibleNodes,\n 0,\n tree,\n defaultGroupsOpen,\n Boolean(normalizedSearch),\n resolvedToolCalls,\n )}\n </LogRows>\n </>\n );\n}\n\nexport function LogViewSkeleton({\n rows = 5,\n timestamps = 'off',\n wrap = false,\n showLineNumbers = true,\n className,\n}: LogViewSkeletonProps) {\n const widths = ['w-[62%]', 'w-[44%]', 'w-[74%]', 'w-[36%]', 'w-[55%]'];\n const skeletonRows = getSkeletonRows(rows);\n\n return (\n <LogRows\n timestamps={timestamps}\n wrap={wrap}\n showLineNumbers={showLineNumbers}\n className={className}\n role=\"presentation\"\n aria-live=\"off\"\n aria-hidden=\"true\"\n >\n {skeletonRows.map((row) => (\n <LogRow key={row.id} lineNumber={row.lineNumber}>\n <Skeleton\n className={`my-[4px] h-12 ${widths[(row.lineNumber - 1) % widths.length] ?? 'w-[48%]'}`}\n />\n </LogRow>\n ))}\n </LogRows>\n );\n}\n\nfunction getSkeletonRows(rows: number): {id: string; lineNumber: number}[] {\n return Array.from({length: rows}, (_, index) => {\n const lineNumber = index + 1;\n return {id: `log-view-skeleton-row-${lineNumber}`, lineNumber};\n });\n}\n\nfunction getNoOutputState(\n tree: LogTree,\n emptyState: NonNullable<LogViewProps['emptyState']>,\n): LogViewProps['emptyState'] | null {\n if (tree.nodes.length === 0) return emptyState;\n\n if (tree.lineCount !== 0) return null;\n if (tree.nodes.length !== 1) return null;\n\n const [node] = tree.nodes;\n if (node?.kind === 'marker' && node.record.type === 'end') return 'complete';\n\n return null;\n}\n\nfunction NoOutputRow({state}: {state: NonNullable<LogViewProps['emptyState']>}) {\n const copy =\n state === 'pending'\n ? {\n title: 'No output yet',\n detail: 'New lines will appear here as the step writes them.',\n }\n : {\n title: 'Step produced no output',\n detail: 'This log stream closed without session entries or process output.',\n };\n\n return (\n <LogRow lineNumber={null}>\n <LogContent className=\"text-foreground-contrast-secondary\">\n <span className=\"inline-flex min-w-0 items-center gap-inline\">\n <Icon name=\"info\" className=\"size-14 flex-none\" aria-hidden=\"true\" />\n <span className=\"min-w-0\">\n <span className=\"font-medium\">{copy.title}</span>\n {' · '}\n <span className=\"text-foreground-contrast-secondary\">{copy.detail}</span>\n </span>\n </span>\n </LogContent>\n </LogRow>\n );\n}\n\nfunction NoSearchMatchesRow({query}: {query: string}) {\n return (\n <LogRow lineNumber={null}>\n <LogContent className=\"text-foreground-contrast-secondary\">\n <span className=\"inline-flex min-w-0 items-center gap-inline\">\n <Icon name=\"searchLine\" className=\"size-14 flex-none\" aria-hidden=\"true\" />\n <span>No log lines match “{query}”.</span>\n </span>\n </LogContent>\n </LogRow>\n );\n}\n\nfunction renderNodes(\n nodes: readonly LogNode[],\n depth: number,\n tree: LogTree,\n defaultGroupsOpen: boolean,\n forceOpen: boolean,\n resolvedToolCalls: ResolvedToolCalls,\n): ReactNode[] {\n // `node.seq` is the stable, unique render key (see `LogNodeBase`): a concatenated\n // multi-step/retry stream can repeat a `group_id` or a marker's `(type, ts)` at one\n // level, which a key derived from those fields would collide on.\n return nodes.map((node): ReactNode => {\n switch (node.kind) {\n case 'output':\n return (\n <OutputLogRow\n key={node.seq}\n record={node.record}\n lineNumber={node.lineNumber}\n indent={depth}\n />\n );\n case 'group':\n return (\n <LogGroup\n key={node.seq}\n node={node}\n depth={depth}\n terminated={tree.terminated}\n defaultOpen={defaultGroupsOpen}\n forceOpen={forceOpen}\n >\n {renderNodes(\n node.children,\n depth + 1,\n tree,\n defaultGroupsOpen,\n forceOpen,\n resolvedToolCalls,\n )}\n </LogGroup>\n );\n case 'marker':\n return <MarkerRow key={node.seq} record={node.record} tree={tree} />;\n case 'session':\n return (\n <AgentSessionRows\n key={node.seq}\n rows={[node.record.row]}\n resolvedToolCallIds={resolvedToolCalls.ids}\n toolCallNames={resolvedToolCalls.names}\n indent={depth}\n forceOpen={forceOpen}\n />\n );\n default:\n return assertNever(node);\n }\n });\n}\n\ninterface ResolvedToolCalls {\n ids: ReadonlySet<string>;\n names: ReadonlyMap<string, string>;\n}\n\nfunction collectResolvedToolCalls(nodes: readonly LogNode[]): ResolvedToolCalls {\n const ids = new Set<string>();\n const names = new Map<string, string>();\n collectResolvedToolCallsInto(nodes, ids, names);\n return {ids, names};\n}\n\nfunction collectResolvedToolCallsInto(\n nodes: readonly LogNode[],\n ids: Set<string>,\n names: Map<string, string>,\n): void {\n for (const node of nodes) {\n switch (node.kind) {\n case 'session':\n if (node.record.row.kind === 'tool-call' && node.record.row.id != null) {\n names.set(node.record.row.id, node.record.row.name);\n } else if (node.record.row.kind === 'tool-result' && node.record.row.toolCallId != null) {\n ids.add(node.record.row.toolCallId);\n }\n break;\n case 'group':\n collectResolvedToolCallsInto(node.children, ids, names);\n break;\n case 'output':\n case 'marker':\n break;\n default:\n assertNever(node);\n }\n }\n}\n\nfunction scheduleAnimationFrame(callback: FrameRequestCallback): number {\n if (typeof globalThis.requestAnimationFrame === 'function') {\n return globalThis.requestAnimationFrame(callback);\n }\n return window.setTimeout(() => callback(Date.now()), 0);\n}\n\nfunction cancelScheduledFrame(frame: number) {\n if (typeof globalThis.cancelAnimationFrame === 'function') {\n globalThis.cancelAnimationFrame(frame);\n return;\n }\n window.clearTimeout(frame);\n}\n\nfunction MarkerRow({record, tree}: {record: MarkerLogRecord; tree: LogTree}): ReactNode {\n switch (record.type) {\n case 'end':\n return (\n <EndMarker\n record={record}\n lineCount={tree.lineCount}\n durationMs={tree.originTs != null ? record.ts - tree.originTs : null}\n />\n );\n case 'gap':\n return <GapMarker record={record} />;\n case 'capped':\n return <CappedMarker record={record} />;\n case 'runner_lost':\n return <RunnerLostMarker record={record} />;\n default:\n return assertNever(record);\n }\n}\n"],"names":["Icon","LogContent","LogRow","LogRows","Skeleton","useDeferredValue","useEffect","useMemo","useRef","buildLogSearchIndex","filterLogNodes","assertNever","buildLogTree","AgentSessionRows","LogGroup","OutputLogRow","CappedMarker","EndMarker","GapMarker","RunnerLostMarker","LogView","records","timestamps","wrap","showLineNumbers","emptyState","defaultGroupsOpen","anchorToFailure","search","ariaLive","className","onScroll","rowsRef","tree","deferredSearch","normalizedSearch","trim","toLowerCase","searchIndex","nodes","visibleNodes","resolvedToolCalls","collectResolvedToolCalls","noOutputState","getNoOutputState","anchorRecordCount","length","searchStatus","frame","scheduleAnimationFrame","rows","current","failure","querySelector","scrollIntoView","block","scrollTop","scrollHeight","cancelScheduledFrame","div","role","aria-live","aria-atomic","ref","originTs","timestampOrigin","Date","NoOutputRow","state","NoSearchMatchesRow","query","renderNodes","Boolean","LogViewSkeleton","widths","skeletonRows","getSkeletonRows","aria-hidden","map","row","lineNumber","id","Array","from","_","index","lineCount","node","kind","record","type","copy","title","detail","span","name","depth","forceOpen","indent","seq","terminated","defaultOpen","children","MarkerRow","resolvedToolCallIds","ids","toolCallNames","names","Set","Map","collectResolvedToolCallsInto","set","toolCallId","add","callback","globalThis","requestAnimationFrame","window","setTimeout","now","cancelAnimationFrame","clearTimeout","durationMs","ts"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-tree.d.ts","sourceRoot":"","sources":["../../src/core/log-tree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAE9C;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,SAAS,EAAE;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,CAAC,CAAC;AACnE,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,SAAS,EAAE;IAAC,IAAI,EAAE,aAAa,CAAA;CAAC,CAAC,CAAC;AAC5E,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE;IAAC,IAAI,EAAE,KAAK,CAAA;CAAC,CAAC,CAAC;AAC7D,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE;IAAC,IAAI,EAAE,KAAK,CAAA;CAAC,CAAC,CAAC;AAC7D,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,SAAS,EAAE;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,CAAC,CAAC;AACnE,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,SAAS,EAAE;IAAC,IAAI,EAAE,aAAa,CAAA;CAAC,CAAC,CAAC;AAC5E,MAAM,MAAM,qBAAqB,GAAG,OAAO,CAAC,SAAS,EAAE;IAAC,IAAI,EAAE,eAAe,CAAA;CAAC,CAAC,CAAC;AAChF,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,YAAY,GAAG,eAAe,GAAG,mBAAmB,CAAC;AAElG;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;CACzB;AAED,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,eAAe,CAAC;CACzB;AAED,MAAM,WAAW,YAAa,SAAQ,WAAW;IAC/C,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,mBAAmB,CAAC;IAC5B,kFAAkF;IAClF,MAAM,EAAE,OAAO,CAAC;IAChB,wEAAwE;IACxE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qIAAqI;IACrI,QAAQ,EAAE,OAAO,CAAC;IAClB,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,qBAAqB,CAAC;CAC/B;AAED,MAAM,MAAM,OAAO,GAAG,aAAa,GAAG,aAAa,GAAG,YAAY,GAAG,cAAc,CAAC;AAEpF,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,6EAA6E;IAC7E,UAAU,EAAE,OAAO,CAAC;IACpB,uFAAuF;IACvF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,oFAAoF;IACpF,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,sHAAsH;AACtH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAE/C;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"log-tree.d.ts","sourceRoot":"","sources":["../../src/core/log-tree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAE9C;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,SAAS,EAAE;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,CAAC,CAAC;AACnE,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,SAAS,EAAE;IAAC,IAAI,EAAE,aAAa,CAAA;CAAC,CAAC,CAAC;AAC5E,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE;IAAC,IAAI,EAAE,KAAK,CAAA;CAAC,CAAC,CAAC;AAC7D,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE;IAAC,IAAI,EAAE,KAAK,CAAA;CAAC,CAAC,CAAC;AAC7D,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,SAAS,EAAE;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,CAAC,CAAC;AACnE,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,SAAS,EAAE;IAAC,IAAI,EAAE,aAAa,CAAA;CAAC,CAAC,CAAC;AAC5E,MAAM,MAAM,qBAAqB,GAAG,OAAO,CAAC,SAAS,EAAE;IAAC,IAAI,EAAE,eAAe,CAAA;CAAC,CAAC,CAAC;AAChF,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,YAAY,GAAG,eAAe,GAAG,mBAAmB,CAAC;AAElG;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;CACzB;AAED,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,eAAe,CAAC;CACzB;AAED,MAAM,WAAW,YAAa,SAAQ,WAAW;IAC/C,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,mBAAmB,CAAC;IAC5B,kFAAkF;IAClF,MAAM,EAAE,OAAO,CAAC;IAChB,wEAAwE;IACxE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qIAAqI;IACrI,QAAQ,EAAE,OAAO,CAAC;IAClB,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,qBAAqB,CAAC;CAC/B;AAED,MAAM,MAAM,OAAO,GAAG,aAAa,GAAG,aAAa,GAAG,YAAY,GAAG,cAAc,CAAC;AAEpF,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,6EAA6E;IAC7E,UAAU,EAAE,OAAO,CAAC;IACpB,uFAAuF;IACvF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,oFAAoF;IACpF,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,sHAAsH;AACtH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAE/C;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,GAAG,OAAO,CAsBnE"}
|
package/dist/core/log-tree.js
CHANGED
|
@@ -6,134 +6,120 @@ export function assertNever(value) {
|
|
|
6
6
|
throw new Error(`unexpected log record type: ${JSON.stringify(value)}`);
|
|
7
7
|
}
|
|
8
8
|
export function buildLogTree(records) {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// Bubble a failure signal (a runner_lost only) to every currently-open ancestor group
|
|
18
|
-
// in one pass, so `hasError` is read in O(1) at render time instead of re-walking subtrees.
|
|
19
|
-
const markOpenGroupsError = ()=>{
|
|
20
|
-
for (const frame of stack)frame.hasError = true;
|
|
9
|
+
const state = {
|
|
10
|
+
nodes: [],
|
|
11
|
+
stack: [],
|
|
12
|
+
seq: 0,
|
|
13
|
+
lineNumber: 0,
|
|
14
|
+
lineCount: 0,
|
|
15
|
+
terminated: false,
|
|
16
|
+
originTs: null
|
|
21
17
|
};
|
|
22
18
|
for (const record of records){
|
|
23
|
-
if (originTs === null) originTs = record.ts;
|
|
24
|
-
|
|
25
|
-
case 'output':
|
|
26
|
-
{
|
|
27
|
-
lineNumber += 1;
|
|
28
|
-
lineCount += 1;
|
|
29
|
-
for (const frame of stack)frame.lineCount += 1;
|
|
30
|
-
childrenOf().push({
|
|
31
|
-
kind: 'output',
|
|
32
|
-
seq: seq++,
|
|
33
|
-
lineNumber,
|
|
34
|
-
record
|
|
35
|
-
});
|
|
36
|
-
break;
|
|
37
|
-
}
|
|
38
|
-
case 'group_start':
|
|
39
|
-
{
|
|
40
|
-
// Reconcile the open stack to the declared parent before nesting. `parent_group_id`
|
|
41
|
-
// is the runner's stack top at emit time (null at the root), so any reader frame
|
|
42
|
-
// below that parent (or every open frame, when the parent is root) is a group whose
|
|
43
|
-
// own `group_end` was dropped under backlog pressure. Orphan-close those frames so a
|
|
44
|
-
// dropped end never mis-parents the groups that follow. A parent whose own start was
|
|
45
|
-
// dropped is not on the stack: it falls through to best-effort root placement.
|
|
46
|
-
const parentId = record.parentGroupId;
|
|
47
|
-
let parentIndex = -1;
|
|
48
|
-
if (parentId !== null) {
|
|
49
|
-
for(let i = stack.length - 1; i >= 0; i -= 1){
|
|
50
|
-
if (stack[i]?.record.groupId === parentId) {
|
|
51
|
-
parentIndex = i;
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
for(let i = stack.length - 1; i > parentIndex; i -= 1){
|
|
57
|
-
const frame = stack[i];
|
|
58
|
-
if (frame) frame.closed = true;
|
|
59
|
-
}
|
|
60
|
-
stack.length = parentIndex + 1;
|
|
61
|
-
const group = {
|
|
62
|
-
kind: 'group',
|
|
63
|
-
seq: seq++,
|
|
64
|
-
record,
|
|
65
|
-
closed: false,
|
|
66
|
-
endTs: null,
|
|
67
|
-
hasError: false,
|
|
68
|
-
lineCount: 0,
|
|
69
|
-
children: []
|
|
70
|
-
};
|
|
71
|
-
childrenOf().push(group);
|
|
72
|
-
stack.push(group);
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
case 'group_end':
|
|
76
|
-
{
|
|
77
|
-
// Close the matching open group_id; any inner frames orphaned by a dropped
|
|
78
|
-
// group_end close with it. An end with no matching open start is ignored.
|
|
79
|
-
let matchIndex = -1;
|
|
80
|
-
for(let i = stack.length - 1; i >= 0; i -= 1){
|
|
81
|
-
if (stack[i]?.record.groupId === record.groupId) {
|
|
82
|
-
matchIndex = i;
|
|
83
|
-
break;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (matchIndex !== -1) {
|
|
87
|
-
for(let i = stack.length - 1; i >= matchIndex; i -= 1){
|
|
88
|
-
const frame = stack[i];
|
|
89
|
-
if (frame) frame.closed = true;
|
|
90
|
-
}
|
|
91
|
-
const matched = stack[matchIndex];
|
|
92
|
-
if (matched) matched.endTs = record.ts;
|
|
93
|
-
stack.length = matchIndex;
|
|
94
|
-
}
|
|
95
|
-
break;
|
|
96
|
-
}
|
|
97
|
-
case 'end':
|
|
98
|
-
case 'gap':
|
|
99
|
-
case 'capped':
|
|
100
|
-
{
|
|
101
|
-
if (record.type === 'end') terminated = true;
|
|
102
|
-
childrenOf().push({
|
|
103
|
-
kind: 'marker',
|
|
104
|
-
seq: seq++,
|
|
105
|
-
record
|
|
106
|
-
});
|
|
107
|
-
break;
|
|
108
|
-
}
|
|
109
|
-
case 'runner_lost':
|
|
110
|
-
{
|
|
111
|
-
terminated = true;
|
|
112
|
-
childrenOf().push({
|
|
113
|
-
kind: 'marker',
|
|
114
|
-
seq: seq++,
|
|
115
|
-
record
|
|
116
|
-
});
|
|
117
|
-
markOpenGroupsError();
|
|
118
|
-
break;
|
|
119
|
-
}
|
|
120
|
-
case 'agent_session':
|
|
121
|
-
childrenOf().push({
|
|
122
|
-
kind: 'session',
|
|
123
|
-
seq: seq++,
|
|
124
|
-
record
|
|
125
|
-
});
|
|
126
|
-
break;
|
|
127
|
-
default:
|
|
128
|
-
assertNever(record);
|
|
129
|
-
}
|
|
19
|
+
if (state.originTs === null) state.originTs = record.ts;
|
|
20
|
+
appendLogRecord(state, record);
|
|
130
21
|
}
|
|
131
22
|
return {
|
|
132
|
-
nodes,
|
|
133
|
-
terminated,
|
|
134
|
-
originTs,
|
|
135
|
-
lineCount
|
|
23
|
+
nodes: state.nodes,
|
|
24
|
+
terminated: state.terminated,
|
|
25
|
+
originTs: state.originTs,
|
|
26
|
+
lineCount: state.lineCount
|
|
136
27
|
};
|
|
137
28
|
}
|
|
29
|
+
function childrenOf(state) {
|
|
30
|
+
return state.stack[state.stack.length - 1]?.children ?? state.nodes;
|
|
31
|
+
}
|
|
32
|
+
function appendLogRecord(state, record) {
|
|
33
|
+
switch(record.type){
|
|
34
|
+
case 'output':
|
|
35
|
+
appendOutputRecord(state, record);
|
|
36
|
+
return;
|
|
37
|
+
case 'group_start':
|
|
38
|
+
appendGroupStartRecord(state, record);
|
|
39
|
+
return;
|
|
40
|
+
case 'group_end':
|
|
41
|
+
appendGroupEndRecord(state, record);
|
|
42
|
+
return;
|
|
43
|
+
case 'end':
|
|
44
|
+
case 'gap':
|
|
45
|
+
case 'capped':
|
|
46
|
+
if (record.type === 'end') state.terminated = true;
|
|
47
|
+
childrenOf(state).push({
|
|
48
|
+
kind: 'marker',
|
|
49
|
+
seq: state.seq++,
|
|
50
|
+
record
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
case 'runner_lost':
|
|
54
|
+
state.terminated = true;
|
|
55
|
+
childrenOf(state).push({
|
|
56
|
+
kind: 'marker',
|
|
57
|
+
seq: state.seq++,
|
|
58
|
+
record
|
|
59
|
+
});
|
|
60
|
+
for (const frame of state.stack)frame.hasError = true;
|
|
61
|
+
return;
|
|
62
|
+
case 'agent_session':
|
|
63
|
+
childrenOf(state).push({
|
|
64
|
+
kind: 'session',
|
|
65
|
+
seq: state.seq++,
|
|
66
|
+
record
|
|
67
|
+
});
|
|
68
|
+
return;
|
|
69
|
+
default:
|
|
70
|
+
assertNever(record);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function appendOutputRecord(state, record) {
|
|
74
|
+
state.lineNumber += 1;
|
|
75
|
+
state.lineCount += 1;
|
|
76
|
+
for (const frame of state.stack)frame.lineCount += 1;
|
|
77
|
+
childrenOf(state).push({
|
|
78
|
+
kind: 'output',
|
|
79
|
+
seq: state.seq++,
|
|
80
|
+
lineNumber: state.lineNumber,
|
|
81
|
+
record
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function appendGroupStartRecord(state, record) {
|
|
85
|
+
let parentIndex = -1;
|
|
86
|
+
if (record.parentGroupId !== null) {
|
|
87
|
+
parentIndex = findOpenGroupIndex(state.stack, record.parentGroupId);
|
|
88
|
+
}
|
|
89
|
+
for(let index = state.stack.length - 1; index > parentIndex; index -= 1){
|
|
90
|
+
const frame = state.stack[index];
|
|
91
|
+
if (frame) frame.closed = true;
|
|
92
|
+
}
|
|
93
|
+
state.stack.length = parentIndex + 1;
|
|
94
|
+
const group = {
|
|
95
|
+
kind: 'group',
|
|
96
|
+
seq: state.seq++,
|
|
97
|
+
record,
|
|
98
|
+
closed: false,
|
|
99
|
+
endTs: null,
|
|
100
|
+
hasError: false,
|
|
101
|
+
lineCount: 0,
|
|
102
|
+
children: []
|
|
103
|
+
};
|
|
104
|
+
childrenOf(state).push(group);
|
|
105
|
+
state.stack.push(group);
|
|
106
|
+
}
|
|
107
|
+
function appendGroupEndRecord(state, record) {
|
|
108
|
+
const matchIndex = findOpenGroupIndex(state.stack, record.groupId);
|
|
109
|
+
if (matchIndex === -1) return;
|
|
110
|
+
for(let index = state.stack.length - 1; index >= matchIndex; index -= 1){
|
|
111
|
+
const frame = state.stack[index];
|
|
112
|
+
if (frame) frame.closed = true;
|
|
113
|
+
}
|
|
114
|
+
const matched = state.stack[matchIndex];
|
|
115
|
+
if (matched) matched.endTs = record.ts;
|
|
116
|
+
state.stack.length = matchIndex;
|
|
117
|
+
}
|
|
118
|
+
function findOpenGroupIndex(stack, groupId) {
|
|
119
|
+
for(let index = stack.length - 1; index >= 0; index -= 1){
|
|
120
|
+
if (stack[index]?.record.groupId === groupId) return index;
|
|
121
|
+
}
|
|
122
|
+
return -1;
|
|
123
|
+
}
|
|
138
124
|
|
|
139
125
|
//# sourceMappingURL=log-tree.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/log-tree.ts"],"sourcesContent":["import type {LogRecord} from './log-model.js';\n\n/**\n * Pure render transform for the step-log read stream. The runner emits a flat,\n * ordered NDJSON record list; `group_start`/`group_end` form a tree that the\n * reader reconstructs here before rendering. No React, no state: one function\n * over the record array.\n *\n * records[] ──▶ buildLogTree ──▶ { nodes (forest), terminated, originTs, lineCount }\n *\n * Group closing matches `group_id` (not a blind top-of-stack pop) so a stream that\n * drops a `group_start` under backlog/gap pressure but still delivers its\n * `group_end` does not mis-nest everything after it.\n */\n\nexport type OutputLogRecord = Extract<LogRecord, {type: 'output'}>;\nexport type GroupStartLogRecord = Extract<LogRecord, {type: 'group_start'}>;\nexport type EndLogRecord = Extract<LogRecord, {type: 'end'}>;\nexport type GapLogRecord = Extract<LogRecord, {type: 'gap'}>;\nexport type CappedLogRecord = Extract<LogRecord, {type: 'capped'}>;\nexport type RunnerLostLogRecord = Extract<LogRecord, {type: 'runner_lost'}>;\nexport type AgentSessionLogRecord = Extract<LogRecord, {type: 'agent_session'}>;\nexport type MarkerLogRecord = EndLogRecord | GapLogRecord | CappedLogRecord | RunnerLostLogRecord;\n\n/**\n * Stable, unique render key in creation order. A natural key is not enough: `group_id`\n * and a marker's `(type, ts)` can both repeat among siblings once a consumer feeds a\n * concatenated multi-step/retry stream (or two markers land in the same millisecond),\n * and the append-only build order keeps `seq` stable across re-renders.\n */\nexport interface LogNodeBase {\n seq: number;\n}\n\nexport interface OutputLogNode extends LogNodeBase {\n kind: 'output';\n lineNumber: number;\n record: OutputLogRecord;\n}\n\nexport interface MarkerLogNode extends LogNodeBase {\n kind: 'marker';\n record: MarkerLogRecord;\n}\n\nexport interface GroupLogNode extends LogNodeBase {\n kind: 'group';\n record: GroupStartLogRecord;\n /** False when no matching `group_end` arrived (still streaming, or truncated). */\n closed: boolean;\n /** `group_end` timestamp when closed by its matching end, else null. */\n endTs: number | null;\n /** Precomputed: subtree contains a `runner_lost` (a genuine failure). `stderr` is a channel, not an error, so it never sets this. */\n hasError: boolean;\n /** Precomputed output-line count in the subtree, for the collapsed summary. */\n lineCount: number;\n children: LogNode[];\n}\n\nexport interface SessionLogNode extends LogNodeBase {\n kind: 'session';\n record: AgentSessionLogRecord;\n}\n\nexport type LogNode = OutputLogNode | MarkerLogNode | GroupLogNode | SessionLogNode;\n\nexport interface LogTree {\n nodes: LogNode[];\n /** The stream is closed: the records contain an `end` or a `runner_lost`. */\n terminated: boolean;\n /** First record's timestamp; the baseline for relative timestamps. Null when empty. */\n originTs: number | null;\n /** Physical output lines (one per `output` record in v1); drives the end banner. */\n lineCount: number;\n}\n\nconst TRAILING_NEWLINE = /\\r?\\n$/;\n\n/** Strips a single trailing line ending (CRLF or LF) so a line-framed record renders without a blank continuation. */\nexport function stripTrailingNewline(data: string): string {\n return data.replace(TRAILING_NEWLINE, '');\n}\n\nexport function assertNever(value: never): never {\n throw new Error(`unexpected log record type: ${JSON.stringify(value)}`);\n}\n\nexport function buildLogTree(records: readonly LogRecord[]): LogTree {\n const nodes: LogNode[] = [];\n const stack: GroupLogNode[] = [];\n let seq = 0;\n let lineNumber = 0;\n let lineCount = 0;\n let terminated = false;\n let originTs: number | null = null;\n\n const childrenOf = (): LogNode[] => stack[stack.length - 1]?.children ?? nodes;\n\n // Bubble a failure signal (a runner_lost only) to every currently-open ancestor group\n // in one pass, so `hasError` is read in O(1) at render time instead of re-walking subtrees.\n const markOpenGroupsError = (): void => {\n for (const frame of stack) frame.hasError = true;\n };\n\n for (const record of records) {\n if (originTs === null) originTs = record.ts;\n switch (record.type) {\n case 'output': {\n lineNumber += 1;\n lineCount += 1;\n for (const frame of stack) frame.lineCount += 1;\n childrenOf().push({kind: 'output', seq: seq++, lineNumber, record});\n break;\n }\n case 'group_start': {\n // Reconcile the open stack to the declared parent before nesting. `parent_group_id`\n // is the runner's stack top at emit time (null at the root), so any reader frame\n // below that parent (or every open frame, when the parent is root) is a group whose\n // own `group_end` was dropped under backlog pressure. Orphan-close those frames so a\n // dropped end never mis-parents the groups that follow. A parent whose own start was\n // dropped is not on the stack: it falls through to best-effort root placement.\n const parentId = record.parentGroupId;\n let parentIndex = -1;\n if (parentId !== null) {\n for (let i = stack.length - 1; i >= 0; i -= 1) {\n if (stack[i]?.record.groupId === parentId) {\n parentIndex = i;\n break;\n }\n }\n }\n for (let i = stack.length - 1; i > parentIndex; i -= 1) {\n const frame = stack[i];\n if (frame) frame.closed = true;\n }\n stack.length = parentIndex + 1;\n\n const group: GroupLogNode = {\n kind: 'group',\n seq: seq++,\n record,\n closed: false,\n endTs: null,\n hasError: false,\n lineCount: 0,\n children: [],\n };\n childrenOf().push(group);\n stack.push(group);\n break;\n }\n case 'group_end': {\n // Close the matching open group_id; any inner frames orphaned by a dropped\n // group_end close with it. An end with no matching open start is ignored.\n let matchIndex = -1;\n for (let i = stack.length - 1; i >= 0; i -= 1) {\n if (stack[i]?.record.groupId === record.groupId) {\n matchIndex = i;\n break;\n }\n }\n if (matchIndex !== -1) {\n for (let i = stack.length - 1; i >= matchIndex; i -= 1) {\n const frame = stack[i];\n if (frame) frame.closed = true;\n }\n const matched = stack[matchIndex];\n if (matched) matched.endTs = record.ts;\n stack.length = matchIndex;\n }\n break;\n }\n case 'end':\n case 'gap':\n case 'capped': {\n if (record.type === 'end') terminated = true;\n childrenOf().push({kind: 'marker', seq: seq++, record});\n break;\n }\n case 'runner_lost': {\n terminated = true;\n childrenOf().push({kind: 'marker', seq: seq++, record});\n markOpenGroupsError();\n break;\n }\n case 'agent_session':\n childrenOf().push({kind: 'session', seq: seq++, record});\n break;\n default:\n assertNever(record);\n }\n }\n\n return {\n nodes,\n terminated,\n originTs,\n lineCount,\n };\n}\n"],"names":["TRAILING_NEWLINE","stripTrailingNewline","data","replace","assertNever","value","Error","JSON","stringify","buildLogTree","records","nodes","stack","seq","lineNumber","lineCount","terminated","originTs","childrenOf","length","children","markOpenGroupsError","frame","hasError","record","ts","type","push","kind","parentId","parentGroupId","parentIndex","i","groupId","closed","group","endTs","matchIndex","matched"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/core/log-tree.ts"],"sourcesContent":["import type {LogRecord} from './log-model.js';\n\n/**\n * Pure render transform for the step-log read stream. The runner emits a flat,\n * ordered NDJSON record list; `group_start`/`group_end` form a tree that the\n * reader reconstructs here before rendering. No React, no state: one function\n * over the record array.\n *\n * records[] ──▶ buildLogTree ──▶ { nodes (forest), terminated, originTs, lineCount }\n *\n * Group closing matches `group_id` (not a blind top-of-stack pop) so a stream that\n * drops a `group_start` under backlog/gap pressure but still delivers its\n * `group_end` does not mis-nest everything after it.\n */\n\nexport type OutputLogRecord = Extract<LogRecord, {type: 'output'}>;\nexport type GroupStartLogRecord = Extract<LogRecord, {type: 'group_start'}>;\nexport type EndLogRecord = Extract<LogRecord, {type: 'end'}>;\nexport type GapLogRecord = Extract<LogRecord, {type: 'gap'}>;\nexport type CappedLogRecord = Extract<LogRecord, {type: 'capped'}>;\nexport type RunnerLostLogRecord = Extract<LogRecord, {type: 'runner_lost'}>;\nexport type AgentSessionLogRecord = Extract<LogRecord, {type: 'agent_session'}>;\nexport type MarkerLogRecord = EndLogRecord | GapLogRecord | CappedLogRecord | RunnerLostLogRecord;\n\n/**\n * Stable, unique render key in creation order. A natural key is not enough: `group_id`\n * and a marker's `(type, ts)` can both repeat among siblings once a consumer feeds a\n * concatenated multi-step/retry stream (or two markers land in the same millisecond),\n * and the append-only build order keeps `seq` stable across re-renders.\n */\nexport interface LogNodeBase {\n seq: number;\n}\n\nexport interface OutputLogNode extends LogNodeBase {\n kind: 'output';\n lineNumber: number;\n record: OutputLogRecord;\n}\n\nexport interface MarkerLogNode extends LogNodeBase {\n kind: 'marker';\n record: MarkerLogRecord;\n}\n\nexport interface GroupLogNode extends LogNodeBase {\n kind: 'group';\n record: GroupStartLogRecord;\n /** False when no matching `group_end` arrived (still streaming, or truncated). */\n closed: boolean;\n /** `group_end` timestamp when closed by its matching end, else null. */\n endTs: number | null;\n /** Precomputed: subtree contains a `runner_lost` (a genuine failure). `stderr` is a channel, not an error, so it never sets this. */\n hasError: boolean;\n /** Precomputed output-line count in the subtree, for the collapsed summary. */\n lineCount: number;\n children: LogNode[];\n}\n\nexport interface SessionLogNode extends LogNodeBase {\n kind: 'session';\n record: AgentSessionLogRecord;\n}\n\nexport type LogNode = OutputLogNode | MarkerLogNode | GroupLogNode | SessionLogNode;\n\nexport interface LogTree {\n nodes: LogNode[];\n /** The stream is closed: the records contain an `end` or a `runner_lost`. */\n terminated: boolean;\n /** First record's timestamp; the baseline for relative timestamps. Null when empty. */\n originTs: number | null;\n /** Physical output lines (one per `output` record in v1); drives the end banner. */\n lineCount: number;\n}\n\nconst TRAILING_NEWLINE = /\\r?\\n$/;\n\n/** Strips a single trailing line ending (CRLF or LF) so a line-framed record renders without a blank continuation. */\nexport function stripTrailingNewline(data: string): string {\n return data.replace(TRAILING_NEWLINE, '');\n}\n\nexport function assertNever(value: never): never {\n throw new Error(`unexpected log record type: ${JSON.stringify(value)}`);\n}\n\nexport function buildLogTree(records: readonly LogRecord[]): LogTree {\n const state: LogTreeBuildState = {\n nodes: [],\n stack: [],\n seq: 0,\n lineNumber: 0,\n lineCount: 0,\n terminated: false,\n originTs: null,\n };\n\n for (const record of records) {\n if (state.originTs === null) state.originTs = record.ts;\n appendLogRecord(state, record);\n }\n\n return {\n nodes: state.nodes,\n terminated: state.terminated,\n originTs: state.originTs,\n lineCount: state.lineCount,\n };\n}\n\ninterface LogTreeBuildState {\n nodes: LogNode[];\n stack: GroupLogNode[];\n seq: number;\n lineNumber: number;\n lineCount: number;\n terminated: boolean;\n originTs: number | null;\n}\n\nfunction childrenOf(state: LogTreeBuildState): LogNode[] {\n return state.stack[state.stack.length - 1]?.children ?? state.nodes;\n}\n\nfunction appendLogRecord(state: LogTreeBuildState, record: LogRecord): void {\n switch (record.type) {\n case 'output':\n appendOutputRecord(state, record);\n return;\n case 'group_start':\n appendGroupStartRecord(state, record);\n return;\n case 'group_end':\n appendGroupEndRecord(state, record);\n return;\n case 'end':\n case 'gap':\n case 'capped':\n if (record.type === 'end') state.terminated = true;\n childrenOf(state).push({kind: 'marker', seq: state.seq++, record});\n return;\n case 'runner_lost':\n state.terminated = true;\n childrenOf(state).push({kind: 'marker', seq: state.seq++, record});\n for (const frame of state.stack) frame.hasError = true;\n return;\n case 'agent_session':\n childrenOf(state).push({kind: 'session', seq: state.seq++, record});\n return;\n default:\n assertNever(record);\n }\n}\n\nfunction appendOutputRecord(\n state: LogTreeBuildState,\n record: Extract<LogRecord, {type: 'output'}>,\n): void {\n state.lineNumber += 1;\n state.lineCount += 1;\n for (const frame of state.stack) frame.lineCount += 1;\n childrenOf(state).push({kind: 'output', seq: state.seq++, lineNumber: state.lineNumber, record});\n}\n\nfunction appendGroupStartRecord(\n state: LogTreeBuildState,\n record: Extract<LogRecord, {type: 'group_start'}>,\n): void {\n let parentIndex = -1;\n if (record.parentGroupId !== null) {\n parentIndex = findOpenGroupIndex(state.stack, record.parentGroupId);\n }\n for (let index = state.stack.length - 1; index > parentIndex; index -= 1) {\n const frame = state.stack[index];\n if (frame) frame.closed = true;\n }\n state.stack.length = parentIndex + 1;\n const group: GroupLogNode = {\n kind: 'group',\n seq: state.seq++,\n record,\n closed: false,\n endTs: null,\n hasError: false,\n lineCount: 0,\n children: [],\n };\n childrenOf(state).push(group);\n state.stack.push(group);\n}\n\nfunction appendGroupEndRecord(\n state: LogTreeBuildState,\n record: Extract<LogRecord, {type: 'group_end'}>,\n): void {\n const matchIndex = findOpenGroupIndex(state.stack, record.groupId);\n if (matchIndex === -1) return;\n for (let index = state.stack.length - 1; index >= matchIndex; index -= 1) {\n const frame = state.stack[index];\n if (frame) frame.closed = true;\n }\n const matched = state.stack[matchIndex];\n if (matched) matched.endTs = record.ts;\n state.stack.length = matchIndex;\n}\n\nfunction findOpenGroupIndex(stack: readonly GroupLogNode[], groupId: string): number {\n for (let index = stack.length - 1; index >= 0; index -= 1) {\n if (stack[index]?.record.groupId === groupId) return index;\n }\n return -1;\n}\n"],"names":["TRAILING_NEWLINE","stripTrailingNewline","data","replace","assertNever","value","Error","JSON","stringify","buildLogTree","records","state","nodes","stack","seq","lineNumber","lineCount","terminated","originTs","record","ts","appendLogRecord","childrenOf","length","children","type","appendOutputRecord","appendGroupStartRecord","appendGroupEndRecord","push","kind","frame","hasError","parentIndex","parentGroupId","findOpenGroupIndex","index","closed","group","endTs","matchIndex","groupId","matched"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"step-logs.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/step-logs.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,eAAe,EAErB,MAAM,mBAAmB,CAAC;AAG3B,eAAO,MAAM,iBAAiB;IAC5B,GAAG,YAAG,WAAW;IACjB,MAAM,WAAW,MAAM,WAAW,MAAM;CAEzC,CAAC;AAEF,UAAU,6BAA6B;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,wBAAsB,uBAAuB,CAAC,EAC5C,MAAM,EACN,OAAO,EACP,MAAM,EACN,MAAM,GACP,EAAE,6BAA6B,iHAQ/B;AAkBD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEnE;AAED,MAAM,WAAW,8BAA8B;IAC7C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,uBAAuB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,yBAAyB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/C,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,GAAE,8BAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"step-logs.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/step-logs.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,eAAe,EAErB,MAAM,mBAAmB,CAAC;AAG3B,eAAO,MAAM,iBAAiB;IAC5B,GAAG,YAAG,WAAW;IACjB,MAAM,WAAW,MAAM,WAAW,MAAM;CAEzC,CAAC;AAEF,UAAU,6BAA6B;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,wBAAsB,uBAAuB,CAAC,EAC5C,MAAM,EACN,OAAO,EACP,MAAM,EACN,MAAM,GACP,EAAE,6BAA6B,iHAQ/B;AAkBD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEnE;AAED,MAAM,WAAW,8BAA8B;IAC7C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,uBAAuB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,yBAAyB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/C,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,GAAE,8BAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwE7C"}
|