@opengeni/react 0.25.0 → 0.26.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/dist/{chunk-AVPU5PMC.js → chunk-F4CFWKVI.js} +332 -64
- package/dist/chunk-F4CFWKVI.js.map +1 -0
- package/dist/chunk-GQN2QIR2.js +3767 -0
- package/dist/chunk-GQN2QIR2.js.map +1 -0
- package/dist/{chunk-I3BJZIG5.js → chunk-HIWPQYWI.js} +2 -120
- package/dist/chunk-HIWPQYWI.js.map +1 -0
- package/dist/chunk-M7X4JZOD.js +121 -0
- package/dist/chunk-M7X4JZOD.js.map +1 -0
- package/dist/{chunk-SHOFILHJ.js → chunk-MP6237JB.js} +570 -984
- package/dist/chunk-MP6237JB.js.map +1 -0
- package/dist/chunk-OZDLELJQ.js +937 -0
- package/dist/chunk-OZDLELJQ.js.map +1 -0
- package/dist/{chunk-RDPDU4TA.js → chunk-TMH6HZWF.js} +3 -3
- package/dist/{chunk-6XUS5VFM.js → chunk-YU5PGUK7.js} +6 -4
- package/dist/{chunk-6XUS5VFM.js.map → chunk-YU5PGUK7.js.map} +1 -1
- package/dist/{composer-BXb0Q1HF.d.ts → composer-DoC4veX1.d.ts} +4 -75
- package/dist/composer.d.ts +2 -1
- package/dist/composer.js +4 -3
- package/dist/index.d.ts +14 -259
- package/dist/index.js +1016 -5140
- package/dist/index.js.map +1 -1
- package/dist/machines.js +3 -2
- package/dist/session-Du_FsrZ1.d.ts +264 -0
- package/dist/session-ui-BqQDH7YV.d.ts +183 -0
- package/dist/session-ui.d.ts +7 -0
- package/dist/session-ui.js +17 -0
- package/dist/session-ui.js.map +1 -0
- package/dist/session.d.ts +3 -1
- package/dist/session.js +26 -9
- package/dist/use-file-attachments-C0kpHrs9.d.ts +76 -0
- package/dist/{session-BEvtFWhe.d.ts → use-turn-queue-3rkJwjFv.d.ts} +3 -185
- package/package.json +6 -2
- package/src/components/message-timeline.tsx +92 -52
- package/src/hooks/use-composer.ts +456 -69
- package/src/hooks/use-file-attachments.ts +1 -1
- package/src/hooks/use-goal.ts +1 -1
- package/src/hooks/use-session-events.ts +5 -0
- package/src/hooks/use-session-lineage.ts +1 -1
- package/src/hooks/use-session.ts +9 -6
- package/src/session-ui.ts +13 -0
- package/src/session.ts +15 -0
- package/src/timeline/activity-rail.tsx +1 -1
- package/dist/chunk-AVPU5PMC.js.map +0 -1
- package/dist/chunk-I3BJZIG5.js.map +0 -1
- package/dist/chunk-SHOFILHJ.js.map +0 -1
- /package/dist/{chunk-RDPDU4TA.js.map → chunk-TMH6HZWF.js.map} +0 -0
|
@@ -0,0 +1,3767 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cn
|
|
3
|
+
} from "./chunk-TK7G6XLT.js";
|
|
4
|
+
import {
|
|
5
|
+
buildTimeline,
|
|
6
|
+
groupTimeline
|
|
7
|
+
} from "./chunk-OZDLELJQ.js";
|
|
8
|
+
import {
|
|
9
|
+
formatRelativeTime,
|
|
10
|
+
stringifyPayload,
|
|
11
|
+
truncate,
|
|
12
|
+
tryParseJson
|
|
13
|
+
} from "./chunk-M7X4JZOD.js";
|
|
14
|
+
import {
|
|
15
|
+
EmptyQueueStateSurface
|
|
16
|
+
} from "./chunk-YDNWMKXO.js";
|
|
17
|
+
|
|
18
|
+
// src/components/queue-surface.tsx
|
|
19
|
+
import { Loader2Icon } from "lucide-react";
|
|
20
|
+
import { lazy, Suspense } from "react";
|
|
21
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
22
|
+
var loadQueueSurface = () => import("./queue-surface-implementation-3UW3MIIR.js");
|
|
23
|
+
var QueueSurface = createQueueSurface(loadQueueSurface);
|
|
24
|
+
function createQueueSurface(loadImplementation) {
|
|
25
|
+
const LazyQueueSurface = lazy(async () => ({
|
|
26
|
+
default: (await loadImplementation()).QueueSurface
|
|
27
|
+
}));
|
|
28
|
+
return function QueueSurfaceBoundary(props) {
|
|
29
|
+
const { queue } = props;
|
|
30
|
+
if (queue.queue.length === 0) {
|
|
31
|
+
if (!queue.stoppingPreviousAttempt && !queue.error && !queue.mutationError) return null;
|
|
32
|
+
return /* @__PURE__ */ jsx(EmptyQueueStateSurface, { queue });
|
|
33
|
+
}
|
|
34
|
+
return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(QueueSurfaceFallback, { count: queue.queue.length }), children: /* @__PURE__ */ jsx(LazyQueueSurface, { ...props }) });
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function QueueSurfaceFallback({ count }) {
|
|
38
|
+
return /* @__PURE__ */ jsx(
|
|
39
|
+
"div",
|
|
40
|
+
{
|
|
41
|
+
"aria-live": "polite",
|
|
42
|
+
className: "mx-auto mb-2 w-full max-w-3xl shrink-0 px-4 sm:px-6",
|
|
43
|
+
"data-testid": "queue-surface-loading",
|
|
44
|
+
role: "status",
|
|
45
|
+
children: /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-lg border border-border bg-surface/80 shadow-sm", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 text-xs text-fg-muted pointer-coarse:min-h-[44px]", children: [
|
|
46
|
+
/* @__PURE__ */ jsx(
|
|
47
|
+
Loader2Icon,
|
|
48
|
+
{
|
|
49
|
+
"aria-hidden": "true",
|
|
50
|
+
className: "size-3.5 shrink-0 animate-spin motion-reduce:animate-none"
|
|
51
|
+
}
|
|
52
|
+
),
|
|
53
|
+
"Loading ",
|
|
54
|
+
count,
|
|
55
|
+
" queued prompt",
|
|
56
|
+
count === 1 ? "" : "s",
|
|
57
|
+
"\u2026"
|
|
58
|
+
] }) })
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/components/human-input-form.tsx
|
|
64
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
65
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
66
|
+
var defaultHumanInputFormMessages = {
|
|
67
|
+
title: "Your input is needed",
|
|
68
|
+
description: "The agent is paused until you answer these questions.",
|
|
69
|
+
submit: "Continue",
|
|
70
|
+
skip: "Skip",
|
|
71
|
+
submitting: "Submitting\u2026",
|
|
72
|
+
other: "Other",
|
|
73
|
+
deadlineLabel: "Respond before",
|
|
74
|
+
formatDeadline,
|
|
75
|
+
required: "This question is required.",
|
|
76
|
+
minLength: (count) => `Enter at least ${count} characters.`,
|
|
77
|
+
maxLength: (count) => `Enter no more than ${count} characters.`,
|
|
78
|
+
otherRequired: "Enter a value for Other.",
|
|
79
|
+
minSelections: (count) => `Choose at least ${count} option${count === 1 ? "" : "s"}.`,
|
|
80
|
+
maxSelections: (count) => `Choose no more than ${count} option${count === 1 ? "" : "s"}.`
|
|
81
|
+
};
|
|
82
|
+
function HumanInputForm({
|
|
83
|
+
request,
|
|
84
|
+
onSubmit,
|
|
85
|
+
submitting = false,
|
|
86
|
+
error,
|
|
87
|
+
title,
|
|
88
|
+
description,
|
|
89
|
+
submitLabel,
|
|
90
|
+
skipLabel,
|
|
91
|
+
messages: messageOverrides,
|
|
92
|
+
autoFocus = true,
|
|
93
|
+
className
|
|
94
|
+
}) {
|
|
95
|
+
const messages = { ...defaultHumanInputFormMessages, ...messageOverrides };
|
|
96
|
+
const resolvedTitle = title === void 0 ? messages.title : title;
|
|
97
|
+
const resolvedDescription = description === void 0 ? messages.description : description;
|
|
98
|
+
const resolvedSubmitLabel = submitLabel ?? messages.submit;
|
|
99
|
+
const resolvedSkipLabel = skipLabel ?? messages.skip;
|
|
100
|
+
const formId = useId();
|
|
101
|
+
const [drafts, setDrafts] = useState(
|
|
102
|
+
() => initialDrafts(request.questions)
|
|
103
|
+
);
|
|
104
|
+
const [validationErrors, setValidationErrors] = useState({});
|
|
105
|
+
const [submissionError, setSubmissionError] = useState(null);
|
|
106
|
+
const [submittingInternally, setSubmittingInternally] = useState(false);
|
|
107
|
+
const submissionInFlight = useRef(false);
|
|
108
|
+
const submissionGeneration = useRef(0);
|
|
109
|
+
const busy = submitting || submittingInternally;
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
submissionGeneration.current += 1;
|
|
112
|
+
submissionInFlight.current = false;
|
|
113
|
+
setDrafts(initialDrafts(request.questions));
|
|
114
|
+
setValidationErrors({});
|
|
115
|
+
setSubmissionError(null);
|
|
116
|
+
setSubmittingInternally(false);
|
|
117
|
+
}, [request.id, request.questions]);
|
|
118
|
+
const update = (questionId, apply) => {
|
|
119
|
+
setDrafts((current) => ({
|
|
120
|
+
...current,
|
|
121
|
+
[questionId]: apply(current[questionId] ?? emptyDraft())
|
|
122
|
+
}));
|
|
123
|
+
setValidationErrors((current) => {
|
|
124
|
+
if (!(questionId in current)) return current;
|
|
125
|
+
const next = { ...current };
|
|
126
|
+
delete next[questionId];
|
|
127
|
+
return next;
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
const submitResponse = async (response) => {
|
|
131
|
+
if (busy || submissionInFlight.current) return;
|
|
132
|
+
const generation = submissionGeneration.current;
|
|
133
|
+
submissionInFlight.current = true;
|
|
134
|
+
setSubmissionError(null);
|
|
135
|
+
setSubmittingInternally(true);
|
|
136
|
+
try {
|
|
137
|
+
await onSubmit(response);
|
|
138
|
+
} catch (cause) {
|
|
139
|
+
if (generation === submissionGeneration.current) {
|
|
140
|
+
setSubmissionError(cause instanceof Error ? cause.message : String(cause));
|
|
141
|
+
}
|
|
142
|
+
} finally {
|
|
143
|
+
if (generation === submissionGeneration.current) {
|
|
144
|
+
submissionInFlight.current = false;
|
|
145
|
+
setSubmittingInternally(false);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
const submit = async (event) => {
|
|
150
|
+
event.preventDefault();
|
|
151
|
+
const result = answersFromDrafts(request.questions, drafts, messages);
|
|
152
|
+
if (Object.keys(result.errors).length > 0) {
|
|
153
|
+
setValidationErrors(result.errors);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
await submitResponse({ outcome: "answered", answers: result.answers });
|
|
157
|
+
};
|
|
158
|
+
return /* @__PURE__ */ jsxs2(
|
|
159
|
+
"form",
|
|
160
|
+
{
|
|
161
|
+
"data-human-input-request": request.id,
|
|
162
|
+
onSubmit: (event) => void submit(event),
|
|
163
|
+
className: cn(
|
|
164
|
+
"og-root flex w-full flex-col gap-5 rounded-og-lg border border-og-border bg-og-surface-1 p-5 shadow-og-sm",
|
|
165
|
+
className
|
|
166
|
+
),
|
|
167
|
+
children: [
|
|
168
|
+
/* @__PURE__ */ jsxs2("header", { children: [
|
|
169
|
+
/* @__PURE__ */ jsx2("h2", { className: "text-og-md font-semibold text-og-fg", children: resolvedTitle }),
|
|
170
|
+
resolvedDescription ? /* @__PURE__ */ jsx2("div", { className: "mt-1 text-og-sm text-og-fg-muted", children: resolvedDescription }) : null,
|
|
171
|
+
request.expiresAt ? /* @__PURE__ */ jsxs2("p", { className: "mt-1 text-og-xs text-og-fg-subtle", children: [
|
|
172
|
+
messages.deadlineLabel,
|
|
173
|
+
" ",
|
|
174
|
+
/* @__PURE__ */ jsx2("time", { dateTime: request.expiresAt, children: messages.formatDeadline(request.expiresAt) })
|
|
175
|
+
] }) : null
|
|
176
|
+
] }),
|
|
177
|
+
/* @__PURE__ */ jsx2("fieldset", { disabled: busy, className: "contents", children: request.questions.map((question, index) => {
|
|
178
|
+
const draft = drafts[question.id] ?? emptyDraft();
|
|
179
|
+
const fieldId = `${formId}-${index}`;
|
|
180
|
+
const errorId = `${fieldId}-error`;
|
|
181
|
+
const helpId = `${fieldId}-help`;
|
|
182
|
+
const describedBy = [question.helpText ? helpId : null, validationErrors[question.id] ? errorId : null].filter(Boolean).join(" ") || void 0;
|
|
183
|
+
return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-2", children: [
|
|
184
|
+
/* @__PURE__ */ jsxs2(
|
|
185
|
+
"label",
|
|
186
|
+
{
|
|
187
|
+
htmlFor: question.kind === "text" ? fieldId : void 0,
|
|
188
|
+
className: "text-og-base font-medium text-og-fg",
|
|
189
|
+
children: [
|
|
190
|
+
question.label ?? question.prompt,
|
|
191
|
+
question.required ? /* @__PURE__ */ jsx2("span", { "aria-hidden": true, className: "ml-1 text-og-status-failed", children: "*" }) : null
|
|
192
|
+
]
|
|
193
|
+
}
|
|
194
|
+
),
|
|
195
|
+
question.label ? /* @__PURE__ */ jsx2("p", { className: "text-og-sm text-og-fg-muted", children: question.prompt }) : null,
|
|
196
|
+
question.helpText ? /* @__PURE__ */ jsx2("p", { id: helpId, className: "text-og-xs text-og-fg-subtle", children: question.helpText }) : null,
|
|
197
|
+
question.kind === "text" ? /* @__PURE__ */ jsx2(
|
|
198
|
+
"textarea",
|
|
199
|
+
{
|
|
200
|
+
id: fieldId,
|
|
201
|
+
value: draft.values[0] ?? "",
|
|
202
|
+
onChange: (event) => update(question.id, (current) => ({
|
|
203
|
+
...current,
|
|
204
|
+
values: event.target.value ? [event.target.value] : []
|
|
205
|
+
})),
|
|
206
|
+
"aria-invalid": Boolean(validationErrors[question.id]),
|
|
207
|
+
"aria-describedby": describedBy,
|
|
208
|
+
autoFocus: autoFocus && index === 0,
|
|
209
|
+
rows: 3,
|
|
210
|
+
className: "min-h-20 w-full resize-y rounded-og-md border border-og-border bg-og-surface-2 px-3 py-2 text-og-base text-og-fg outline-none placeholder:text-og-fg-subtle focus:border-og-accent"
|
|
211
|
+
}
|
|
212
|
+
) : /* @__PURE__ */ jsxs2(
|
|
213
|
+
"div",
|
|
214
|
+
{
|
|
215
|
+
role: question.kind === "single_select" ? "radiogroup" : "group",
|
|
216
|
+
"aria-describedby": describedBy,
|
|
217
|
+
className: "flex flex-col gap-2",
|
|
218
|
+
children: [
|
|
219
|
+
question.options.map((option, optionIndex) => {
|
|
220
|
+
const checked = draft.values.includes(option.id);
|
|
221
|
+
return /* @__PURE__ */ jsxs2(
|
|
222
|
+
"label",
|
|
223
|
+
{
|
|
224
|
+
className: "flex cursor-pointer items-start gap-2 rounded-og-md border border-og-border px-3 py-2 hover:bg-og-surface-2",
|
|
225
|
+
children: [
|
|
226
|
+
/* @__PURE__ */ jsx2(
|
|
227
|
+
"input",
|
|
228
|
+
{
|
|
229
|
+
type: question.kind === "single_select" ? "radio" : "checkbox",
|
|
230
|
+
name: question.kind === "single_select" ? fieldId : void 0,
|
|
231
|
+
autoFocus: autoFocus && index === 0 && optionIndex === 0,
|
|
232
|
+
checked,
|
|
233
|
+
onChange: (event) => update(question.id, (current) => ({
|
|
234
|
+
...current,
|
|
235
|
+
values: question.kind === "single_select" ? event.target.checked ? [option.id] : [] : event.target.checked ? [...current.values, option.id] : current.values.filter((value) => value !== option.id),
|
|
236
|
+
...question.kind === "single_select" && event.target.checked ? { otherSelected: false } : {}
|
|
237
|
+
})),
|
|
238
|
+
className: "mt-0.5 accent-og-accent"
|
|
239
|
+
}
|
|
240
|
+
),
|
|
241
|
+
/* @__PURE__ */ jsxs2("span", { className: "min-w-0", children: [
|
|
242
|
+
/* @__PURE__ */ jsx2("span", { className: "block text-og-sm font-medium text-og-fg", children: option.label }),
|
|
243
|
+
option.description ? /* @__PURE__ */ jsx2("span", { className: "block text-og-xs text-og-fg-muted", children: option.description }) : null
|
|
244
|
+
] })
|
|
245
|
+
]
|
|
246
|
+
},
|
|
247
|
+
option.id
|
|
248
|
+
);
|
|
249
|
+
}),
|
|
250
|
+
question.allowOther ? /* @__PURE__ */ jsxs2("label", { className: "flex items-start gap-2 rounded-og-md border border-og-border px-3 py-2", children: [
|
|
251
|
+
/* @__PURE__ */ jsx2(
|
|
252
|
+
"input",
|
|
253
|
+
{
|
|
254
|
+
type: question.kind === "single_select" ? "radio" : "checkbox",
|
|
255
|
+
name: question.kind === "single_select" ? fieldId : void 0,
|
|
256
|
+
checked: draft.otherSelected,
|
|
257
|
+
autoFocus: autoFocus && index === 0 && question.options.length === 0,
|
|
258
|
+
onChange: (event) => update(question.id, (current) => ({
|
|
259
|
+
...current,
|
|
260
|
+
otherSelected: event.target.checked,
|
|
261
|
+
...question.kind === "single_select" && event.target.checked ? { values: [] } : {}
|
|
262
|
+
})),
|
|
263
|
+
className: "mt-2 accent-og-accent"
|
|
264
|
+
}
|
|
265
|
+
),
|
|
266
|
+
/* @__PURE__ */ jsxs2("span", { className: "min-w-0 flex-1", children: [
|
|
267
|
+
/* @__PURE__ */ jsx2("span", { className: "block text-og-sm font-medium text-og-fg", children: messages.other }),
|
|
268
|
+
/* @__PURE__ */ jsx2(
|
|
269
|
+
"input",
|
|
270
|
+
{
|
|
271
|
+
type: "text",
|
|
272
|
+
value: draft.other,
|
|
273
|
+
disabled: !draft.otherSelected || busy,
|
|
274
|
+
onChange: (event) => update(question.id, (current) => ({
|
|
275
|
+
...current,
|
|
276
|
+
other: event.target.value
|
|
277
|
+
})),
|
|
278
|
+
className: "mt-1 w-full rounded-og-sm border border-og-border bg-og-surface-2 px-2 py-1.5 text-og-sm text-og-fg outline-none focus:border-og-accent disabled:opacity-50"
|
|
279
|
+
}
|
|
280
|
+
)
|
|
281
|
+
] })
|
|
282
|
+
] }) : null
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
),
|
|
286
|
+
validationErrors[question.id] ? /* @__PURE__ */ jsx2("p", { id: errorId, role: "alert", className: "text-og-xs text-og-status-failed", children: validationErrors[question.id] }) : null
|
|
287
|
+
] }, question.id);
|
|
288
|
+
}) }),
|
|
289
|
+
error ?? submissionError ? /* @__PURE__ */ jsx2("p", { role: "alert", className: "text-og-sm text-og-status-failed", children: error ?? submissionError }) : null,
|
|
290
|
+
/* @__PURE__ */ jsxs2("footer", { className: "flex items-center justify-end gap-2", children: [
|
|
291
|
+
request.allowSkip ? /* @__PURE__ */ jsx2(
|
|
292
|
+
"button",
|
|
293
|
+
{
|
|
294
|
+
type: "button",
|
|
295
|
+
disabled: busy,
|
|
296
|
+
onClick: () => void submitResponse({ outcome: "skipped" }),
|
|
297
|
+
className: "rounded-og-md border border-og-border px-3 py-2 text-og-sm font-medium text-og-fg-muted hover:bg-og-surface-2 disabled:opacity-50",
|
|
298
|
+
children: resolvedSkipLabel
|
|
299
|
+
}
|
|
300
|
+
) : null,
|
|
301
|
+
/* @__PURE__ */ jsx2(
|
|
302
|
+
"button",
|
|
303
|
+
{
|
|
304
|
+
type: "submit",
|
|
305
|
+
disabled: busy,
|
|
306
|
+
className: "rounded-og-md bg-og-accent px-3 py-2 text-og-sm font-medium text-og-accent-fg hover:bg-og-accent-strong disabled:opacity-50",
|
|
307
|
+
children: busy ? messages.submitting : resolvedSubmitLabel
|
|
308
|
+
}
|
|
309
|
+
)
|
|
310
|
+
] })
|
|
311
|
+
]
|
|
312
|
+
}
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
function answersFromDrafts(questions, drafts, messageOverrides = {}) {
|
|
316
|
+
const messages = { ...defaultHumanInputFormMessages, ...messageOverrides };
|
|
317
|
+
const answers = [];
|
|
318
|
+
const errors = {};
|
|
319
|
+
for (const question of questions) {
|
|
320
|
+
const draft = drafts[question.id] ?? emptyDraft();
|
|
321
|
+
const values = question.kind === "text" ? draft.values.filter(Boolean) : draft.values;
|
|
322
|
+
const other = draft.otherSelected ? draft.other.trim() : "";
|
|
323
|
+
const supplied = values.length + (other ? 1 : 0);
|
|
324
|
+
if (question.required && supplied === 0) {
|
|
325
|
+
errors[question.id] = messages.required;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (question.kind === "text") {
|
|
329
|
+
const value = values[0] ?? "";
|
|
330
|
+
if (value && question.validation?.minLength != null && value.length < question.validation.minLength) {
|
|
331
|
+
errors[question.id] = messages.minLength(question.validation.minLength);
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
if (question.validation?.maxLength != null && value.length > question.validation.maxLength) {
|
|
335
|
+
errors[question.id] = messages.maxLength(question.validation.maxLength);
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
} else {
|
|
339
|
+
if (draft.otherSelected && !other) {
|
|
340
|
+
errors[question.id] = messages.otherRequired;
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
const min = question.validation?.minSelections;
|
|
344
|
+
const max = question.kind === "single_select" ? 1 : question.validation?.maxSelections;
|
|
345
|
+
if (min != null && supplied < min) {
|
|
346
|
+
errors[question.id] = messages.minSelections(min);
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
if (max != null && supplied > max) {
|
|
350
|
+
errors[question.id] = messages.maxSelections(max);
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (supplied > 0) {
|
|
355
|
+
answers.push({
|
|
356
|
+
questionId: question.id,
|
|
357
|
+
values,
|
|
358
|
+
...other ? { other } : {}
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return { answers, errors };
|
|
363
|
+
}
|
|
364
|
+
function initialDrafts(questions) {
|
|
365
|
+
return Object.fromEntries(questions.map((question) => [question.id, emptyDraft()]));
|
|
366
|
+
}
|
|
367
|
+
function emptyDraft() {
|
|
368
|
+
return { values: [], other: "", otherSelected: false };
|
|
369
|
+
}
|
|
370
|
+
function formatDeadline(value) {
|
|
371
|
+
const date = new Date(value);
|
|
372
|
+
return Number.isNaN(date.getTime()) ? value : date.toLocaleString();
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// src/timeline/registry.ts
|
|
376
|
+
function rawTypeOf(item) {
|
|
377
|
+
const raw = item.raw;
|
|
378
|
+
if (raw && typeof raw === "object" && typeof raw.type === "string") {
|
|
379
|
+
return raw.type;
|
|
380
|
+
}
|
|
381
|
+
return null;
|
|
382
|
+
}
|
|
383
|
+
function createToolRegistry(baseEntries, baseFallback, options = {}) {
|
|
384
|
+
const entries = [...options.entries ?? [], ...baseEntries];
|
|
385
|
+
const fallback = options.fallback ?? baseFallback;
|
|
386
|
+
const byRawType = /* @__PURE__ */ new Map();
|
|
387
|
+
const byName = /* @__PURE__ */ new Map();
|
|
388
|
+
for (const entry of entries) {
|
|
389
|
+
if (entry.match === "rawType") {
|
|
390
|
+
if (!byRawType.has(entry.type)) {
|
|
391
|
+
byRawType.set(entry.type, entry.render);
|
|
392
|
+
}
|
|
393
|
+
} else if (!byName.has(entry.name)) {
|
|
394
|
+
byName.set(entry.name, entry.render);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
const resolve = (item) => {
|
|
398
|
+
const rawType = rawTypeOf(item);
|
|
399
|
+
if (rawType) {
|
|
400
|
+
const byType = byRawType.get(rawType);
|
|
401
|
+
if (byType) {
|
|
402
|
+
return byType;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return byName.get(item.name) ?? fallback;
|
|
406
|
+
};
|
|
407
|
+
return { resolve, fallback };
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// src/timeline/parsers.ts
|
|
411
|
+
function sandboxCommandExitCode(out) {
|
|
412
|
+
const match = String(out ?? "").match(/Process exited with code (-?\d+)/);
|
|
413
|
+
return match ? Number(match[1]) : null;
|
|
414
|
+
}
|
|
415
|
+
function parseExecBannerSessionId(out) {
|
|
416
|
+
const text = String(out ?? "");
|
|
417
|
+
const outputIdx = text.indexOf("\nOutput:\n");
|
|
418
|
+
const banner = outputIdx >= 0 ? text.slice(0, outputIdx) : text.startsWith("Output:\n") ? "" : text;
|
|
419
|
+
const match = banner.match(/Process running with session ID (\d+)/);
|
|
420
|
+
if (!match) {
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
const n = Number.parseInt(match[1], 10);
|
|
424
|
+
return Number.isFinite(n) ? n : null;
|
|
425
|
+
}
|
|
426
|
+
function stripExecBanner(out) {
|
|
427
|
+
const text = String(out ?? "");
|
|
428
|
+
const marker = text.indexOf("\nOutput:\n");
|
|
429
|
+
if (marker >= 0) {
|
|
430
|
+
return text.slice(marker + "\nOutput:\n".length);
|
|
431
|
+
}
|
|
432
|
+
if (text.startsWith("Output:\n")) {
|
|
433
|
+
return text.slice("Output:\n".length);
|
|
434
|
+
}
|
|
435
|
+
return text;
|
|
436
|
+
}
|
|
437
|
+
function execTruncated(out) {
|
|
438
|
+
return /Total output lines:|\.{3}\d+ tokens truncated\.{3}|\[\.{3}\d+ characters truncated/.test(
|
|
439
|
+
String(out ?? "")
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
function isExecSessionLostBanner(out) {
|
|
443
|
+
return /write_stdin failed: session not found: \d+/.test(String(out ?? ""));
|
|
444
|
+
}
|
|
445
|
+
function looksBinary(text) {
|
|
446
|
+
return text.includes("\0") || text.startsWith("\x7FELF");
|
|
447
|
+
}
|
|
448
|
+
function controlCaret(printable) {
|
|
449
|
+
return String(printable).replace(
|
|
450
|
+
/[\u0000-\u001f]/g,
|
|
451
|
+
(c) => `^${String.fromCharCode(c.charCodeAt(0) + 64)}`
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
function v4aToGitFileDiff(op) {
|
|
455
|
+
const status = op.type === "create_file" ? "added" : op.type === "delete_file" ? "deleted" : op.moveTo ? "renamed" : "modified";
|
|
456
|
+
const oldPath = op.moveTo ? op.path : null;
|
|
457
|
+
const path = op.moveTo || op.path;
|
|
458
|
+
const hunks = [];
|
|
459
|
+
let additions = 0;
|
|
460
|
+
let deletions = 0;
|
|
461
|
+
let sawHunkAnchor = false;
|
|
462
|
+
if (op.type !== "delete_file") {
|
|
463
|
+
const lines = (op.diff ?? "").split("\n");
|
|
464
|
+
let cur = null;
|
|
465
|
+
let oldNo = 1;
|
|
466
|
+
let newNo = 1;
|
|
467
|
+
for (const raw of lines) {
|
|
468
|
+
if (raw.startsWith("@@")) {
|
|
469
|
+
sawHunkAnchor = true;
|
|
470
|
+
const match = raw.match(/-(\d+)(?:,\d+)?\s+\+(\d+)/);
|
|
471
|
+
oldNo = match ? Number(match[1]) : 1;
|
|
472
|
+
newNo = match ? Number(match[2]) : 1;
|
|
473
|
+
cur = {
|
|
474
|
+
oldStart: oldNo,
|
|
475
|
+
oldLines: 0,
|
|
476
|
+
newStart: newNo,
|
|
477
|
+
newLines: 0,
|
|
478
|
+
header: raw,
|
|
479
|
+
lines: [{ type: "meta", oldNo: null, newNo: null, text: raw }]
|
|
480
|
+
};
|
|
481
|
+
hunks.push(cur);
|
|
482
|
+
} else if (cur || op.type === "create_file") {
|
|
483
|
+
if (!cur) {
|
|
484
|
+
cur = {
|
|
485
|
+
oldStart: 0,
|
|
486
|
+
oldLines: 0,
|
|
487
|
+
newStart: 1,
|
|
488
|
+
newLines: 0,
|
|
489
|
+
header: "",
|
|
490
|
+
lines: []
|
|
491
|
+
};
|
|
492
|
+
hunks.push(cur);
|
|
493
|
+
oldNo = 0;
|
|
494
|
+
newNo = 1;
|
|
495
|
+
}
|
|
496
|
+
if (raw.startsWith("+")) {
|
|
497
|
+
cur.lines.push({
|
|
498
|
+
type: "add",
|
|
499
|
+
oldNo: null,
|
|
500
|
+
newNo: newNo++,
|
|
501
|
+
text: raw.slice(1)
|
|
502
|
+
});
|
|
503
|
+
cur.newLines += 1;
|
|
504
|
+
additions += 1;
|
|
505
|
+
} else if (raw.startsWith("-")) {
|
|
506
|
+
cur.lines.push({
|
|
507
|
+
type: "del",
|
|
508
|
+
oldNo: oldNo++,
|
|
509
|
+
newNo: null,
|
|
510
|
+
text: raw.slice(1)
|
|
511
|
+
});
|
|
512
|
+
cur.oldLines += 1;
|
|
513
|
+
deletions += 1;
|
|
514
|
+
} else {
|
|
515
|
+
cur.lines.push({
|
|
516
|
+
type: "context",
|
|
517
|
+
oldNo: oldNo++,
|
|
518
|
+
newNo: newNo++,
|
|
519
|
+
text: raw.replace(/^ /, "")
|
|
520
|
+
});
|
|
521
|
+
cur.oldLines += 1;
|
|
522
|
+
cur.newLines += 1;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
if (op.type === "update_file" && !sawHunkAnchor && lines.some((l) => l.trim().length > 0)) {
|
|
527
|
+
throw new Error("malformed V4A: no @@ hunk anchor");
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return {
|
|
531
|
+
path,
|
|
532
|
+
oldPath,
|
|
533
|
+
status,
|
|
534
|
+
isBinary: false,
|
|
535
|
+
isImage: false,
|
|
536
|
+
additions,
|
|
537
|
+
deletions,
|
|
538
|
+
hunks,
|
|
539
|
+
truncated: false
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
function applyPatchOps(raw) {
|
|
543
|
+
const r = raw ?? {};
|
|
544
|
+
if (Array.isArray(r.operations)) {
|
|
545
|
+
return r.operations;
|
|
546
|
+
}
|
|
547
|
+
return r.operation ? [r.operation] : [];
|
|
548
|
+
}
|
|
549
|
+
function isApplyPatch(item) {
|
|
550
|
+
const type = item.raw && typeof item.raw === "object" ? item.raw.type : void 0;
|
|
551
|
+
return type === "apply_patch_call" || item.name === "apply_patch_call";
|
|
552
|
+
}
|
|
553
|
+
var SECRET_KEY = /^(value|secret|token|password|api[_-]?key|signing[_-]?key)$/i;
|
|
554
|
+
function redactSecrets(value) {
|
|
555
|
+
if (Array.isArray(value)) {
|
|
556
|
+
return value.map(redactSecrets);
|
|
557
|
+
}
|
|
558
|
+
if (value && typeof value === "object") {
|
|
559
|
+
const out = {};
|
|
560
|
+
for (const [k, v] of Object.entries(value)) {
|
|
561
|
+
out[k] = SECRET_KEY.test(k) ? "\u2022\u2022\u2022\u2022" : redactSecrets(v);
|
|
562
|
+
}
|
|
563
|
+
return out;
|
|
564
|
+
}
|
|
565
|
+
return value;
|
|
566
|
+
}
|
|
567
|
+
function parseToolArgs(args) {
|
|
568
|
+
if (args == null) {
|
|
569
|
+
return {};
|
|
570
|
+
}
|
|
571
|
+
if (typeof args === "string") {
|
|
572
|
+
const parsed = tryParseJson(args);
|
|
573
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
574
|
+
}
|
|
575
|
+
return typeof args === "object" ? args : {};
|
|
576
|
+
}
|
|
577
|
+
function tailPeek(text) {
|
|
578
|
+
const trimmed = text.trim();
|
|
579
|
+
if (!trimmed) {
|
|
580
|
+
return "";
|
|
581
|
+
}
|
|
582
|
+
const lines = trimmed.split("\n");
|
|
583
|
+
return lines[lines.length - 1] ?? "";
|
|
584
|
+
}
|
|
585
|
+
function unwrapMcpOutput(output) {
|
|
586
|
+
if (output && typeof output === "object" && output.type === "text" && typeof output.text === "string") {
|
|
587
|
+
const record = output;
|
|
588
|
+
return { text: record.text, isError: Boolean(record.isError) };
|
|
589
|
+
}
|
|
590
|
+
if (output && typeof output === "object" && "content" in output) {
|
|
591
|
+
const record = output;
|
|
592
|
+
const isError = Boolean(record.isError);
|
|
593
|
+
if (Array.isArray(record.content)) {
|
|
594
|
+
const textPart = record.content.find(
|
|
595
|
+
(part) => !!part && typeof part === "object" && part.type === "text"
|
|
596
|
+
);
|
|
597
|
+
return {
|
|
598
|
+
text: textPart ? String(textPart.text) : JSON.stringify(output),
|
|
599
|
+
isError
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
return { text: JSON.stringify(output), isError };
|
|
603
|
+
}
|
|
604
|
+
return {
|
|
605
|
+
text: typeof output === "string" ? output : output == null ? "" : JSON.stringify(output),
|
|
606
|
+
isError: false
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
function screenshotDataUrl(out) {
|
|
610
|
+
if (typeof out === "string") {
|
|
611
|
+
if (out.startsWith("data:image")) {
|
|
612
|
+
return out;
|
|
613
|
+
}
|
|
614
|
+
if (out.startsWith("{") || out.startsWith("[")) {
|
|
615
|
+
const parsed = tryParseJson(out);
|
|
616
|
+
if (parsed !== void 0 && parsed !== out) {
|
|
617
|
+
return screenshotDataUrl(parsed);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return null;
|
|
621
|
+
}
|
|
622
|
+
if (Array.isArray(out)) {
|
|
623
|
+
for (const entry of out) {
|
|
624
|
+
const url = screenshotDataUrl(entry);
|
|
625
|
+
if (url) {
|
|
626
|
+
return url;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
return null;
|
|
630
|
+
}
|
|
631
|
+
if (out === null || typeof out !== "object") {
|
|
632
|
+
return null;
|
|
633
|
+
}
|
|
634
|
+
const record = out;
|
|
635
|
+
const imageUrl = record.image_url ?? record.imageUrl;
|
|
636
|
+
if (typeof imageUrl === "string" && imageUrl.startsWith("data:image")) {
|
|
637
|
+
return imageUrl;
|
|
638
|
+
}
|
|
639
|
+
if (imageUrl && typeof imageUrl === "object") {
|
|
640
|
+
const url = imageUrl.url;
|
|
641
|
+
if (typeof url === "string" && url.startsWith("data:image")) {
|
|
642
|
+
return url;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
const image = record.image;
|
|
646
|
+
if (image && typeof image === "object") {
|
|
647
|
+
const mediaType = typeof image.mediaType === "string" ? image.mediaType : "image/png";
|
|
648
|
+
const base64 = bytesToBase64(image.data);
|
|
649
|
+
if (base64) {
|
|
650
|
+
return `data:${mediaType};base64,${base64}`;
|
|
651
|
+
}
|
|
652
|
+
if (typeof image.data === "string" && image.data.length > 0) {
|
|
653
|
+
return `data:${mediaType};base64,${image.data}`;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
return null;
|
|
657
|
+
}
|
|
658
|
+
function mediaPreviewFact(out) {
|
|
659
|
+
if (typeof out === "string" && (out.startsWith("{") || out.startsWith("["))) {
|
|
660
|
+
const parsed = tryParseJson(out);
|
|
661
|
+
if (parsed !== void 0 && parsed !== out) return mediaPreviewFact(parsed);
|
|
662
|
+
}
|
|
663
|
+
if (Array.isArray(out)) {
|
|
664
|
+
for (const entry of out) {
|
|
665
|
+
const preview = mediaPreviewFact(entry);
|
|
666
|
+
if (preview) return preview;
|
|
667
|
+
}
|
|
668
|
+
return null;
|
|
669
|
+
}
|
|
670
|
+
if (!out || typeof out !== "object") return null;
|
|
671
|
+
const record = out;
|
|
672
|
+
if (record.type !== "media_preview" || typeof record.mediaType !== "string" || record.fullOutputAvailable !== false || typeof record.preview !== "string" || record.inlineBytes !== null && typeof record.inlineBytes !== "number") {
|
|
673
|
+
return null;
|
|
674
|
+
}
|
|
675
|
+
return record;
|
|
676
|
+
}
|
|
677
|
+
function bytesToBase64(data) {
|
|
678
|
+
const isByte = (n) => typeof n === "number" && Number.isInteger(n) && n >= 0 && n <= 255;
|
|
679
|
+
let bytes = null;
|
|
680
|
+
if (Array.isArray(data) && data.every(isByte)) {
|
|
681
|
+
bytes = data;
|
|
682
|
+
} else if (data && typeof data === "object") {
|
|
683
|
+
const record = data;
|
|
684
|
+
if (record.type === "Buffer" && Array.isArray(record.data) && record.data.every(isByte)) {
|
|
685
|
+
bytes = record.data;
|
|
686
|
+
} else {
|
|
687
|
+
const keys = Object.keys(record);
|
|
688
|
+
if (keys.length > 0 && keys.every((key) => /^\d+$/.test(key))) {
|
|
689
|
+
const values = keys.sort((a, b) => Number(a) - Number(b)).map((key) => record[key]);
|
|
690
|
+
if (values.every(isByte)) {
|
|
691
|
+
bytes = values;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
if (!bytes || bytes.length === 0) {
|
|
697
|
+
return null;
|
|
698
|
+
}
|
|
699
|
+
try {
|
|
700
|
+
let binary = "";
|
|
701
|
+
const CHUNK = 32768;
|
|
702
|
+
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
703
|
+
binary += String.fromCharCode(...bytes.slice(i, i + CHUNK));
|
|
704
|
+
}
|
|
705
|
+
return typeof btoa === "function" ? btoa(binary) : Buffer.from(binary, "binary").toString("base64");
|
|
706
|
+
} catch {
|
|
707
|
+
return null;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// src/timeline/disclosure-context.tsx
|
|
712
|
+
import { createContext, useContext } from "react";
|
|
713
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
714
|
+
var DisclosureDefaultsContext = createContext(void 0);
|
|
715
|
+
function DisclosureDefaultsProvider({
|
|
716
|
+
defaultOpen,
|
|
717
|
+
children
|
|
718
|
+
}) {
|
|
719
|
+
return /* @__PURE__ */ jsx3(DisclosureDefaultsContext.Provider, { value: defaultOpen, children });
|
|
720
|
+
}
|
|
721
|
+
function useForcedDefaultOpen() {
|
|
722
|
+
return useContext(DisclosureDefaultsContext);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// src/timeline/screenshot-lightbox.tsx
|
|
726
|
+
import { XIcon } from "lucide-react";
|
|
727
|
+
import { AnimatePresence, motion } from "motion/react";
|
|
728
|
+
import { createContext as createContext2, useCallback, useContext as useContext2, useMemo, useState as useState2 } from "react";
|
|
729
|
+
import { Dialog } from "radix-ui";
|
|
730
|
+
import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
731
|
+
var LightboxContext = createContext2(null);
|
|
732
|
+
function useLightbox() {
|
|
733
|
+
return useContext2(LightboxContext) ?? NOOP;
|
|
734
|
+
}
|
|
735
|
+
function useLightboxOptional() {
|
|
736
|
+
return useContext2(LightboxContext);
|
|
737
|
+
}
|
|
738
|
+
var NOOP = { open: () => {
|
|
739
|
+
} };
|
|
740
|
+
function LightboxProvider({ children }) {
|
|
741
|
+
const ancestor = useContext2(LightboxContext);
|
|
742
|
+
if (ancestor) {
|
|
743
|
+
return /* @__PURE__ */ jsx4(Fragment, { children });
|
|
744
|
+
}
|
|
745
|
+
return /* @__PURE__ */ jsx4(LightboxRoot, { children });
|
|
746
|
+
}
|
|
747
|
+
function LightboxRoot({ children }) {
|
|
748
|
+
const [state, setState] = useState2(null);
|
|
749
|
+
const open = useCallback((src, caption) => {
|
|
750
|
+
setState(caption ? { src, caption } : { src });
|
|
751
|
+
}, []);
|
|
752
|
+
const controller = useMemo(() => ({ open }), [open]);
|
|
753
|
+
return /* @__PURE__ */ jsxs3(LightboxContext.Provider, { value: controller, children: [
|
|
754
|
+
children,
|
|
755
|
+
/* @__PURE__ */ jsx4(Dialog.Root, { open: state !== null, onOpenChange: (next) => !next && setState(null), children: /* @__PURE__ */ jsx4(AnimatePresence, { children: state !== null ? /* @__PURE__ */ jsxs3(Dialog.Portal, { forceMount: true, children: [
|
|
756
|
+
/* @__PURE__ */ jsx4(Dialog.Overlay, { asChild: true, forceMount: true, children: /* @__PURE__ */ jsx4(
|
|
757
|
+
motion.div,
|
|
758
|
+
{
|
|
759
|
+
initial: { opacity: 0 },
|
|
760
|
+
animate: { opacity: 1 },
|
|
761
|
+
exit: { opacity: 0 },
|
|
762
|
+
transition: { duration: 0.15 },
|
|
763
|
+
className: "og-root fixed inset-0 z-50 bg-black/90 backdrop-blur-md"
|
|
764
|
+
}
|
|
765
|
+
) }),
|
|
766
|
+
/* @__PURE__ */ jsx4(
|
|
767
|
+
Dialog.Content,
|
|
768
|
+
{
|
|
769
|
+
asChild: true,
|
|
770
|
+
forceMount: true,
|
|
771
|
+
"aria-label": "Screenshot",
|
|
772
|
+
onOpenAutoFocus: (event) => event.preventDefault(),
|
|
773
|
+
children: /* @__PURE__ */ jsxs3(
|
|
774
|
+
motion.div,
|
|
775
|
+
{
|
|
776
|
+
initial: { opacity: 0, scale: 0.98 },
|
|
777
|
+
animate: { opacity: 1, scale: 1 },
|
|
778
|
+
exit: { opacity: 0, scale: 0.98 },
|
|
779
|
+
transition: { duration: 0.18, ease: [0.16, 1, 0.3, 1] },
|
|
780
|
+
onClick: (event) => {
|
|
781
|
+
if (event.target === event.currentTarget) {
|
|
782
|
+
setState(null);
|
|
783
|
+
}
|
|
784
|
+
},
|
|
785
|
+
className: "og-root fixed inset-0 z-50 flex items-center justify-center p-6 sm:p-12",
|
|
786
|
+
children: [
|
|
787
|
+
/* @__PURE__ */ jsx4(Dialog.Title, { className: "sr-only", children: "Screenshot" }),
|
|
788
|
+
/* @__PURE__ */ jsxs3("figure", { className: "m-0 flex max-h-full max-w-5xl flex-col items-center gap-3", children: [
|
|
789
|
+
/* @__PURE__ */ jsxs3("div", { className: "relative flex min-h-0 w-fit max-w-full", children: [
|
|
790
|
+
/* @__PURE__ */ jsx4(
|
|
791
|
+
"img",
|
|
792
|
+
{
|
|
793
|
+
src: state.src,
|
|
794
|
+
alt: state.caption ?? "Screenshot",
|
|
795
|
+
className: "min-h-0 max-h-[82vh] w-auto max-w-full rounded-og-md border border-white/10 object-contain shadow-og-lg"
|
|
796
|
+
}
|
|
797
|
+
),
|
|
798
|
+
/* @__PURE__ */ jsx4(
|
|
799
|
+
Dialog.Close,
|
|
800
|
+
{
|
|
801
|
+
className: cn(
|
|
802
|
+
"absolute -right-3 -top-3 inline-flex size-9 items-center justify-center rounded-full",
|
|
803
|
+
"border border-white/15 bg-black/60 text-white/70 backdrop-blur",
|
|
804
|
+
"transition-colors hover:border-white/30 hover:text-white"
|
|
805
|
+
),
|
|
806
|
+
"aria-label": "Close",
|
|
807
|
+
children: /* @__PURE__ */ jsx4(XIcon, { className: "size-4" })
|
|
808
|
+
}
|
|
809
|
+
)
|
|
810
|
+
] }),
|
|
811
|
+
state.caption ? /* @__PURE__ */ jsx4("figcaption", { className: "max-w-2xl text-center font-og-mono text-og-xs text-white/55", children: state.caption }) : /* @__PURE__ */ jsx4("figcaption", { className: "font-og-mono text-og-xs uppercase tracking-[0.1em] text-white/35", children: "Esc or click outside to close" })
|
|
812
|
+
] })
|
|
813
|
+
]
|
|
814
|
+
}
|
|
815
|
+
)
|
|
816
|
+
}
|
|
817
|
+
)
|
|
818
|
+
] }) : null }) })
|
|
819
|
+
] });
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// src/timeline/shared.tsx
|
|
823
|
+
import { CameraIcon, CameraOffIcon, ChevronRightIcon } from "lucide-react";
|
|
824
|
+
import { useState as useState3 } from "react";
|
|
825
|
+
import { Collapsible } from "radix-ui";
|
|
826
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
827
|
+
var ICON_TONE = {
|
|
828
|
+
accent: "text-og-accent",
|
|
829
|
+
failed: "text-og-status-failed",
|
|
830
|
+
running: "text-og-status-running",
|
|
831
|
+
muted: "text-og-fg-subtle"
|
|
832
|
+
};
|
|
833
|
+
function ActivityDisclosure({
|
|
834
|
+
icon,
|
|
835
|
+
iconTone: iconToneProp = "muted",
|
|
836
|
+
title,
|
|
837
|
+
titleMono,
|
|
838
|
+
running,
|
|
839
|
+
preview,
|
|
840
|
+
media,
|
|
841
|
+
chip: chipProp,
|
|
842
|
+
failed,
|
|
843
|
+
cancelled,
|
|
844
|
+
expandable = true,
|
|
845
|
+
children
|
|
846
|
+
}) {
|
|
847
|
+
const iconTone = failed && iconToneProp === "muted" ? "failed" : iconToneProp;
|
|
848
|
+
const chip = chipProp ?? (failed ? { tone: "bad", text: "failed" } : cancelled ? { tone: "interrupted", text: "interrupted" } : void 0);
|
|
849
|
+
const forcedDefaultOpen = useForcedDefaultOpen();
|
|
850
|
+
const [open, setOpen] = useState3(forcedDefaultOpen ?? false);
|
|
851
|
+
const hasBody = expandable && children != null;
|
|
852
|
+
const previewVisible = preview != null && !open;
|
|
853
|
+
const rowClass = cn(
|
|
854
|
+
"group/disclosure flex w-full min-w-0 items-center gap-2 rounded-og-sm px-1.5 py-1.5 text-left text-og-base",
|
|
855
|
+
"text-og-fg-muted transition-colors duration-150",
|
|
856
|
+
// A tool row is a touch target on coarse pointers: grow its padding so the
|
|
857
|
+
// hit area clears the 40px minimum without loosening the dense desktop rail.
|
|
858
|
+
"pointer-coarse:py-2.5"
|
|
859
|
+
);
|
|
860
|
+
const inner = /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
861
|
+
hasBody ? /* @__PURE__ */ jsx5(ChevronRightIcon, { className: "size-3.5 shrink-0 text-og-fg-subtle transition-transform duration-150 ease-og-in-out group-data-[state=open]/disclosure:rotate-90" }) : /* @__PURE__ */ jsx5("span", { className: "size-3.5 shrink-0" }),
|
|
862
|
+
/* @__PURE__ */ jsx5("span", { className: cn("shrink-0", ICON_TONE[iconTone]), children: icon }),
|
|
863
|
+
/* @__PURE__ */ jsx5(
|
|
864
|
+
"span",
|
|
865
|
+
{
|
|
866
|
+
className: cn(
|
|
867
|
+
"min-w-0 shrink truncate text-og-base font-medium",
|
|
868
|
+
titleMono && "font-og-mono text-og-sm font-normal",
|
|
869
|
+
running && "og-shimmer-text"
|
|
870
|
+
),
|
|
871
|
+
children: title
|
|
872
|
+
}
|
|
873
|
+
),
|
|
874
|
+
previewVisible && !media ? /* @__PURE__ */ jsx5("span", { className: "min-w-0 flex-1 truncate text-og-sm text-og-fg-subtle", children: preview }) : /* @__PURE__ */ jsx5("span", { className: "flex-1" }),
|
|
875
|
+
media ? /* @__PURE__ */ jsx5("span", { className: "ml-auto flex shrink-0 items-center gap-2 pl-2", children: media }) : chip && !open ? /* @__PURE__ */ jsx5("span", { className: "ml-auto shrink-0 pl-2", children: /* @__PURE__ */ jsx5(Chip, { chip }) }) : null
|
|
876
|
+
] });
|
|
877
|
+
const dataStatus = cancelled ? "cancelled" : failed ? "failed" : void 0;
|
|
878
|
+
if (!hasBody) {
|
|
879
|
+
return /* @__PURE__ */ jsx5("div", { className: cn(rowClass, "cursor-default"), "data-status": dataStatus, children: inner });
|
|
880
|
+
}
|
|
881
|
+
return /* @__PURE__ */ jsxs4(Collapsible.Root, { open, onOpenChange: setOpen, children: [
|
|
882
|
+
/* @__PURE__ */ jsx5(Collapsible.Trigger, { asChild: true, children: /* @__PURE__ */ jsx5(
|
|
883
|
+
"div",
|
|
884
|
+
{
|
|
885
|
+
role: "button",
|
|
886
|
+
tabIndex: 0,
|
|
887
|
+
onKeyDown: (event) => {
|
|
888
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
889
|
+
event.preventDefault();
|
|
890
|
+
setOpen((prev) => !prev);
|
|
891
|
+
}
|
|
892
|
+
},
|
|
893
|
+
"data-status": dataStatus,
|
|
894
|
+
className: cn(
|
|
895
|
+
rowClass,
|
|
896
|
+
"cursor-pointer outline-none hover:bg-og-surface-1 hover:text-og-fg",
|
|
897
|
+
"focus-visible:ring-2 focus-visible:ring-og-accent focus-visible:ring-offset-0"
|
|
898
|
+
),
|
|
899
|
+
children: inner
|
|
900
|
+
}
|
|
901
|
+
) }),
|
|
902
|
+
/* @__PURE__ */ jsx5(Collapsible.Content, { className: "overflow-hidden data-[state=closed]:animate-og-collapse data-[state=open]:animate-og-expand", children: /* @__PURE__ */ jsx5("div", { className: "mb-2 ml-7 mt-1.5 flex flex-col gap-2", children }) })
|
|
903
|
+
] });
|
|
904
|
+
}
|
|
905
|
+
function Chip({ chip }) {
|
|
906
|
+
const base = "inline-flex items-center font-og-mono text-og-xs leading-none";
|
|
907
|
+
const withText = chip.text ? "gap-1.5" : "gap-0";
|
|
908
|
+
if (chip.tone === "bad") {
|
|
909
|
+
return /* @__PURE__ */ jsxs4("span", { className: cn(base, withText, "text-og-status-failed"), children: [
|
|
910
|
+
/* @__PURE__ */ jsx5("span", { className: "size-1.5 rounded-full bg-og-status-failed" }),
|
|
911
|
+
chip.text
|
|
912
|
+
] });
|
|
913
|
+
}
|
|
914
|
+
if (chip.tone === "interrupted") {
|
|
915
|
+
return /* @__PURE__ */ jsx5("span", { className: cn(base, "text-og-fg-subtle og-cancelled-chip"), children: chip.text });
|
|
916
|
+
}
|
|
917
|
+
return /* @__PURE__ */ jsx5("span", { className: cn(base, "text-og-fg-subtle"), children: chip.text });
|
|
918
|
+
}
|
|
919
|
+
function TermBlock({
|
|
920
|
+
command,
|
|
921
|
+
workdir,
|
|
922
|
+
output,
|
|
923
|
+
live,
|
|
924
|
+
tailLines = 12,
|
|
925
|
+
failed
|
|
926
|
+
}) {
|
|
927
|
+
const [full, setFull] = useState3(false);
|
|
928
|
+
const empty = output.trim() === "";
|
|
929
|
+
const lines = output.split("\n");
|
|
930
|
+
const big = lines.length > tailLines + 4;
|
|
931
|
+
const shown = full || !big ? output : lines.slice(-tailLines).join("\n");
|
|
932
|
+
const showMore = big && !full;
|
|
933
|
+
const showHeader = command != null || workdir != null;
|
|
934
|
+
return /* @__PURE__ */ jsxs4(
|
|
935
|
+
"div",
|
|
936
|
+
{
|
|
937
|
+
className: cn(
|
|
938
|
+
"min-w-0 border-l-2 pl-3",
|
|
939
|
+
failed ? "border-og-status-failed/50" : live ? "border-og-status-running/50" : "border-og-border"
|
|
940
|
+
),
|
|
941
|
+
children: [
|
|
942
|
+
showHeader ? /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 pb-1", children: [
|
|
943
|
+
/* @__PURE__ */ jsx5("span", { className: "select-none text-og-status-idle", children: "$" }),
|
|
944
|
+
command != null ? /* @__PURE__ */ jsx5("span", { className: "min-w-0 flex-1 truncate font-og-mono text-og-sm text-og-fg-muted", children: command }) : /* @__PURE__ */ jsx5("span", { className: "flex-1" }),
|
|
945
|
+
workdir ? /* @__PURE__ */ jsx5("span", { className: "shrink-0 font-og-mono text-og-xs text-og-fg-subtle", children: workdir }) : null
|
|
946
|
+
] }) : null,
|
|
947
|
+
empty ? /* @__PURE__ */ jsx5("p", { className: "font-og-mono text-og-xs italic text-og-fg-subtle", children: "(no output)" }) : /* @__PURE__ */ jsxs4("pre", { className: "max-h-72 overflow-auto whitespace-pre-wrap break-all font-og-mono text-og-xs leading-5 text-og-fg-muted", children: [
|
|
948
|
+
shown,
|
|
949
|
+
live ? /* @__PURE__ */ jsx5("span", { className: "ml-px inline-block h-[1em] w-[2px] translate-y-[2px] animate-og-blink bg-og-accent align-middle" }) : null
|
|
950
|
+
] }),
|
|
951
|
+
showMore ? /* @__PURE__ */ jsxs4(
|
|
952
|
+
"button",
|
|
953
|
+
{
|
|
954
|
+
type: "button",
|
|
955
|
+
onClick: () => setFull(true),
|
|
956
|
+
className: "mt-1 text-left text-og-xs text-og-fg-subtle transition-colors hover:text-og-fg",
|
|
957
|
+
children: [
|
|
958
|
+
"show full output (",
|
|
959
|
+
lines.length,
|
|
960
|
+
" lines)"
|
|
961
|
+
]
|
|
962
|
+
}
|
|
963
|
+
) : null
|
|
964
|
+
]
|
|
965
|
+
}
|
|
966
|
+
);
|
|
967
|
+
}
|
|
968
|
+
function PayloadBlock({
|
|
969
|
+
label,
|
|
970
|
+
value,
|
|
971
|
+
failed
|
|
972
|
+
}) {
|
|
973
|
+
const text = typeof value === "string" ? value : stringifyPayload(value);
|
|
974
|
+
if (!text || text.trim() === "") {
|
|
975
|
+
return null;
|
|
976
|
+
}
|
|
977
|
+
return /* @__PURE__ */ jsxs4(
|
|
978
|
+
"div",
|
|
979
|
+
{
|
|
980
|
+
className: cn(
|
|
981
|
+
"min-w-0 border-l-2 pl-3",
|
|
982
|
+
failed ? "border-og-status-failed/50" : "border-og-border"
|
|
983
|
+
),
|
|
984
|
+
children: [
|
|
985
|
+
/* @__PURE__ */ jsx5("p", { className: "mb-1 text-og-xs font-medium uppercase tracking-[0.08em] text-og-fg-subtle", children: label }),
|
|
986
|
+
/* @__PURE__ */ jsx5(
|
|
987
|
+
"pre",
|
|
988
|
+
{
|
|
989
|
+
className: cn(
|
|
990
|
+
"max-h-64 overflow-auto whitespace-pre-wrap break-all font-og-mono text-og-xs leading-5",
|
|
991
|
+
failed ? "text-og-status-failed" : "text-og-fg-muted"
|
|
992
|
+
),
|
|
993
|
+
children: text
|
|
994
|
+
}
|
|
995
|
+
)
|
|
996
|
+
]
|
|
997
|
+
}
|
|
998
|
+
);
|
|
999
|
+
}
|
|
1000
|
+
function BodyNote({
|
|
1001
|
+
children,
|
|
1002
|
+
tone
|
|
1003
|
+
}) {
|
|
1004
|
+
if (tone === "error") {
|
|
1005
|
+
return /* @__PURE__ */ jsx5("div", { className: "border-l-2 border-og-status-failed/50 pl-3 font-og-mono text-og-xs leading-5 text-og-status-failed", children });
|
|
1006
|
+
}
|
|
1007
|
+
return /* @__PURE__ */ jsx5("p", { className: "px-0.5 text-og-sm italic leading-5 text-og-fg-subtle", children });
|
|
1008
|
+
}
|
|
1009
|
+
var MEDIA_BOX = "h-7 w-[52px] shrink-0 rounded-og-xs border border-og-border";
|
|
1010
|
+
function MediaSkeleton() {
|
|
1011
|
+
return /* @__PURE__ */ jsxs4(
|
|
1012
|
+
"span",
|
|
1013
|
+
{
|
|
1014
|
+
className: cn(
|
|
1015
|
+
MEDIA_BOX,
|
|
1016
|
+
"relative inline-flex items-center justify-center overflow-hidden bg-og-surface-2"
|
|
1017
|
+
),
|
|
1018
|
+
children: [
|
|
1019
|
+
/* @__PURE__ */ jsx5("span", { className: "absolute inset-0 animate-og-pulse bg-og-surface-3/50" }),
|
|
1020
|
+
/* @__PURE__ */ jsx5(CameraIcon, { className: "relative size-3.5 text-og-fg-subtle" })
|
|
1021
|
+
]
|
|
1022
|
+
}
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
function MediaEmpty() {
|
|
1026
|
+
return /* @__PURE__ */ jsx5("span", { className: cn(MEDIA_BOX, "inline-flex items-center justify-center bg-og-bg"), children: /* @__PURE__ */ jsx5(CameraOffIcon, { className: "size-3.5 text-og-fg-subtle" }) });
|
|
1027
|
+
}
|
|
1028
|
+
function Thumbnail({
|
|
1029
|
+
src,
|
|
1030
|
+
caption,
|
|
1031
|
+
alt = "screenshot"
|
|
1032
|
+
}) {
|
|
1033
|
+
const lightbox = useLightboxOptional();
|
|
1034
|
+
const [failed, setFailed] = useState3(false);
|
|
1035
|
+
if (failed) {
|
|
1036
|
+
return /* @__PURE__ */ jsx5(MediaEmpty, {});
|
|
1037
|
+
}
|
|
1038
|
+
const img = /* @__PURE__ */ jsx5(
|
|
1039
|
+
"img",
|
|
1040
|
+
{
|
|
1041
|
+
src,
|
|
1042
|
+
alt,
|
|
1043
|
+
onError: () => setFailed(true),
|
|
1044
|
+
className: "h-full w-full object-cover transition-opacity group-hover/thumb:opacity-80"
|
|
1045
|
+
}
|
|
1046
|
+
);
|
|
1047
|
+
if (!lightbox) {
|
|
1048
|
+
return /* @__PURE__ */ jsx5("span", { className: cn(MEDIA_BOX, "inline-flex overflow-hidden bg-og-bg"), children: img });
|
|
1049
|
+
}
|
|
1050
|
+
return /* @__PURE__ */ jsx5(
|
|
1051
|
+
"button",
|
|
1052
|
+
{
|
|
1053
|
+
type: "button",
|
|
1054
|
+
onClick: (event) => {
|
|
1055
|
+
event.stopPropagation();
|
|
1056
|
+
lightbox.open(src, caption);
|
|
1057
|
+
},
|
|
1058
|
+
onKeyDown: (event) => {
|
|
1059
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
1060
|
+
event.stopPropagation();
|
|
1061
|
+
}
|
|
1062
|
+
},
|
|
1063
|
+
className: cn(
|
|
1064
|
+
MEDIA_BOX,
|
|
1065
|
+
"group/thumb relative inline-flex overflow-hidden bg-og-bg outline-none",
|
|
1066
|
+
"focus-visible:ring-2 focus-visible:ring-og-accent"
|
|
1067
|
+
),
|
|
1068
|
+
"aria-label": "Expand screenshot",
|
|
1069
|
+
children: img
|
|
1070
|
+
}
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
function ScreenshotFigure({
|
|
1074
|
+
src,
|
|
1075
|
+
caption,
|
|
1076
|
+
alt = "screenshot"
|
|
1077
|
+
}) {
|
|
1078
|
+
const lightbox = useLightboxOptional();
|
|
1079
|
+
const [failed, setFailed] = useState3(false);
|
|
1080
|
+
const surface = "block w-full overflow-hidden rounded-og-md border border-og-border bg-og-bg";
|
|
1081
|
+
const img = /* @__PURE__ */ jsx5(
|
|
1082
|
+
"img",
|
|
1083
|
+
{
|
|
1084
|
+
src,
|
|
1085
|
+
alt,
|
|
1086
|
+
onError: () => setFailed(true),
|
|
1087
|
+
className: "max-h-80 w-full object-contain"
|
|
1088
|
+
}
|
|
1089
|
+
);
|
|
1090
|
+
return /* @__PURE__ */ jsxs4("figure", { className: "m-0 min-w-0", children: [
|
|
1091
|
+
failed ? /* @__PURE__ */ jsx5("div", { className: "rounded-og-md border border-og-border bg-og-bg px-3 py-6 text-center font-og-mono text-og-xs text-og-fg-subtle", children: "image unavailable" }) : lightbox ? /* @__PURE__ */ jsx5(
|
|
1092
|
+
"button",
|
|
1093
|
+
{
|
|
1094
|
+
type: "button",
|
|
1095
|
+
onClick: () => lightbox.open(src, caption),
|
|
1096
|
+
className: surface,
|
|
1097
|
+
"aria-label": "Expand screenshot",
|
|
1098
|
+
children: img
|
|
1099
|
+
}
|
|
1100
|
+
) : /* @__PURE__ */ jsx5("div", { className: surface, children: img }),
|
|
1101
|
+
caption ? /* @__PURE__ */ jsx5("figcaption", { className: "mt-1.5 font-og-mono text-og-xs text-og-fg-subtle", children: caption }) : null
|
|
1102
|
+
] });
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
// src/lib/git-patch.ts
|
|
1106
|
+
function gitFileDiffToPatch(file) {
|
|
1107
|
+
const oldPath = file.oldPath ?? file.path;
|
|
1108
|
+
const newPath = file.path;
|
|
1109
|
+
const lines = [];
|
|
1110
|
+
lines.push(`diff --git a/${oldPath} b/${newPath}`);
|
|
1111
|
+
if (file.status === "deleted") {
|
|
1112
|
+
lines.push(`--- a/${oldPath}`);
|
|
1113
|
+
lines.push(`+++ /dev/null`);
|
|
1114
|
+
} else if (file.status === "added" || file.status === "untracked") {
|
|
1115
|
+
lines.push(`--- /dev/null`);
|
|
1116
|
+
lines.push(`+++ b/${newPath}`);
|
|
1117
|
+
} else {
|
|
1118
|
+
lines.push(`--- a/${oldPath}`);
|
|
1119
|
+
lines.push(`+++ b/${newPath}`);
|
|
1120
|
+
}
|
|
1121
|
+
for (const hunk of file.hunks) {
|
|
1122
|
+
const headerIsValid = /^@@ -\d+(?:,\d+)? \+\d+(?:,\d+)? @@/.test(hunk.header ?? "");
|
|
1123
|
+
const header = headerIsValid ? hunk.header : `@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@`;
|
|
1124
|
+
lines.push(header);
|
|
1125
|
+
for (const line of hunk.lines) {
|
|
1126
|
+
if (line.type === "meta") continue;
|
|
1127
|
+
const prefix = line.type === "add" ? "+" : line.type === "del" ? "-" : " ";
|
|
1128
|
+
lines.push(`${prefix}${line.text}`);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
return lines.join("\n") + "\n";
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
// src/components/pierre-diff.tsx
|
|
1135
|
+
import {
|
|
1136
|
+
lazy as lazy2,
|
|
1137
|
+
Suspense as Suspense2,
|
|
1138
|
+
useEffect as useEffect2,
|
|
1139
|
+
useState as useState4
|
|
1140
|
+
} from "react";
|
|
1141
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1142
|
+
var LazyPatchDiff = lazy2(async () => {
|
|
1143
|
+
const mod = await import("@pierre/diffs/react");
|
|
1144
|
+
return { default: mod.PatchDiff };
|
|
1145
|
+
});
|
|
1146
|
+
function PierreDiff({
|
|
1147
|
+
diff,
|
|
1148
|
+
layout = "unified",
|
|
1149
|
+
themeType,
|
|
1150
|
+
theme,
|
|
1151
|
+
disableWorkerPool,
|
|
1152
|
+
loading,
|
|
1153
|
+
fallback,
|
|
1154
|
+
plain,
|
|
1155
|
+
overflow = "wrap",
|
|
1156
|
+
className
|
|
1157
|
+
}) {
|
|
1158
|
+
const [failed, setFailed] = useState4(false);
|
|
1159
|
+
const [forcedColors, setForcedColors] = useState4(false);
|
|
1160
|
+
useEffect2(() => {
|
|
1161
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
1162
|
+
const query = window.matchMedia("(forced-colors: active)");
|
|
1163
|
+
const update = () => setForcedColors(query.matches);
|
|
1164
|
+
update();
|
|
1165
|
+
query.addEventListener?.("change", update);
|
|
1166
|
+
return () => query.removeEventListener?.("change", update);
|
|
1167
|
+
}, []);
|
|
1168
|
+
useEffect2(() => {
|
|
1169
|
+
if (plain) return;
|
|
1170
|
+
let cancelled = false;
|
|
1171
|
+
void import("@pierre/diffs/react").catch(() => {
|
|
1172
|
+
if (!cancelled) setFailed(true);
|
|
1173
|
+
});
|
|
1174
|
+
return () => {
|
|
1175
|
+
cancelled = true;
|
|
1176
|
+
};
|
|
1177
|
+
}, [plain]);
|
|
1178
|
+
if (plain || failed || forcedColors) {
|
|
1179
|
+
return /* @__PURE__ */ jsx6(
|
|
1180
|
+
"div",
|
|
1181
|
+
{
|
|
1182
|
+
className,
|
|
1183
|
+
"data-opengeni-plain-diff": forcedColors ? "forced-colors" : "fallback",
|
|
1184
|
+
children: fallback ?? /* @__PURE__ */ jsx6(PlainPatch, { diff })
|
|
1185
|
+
}
|
|
1186
|
+
);
|
|
1187
|
+
}
|
|
1188
|
+
const options = {
|
|
1189
|
+
diffStyle: layout,
|
|
1190
|
+
overflow,
|
|
1191
|
+
stickyHeader: true,
|
|
1192
|
+
...theme ? { theme } : {
|
|
1193
|
+
theme: {
|
|
1194
|
+
dark: "github-dark-high-contrast",
|
|
1195
|
+
light: "github-light-high-contrast"
|
|
1196
|
+
}
|
|
1197
|
+
},
|
|
1198
|
+
themeType: themeType ?? "dark"
|
|
1199
|
+
};
|
|
1200
|
+
const pierreVars = {
|
|
1201
|
+
"--diffs-dark-bg": "var(--og-color-bg)",
|
|
1202
|
+
"--diffs-light-bg": "var(--og-color-bg)",
|
|
1203
|
+
"--diffs-bg-buffer-override": "var(--og-color-surface-1)",
|
|
1204
|
+
"--diffs-bg-separator-override": "var(--og-color-surface-1)",
|
|
1205
|
+
"--diffs-addition-color-override": "var(--og-color-status-idle)",
|
|
1206
|
+
"--diffs-deletion-color-override": "var(--og-color-status-failed)",
|
|
1207
|
+
"--diffs-fg-number-addition-override": "var(--og-color-status-idle)",
|
|
1208
|
+
"--diffs-fg-number-deletion-override": "var(--og-color-status-failed)",
|
|
1209
|
+
"--diffs-bg-addition-override": "color-mix(in oklab, var(--og-color-status-idle) 12%, var(--og-color-bg))",
|
|
1210
|
+
"--diffs-bg-deletion-override": "color-mix(in oklab, var(--og-color-status-failed) 12%, var(--og-color-bg))",
|
|
1211
|
+
"--diffs-bg-addition-emphasis-override": "color-mix(in oklab, var(--og-color-status-idle) 22%, var(--og-color-bg))",
|
|
1212
|
+
"--diffs-bg-deletion-emphasis-override": "color-mix(in oklab, var(--og-color-status-failed) 22%, var(--og-color-bg))",
|
|
1213
|
+
"--diffs-header-font-family": "var(--og-font-sans)",
|
|
1214
|
+
"--diffs-font-family": "var(--og-font-mono)",
|
|
1215
|
+
"--diffs-font-size": "var(--og-code-font-size)",
|
|
1216
|
+
"--diffs-line-height": "var(--og-code-line-height)"
|
|
1217
|
+
};
|
|
1218
|
+
return /* @__PURE__ */ jsx6("div", { className: cn("min-w-0", className), "data-opengeni-pierre-diff": true, style: pierreVars, children: /* @__PURE__ */ jsx6(Suspense2, { fallback: loading ?? /* @__PURE__ */ jsx6(DiffSkeleton, {}), children: diff.map((file) => /* @__PURE__ */ jsx6("div", { className: "mb-2", children: /* @__PURE__ */ jsx6(
|
|
1219
|
+
LazyPatchDiff,
|
|
1220
|
+
{
|
|
1221
|
+
patch: gitFileDiffToPatch(file),
|
|
1222
|
+
options,
|
|
1223
|
+
...disableWorkerPool !== void 0 ? { disableWorkerPool } : {}
|
|
1224
|
+
}
|
|
1225
|
+
) }, file.path)) }) });
|
|
1226
|
+
}
|
|
1227
|
+
function DiffSkeleton() {
|
|
1228
|
+
return /* @__PURE__ */ jsx6("div", { className: "p-3 text-og-sm text-og-fg-subtle", children: "Loading diff\u2026" });
|
|
1229
|
+
}
|
|
1230
|
+
function PlainPatch({ diff }) {
|
|
1231
|
+
if (diff.length === 0) {
|
|
1232
|
+
return /* @__PURE__ */ jsx6("div", { className: "p-3 text-og-sm text-og-fg-subtle", children: "No changes" });
|
|
1233
|
+
}
|
|
1234
|
+
return /* @__PURE__ */ jsx6("div", { className: "min-w-0", children: diff.map((file) => /* @__PURE__ */ jsx6(
|
|
1235
|
+
"pre",
|
|
1236
|
+
{
|
|
1237
|
+
"aria-label": `Diff for ${file.path}`,
|
|
1238
|
+
className: "mb-2 overflow-auto whitespace-pre rounded-og-sm border border-og-border bg-og-bg/60 p-2.5 font-og-mono text-og-xs leading-5",
|
|
1239
|
+
role: "region",
|
|
1240
|
+
tabIndex: 0,
|
|
1241
|
+
children: gitFileDiffToPatch(file).split("\n").map((line, index) => /* @__PURE__ */ jsx6(
|
|
1242
|
+
"span",
|
|
1243
|
+
{
|
|
1244
|
+
className: cn(
|
|
1245
|
+
"block",
|
|
1246
|
+
line.startsWith("@@") ? "text-og-accent" : line.startsWith("+") ? "text-og-status-idle" : line.startsWith("-") ? "text-og-status-failed" : "text-og-fg-muted"
|
|
1247
|
+
),
|
|
1248
|
+
children: line || " "
|
|
1249
|
+
},
|
|
1250
|
+
index
|
|
1251
|
+
))
|
|
1252
|
+
},
|
|
1253
|
+
file.path
|
|
1254
|
+
)) });
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
// src/timeline/tool-renderers.tsx
|
|
1258
|
+
import {
|
|
1259
|
+
CameraIcon as CameraIcon2,
|
|
1260
|
+
CameraOffIcon as CameraOffIcon2,
|
|
1261
|
+
FileDiffIcon,
|
|
1262
|
+
GlobeIcon,
|
|
1263
|
+
ImageIcon,
|
|
1264
|
+
KeyboardIcon,
|
|
1265
|
+
KeyRoundIcon,
|
|
1266
|
+
LockIcon,
|
|
1267
|
+
MousePointer2Icon,
|
|
1268
|
+
PlugIcon,
|
|
1269
|
+
SearchIcon,
|
|
1270
|
+
TerminalIcon,
|
|
1271
|
+
WrenchIcon
|
|
1272
|
+
} from "lucide-react";
|
|
1273
|
+
|
|
1274
|
+
// src/timeline/tool-diff.tsx
|
|
1275
|
+
import { useState as useState6 } from "react";
|
|
1276
|
+
|
|
1277
|
+
// src/lib/use-theme-type.ts
|
|
1278
|
+
import { useEffect as useEffect3, useState as useState5 } from "react";
|
|
1279
|
+
function useThemeType(forced) {
|
|
1280
|
+
const [detected, setDetected] = useState5("dark");
|
|
1281
|
+
useEffect3(() => {
|
|
1282
|
+
if (forced || typeof document === "undefined") return;
|
|
1283
|
+
const read = () => {
|
|
1284
|
+
const el = document.querySelector("[data-og-theme]");
|
|
1285
|
+
const value = el?.getAttribute("data-og-theme");
|
|
1286
|
+
setDetected(value === "light" ? "light" : "dark");
|
|
1287
|
+
};
|
|
1288
|
+
read();
|
|
1289
|
+
const observer = new MutationObserver(read);
|
|
1290
|
+
observer.observe(document.documentElement, {
|
|
1291
|
+
attributes: true,
|
|
1292
|
+
attributeFilter: ["data-og-theme"],
|
|
1293
|
+
subtree: true
|
|
1294
|
+
});
|
|
1295
|
+
return () => observer.disconnect();
|
|
1296
|
+
}, [forced]);
|
|
1297
|
+
return forced ?? detected;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// src/timeline/tool-diff.tsx
|
|
1301
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1302
|
+
function ToolDiff({ files }) {
|
|
1303
|
+
const [layout, setLayout] = useState6("unified");
|
|
1304
|
+
const themeType = useThemeType(void 0);
|
|
1305
|
+
return /* @__PURE__ */ jsxs5("div", { className: "min-w-0", children: [
|
|
1306
|
+
/* @__PURE__ */ jsx7("div", { className: "mb-1.5 flex justify-end", children: /* @__PURE__ */ jsx7(LayoutToggle, { layout, onChange: setLayout }) }),
|
|
1307
|
+
/* @__PURE__ */ jsx7(PierreDiff, { diff: files, layout, themeType })
|
|
1308
|
+
] });
|
|
1309
|
+
}
|
|
1310
|
+
function LayoutToggle({
|
|
1311
|
+
layout,
|
|
1312
|
+
onChange
|
|
1313
|
+
}) {
|
|
1314
|
+
return /* @__PURE__ */ jsx7("div", { className: "inline-flex items-center gap-px rounded-og-xs border border-og-border p-px", children: ["unified", "split"].map((value) => /* @__PURE__ */ jsx7(
|
|
1315
|
+
"button",
|
|
1316
|
+
{
|
|
1317
|
+
type: "button",
|
|
1318
|
+
onClick: () => onChange(value),
|
|
1319
|
+
className: cn(
|
|
1320
|
+
"rounded-og-xs px-2 py-[3px] text-og-xs font-medium capitalize transition-colors",
|
|
1321
|
+
layout === value ? "bg-og-surface-2 text-og-fg" : "text-og-fg-subtle hover:text-og-fg-muted"
|
|
1322
|
+
),
|
|
1323
|
+
children: value
|
|
1324
|
+
},
|
|
1325
|
+
value
|
|
1326
|
+
)) });
|
|
1327
|
+
}
|
|
1328
|
+
function RawPatch({ diff }) {
|
|
1329
|
+
const occurrences = /* @__PURE__ */ new Map();
|
|
1330
|
+
const lines = diff.split("\n").map((line) => {
|
|
1331
|
+
const occurrence = (occurrences.get(line) ?? 0) + 1;
|
|
1332
|
+
occurrences.set(line, occurrence);
|
|
1333
|
+
return { key: `${line}\0${occurrence}`, line };
|
|
1334
|
+
});
|
|
1335
|
+
return /* @__PURE__ */ jsxs5("div", { className: "min-w-0", children: [
|
|
1336
|
+
/* @__PURE__ */ jsx7("p", { className: "mb-1 text-og-xs font-medium uppercase tracking-[0.08em] text-og-fg-subtle", children: "raw patch (could not parse hunks)" }),
|
|
1337
|
+
/* @__PURE__ */ jsx7("pre", { className: "max-h-72 overflow-auto border-l-2 border-og-border pl-3 font-og-mono text-og-xs leading-5", children: lines.map(({ key, line }) => /* @__PURE__ */ jsx7(
|
|
1338
|
+
"span",
|
|
1339
|
+
{
|
|
1340
|
+
className: cn(
|
|
1341
|
+
"block",
|
|
1342
|
+
line.startsWith("@@") ? "text-og-accent" : line.startsWith("+") ? "text-og-status-idle" : line.startsWith("-") ? "text-og-status-failed" : "text-og-fg-muted"
|
|
1343
|
+
),
|
|
1344
|
+
children: line || " "
|
|
1345
|
+
},
|
|
1346
|
+
key
|
|
1347
|
+
)) })
|
|
1348
|
+
] });
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
// src/timeline/tool-display-name.ts
|
|
1352
|
+
function toolDisplayName(name) {
|
|
1353
|
+
const boundary = name.indexOf("__");
|
|
1354
|
+
const toolPart = boundary >= 0 ? name.slice(boundary + 2) : name;
|
|
1355
|
+
return toolPart.replace(/[_-]+/g, " ").trim();
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
// src/timeline/tool-renderers.tsx
|
|
1359
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1360
|
+
var ICON_SIZE = "size-3.5";
|
|
1361
|
+
function RunningPreview({ children }) {
|
|
1362
|
+
return /* @__PURE__ */ jsxs6("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
1363
|
+
/* @__PURE__ */ jsx8("span", { className: "size-1.5 shrink-0 animate-og-pulse rounded-full bg-og-status-running" }),
|
|
1364
|
+
/* @__PURE__ */ jsx8("span", { className: "min-w-0 truncate", children })
|
|
1365
|
+
] });
|
|
1366
|
+
}
|
|
1367
|
+
function ExecRenderer({ item }) {
|
|
1368
|
+
const args = parseToolArgs(item.arguments);
|
|
1369
|
+
const cmd = typeof args.cmd === "string" ? args.cmd : "";
|
|
1370
|
+
const workdir = typeof args.workdir === "string" ? args.workdir : null;
|
|
1371
|
+
const running = item.status === "running";
|
|
1372
|
+
const out = item.output;
|
|
1373
|
+
const title = `$ ${cmd}`;
|
|
1374
|
+
if (item.status === "failed" && out === void 0) {
|
|
1375
|
+
return /* @__PURE__ */ jsx8(
|
|
1376
|
+
ActivityDisclosure,
|
|
1377
|
+
{
|
|
1378
|
+
icon: /* @__PURE__ */ jsx8(TerminalIcon, { className: ICON_SIZE }),
|
|
1379
|
+
iconTone: "failed",
|
|
1380
|
+
title,
|
|
1381
|
+
titleMono: true,
|
|
1382
|
+
chip: { tone: "bad", text: "failed" },
|
|
1383
|
+
preview: "output lost \u2014 NUL byte could not be stored",
|
|
1384
|
+
children: /* @__PURE__ */ jsx8(BodyNote, { tone: "error", children: "output contained a NUL byte and could not be stored; the turn failed on this tool's output insert \u2014 no output event ever arrived." })
|
|
1385
|
+
}
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
if (item.status === "failed" && (out == null || out === "")) {
|
|
1389
|
+
return /* @__PURE__ */ jsx8(
|
|
1390
|
+
ActivityDisclosure,
|
|
1391
|
+
{
|
|
1392
|
+
icon: /* @__PURE__ */ jsx8(TerminalIcon, { className: ICON_SIZE }),
|
|
1393
|
+
iconTone: "failed",
|
|
1394
|
+
title,
|
|
1395
|
+
titleMono: true,
|
|
1396
|
+
chip: { tone: "bad", text: "failed" },
|
|
1397
|
+
preview: "tool call failed",
|
|
1398
|
+
children: /* @__PURE__ */ jsx8(BodyNote, { tone: "error", children: "the tool call failed with no output." })
|
|
1399
|
+
}
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1402
|
+
if (running) {
|
|
1403
|
+
const streamed = typeof out === "string" ? stripExecBanner(out) : "";
|
|
1404
|
+
return /* @__PURE__ */ jsx8(
|
|
1405
|
+
ActivityDisclosure,
|
|
1406
|
+
{
|
|
1407
|
+
icon: /* @__PURE__ */ jsx8(TerminalIcon, { className: ICON_SIZE }),
|
|
1408
|
+
iconTone: "running",
|
|
1409
|
+
title,
|
|
1410
|
+
titleMono: true,
|
|
1411
|
+
running: true,
|
|
1412
|
+
preview: /* @__PURE__ */ jsx8(RunningPreview, { children: streamed ? `${streamed.split("\n").length} lines` : "running\u2026" }),
|
|
1413
|
+
children: /* @__PURE__ */ jsx8(TermBlock, { command: null, workdir, output: streamed, live: true })
|
|
1414
|
+
}
|
|
1415
|
+
);
|
|
1416
|
+
}
|
|
1417
|
+
const text = typeof out === "string" ? out : stringifyPayload(out);
|
|
1418
|
+
const stripped = stripExecBanner(text);
|
|
1419
|
+
const bgSession = parseExecBannerSessionId(text);
|
|
1420
|
+
const exitCode = sandboxCommandExitCode(text);
|
|
1421
|
+
const binary = looksBinary(stripped);
|
|
1422
|
+
let chip;
|
|
1423
|
+
let iconTone = "muted";
|
|
1424
|
+
if (bgSession != null) {
|
|
1425
|
+
chip = { tone: "muted", text: `session ${bgSession}` };
|
|
1426
|
+
} else if (exitCode != null && exitCode !== 0) {
|
|
1427
|
+
chip = { tone: "bad", text: `exit ${exitCode}` };
|
|
1428
|
+
iconTone = "failed";
|
|
1429
|
+
}
|
|
1430
|
+
const preview = binary ? "binary output" : tailPeek(stripped) || "(no output)";
|
|
1431
|
+
const truncated = execTruncated(text);
|
|
1432
|
+
const body = binary ? "(binary output suppressed)" : stripped;
|
|
1433
|
+
return /* @__PURE__ */ jsxs6(
|
|
1434
|
+
ActivityDisclosure,
|
|
1435
|
+
{
|
|
1436
|
+
icon: /* @__PURE__ */ jsx8(TerminalIcon, { className: ICON_SIZE }),
|
|
1437
|
+
iconTone,
|
|
1438
|
+
title,
|
|
1439
|
+
titleMono: true,
|
|
1440
|
+
...chip ? { chip } : {},
|
|
1441
|
+
failed: item.status === "failed",
|
|
1442
|
+
cancelled: item.status === "cancelled",
|
|
1443
|
+
preview: truncated ? `\u22EF truncated \xB7 ${preview}` : preview,
|
|
1444
|
+
children: [
|
|
1445
|
+
/* @__PURE__ */ jsx8(
|
|
1446
|
+
TermBlock,
|
|
1447
|
+
{
|
|
1448
|
+
command: null,
|
|
1449
|
+
workdir,
|
|
1450
|
+
output: body,
|
|
1451
|
+
failed: item.status === "failed" || exitCode != null && exitCode !== 0
|
|
1452
|
+
}
|
|
1453
|
+
),
|
|
1454
|
+
bgSession != null ? /* @__PURE__ */ jsxs6(BodyNote, { children: [
|
|
1455
|
+
"\u21B3 session ",
|
|
1456
|
+
bgSession,
|
|
1457
|
+
" \u2014 a later write_stdin can target this PTY."
|
|
1458
|
+
] }) : null
|
|
1459
|
+
]
|
|
1460
|
+
}
|
|
1461
|
+
);
|
|
1462
|
+
}
|
|
1463
|
+
function WriteStdinRenderer({ item }) {
|
|
1464
|
+
const args = parseToolArgs(item.arguments);
|
|
1465
|
+
const sessionId = typeof args.session_id === "string" || typeof args.session_id === "number" ? args.session_id : void 0;
|
|
1466
|
+
const running = item.status === "running";
|
|
1467
|
+
const text = typeof item.output === "string" ? item.output : stringifyPayload(item.output);
|
|
1468
|
+
const lost = isExecSessionLostBanner(text);
|
|
1469
|
+
const keys = controlCaret(typeof args.chars === "string" ? args.chars : "");
|
|
1470
|
+
const exitCode = sandboxCommandExitCode(text);
|
|
1471
|
+
const stripped = stripExecBanner(text);
|
|
1472
|
+
if (running) {
|
|
1473
|
+
return /* @__PURE__ */ jsx8(
|
|
1474
|
+
ActivityDisclosure,
|
|
1475
|
+
{
|
|
1476
|
+
icon: /* @__PURE__ */ jsx8(KeyboardIcon, { className: ICON_SIZE }),
|
|
1477
|
+
iconTone: "running",
|
|
1478
|
+
title: `session ${sessionId} \u2190 ${keys || "\u2205"}`,
|
|
1479
|
+
titleMono: true,
|
|
1480
|
+
running: true,
|
|
1481
|
+
preview: /* @__PURE__ */ jsx8(RunningPreview, { children: "sending\u2026" }),
|
|
1482
|
+
children: /* @__PURE__ */ jsxs6(BodyNote, { children: [
|
|
1483
|
+
"sending input to session ",
|
|
1484
|
+
sessionId,
|
|
1485
|
+
"\u2026"
|
|
1486
|
+
] })
|
|
1487
|
+
}
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1490
|
+
let chip;
|
|
1491
|
+
if (lost) {
|
|
1492
|
+
chip = { tone: "bad", text: "lost" };
|
|
1493
|
+
} else if (exitCode != null && exitCode !== 0) {
|
|
1494
|
+
chip = { tone: "bad", text: `exit ${exitCode}` };
|
|
1495
|
+
}
|
|
1496
|
+
return /* @__PURE__ */ jsx8(
|
|
1497
|
+
ActivityDisclosure,
|
|
1498
|
+
{
|
|
1499
|
+
icon: /* @__PURE__ */ jsx8(KeyboardIcon, { className: ICON_SIZE }),
|
|
1500
|
+
iconTone: lost ? "failed" : "muted",
|
|
1501
|
+
title: `session ${sessionId} \u2190 ${keys || "\u2205"}`,
|
|
1502
|
+
titleMono: true,
|
|
1503
|
+
...chip ? { chip } : {},
|
|
1504
|
+
failed: item.status === "failed",
|
|
1505
|
+
cancelled: item.status === "cancelled",
|
|
1506
|
+
preview: lost ? `session ${sessionId} PTY vanished` : tailPeek(stripped) || "sent",
|
|
1507
|
+
children: lost ? /* @__PURE__ */ jsx8(BodyNote, { tone: "error", children: stripped || text }) : /* @__PURE__ */ jsx8(TermBlock, { command: `write_stdin \u2192 session ${sessionId}`, output: stripped })
|
|
1508
|
+
}
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
function verbForOp(op) {
|
|
1512
|
+
if (!op) {
|
|
1513
|
+
return "Edited";
|
|
1514
|
+
}
|
|
1515
|
+
return op.type === "create_file" ? "Created" : op.type === "delete_file" ? "Deleted" : op.moveTo ? "Renamed" : "Edited";
|
|
1516
|
+
}
|
|
1517
|
+
function basename(path) {
|
|
1518
|
+
const parts = path.split("/").filter(Boolean);
|
|
1519
|
+
return parts.length ? parts[parts.length - 1] : path;
|
|
1520
|
+
}
|
|
1521
|
+
function dirname(path) {
|
|
1522
|
+
const idx = path.lastIndexOf("/");
|
|
1523
|
+
return idx >= 0 ? path.slice(0, idx + 1) : "";
|
|
1524
|
+
}
|
|
1525
|
+
function PathPreview({
|
|
1526
|
+
path,
|
|
1527
|
+
add,
|
|
1528
|
+
del
|
|
1529
|
+
}) {
|
|
1530
|
+
return /* @__PURE__ */ jsxs6("span", { className: "inline-flex items-center gap-2 truncate font-og-mono", children: [
|
|
1531
|
+
/* @__PURE__ */ jsxs6("span", { className: "truncate", children: [
|
|
1532
|
+
/* @__PURE__ */ jsx8("span", { className: "text-og-fg-subtle", children: dirname(path) }),
|
|
1533
|
+
/* @__PURE__ */ jsx8("span", { className: "text-og-fg-muted", children: basename(path) })
|
|
1534
|
+
] }),
|
|
1535
|
+
add != null || del != null ? /* @__PURE__ */ jsxs6("span", { className: "shrink-0 text-og-fg-subtle", children: [
|
|
1536
|
+
add != null ? `+${add}` : "",
|
|
1537
|
+
add != null && del != null ? " " : "",
|
|
1538
|
+
del != null ? `\u2212${del}` : ""
|
|
1539
|
+
] }) : null
|
|
1540
|
+
] });
|
|
1541
|
+
}
|
|
1542
|
+
function ApplyPatchRenderer({ item }) {
|
|
1543
|
+
const ops = applyPatchOps(item.raw);
|
|
1544
|
+
const failed = item.status === "failed";
|
|
1545
|
+
const cancelled = item.status === "cancelled";
|
|
1546
|
+
const running = item.status === "running";
|
|
1547
|
+
const firstOp = ops[0];
|
|
1548
|
+
if (running) {
|
|
1549
|
+
const fileCount = ops.length;
|
|
1550
|
+
const titleVerb = firstOp ? `Applying ${basename(firstOp.path)}` : "Applying patch";
|
|
1551
|
+
return /* @__PURE__ */ jsx8(
|
|
1552
|
+
ActivityDisclosure,
|
|
1553
|
+
{
|
|
1554
|
+
icon: /* @__PURE__ */ jsx8(FileDiffIcon, { className: ICON_SIZE }),
|
|
1555
|
+
iconTone: "running",
|
|
1556
|
+
title: fileCount > 1 ? `Applying ${fileCount} files` : titleVerb,
|
|
1557
|
+
running: true,
|
|
1558
|
+
preview: /* @__PURE__ */ jsx8(RunningPreview, { children: fileCount > 1 ? `${fileCount} files` : firstOp ? firstOp.path : "applying\u2026" }),
|
|
1559
|
+
children: ops.map((op) => {
|
|
1560
|
+
const file2 = safeParseOp(op);
|
|
1561
|
+
return file2 ? /* @__PURE__ */ jsx8(ToolDiff, { files: [file2] }, op.path) : /* @__PURE__ */ jsxs6("div", { children: [
|
|
1562
|
+
/* @__PURE__ */ jsx8("p", { className: "mb-1 font-og-mono text-og-xs text-og-fg-muted", children: op.path }),
|
|
1563
|
+
/* @__PURE__ */ jsx8(RawPatch, { diff: op.diff ?? "" })
|
|
1564
|
+
] }, op.path);
|
|
1565
|
+
})
|
|
1566
|
+
}
|
|
1567
|
+
);
|
|
1568
|
+
}
|
|
1569
|
+
if (failed) {
|
|
1570
|
+
return /* @__PURE__ */ jsx8(
|
|
1571
|
+
ActivityDisclosure,
|
|
1572
|
+
{
|
|
1573
|
+
icon: /* @__PURE__ */ jsx8(FileDiffIcon, { className: ICON_SIZE }),
|
|
1574
|
+
iconTone: "failed",
|
|
1575
|
+
title: firstOp ? `${verbForOp(firstOp)} ${basename(firstOp.path)}` : "apply_patch",
|
|
1576
|
+
chip: { tone: "bad", text: "failed" },
|
|
1577
|
+
preview: typeof item.output === "string" ? item.output : "patch failed",
|
|
1578
|
+
children: /* @__PURE__ */ jsx8(PayloadBlock, { label: "Error", value: item.output, failed: true })
|
|
1579
|
+
}
|
|
1580
|
+
);
|
|
1581
|
+
}
|
|
1582
|
+
if (ops.length > 1) {
|
|
1583
|
+
const parsed = ops.map((op) => safeParseOp(op));
|
|
1584
|
+
const goodFiles = parsed.filter((f) => f !== null);
|
|
1585
|
+
const add = goodFiles.reduce((n, f) => n + f.additions, 0);
|
|
1586
|
+
const del = goodFiles.reduce((n, f) => n + f.deletions, 0);
|
|
1587
|
+
return /* @__PURE__ */ jsx8(
|
|
1588
|
+
ActivityDisclosure,
|
|
1589
|
+
{
|
|
1590
|
+
icon: /* @__PURE__ */ jsx8(FileDiffIcon, { className: ICON_SIZE }),
|
|
1591
|
+
iconTone: "accent",
|
|
1592
|
+
title: `Edited ${ops.length} files`,
|
|
1593
|
+
cancelled,
|
|
1594
|
+
preview: /* @__PURE__ */ jsxs6("span", { className: "inline-flex items-center gap-2 font-og-mono", children: [
|
|
1595
|
+
/* @__PURE__ */ jsxs6("span", { className: "text-og-fg-muted", children: [
|
|
1596
|
+
ops.length,
|
|
1597
|
+
" files"
|
|
1598
|
+
] }),
|
|
1599
|
+
/* @__PURE__ */ jsxs6("span", { className: "text-og-fg-subtle", children: [
|
|
1600
|
+
"+",
|
|
1601
|
+
add,
|
|
1602
|
+
" \u2212",
|
|
1603
|
+
del
|
|
1604
|
+
] })
|
|
1605
|
+
] }),
|
|
1606
|
+
children: ops.map((op, index) => {
|
|
1607
|
+
const file2 = parsed[index];
|
|
1608
|
+
return file2 ? /* @__PURE__ */ jsx8(ToolDiff, { files: [file2] }, op.path) : /* @__PURE__ */ jsxs6("div", { children: [
|
|
1609
|
+
/* @__PURE__ */ jsx8("p", { className: "mb-1 font-og-mono text-og-xs text-og-fg-muted", children: op.path }),
|
|
1610
|
+
/* @__PURE__ */ jsx8(RawPatch, { diff: op.diff ?? "" })
|
|
1611
|
+
] }, op.path);
|
|
1612
|
+
})
|
|
1613
|
+
}
|
|
1614
|
+
);
|
|
1615
|
+
}
|
|
1616
|
+
if (!firstOp) {
|
|
1617
|
+
return /* @__PURE__ */ jsx8(GenericRenderer, { item });
|
|
1618
|
+
}
|
|
1619
|
+
if (firstOp.type === "delete_file") {
|
|
1620
|
+
return /* @__PURE__ */ jsx8(
|
|
1621
|
+
ActivityDisclosure,
|
|
1622
|
+
{
|
|
1623
|
+
icon: /* @__PURE__ */ jsx8(FileDiffIcon, { className: ICON_SIZE }),
|
|
1624
|
+
iconTone: "failed",
|
|
1625
|
+
title: `Deleted ${basename(firstOp.path)}`,
|
|
1626
|
+
cancelled,
|
|
1627
|
+
preview: /* @__PURE__ */ jsx8(PathPreview, { path: firstOp.path }),
|
|
1628
|
+
children: /* @__PURE__ */ jsx8(BodyNote, { children: "File deleted \u2014 no diff to show." })
|
|
1629
|
+
}
|
|
1630
|
+
);
|
|
1631
|
+
}
|
|
1632
|
+
const file = safeParseOp(firstOp);
|
|
1633
|
+
if (!file) {
|
|
1634
|
+
return /* @__PURE__ */ jsx8(
|
|
1635
|
+
ActivityDisclosure,
|
|
1636
|
+
{
|
|
1637
|
+
icon: /* @__PURE__ */ jsx8(FileDiffIcon, { className: ICON_SIZE }),
|
|
1638
|
+
iconTone: "accent",
|
|
1639
|
+
title: `${verbForOp(firstOp)} ${basename(firstOp.path)}`,
|
|
1640
|
+
cancelled,
|
|
1641
|
+
preview: /* @__PURE__ */ jsxs6("span", { className: "inline-flex items-center gap-2 font-og-mono", children: [
|
|
1642
|
+
/* @__PURE__ */ jsx8("span", { className: "text-og-fg-muted", children: basename(firstOp.path) }),
|
|
1643
|
+
/* @__PURE__ */ jsx8("span", { className: "text-og-fg-subtle", children: "malformed V4A" })
|
|
1644
|
+
] }),
|
|
1645
|
+
children: /* @__PURE__ */ jsx8(RawPatch, { diff: firstOp.diff ?? "" })
|
|
1646
|
+
}
|
|
1647
|
+
);
|
|
1648
|
+
}
|
|
1649
|
+
return /* @__PURE__ */ jsx8(
|
|
1650
|
+
ActivityDisclosure,
|
|
1651
|
+
{
|
|
1652
|
+
icon: /* @__PURE__ */ jsx8(FileDiffIcon, { className: ICON_SIZE }),
|
|
1653
|
+
iconTone: "accent",
|
|
1654
|
+
title: `${verbForOp(firstOp)} ${basename(file.path)}`,
|
|
1655
|
+
cancelled,
|
|
1656
|
+
preview: /* @__PURE__ */ jsx8(PathPreview, { path: file.path, add: file.additions, del: file.deletions }),
|
|
1657
|
+
children: /* @__PURE__ */ jsx8(ToolDiff, { files: [file] })
|
|
1658
|
+
}
|
|
1659
|
+
);
|
|
1660
|
+
}
|
|
1661
|
+
function safeParseOp(op) {
|
|
1662
|
+
try {
|
|
1663
|
+
return v4aToGitFileDiff(op);
|
|
1664
|
+
} catch {
|
|
1665
|
+
return null;
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
function computerVerb(action) {
|
|
1669
|
+
if (!action || !action.type) {
|
|
1670
|
+
return "Acted";
|
|
1671
|
+
}
|
|
1672
|
+
switch (action.type) {
|
|
1673
|
+
case "screenshot":
|
|
1674
|
+
return "Screenshot";
|
|
1675
|
+
case "click":
|
|
1676
|
+
return `Clicked (${action.x}, ${action.y})`;
|
|
1677
|
+
case "double_click":
|
|
1678
|
+
return `Double-clicked (${action.x}, ${action.y})`;
|
|
1679
|
+
case "move":
|
|
1680
|
+
return `Moved (${action.x}, ${action.y})`;
|
|
1681
|
+
case "scroll":
|
|
1682
|
+
return "Scrolled";
|
|
1683
|
+
case "type": {
|
|
1684
|
+
const t = action.text ?? "";
|
|
1685
|
+
return `Typed \u201C${t.slice(0, 28)}${t.length > 28 ? "\u2026" : ""}\u201D`;
|
|
1686
|
+
}
|
|
1687
|
+
case "keypress":
|
|
1688
|
+
return `Pressed ${(action.keys ?? []).join("+")}`;
|
|
1689
|
+
case "drag":
|
|
1690
|
+
return "Dragged";
|
|
1691
|
+
case "wait":
|
|
1692
|
+
return "Waited";
|
|
1693
|
+
default:
|
|
1694
|
+
return action.type;
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
function asComputerArgs(args) {
|
|
1698
|
+
if (!args) {
|
|
1699
|
+
return {};
|
|
1700
|
+
}
|
|
1701
|
+
const parsed = typeof args === "string" ? tryParseJson(args) : args;
|
|
1702
|
+
if (!parsed || typeof parsed !== "object") {
|
|
1703
|
+
return {};
|
|
1704
|
+
}
|
|
1705
|
+
const record = parsed;
|
|
1706
|
+
return {
|
|
1707
|
+
...typeof record.x === "number" ? { x: record.x } : {},
|
|
1708
|
+
...typeof record.y === "number" ? { y: record.y } : {},
|
|
1709
|
+
...typeof record.text === "string" ? { text: record.text } : {},
|
|
1710
|
+
...Array.isArray(record.keys) ? { keys: record.keys } : {},
|
|
1711
|
+
...typeof record.button === "string" ? { button: record.button } : {}
|
|
1712
|
+
};
|
|
1713
|
+
}
|
|
1714
|
+
function ComputerCallRenderer({ item }) {
|
|
1715
|
+
const raw = item.raw ?? {};
|
|
1716
|
+
const functionAction = !raw.action && item.name.startsWith("computer_") && item.name !== "computer_call" ? { type: item.name.slice("computer_".length), ...asComputerArgs(item.arguments) } : void 0;
|
|
1717
|
+
const action = raw.action ?? functionAction;
|
|
1718
|
+
const actions = raw.actions ?? (action ? [action] : []);
|
|
1719
|
+
const verb = computerVerb(action);
|
|
1720
|
+
const out = item.output;
|
|
1721
|
+
const running = item.status === "running";
|
|
1722
|
+
const rejected = raw.providerData?.approvalStatus === "rejected";
|
|
1723
|
+
const readOnly = typeof out === "string" && out.includes("read-only");
|
|
1724
|
+
const shotUrl = screenshotDataUrl(out);
|
|
1725
|
+
const omittedMedia = mediaPreviewFact(out);
|
|
1726
|
+
const empty = out === "" || out == null;
|
|
1727
|
+
const batched = actions.length > 1 ? actions.map((a) => computerVerb(a)).join(" \xB7 ") : null;
|
|
1728
|
+
const countSuffix = actions.length > 1 ? ` \xB7${actions.length}` : "";
|
|
1729
|
+
const isShot = action?.type === "screenshot";
|
|
1730
|
+
if (running) {
|
|
1731
|
+
return /* @__PURE__ */ jsx8(
|
|
1732
|
+
ActivityDisclosure,
|
|
1733
|
+
{
|
|
1734
|
+
icon: isShot ? /* @__PURE__ */ jsx8(CameraIcon2, { className: ICON_SIZE }) : /* @__PURE__ */ jsx8(MousePointer2Icon, { className: ICON_SIZE }),
|
|
1735
|
+
iconTone: "running",
|
|
1736
|
+
title: verb,
|
|
1737
|
+
running: true,
|
|
1738
|
+
media: /* @__PURE__ */ jsx8(MediaSkeleton, {}),
|
|
1739
|
+
children: /* @__PURE__ */ jsx8(BodyNote, { children: "capturing frame\u2026" })
|
|
1740
|
+
}
|
|
1741
|
+
);
|
|
1742
|
+
}
|
|
1743
|
+
if (readOnly) {
|
|
1744
|
+
return /* @__PURE__ */ jsx8(
|
|
1745
|
+
ActivityDisclosure,
|
|
1746
|
+
{
|
|
1747
|
+
icon: /* @__PURE__ */ jsx8(MousePointer2Icon, { className: ICON_SIZE }),
|
|
1748
|
+
iconTone: "failed",
|
|
1749
|
+
title: verb,
|
|
1750
|
+
chip: { tone: "bad", text: "read-only" },
|
|
1751
|
+
preview: "write actions disabled",
|
|
1752
|
+
children: /* @__PURE__ */ jsx8(BodyNote, { tone: "error", children: "computer-use is read-only \u2014 write actions are disabled." })
|
|
1753
|
+
}
|
|
1754
|
+
);
|
|
1755
|
+
}
|
|
1756
|
+
if (rejected) {
|
|
1757
|
+
return /* @__PURE__ */ jsx8(
|
|
1758
|
+
ActivityDisclosure,
|
|
1759
|
+
{
|
|
1760
|
+
icon: /* @__PURE__ */ jsx8(LockIcon, { className: ICON_SIZE }),
|
|
1761
|
+
iconTone: "muted",
|
|
1762
|
+
title: verb,
|
|
1763
|
+
preview: "approval rejected \u2014 this action did not run",
|
|
1764
|
+
children: /* @__PURE__ */ jsx8(BodyNote, { children: "approval rejected \u2014 this action did not run." })
|
|
1765
|
+
}
|
|
1766
|
+
);
|
|
1767
|
+
}
|
|
1768
|
+
const isFailed = item.status === "failed";
|
|
1769
|
+
const isCancelled = item.status === "cancelled";
|
|
1770
|
+
if (shotUrl) {
|
|
1771
|
+
const caption = `${verb}${actions.length > 1 ? ` (+${actions.length - 1} more)` : ""}`;
|
|
1772
|
+
return /* @__PURE__ */ jsxs6(
|
|
1773
|
+
ActivityDisclosure,
|
|
1774
|
+
{
|
|
1775
|
+
icon: isShot ? /* @__PURE__ */ jsx8(CameraIcon2, { className: ICON_SIZE }) : /* @__PURE__ */ jsx8(MousePointer2Icon, { className: ICON_SIZE }),
|
|
1776
|
+
iconTone: isFailed ? "failed" : "accent",
|
|
1777
|
+
title: `${verb}${countSuffix}`,
|
|
1778
|
+
failed: isFailed,
|
|
1779
|
+
cancelled: isCancelled,
|
|
1780
|
+
media: /* @__PURE__ */ jsx8(Thumbnail, { src: shotUrl, caption }),
|
|
1781
|
+
children: [
|
|
1782
|
+
/* @__PURE__ */ jsx8(ScreenshotFigure, { src: shotUrl, caption }),
|
|
1783
|
+
batched ? /* @__PURE__ */ jsxs6(BodyNote, { children: [
|
|
1784
|
+
"batched: ",
|
|
1785
|
+
batched
|
|
1786
|
+
] }) : null
|
|
1787
|
+
]
|
|
1788
|
+
}
|
|
1789
|
+
);
|
|
1790
|
+
}
|
|
1791
|
+
if (omittedMedia) {
|
|
1792
|
+
return /* @__PURE__ */ jsxs6(
|
|
1793
|
+
ActivityDisclosure,
|
|
1794
|
+
{
|
|
1795
|
+
icon: /* @__PURE__ */ jsx8(CameraOffIcon2, { className: ICON_SIZE }),
|
|
1796
|
+
iconTone: isFailed ? "failed" : "muted",
|
|
1797
|
+
title: `${verb}${countSuffix} \xB7 image omitted \xB7 not retained`,
|
|
1798
|
+
failed: isFailed,
|
|
1799
|
+
cancelled: isCancelled,
|
|
1800
|
+
preview: "inline image omitted \xB7 not retained",
|
|
1801
|
+
media: /* @__PURE__ */ jsx8(MediaEmpty, {}),
|
|
1802
|
+
children: [
|
|
1803
|
+
/* @__PURE__ */ jsxs6(BodyNote, { children: [
|
|
1804
|
+
"The inline ",
|
|
1805
|
+
omittedMedia.mediaType,
|
|
1806
|
+
" output was omitted from the audit timeline and its source bytes were not retained."
|
|
1807
|
+
] }),
|
|
1808
|
+
batched ? /* @__PURE__ */ jsxs6(BodyNote, { children: [
|
|
1809
|
+
"batched: ",
|
|
1810
|
+
batched
|
|
1811
|
+
] }) : null
|
|
1812
|
+
]
|
|
1813
|
+
}
|
|
1814
|
+
);
|
|
1815
|
+
}
|
|
1816
|
+
if (empty) {
|
|
1817
|
+
return /* @__PURE__ */ jsx8(
|
|
1818
|
+
ActivityDisclosure,
|
|
1819
|
+
{
|
|
1820
|
+
icon: /* @__PURE__ */ jsx8(CameraOffIcon2, { className: ICON_SIZE }),
|
|
1821
|
+
iconTone: isFailed ? "failed" : "muted",
|
|
1822
|
+
title: verb,
|
|
1823
|
+
failed: isFailed,
|
|
1824
|
+
cancelled: isCancelled,
|
|
1825
|
+
media: /* @__PURE__ */ jsx8(MediaEmpty, {}),
|
|
1826
|
+
children: /* @__PURE__ */ jsx8(BodyNote, { children: isFailed ? "computer_call failed \u2014 no image returned." : isCancelled ? "computer_call interrupted \u2014 no image returned." : "(no image) \u2014 the session returned an empty screenshot." })
|
|
1827
|
+
}
|
|
1828
|
+
);
|
|
1829
|
+
}
|
|
1830
|
+
return /* @__PURE__ */ jsx8(
|
|
1831
|
+
ActivityDisclosure,
|
|
1832
|
+
{
|
|
1833
|
+
icon: /* @__PURE__ */ jsx8(MousePointer2Icon, { className: ICON_SIZE }),
|
|
1834
|
+
iconTone: isFailed ? "failed" : "accent",
|
|
1835
|
+
title: verb,
|
|
1836
|
+
failed: isFailed,
|
|
1837
|
+
cancelled: isCancelled,
|
|
1838
|
+
preview: batched ?? void 0,
|
|
1839
|
+
expandable: batched != null,
|
|
1840
|
+
children: batched ? /* @__PURE__ */ jsx8(BodyNote, { children: batched }) : null
|
|
1841
|
+
}
|
|
1842
|
+
);
|
|
1843
|
+
}
|
|
1844
|
+
function WebSearchRenderer({ item }) {
|
|
1845
|
+
const raw = item.raw ?? {};
|
|
1846
|
+
const action = raw.providerData?.action ?? {};
|
|
1847
|
+
const query = action.query ?? "(query unavailable)";
|
|
1848
|
+
const queries = action.queries ?? [];
|
|
1849
|
+
const variants = queries.length > 1 ? ` +${queries.length - 1} variants` : "";
|
|
1850
|
+
const running = item.status === "running";
|
|
1851
|
+
const rawResults = item.output?.results;
|
|
1852
|
+
const results = Array.isArray(rawResults) ? rawResults.filter((r) => !!r && typeof r === "object") : void 0;
|
|
1853
|
+
const resultOccurrences = /* @__PURE__ */ new Map();
|
|
1854
|
+
const keyedResults = results?.map((result) => {
|
|
1855
|
+
const contentKey = `${result.domain}\0${result.title}\0${result.snippet}`;
|
|
1856
|
+
const occurrence = (resultOccurrences.get(contentKey) ?? 0) + 1;
|
|
1857
|
+
resultOccurrences.set(contentKey, occurrence);
|
|
1858
|
+
return { key: `${contentKey}\0${occurrence}`, result };
|
|
1859
|
+
});
|
|
1860
|
+
if (running) {
|
|
1861
|
+
return /* @__PURE__ */ jsx8(
|
|
1862
|
+
ActivityDisclosure,
|
|
1863
|
+
{
|
|
1864
|
+
icon: /* @__PURE__ */ jsx8(SearchIcon, { className: ICON_SIZE }),
|
|
1865
|
+
iconTone: "running",
|
|
1866
|
+
title: "Searching the web",
|
|
1867
|
+
running: true,
|
|
1868
|
+
preview: /* @__PURE__ */ jsx8(RunningPreview, { children: `${query}${variants}` }),
|
|
1869
|
+
children: /* @__PURE__ */ jsx8(BodyNote, { children: "searching\u2026 results fold into the model context (no output event)." })
|
|
1870
|
+
}
|
|
1871
|
+
);
|
|
1872
|
+
}
|
|
1873
|
+
return /* @__PURE__ */ jsx8(
|
|
1874
|
+
ActivityDisclosure,
|
|
1875
|
+
{
|
|
1876
|
+
icon: /* @__PURE__ */ jsx8(SearchIcon, { className: ICON_SIZE }),
|
|
1877
|
+
iconTone: "muted",
|
|
1878
|
+
title: "Searched the web",
|
|
1879
|
+
preview: `${query}${variants}`,
|
|
1880
|
+
failed: item.status === "failed",
|
|
1881
|
+
cancelled: item.status === "cancelled",
|
|
1882
|
+
children: keyedResults && keyedResults.length ? /* @__PURE__ */ jsx8("ul", { className: "flex flex-col gap-2", children: keyedResults.map(({ key, result }) => /* @__PURE__ */ jsxs6("li", { className: "flex gap-2.5", children: [
|
|
1883
|
+
/* @__PURE__ */ jsx8(GlobeIcon, { className: "mt-0.5 size-3.5 shrink-0 text-og-fg-subtle" }),
|
|
1884
|
+
/* @__PURE__ */ jsxs6("div", { className: "min-w-0", children: [
|
|
1885
|
+
/* @__PURE__ */ jsxs6("p", { className: "truncate text-og-base text-og-fg", children: [
|
|
1886
|
+
result.title,
|
|
1887
|
+
" ",
|
|
1888
|
+
/* @__PURE__ */ jsx8("span", { className: "text-og-fg-subtle", children: result.domain })
|
|
1889
|
+
] }),
|
|
1890
|
+
/* @__PURE__ */ jsx8("p", { className: "text-og-sm leading-5 text-og-fg-muted", children: result.snippet })
|
|
1891
|
+
] })
|
|
1892
|
+
] }, key)) }) : /* @__PURE__ */ jsx8(BodyNote, { children: "results folded into model context \u2014 no list available." })
|
|
1893
|
+
}
|
|
1894
|
+
);
|
|
1895
|
+
}
|
|
1896
|
+
var VIEW_IMAGE_ERRORS = [
|
|
1897
|
+
"was not found",
|
|
1898
|
+
"is not a file",
|
|
1899
|
+
"exceeded the allowed size",
|
|
1900
|
+
"is not a supported image",
|
|
1901
|
+
"unable to read image"
|
|
1902
|
+
];
|
|
1903
|
+
function ViewImageRenderer({ item }) {
|
|
1904
|
+
const args = parseToolArgs(item.arguments);
|
|
1905
|
+
const path = typeof args.path === "string" ? args.path : "";
|
|
1906
|
+
const out = item.output;
|
|
1907
|
+
const text = typeof out === "string" ? out : "";
|
|
1908
|
+
const omittedMedia = mediaPreviewFact(out);
|
|
1909
|
+
if (item.status === "running") {
|
|
1910
|
+
return /* @__PURE__ */ jsx8(
|
|
1911
|
+
ActivityDisclosure,
|
|
1912
|
+
{
|
|
1913
|
+
icon: /* @__PURE__ */ jsx8(ImageIcon, { className: ICON_SIZE }),
|
|
1914
|
+
iconTone: "running",
|
|
1915
|
+
title: `View ${basename(path)}`,
|
|
1916
|
+
running: true,
|
|
1917
|
+
preview: /* @__PURE__ */ jsx8(RunningPreview, { children: "reading\u2026" }),
|
|
1918
|
+
media: /* @__PURE__ */ jsx8(MediaSkeleton, {}),
|
|
1919
|
+
children: /* @__PURE__ */ jsx8(BodyNote, { children: "reading image\u2026" })
|
|
1920
|
+
}
|
|
1921
|
+
);
|
|
1922
|
+
}
|
|
1923
|
+
const viewFailed = item.status === "failed";
|
|
1924
|
+
const viewCancelled = item.status === "cancelled";
|
|
1925
|
+
const errMatch = VIEW_IMAGE_ERRORS.find((p) => text.includes(p));
|
|
1926
|
+
if (errMatch) {
|
|
1927
|
+
const tooBig = text.includes("exceeded the allowed size");
|
|
1928
|
+
return /* @__PURE__ */ jsx8(
|
|
1929
|
+
ActivityDisclosure,
|
|
1930
|
+
{
|
|
1931
|
+
icon: /* @__PURE__ */ jsx8(ImageIcon, { className: ICON_SIZE }),
|
|
1932
|
+
iconTone: "failed",
|
|
1933
|
+
title: `View ${basename(path)}`,
|
|
1934
|
+
chip: { tone: "bad", text: tooBig ? "too large" : "error" },
|
|
1935
|
+
preview: text,
|
|
1936
|
+
children: /* @__PURE__ */ jsx8(BodyNote, { tone: "error", children: text })
|
|
1937
|
+
}
|
|
1938
|
+
);
|
|
1939
|
+
}
|
|
1940
|
+
if (text.startsWith("OpenAI file reference:")) {
|
|
1941
|
+
return /* @__PURE__ */ jsx8(
|
|
1942
|
+
ActivityDisclosure,
|
|
1943
|
+
{
|
|
1944
|
+
icon: /* @__PURE__ */ jsx8(ImageIcon, { className: ICON_SIZE }),
|
|
1945
|
+
iconTone: viewFailed ? "failed" : "muted",
|
|
1946
|
+
title: `Viewed ${basename(path)}`,
|
|
1947
|
+
failed: viewFailed,
|
|
1948
|
+
cancelled: viewCancelled,
|
|
1949
|
+
preview: path,
|
|
1950
|
+
children: /* @__PURE__ */ jsx8(BodyNote, { children: text })
|
|
1951
|
+
}
|
|
1952
|
+
);
|
|
1953
|
+
}
|
|
1954
|
+
if (omittedMedia) {
|
|
1955
|
+
return /* @__PURE__ */ jsx8(
|
|
1956
|
+
ActivityDisclosure,
|
|
1957
|
+
{
|
|
1958
|
+
icon: /* @__PURE__ */ jsx8(ImageIcon, { className: ICON_SIZE }),
|
|
1959
|
+
iconTone: viewFailed ? "failed" : "muted",
|
|
1960
|
+
title: `Viewed ${basename(path)} \xB7 image omitted \xB7 not retained`,
|
|
1961
|
+
failed: viewFailed,
|
|
1962
|
+
cancelled: viewCancelled,
|
|
1963
|
+
preview: "inline image omitted \xB7 not retained",
|
|
1964
|
+
media: /* @__PURE__ */ jsx8(MediaEmpty, {}),
|
|
1965
|
+
children: /* @__PURE__ */ jsxs6(BodyNote, { children: [
|
|
1966
|
+
"The inline ",
|
|
1967
|
+
omittedMedia.mediaType,
|
|
1968
|
+
" output was omitted from the audit timeline and its source bytes were not retained."
|
|
1969
|
+
] })
|
|
1970
|
+
}
|
|
1971
|
+
);
|
|
1972
|
+
}
|
|
1973
|
+
if (text.includes("No image data")) {
|
|
1974
|
+
return /* @__PURE__ */ jsx8(
|
|
1975
|
+
ActivityDisclosure,
|
|
1976
|
+
{
|
|
1977
|
+
icon: /* @__PURE__ */ jsx8(ImageIcon, { className: ICON_SIZE }),
|
|
1978
|
+
iconTone: viewFailed ? "failed" : "muted",
|
|
1979
|
+
title: `Viewed ${basename(path)}`,
|
|
1980
|
+
failed: viewFailed,
|
|
1981
|
+
cancelled: viewCancelled,
|
|
1982
|
+
preview: "(no image)",
|
|
1983
|
+
children: /* @__PURE__ */ jsx8(BodyNote, { children: viewFailed ? "view_image failed \u2014 no image data returned." : viewCancelled ? "view_image interrupted." : "(no image) \u2014 the sandbox session returned no image data." })
|
|
1984
|
+
}
|
|
1985
|
+
);
|
|
1986
|
+
}
|
|
1987
|
+
if (text.startsWith("data:")) {
|
|
1988
|
+
return /* @__PURE__ */ jsx8(
|
|
1989
|
+
ActivityDisclosure,
|
|
1990
|
+
{
|
|
1991
|
+
icon: /* @__PURE__ */ jsx8(ImageIcon, { className: ICON_SIZE }),
|
|
1992
|
+
iconTone: viewFailed ? "failed" : "accent",
|
|
1993
|
+
title: `Viewed ${basename(path)}`,
|
|
1994
|
+
failed: viewFailed,
|
|
1995
|
+
cancelled: viewCancelled,
|
|
1996
|
+
media: /* @__PURE__ */ jsx8(Thumbnail, { src: text, caption: path, alt: path }),
|
|
1997
|
+
children: /* @__PURE__ */ jsx8(ScreenshotFigure, { src: text, caption: path, alt: path })
|
|
1998
|
+
}
|
|
1999
|
+
);
|
|
2000
|
+
}
|
|
2001
|
+
return /* @__PURE__ */ jsx8(GenericRenderer, { item });
|
|
2002
|
+
}
|
|
2003
|
+
function SecretSetRenderer({ item }) {
|
|
2004
|
+
const args = parseToolArgs(item.arguments);
|
|
2005
|
+
const name = typeof args.name === "string" ? args.name : "variable";
|
|
2006
|
+
if (item.status === "running") {
|
|
2007
|
+
return /* @__PURE__ */ jsx8(
|
|
2008
|
+
ActivityDisclosure,
|
|
2009
|
+
{
|
|
2010
|
+
icon: /* @__PURE__ */ jsx8(KeyRoundIcon, { className: ICON_SIZE }),
|
|
2011
|
+
iconTone: "running",
|
|
2012
|
+
title: `Set ${name}`,
|
|
2013
|
+
running: true,
|
|
2014
|
+
preview: /* @__PURE__ */ jsx8(RunningPreview, { children: "setting\u2026" }),
|
|
2015
|
+
children: /* @__PURE__ */ jsx8(PayloadBlock, { label: "Arguments", value: redactSecrets(args) })
|
|
2016
|
+
}
|
|
2017
|
+
);
|
|
2018
|
+
}
|
|
2019
|
+
if (item.status === "failed") {
|
|
2020
|
+
const errorText = typeof item.output === "string" ? item.output : null;
|
|
2021
|
+
return /* @__PURE__ */ jsxs6(
|
|
2022
|
+
ActivityDisclosure,
|
|
2023
|
+
{
|
|
2024
|
+
icon: /* @__PURE__ */ jsx8(KeyRoundIcon, { className: ICON_SIZE }),
|
|
2025
|
+
iconTone: "failed",
|
|
2026
|
+
title: `Set ${name}`,
|
|
2027
|
+
failed: true,
|
|
2028
|
+
preview: errorText ?? "variable write failed",
|
|
2029
|
+
children: [
|
|
2030
|
+
/* @__PURE__ */ jsx8(PayloadBlock, { label: "Arguments", value: redactSecrets(args) }),
|
|
2031
|
+
errorText ? /* @__PURE__ */ jsx8(PayloadBlock, { label: "Error", value: errorText, failed: true }) : /* @__PURE__ */ jsx8(BodyNote, { tone: "error", children: "the tool call failed with no output." })
|
|
2032
|
+
]
|
|
2033
|
+
}
|
|
2034
|
+
);
|
|
2035
|
+
}
|
|
2036
|
+
return /* @__PURE__ */ jsxs6(
|
|
2037
|
+
ActivityDisclosure,
|
|
2038
|
+
{
|
|
2039
|
+
icon: /* @__PURE__ */ jsx8(KeyRoundIcon, { className: ICON_SIZE }),
|
|
2040
|
+
iconTone: "muted",
|
|
2041
|
+
title: `Set ${name}`,
|
|
2042
|
+
cancelled: item.status === "cancelled",
|
|
2043
|
+
preview: "value write-only \xB7 never returned",
|
|
2044
|
+
children: [
|
|
2045
|
+
/* @__PURE__ */ jsx8(PayloadBlock, { label: "Arguments", value: redactSecrets(args) }),
|
|
2046
|
+
/* @__PURE__ */ jsx8(BodyNote, { children: "the value is a secret \u2014 redacted in every view; the API never returns it." })
|
|
2047
|
+
]
|
|
2048
|
+
}
|
|
2049
|
+
);
|
|
2050
|
+
}
|
|
2051
|
+
function GenericRenderer({ item }) {
|
|
2052
|
+
const running = item.status === "running";
|
|
2053
|
+
const args = redactSecrets(parseToolArgs(item.arguments));
|
|
2054
|
+
const display = toolDisplayName(item.name);
|
|
2055
|
+
if (running) {
|
|
2056
|
+
return /* @__PURE__ */ jsx8(
|
|
2057
|
+
ActivityDisclosure,
|
|
2058
|
+
{
|
|
2059
|
+
icon: /* @__PURE__ */ jsx8(PlugIcon, { className: ICON_SIZE }),
|
|
2060
|
+
iconTone: "running",
|
|
2061
|
+
title: display,
|
|
2062
|
+
running: true,
|
|
2063
|
+
preview: /* @__PURE__ */ jsx8(RunningPreview, { children: compactArgs(args) || "running\u2026" }),
|
|
2064
|
+
children: /* @__PURE__ */ jsx8(PayloadBlock, { label: "Arguments", value: args })
|
|
2065
|
+
}
|
|
2066
|
+
);
|
|
2067
|
+
}
|
|
2068
|
+
const { text: outText, isError } = unwrapMcpOutput(item.output);
|
|
2069
|
+
if ((isError || item.status === "failed") && item.status !== "cancelled") {
|
|
2070
|
+
return /* @__PURE__ */ jsxs6(
|
|
2071
|
+
ActivityDisclosure,
|
|
2072
|
+
{
|
|
2073
|
+
icon: /* @__PURE__ */ jsx8(WrenchIcon, { className: ICON_SIZE }),
|
|
2074
|
+
iconTone: "failed",
|
|
2075
|
+
title: display,
|
|
2076
|
+
chip: { tone: "bad", text: "error" },
|
|
2077
|
+
preview: outText.slice(0, 80),
|
|
2078
|
+
children: [
|
|
2079
|
+
/* @__PURE__ */ jsx8(PayloadBlock, { label: "Arguments", value: args }),
|
|
2080
|
+
/* @__PURE__ */ jsx8(PayloadBlock, { label: "Error", value: outText, failed: true })
|
|
2081
|
+
]
|
|
2082
|
+
}
|
|
2083
|
+
);
|
|
2084
|
+
}
|
|
2085
|
+
return /* @__PURE__ */ jsxs6(
|
|
2086
|
+
ActivityDisclosure,
|
|
2087
|
+
{
|
|
2088
|
+
icon: /* @__PURE__ */ jsx8(WrenchIcon, { className: ICON_SIZE }),
|
|
2089
|
+
iconTone: "muted",
|
|
2090
|
+
title: display,
|
|
2091
|
+
cancelled: item.status === "cancelled",
|
|
2092
|
+
preview: compactArgs(args),
|
|
2093
|
+
children: [
|
|
2094
|
+
/* @__PURE__ */ jsx8(PayloadBlock, { label: "Arguments", value: args }),
|
|
2095
|
+
/* @__PURE__ */ jsx8(PayloadBlock, { label: "Result", value: outText })
|
|
2096
|
+
]
|
|
2097
|
+
}
|
|
2098
|
+
);
|
|
2099
|
+
}
|
|
2100
|
+
function compactArgs(args) {
|
|
2101
|
+
const text = stringifyPayload(args).replace(/\s+/g, " ").trim();
|
|
2102
|
+
return text === "{}" ? "" : text.length > 90 ? `${text.slice(0, 89)}\u2026` : text;
|
|
2103
|
+
}
|
|
2104
|
+
var BASE_ENTRIES = [
|
|
2105
|
+
// Provider-native items carry `raw.type` on the wire — this is their source of
|
|
2106
|
+
// truth and is consulted first by the registry.
|
|
2107
|
+
{ match: "rawType", type: "apply_patch_call", render: ApplyPatchRenderer },
|
|
2108
|
+
{ match: "rawType", type: "computer_call", render: ComputerCallRenderer },
|
|
2109
|
+
{ match: "rawType", type: "hosted_tool_call", render: WebSearchRenderer },
|
|
2110
|
+
// First-party sandbox + MCP tools resolve by name. `apply_patch_call` /
|
|
2111
|
+
// `computer_call` are intentionally repeated by name as a fallback only for
|
|
2112
|
+
// first-party replays that omit `raw` (the rawType entries above win whenever
|
|
2113
|
+
// `raw.type` is present, which is the live-wire case).
|
|
2114
|
+
{ match: "name", name: "exec_command", render: ExecRenderer },
|
|
2115
|
+
{ match: "name", name: "write_stdin", render: WriteStdinRenderer },
|
|
2116
|
+
{ match: "name", name: "apply_patch_call", render: ApplyPatchRenderer },
|
|
2117
|
+
{ match: "name", name: "computer_call", render: ComputerCallRenderer },
|
|
2118
|
+
// Function-mode computer tools (codex / chat-wire transports).
|
|
2119
|
+
{ match: "name", name: "computer_screenshot", render: ComputerCallRenderer },
|
|
2120
|
+
{ match: "name", name: "computer_click", render: ComputerCallRenderer },
|
|
2121
|
+
{ match: "name", name: "computer_double_click", render: ComputerCallRenderer },
|
|
2122
|
+
{ match: "name", name: "computer_move", render: ComputerCallRenderer },
|
|
2123
|
+
{ match: "name", name: "computer_scroll", render: ComputerCallRenderer },
|
|
2124
|
+
{ match: "name", name: "computer_type", render: ComputerCallRenderer },
|
|
2125
|
+
{ match: "name", name: "computer_keypress", render: ComputerCallRenderer },
|
|
2126
|
+
{ match: "name", name: "computer_drag", render: ComputerCallRenderer },
|
|
2127
|
+
{ match: "name", name: "web_search_call", render: WebSearchRenderer },
|
|
2128
|
+
{ match: "name", name: "view_image", render: ViewImageRenderer },
|
|
2129
|
+
{ match: "name", name: "environment_set_variable", render: SecretSetRenderer }
|
|
2130
|
+
];
|
|
2131
|
+
var defaultToolRegistry = createToolRegistry(BASE_ENTRIES, GenericRenderer);
|
|
2132
|
+
function createDefaultToolRegistry(options = {}) {
|
|
2133
|
+
return createToolRegistry(BASE_ENTRIES, GenericRenderer, options);
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2136
|
+
// src/timeline/activity-rail.tsx
|
|
2137
|
+
import {
|
|
2138
|
+
ArrowRightIcon,
|
|
2139
|
+
BotIcon,
|
|
2140
|
+
BrainCircuitIcon,
|
|
2141
|
+
BrainIcon,
|
|
2142
|
+
SquareTerminalIcon
|
|
2143
|
+
} from "lucide-react";
|
|
2144
|
+
import { lazy as lazy3, Suspense as Suspense3 } from "react";
|
|
2145
|
+
import { jsx as rowJsx, jsxs as rowJsxs } from "react/jsx-runtime";
|
|
2146
|
+
|
|
2147
|
+
// src/timeline/entrance.tsx
|
|
2148
|
+
import { createContext as createContext3, useContext as useContext3, useRef as useRef2 } from "react";
|
|
2149
|
+
var EntranceAnimationContext = createContext3(true);
|
|
2150
|
+
var EntranceAnimationProvider = EntranceAnimationContext.Provider;
|
|
2151
|
+
function useEntranceAnimation() {
|
|
2152
|
+
const enabled = useContext3(EntranceAnimationContext);
|
|
2153
|
+
const captured = useRef2(enabled);
|
|
2154
|
+
return captured.current;
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
// src/timeline/activity-rail.tsx
|
|
2158
|
+
import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2159
|
+
var LazyFleetDecisionRow = lazy3(() => import("./fleet-decision-row-GGCAT4E4.js"));
|
|
2160
|
+
function familyOf(item) {
|
|
2161
|
+
if (item.kind === "tool-call") {
|
|
2162
|
+
return item.name === "exec_command" || item.name === "write_stdin" ? "terminal" : item.name;
|
|
2163
|
+
}
|
|
2164
|
+
return item.kind;
|
|
2165
|
+
}
|
|
2166
|
+
function ActivityRail({
|
|
2167
|
+
items,
|
|
2168
|
+
toolRegistry = defaultToolRegistry,
|
|
2169
|
+
onOpenSession,
|
|
2170
|
+
onMemoryClick,
|
|
2171
|
+
bare,
|
|
2172
|
+
className
|
|
2173
|
+
}) {
|
|
2174
|
+
const enter = useEntranceAnimation();
|
|
2175
|
+
return /* @__PURE__ */ jsx9(
|
|
2176
|
+
"div",
|
|
2177
|
+
{
|
|
2178
|
+
className: cn(
|
|
2179
|
+
// Rows sit TIGHT by default (gap-0.5) so a same-family run reads as one
|
|
2180
|
+
// calm cluster; a family change opens real breathing room (mt-3) below,
|
|
2181
|
+
// so a long rail reads as a few clusters, not a metronome of rows.
|
|
2182
|
+
"flex flex-col gap-0.5",
|
|
2183
|
+
!bare && "border-l-2 border-og-border pl-3 sm:pl-4",
|
|
2184
|
+
!bare && enter && "animate-og-enter",
|
|
2185
|
+
className
|
|
2186
|
+
),
|
|
2187
|
+
children: items.map((item, index) => {
|
|
2188
|
+
const newFamily = index > 0 && familyOf(item) !== familyOf(items[index - 1]);
|
|
2189
|
+
const row = renderActivity(item, toolRegistry, onOpenSession, onMemoryClick);
|
|
2190
|
+
return /* @__PURE__ */ jsx9("div", { "data-og-timeline-row-anchor": "", className: cn(newFamily && "mt-3"), children: row }, item.id);
|
|
2191
|
+
})
|
|
2192
|
+
}
|
|
2193
|
+
);
|
|
2194
|
+
}
|
|
2195
|
+
function assertNever(item) {
|
|
2196
|
+
throw new Error(`ActivityRail: unhandled activity item ${JSON.stringify(item)}`);
|
|
2197
|
+
}
|
|
2198
|
+
function renderActivity(item, toolRegistry, onOpenSession, onMemoryClick) {
|
|
2199
|
+
switch (item.kind) {
|
|
2200
|
+
case "reasoning":
|
|
2201
|
+
return /* @__PURE__ */ jsx9(ReasoningRow, { item });
|
|
2202
|
+
case "tool-call": {
|
|
2203
|
+
const Renderer = toolRegistry.resolve(item);
|
|
2204
|
+
return /* @__PURE__ */ jsx9(Renderer, { item });
|
|
2205
|
+
}
|
|
2206
|
+
case "worker":
|
|
2207
|
+
return /* @__PURE__ */ jsx9(WorkerRow, { item, onOpenSession });
|
|
2208
|
+
case "sandbox":
|
|
2209
|
+
return /* @__PURE__ */ jsx9(SandboxRow, { item });
|
|
2210
|
+
case "memory":
|
|
2211
|
+
return /* @__PURE__ */ jsx9(MemoryRow, { item, onMemoryClick });
|
|
2212
|
+
case "fleet-decision":
|
|
2213
|
+
return /* @__PURE__ */ jsx9(Suspense3, { fallback: null, children: /* @__PURE__ */ jsx9(
|
|
2214
|
+
LazyFleetDecisionRow,
|
|
2215
|
+
{
|
|
2216
|
+
item,
|
|
2217
|
+
d: ActivityDisclosure,
|
|
2218
|
+
b: BodyNote,
|
|
2219
|
+
j: rowJsx,
|
|
2220
|
+
s: rowJsxs
|
|
2221
|
+
}
|
|
2222
|
+
) });
|
|
2223
|
+
default:
|
|
2224
|
+
return assertNever(item);
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
function ReasoningRow({ item }) {
|
|
2228
|
+
return /* @__PURE__ */ jsx9(
|
|
2229
|
+
ActivityDisclosure,
|
|
2230
|
+
{
|
|
2231
|
+
icon: /* @__PURE__ */ jsx9(BrainIcon, { className: "size-3.5" }),
|
|
2232
|
+
iconTone: "muted",
|
|
2233
|
+
title: item.streaming ? "Thinking" : /* @__PURE__ */ jsx9("span", { className: "font-normal italic text-og-fg-subtle", children: "Thought" }),
|
|
2234
|
+
running: item.streaming,
|
|
2235
|
+
preview: truncate(item.text, 110),
|
|
2236
|
+
children: /* @__PURE__ */ jsx9("p", { className: "whitespace-pre-wrap text-og-base leading-6 text-og-fg-muted", children: item.text })
|
|
2237
|
+
}
|
|
2238
|
+
);
|
|
2239
|
+
}
|
|
2240
|
+
var MEMORY_KIND_LABEL = {
|
|
2241
|
+
preference: "Preference",
|
|
2242
|
+
semantic: "Fact",
|
|
2243
|
+
procedural: "Procedure",
|
|
2244
|
+
decision: "Decision",
|
|
2245
|
+
episodic: "History"
|
|
2246
|
+
};
|
|
2247
|
+
function MemoryRow({
|
|
2248
|
+
item,
|
|
2249
|
+
onMemoryClick
|
|
2250
|
+
}) {
|
|
2251
|
+
const corrected = item.variant === "corrected";
|
|
2252
|
+
const kindLabel = MEMORY_KIND_LABEL[item.memoryKind];
|
|
2253
|
+
const superseded = corrected && Boolean(item.replacementPreview);
|
|
2254
|
+
const targetId = corrected ? item.replacementMemoryId ?? item.memoryId : item.memoryId;
|
|
2255
|
+
const deepLink = Boolean(onMemoryClick);
|
|
2256
|
+
return /* @__PURE__ */ jsxs7(
|
|
2257
|
+
ActivityDisclosure,
|
|
2258
|
+
{
|
|
2259
|
+
icon: /* @__PURE__ */ jsx9(BrainCircuitIcon, { className: "size-3.5" }),
|
|
2260
|
+
iconTone: "muted",
|
|
2261
|
+
title: /* @__PURE__ */ jsxs7("span", { className: "inline-flex min-w-0 items-center gap-2", children: [
|
|
2262
|
+
/* @__PURE__ */ jsx9("span", { className: "shrink-0", children: corrected ? "Updated memory" : "Saved to memory" }),
|
|
2263
|
+
kindLabel ? /* @__PURE__ */ jsx9("span", { className: "shrink-0 rounded-og-xs bg-og-surface-2 px-1.5 py-px text-og-xs font-normal leading-tight text-og-fg-subtle", children: kindLabel }) : null
|
|
2264
|
+
] }),
|
|
2265
|
+
preview: superseded ? item.replacementPreview : item.preview,
|
|
2266
|
+
children: [
|
|
2267
|
+
superseded ? (
|
|
2268
|
+
// The correction as a before → after: the old memory struck through and
|
|
2269
|
+
// dimmed, the new text in the ordinary body weight below it.
|
|
2270
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-1.5", children: [
|
|
2271
|
+
/* @__PURE__ */ jsx9("p", { className: "whitespace-pre-wrap text-og-sm leading-6 text-og-fg-subtle line-through", children: item.preview }),
|
|
2272
|
+
/* @__PURE__ */ jsx9("p", { className: "whitespace-pre-wrap text-og-base leading-6 text-og-fg-muted", children: item.replacementPreview })
|
|
2273
|
+
] })
|
|
2274
|
+
) : corrected && item.action === "updated" ? (
|
|
2275
|
+
// Edited in place, no replacement record: the memory is still live, so
|
|
2276
|
+
// show its current text — NOT the archived treatment.
|
|
2277
|
+
/* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
2278
|
+
/* @__PURE__ */ jsx9("p", { className: "whitespace-pre-wrap text-og-base leading-6 text-og-fg-muted", children: item.preview }),
|
|
2279
|
+
/* @__PURE__ */ jsx9(BodyNote, { tone: "muted", children: "Updated in place." })
|
|
2280
|
+
] })
|
|
2281
|
+
) : corrected ? (
|
|
2282
|
+
// A correction with no replacement (and not an in-place update) archived the record.
|
|
2283
|
+
/* @__PURE__ */ jsx9(BodyNote, { tone: "muted", children: "Archived." })
|
|
2284
|
+
) : /* @__PURE__ */ jsx9("p", { className: "whitespace-pre-wrap text-og-base leading-6 text-og-fg-muted", children: item.preview }),
|
|
2285
|
+
item.deduped ? /* @__PURE__ */ jsx9(BodyNote, { tone: "muted", children: "Merged into an existing memory." }) : null,
|
|
2286
|
+
deepLink ? /* @__PURE__ */ jsxs7(
|
|
2287
|
+
"button",
|
|
2288
|
+
{
|
|
2289
|
+
type: "button",
|
|
2290
|
+
onClick: () => onMemoryClick?.(targetId),
|
|
2291
|
+
className: cn(
|
|
2292
|
+
"group/memlink -mx-1 inline-flex w-fit items-center gap-1 rounded-og-sm px-1 py-0.5 text-left text-og-sm text-og-fg-subtle",
|
|
2293
|
+
"outline-none transition-colors duration-150 hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent"
|
|
2294
|
+
),
|
|
2295
|
+
children: [
|
|
2296
|
+
"View in memory",
|
|
2297
|
+
/* @__PURE__ */ jsx9(ArrowRightIcon, { className: "size-3.5 transition-transform duration-150 group-hover/memlink:translate-x-0.5" })
|
|
2298
|
+
]
|
|
2299
|
+
}
|
|
2300
|
+
) : null
|
|
2301
|
+
]
|
|
2302
|
+
}
|
|
2303
|
+
);
|
|
2304
|
+
}
|
|
2305
|
+
function sandboxRowTitle(item) {
|
|
2306
|
+
if (item.name === "sandbox.provision") {
|
|
2307
|
+
if (item.status === "failed") return "Sandbox didn\u2019t start";
|
|
2308
|
+
if (item.status === "running") return "Starting sandbox";
|
|
2309
|
+
if (item.origin === "resumed") return "Sandbox reattached";
|
|
2310
|
+
if (item.origin === "restored") return "Sandbox restored";
|
|
2311
|
+
if (item.origin === "created") return "Sandbox created";
|
|
2312
|
+
return "Sandbox ready";
|
|
2313
|
+
}
|
|
2314
|
+
return toolDisplayName(item.name);
|
|
2315
|
+
}
|
|
2316
|
+
function SandboxRow({ item }) {
|
|
2317
|
+
return /* @__PURE__ */ jsxs7(
|
|
2318
|
+
ActivityDisclosure,
|
|
2319
|
+
{
|
|
2320
|
+
icon: /* @__PURE__ */ jsx9(SquareTerminalIcon, { className: "size-3.5" }),
|
|
2321
|
+
iconTone: item.status === "failed" ? "failed" : item.status === "running" ? "running" : "muted",
|
|
2322
|
+
title: sandboxRowTitle(item),
|
|
2323
|
+
running: item.status === "running",
|
|
2324
|
+
failed: item.status === "failed",
|
|
2325
|
+
cancelled: item.status === "cancelled",
|
|
2326
|
+
preview: item.command ?? void 0,
|
|
2327
|
+
children: [
|
|
2328
|
+
item.command ? /* @__PURE__ */ jsx9(PayloadBlock, { label: "Command", value: item.command }) : null,
|
|
2329
|
+
item.output ? /* @__PURE__ */ jsx9(PayloadBlock, { label: "Output", value: item.output }) : null
|
|
2330
|
+
]
|
|
2331
|
+
}
|
|
2332
|
+
);
|
|
2333
|
+
}
|
|
2334
|
+
function WorkerRow({
|
|
2335
|
+
item,
|
|
2336
|
+
onOpenSession
|
|
2337
|
+
}) {
|
|
2338
|
+
const running = item.status === "running";
|
|
2339
|
+
const failed = item.status === "failed";
|
|
2340
|
+
const cancelled = item.status === "cancelled";
|
|
2341
|
+
const title = item.action === "spawn" ? running ? "Spawning worker" : failed ? "Worker spawn failed" : cancelled ? "Worker interrupted" : "Worker spawned" : running ? "Messaging worker" : failed ? "Worker message failed" : cancelled ? "Worker interrupted" : "Worker messaged";
|
|
2342
|
+
const sessionId = item.workerSessionId;
|
|
2343
|
+
const deepLink = Boolean(sessionId) && Boolean(onOpenSession) && !failed && !cancelled;
|
|
2344
|
+
const inner = /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
2345
|
+
/* @__PURE__ */ jsx9("span", { className: "size-3.5 shrink-0", "aria-hidden": true }),
|
|
2346
|
+
/* @__PURE__ */ jsx9("span", { className: cn("mt-px shrink-0", failed ? "text-og-status-failed" : "text-og-accent"), children: /* @__PURE__ */ jsx9(BotIcon, { className: "size-3.5" }) }),
|
|
2347
|
+
/* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1", children: [
|
|
2348
|
+
/* @__PURE__ */ jsx9(
|
|
2349
|
+
"span",
|
|
2350
|
+
{
|
|
2351
|
+
className: cn(
|
|
2352
|
+
"text-og-base font-medium",
|
|
2353
|
+
running ? "og-shimmer-text" : failed ? "text-og-status-failed" : "text-og-fg"
|
|
2354
|
+
),
|
|
2355
|
+
children: title
|
|
2356
|
+
}
|
|
2357
|
+
),
|
|
2358
|
+
item.prompt ? /* @__PURE__ */ jsx9("p", { className: "mt-0.5 truncate text-og-sm text-og-fg-muted", children: truncate(item.prompt, 140) }) : null
|
|
2359
|
+
] }),
|
|
2360
|
+
failed ? /* @__PURE__ */ jsxs7("span", { className: "inline-flex shrink-0 self-center items-center gap-1.5 font-og-mono text-og-xs leading-none text-og-status-failed", children: [
|
|
2361
|
+
/* @__PURE__ */ jsx9("span", { className: "size-1.5 rounded-full bg-og-status-failed" }),
|
|
2362
|
+
"failed"
|
|
2363
|
+
] }) : cancelled ? /* @__PURE__ */ jsx9("span", { className: "og-cancelled-chip shrink-0 self-center font-og-mono text-og-xs leading-none text-og-fg-subtle", children: "interrupted" }) : deepLink ? /* @__PURE__ */ jsx9(
|
|
2364
|
+
ArrowRightIcon,
|
|
2365
|
+
{
|
|
2366
|
+
"aria-hidden": true,
|
|
2367
|
+
className: "mt-0.5 size-3.5 shrink-0 text-og-fg-subtle transition-[transform,color] duration-150 group-hover/worker:translate-x-0.5 group-hover/worker:text-og-fg"
|
|
2368
|
+
}
|
|
2369
|
+
) : null
|
|
2370
|
+
] });
|
|
2371
|
+
if (deepLink && sessionId && onOpenSession) {
|
|
2372
|
+
return /* @__PURE__ */ jsx9(
|
|
2373
|
+
"button",
|
|
2374
|
+
{
|
|
2375
|
+
type: "button",
|
|
2376
|
+
onClick: () => onOpenSession(sessionId),
|
|
2377
|
+
className: cn(
|
|
2378
|
+
"group/worker -mx-1.5 flex w-full items-start gap-2 rounded-og-sm px-1.5 py-1.5 text-left",
|
|
2379
|
+
"outline-none transition-colors duration-150 hover:bg-og-surface-1 focus-visible:ring-2 focus-visible:ring-og-accent",
|
|
2380
|
+
"pointer-coarse:py-2.5"
|
|
2381
|
+
),
|
|
2382
|
+
children: inner
|
|
2383
|
+
}
|
|
2384
|
+
);
|
|
2385
|
+
}
|
|
2386
|
+
return /* @__PURE__ */ jsx9("div", { className: "flex items-start gap-2 px-1.5 py-1.5", children: inner });
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
// src/timeline/turn-summary.tsx
|
|
2390
|
+
import { CheckIcon, ChevronRightIcon as ChevronRightIcon2, CircleSlashIcon, TriangleAlertIcon } from "lucide-react";
|
|
2391
|
+
import { useState as useState7 } from "react";
|
|
2392
|
+
import { Collapsible as Collapsible2 } from "radix-ui";
|
|
2393
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2394
|
+
function TurnSummary({
|
|
2395
|
+
items,
|
|
2396
|
+
outcome,
|
|
2397
|
+
failureText,
|
|
2398
|
+
durationMs,
|
|
2399
|
+
defaultOpen,
|
|
2400
|
+
bare,
|
|
2401
|
+
children
|
|
2402
|
+
}) {
|
|
2403
|
+
const forcedDefaultOpen = useForcedDefaultOpen();
|
|
2404
|
+
const [open, setOpen] = useState7(defaultOpen ?? forcedDefaultOpen ?? false);
|
|
2405
|
+
const enter = useEntranceAnimation();
|
|
2406
|
+
const facets = summarizeTurn(items, durationMs);
|
|
2407
|
+
return /* @__PURE__ */ jsxs8(
|
|
2408
|
+
Collapsible2.Root,
|
|
2409
|
+
{
|
|
2410
|
+
open,
|
|
2411
|
+
onOpenChange: setOpen,
|
|
2412
|
+
className: enter && !bare ? "animate-og-enter" : void 0,
|
|
2413
|
+
children: [
|
|
2414
|
+
/* @__PURE__ */ jsxs8(
|
|
2415
|
+
Collapsible2.Trigger,
|
|
2416
|
+
{
|
|
2417
|
+
className: cn(
|
|
2418
|
+
// Both the top-level turn fold and a nested cluster fold render as a
|
|
2419
|
+
// FLAT rail row — chevron + glyph + facets on the page background, no
|
|
2420
|
+
// border, no fill. Only a hover tint hints the row is expandable, so a
|
|
2421
|
+
// collapsed turn never reads as a boxed card. The top-level row is a
|
|
2422
|
+
// touch larger (base text, size-5 glyph, wider gap) so it still reads
|
|
2423
|
+
// as a turn landmark above the nested cluster rows it groups.
|
|
2424
|
+
"group flex w-full items-center rounded-og-sm text-left transition-colors",
|
|
2425
|
+
// A folded turn is a touch target on coarse pointers: grow the row so it
|
|
2426
|
+
// clears the 40px minimum without disturbing the calm desktop rhythm.
|
|
2427
|
+
"pointer-coarse:py-2.5",
|
|
2428
|
+
bare ? "gap-2 px-1.5 py-1.5 text-og-sm text-og-fg-muted" : "-mx-2 gap-2.5 px-2 py-1.5 text-og-base text-og-fg-muted",
|
|
2429
|
+
// A failed fold keeps its red accent (glyph + inline reason below) and a
|
|
2430
|
+
// faint red hover wash so attention still lands there; every other
|
|
2431
|
+
// outcome gets the neutral surface hover.
|
|
2432
|
+
outcome === "failed" ? "hover:bg-og-status-failed/[0.06] hover:text-og-fg" : "hover:bg-og-surface-1 hover:text-og-fg"
|
|
2433
|
+
),
|
|
2434
|
+
children: [
|
|
2435
|
+
/* @__PURE__ */ jsx10(ChevronRightIcon2, { className: "size-3.5 shrink-0 text-og-fg-subtle transition-transform duration-150 group-data-[state=open]:rotate-90" }),
|
|
2436
|
+
/* @__PURE__ */ jsx10(
|
|
2437
|
+
"span",
|
|
2438
|
+
{
|
|
2439
|
+
className: cn(
|
|
2440
|
+
"inline-flex shrink-0 items-center justify-center",
|
|
2441
|
+
bare ? "size-3.5" : "size-5",
|
|
2442
|
+
outcome === "failed" ? "text-og-status-failed" : "text-og-fg-subtle"
|
|
2443
|
+
),
|
|
2444
|
+
children: outcome === "failed" ? /* @__PURE__ */ jsx10(TriangleAlertIcon, { className: "size-3" }) : outcome === "cancelled" ? /* @__PURE__ */ jsx10(CircleSlashIcon, { className: "size-3" }) : outcome === "complete" ? /* @__PURE__ */ jsx10(CheckIcon, { className: bare ? "size-3" : "size-3.5" }) : /* @__PURE__ */ jsx10("span", { className: "size-1.5 animate-og-pulse rounded-full bg-og-fg-subtle" })
|
|
2445
|
+
}
|
|
2446
|
+
),
|
|
2447
|
+
/* @__PURE__ */ jsxs8("span", { className: cn("min-w-0 flex-1 truncate", bare ? "text-og-sm" : "text-og-fg-muted"), children: [
|
|
2448
|
+
facets,
|
|
2449
|
+
outcome === "failed" && failureText ? /* @__PURE__ */ jsxs8("span", { className: "text-og-status-failed", children: [
|
|
2450
|
+
" \xB7 ",
|
|
2451
|
+
failureText
|
|
2452
|
+
] }) : null,
|
|
2453
|
+
outcome === "cancelled" ? /* @__PURE__ */ jsx10("span", { className: "text-og-fg-subtle", children: " \xB7 interrupted" }) : null
|
|
2454
|
+
] }),
|
|
2455
|
+
/* @__PURE__ */ jsx10(
|
|
2456
|
+
"span",
|
|
2457
|
+
{
|
|
2458
|
+
"aria-hidden": true,
|
|
2459
|
+
className: cn(
|
|
2460
|
+
"ml-auto shrink-0 pl-2 text-og-xs text-og-fg-subtle transition-opacity duration-150",
|
|
2461
|
+
"opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100",
|
|
2462
|
+
"pointer-coarse:opacity-100"
|
|
2463
|
+
),
|
|
2464
|
+
children: open ? "hide steps" : "show steps"
|
|
2465
|
+
}
|
|
2466
|
+
)
|
|
2467
|
+
]
|
|
2468
|
+
}
|
|
2469
|
+
),
|
|
2470
|
+
/* @__PURE__ */ jsx10(Collapsible2.Content, { className: "overflow-hidden data-[state=closed]:animate-og-collapse data-[state=open]:animate-og-expand", children: /* @__PURE__ */ jsx10("div", { className: bare ? "pt-1 pl-5" : "pt-2", children }) })
|
|
2471
|
+
]
|
|
2472
|
+
}
|
|
2473
|
+
);
|
|
2474
|
+
}
|
|
2475
|
+
function summarizeTurn(items, durationMs) {
|
|
2476
|
+
let files = 0;
|
|
2477
|
+
let commands = 0;
|
|
2478
|
+
let screenshots = 0;
|
|
2479
|
+
let memoriesSaved = 0;
|
|
2480
|
+
let memoriesUpdated = 0;
|
|
2481
|
+
for (const item of items) {
|
|
2482
|
+
if (item.kind === "memory") {
|
|
2483
|
+
if (item.variant === "corrected") {
|
|
2484
|
+
memoriesUpdated += 1;
|
|
2485
|
+
} else {
|
|
2486
|
+
memoriesSaved += 1;
|
|
2487
|
+
}
|
|
2488
|
+
continue;
|
|
2489
|
+
}
|
|
2490
|
+
if (item.kind !== "tool-call") {
|
|
2491
|
+
continue;
|
|
2492
|
+
}
|
|
2493
|
+
if (isApplyPatch(item)) {
|
|
2494
|
+
files += applyPatchOps(item.raw).length;
|
|
2495
|
+
} else if (item.name === "exec_command") {
|
|
2496
|
+
commands += 1;
|
|
2497
|
+
} else if (rawTypeOf(item) === "computer_call" || item.name === "computer_call" || item.name === "computer_screenshot") {
|
|
2498
|
+
if (screenshotDataUrl(item.output) !== null || mediaPreviewFact(item.output) !== null) {
|
|
2499
|
+
screenshots += 1;
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
const parts = [`${items.length} ${items.length === 1 ? "step" : "steps"}`];
|
|
2504
|
+
if (files) {
|
|
2505
|
+
parts.push(`${files} ${files === 1 ? "file" : "files"} edited`);
|
|
2506
|
+
}
|
|
2507
|
+
if (commands) {
|
|
2508
|
+
parts.push(`${commands} ${commands === 1 ? "command" : "commands"}`);
|
|
2509
|
+
}
|
|
2510
|
+
if (screenshots) {
|
|
2511
|
+
parts.push(`${screenshots} ${screenshots === 1 ? "screenshot" : "screenshots"}`);
|
|
2512
|
+
}
|
|
2513
|
+
if (memoriesSaved) {
|
|
2514
|
+
parts.push(`${memoriesSaved} ${memoriesSaved === 1 ? "memory" : "memories"} saved`);
|
|
2515
|
+
}
|
|
2516
|
+
if (memoriesUpdated) {
|
|
2517
|
+
parts.push(`${memoriesUpdated} ${memoriesUpdated === 1 ? "memory" : "memories"} updated`);
|
|
2518
|
+
}
|
|
2519
|
+
const duration = formatDurationFacet(durationMs);
|
|
2520
|
+
if (duration) {
|
|
2521
|
+
parts.push(duration);
|
|
2522
|
+
}
|
|
2523
|
+
return parts.join(" \xB7 ");
|
|
2524
|
+
}
|
|
2525
|
+
function formatDurationFacet(durationMs) {
|
|
2526
|
+
if (durationMs === void 0 || !Number.isFinite(durationMs) || durationMs < 1e3) {
|
|
2527
|
+
return null;
|
|
2528
|
+
}
|
|
2529
|
+
const totalSeconds = Math.floor(durationMs / 1e3);
|
|
2530
|
+
if (totalSeconds < 60) {
|
|
2531
|
+
return `${totalSeconds}s`;
|
|
2532
|
+
}
|
|
2533
|
+
const totalMinutes = Math.floor(totalSeconds / 60);
|
|
2534
|
+
if (totalMinutes < 60) {
|
|
2535
|
+
return `${totalMinutes}m`;
|
|
2536
|
+
}
|
|
2537
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
2538
|
+
const minutes = totalMinutes % 60;
|
|
2539
|
+
return `${hours}h ${String(minutes).padStart(2, "0")}m`;
|
|
2540
|
+
}
|
|
2541
|
+
|
|
2542
|
+
// src/components/markdown.tsx
|
|
2543
|
+
import { memo } from "react";
|
|
2544
|
+
import ReactMarkdown from "react-markdown";
|
|
2545
|
+
import remarkGfm from "remark-gfm";
|
|
2546
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
2547
|
+
var components = {
|
|
2548
|
+
h1: ({ children, ...props }) => /* @__PURE__ */ jsx11(
|
|
2549
|
+
"h1",
|
|
2550
|
+
{
|
|
2551
|
+
className: "mt-5 mb-2.5 text-xl font-semibold tracking-tight text-og-fg first:mt-0",
|
|
2552
|
+
...props,
|
|
2553
|
+
children
|
|
2554
|
+
}
|
|
2555
|
+
),
|
|
2556
|
+
h2: ({ children, ...props }) => /* @__PURE__ */ jsx11("h2", { className: "mt-5 mb-2 text-lg font-semibold tracking-tight text-og-fg first:mt-0", ...props, children }),
|
|
2557
|
+
h3: ({ children, ...props }) => /* @__PURE__ */ jsx11(
|
|
2558
|
+
"h3",
|
|
2559
|
+
{
|
|
2560
|
+
className: "mt-4 mb-1.5 text-og-md font-semibold tracking-tight text-og-fg first:mt-0",
|
|
2561
|
+
...props,
|
|
2562
|
+
children
|
|
2563
|
+
}
|
|
2564
|
+
),
|
|
2565
|
+
h4: ({ children, ...props }) => /* @__PURE__ */ jsx11(
|
|
2566
|
+
"h4",
|
|
2567
|
+
{
|
|
2568
|
+
className: "mt-4 mb-1.5 text-og-sm font-semibold uppercase tracking-[0.04em] text-og-fg-muted first:mt-0",
|
|
2569
|
+
...props,
|
|
2570
|
+
children
|
|
2571
|
+
}
|
|
2572
|
+
),
|
|
2573
|
+
p: ({ children, ...props }) => /* @__PURE__ */ jsx11("p", { className: "my-2.5 leading-7 first:mt-0 last:mb-0", ...props, children }),
|
|
2574
|
+
strong: ({ children, ...props }) => /* @__PURE__ */ jsx11("strong", { className: "font-semibold text-og-fg", ...props, children }),
|
|
2575
|
+
em: ({ children, ...props }) => /* @__PURE__ */ jsx11("em", { className: "italic", ...props, children }),
|
|
2576
|
+
a: ({ children, ...props }) => /* @__PURE__ */ jsx11(
|
|
2577
|
+
"a",
|
|
2578
|
+
{
|
|
2579
|
+
className: "break-words font-medium text-og-accent underline-offset-2 hover:underline",
|
|
2580
|
+
target: "_blank",
|
|
2581
|
+
rel: "noreferrer noopener",
|
|
2582
|
+
...props,
|
|
2583
|
+
children
|
|
2584
|
+
}
|
|
2585
|
+
),
|
|
2586
|
+
ul: ({ children, ...props }) => /* @__PURE__ */ jsx11(
|
|
2587
|
+
"ul",
|
|
2588
|
+
{
|
|
2589
|
+
className: "my-2.5 ml-5 flex list-disc flex-col gap-1 marker:text-og-fg-subtle first:mt-0 last:mb-0",
|
|
2590
|
+
...props,
|
|
2591
|
+
children
|
|
2592
|
+
}
|
|
2593
|
+
),
|
|
2594
|
+
ol: ({ children, ...props }) => /* @__PURE__ */ jsx11(
|
|
2595
|
+
"ol",
|
|
2596
|
+
{
|
|
2597
|
+
className: "my-2.5 ml-5 flex list-decimal flex-col gap-1 marker:text-og-fg-subtle first:mt-0 last:mb-0",
|
|
2598
|
+
...props,
|
|
2599
|
+
children
|
|
2600
|
+
}
|
|
2601
|
+
),
|
|
2602
|
+
// GFM task-list items carry a leading checkbox <input>; `list-none` + a
|
|
2603
|
+
// negative margin pull the checkbox back to the bullet column so it aligns
|
|
2604
|
+
// with the text.
|
|
2605
|
+
li: ({ children, ...props }) => /* @__PURE__ */ jsx11(
|
|
2606
|
+
"li",
|
|
2607
|
+
{
|
|
2608
|
+
className: "leading-7 marker:text-og-fg-subtle [&>ul]:my-1 [&>ol]:my-1 [&:has(>input)]:list-none [&:has(>input)]:-ml-5",
|
|
2609
|
+
...props,
|
|
2610
|
+
children
|
|
2611
|
+
}
|
|
2612
|
+
),
|
|
2613
|
+
input: ({ type, ...props }) => type === "checkbox" ? /* @__PURE__ */ jsx11(
|
|
2614
|
+
"input",
|
|
2615
|
+
{
|
|
2616
|
+
...props,
|
|
2617
|
+
type: "checkbox",
|
|
2618
|
+
disabled: true,
|
|
2619
|
+
className: "mr-2 size-3.5 translate-y-[2px] cursor-default accent-og-accent align-baseline"
|
|
2620
|
+
}
|
|
2621
|
+
) : /* @__PURE__ */ jsx11("input", { type, ...props }),
|
|
2622
|
+
blockquote: ({ children, ...props }) => /* @__PURE__ */ jsx11(
|
|
2623
|
+
"blockquote",
|
|
2624
|
+
{
|
|
2625
|
+
className: "my-3 border-l-2 border-og-border-strong pl-3.5 text-og-fg-muted [&>p]:my-1.5 first:mt-0 last:mb-0",
|
|
2626
|
+
...props,
|
|
2627
|
+
children
|
|
2628
|
+
}
|
|
2629
|
+
),
|
|
2630
|
+
hr: (props) => /* @__PURE__ */ jsx11("hr", { className: "my-4 border-0 border-t border-og-border", ...props }),
|
|
2631
|
+
// Inline `code` vs fenced code blocks. react-markdown v10 no longer passes an
|
|
2632
|
+
// `inline` flag; a fenced block is a <code> whose parent is <pre> (styled by
|
|
2633
|
+
// the `pre` renderer), so a `code` reaching here is treated as inline.
|
|
2634
|
+
code: ({ children, className: _className, ...props }) => /* @__PURE__ */ jsx11(
|
|
2635
|
+
"code",
|
|
2636
|
+
{
|
|
2637
|
+
className: "rounded-og-xs border border-og-border bg-og-surface-1 px-1 py-0.5 font-og-mono text-og-sm text-og-fg",
|
|
2638
|
+
...props,
|
|
2639
|
+
children
|
|
2640
|
+
}
|
|
2641
|
+
),
|
|
2642
|
+
// Fenced code blocks — mirror the timeline's PayloadBlock <pre> styling for
|
|
2643
|
+
// visual consistency (bordered, scrollable, mono, surface background).
|
|
2644
|
+
pre: ({ children, ...props }) => /* @__PURE__ */ jsx11(
|
|
2645
|
+
"pre",
|
|
2646
|
+
{
|
|
2647
|
+
className: "my-3 max-h-96 overflow-auto rounded-og-md border border-og-border bg-og-bg/60 p-3 font-og-mono text-og-sm text-og-fg-muted [&>code]:border-0 [&>code]:bg-transparent [&>code]:p-0 [&>code]:text-inherit first:mt-0 last:mb-0",
|
|
2648
|
+
...props,
|
|
2649
|
+
children
|
|
2650
|
+
}
|
|
2651
|
+
),
|
|
2652
|
+
table: ({ children, ...props }) => /* @__PURE__ */ jsx11("div", { className: "my-3 max-w-full overflow-x-auto rounded-og-md border border-og-border first:mt-0 last:mb-0", children: /* @__PURE__ */ jsx11("table", { className: "w-full border-collapse text-og-base", ...props, children }) }),
|
|
2653
|
+
thead: ({ children, ...props }) => /* @__PURE__ */ jsx11("thead", { className: "bg-og-surface-1", ...props, children }),
|
|
2654
|
+
th: ({ children, ...props }) => /* @__PURE__ */ jsx11(
|
|
2655
|
+
"th",
|
|
2656
|
+
{
|
|
2657
|
+
className: "border-b border-og-border px-3 py-1.5 text-left font-medium text-og-fg",
|
|
2658
|
+
...props,
|
|
2659
|
+
children
|
|
2660
|
+
}
|
|
2661
|
+
),
|
|
2662
|
+
td: ({ children, ...props }) => /* @__PURE__ */ jsx11(
|
|
2663
|
+
"td",
|
|
2664
|
+
{
|
|
2665
|
+
className: "border-b border-og-border px-3 py-1.5 align-top text-og-fg-muted [tr:last-child>&]:border-b-0",
|
|
2666
|
+
...props,
|
|
2667
|
+
children
|
|
2668
|
+
}
|
|
2669
|
+
),
|
|
2670
|
+
img: ({ alt, ...props }) => /* @__PURE__ */ jsx11(
|
|
2671
|
+
"img",
|
|
2672
|
+
{
|
|
2673
|
+
alt: alt ?? "",
|
|
2674
|
+
className: "my-3 max-w-full rounded-og-md border border-og-border",
|
|
2675
|
+
...props
|
|
2676
|
+
}
|
|
2677
|
+
)
|
|
2678
|
+
};
|
|
2679
|
+
function MarkdownImpl({ children, className }) {
|
|
2680
|
+
return (
|
|
2681
|
+
// `min-w-0` lets the prose shrink inside flex parents (message bubbles) so
|
|
2682
|
+
// long links and code blocks wrap/scroll instead of forcing overflow.
|
|
2683
|
+
/* @__PURE__ */ jsx11("div", { className: cn("min-w-0 break-words", className), children: /* @__PURE__ */ jsx11(ReactMarkdown, { remarkPlugins: [remarkGfm], components, children }) })
|
|
2684
|
+
);
|
|
2685
|
+
}
|
|
2686
|
+
var Markdown = memo(MarkdownImpl);
|
|
2687
|
+
|
|
2688
|
+
// src/components/session-status.tsx
|
|
2689
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2690
|
+
var SESSION_STATUS_META = {
|
|
2691
|
+
queued: {
|
|
2692
|
+
label: "Queued",
|
|
2693
|
+
dotClassName: "bg-og-status-queued",
|
|
2694
|
+
badgeClassName: "text-og-fg-muted border-og-border bg-og-status-queued/10",
|
|
2695
|
+
pulse: true
|
|
2696
|
+
},
|
|
2697
|
+
running: {
|
|
2698
|
+
label: "Running",
|
|
2699
|
+
dotClassName: "bg-og-status-running",
|
|
2700
|
+
badgeClassName: "text-og-status-running border-og-status-running/30 bg-og-status-running/10",
|
|
2701
|
+
pulse: true
|
|
2702
|
+
},
|
|
2703
|
+
recovering: {
|
|
2704
|
+
label: "Recovering",
|
|
2705
|
+
dotClassName: "bg-og-status-running",
|
|
2706
|
+
badgeClassName: "text-og-status-running border-og-status-running/30 bg-og-status-running/10",
|
|
2707
|
+
pulse: true
|
|
2708
|
+
},
|
|
2709
|
+
waiting_capacity: {
|
|
2710
|
+
label: "Waiting for capacity",
|
|
2711
|
+
dotClassName: "bg-og-status-waiting",
|
|
2712
|
+
badgeClassName: "text-og-status-waiting border-og-status-waiting/35 bg-og-status-waiting/10",
|
|
2713
|
+
pulse: true
|
|
2714
|
+
},
|
|
2715
|
+
idle: {
|
|
2716
|
+
label: "Idle",
|
|
2717
|
+
dotClassName: "bg-og-status-idle",
|
|
2718
|
+
badgeClassName: "text-og-status-idle border-og-status-idle/30 bg-og-status-idle/10",
|
|
2719
|
+
pulse: false
|
|
2720
|
+
},
|
|
2721
|
+
requires_action: {
|
|
2722
|
+
label: "Waiting on you",
|
|
2723
|
+
dotClassName: "bg-og-status-waiting",
|
|
2724
|
+
badgeClassName: "text-og-status-waiting border-og-status-waiting/35 bg-og-status-waiting/10",
|
|
2725
|
+
pulse: true
|
|
2726
|
+
},
|
|
2727
|
+
failed: {
|
|
2728
|
+
label: "Failed",
|
|
2729
|
+
dotClassName: "bg-og-status-failed",
|
|
2730
|
+
badgeClassName: "text-og-status-failed border-og-status-failed/35 bg-og-status-failed/10",
|
|
2731
|
+
pulse: false
|
|
2732
|
+
},
|
|
2733
|
+
cancelled: {
|
|
2734
|
+
label: "Cancelled",
|
|
2735
|
+
dotClassName: "bg-og-status-cancelled",
|
|
2736
|
+
badgeClassName: "text-og-fg-subtle border-og-border bg-og-status-cancelled/10",
|
|
2737
|
+
pulse: false
|
|
2738
|
+
}
|
|
2739
|
+
};
|
|
2740
|
+
function SessionStatus({ status, label, size = "md", className }) {
|
|
2741
|
+
const meta = SESSION_STATUS_META[status];
|
|
2742
|
+
return /* @__PURE__ */ jsxs9(
|
|
2743
|
+
"span",
|
|
2744
|
+
{
|
|
2745
|
+
"data-status": status,
|
|
2746
|
+
className: cn(
|
|
2747
|
+
"og-root inline-flex shrink-0 items-center rounded-full border font-medium",
|
|
2748
|
+
size === "sm" ? "gap-1 px-1.5 py-px text-og-xs" : "gap-1.5 px-2 py-0.5 text-xs",
|
|
2749
|
+
meta.badgeClassName,
|
|
2750
|
+
className
|
|
2751
|
+
),
|
|
2752
|
+
children: [
|
|
2753
|
+
/* @__PURE__ */ jsx12(StatusDot, { status, className: size === "sm" ? "size-1" : "size-1.5" }),
|
|
2754
|
+
label ?? meta.label
|
|
2755
|
+
]
|
|
2756
|
+
}
|
|
2757
|
+
);
|
|
2758
|
+
}
|
|
2759
|
+
function StatusDot({ status, className }) {
|
|
2760
|
+
const meta = SESSION_STATUS_META[status];
|
|
2761
|
+
return /* @__PURE__ */ jsx12(
|
|
2762
|
+
"span",
|
|
2763
|
+
{
|
|
2764
|
+
className: cn(
|
|
2765
|
+
"relative inline-flex size-1.5 shrink-0 rounded-full",
|
|
2766
|
+
meta.dotClassName,
|
|
2767
|
+
className
|
|
2768
|
+
),
|
|
2769
|
+
children: meta.pulse ? /* @__PURE__ */ jsx12("span", { className: cn("absolute inset-0 animate-og-pulse rounded-full", meta.dotClassName) }) : null
|
|
2770
|
+
}
|
|
2771
|
+
);
|
|
2772
|
+
}
|
|
2773
|
+
|
|
2774
|
+
// src/components/message-timeline.tsx
|
|
2775
|
+
import {
|
|
2776
|
+
ArrowDownIcon,
|
|
2777
|
+
ArrowRightIcon as ArrowRightIcon2,
|
|
2778
|
+
BotIcon as BotIcon2,
|
|
2779
|
+
CheckCircle2Icon,
|
|
2780
|
+
CheckIcon as CheckIcon2,
|
|
2781
|
+
ChevronRightIcon as ChevronRightIcon3,
|
|
2782
|
+
PauseCircleIcon,
|
|
2783
|
+
PauseIcon,
|
|
2784
|
+
PencilLineIcon,
|
|
2785
|
+
PlayIcon,
|
|
2786
|
+
RefreshCwIcon,
|
|
2787
|
+
TargetIcon,
|
|
2788
|
+
Trash2Icon,
|
|
2789
|
+
TriangleAlertIcon as TriangleAlertIcon2,
|
|
2790
|
+
XCircleIcon
|
|
2791
|
+
} from "lucide-react";
|
|
2792
|
+
import { AnimatePresence as AnimatePresence2, motion as motion2 } from "motion/react";
|
|
2793
|
+
import { Collapsible as Collapsible3 } from "radix-ui";
|
|
2794
|
+
import {
|
|
2795
|
+
memo as memo2,
|
|
2796
|
+
useCallback as useCallback2,
|
|
2797
|
+
useEffect as useEffect4,
|
|
2798
|
+
useLayoutEffect,
|
|
2799
|
+
useMemo as useMemo2,
|
|
2800
|
+
useRef as useRef3,
|
|
2801
|
+
useState as useState8
|
|
2802
|
+
} from "react";
|
|
2803
|
+
import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2804
|
+
var INITIAL_MOUNTED_GROUPS = 1;
|
|
2805
|
+
function MessageTimeline({
|
|
2806
|
+
events,
|
|
2807
|
+
items,
|
|
2808
|
+
status,
|
|
2809
|
+
renderMessageText,
|
|
2810
|
+
onOpenSession,
|
|
2811
|
+
onMemoryClick,
|
|
2812
|
+
onReconnect,
|
|
2813
|
+
resolveProviderLogo,
|
|
2814
|
+
toolRegistry = defaultToolRegistry,
|
|
2815
|
+
autoFollow = true,
|
|
2816
|
+
hasOlder = false,
|
|
2817
|
+
loadingOlder = false,
|
|
2818
|
+
onLoadOlder,
|
|
2819
|
+
emptyState,
|
|
2820
|
+
className
|
|
2821
|
+
}) {
|
|
2822
|
+
const resolvedItems = useMemo2(() => items ?? buildTimeline(events ?? []), [items, events]);
|
|
2823
|
+
const allGroups = useMemo2(() => groupTimeline(resolvedItems), [resolvedItems]);
|
|
2824
|
+
const keyedGroups = useStableTimelineGroupKeys(allGroups);
|
|
2825
|
+
const { mountedGroups: groups, mountingOlderGroups } = useProgressivelyMountedGroups(keyedGroups);
|
|
2826
|
+
const firstGroupKey = allGroups[0] ? timelineGroupKey(allGroups[0]) : null;
|
|
2827
|
+
const scrollRef = useRef3(null);
|
|
2828
|
+
const topSentinelRef = useRef3(null);
|
|
2829
|
+
const previousBulkFirstKeyRef = useRef3(void 0);
|
|
2830
|
+
const [pinned, setPinned] = useState8(true);
|
|
2831
|
+
const [bulkActive, setBulkActive] = useState8(true);
|
|
2832
|
+
const [revealed, setRevealed] = useState8(false);
|
|
2833
|
+
const programmaticScrollTargetsRef = useRef3([]);
|
|
2834
|
+
const assignScrollTop = useCallback2((node, value) => {
|
|
2835
|
+
const previous = node.scrollTop;
|
|
2836
|
+
node.scrollTop = value;
|
|
2837
|
+
if (node.scrollTop === previous) {
|
|
2838
|
+
return;
|
|
2839
|
+
}
|
|
2840
|
+
const pending = programmaticScrollTargetsRef.current;
|
|
2841
|
+
pending.push(node.scrollTop);
|
|
2842
|
+
if (pending.length > 32) {
|
|
2843
|
+
pending.splice(0, pending.length - 32);
|
|
2844
|
+
}
|
|
2845
|
+
}, []);
|
|
2846
|
+
const pinnedRef = useRef3(true);
|
|
2847
|
+
const anchorRef = useRef3(null);
|
|
2848
|
+
const lastItem = resolvedItems[resolvedItems.length - 1];
|
|
2849
|
+
const streaming = lastItem !== void 0 && (lastItem.kind === "agent-message" || lastItem.kind === "reasoning") && lastItem.streaming;
|
|
2850
|
+
const working = status === "running" && !streaming;
|
|
2851
|
+
const firstKeyChangedForBulk = previousBulkFirstKeyRef.current !== void 0 && previousBulkFirstKeyRef.current !== firstGroupKey;
|
|
2852
|
+
const bulkRender = allGroups.length > 0 && (bulkActive || firstKeyChangedForBulk || mountingOlderGroups);
|
|
2853
|
+
const captureAnchor = useCallback2(() => {
|
|
2854
|
+
const node = scrollRef.current;
|
|
2855
|
+
const inner = node?.firstElementChild;
|
|
2856
|
+
if (!node || !inner) {
|
|
2857
|
+
anchorRef.current = null;
|
|
2858
|
+
return;
|
|
2859
|
+
}
|
|
2860
|
+
const containerTop = node.getBoundingClientRect().top;
|
|
2861
|
+
const findVisible = (selector) => {
|
|
2862
|
+
for (const candidate of inner.querySelectorAll(selector)) {
|
|
2863
|
+
if (candidate instanceof HTMLElement && candidate.dataset.ogTimelineChrome !== void 0) {
|
|
2864
|
+
continue;
|
|
2865
|
+
}
|
|
2866
|
+
const rect = candidate.getBoundingClientRect();
|
|
2867
|
+
if (rect.bottom > containerTop + 1 && rect.height > 0) {
|
|
2868
|
+
return candidate;
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
return null;
|
|
2872
|
+
};
|
|
2873
|
+
const anchor = findVisible("[data-og-timeline-row-anchor]") ?? findVisible("[data-og-timeline-group-anchor]");
|
|
2874
|
+
if (anchor) {
|
|
2875
|
+
const rect = anchor.getBoundingClientRect();
|
|
2876
|
+
anchorRef.current = { el: anchor, top: rect.top - containerTop };
|
|
2877
|
+
return;
|
|
2878
|
+
}
|
|
2879
|
+
anchorRef.current = null;
|
|
2880
|
+
}, []);
|
|
2881
|
+
const restoreAnchor = useCallback2(
|
|
2882
|
+
(node) => {
|
|
2883
|
+
if (autoFollow && pinnedRef.current) {
|
|
2884
|
+
assignScrollTop(node, node.scrollHeight);
|
|
2885
|
+
return;
|
|
2886
|
+
}
|
|
2887
|
+
const anchor = anchorRef.current;
|
|
2888
|
+
if (!anchor || !anchor.el.isConnected) {
|
|
2889
|
+
return;
|
|
2890
|
+
}
|
|
2891
|
+
const containerTop = node.getBoundingClientRect().top;
|
|
2892
|
+
const now = anchor.el.getBoundingClientRect().top - containerTop;
|
|
2893
|
+
const diff = now - anchor.top;
|
|
2894
|
+
if (diff !== 0) {
|
|
2895
|
+
assignScrollTop(node, node.scrollTop + diff);
|
|
2896
|
+
}
|
|
2897
|
+
},
|
|
2898
|
+
[assignScrollTop, autoFollow]
|
|
2899
|
+
);
|
|
2900
|
+
useLayoutEffect(() => {
|
|
2901
|
+
const node = scrollRef.current;
|
|
2902
|
+
if (node) {
|
|
2903
|
+
restoreAnchor(node);
|
|
2904
|
+
}
|
|
2905
|
+
if (!revealed && groups.length > 0) {
|
|
2906
|
+
setRevealed(true);
|
|
2907
|
+
}
|
|
2908
|
+
}, [resolvedItems, working, revealed, groups.length, restoreAnchor]);
|
|
2909
|
+
useLayoutEffect(() => {
|
|
2910
|
+
if (allGroups.length === 0 && revealed) {
|
|
2911
|
+
setRevealed(false);
|
|
2912
|
+
}
|
|
2913
|
+
}, [allGroups.length, revealed]);
|
|
2914
|
+
useLayoutEffect(() => {
|
|
2915
|
+
previousBulkFirstKeyRef.current = firstGroupKey;
|
|
2916
|
+
if (!bulkRender) {
|
|
2917
|
+
return;
|
|
2918
|
+
}
|
|
2919
|
+
setBulkActive(true);
|
|
2920
|
+
if (mountingOlderGroups) {
|
|
2921
|
+
return;
|
|
2922
|
+
}
|
|
2923
|
+
const frame = requestFrame(() => setBulkActive(false));
|
|
2924
|
+
return () => cancelFrame(frame);
|
|
2925
|
+
}, [bulkRender, firstGroupKey, mountingOlderGroups]);
|
|
2926
|
+
useEffect4(() => {
|
|
2927
|
+
const root = scrollRef.current;
|
|
2928
|
+
const target = topSentinelRef.current;
|
|
2929
|
+
if (!root || !target || mountingOlderGroups || !hasOlder || loadingOlder || !onLoadOlder || typeof IntersectionObserver === "undefined") {
|
|
2930
|
+
return;
|
|
2931
|
+
}
|
|
2932
|
+
const observer = new IntersectionObserver(
|
|
2933
|
+
(entries) => {
|
|
2934
|
+
if (entries.some((entry) => entry.isIntersecting)) {
|
|
2935
|
+
onLoadOlder();
|
|
2936
|
+
}
|
|
2937
|
+
},
|
|
2938
|
+
{ root, rootMargin: "1600px 0px 0px 0px" }
|
|
2939
|
+
);
|
|
2940
|
+
observer.observe(target);
|
|
2941
|
+
return () => observer.disconnect();
|
|
2942
|
+
}, [hasOlder, loadingOlder, onLoadOlder, firstGroupKey, mountingOlderGroups]);
|
|
2943
|
+
useEffect4(() => {
|
|
2944
|
+
const node = scrollRef.current;
|
|
2945
|
+
const inner = node?.firstElementChild;
|
|
2946
|
+
if (!node || !inner || typeof ResizeObserver === "undefined") {
|
|
2947
|
+
return;
|
|
2948
|
+
}
|
|
2949
|
+
const observer = new ResizeObserver(() => {
|
|
2950
|
+
const current = scrollRef.current;
|
|
2951
|
+
if (!current) {
|
|
2952
|
+
return;
|
|
2953
|
+
}
|
|
2954
|
+
restoreAnchor(current);
|
|
2955
|
+
});
|
|
2956
|
+
observer.observe(inner);
|
|
2957
|
+
return () => observer.disconnect();
|
|
2958
|
+
}, [restoreAnchor]);
|
|
2959
|
+
const onScroll = () => {
|
|
2960
|
+
const node = scrollRef.current;
|
|
2961
|
+
if (!node) {
|
|
2962
|
+
return;
|
|
2963
|
+
}
|
|
2964
|
+
const pending = programmaticScrollTargetsRef.current;
|
|
2965
|
+
const programmaticIndex = pending.findIndex((target) => Math.abs(node.scrollTop - target) <= 1);
|
|
2966
|
+
const programmatic = programmaticIndex >= 0;
|
|
2967
|
+
if (programmatic) {
|
|
2968
|
+
pending.splice(0, programmaticIndex + 1);
|
|
2969
|
+
} else {
|
|
2970
|
+
pending.length = 0;
|
|
2971
|
+
}
|
|
2972
|
+
const nextPinned = node.scrollHeight - node.scrollTop - node.clientHeight < 48;
|
|
2973
|
+
if (nextPinned || !programmatic) {
|
|
2974
|
+
pinnedRef.current = nextPinned;
|
|
2975
|
+
setPinned(nextPinned);
|
|
2976
|
+
}
|
|
2977
|
+
if (!programmatic) {
|
|
2978
|
+
captureAnchor();
|
|
2979
|
+
}
|
|
2980
|
+
};
|
|
2981
|
+
return /* @__PURE__ */ jsx13(LightboxProvider, { children: /* @__PURE__ */ jsx13(EntranceAnimationProvider, { value: !bulkRender, children: /* @__PURE__ */ jsxs10("div", { className: cn("og-root relative flex min-h-0 flex-col", className), children: [
|
|
2982
|
+
/* @__PURE__ */ jsx13(
|
|
2983
|
+
"div",
|
|
2984
|
+
{
|
|
2985
|
+
ref: scrollRef,
|
|
2986
|
+
onScroll,
|
|
2987
|
+
style: groups.length > 0 && !revealed ? { visibility: "hidden" } : void 0,
|
|
2988
|
+
className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-6 [overflow-anchor:none] sm:px-6",
|
|
2989
|
+
children: /* @__PURE__ */ jsxs10("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: [
|
|
2990
|
+
groups.length === 0 && !working ? emptyState ?? /* @__PURE__ */ jsx13("p", { className: "py-10 text-center text-sm text-og-fg-subtle", children: "No activity yet." }) : null,
|
|
2991
|
+
hasOlder && !mountingOlderGroups ? /* @__PURE__ */ jsx13(
|
|
2992
|
+
"div",
|
|
2993
|
+
{
|
|
2994
|
+
ref: topSentinelRef,
|
|
2995
|
+
"data-og-top-sentinel": "",
|
|
2996
|
+
"data-og-timeline-chrome": "",
|
|
2997
|
+
"aria-hidden": "true",
|
|
2998
|
+
className: "h-px w-full shrink-0"
|
|
2999
|
+
}
|
|
3000
|
+
) : null,
|
|
3001
|
+
loadingOlder ? /* @__PURE__ */ jsx13("div", { "data-og-timeline-chrome": "", className: "flex items-center gap-2 text-sm", children: /* @__PURE__ */ jsx13("span", { className: "og-shimmer-text font-medium", children: "Loading earlier activity\u2026" }) }) : null,
|
|
3002
|
+
groups.map(({ group, key }, index) => /* @__PURE__ */ jsx13("div", { "data-og-timeline-group-anchor": "", children: /* @__PURE__ */ jsx13(
|
|
3003
|
+
TimelineGroupView,
|
|
3004
|
+
{
|
|
3005
|
+
group,
|
|
3006
|
+
renderMessageText,
|
|
3007
|
+
onOpenSession,
|
|
3008
|
+
onMemoryClick,
|
|
3009
|
+
onReconnect,
|
|
3010
|
+
resolveProviderLogo,
|
|
3011
|
+
toolRegistry,
|
|
3012
|
+
foldLiveCluster: isAgentProgress(groups[index + 1]?.group)
|
|
3013
|
+
}
|
|
3014
|
+
) }, key)),
|
|
3015
|
+
working ? /* @__PURE__ */ jsx13("div", { className: "flex items-center gap-2 text-sm", children: /* @__PURE__ */ jsx13("span", { className: "og-shimmer-text font-medium", children: "Working\u2026" }) }) : null
|
|
3016
|
+
] })
|
|
3017
|
+
}
|
|
3018
|
+
),
|
|
3019
|
+
/* @__PURE__ */ jsx13(AnimatePresence2, { children: !pinned && autoFollow ? /* @__PURE__ */ jsxs10(
|
|
3020
|
+
motion2.button,
|
|
3021
|
+
{
|
|
3022
|
+
type: "button",
|
|
3023
|
+
initial: { opacity: 0, y: 8 },
|
|
3024
|
+
animate: { opacity: 1, y: 0 },
|
|
3025
|
+
exit: { opacity: 0, y: 8 },
|
|
3026
|
+
transition: { duration: 0.15, ease: "easeOut" },
|
|
3027
|
+
onClick: () => {
|
|
3028
|
+
const node = scrollRef.current;
|
|
3029
|
+
if (node) {
|
|
3030
|
+
node.scrollTo({ top: node.scrollHeight, behavior: "smooth" });
|
|
3031
|
+
}
|
|
3032
|
+
pinnedRef.current = true;
|
|
3033
|
+
setPinned(true);
|
|
3034
|
+
},
|
|
3035
|
+
className: cn(
|
|
3036
|
+
"absolute bottom-4 left-1/2 -translate-x-1/2",
|
|
3037
|
+
"inline-flex items-center gap-1.5 rounded-full border border-og-border bg-og-surface-3/90 px-3 py-1.5",
|
|
3038
|
+
"text-xs font-medium text-og-fg shadow-og-md backdrop-blur",
|
|
3039
|
+
"hover:border-og-border-strong"
|
|
3040
|
+
),
|
|
3041
|
+
children: [
|
|
3042
|
+
/* @__PURE__ */ jsx13(ArrowDownIcon, { className: "size-3.5" }),
|
|
3043
|
+
"Jump to latest"
|
|
3044
|
+
]
|
|
3045
|
+
}
|
|
3046
|
+
) : null })
|
|
3047
|
+
] }) }) });
|
|
3048
|
+
}
|
|
3049
|
+
function useStableTimelineGroupKeys(allGroups) {
|
|
3050
|
+
const previousRef = useRef3([]);
|
|
3051
|
+
const keyedGroups = useMemo2(() => {
|
|
3052
|
+
const previousByItemId = /* @__PURE__ */ new Map();
|
|
3053
|
+
for (const previous of previousRef.current) {
|
|
3054
|
+
for (const itemId of timelineGroupItemIds(previous.group)) {
|
|
3055
|
+
previousByItemId.set(itemId, previous);
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
const usedKeys = /* @__PURE__ */ new Set();
|
|
3059
|
+
return allGroups.map((group, index) => {
|
|
3060
|
+
const itemIds = timelineGroupItemIds(group);
|
|
3061
|
+
let retainedKey;
|
|
3062
|
+
for (const itemId of itemIds) {
|
|
3063
|
+
const previous = previousByItemId.get(itemId);
|
|
3064
|
+
if (previous && !usedKeys.has(previous.key)) {
|
|
3065
|
+
retainedKey = previous.key;
|
|
3066
|
+
break;
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3069
|
+
const canonicalKey = timelineGroupKey(group);
|
|
3070
|
+
let key = retainedKey ?? canonicalKey;
|
|
3071
|
+
let collision = 0;
|
|
3072
|
+
while (usedKeys.has(key)) {
|
|
3073
|
+
key = `${canonicalKey}:${index}:${collision}`;
|
|
3074
|
+
collision += 1;
|
|
3075
|
+
}
|
|
3076
|
+
usedKeys.add(key);
|
|
3077
|
+
return { group, key };
|
|
3078
|
+
});
|
|
3079
|
+
}, [allGroups]);
|
|
3080
|
+
useLayoutEffect(() => {
|
|
3081
|
+
previousRef.current = keyedGroups;
|
|
3082
|
+
}, [keyedGroups]);
|
|
3083
|
+
return keyedGroups;
|
|
3084
|
+
}
|
|
3085
|
+
function useProgressivelyMountedGroups(allGroups) {
|
|
3086
|
+
const previousGroupKeysRef = useRef3([]);
|
|
3087
|
+
const groupKeys = useMemo2(() => {
|
|
3088
|
+
const nextKeys = allGroups.map((group) => group.key);
|
|
3089
|
+
const previousKeys = previousGroupKeysRef.current;
|
|
3090
|
+
return nextKeys.length === previousKeys.length && nextKeys.every((key, index) => key === previousKeys[index]) ? previousKeys : nextKeys;
|
|
3091
|
+
}, [allGroups]);
|
|
3092
|
+
useLayoutEffect(() => {
|
|
3093
|
+
previousGroupKeysRef.current = groupKeys;
|
|
3094
|
+
}, [groupKeys]);
|
|
3095
|
+
const [window2, setWindow] = useState8(() => ({
|
|
3096
|
+
groupKeys,
|
|
3097
|
+
visibleStart: Math.max(0, allGroups.length - INITIAL_MOUNTED_GROUPS)
|
|
3098
|
+
}));
|
|
3099
|
+
const lastPossibleStart = Math.max(0, allGroups.length - INITIAL_MOUNTED_GROUPS);
|
|
3100
|
+
let visibleStart = 0;
|
|
3101
|
+
if (allGroups.length > 0) {
|
|
3102
|
+
const currentIndexByKey = new Map(groupKeys.map((key, index) => [key, index]));
|
|
3103
|
+
let retainedStart;
|
|
3104
|
+
for (const key of window2.groupKeys.slice(window2.visibleStart)) {
|
|
3105
|
+
const index = currentIndexByKey.get(key);
|
|
3106
|
+
if (index !== void 0) {
|
|
3107
|
+
retainedStart = index;
|
|
3108
|
+
break;
|
|
3109
|
+
}
|
|
3110
|
+
}
|
|
3111
|
+
visibleStart = retainedStart === void 0 ? lastPossibleStart : Math.min(retainedStart, lastPossibleStart);
|
|
3112
|
+
}
|
|
3113
|
+
useEffect4(() => {
|
|
3114
|
+
if (window2.groupKeys !== groupKeys || window2.visibleStart !== visibleStart) {
|
|
3115
|
+
setWindow({ groupKeys, visibleStart });
|
|
3116
|
+
return;
|
|
3117
|
+
}
|
|
3118
|
+
if (visibleStart === 0) {
|
|
3119
|
+
return;
|
|
3120
|
+
}
|
|
3121
|
+
const frame = requestFrame(() => {
|
|
3122
|
+
setWindow(
|
|
3123
|
+
(current) => current.groupKeys === groupKeys && current.visibleStart > 0 ? { ...current, visibleStart: current.visibleStart - 1 } : current
|
|
3124
|
+
);
|
|
3125
|
+
});
|
|
3126
|
+
return () => cancelFrame(frame);
|
|
3127
|
+
}, [groupKeys, visibleStart, window2.groupKeys, window2.visibleStart]);
|
|
3128
|
+
return {
|
|
3129
|
+
mountedGroups: allGroups.slice(visibleStart),
|
|
3130
|
+
mountingOlderGroups: visibleStart > 0
|
|
3131
|
+
};
|
|
3132
|
+
}
|
|
3133
|
+
function requestFrame(callback) {
|
|
3134
|
+
if (typeof requestAnimationFrame === "function") {
|
|
3135
|
+
return requestAnimationFrame(callback);
|
|
3136
|
+
}
|
|
3137
|
+
return window.setTimeout(() => callback(performance.now()), 16);
|
|
3138
|
+
}
|
|
3139
|
+
function cancelFrame(id) {
|
|
3140
|
+
if (typeof cancelAnimationFrame === "function") {
|
|
3141
|
+
cancelAnimationFrame(id);
|
|
3142
|
+
return;
|
|
3143
|
+
}
|
|
3144
|
+
window.clearTimeout(id);
|
|
3145
|
+
}
|
|
3146
|
+
var TimelineGroupView = memo2(function TimelineGroupView2({
|
|
3147
|
+
group,
|
|
3148
|
+
renderMessageText,
|
|
3149
|
+
onOpenSession,
|
|
3150
|
+
onMemoryClick,
|
|
3151
|
+
onReconnect,
|
|
3152
|
+
resolveProviderLogo,
|
|
3153
|
+
toolRegistry,
|
|
3154
|
+
insideTurn = false,
|
|
3155
|
+
foldLiveCluster = false
|
|
3156
|
+
}) {
|
|
3157
|
+
switch (group.kind) {
|
|
3158
|
+
case "activity":
|
|
3159
|
+
return group.outcome || foldLiveCluster && clusterIsSettled(group) ? /* @__PURE__ */ jsx13(
|
|
3160
|
+
TurnSummary,
|
|
3161
|
+
{
|
|
3162
|
+
items: group.items,
|
|
3163
|
+
outcome: group.outcome,
|
|
3164
|
+
failureText: insideTurn ? void 0 : group.failureText,
|
|
3165
|
+
defaultOpen: !insideTurn && group.outcome === "failed" ? true : void 0,
|
|
3166
|
+
bare: insideTurn,
|
|
3167
|
+
children: /* @__PURE__ */ jsx13(
|
|
3168
|
+
ActivityRail,
|
|
3169
|
+
{
|
|
3170
|
+
items: group.items,
|
|
3171
|
+
onOpenSession,
|
|
3172
|
+
onMemoryClick,
|
|
3173
|
+
toolRegistry,
|
|
3174
|
+
bare: insideTurn
|
|
3175
|
+
}
|
|
3176
|
+
)
|
|
3177
|
+
}
|
|
3178
|
+
) : (
|
|
3179
|
+
// A nested live cluster hangs on the turn's rail (bare); a top-level one
|
|
3180
|
+
// owns its own rail.
|
|
3181
|
+
/* @__PURE__ */ jsx13(
|
|
3182
|
+
ActivityRail,
|
|
3183
|
+
{
|
|
3184
|
+
items: group.items,
|
|
3185
|
+
onOpenSession,
|
|
3186
|
+
onMemoryClick,
|
|
3187
|
+
toolRegistry,
|
|
3188
|
+
bare: insideTurn
|
|
3189
|
+
}
|
|
3190
|
+
)
|
|
3191
|
+
);
|
|
3192
|
+
case "turn": {
|
|
3193
|
+
const activityItems = flattenActivityItems(group.groups);
|
|
3194
|
+
const body = group.groups.map((child) => /* @__PURE__ */ jsx13(
|
|
3195
|
+
TimelineGroupView2,
|
|
3196
|
+
{
|
|
3197
|
+
group: child,
|
|
3198
|
+
renderMessageText,
|
|
3199
|
+
onOpenSession,
|
|
3200
|
+
onMemoryClick,
|
|
3201
|
+
onReconnect,
|
|
3202
|
+
resolveProviderLogo,
|
|
3203
|
+
toolRegistry,
|
|
3204
|
+
insideTurn: true
|
|
3205
|
+
},
|
|
3206
|
+
timelineGroupKey(child)
|
|
3207
|
+
));
|
|
3208
|
+
return /* @__PURE__ */ jsx13(
|
|
3209
|
+
TurnSummary,
|
|
3210
|
+
{
|
|
3211
|
+
items: activityItems,
|
|
3212
|
+
outcome: group.outcome,
|
|
3213
|
+
failureText: insideTurn ? void 0 : group.failureText,
|
|
3214
|
+
durationMs: durationBetween(group.startedAt, group.endedAt),
|
|
3215
|
+
defaultOpen: !insideTurn && group.outcome === "failed" ? true : void 0,
|
|
3216
|
+
bare: insideTurn,
|
|
3217
|
+
children: insideTurn ? (
|
|
3218
|
+
// A nested turn is already on an ancestor rail — its body just stacks
|
|
3219
|
+
// flush (the bare-node body already indents it), so no second rule.
|
|
3220
|
+
/* @__PURE__ */ jsx13("div", { className: "flex flex-col gap-4", children: body })
|
|
3221
|
+
) : (
|
|
3222
|
+
// The top-level turn draws THE rail: one thin continuous rule that
|
|
3223
|
+
// every nested node and step hangs off of.
|
|
3224
|
+
/* @__PURE__ */ jsx13("div", { className: "flex flex-col gap-4 border-l-2 border-og-border pl-3 sm:pl-4", children: body })
|
|
3225
|
+
)
|
|
3226
|
+
}
|
|
3227
|
+
);
|
|
3228
|
+
}
|
|
3229
|
+
case "item":
|
|
3230
|
+
return /* @__PURE__ */ jsx13(
|
|
3231
|
+
TimelineRow,
|
|
3232
|
+
{
|
|
3233
|
+
item: group.item,
|
|
3234
|
+
renderMessageText,
|
|
3235
|
+
onReconnect,
|
|
3236
|
+
resolveProviderLogo,
|
|
3237
|
+
onOpenSession
|
|
3238
|
+
}
|
|
3239
|
+
);
|
|
3240
|
+
}
|
|
3241
|
+
});
|
|
3242
|
+
function timelineGroupKey(group) {
|
|
3243
|
+
switch (group.kind) {
|
|
3244
|
+
case "item":
|
|
3245
|
+
return group.item.id;
|
|
3246
|
+
case "activity":
|
|
3247
|
+
return group.id;
|
|
3248
|
+
case "turn":
|
|
3249
|
+
return group.id;
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
function timelineGroupItemIds(group) {
|
|
3253
|
+
switch (group.kind) {
|
|
3254
|
+
case "item":
|
|
3255
|
+
return [group.item.id];
|
|
3256
|
+
case "activity":
|
|
3257
|
+
return group.items.map((item) => item.id);
|
|
3258
|
+
case "turn":
|
|
3259
|
+
return group.groups.flatMap(timelineGroupItemIds);
|
|
3260
|
+
}
|
|
3261
|
+
}
|
|
3262
|
+
function isAgentProgress(next) {
|
|
3263
|
+
if (!next) {
|
|
3264
|
+
return false;
|
|
3265
|
+
}
|
|
3266
|
+
return next.kind === "activity" || next.kind === "turn" || next.kind === "item" && next.item.kind === "agent-message";
|
|
3267
|
+
}
|
|
3268
|
+
function clusterIsSettled(group) {
|
|
3269
|
+
return group.items.every((item) => {
|
|
3270
|
+
if (item.kind === "reasoning") {
|
|
3271
|
+
return !item.streaming;
|
|
3272
|
+
}
|
|
3273
|
+
if (item.kind === "memory" || item.kind === "fleet-decision") {
|
|
3274
|
+
return true;
|
|
3275
|
+
}
|
|
3276
|
+
return item.status !== "running";
|
|
3277
|
+
});
|
|
3278
|
+
}
|
|
3279
|
+
function flattenActivityItems(groups) {
|
|
3280
|
+
const items = [];
|
|
3281
|
+
for (const group of groups) {
|
|
3282
|
+
if (group.kind === "activity") {
|
|
3283
|
+
items.push(...group.items);
|
|
3284
|
+
} else if (group.kind === "turn") {
|
|
3285
|
+
items.push(...flattenActivityItems(group.groups));
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
return items;
|
|
3289
|
+
}
|
|
3290
|
+
function durationBetween(startedAt, endedAt) {
|
|
3291
|
+
const started = Date.parse(startedAt);
|
|
3292
|
+
const ended = Date.parse(endedAt);
|
|
3293
|
+
if (!Number.isFinite(started) || !Number.isFinite(ended) || ended < started) {
|
|
3294
|
+
return void 0;
|
|
3295
|
+
}
|
|
3296
|
+
return ended - started;
|
|
3297
|
+
}
|
|
3298
|
+
function TimelineRow({
|
|
3299
|
+
item,
|
|
3300
|
+
renderMessageText,
|
|
3301
|
+
onReconnect,
|
|
3302
|
+
resolveProviderLogo,
|
|
3303
|
+
onOpenSession
|
|
3304
|
+
}) {
|
|
3305
|
+
switch (item.kind) {
|
|
3306
|
+
case "user-message":
|
|
3307
|
+
return /* @__PURE__ */ jsx13(UserMessageRow, { item, renderMessageText });
|
|
3308
|
+
case "agent-message":
|
|
3309
|
+
return /* @__PURE__ */ jsx13(AgentMessageRow, { item, renderMessageText });
|
|
3310
|
+
case "worker-completion":
|
|
3311
|
+
return /* @__PURE__ */ jsx13(WorkerCompletionRow, { item, onOpenSession });
|
|
3312
|
+
case "session-status":
|
|
3313
|
+
return /* @__PURE__ */ jsx13(SessionStatusRow, { item });
|
|
3314
|
+
case "goal":
|
|
3315
|
+
return /* @__PURE__ */ jsx13(GoalRow, { item });
|
|
3316
|
+
case "notice":
|
|
3317
|
+
return /* @__PURE__ */ jsx13(NoticeRow, { item });
|
|
3318
|
+
case "auth-needed":
|
|
3319
|
+
return /* @__PURE__ */ jsx13(
|
|
3320
|
+
AuthNeededRow,
|
|
3321
|
+
{
|
|
3322
|
+
item,
|
|
3323
|
+
onReconnect,
|
|
3324
|
+
resolveProviderLogo
|
|
3325
|
+
}
|
|
3326
|
+
);
|
|
3327
|
+
default:
|
|
3328
|
+
return null;
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3331
|
+
function UserMessageRow({
|
|
3332
|
+
item,
|
|
3333
|
+
renderMessageText
|
|
3334
|
+
}) {
|
|
3335
|
+
const enter = useEntranceAnimation();
|
|
3336
|
+
return /* @__PURE__ */ jsx13("div", { className: cn(enter && "animate-og-enter", "flex justify-end"), children: /* @__PURE__ */ jsx13("div", { className: "flex max-w-[85%] min-w-0 flex-col items-end gap-1", children: /* @__PURE__ */ jsx13("div", { className: "w-fit max-w-full min-w-0 rounded-og-lg rounded-br-og-xs border border-og-border bg-og-surface-2 px-4 py-2.5 text-og-md leading-6 text-og-fg", children: renderMessageText ? renderMessageText(item.text, item) : /* @__PURE__ */ jsx13(Markdown, { children: item.text }) }) }) });
|
|
3337
|
+
}
|
|
3338
|
+
function AgentMessageRow({
|
|
3339
|
+
item,
|
|
3340
|
+
renderMessageText
|
|
3341
|
+
}) {
|
|
3342
|
+
const enter = useEntranceAnimation();
|
|
3343
|
+
const caret = item.streaming ? /* @__PURE__ */ jsx13(
|
|
3344
|
+
"span",
|
|
3345
|
+
{
|
|
3346
|
+
className: "ml-0.5 inline-block h-[1.1em] w-[2px] translate-y-[3px] animate-og-blink rounded-full bg-og-accent",
|
|
3347
|
+
"aria-hidden": true
|
|
3348
|
+
}
|
|
3349
|
+
) : null;
|
|
3350
|
+
return /* @__PURE__ */ jsx13("div", { className: cn(enter && "animate-og-enter", "min-w-0 text-og-md leading-7 text-og-fg"), children: renderMessageText ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
|
|
3351
|
+
renderMessageText(item.text, item),
|
|
3352
|
+
caret
|
|
3353
|
+
] }) : (
|
|
3354
|
+
// While streaming, let the caret ride the end of the last rendered line:
|
|
3355
|
+
// the trailing block (usually a <p>) flows inline so the caret sits on
|
|
3356
|
+
// its baseline instead of dropping to a new line.
|
|
3357
|
+
/* @__PURE__ */ jsxs10("div", { className: item.streaming ? "[&_>div>:last-child]:inline" : void 0, children: [
|
|
3358
|
+
/* @__PURE__ */ jsx13(Markdown, { children: item.text }),
|
|
3359
|
+
caret
|
|
3360
|
+
] })
|
|
3361
|
+
) });
|
|
3362
|
+
}
|
|
3363
|
+
function workerCompletionMeta(item) {
|
|
3364
|
+
if (item.childStatus === "failed") {
|
|
3365
|
+
return {
|
|
3366
|
+
label: "Worker failed",
|
|
3367
|
+
icon: XCircleIcon,
|
|
3368
|
+
iconClass: "text-og-status-failed",
|
|
3369
|
+
accentClass: "border-og-status-failed/60"
|
|
3370
|
+
};
|
|
3371
|
+
}
|
|
3372
|
+
if (item.goalStatus === "paused") {
|
|
3373
|
+
return {
|
|
3374
|
+
label: "Worker paused",
|
|
3375
|
+
icon: PauseCircleIcon,
|
|
3376
|
+
iconClass: "text-og-status-waiting",
|
|
3377
|
+
accentClass: "border-og-status-waiting/50"
|
|
3378
|
+
};
|
|
3379
|
+
}
|
|
3380
|
+
if (item.goalStatus === "completed") {
|
|
3381
|
+
return {
|
|
3382
|
+
label: "Worker completed",
|
|
3383
|
+
icon: CheckCircle2Icon,
|
|
3384
|
+
iconClass: "text-og-status-idle",
|
|
3385
|
+
accentClass: "border-og-status-idle/45"
|
|
3386
|
+
};
|
|
3387
|
+
}
|
|
3388
|
+
return {
|
|
3389
|
+
label: "Worker reported back",
|
|
3390
|
+
icon: BotIcon2,
|
|
3391
|
+
iconClass: "text-og-accent",
|
|
3392
|
+
accentClass: "border-og-border-strong"
|
|
3393
|
+
};
|
|
3394
|
+
}
|
|
3395
|
+
function WorkerCompletionRow({
|
|
3396
|
+
item,
|
|
3397
|
+
onOpenSession
|
|
3398
|
+
}) {
|
|
3399
|
+
const enter = useEntranceAnimation();
|
|
3400
|
+
const [open, setOpen] = useState8(false);
|
|
3401
|
+
const meta = workerCompletionMeta(item);
|
|
3402
|
+
const Icon = meta.icon;
|
|
3403
|
+
const showPausedReason = item.childStatus !== "failed" && item.goalStatus === "paused" && Boolean(item.pausedReason?.trim());
|
|
3404
|
+
const details = [
|
|
3405
|
+
...item.text.trim() ? [{ label: "Report", value: item.text.trim() }] : [],
|
|
3406
|
+
...item.evidence?.trim() ? [{ label: "Evidence", value: item.evidence.trim(), muted: true }] : [],
|
|
3407
|
+
...showPausedReason ? [{ label: "Paused because", value: item.pausedReason.trim(), muted: true }] : []
|
|
3408
|
+
];
|
|
3409
|
+
const hasDetails = details.length > 0;
|
|
3410
|
+
return /* @__PURE__ */ jsx13("div", { className: cn(enter && "animate-og-enter", "min-w-0"), children: /* @__PURE__ */ jsxs10("div", { className: cn("flex flex-col gap-2 border-l-2 pl-3", meta.accentClass), children: [
|
|
3411
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex items-start gap-2.5", children: [
|
|
3412
|
+
/* @__PURE__ */ jsx13("span", { className: cn("mt-0.5 shrink-0", meta.iconClass), children: /* @__PURE__ */ jsx13(Icon, { className: "size-4" }) }),
|
|
3413
|
+
/* @__PURE__ */ jsx13("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsxs10("p", { className: "text-og-base leading-5 text-og-fg", children: [
|
|
3414
|
+
/* @__PURE__ */ jsx13("span", { className: "font-medium", children: meta.label }),
|
|
3415
|
+
item.goalText ? /* @__PURE__ */ jsxs10("span", { className: "text-og-fg-muted", children: [
|
|
3416
|
+
" \xB7 ",
|
|
3417
|
+
truncate(item.goalText, 90)
|
|
3418
|
+
] }) : null
|
|
3419
|
+
] }) }),
|
|
3420
|
+
item.childSessionId && onOpenSession ? /* @__PURE__ */ jsxs10(
|
|
3421
|
+
"button",
|
|
3422
|
+
{
|
|
3423
|
+
type: "button",
|
|
3424
|
+
onClick: () => onOpenSession(item.childSessionId),
|
|
3425
|
+
className: cn(
|
|
3426
|
+
"-my-0.5 -mr-1 inline-flex shrink-0 items-center gap-1 rounded-og-sm px-2 py-1 text-og-sm font-medium text-og-fg-muted pointer-coarse:py-2",
|
|
3427
|
+
"outline-none transition-colors duration-150 hover:bg-og-surface-2 hover:text-og-fg",
|
|
3428
|
+
"focus-visible:ring-2 focus-visible:ring-og-accent"
|
|
3429
|
+
),
|
|
3430
|
+
children: [
|
|
3431
|
+
"View session",
|
|
3432
|
+
/* @__PURE__ */ jsx13(ArrowRightIcon2, { className: "size-3.5" })
|
|
3433
|
+
]
|
|
3434
|
+
}
|
|
3435
|
+
) : null
|
|
3436
|
+
] }),
|
|
3437
|
+
hasDetails ? /* @__PURE__ */ jsxs10(Collapsible3.Root, { open, onOpenChange: setOpen, children: [
|
|
3438
|
+
/* @__PURE__ */ jsx13(Collapsible3.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs10(
|
|
3439
|
+
"button",
|
|
3440
|
+
{
|
|
3441
|
+
type: "button",
|
|
3442
|
+
className: cn(
|
|
3443
|
+
"group/wc -mx-1 inline-flex w-fit items-center gap-1 rounded-og-sm px-1 py-0.5 text-og-xs font-medium text-og-fg-subtle",
|
|
3444
|
+
"outline-none transition-colors duration-150 hover:text-og-fg-muted focus-visible:ring-2 focus-visible:ring-og-accent"
|
|
3445
|
+
),
|
|
3446
|
+
children: [
|
|
3447
|
+
/* @__PURE__ */ jsx13(ChevronRightIcon3, { className: "size-3 transition-transform duration-150 ease-og-in-out group-data-[state=open]/wc:rotate-90" }),
|
|
3448
|
+
open ? "Hide details" : "Show details"
|
|
3449
|
+
]
|
|
3450
|
+
}
|
|
3451
|
+
) }),
|
|
3452
|
+
/* @__PURE__ */ jsx13(Collapsible3.Content, { className: "overflow-hidden data-[state=closed]:animate-og-collapse data-[state=open]:animate-og-expand", children: /* @__PURE__ */ jsx13("div", { className: "ml-1 mt-1.5 flex flex-col gap-2.5", children: details.map((detail) => /* @__PURE__ */ jsxs10("div", { className: "min-w-0", children: [
|
|
3453
|
+
/* @__PURE__ */ jsx13("p", { className: "mb-1 text-og-xs font-medium uppercase tracking-[0.08em] text-og-fg-subtle", children: detail.label }),
|
|
3454
|
+
/* @__PURE__ */ jsx13(
|
|
3455
|
+
"p",
|
|
3456
|
+
{
|
|
3457
|
+
className: cn(
|
|
3458
|
+
"whitespace-pre-wrap break-words text-og-sm leading-6",
|
|
3459
|
+
detail.muted ? "text-og-fg-subtle" : "text-og-fg-muted"
|
|
3460
|
+
),
|
|
3461
|
+
children: detail.value
|
|
3462
|
+
}
|
|
3463
|
+
)
|
|
3464
|
+
] }, detail.label)) }) })
|
|
3465
|
+
] }) : null
|
|
3466
|
+
] }) });
|
|
3467
|
+
}
|
|
3468
|
+
function SessionStatusRow({ item }) {
|
|
3469
|
+
const enter = useEntranceAnimation();
|
|
3470
|
+
const meta = SESSION_STATUS_META[item.status];
|
|
3471
|
+
return /* @__PURE__ */ jsxs10(
|
|
3472
|
+
"div",
|
|
3473
|
+
{
|
|
3474
|
+
className: cn(
|
|
3475
|
+
enter && "animate-og-enter",
|
|
3476
|
+
"flex items-center gap-3 text-og-xs text-og-fg-subtle"
|
|
3477
|
+
),
|
|
3478
|
+
role: "status",
|
|
3479
|
+
children: [
|
|
3480
|
+
/* @__PURE__ */ jsx13("span", { className: "h-px flex-1 bg-og-border" }),
|
|
3481
|
+
/* @__PURE__ */ jsxs10("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
3482
|
+
/* @__PURE__ */ jsx13(StatusDot, { status: item.status, className: "size-1" }),
|
|
3483
|
+
meta.label.toLowerCase(),
|
|
3484
|
+
" \xB7 ",
|
|
3485
|
+
formatRelativeTime(item.occurredAt)
|
|
3486
|
+
] }),
|
|
3487
|
+
/* @__PURE__ */ jsx13("span", { className: "h-px flex-1 bg-og-border" })
|
|
3488
|
+
]
|
|
3489
|
+
}
|
|
3490
|
+
);
|
|
3491
|
+
}
|
|
3492
|
+
var NEUTRAL_PILL = "border-og-border bg-og-surface-1 text-og-fg-muted";
|
|
3493
|
+
var GOAL_META = {
|
|
3494
|
+
set: {
|
|
3495
|
+
label: "Goal set",
|
|
3496
|
+
pill: "border-og-accent/30 bg-og-accent/10 text-og-accent",
|
|
3497
|
+
icon: TargetIcon
|
|
3498
|
+
},
|
|
3499
|
+
updated: { label: "Goal updated", pill: NEUTRAL_PILL, icon: PencilLineIcon },
|
|
3500
|
+
completed: {
|
|
3501
|
+
label: "Goal completed",
|
|
3502
|
+
pill: "border-og-status-idle/30 bg-og-status-idle/10 text-og-status-idle",
|
|
3503
|
+
icon: CheckIcon2
|
|
3504
|
+
},
|
|
3505
|
+
paused: {
|
|
3506
|
+
label: "Goal paused",
|
|
3507
|
+
pill: "border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting",
|
|
3508
|
+
icon: PauseIcon
|
|
3509
|
+
},
|
|
3510
|
+
resumed: { label: "Goal resumed", pill: NEUTRAL_PILL, icon: PlayIcon },
|
|
3511
|
+
cleared: { label: "Goal cleared", pill: NEUTRAL_PILL, icon: Trash2Icon },
|
|
3512
|
+
continuation: { label: "Continuing toward the goal", pill: NEUTRAL_PILL, icon: ArrowRightIcon2 }
|
|
3513
|
+
};
|
|
3514
|
+
function GoalRow({ item }) {
|
|
3515
|
+
const enter = useEntranceAnimation();
|
|
3516
|
+
const { label, pill, icon: Icon } = GOAL_META[item.action];
|
|
3517
|
+
return /* @__PURE__ */ jsx13("div", { className: cn(enter && "animate-og-enter", "flex justify-center"), children: /* @__PURE__ */ jsxs10(
|
|
3518
|
+
"span",
|
|
3519
|
+
{
|
|
3520
|
+
className: cn(
|
|
3521
|
+
"inline-flex max-w-full items-center gap-1.5 rounded-full border px-3 py-1 text-og-sm",
|
|
3522
|
+
pill
|
|
3523
|
+
),
|
|
3524
|
+
children: [
|
|
3525
|
+
/* @__PURE__ */ jsx13(Icon, { className: "size-3.5 shrink-0" }),
|
|
3526
|
+
/* @__PURE__ */ jsxs10("span", { className: "truncate", children: [
|
|
3527
|
+
label,
|
|
3528
|
+
item.text ? `: ${truncate(item.text, 90)}` : ""
|
|
3529
|
+
] })
|
|
3530
|
+
]
|
|
3531
|
+
}
|
|
3532
|
+
) });
|
|
3533
|
+
}
|
|
3534
|
+
function NoticeRow({ item }) {
|
|
3535
|
+
const enter = useEntranceAnimation();
|
|
3536
|
+
const tone = item.tone === "failed" ? "border-og-status-failed/35 bg-og-status-failed/10 text-og-status-failed" : item.tone === "waiting" ? "border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting" : "border-og-border bg-og-surface-1 text-og-fg-muted";
|
|
3537
|
+
return /* @__PURE__ */ jsxs10(
|
|
3538
|
+
"div",
|
|
3539
|
+
{
|
|
3540
|
+
className: cn(
|
|
3541
|
+
enter && "animate-og-enter",
|
|
3542
|
+
"flex items-start gap-2.5 rounded-og-md border px-3.5 py-2.5 text-sm",
|
|
3543
|
+
tone
|
|
3544
|
+
),
|
|
3545
|
+
role: "status",
|
|
3546
|
+
children: [
|
|
3547
|
+
/* @__PURE__ */ jsx13(
|
|
3548
|
+
TriangleAlertIcon2,
|
|
3549
|
+
{
|
|
3550
|
+
className: cn("mt-0.5 size-4 shrink-0", item.tone === "cancelled" && "opacity-60")
|
|
3551
|
+
}
|
|
3552
|
+
),
|
|
3553
|
+
/* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1", children: [
|
|
3554
|
+
/* @__PURE__ */ jsx13("span", { className: "whitespace-pre-wrap break-words", children: item.text }),
|
|
3555
|
+
item.details ? /* @__PURE__ */ jsxs10("details", { className: "mt-2 text-xs", children: [
|
|
3556
|
+
/* @__PURE__ */ jsx13("summary", { className: "cursor-pointer font-medium", children: item.details.label }),
|
|
3557
|
+
/* @__PURE__ */ jsx13("pre", { className: "mt-2 max-h-64 overflow-auto whitespace-pre-wrap break-all rounded-og-sm bg-black/5 p-2 font-mono dark:bg-white/5", children: JSON.stringify(item.details.value, null, 2) })
|
|
3558
|
+
] }) : null
|
|
3559
|
+
] }),
|
|
3560
|
+
item.action ? /* @__PURE__ */ jsx13(
|
|
3561
|
+
"a",
|
|
3562
|
+
{
|
|
3563
|
+
className: "shrink-0 rounded-og-sm border border-current/25 px-2 py-1 text-xs font-medium hover:bg-current/10",
|
|
3564
|
+
href: item.action.url,
|
|
3565
|
+
rel: "noreferrer",
|
|
3566
|
+
target: "_blank",
|
|
3567
|
+
children: item.action.label
|
|
3568
|
+
}
|
|
3569
|
+
) : null
|
|
3570
|
+
]
|
|
3571
|
+
}
|
|
3572
|
+
);
|
|
3573
|
+
}
|
|
3574
|
+
function AuthNeededRow({
|
|
3575
|
+
item,
|
|
3576
|
+
onReconnect,
|
|
3577
|
+
resolveProviderLogo
|
|
3578
|
+
}) {
|
|
3579
|
+
const enter = useEntranceAnimation();
|
|
3580
|
+
const [busy, setBusy] = useState8(false);
|
|
3581
|
+
const [failed, setFailed] = useState8(false);
|
|
3582
|
+
const provider = providerLabel(item.providerDomain);
|
|
3583
|
+
const unavailable = item.reason === "unsupported_auth" || item.reason === "resource_scope_unavailable";
|
|
3584
|
+
const missing = item.reason === "missing_connection";
|
|
3585
|
+
const actionLabel = missing ? "Connect" : "Reconnect";
|
|
3586
|
+
const start = async () => {
|
|
3587
|
+
if (!onReconnect || busy) {
|
|
3588
|
+
return;
|
|
3589
|
+
}
|
|
3590
|
+
setBusy(true);
|
|
3591
|
+
setFailed(false);
|
|
3592
|
+
try {
|
|
3593
|
+
await onReconnect(item);
|
|
3594
|
+
setBusy(false);
|
|
3595
|
+
} catch {
|
|
3596
|
+
setFailed(true);
|
|
3597
|
+
setBusy(false);
|
|
3598
|
+
}
|
|
3599
|
+
};
|
|
3600
|
+
return /* @__PURE__ */ jsxs10("div", { className: cn(enter && "animate-og-enter", "flex flex-col gap-2"), role: "status", children: [
|
|
3601
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-3 rounded-og-lg border border-og-border bg-og-surface-1 px-3.5 py-3 sm:flex-row sm:items-center", children: [
|
|
3602
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [
|
|
3603
|
+
/* @__PURE__ */ jsx13(
|
|
3604
|
+
AuthProviderLogo,
|
|
3605
|
+
{
|
|
3606
|
+
src: resolveProviderLogo?.(item.providerDomain) ?? null,
|
|
3607
|
+
label: provider
|
|
3608
|
+
}
|
|
3609
|
+
),
|
|
3610
|
+
/* @__PURE__ */ jsxs10("div", { className: "min-w-0", children: [
|
|
3611
|
+
/* @__PURE__ */ jsx13("p", { className: "truncate text-og-md font-medium text-og-fg", children: unavailable ? `${provider} tools unavailable` : `${actionLabel} ${provider}` }),
|
|
3612
|
+
/* @__PURE__ */ jsx13("p", { className: "truncate text-og-sm text-og-fg-subtle", children: authReasonLine(item.reason) })
|
|
3613
|
+
] })
|
|
3614
|
+
] }),
|
|
3615
|
+
!unavailable && onReconnect ? /* @__PURE__ */ jsxs10(
|
|
3616
|
+
"button",
|
|
3617
|
+
{
|
|
3618
|
+
type: "button",
|
|
3619
|
+
onClick: () => void start(),
|
|
3620
|
+
disabled: busy,
|
|
3621
|
+
className: cn(
|
|
3622
|
+
"inline-flex w-full shrink-0 items-center justify-center gap-1.5 rounded-og-md bg-og-accent px-3 py-1.5 text-sm font-medium text-og-accent-fg sm:w-auto",
|
|
3623
|
+
"transition-colors hover:bg-og-accent-strong disabled:opacity-70 pointer-coarse:min-h-9"
|
|
3624
|
+
),
|
|
3625
|
+
children: [
|
|
3626
|
+
/* @__PURE__ */ jsx13(RefreshCwIcon, { className: cn("size-3.5", busy && "animate-og-spin"), "aria-hidden": true }),
|
|
3627
|
+
busy ? "Opening\u2026" : actionLabel
|
|
3628
|
+
]
|
|
3629
|
+
}
|
|
3630
|
+
) : !unavailable && item.authorizationUrl ? /* @__PURE__ */ jsxs10(
|
|
3631
|
+
"a",
|
|
3632
|
+
{
|
|
3633
|
+
href: item.authorizationUrl,
|
|
3634
|
+
rel: "noreferrer",
|
|
3635
|
+
target: "_blank",
|
|
3636
|
+
className: cn(
|
|
3637
|
+
"inline-flex w-full shrink-0 items-center justify-center gap-1.5 rounded-og-md bg-og-accent px-3 py-1.5 text-sm font-medium text-og-accent-fg sm:w-auto",
|
|
3638
|
+
"transition-colors hover:bg-og-accent-strong pointer-coarse:min-h-9"
|
|
3639
|
+
),
|
|
3640
|
+
children: [
|
|
3641
|
+
/* @__PURE__ */ jsx13(RefreshCwIcon, { className: "size-3.5", "aria-hidden": true }),
|
|
3642
|
+
actionLabel
|
|
3643
|
+
]
|
|
3644
|
+
}
|
|
3645
|
+
) : null
|
|
3646
|
+
] }),
|
|
3647
|
+
!unavailable ? /* @__PURE__ */ jsxs10("p", { className: "px-1 text-og-xs text-og-fg-subtle", children: [
|
|
3648
|
+
"This tool call wasn't replayed. After ",
|
|
3649
|
+
missing ? "connecting" : "reconnecting",
|
|
3650
|
+
", send a new message to try again."
|
|
3651
|
+
] }) : null,
|
|
3652
|
+
failed ? /* @__PURE__ */ jsxs10("p", { className: "px-1 text-og-xs text-og-status-failed", children: [
|
|
3653
|
+
"Couldn't start ",
|
|
3654
|
+
missing ? "connecting" : "reconnecting",
|
|
3655
|
+
" ",
|
|
3656
|
+
provider,
|
|
3657
|
+
". Try again."
|
|
3658
|
+
] }) : null
|
|
3659
|
+
] });
|
|
3660
|
+
}
|
|
3661
|
+
function AuthProviderLogo({ src, label }) {
|
|
3662
|
+
const [failed, setFailed] = useState8(false);
|
|
3663
|
+
useEffect4(() => setFailed(false), [src]);
|
|
3664
|
+
const showImage = src && !failed;
|
|
3665
|
+
return /* @__PURE__ */ jsx13(
|
|
3666
|
+
"span",
|
|
3667
|
+
{
|
|
3668
|
+
className: "relative flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-og-md border border-og-border bg-og-surface-2 text-sm font-semibold text-og-fg-muted",
|
|
3669
|
+
"aria-hidden": true,
|
|
3670
|
+
children: showImage ? /* @__PURE__ */ jsx13(
|
|
3671
|
+
"img",
|
|
3672
|
+
{
|
|
3673
|
+
src,
|
|
3674
|
+
alt: "",
|
|
3675
|
+
loading: "lazy",
|
|
3676
|
+
decoding: "async",
|
|
3677
|
+
className: "size-full object-contain p-1.5",
|
|
3678
|
+
onError: () => setFailed(true)
|
|
3679
|
+
}
|
|
3680
|
+
) : /* @__PURE__ */ jsx13("span", { children: monogram(label) })
|
|
3681
|
+
}
|
|
3682
|
+
);
|
|
3683
|
+
}
|
|
3684
|
+
function monogram(label) {
|
|
3685
|
+
const words = label.trim().split(/\s+/).filter(Boolean);
|
|
3686
|
+
if (words.length === 0) {
|
|
3687
|
+
return "?";
|
|
3688
|
+
}
|
|
3689
|
+
if (words.length === 1) {
|
|
3690
|
+
return words[0].slice(0, 2).toUpperCase();
|
|
3691
|
+
}
|
|
3692
|
+
return (words[0][0] + words[1][0]).toUpperCase();
|
|
3693
|
+
}
|
|
3694
|
+
function providerLabel(domain) {
|
|
3695
|
+
const host = domain.trim().replace(/^https?:\/\//, "").replace(/^www\./, "").split("/")[0] ?? "";
|
|
3696
|
+
const first = host.split(".")[0] ?? host;
|
|
3697
|
+
if (!first) {
|
|
3698
|
+
return "this service";
|
|
3699
|
+
}
|
|
3700
|
+
return first.charAt(0).toUpperCase() + first.slice(1);
|
|
3701
|
+
}
|
|
3702
|
+
function authReasonLine(reason) {
|
|
3703
|
+
switch (reason) {
|
|
3704
|
+
case "insufficient_scope":
|
|
3705
|
+
return "It needs additional access to continue.";
|
|
3706
|
+
case "missing_connection":
|
|
3707
|
+
return "It isn't connected yet.";
|
|
3708
|
+
case "expired":
|
|
3709
|
+
case "refresh_failed":
|
|
3710
|
+
return "Its access expired.";
|
|
3711
|
+
case "unsupported_auth":
|
|
3712
|
+
return "This connection cannot authenticate the configured tool endpoint.";
|
|
3713
|
+
case "resource_scope_unavailable":
|
|
3714
|
+
return "This tool endpoint cannot enforce the selected repository access.";
|
|
3715
|
+
default:
|
|
3716
|
+
return "Its connection needs attention.";
|
|
3717
|
+
}
|
|
3718
|
+
}
|
|
3719
|
+
|
|
3720
|
+
export {
|
|
3721
|
+
QueueSurface,
|
|
3722
|
+
defaultHumanInputFormMessages,
|
|
3723
|
+
HumanInputForm,
|
|
3724
|
+
answersFromDrafts,
|
|
3725
|
+
rawTypeOf,
|
|
3726
|
+
createToolRegistry,
|
|
3727
|
+
sandboxCommandExitCode,
|
|
3728
|
+
parseExecBannerSessionId,
|
|
3729
|
+
stripExecBanner,
|
|
3730
|
+
execTruncated,
|
|
3731
|
+
isExecSessionLostBanner,
|
|
3732
|
+
looksBinary,
|
|
3733
|
+
controlCaret,
|
|
3734
|
+
v4aToGitFileDiff,
|
|
3735
|
+
applyPatchOps,
|
|
3736
|
+
isApplyPatch,
|
|
3737
|
+
redactSecrets,
|
|
3738
|
+
parseToolArgs,
|
|
3739
|
+
tailPeek,
|
|
3740
|
+
unwrapMcpOutput,
|
|
3741
|
+
DisclosureDefaultsProvider,
|
|
3742
|
+
useLightbox,
|
|
3743
|
+
useLightboxOptional,
|
|
3744
|
+
LightboxProvider,
|
|
3745
|
+
ActivityDisclosure,
|
|
3746
|
+
TermBlock,
|
|
3747
|
+
PayloadBlock,
|
|
3748
|
+
BodyNote,
|
|
3749
|
+
MediaSkeleton,
|
|
3750
|
+
MediaEmpty,
|
|
3751
|
+
Thumbnail,
|
|
3752
|
+
ScreenshotFigure,
|
|
3753
|
+
useThemeType,
|
|
3754
|
+
gitFileDiffToPatch,
|
|
3755
|
+
PierreDiff,
|
|
3756
|
+
defaultToolRegistry,
|
|
3757
|
+
createDefaultToolRegistry,
|
|
3758
|
+
ActivityRail,
|
|
3759
|
+
TurnSummary,
|
|
3760
|
+
Markdown,
|
|
3761
|
+
SESSION_STATUS_META,
|
|
3762
|
+
SessionStatus,
|
|
3763
|
+
StatusDot,
|
|
3764
|
+
MessageTimeline,
|
|
3765
|
+
TimelineRow
|
|
3766
|
+
};
|
|
3767
|
+
//# sourceMappingURL=chunk-GQN2QIR2.js.map
|