@shipfox/client-logs 11.0.0 → 13.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/CHANGELOG.md +19 -0
- package/dist/components/agent-session-rows.js +16 -2
- package/dist/components/agent-session-rows.js.map +1 -1
- package/dist/core/log-model.d.ts +1 -0
- package/dist/core/log-model.d.ts.map +1 -1
- package/dist/core/log-model.js.map +1 -1
- package/dist/core/log-tree.d.ts +1 -1
- package/dist/core/log-tree.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/components/agent-session-rows.tsx +15 -4
- package/src/components/log-group.stories.tsx +1 -1
- package/src/core/log-model.ts +8 -1
- package/src/core/log-tree.ts +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
$ shipfox-swc
|
|
2
|
-
Successfully compiled: 13 files with swc (
|
|
2
|
+
Successfully compiled: 13 files with swc (231.07ms)
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @shipfox/client-logs
|
|
2
2
|
|
|
3
|
+
## 13.0.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f78740d: Remove Unicode dash punctuation from package prose and source comments.
|
|
8
|
+
- Updated dependencies [f78740d]
|
|
9
|
+
- Updated dependencies [9969937]
|
|
10
|
+
- Updated dependencies [6adc228]
|
|
11
|
+
- @shipfox/api-logs-dto@12.0.0
|
|
12
|
+
- @shipfox/react-ui@0.4.0
|
|
13
|
+
|
|
14
|
+
## 12.0.1
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- 57e69d8: Preserve and display Claude tool-use summaries on their matching tool-call rows.
|
|
19
|
+
- Updated dependencies [57e69d8]
|
|
20
|
+
- @shipfox/api-logs-dto@10.2.0
|
|
21
|
+
|
|
3
22
|
## 11.0.0
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
|
@@ -92,7 +92,7 @@ function AgentSessionRowView({ row, resolvedToolCallIds, toolCallNames, indent }
|
|
|
92
92
|
children: [
|
|
93
93
|
/*#__PURE__*/ _jsx(LogDisclosureTrigger, {
|
|
94
94
|
timestamp: new Date(row.timestamp),
|
|
95
|
-
summary: compactPreview(row.input),
|
|
95
|
+
summary: compactPreview(row.summary ?? row.input),
|
|
96
96
|
trailing: awaitingResult ? /*#__PURE__*/ _jsxs("span", {
|
|
97
97
|
className: "inline-flex items-center gap-4",
|
|
98
98
|
children: [
|
|
@@ -123,7 +123,21 @@ function AgentSessionRowView({ row, resolvedToolCallIds, toolCallNames, indent }
|
|
|
123
123
|
})
|
|
124
124
|
}),
|
|
125
125
|
/*#__PURE__*/ _jsx(LogDisclosureContent, {
|
|
126
|
-
children: /*#__PURE__*/
|
|
126
|
+
children: row.summary != null ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
127
|
+
children: [
|
|
128
|
+
/*#__PURE__*/ _jsx(LogContent, {
|
|
129
|
+
children: /*#__PURE__*/ _jsx(PreviewText, {
|
|
130
|
+
text: row.summary
|
|
131
|
+
})
|
|
132
|
+
}),
|
|
133
|
+
/*#__PURE__*/ _jsx(LogContent, {
|
|
134
|
+
variant: "code",
|
|
135
|
+
children: /*#__PURE__*/ _jsx(PreviewText, {
|
|
136
|
+
text: row.input
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
]
|
|
140
|
+
}) : /*#__PURE__*/ _jsx(LogContent, {
|
|
127
141
|
variant: "code",
|
|
128
142
|
children: /*#__PURE__*/ _jsx(PreviewText, {
|
|
129
143
|
text: row.input
|
|
@@ -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, 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}\n\nexport function AgentSessionRows({\n rows,\n resolvedToolCallIds,\n toolCallNames,\n indent,\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 />\n ));\n}\n\nfunction AgentSessionRowView({\n row,\n resolvedToolCallIds,\n toolCallNames,\n indent,\n}: {\n row: SessionViewRow;\n resolvedToolCallIds: ReadonlySet<string>;\n toolCallNames: ReadonlyMap<string, string>;\n indent: number;\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-neutral-base\">\n <span className=\"flex min-w-0 items-start gap-8\">\n <MessageIcon role={row.role} terminalFailure={row.terminalFailure} />\n <span className=\"flex min-w-0 flex-1 flex-col gap-2\">\n <span className=\"flex min-w-0 items-center gap-8\">\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}>\n <LogDisclosureTrigger\n summary={wordSummary(row.text)}\n timestamp={new Date(row.timestamp)}\n className=\"text-foreground-neutral-subtle\"\n >\n thinking\n </LogDisclosureTrigger>\n <LogDisclosureContent className=\"text-foreground-neutral-subtle\">\n <LogContent className=\"text-foreground-neutral-subtle\">\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}>\n <LogDisclosureTrigger\n timestamp={new Date(row.timestamp)}\n summary={compactPreview(row.input)}\n trailing={\n awaitingResult ? (\n <span className=\"inline-flex items-center gap-4\">\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-6\">\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 <LogContent variant=\"code\">\n <PreviewText text={row.input} />\n </LogContent>\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}>\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-4',\n row.isError ? 'text-red-600 dark:text-red-400' : 'text-foreground-neutral-muted',\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-6\">\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\n variant=\"code\"\n className={cn(row.isError && 'text-red-600 dark:text-red-400')}\n >\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-neutral-muted\">\n <span className=\"inline-flex w-full items-center gap-8\">\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-neutral-subtle\">{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}>\n <LogDisclosureTrigger\n timestamp={new Date(row.timestamp)}\n summary={compactPreview(row.raw)}\n className=\"text-orange-600 dark:text-orange-400\"\n >\n <span className=\"inline-flex min-w-0 items-center gap-6\">\n <Icon name=\"errorWarningLine\" className=\"size-14 flex-none\" aria-hidden=\"true\" />\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-2 size-14 flex-none',\n terminalFailure ? 'text-red-600 dark:text-red-400' : 'text-foreground-neutral-muted',\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-neutral-muted',\n terminalFailure && 'text-foreground-highlight-error',\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-neutral-muted', 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-neutral-muted opacity-60 transition-opacity hover:bg-background-components-hover hover:text-foreground-neutral-base hover:opacity-100 focus-visible:opacity-100 focus-visible:shadow-[inset_0_0_0_2px_var(--color-primary-500)] 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 px-8 py-6\">\n <span className=\"grid grid-cols-[max-content_minmax(0,1fr)] gap-x-8 gap-y-2 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=\"ml-8 inline-flex min-h-24 items-center rounded-4 px-6 font-display text-xs text-foreground-highlight-interactive focus-visible:shadow-[inset_0_0_0_2px_var(--color-primary-500)]\"\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","useState","PREVIEW_CHAR_LIMIT","WORD_SUMMARY_CHAR_LIMIT","WHITESPACE","WORD_SEPARATOR","AgentSessionRows","rows","resolvedToolCallIds","toolCallNames","indent","map","row","index","AgentSessionRowView","kind","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} 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, 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}\n\nexport function AgentSessionRows({\n rows,\n resolvedToolCallIds,\n toolCallNames,\n indent,\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 />\n ));\n}\n\nfunction AgentSessionRowView({\n row,\n resolvedToolCallIds,\n toolCallNames,\n indent,\n}: {\n row: SessionViewRow;\n resolvedToolCallIds: ReadonlySet<string>;\n toolCallNames: ReadonlyMap<string, string>;\n indent: number;\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-neutral-base\">\n <span className=\"flex min-w-0 items-start gap-8\">\n <MessageIcon role={row.role} terminalFailure={row.terminalFailure} />\n <span className=\"flex min-w-0 flex-1 flex-col gap-2\">\n <span className=\"flex min-w-0 items-center gap-8\">\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}>\n <LogDisclosureTrigger\n summary={wordSummary(row.text)}\n timestamp={new Date(row.timestamp)}\n className=\"text-foreground-neutral-subtle\"\n >\n thinking\n </LogDisclosureTrigger>\n <LogDisclosureContent className=\"text-foreground-neutral-subtle\">\n <LogContent className=\"text-foreground-neutral-subtle\">\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}>\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-4\">\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-6\">\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}>\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-4',\n row.isError ? 'text-red-600 dark:text-red-400' : 'text-foreground-neutral-muted',\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-6\">\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\n variant=\"code\"\n className={cn(row.isError && 'text-red-600 dark:text-red-400')}\n >\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-neutral-muted\">\n <span className=\"inline-flex w-full items-center gap-8\">\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-neutral-subtle\">{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}>\n <LogDisclosureTrigger\n timestamp={new Date(row.timestamp)}\n summary={compactPreview(row.raw)}\n className=\"text-orange-600 dark:text-orange-400\"\n >\n <span className=\"inline-flex min-w-0 items-center gap-6\">\n <Icon name=\"errorWarningLine\" className=\"size-14 flex-none\" aria-hidden=\"true\" />\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-2 size-14 flex-none',\n terminalFailure ? 'text-red-600 dark:text-red-400' : 'text-foreground-neutral-muted',\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-neutral-muted',\n terminalFailure && 'text-foreground-highlight-error',\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-neutral-muted', 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-neutral-muted opacity-60 transition-opacity hover:bg-background-components-hover hover:text-foreground-neutral-base hover:opacity-100 focus-visible:opacity-100 focus-visible:shadow-[inset_0_0_0_2px_var(--color-primary-500)] 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 px-8 py-6\">\n <span className=\"grid grid-cols-[max-content_minmax(0,1fr)] gap-x-8 gap-y-2 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=\"ml-8 inline-flex min-h-24 items-center rounded-4 px-6 font-display text-xs text-foreground-highlight-interactive focus-visible:shadow-[inset_0_0_0_2px_var(--color-primary-500)]\"\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","useState","PREVIEW_CHAR_LIMIT","WORD_SUMMARY_CHAR_LIMIT","WHITESPACE","WORD_SEPARATOR","AgentSessionRows","rows","resolvedToolCallIds","toolCallNames","indent","map","row","index","AgentSessionRowView","kind","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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"}
|
package/dist/core/log-model.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-model.d.ts","sourceRoot":"","sources":["../../src/core/log-model.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC9B;AAED,MAAM,MAAM,cAAc,GACtB;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,OAAO,CAAC;CAC1B,GACD;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GACnD;
|
|
1
|
+
{"version":3,"file":"log-model.d.ts","sourceRoot":"","sources":["../../src/core/log-model.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/log-model.ts"],"sourcesContent":["export interface SessionViewRowMeta {\n label: string;\n value: string;\n inline?: boolean | undefined;\n}\n\nexport type SessionViewRow =\n | {\n kind: 'message';\n timestamp: number;\n role: string;\n label: string;\n meta: readonly SessionViewRowMeta[];\n text: string;\n terminalFailure: boolean;\n }\n | {kind: 'thinking'; timestamp: number; text: string}\n | {kind: 'tool-call'
|
|
1
|
+
{"version":3,"sources":["../../src/core/log-model.ts"],"sourcesContent":["export interface SessionViewRowMeta {\n label: string;\n value: string;\n inline?: boolean | undefined;\n}\n\nexport type SessionViewRow =\n | {\n kind: 'message';\n timestamp: number;\n role: string;\n label: string;\n meta: readonly SessionViewRowMeta[];\n text: string;\n terminalFailure: boolean;\n }\n | {kind: 'thinking'; timestamp: number; text: string}\n | {\n kind: 'tool-call';\n timestamp: number;\n id: string | null;\n name: string;\n input: string;\n summary?: string | undefined;\n }\n | {\n kind: 'tool-result';\n timestamp: number;\n toolCallId: string | null;\n toolName: string;\n output: string;\n isError: boolean;\n }\n | {\n kind: 'lifecycle';\n timestamp: number;\n label: string;\n detail: string | null;\n meta: readonly SessionViewRowMeta[];\n tone: 'default' | 'warning' | 'error';\n terminalFailure: boolean;\n }\n | {kind: 'raw'; timestamp: number; label: string; raw: string};\n\ninterface LogRecordBase {\n v: 1;\n ts: number;\n}\n\nexport type LogRecord =\n | (LogRecordBase & {type: 'output'; stream: 'stdout' | 'stderr'; data: string})\n | (LogRecordBase & {\n type: 'group_start';\n groupId: string;\n parentGroupId: string | null;\n name: string;\n })\n | (LogRecordBase & {type: 'group_end'; groupId: string})\n | (LogRecordBase & {type: 'end'; totalBytes: number})\n | (LogRecordBase & {type: 'gap'; droppedBytes: number})\n | (LogRecordBase & {type: 'agent_session'; row: SessionViewRow})\n | (LogRecordBase & {type: 'capped'})\n | (LogRecordBase & {type: 'runner_lost'});\n\nexport type LogSource = 'inline' | 'presigned';\nexport type LogState = 'open' | 'closed' | 'compacted';\n\nexport interface InlineLogRead {\n mode: 'inline';\n ndjson: string;\n nextCursor: number;\n hasMore: boolean;\n state: 'open' | 'closed';\n truncated: boolean;\n}\n\nexport interface PresignedLogRead {\n mode: 'presigned';\n url: string;\n expiresAt: string;\n totalBytes: number;\n truncated: boolean;\n}\n"],"names":[],"mappings":"AA4EA,WAMC"}
|
package/dist/core/log-tree.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { LogRecord } from './log-model.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Pure render transform for the step-log read stream. The runner emits a flat,
|
|
4
4
|
* ordered NDJSON record list; `group_start`/`group_end` form a tree that the
|
|
5
|
-
* reader reconstructs here before rendering. No React, no state
|
|
5
|
+
* reader reconstructs here before rendering. No React, no state: one function
|
|
6
6
|
* over the record array.
|
|
7
7
|
*
|
|
8
8
|
* records[] ──▶ buildLogTree ──▶ { nodes (forest), terminated, originTs, lineCount }
|
|
@@ -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 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":"AA4EA,MAAMA,mBAAmB;AAEzB,oHAAoH,GACpH,OAAO,SAASC,qBAAqBC,IAAY;IAC/C,OAAOA,KAAKC,OAAO,CAACH,kBAAkB;AACxC;AAEA,OAAO,SAASI,YAAYC,KAAY;IACtC,MAAM,IAAIC,MAAM,CAAC,4BAA4B,EAAEC,KAAKC,SAAS,CAACH,QAAQ;AACxE;AAEA,OAAO,SAASI,aAAaC,OAA6B;IACxD,MAAMC,QAAmB,EAAE;IAC3B,MAAMC,QAAwB,EAAE;IAChC,IAAIC,MAAM;IACV,IAAIC,aAAa;IACjB,IAAIC,YAAY;IAChB,IAAIC,aAAa;IACjB,IAAIC,WAA0B;IAE9B,MAAMC,aAAa,IAAiBN,KAAK,CAACA,MAAMO,MAAM,GAAG,EAAE,EAAEC,YAAYT;IAEzE,sFAAsF;IACtF,4FAA4F;IAC5F,MAAMU,sBAAsB;QAC1B,KAAK,MAAMC,SAASV,MAAOU,MAAMC,QAAQ,GAAG;IAC9C;IAEA,KAAK,MAAMC,UAAUd,QAAS;QAC5B,IAAIO,aAAa,MAAMA,WAAWO,OAAOC,EAAE;QAC3C,OAAQD,OAAOE,IAAI;YACjB,KAAK;gBAAU;oBACbZ,cAAc;oBACdC,aAAa;oBACb,KAAK,MAAMO,SAASV,MAAOU,MAAMP,SAAS,IAAI;oBAC9CG,aAAaS,IAAI,CAAC;wBAACC,MAAM;wBAAUf,KAAKA;wBAAOC;wBAAYU;oBAAM;oBACjE;gBACF;YACA,KAAK;gBAAe;oBAClB,oFAAoF;oBACpF,iFAAiF;oBACjF,oFAAoF;oBACpF,qFAAqF;oBACrF,qFAAqF;oBACrF,+EAA+E;oBAC/E,MAAMK,WAAWL,OAAOM,aAAa;oBACrC,IAAIC,cAAc,CAAC;oBACnB,IAAIF,aAAa,MAAM;wBACrB,IAAK,IAAIG,IAAIpB,MAAMO,MAAM,GAAG,GAAGa,KAAK,GAAGA,KAAK,EAAG;4BAC7C,IAAIpB,KAAK,CAACoB,EAAE,EAAER,OAAOS,YAAYJ,UAAU;gCACzCE,cAAcC;gCACd;4BACF;wBACF;oBACF;oBACA,IAAK,IAAIA,IAAIpB,MAAMO,MAAM,GAAG,GAAGa,IAAID,aAAaC,KAAK,EAAG;wBACtD,MAAMV,QAAQV,KAAK,CAACoB,EAAE;wBACtB,IAAIV,OAAOA,MAAMY,MAAM,GAAG;oBAC5B;oBACAtB,MAAMO,MAAM,GAAGY,cAAc;oBAE7B,MAAMI,QAAsB;wBAC1BP,MAAM;wBACNf,KAAKA;wBACLW;wBACAU,QAAQ;wBACRE,OAAO;wBACPb,UAAU;wBACVR,WAAW;wBACXK,UAAU,EAAE;oBACd;oBACAF,aAAaS,IAAI,CAACQ;oBAClBvB,MAAMe,IAAI,CAACQ;oBACX;gBACF;YACA,KAAK;gBAAa;oBAChB,2EAA2E;oBAC3E,0EAA0E;oBAC1E,IAAIE,aAAa,CAAC;oBAClB,IAAK,IAAIL,IAAIpB,MAAMO,MAAM,GAAG,GAAGa,KAAK,GAAGA,KAAK,EAAG;wBAC7C,IAAIpB,KAAK,CAACoB,EAAE,EAAER,OAAOS,YAAYT,OAAOS,OAAO,EAAE;4BAC/CI,aAAaL;4BACb;wBACF;oBACF;oBACA,IAAIK,eAAe,CAAC,GAAG;wBACrB,IAAK,IAAIL,IAAIpB,MAAMO,MAAM,GAAG,GAAGa,KAAKK,YAAYL,KAAK,EAAG;4BACtD,MAAMV,QAAQV,KAAK,CAACoB,EAAE;4BACtB,IAAIV,OAAOA,MAAMY,MAAM,GAAG;wBAC5B;wBACA,MAAMI,UAAU1B,KAAK,CAACyB,WAAW;wBACjC,IAAIC,SAASA,QAAQF,KAAK,GAAGZ,OAAOC,EAAE;wBACtCb,MAAMO,MAAM,GAAGkB;oBACjB;oBACA;gBACF;YACA,KAAK;YACL,KAAK;YACL,KAAK;gBAAU;oBACb,IAAIb,OAAOE,IAAI,KAAK,OAAOV,aAAa;oBACxCE,aAAaS,IAAI,CAAC;wBAACC,MAAM;wBAAUf,KAAKA;wBAAOW;oBAAM;oBACrD;gBACF;YACA,KAAK;gBAAe;oBAClBR,aAAa;oBACbE,aAAaS,IAAI,CAAC;wBAACC,MAAM;wBAAUf,KAAKA;wBAAOW;oBAAM;oBACrDH;oBACA;gBACF;YACA,KAAK;gBACHH,aAAaS,IAAI,CAAC;oBAACC,MAAM;oBAAWf,KAAKA;oBAAOW;gBAAM;gBACtD;YACF;gBACEpB,YAAYoB;QAChB;IACF;IAEA,OAAO;QACLb;QACAK;QACAC;QACAF;IACF;AACF"}
|