@shipfox/client-logs 14.0.0 → 16.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 +20 -0
- package/dist/components/agent-session-rows.js +13 -13
- package/dist/components/agent-session-rows.js.map +1 -1
- package/dist/components/log-group.js +1 -1
- package/dist/components/log-group.js.map +1 -1
- package/dist/components/log-view.js +2 -2
- package/dist/components/log-view.js.map +1 -1
- package/dist/components/system-markers.js +1 -1
- package/dist/components/system-markers.js.map +1 -1
- package/dist/hooks/api/step-logs.d.ts +1 -1
- package/dist/hooks/api/step-logs.d.ts.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/components/agent-session-rows.tsx +13 -13
- package/src/components/log-group.tsx +1 -1
- package/src/components/log-view.tsx +2 -2
- package/src/components/system-markers.tsx +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 (385.25ms)
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @shipfox/client-logs
|
|
2
2
|
|
|
3
|
+
## 16.0.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [80cde6b]
|
|
8
|
+
- @shipfox/react-ui@1.1.0
|
|
9
|
+
|
|
10
|
+
## 14.0.1
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- 88bf8e8: Migrates the shell, auth, secrets, logs, workspace-settings, config, and invitations
|
|
15
|
+
surfaces to semantic spacing roles and brings them under the `no-raw-spacing` Biome
|
|
16
|
+
plugin. Adds shared menu-surface and edge-specific panel roles for existing spacing
|
|
17
|
+
contracts.
|
|
18
|
+
- Updated dependencies [88bf8e8]
|
|
19
|
+
- Updated dependencies [6aa6c7a]
|
|
20
|
+
- Updated dependencies [5c56ba6]
|
|
21
|
+
- @shipfox/react-ui@1.0.0
|
|
22
|
+
|
|
3
23
|
## 14.0.0
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
|
@@ -29,17 +29,17 @@ function AgentSessionRowView({ row, resolvedToolCallIds, toolCallNames, indent }
|
|
|
29
29
|
children: /*#__PURE__*/ _jsx(LogContent, {
|
|
30
30
|
className: "text-foreground-neutral-base",
|
|
31
31
|
children: /*#__PURE__*/ _jsxs("span", {
|
|
32
|
-
className: "flex min-w-0 items-start gap-
|
|
32
|
+
className: "flex min-w-0 items-start gap-inline",
|
|
33
33
|
children: [
|
|
34
34
|
/*#__PURE__*/ _jsx(MessageIcon, {
|
|
35
35
|
role: row.role,
|
|
36
36
|
terminalFailure: row.terminalFailure
|
|
37
37
|
}),
|
|
38
38
|
/*#__PURE__*/ _jsxs("span", {
|
|
39
|
-
className: "flex min-w-0 flex-1 flex-col gap-
|
|
39
|
+
className: "flex min-w-0 flex-1 flex-col gap-tight",
|
|
40
40
|
children: [
|
|
41
41
|
/*#__PURE__*/ _jsxs("span", {
|
|
42
|
-
className: "flex min-w-0 items-center gap-
|
|
42
|
+
className: "flex min-w-0 items-center gap-inline",
|
|
43
43
|
children: [
|
|
44
44
|
/*#__PURE__*/ _jsx(MessageRoleLabel, {
|
|
45
45
|
label: row.label,
|
|
@@ -94,7 +94,7 @@ function AgentSessionRowView({ row, resolvedToolCallIds, toolCallNames, indent }
|
|
|
94
94
|
timestamp: new Date(row.timestamp),
|
|
95
95
|
summary: compactPreview(row.summary ?? row.input),
|
|
96
96
|
trailing: awaitingResult ? /*#__PURE__*/ _jsxs("span", {
|
|
97
|
-
className: "inline-flex items-center gap-
|
|
97
|
+
className: "inline-flex items-center gap-tight",
|
|
98
98
|
children: [
|
|
99
99
|
/*#__PURE__*/ _jsx(Icon, {
|
|
100
100
|
name: "loader4Line",
|
|
@@ -105,7 +105,7 @@ function AgentSessionRowView({ row, resolvedToolCallIds, toolCallNames, indent }
|
|
|
105
105
|
]
|
|
106
106
|
}) : null,
|
|
107
107
|
children: /*#__PURE__*/ _jsxs("span", {
|
|
108
|
-
className: "inline-flex min-w-0 items-center gap-
|
|
108
|
+
className: "inline-flex min-w-0 items-center gap-inline",
|
|
109
109
|
children: [
|
|
110
110
|
/*#__PURE__*/ _jsx(Icon, {
|
|
111
111
|
name: "terminalBoxLine",
|
|
@@ -157,7 +157,7 @@ function AgentSessionRowView({ row, resolvedToolCallIds, toolCallNames, indent }
|
|
|
157
157
|
timestamp: new Date(row.timestamp),
|
|
158
158
|
summary: compactPreview(row.output),
|
|
159
159
|
trailing: /*#__PURE__*/ _jsxs("span", {
|
|
160
|
-
className: cn('inline-flex items-center gap-
|
|
160
|
+
className: cn('inline-flex items-center gap-tight', row.isError ? 'text-red-600 dark:text-red-400' : 'text-foreground-neutral-muted'),
|
|
161
161
|
children: [
|
|
162
162
|
/*#__PURE__*/ _jsx(Icon, {
|
|
163
163
|
name: row.isError ? 'closeCircleLine' : 'checkLine',
|
|
@@ -168,7 +168,7 @@ function AgentSessionRowView({ row, resolvedToolCallIds, toolCallNames, indent }
|
|
|
168
168
|
]
|
|
169
169
|
}),
|
|
170
170
|
children: /*#__PURE__*/ _jsxs("span", {
|
|
171
|
-
className: "inline-flex min-w-0 items-center gap-
|
|
171
|
+
className: "inline-flex min-w-0 items-center gap-inline",
|
|
172
172
|
children: [
|
|
173
173
|
/*#__PURE__*/ _jsx(Icon, {
|
|
174
174
|
name: "terminalWindowLine",
|
|
@@ -207,7 +207,7 @@ function AgentSessionRowView({ row, resolvedToolCallIds, toolCallNames, indent }
|
|
|
207
207
|
children: /*#__PURE__*/ _jsx(LogContent, {
|
|
208
208
|
className: "text-foreground-neutral-muted",
|
|
209
209
|
children: /*#__PURE__*/ _jsxs("span", {
|
|
210
|
-
className: "inline-flex w-full items-center gap-
|
|
210
|
+
className: "inline-flex w-full items-center gap-inline",
|
|
211
211
|
children: [
|
|
212
212
|
/*#__PURE__*/ _jsx(Icon, {
|
|
213
213
|
name: "informationLine",
|
|
@@ -252,7 +252,7 @@ function AgentSessionRowView({ row, resolvedToolCallIds, toolCallNames, indent }
|
|
|
252
252
|
summary: compactPreview(row.raw),
|
|
253
253
|
className: "text-orange-600 dark:text-orange-400",
|
|
254
254
|
children: /*#__PURE__*/ _jsxs("span", {
|
|
255
|
-
className: "inline-flex min-w-0 items-center gap-
|
|
255
|
+
className: "inline-flex min-w-0 items-center gap-inline",
|
|
256
256
|
children: [
|
|
257
257
|
/*#__PURE__*/ _jsx(Icon, {
|
|
258
258
|
name: "errorWarningLine",
|
|
@@ -284,7 +284,7 @@ function MessageIcon({ role, terminalFailure }) {
|
|
|
284
284
|
const name = terminalFailure ? 'closeCircleLine' : role === 'user' ? 'userLine' : role === 'assistant' ? 'robot2Line' : 'message2Line';
|
|
285
285
|
return /*#__PURE__*/ _jsx(Icon, {
|
|
286
286
|
name: name,
|
|
287
|
-
className: cn('mt-
|
|
287
|
+
className: cn('mt-[2px] size-14 flex-none', terminalFailure ? 'text-red-600 dark:text-red-400' : 'text-foreground-neutral-muted'),
|
|
288
288
|
"aria-hidden": "true"
|
|
289
289
|
});
|
|
290
290
|
}
|
|
@@ -333,9 +333,9 @@ function MetadataTrigger({ meta }) {
|
|
|
333
333
|
/*#__PURE__*/ _jsx(TooltipContent, {
|
|
334
334
|
align: "end",
|
|
335
335
|
variant: "inverted",
|
|
336
|
-
className: "max-w-360
|
|
336
|
+
className: "max-w-360 p-tight",
|
|
337
337
|
children: /*#__PURE__*/ _jsx("span", {
|
|
338
|
-
className: "grid grid-cols-[max-content_minmax(0,1fr)] gap-x-
|
|
338
|
+
className: "grid grid-cols-[max-content_minmax(0,1fr)] gap-x-[var(--space-inline)] gap-y-[var(--space-tight)] font-code text-xs",
|
|
339
339
|
children: meta.map((item)=>/*#__PURE__*/ _jsxs(Fragment, {
|
|
340
340
|
children: [
|
|
341
341
|
/*#__PURE__*/ _jsx("span", {
|
|
@@ -363,7 +363,7 @@ function PreviewText({ text }) {
|
|
|
363
363
|
truncated ? /*#__PURE__*/ _jsx("button", {
|
|
364
364
|
type: "button",
|
|
365
365
|
"aria-expanded": expanded,
|
|
366
|
-
className: "
|
|
366
|
+
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-[inset_0_0_0_2px_var(--color-primary-500)]",
|
|
367
367
|
onClick: ()=>setExpanded((value)=>!value),
|
|
368
368
|
children: expanded ? 'show less' : 'show more'
|
|
369
369
|
}) : null
|
|
@@ -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.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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"}
|
|
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-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}>\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-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}>\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-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-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\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-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-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-inline\">\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-[2px] 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 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-[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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"}
|
|
@@ -42,7 +42,7 @@ function GroupStatus({ node, terminated }) {
|
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
return /*#__PURE__*/ _jsxs("span", {
|
|
45
|
-
className: "inline-flex items-center gap-
|
|
45
|
+
className: "inline-flex items-center gap-tight text-foreground-neutral-muted",
|
|
46
46
|
children: [
|
|
47
47
|
/*#__PURE__*/ _jsx(Icon, {
|
|
48
48
|
name: "loader4Line",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/log-group.tsx"],"sourcesContent":["'use client';\n\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {LogDisclosure, LogDisclosureContent, LogDisclosureTrigger} from '@shipfox/react-ui/log';\nimport {cn, formatDuration} from '@shipfox/react-ui/utils';\nimport type {ReactNode} from 'react';\nimport type {GroupLogNode} from '#core/log-tree.js';\n\nexport interface LogGroupProps {\n node: GroupLogNode;\n depth: number;\n terminated: boolean;\n children: ReactNode;\n defaultOpen?: boolean;\n}\n\nexport function LogGroup({node, depth, terminated, children, defaultOpen = false}: LogGroupProps) {\n const lineLabel = `${node.lineCount} ${node.lineCount === 1 ? 'line' : 'lines'}`;\n\n return (\n <LogDisclosure indent={depth} defaultOpen={defaultOpen}>\n <LogDisclosureTrigger\n summary={lineLabel}\n trailing={<GroupStatus node={node} terminated={terminated} />}\n className={cn(node.hasError && 'shadow-[inset_2px_0_0_var(--color-red-500)]')}\n >\n {node.record.name}\n </LogDisclosureTrigger>\n <LogDisclosureContent rail={false}>{children}</LogDisclosureContent>\n </LogDisclosure>\n );\n}\n\nfunction GroupStatus({node, terminated}: {node: GroupLogNode; terminated: boolean}): ReactNode {\n if (node.closed && node.endTs != null) {\n return (\n <span className=\"font-code tabular-nums\">{formatDuration(node.endTs - node.record.ts)}</span>\n );\n }\n\n // No clean end: either still open under a terminated stream (runner died mid-group), or\n // closed only because an ancestor's group_end cascaded (its own end was dropped, so endTs\n // is null). Either way show \"incomplete\" rather than a blank slot or a forever spinner.\n if (node.closed || terminated) {\n return <span className=\"text-foreground-neutral-muted\">incomplete</span>;\n }\n\n return (\n <span className=\"inline-flex items-center gap-
|
|
1
|
+
{"version":3,"sources":["../../src/components/log-group.tsx"],"sourcesContent":["'use client';\n\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {LogDisclosure, LogDisclosureContent, LogDisclosureTrigger} from '@shipfox/react-ui/log';\nimport {cn, formatDuration} from '@shipfox/react-ui/utils';\nimport type {ReactNode} from 'react';\nimport type {GroupLogNode} from '#core/log-tree.js';\n\nexport interface LogGroupProps {\n node: GroupLogNode;\n depth: number;\n terminated: boolean;\n children: ReactNode;\n defaultOpen?: boolean;\n}\n\nexport function LogGroup({node, depth, terminated, children, defaultOpen = false}: LogGroupProps) {\n const lineLabel = `${node.lineCount} ${node.lineCount === 1 ? 'line' : 'lines'}`;\n\n return (\n <LogDisclosure indent={depth} defaultOpen={defaultOpen}>\n <LogDisclosureTrigger\n summary={lineLabel}\n trailing={<GroupStatus node={node} terminated={terminated} />}\n className={cn(node.hasError && 'shadow-[inset_2px_0_0_var(--color-red-500)]')}\n >\n {node.record.name}\n </LogDisclosureTrigger>\n <LogDisclosureContent rail={false}>{children}</LogDisclosureContent>\n </LogDisclosure>\n );\n}\n\nfunction GroupStatus({node, terminated}: {node: GroupLogNode; terminated: boolean}): ReactNode {\n if (node.closed && node.endTs != null) {\n return (\n <span className=\"font-code tabular-nums\">{formatDuration(node.endTs - node.record.ts)}</span>\n );\n }\n\n // No clean end: either still open under a terminated stream (runner died mid-group), or\n // closed only because an ancestor's group_end cascaded (its own end was dropped, so endTs\n // is null). Either way show \"incomplete\" rather than a blank slot or a forever spinner.\n if (node.closed || terminated) {\n return <span className=\"text-foreground-neutral-muted\">incomplete</span>;\n }\n\n return (\n <span className=\"inline-flex items-center gap-tight text-foreground-neutral-muted\">\n <Icon name=\"loader4Line\" className=\"size-12 motion-safe:animate-spin\" aria-hidden=\"true\" />\n running\n </span>\n );\n}\n"],"names":["Icon","LogDisclosure","LogDisclosureContent","LogDisclosureTrigger","cn","formatDuration","LogGroup","node","depth","terminated","children","defaultOpen","lineLabel","lineCount","indent","summary","trailing","GroupStatus","className","hasError","record","name","rail","closed","endTs","span","ts","aria-hidden"],"mappings":"AAAA;;AAEA,SAAQA,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,aAAa,EAAEC,oBAAoB,EAAEC,oBAAoB,QAAO,wBAAwB;AAChG,SAAQC,EAAE,EAAEC,cAAc,QAAO,0BAA0B;AAY3D,OAAO,SAASC,SAAS,EAACC,IAAI,EAAEC,KAAK,EAAEC,UAAU,EAAEC,QAAQ,EAAEC,cAAc,KAAK,EAAgB;IAC9F,MAAMC,YAAY,GAAGL,KAAKM,SAAS,CAAC,CAAC,EAAEN,KAAKM,SAAS,KAAK,IAAI,SAAS,SAAS;IAEhF,qBACE,MAACZ;QAAca,QAAQN;QAAOG,aAAaA;;0BACzC,KAACR;gBACCY,SAASH;gBACTI,wBAAU,KAACC;oBAAYV,MAAMA;oBAAME,YAAYA;;gBAC/CS,WAAWd,GAAGG,KAAKY,QAAQ,IAAI;0BAE9BZ,KAAKa,MAAM,CAACC,IAAI;;0BAEnB,KAACnB;gBAAqBoB,MAAM;0BAAQZ;;;;AAG1C;AAEA,SAASO,YAAY,EAACV,IAAI,EAAEE,UAAU,EAA4C;IAChF,IAAIF,KAAKgB,MAAM,IAAIhB,KAAKiB,KAAK,IAAI,MAAM;QACrC,qBACE,KAACC;YAAKP,WAAU;sBAA0Bb,eAAeE,KAAKiB,KAAK,GAAGjB,KAAKa,MAAM,CAACM,EAAE;;IAExF;IAEA,wFAAwF;IACxF,0FAA0F;IAC1F,wFAAwF;IACxF,IAAInB,KAAKgB,MAAM,IAAId,YAAY;QAC7B,qBAAO,KAACgB;YAAKP,WAAU;sBAAgC;;IACzD;IAEA,qBACE,MAACO;QAAKP,WAAU;;0BACd,KAAClB;gBAAKqB,MAAK;gBAAcH,WAAU;gBAAmCS,eAAY;;YAAS;;;AAIjG"}
|
|
@@ -77,7 +77,7 @@ export function LogViewSkeleton({ rows = 5, timestamps = 'off', wrap = false, sh
|
|
|
77
77
|
children: skeletonRows.map((row)=>/*#__PURE__*/ _jsx(LogRow, {
|
|
78
78
|
lineNumber: row.lineNumber,
|
|
79
79
|
children: /*#__PURE__*/ _jsx(Skeleton, {
|
|
80
|
-
className: `my-
|
|
80
|
+
className: `my-[4px] h-12 ${widths[(row.lineNumber - 1) % widths.length] ?? 'w-[48%]'}`
|
|
81
81
|
})
|
|
82
82
|
}, row.id))
|
|
83
83
|
});
|
|
@@ -114,7 +114,7 @@ function NoOutputRow({ state }) {
|
|
|
114
114
|
children: /*#__PURE__*/ _jsx(LogContent, {
|
|
115
115
|
className: "text-foreground-neutral-muted",
|
|
116
116
|
children: /*#__PURE__*/ _jsxs("span", {
|
|
117
|
-
className: "inline-flex min-w-0 items-center gap-
|
|
117
|
+
className: "inline-flex min-w-0 items-center gap-inline",
|
|
118
118
|
children: [
|
|
119
119
|
/*#__PURE__*/ _jsx(Icon, {
|
|
120
120
|
name: "info",
|
|
@@ -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 {type ReactNode, type UIEventHandler, useEffect, useMemo, useRef} from 'react';\nimport type {LogRecord} from '#core/log-model.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 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 className,\n onScroll,\n}: LogViewProps) {\n const rowsRef = useRef<HTMLDivElement>(null);\n const tree = useMemo(() => buildLogTree(records), [records]);\n const resolvedToolCalls = useMemo(() => collectResolvedToolCalls(tree.nodes), [tree.nodes]);\n const noOutputState = getNoOutputState(tree, emptyState);\n const anchorRecordCount = records.length;\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 <LogRows\n ref={rowsRef}\n timestamps={timestamps}\n wrap={wrap}\n showLineNumbers={showLineNumbers}\n className={className}\n onScroll={onScroll}\n {...(tree.originTs != null ? {timestampOrigin: new Date(tree.originTs)} : {})}\n >\n {noOutputState ? <NoOutputRow state={noOutputState} /> : null}\n {renderNodes(tree.nodes, 0, tree, defaultGroupsOpen, resolvedToolCalls)}\n </LogRows>\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-4 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-neutral-muted\">\n <span className=\"inline-flex min-w-0 items-center gap-8\">\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-neutral-subtle\">{copy.detail}</span>\n </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 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 >\n {renderNodes(node.children, depth + 1, tree, defaultGroupsOpen, resolvedToolCalls)}\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 />\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","useEffect","useMemo","useRef","assertNever","buildLogTree","AgentSessionRows","LogGroup","OutputLogRow","CappedMarker","EndMarker","GapMarker","RunnerLostMarker","LogView","records","timestamps","wrap","showLineNumbers","emptyState","defaultGroupsOpen","anchorToFailure","className","onScroll","rowsRef","tree","resolvedToolCalls","collectResolvedToolCalls","nodes","noOutputState","getNoOutputState","anchorRecordCount","length","frame","scheduleAnimationFrame","rows","current","failure","querySelector","scrollIntoView","block","scrollTop","scrollHeight","cancelScheduledFrame","ref","originTs","timestampOrigin","Date","NoOutputRow","state","renderNodes","LogViewSkeleton","widths","skeletonRows","getSkeletonRows","role","aria-live","aria-hidden","map","row","lineNumber","id","Array","from","_","index","lineCount","node","kind","record","type","copy","title","detail","span","name","depth","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 {type ReactNode, type UIEventHandler, useEffect, useMemo, useRef} from 'react';\nimport type {LogRecord} from '#core/log-model.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 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 className,\n onScroll,\n}: LogViewProps) {\n const rowsRef = useRef<HTMLDivElement>(null);\n const tree = useMemo(() => buildLogTree(records), [records]);\n const resolvedToolCalls = useMemo(() => collectResolvedToolCalls(tree.nodes), [tree.nodes]);\n const noOutputState = getNoOutputState(tree, emptyState);\n const anchorRecordCount = records.length;\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 <LogRows\n ref={rowsRef}\n timestamps={timestamps}\n wrap={wrap}\n showLineNumbers={showLineNumbers}\n className={className}\n onScroll={onScroll}\n {...(tree.originTs != null ? {timestampOrigin: new Date(tree.originTs)} : {})}\n >\n {noOutputState ? <NoOutputRow state={noOutputState} /> : null}\n {renderNodes(tree.nodes, 0, tree, defaultGroupsOpen, resolvedToolCalls)}\n </LogRows>\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-neutral-muted\">\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-neutral-subtle\">{copy.detail}</span>\n </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 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 >\n {renderNodes(node.children, depth + 1, tree, defaultGroupsOpen, resolvedToolCalls)}\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 />\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","useEffect","useMemo","useRef","assertNever","buildLogTree","AgentSessionRows","LogGroup","OutputLogRow","CappedMarker","EndMarker","GapMarker","RunnerLostMarker","LogView","records","timestamps","wrap","showLineNumbers","emptyState","defaultGroupsOpen","anchorToFailure","className","onScroll","rowsRef","tree","resolvedToolCalls","collectResolvedToolCalls","nodes","noOutputState","getNoOutputState","anchorRecordCount","length","frame","scheduleAnimationFrame","rows","current","failure","querySelector","scrollIntoView","block","scrollTop","scrollHeight","cancelScheduledFrame","ref","originTs","timestampOrigin","Date","NoOutputRow","state","renderNodes","LogViewSkeleton","widths","skeletonRows","getSkeletonRows","role","aria-live","aria-hidden","map","row","lineNumber","id","Array","from","_","index","lineCount","node","kind","record","type","copy","title","detail","span","name","depth","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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"}
|
|
@@ -22,7 +22,7 @@ const toneText = {
|
|
|
22
22
|
children: /*#__PURE__*/ _jsx(LogContent, {
|
|
23
23
|
className: cn('block', toneText[tone]),
|
|
24
24
|
children: /*#__PURE__*/ _jsxs("span", {
|
|
25
|
-
className: "inline-flex w-full items-center gap-
|
|
25
|
+
className: "inline-flex w-full items-center gap-inline",
|
|
26
26
|
children: [
|
|
27
27
|
/*#__PURE__*/ _jsx(Icon, {
|
|
28
28
|
name: icon,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/system-markers.tsx"],"sourcesContent":["import {Icon, type IconName} from '@shipfox/react-ui/icon';\nimport {LogContent, LogRow} from '@shipfox/react-ui/log';\nimport {cn, formatBytes, formatDuration} from '@shipfox/react-ui/utils';\nimport type {\n CappedLogRecord,\n EndLogRecord,\n GapLogRecord,\n RunnerLostLogRecord,\n} from '#core/log-tree.js';\n\ntype MarkerTone = 'default' | 'warning' | 'error';\n\nconst toneText: Record<MarkerTone, string> = {\n default: 'text-foreground-neutral-muted',\n warning: 'text-orange-600 dark:text-orange-400',\n error: 'text-red-600 dark:text-red-400',\n};\n\ninterface LogMarkerRowProps {\n icon: IconName;\n tone: MarkerTone;\n timestamp?: Date | null;\n /** Plain-language clause after the label: what it means / what to do. */\n detail?: string;\n /** Right-aligned `font-code` figures (bytes, line count, duration). */\n meta?: string;\n terminalFailure?: boolean;\n children: string;\n}\n\n/**\n * Shared timeline-marker row: a non-numbered line with a leading icon, a bold label, an\n * optional plain-language detail clause, a dashed divider, and optional right-aligned\n * monospace figures. The detail explains the consequence to the operator (the label\n * names the event, the icon/tone carry severity), so the copy reads helpfully rather\n * than mechanically.\n */\nfunction LogMarkerRow({\n icon,\n tone,\n timestamp = null,\n detail,\n meta,\n terminalFailure = false,\n children,\n}: LogMarkerRowProps) {\n return (\n <LogRow\n lineNumber={null}\n timestamp={timestamp}\n tone={tone}\n data-log-terminal-failure={terminalFailure ? 'true' : undefined}\n >\n <LogContent className={cn('block', toneText[tone])}>\n <span className=\"inline-flex w-full items-center gap-
|
|
1
|
+
{"version":3,"sources":["../../src/components/system-markers.tsx"],"sourcesContent":["import {Icon, type IconName} from '@shipfox/react-ui/icon';\nimport {LogContent, LogRow} from '@shipfox/react-ui/log';\nimport {cn, formatBytes, formatDuration} from '@shipfox/react-ui/utils';\nimport type {\n CappedLogRecord,\n EndLogRecord,\n GapLogRecord,\n RunnerLostLogRecord,\n} from '#core/log-tree.js';\n\ntype MarkerTone = 'default' | 'warning' | 'error';\n\nconst toneText: Record<MarkerTone, string> = {\n default: 'text-foreground-neutral-muted',\n warning: 'text-orange-600 dark:text-orange-400',\n error: 'text-red-600 dark:text-red-400',\n};\n\ninterface LogMarkerRowProps {\n icon: IconName;\n tone: MarkerTone;\n timestamp?: Date | null;\n /** Plain-language clause after the label: what it means / what to do. */\n detail?: string;\n /** Right-aligned `font-code` figures (bytes, line count, duration). */\n meta?: string;\n terminalFailure?: boolean;\n children: string;\n}\n\n/**\n * Shared timeline-marker row: a non-numbered line with a leading icon, a bold label, an\n * optional plain-language detail clause, a dashed divider, and optional right-aligned\n * monospace figures. The detail explains the consequence to the operator (the label\n * names the event, the icon/tone carry severity), so the copy reads helpfully rather\n * than mechanically.\n */\nfunction LogMarkerRow({\n icon,\n tone,\n timestamp = null,\n detail,\n meta,\n terminalFailure = false,\n children,\n}: LogMarkerRowProps) {\n return (\n <LogRow\n lineNumber={null}\n timestamp={timestamp}\n tone={tone}\n data-log-terminal-failure={terminalFailure ? 'true' : undefined}\n >\n <LogContent className={cn('block', toneText[tone])}>\n <span className=\"inline-flex w-full items-center gap-inline\">\n <Icon name={icon} className=\"size-14 flex-none\" aria-hidden=\"true\" />\n {/* Label, detail, and figures share one text cluster joined by a literal\n \" · \". Flex `gap` is visual only and would copy with no separator, so the\n separators are real inline text. The dashed rule trails after the text\n (an aria-hidden flex filler) and contributes nothing to a selection. */}\n <span className=\"min-w-0\">\n <span className=\"font-medium\">{children}</span>\n {detail != null && (\n <>\n {' · '}\n <span className=\"font-normal opacity-80\">{detail}</span>\n </>\n )}\n {meta != null && (\n <>\n {' · '}\n <span className=\"font-code tabular-nums opacity-80\">{meta}</span>\n </>\n )}\n </span>\n <span\n aria-hidden=\"true\"\n className=\"h-px flex-1 border-t border-dashed border-current opacity-30\"\n />\n </span>\n </LogContent>\n </LogRow>\n );\n}\n\nexport interface EndMarkerProps {\n record: EndLogRecord;\n lineCount: number;\n durationMs?: number | null;\n}\n\n/** Clean end of the log: line count + output bytes (+ overall duration). `total_bytes` is payload bytes. */\nexport function EndMarker({record, lineCount, durationMs = null}: EndMarkerProps) {\n const meta = [\n `${lineCount} ${lineCount === 1 ? 'line' : 'lines'}`,\n formatBytes(record.totalBytes),\n ...(durationMs != null ? [formatDuration(durationMs)] : []),\n ].join(' · ');\n\n return (\n <LogMarkerRow icon=\"flagLine\" tone=\"default\" timestamp={new Date(record.ts)} meta={meta}>\n End of log\n </LogMarkerRow>\n );\n}\n\n/** The runner's local backlog shed bytes before upload, so some output never arrived. A warning. */\nexport function GapMarker({record}: {record: GapLogRecord}) {\n return (\n <LogMarkerRow\n icon=\"errorWarningLine\"\n tone=\"warning\"\n timestamp={new Date(record.ts)}\n detail={`the runner fell behind and dropped ${formatBytes(record.droppedBytes)}`}\n >\n Output missing\n </LogMarkerRow>\n );\n}\n\n/** The job hit its shared log size limit; logging stopped but the step kept running. A warning. */\nexport function CappedMarker({record}: {record: CappedLogRecord}) {\n return (\n <LogMarkerRow\n icon=\"forbidLine\"\n tone=\"warning\"\n timestamp={new Date(record.ts)}\n detail=\"later output isn't shown; the step kept running\"\n >\n Log size limit reached\n </LogMarkerRow>\n );\n}\n\n/** The runner disappeared and the stream was force-closed. A terminal failure (status taxonomy §9). */\nexport function RunnerLostMarker({record}: {record: RunnerLostLogRecord}) {\n return (\n <LogMarkerRow\n icon=\"closeCircleLine\"\n tone=\"error\"\n timestamp={new Date(record.ts)}\n detail=\"the log ends here and may be incomplete\"\n terminalFailure\n >\n Runner disconnected\n </LogMarkerRow>\n );\n}\n"],"names":["Icon","LogContent","LogRow","cn","formatBytes","formatDuration","toneText","default","warning","error","LogMarkerRow","icon","tone","timestamp","detail","meta","terminalFailure","children","lineNumber","data-log-terminal-failure","undefined","className","span","name","aria-hidden","EndMarker","record","lineCount","durationMs","totalBytes","join","Date","ts","GapMarker","droppedBytes","CappedMarker","RunnerLostMarker"],"mappings":";AAAA,SAAQA,IAAI,QAAsB,yBAAyB;AAC3D,SAAQC,UAAU,EAAEC,MAAM,QAAO,wBAAwB;AACzD,SAAQC,EAAE,EAAEC,WAAW,EAAEC,cAAc,QAAO,0BAA0B;AAUxE,MAAMC,WAAuC;IAC3CC,SAAS;IACTC,SAAS;IACTC,OAAO;AACT;AAcA;;;;;;CAMC,GACD,SAASC,aAAa,EACpBC,IAAI,EACJC,IAAI,EACJC,YAAY,IAAI,EAChBC,MAAM,EACNC,IAAI,EACJC,kBAAkB,KAAK,EACvBC,QAAQ,EACU;IAClB,qBACE,KAACf;QACCgB,YAAY;QACZL,WAAWA;QACXD,MAAMA;QACNO,6BAA2BH,kBAAkB,SAASI;kBAEtD,cAAA,KAACnB;YAAWoB,WAAWlB,GAAG,SAASG,QAAQ,CAACM,KAAK;sBAC/C,cAAA,MAACU;gBAAKD,WAAU;;kCACd,KAACrB;wBAAKuB,MAAMZ;wBAAMU,WAAU;wBAAoBG,eAAY;;kCAK5D,MAACF;wBAAKD,WAAU;;0CACd,KAACC;gCAAKD,WAAU;0CAAeJ;;4BAC9BH,UAAU,sBACT;;oCACG;kDACD,KAACQ;wCAAKD,WAAU;kDAA0BP;;;;4BAG7CC,QAAQ,sBACP;;oCACG;kDACD,KAACO;wCAAKD,WAAU;kDAAqCN;;;;;;kCAI3D,KAACO;wBACCE,eAAY;wBACZH,WAAU;;;;;;AAMtB;AAQA,0GAA0G,GAC1G,OAAO,SAASI,UAAU,EAACC,MAAM,EAAEC,SAAS,EAAEC,aAAa,IAAI,EAAiB;IAC9E,MAAMb,OAAO;QACX,GAAGY,UAAU,CAAC,EAAEA,cAAc,IAAI,SAAS,SAAS;QACpDvB,YAAYsB,OAAOG,UAAU;WACzBD,cAAc,OAAO;YAACvB,eAAeuB;SAAY,GAAG,EAAE;KAC3D,CAACE,IAAI,CAAC;IAEP,qBACE,KAACpB;QAAaC,MAAK;QAAWC,MAAK;QAAUC,WAAW,IAAIkB,KAAKL,OAAOM,EAAE;QAAGjB,MAAMA;kBAAM;;AAI7F;AAEA,kGAAkG,GAClG,OAAO,SAASkB,UAAU,EAACP,MAAM,EAAyB;IACxD,qBACE,KAAChB;QACCC,MAAK;QACLC,MAAK;QACLC,WAAW,IAAIkB,KAAKL,OAAOM,EAAE;QAC7BlB,QAAQ,CAAC,mCAAmC,EAAEV,YAAYsB,OAAOQ,YAAY,GAAG;kBACjF;;AAIL;AAEA,iGAAiG,GACjG,OAAO,SAASC,aAAa,EAACT,MAAM,EAA4B;IAC9D,qBACE,KAAChB;QACCC,MAAK;QACLC,MAAK;QACLC,WAAW,IAAIkB,KAAKL,OAAOM,EAAE;QAC7BlB,QAAO;kBACR;;AAIL;AAEA,qGAAqG,GACrG,OAAO,SAASsB,iBAAiB,EAACV,MAAM,EAAgC;IACtE,qBACE,KAAChB;QACCC,MAAK;QACLC,MAAK;QACLC,WAAW,IAAIkB,KAAKL,OAAOM,EAAE;QAC7BlB,QAAO;QACPE,eAAe;kBAChB;;AAIL"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type StepLogSnapshot } from '#core/log-read.js';
|
|
2
2
|
export declare const stepLogsQueryKeys: {
|
|
3
|
-
all: readonly [
|
|
3
|
+
all: readonly ['step-logs'];
|
|
4
4
|
detail: (stepId: string, attempt: number) => readonly ["step-logs", "detail", string, number];
|
|
5
5
|
};
|
|
6
6
|
interface ReadStepAttemptLogsPageParams {
|
|
@@ -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
|
|
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,mFA2F7C"}
|