@mlpal/yodex-ui 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/dist/client/types.d.ts +3 -0
- package/dist/client/useYodexSession.d.ts +6 -0
- package/dist/components/ApprovalPrompt.d.ts +7 -0
- package/dist/components/Composer.d.ts +11 -7
- package/dist/components/PermissionPrompt.d.ts +8 -3
- package/dist/components/RunStatus.d.ts +3 -1
- package/dist/components/Transcript.d.ts +7 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +459 -299
- package/dist/index.js.map +12 -11
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ class YodexClient {
|
|
|
9
9
|
seq = 0;
|
|
10
10
|
state = "closed";
|
|
11
11
|
constructor(options) {
|
|
12
|
+
const given = Object.fromEntries(Object.entries(options).filter(([, v]) => v !== undefined));
|
|
12
13
|
this.opts = {
|
|
13
14
|
backoffMs: { min: 500, max: 1e4 },
|
|
14
15
|
requestTimeoutMs: 15000,
|
|
@@ -16,7 +17,7 @@ class YodexClient {
|
|
|
16
17
|
setTimer: (fn, ms) => setTimeout(fn, ms),
|
|
17
18
|
clearTimer: (h) => clearTimeout(h),
|
|
18
19
|
random: Math.random,
|
|
19
|
-
...
|
|
20
|
+
...given
|
|
20
21
|
};
|
|
21
22
|
}
|
|
22
23
|
get url() {
|
|
@@ -295,8 +296,19 @@ function applyEvent(state, ev, live) {
|
|
|
295
296
|
}
|
|
296
297
|
function reduce(state, action) {
|
|
297
298
|
switch (action.type) {
|
|
298
|
-
case "connection":
|
|
299
|
-
|
|
299
|
+
case "connection": {
|
|
300
|
+
if (action.state === "connected" || !state.running)
|
|
301
|
+
return { ...state, connection: action.state };
|
|
302
|
+
return {
|
|
303
|
+
...state,
|
|
304
|
+
connection: action.state,
|
|
305
|
+
running: false,
|
|
306
|
+
activity: undefined,
|
|
307
|
+
pendingPermissions: [],
|
|
308
|
+
pendingQuestion: undefined,
|
|
309
|
+
items: [...dropDraft(state.items), { kind: "error", id: nextId("e"), message: "Connection lost while the agent was working; what streamed so far was kept.", ts: new Date().toISOString() }]
|
|
310
|
+
};
|
|
311
|
+
}
|
|
300
312
|
case "clear":
|
|
301
313
|
return { ...initialState(), connection: state.connection, protocol: state.protocol, capabilities: state.capabilities, hop: state.hop, rootCwd: state.rootCwd, sessions: state.sessions, models: state.models, skills: state.skills };
|
|
302
314
|
case "error":
|
|
@@ -324,10 +336,16 @@ function reduce(state, action) {
|
|
|
324
336
|
case "ready":
|
|
325
337
|
return { ...state, connection: "connected", protocol: m.protocol, capabilities: m.capabilities ?? [], hop: m.hop, rootCwd: m.cwd };
|
|
326
338
|
case "event":
|
|
339
|
+
if (state.sessionId && m.sessionId !== state.sessionId)
|
|
340
|
+
return state;
|
|
327
341
|
return applyEvent(state.sessionId ? state : { ...state, sessionId: m.sessionId }, m.event, true);
|
|
328
342
|
case "permission_request":
|
|
329
|
-
|
|
343
|
+
if (state.sessionId && m.sessionId !== state.sessionId)
|
|
344
|
+
return state;
|
|
345
|
+
return { ...state, pendingPermissions: [...state.pendingPermissions, { id: m.id, sessionId: m.sessionId, toolName: m.toolName, input: m.input, ...m.reason ? { reason: m.reason } : {}, ...m.safetyReason ? { safetyReason: m.safetyReason } : {} }] };
|
|
330
346
|
case "question_request":
|
|
347
|
+
if (state.sessionId && m.sessionId !== state.sessionId)
|
|
348
|
+
return state;
|
|
331
349
|
return { ...state, pendingQuestion: { id: m.id, sessionId: m.sessionId, questions: m.questions } };
|
|
332
350
|
case "sessions":
|
|
333
351
|
return { ...state, sessions: m.sessions };
|
|
@@ -345,6 +363,8 @@ function reduce(state, action) {
|
|
|
345
363
|
};
|
|
346
364
|
}
|
|
347
365
|
case "done":
|
|
366
|
+
if (state.sessionId && m.sessionId !== state.sessionId)
|
|
367
|
+
return state;
|
|
348
368
|
return {
|
|
349
369
|
...state,
|
|
350
370
|
running: false,
|
|
@@ -391,12 +411,18 @@ import { useCallback, useEffect, useMemo, useReducer, useRef } from "react";
|
|
|
391
411
|
function useYodexSession(options) {
|
|
392
412
|
const [state, dispatch] = useReducer(reduce, undefined, initialState);
|
|
393
413
|
const sessionIdRef = useRef(options.sessionId);
|
|
414
|
+
const allowed = useRef(new Set);
|
|
415
|
+
const ruleFor = (p) => `${p.toolName}\x00${typeof p.input.command === "string" ? p.input.command : ""}`;
|
|
394
416
|
const client = useMemo(() => new YodexClient({
|
|
395
417
|
url: options.url,
|
|
396
418
|
token: options.token,
|
|
397
419
|
socketFactory: options.socketFactory,
|
|
398
420
|
onState: (s) => dispatch({ type: "connection", state: s }),
|
|
399
421
|
onMessage: (m) => {
|
|
422
|
+
if (m.type === "permission_request" && allowed.current.has(ruleFor(m))) {
|
|
423
|
+
client.respondPermission(m.id, "allow");
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
400
426
|
dispatch({ type: "server", message: m });
|
|
401
427
|
if (m.type === "ready" && sessionIdRef.current) {
|
|
402
428
|
client.loadSession(sessionIdRef.current).catch((e) => dispatch({ type: "error", message: e.message }));
|
|
@@ -412,6 +438,16 @@ function useYodexSession(options) {
|
|
|
412
438
|
useEffect(() => {
|
|
413
439
|
sessionIdRef.current = state.sessionId ?? options.sessionId;
|
|
414
440
|
}, [state.sessionId, options.sessionId]);
|
|
441
|
+
const lastRequested = useRef(options.sessionId);
|
|
442
|
+
useEffect(() => {
|
|
443
|
+
if (options.sessionId === lastRequested.current)
|
|
444
|
+
return;
|
|
445
|
+
lastRequested.current = options.sessionId;
|
|
446
|
+
sessionIdRef.current = options.sessionId;
|
|
447
|
+
dispatch({ type: "clear" });
|
|
448
|
+
if (options.sessionId && client.connected)
|
|
449
|
+
client.loadSession(options.sessionId).catch((e) => dispatch({ type: "error", message: e.message }));
|
|
450
|
+
}, [options.sessionId, client]);
|
|
415
451
|
const guard = useCallback((fn) => {
|
|
416
452
|
try {
|
|
417
453
|
fn();
|
|
@@ -452,6 +488,23 @@ function useYodexSession(options) {
|
|
|
452
488
|
dispatch({ type: "run_started", sessionId, at: Date.now() });
|
|
453
489
|
client.respondApproval(sessionId, decision, reason);
|
|
454
490
|
}), [client, guard]);
|
|
491
|
+
const allowForSession = useCallback((id) => {
|
|
492
|
+
const p = state.pendingPermissions.find((x) => x.id === id);
|
|
493
|
+
if (p)
|
|
494
|
+
allowed.current.add(ruleFor(p));
|
|
495
|
+
guard(() => {
|
|
496
|
+
client.respondPermission(id, "allow");
|
|
497
|
+
dispatch({ type: "permission_answered", id });
|
|
498
|
+
});
|
|
499
|
+
}, [client, guard, state.pendingPermissions]);
|
|
500
|
+
const steer = useCallback((text) => guard(() => {
|
|
501
|
+
const sessionId = sessionIdRef.current;
|
|
502
|
+
if (!sessionId)
|
|
503
|
+
throw new Error("no session to steer");
|
|
504
|
+
client.sendPeer(sessionId, text);
|
|
505
|
+
dispatch({ type: "local_user", text, ts: new Date().toISOString() });
|
|
506
|
+
}), [client, guard]);
|
|
507
|
+
const waitingOn = state.pendingQuestion ? "question" : state.pendingPermissions.length ? "permission" : undefined;
|
|
455
508
|
const loadSession = useCallback(async (sessionId) => {
|
|
456
509
|
sessionIdRef.current = sessionId;
|
|
457
510
|
dispatch({ type: "clear" });
|
|
@@ -479,7 +532,7 @@ function useYodexSession(options) {
|
|
|
479
532
|
sessionIdRef.current = undefined;
|
|
480
533
|
dispatch({ type: "clear" });
|
|
481
534
|
}, []);
|
|
482
|
-
return { state, client, run, stop, allow, deny, answer, approve, loadSession, refreshSessions, refreshModels, newSession };
|
|
535
|
+
return { state, client, run, stop, allow, deny, answer, approve, allowForSession, steer, waitingOn, loadSession, refreshSessions, refreshModels, newSession };
|
|
483
536
|
}
|
|
484
537
|
// src/components/Transcript.tsx
|
|
485
538
|
import { useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
@@ -496,73 +549,88 @@ function cn(...inputs) {
|
|
|
496
549
|
}
|
|
497
550
|
|
|
498
551
|
// src/components/AssistantMessage.tsx
|
|
499
|
-
import { jsx } from "react/jsx-runtime";
|
|
552
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
500
553
|
var plugins = [remarkGfm];
|
|
501
554
|
function AssistantMessage({ text, live, className }) {
|
|
502
|
-
return /* @__PURE__ */
|
|
503
|
-
className: cn("yx-assistant
|
|
555
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
556
|
+
className: cn("yx-assistant max-w-none break-words text-[15px] leading-6 text-foreground", className),
|
|
504
557
|
"data-live": live ? "true" : undefined,
|
|
505
|
-
children:
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
...props,
|
|
511
|
-
target: "_blank",
|
|
512
|
-
rel: "noopener noreferrer",
|
|
513
|
-
className: "text-info underline underline-offset-2"
|
|
514
|
-
}),
|
|
515
|
-
pre: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("pre", {
|
|
516
|
-
...props,
|
|
517
|
-
className: "overflow-x-auto rounded-md border border-border bg-card p-3 font-mono text-[12.5px] leading-5"
|
|
518
|
-
}),
|
|
519
|
-
code: ({ node: _n, className: cls, ...props }) => cls ? /* @__PURE__ */ jsx("code", {
|
|
520
|
-
...props,
|
|
521
|
-
className: cls
|
|
522
|
-
}) : /* @__PURE__ */ jsx("code", {
|
|
523
|
-
...props,
|
|
524
|
-
className: "rounded bg-muted px-1 py-0.5 font-mono text-[0.9em]"
|
|
525
|
-
}),
|
|
526
|
-
table: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
527
|
-
className: "overflow-x-auto",
|
|
528
|
-
children: /* @__PURE__ */ jsx("table", {
|
|
558
|
+
children: [
|
|
559
|
+
/* @__PURE__ */ jsx(Markdown, {
|
|
560
|
+
remarkPlugins: plugins,
|
|
561
|
+
skipHtml: true,
|
|
562
|
+
components: {
|
|
563
|
+
a: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("a", {
|
|
529
564
|
...props,
|
|
530
|
-
|
|
565
|
+
target: "_blank",
|
|
566
|
+
rel: "noopener noreferrer",
|
|
567
|
+
className: "text-info underline underline-offset-2"
|
|
568
|
+
}),
|
|
569
|
+
pre: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("pre", {
|
|
570
|
+
...props,
|
|
571
|
+
className: "overflow-x-auto rounded-md border border-border bg-card p-3 font-mono text-[12.5px] leading-5"
|
|
572
|
+
}),
|
|
573
|
+
code: ({ node: _n, className: cls, ...props }) => cls ? /* @__PURE__ */ jsx("code", {
|
|
574
|
+
...props,
|
|
575
|
+
className: cls
|
|
576
|
+
}) : /* @__PURE__ */ jsx("code", {
|
|
577
|
+
...props,
|
|
578
|
+
className: "rounded bg-muted px-1 py-0.5 font-mono text-[0.9em]"
|
|
579
|
+
}),
|
|
580
|
+
table: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
581
|
+
className: "overflow-x-auto",
|
|
582
|
+
children: /* @__PURE__ */ jsx("table", {
|
|
583
|
+
...props,
|
|
584
|
+
className: "my-2 w-full border-collapse text-sm"
|
|
585
|
+
})
|
|
586
|
+
}),
|
|
587
|
+
th: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("th", {
|
|
588
|
+
...props,
|
|
589
|
+
className: "border border-border bg-muted px-2 py-1 text-left font-medium text-foreground"
|
|
590
|
+
}),
|
|
591
|
+
strong: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("strong", {
|
|
592
|
+
...props,
|
|
593
|
+
className: "font-semibold text-foreground"
|
|
594
|
+
}),
|
|
595
|
+
blockquote: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("blockquote", {
|
|
596
|
+
...props,
|
|
597
|
+
className: "border-l-2 border-border pl-3 text-muted-foreground"
|
|
598
|
+
}),
|
|
599
|
+
td: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("td", {
|
|
600
|
+
...props,
|
|
601
|
+
className: "border border-border px-2 py-1 align-top"
|
|
531
602
|
})
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
},
|
|
542
|
-
children: text
|
|
543
|
-
})
|
|
603
|
+
},
|
|
604
|
+
children: text
|
|
605
|
+
}),
|
|
606
|
+
live && /* @__PURE__ */ jsx("span", {
|
|
607
|
+
className: "yx-caret",
|
|
608
|
+
"aria-hidden": true,
|
|
609
|
+
children: "▍"
|
|
610
|
+
})
|
|
611
|
+
]
|
|
544
612
|
});
|
|
545
613
|
}
|
|
546
614
|
|
|
547
615
|
// src/components/PlanChecklist.tsx
|
|
548
616
|
import { Check, Circle, Loader2 } from "lucide-react";
|
|
549
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
617
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
550
618
|
function PlanChecklist({ items, className }) {
|
|
551
619
|
if (!items.length)
|
|
552
620
|
return null;
|
|
553
621
|
const done = items.filter((t) => t.status === "completed").length;
|
|
554
|
-
return /* @__PURE__ */
|
|
622
|
+
return /* @__PURE__ */ jsxs2("div", {
|
|
555
623
|
className: cn("yx-plan rounded-md border border-border bg-card p-3 text-sm", className),
|
|
556
624
|
"aria-label": "plan",
|
|
557
625
|
children: [
|
|
558
|
-
/* @__PURE__ */
|
|
626
|
+
/* @__PURE__ */ jsxs2("div", {
|
|
559
627
|
className: "mb-2 flex items-center justify-between",
|
|
560
628
|
children: [
|
|
561
629
|
/* @__PURE__ */ jsx2("span", {
|
|
562
630
|
className: "font-medium",
|
|
563
631
|
children: "Plan"
|
|
564
632
|
}),
|
|
565
|
-
/* @__PURE__ */
|
|
633
|
+
/* @__PURE__ */ jsxs2("span", {
|
|
566
634
|
className: "font-mono text-[12px] tabular-nums text-muted-foreground",
|
|
567
635
|
children: [
|
|
568
636
|
done,
|
|
@@ -574,7 +642,7 @@ function PlanChecklist({ items, className }) {
|
|
|
574
642
|
}),
|
|
575
643
|
/* @__PURE__ */ jsx2("ol", {
|
|
576
644
|
className: "space-y-1",
|
|
577
|
-
children: items.map((t) => /* @__PURE__ */
|
|
645
|
+
children: items.map((t) => /* @__PURE__ */ jsxs2("li", {
|
|
578
646
|
className: cn("flex items-start gap-2", t.status === "completed" && "text-muted-foreground line-through"),
|
|
579
647
|
"data-status": t.status,
|
|
580
648
|
children: [
|
|
@@ -635,7 +703,7 @@ function DiffView({ diff, className }) {
|
|
|
635
703
|
}
|
|
636
704
|
|
|
637
705
|
// src/components/ToolCall.tsx
|
|
638
|
-
import { jsx as jsx4, jsxs as
|
|
706
|
+
import { jsx as jsx4, jsxs as jsxs3, Fragment } from "react/jsx-runtime";
|
|
639
707
|
function toolSummary(name, input) {
|
|
640
708
|
const pick = (...keys) => {
|
|
641
709
|
for (const k of keys) {
|
|
@@ -681,12 +749,12 @@ function ToolCall({ item, defaultOpen = false, onOpenFile }) {
|
|
|
681
749
|
const counts = r?.diff ? diffCounts(r.diff) : null;
|
|
682
750
|
const path = typeof item.input.file_path === "string" ? item.input.file_path : typeof item.input.path === "string" ? item.input.path : undefined;
|
|
683
751
|
const Icon = r?.diff ? FileDiff : item.name === "Bash" ? Terminal : Wrench;
|
|
684
|
-
return /* @__PURE__ */
|
|
752
|
+
return /* @__PURE__ */ jsxs3("div", {
|
|
685
753
|
className: cn("yx-tool rounded-md border border-border bg-card text-sm", status === "error" && "border-destructive/40"),
|
|
686
754
|
"data-tool": item.name,
|
|
687
755
|
"data-status": status,
|
|
688
756
|
children: [
|
|
689
|
-
/* @__PURE__ */
|
|
757
|
+
/* @__PURE__ */ jsxs3("button", {
|
|
690
758
|
type: "button",
|
|
691
759
|
onClick: () => setOpen((o) => !o),
|
|
692
760
|
"aria-expanded": open,
|
|
@@ -708,10 +776,10 @@ function ToolCall({ item, defaultOpen = false, onOpenFile }) {
|
|
|
708
776
|
className: "min-w-0 flex-1 truncate font-mono text-[12.5px] text-muted-foreground",
|
|
709
777
|
children: clip(summary)
|
|
710
778
|
}),
|
|
711
|
-
counts && /* @__PURE__ */
|
|
779
|
+
counts && /* @__PURE__ */ jsxs3("span", {
|
|
712
780
|
className: "shrink-0 font-mono text-[12px] tabular-nums",
|
|
713
781
|
children: [
|
|
714
|
-
/* @__PURE__ */
|
|
782
|
+
/* @__PURE__ */ jsxs3("span", {
|
|
715
783
|
className: "text-success",
|
|
716
784
|
children: [
|
|
717
785
|
"+",
|
|
@@ -719,7 +787,7 @@ function ToolCall({ item, defaultOpen = false, onOpenFile }) {
|
|
|
719
787
|
]
|
|
720
788
|
}),
|
|
721
789
|
" ",
|
|
722
|
-
/* @__PURE__ */
|
|
790
|
+
/* @__PURE__ */ jsxs3("span", {
|
|
723
791
|
className: "text-destructive",
|
|
724
792
|
children: [
|
|
725
793
|
"−",
|
|
@@ -742,7 +810,7 @@ function ToolCall({ item, defaultOpen = false, onOpenFile }) {
|
|
|
742
810
|
})
|
|
743
811
|
]
|
|
744
812
|
}),
|
|
745
|
-
open && /* @__PURE__ */
|
|
813
|
+
open && /* @__PURE__ */ jsxs3("div", {
|
|
746
814
|
className: "border-t border-border px-3 py-2",
|
|
747
815
|
children: [
|
|
748
816
|
/* @__PURE__ */ jsx4("div", {
|
|
@@ -753,9 +821,9 @@ function ToolCall({ item, defaultOpen = false, onOpenFile }) {
|
|
|
753
821
|
className: "overflow-x-auto whitespace-pre-wrap break-words font-mono text-[12px] leading-5",
|
|
754
822
|
children: summary && Object.keys(item.input).length === 1 ? summary : JSON.stringify(item.input, null, 2)
|
|
755
823
|
}),
|
|
756
|
-
r && /* @__PURE__ */
|
|
824
|
+
r && /* @__PURE__ */ jsxs3(Fragment, {
|
|
757
825
|
children: [
|
|
758
|
-
/* @__PURE__ */
|
|
826
|
+
/* @__PURE__ */ jsxs3("div", {
|
|
759
827
|
className: "mb-1 mt-2 flex items-center gap-2 text-[11px] uppercase tracking-wide text-muted-foreground",
|
|
760
828
|
children: [
|
|
761
829
|
/* @__PURE__ */ jsx4("span", {
|
|
@@ -785,7 +853,85 @@ function ToolCall({ item, defaultOpen = false, onOpenFile }) {
|
|
|
785
853
|
}
|
|
786
854
|
|
|
787
855
|
// src/components/Transcript.tsx
|
|
788
|
-
import { jsx as jsx5, jsxs as
|
|
856
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
857
|
+
function TranscriptRow({ item, onOpenFile }) {
|
|
858
|
+
const it = item;
|
|
859
|
+
switch (it.kind) {
|
|
860
|
+
case "user":
|
|
861
|
+
return /* @__PURE__ */ jsx5("div", {
|
|
862
|
+
className: cn("flex", it.author.type === "human" ? "justify-end" : "justify-start"),
|
|
863
|
+
"data-author": it.author.type,
|
|
864
|
+
children: /* @__PURE__ */ jsxs4("div", {
|
|
865
|
+
className: cn("max-w-[85%] whitespace-pre-wrap break-words rounded-2xl px-4 py-2 text-[15px] leading-6", it.author.type === "human" ? "rounded-br-md bg-primary text-primary-foreground" : "rounded-bl-md border border-border bg-card"),
|
|
866
|
+
children: [
|
|
867
|
+
it.author.type !== "human" && /* @__PURE__ */ jsx5("div", {
|
|
868
|
+
className: "mb-1 text-[11px] text-muted-foreground",
|
|
869
|
+
children: it.author.displayName ?? it.author.type
|
|
870
|
+
}),
|
|
871
|
+
it.blocks?.some((b) => b.type === "image") && /* @__PURE__ */ jsx5("div", {
|
|
872
|
+
className: "mb-1 text-[11px] opacity-80",
|
|
873
|
+
children: "[image]"
|
|
874
|
+
}),
|
|
875
|
+
it.text
|
|
876
|
+
]
|
|
877
|
+
})
|
|
878
|
+
});
|
|
879
|
+
case "assistant":
|
|
880
|
+
return /* @__PURE__ */ jsx5(AssistantMessage, {
|
|
881
|
+
text: it.text,
|
|
882
|
+
live: it.live
|
|
883
|
+
});
|
|
884
|
+
case "tool":
|
|
885
|
+
return /* @__PURE__ */ jsx5(ToolCall, {
|
|
886
|
+
item: it,
|
|
887
|
+
onOpenFile
|
|
888
|
+
});
|
|
889
|
+
case "plan":
|
|
890
|
+
return /* @__PURE__ */ jsx5(PlanChecklist, {
|
|
891
|
+
items: it.items
|
|
892
|
+
});
|
|
893
|
+
case "result": {
|
|
894
|
+
const { label, tone } = resultLabel(it.result);
|
|
895
|
+
return /* @__PURE__ */ jsxs4("div", {
|
|
896
|
+
className: cn("flex items-center gap-2 text-[12px] text-muted-foreground", tone === "bad" && "text-destructive"),
|
|
897
|
+
"data-subtype": it.result.subtype,
|
|
898
|
+
children: [
|
|
899
|
+
/* @__PURE__ */ jsx5("span", {
|
|
900
|
+
children: label
|
|
901
|
+
}),
|
|
902
|
+
/* @__PURE__ */ jsx5("span", {
|
|
903
|
+
children: "·"
|
|
904
|
+
}),
|
|
905
|
+
/* @__PURE__ */ jsxs4("span", {
|
|
906
|
+
className: "font-mono tabular-nums",
|
|
907
|
+
children: [
|
|
908
|
+
it.result.numTurns,
|
|
909
|
+
" step",
|
|
910
|
+
it.result.numTurns === 1 ? "" : "s",
|
|
911
|
+
" · ",
|
|
912
|
+
formatTokens(it.result.usage)
|
|
913
|
+
]
|
|
914
|
+
})
|
|
915
|
+
]
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
case "error":
|
|
919
|
+
return /* @__PURE__ */ jsx5("div", {
|
|
920
|
+
role: "alert",
|
|
921
|
+
className: "rounded-md border border-destructive/40 bg-destructive/5 px-3 py-2 text-[13px] text-destructive",
|
|
922
|
+
children: it.message
|
|
923
|
+
});
|
|
924
|
+
case "compact":
|
|
925
|
+
return /* @__PURE__ */ jsxs4("div", {
|
|
926
|
+
className: "text-center text-[11px] text-muted-foreground",
|
|
927
|
+
children: [
|
|
928
|
+
"— context compacted (",
|
|
929
|
+
it.replacedMessages,
|
|
930
|
+
" earlier messages summarised) —"
|
|
931
|
+
]
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
}
|
|
789
935
|
function Transcript({ items, autoScroll = true, onOpenFile, footer, emptyState, className }) {
|
|
790
936
|
const ref = useRef2(null);
|
|
791
937
|
const pinned = useRef2(true);
|
|
@@ -808,97 +954,23 @@ function Transcript({ items, autoScroll = true, onOpenFile, footer, emptyState,
|
|
|
808
954
|
ref,
|
|
809
955
|
className: cn("yx-transcript flex-1 overflow-y-auto px-4 py-3", className),
|
|
810
956
|
role: "log",
|
|
811
|
-
|
|
812
|
-
children: /* @__PURE__ */ jsxs3("div", {
|
|
957
|
+
children: /* @__PURE__ */ jsxs4("div", {
|
|
813
958
|
className: "mx-auto flex w-full max-w-3xl flex-col gap-3",
|
|
814
959
|
children: [
|
|
815
960
|
items.length === 0 && emptyState,
|
|
816
|
-
items.map((it) => {
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
className: cn("flex", it.author.type === "human" ? "justify-end" : "justify-start"),
|
|
821
|
-
"data-author": it.author.type,
|
|
822
|
-
children: /* @__PURE__ */ jsxs3("div", {
|
|
823
|
-
className: cn("max-w-[85%] whitespace-pre-wrap break-words rounded-2xl px-4 py-2 text-[15px] leading-6", it.author.type === "human" ? "rounded-br-md bg-primary text-primary-foreground" : "rounded-bl-md border border-border bg-card"),
|
|
824
|
-
children: [
|
|
825
|
-
it.author.type !== "human" && /* @__PURE__ */ jsx5("div", {
|
|
826
|
-
className: "mb-1 text-[11px] text-muted-foreground",
|
|
827
|
-
children: it.author.displayName ?? it.author.type
|
|
828
|
-
}),
|
|
829
|
-
it.blocks?.some((b) => b.type === "image") && /* @__PURE__ */ jsx5("div", {
|
|
830
|
-
className: "mb-1 text-[11px] opacity-80",
|
|
831
|
-
children: "[image]"
|
|
832
|
-
}),
|
|
833
|
-
it.text
|
|
834
|
-
]
|
|
835
|
-
})
|
|
836
|
-
}, it.id);
|
|
837
|
-
case "assistant":
|
|
838
|
-
return /* @__PURE__ */ jsx5(AssistantMessage, {
|
|
839
|
-
text: it.text,
|
|
840
|
-
live: it.live
|
|
841
|
-
}, it.id);
|
|
842
|
-
case "tool":
|
|
843
|
-
return /* @__PURE__ */ jsx5(ToolCall, {
|
|
844
|
-
item: it,
|
|
845
|
-
onOpenFile
|
|
846
|
-
}, it.id);
|
|
847
|
-
case "plan":
|
|
848
|
-
return /* @__PURE__ */ jsx5(PlanChecklist, {
|
|
849
|
-
items: it.items
|
|
850
|
-
}, "plan");
|
|
851
|
-
case "result": {
|
|
852
|
-
const { label, tone } = resultLabel(it.result);
|
|
853
|
-
return /* @__PURE__ */ jsxs3("div", {
|
|
854
|
-
className: cn("flex items-center gap-2 text-[12px] text-muted-foreground", tone === "bad" && "text-destructive"),
|
|
855
|
-
"data-subtype": it.result.subtype,
|
|
856
|
-
children: [
|
|
857
|
-
/* @__PURE__ */ jsx5("span", {
|
|
858
|
-
children: label
|
|
859
|
-
}),
|
|
860
|
-
/* @__PURE__ */ jsx5("span", {
|
|
861
|
-
children: "·"
|
|
862
|
-
}),
|
|
863
|
-
/* @__PURE__ */ jsxs3("span", {
|
|
864
|
-
className: "font-mono tabular-nums",
|
|
865
|
-
children: [
|
|
866
|
-
it.result.numTurns,
|
|
867
|
-
" step",
|
|
868
|
-
it.result.numTurns === 1 ? "" : "s",
|
|
869
|
-
" · ",
|
|
870
|
-
formatTokens(it.result.usage)
|
|
871
|
-
]
|
|
872
|
-
})
|
|
873
|
-
]
|
|
874
|
-
}, it.id);
|
|
875
|
-
}
|
|
876
|
-
case "error":
|
|
877
|
-
return /* @__PURE__ */ jsx5("div", {
|
|
878
|
-
role: "alert",
|
|
879
|
-
className: "rounded-md border border-destructive/40 bg-destructive/5 px-3 py-2 text-[13px] text-destructive",
|
|
880
|
-
children: it.message
|
|
881
|
-
}, it.id);
|
|
882
|
-
case "compact":
|
|
883
|
-
return /* @__PURE__ */ jsxs3("div", {
|
|
884
|
-
className: "text-center text-[11px] text-muted-foreground",
|
|
885
|
-
children: [
|
|
886
|
-
"— context compacted (",
|
|
887
|
-
it.replacedMessages,
|
|
888
|
-
" earlier messages summarised) —"
|
|
889
|
-
]
|
|
890
|
-
}, it.id);
|
|
891
|
-
}
|
|
892
|
-
}),
|
|
961
|
+
items.map((it) => /* @__PURE__ */ jsx5(TranscriptRow, {
|
|
962
|
+
item: it,
|
|
963
|
+
onOpenFile
|
|
964
|
+
}, it.id)),
|
|
893
965
|
footer
|
|
894
966
|
]
|
|
895
967
|
})
|
|
896
968
|
});
|
|
897
969
|
}
|
|
898
970
|
// src/components/PermissionPrompt.tsx
|
|
899
|
-
import { useEffect as useEffect3 } from "react";
|
|
971
|
+
import { useEffect as useEffect3, useState as useState2 } from "react";
|
|
900
972
|
import { ShieldAlert } from "lucide-react";
|
|
901
|
-
import { jsx as jsx6, jsxs as
|
|
973
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
902
974
|
function permissionSummary(p) {
|
|
903
975
|
const v = p.input.command ?? p.input.file_path ?? p.input.path ?? p.input.url;
|
|
904
976
|
if (typeof v === "string")
|
|
@@ -906,8 +978,12 @@ function permissionSummary(p) {
|
|
|
906
978
|
const s = JSON.stringify(p.input);
|
|
907
979
|
return s.length > 240 ? `${s.slice(0, 239)}…` : s;
|
|
908
980
|
}
|
|
909
|
-
function PermissionPrompt({ request, onAllow, onDeny, className }) {
|
|
981
|
+
function PermissionPrompt({ request, onAllow, onDeny, onAllowSession, hotkeys = false, className }) {
|
|
982
|
+
const [reasonOpen, setReasonOpen] = useState2(false);
|
|
983
|
+
const [reason, setReason] = useState2("");
|
|
910
984
|
useEffect3(() => {
|
|
985
|
+
if (!hotkeys)
|
|
986
|
+
return;
|
|
911
987
|
const key = (e) => {
|
|
912
988
|
const t = e.target;
|
|
913
989
|
if (t && (t.tagName === "TEXTAREA" || t.tagName === "INPUT" || t.isContentEditable))
|
|
@@ -919,15 +995,19 @@ function PermissionPrompt({ request, onAllow, onDeny, className }) {
|
|
|
919
995
|
};
|
|
920
996
|
document.addEventListener("keydown", key);
|
|
921
997
|
return () => document.removeEventListener("keydown", key);
|
|
922
|
-
}, [request.id, onAllow, onDeny]);
|
|
923
|
-
|
|
998
|
+
}, [hotkeys, request.id, onAllow, onDeny]);
|
|
999
|
+
const kbd = (k) => hotkeys ? /* @__PURE__ */ jsx6("kbd", {
|
|
1000
|
+
className: "ml-1 rounded bg-black/10 px-1 text-[11px]",
|
|
1001
|
+
children: k
|
|
1002
|
+
}) : null;
|
|
1003
|
+
return /* @__PURE__ */ jsxs5("div", {
|
|
924
1004
|
role: "alertdialog",
|
|
925
1005
|
"aria-labelledby": `perm-${request.id}`,
|
|
926
1006
|
className: cn("yx-permission rounded-md border border-warning/50 bg-card p-3 text-sm", className),
|
|
927
1007
|
children: [
|
|
928
|
-
/* @__PURE__ */
|
|
1008
|
+
/* @__PURE__ */ jsxs5("div", {
|
|
929
1009
|
id: `perm-${request.id}`,
|
|
930
|
-
className: "mb-
|
|
1010
|
+
className: "mb-1 flex items-center gap-2 font-medium",
|
|
931
1011
|
children: [
|
|
932
1012
|
/* @__PURE__ */ jsx6(ShieldAlert, {
|
|
933
1013
|
className: "h-4 w-4 text-warning",
|
|
@@ -941,46 +1021,116 @@ function PermissionPrompt({ request, onAllow, onDeny, className }) {
|
|
|
941
1021
|
"?"
|
|
942
1022
|
]
|
|
943
1023
|
}),
|
|
1024
|
+
(request.safetyReason || request.reason) && /* @__PURE__ */ jsx6("div", {
|
|
1025
|
+
className: "mb-2 text-[12px] text-muted-foreground",
|
|
1026
|
+
children: request.safetyReason ?? request.reason
|
|
1027
|
+
}),
|
|
944
1028
|
/* @__PURE__ */ jsx6("pre", {
|
|
945
1029
|
className: "mb-3 overflow-x-auto whitespace-pre-wrap break-words rounded bg-muted p-2 font-mono text-[12.5px] leading-5",
|
|
946
1030
|
children: permissionSummary(request)
|
|
947
1031
|
}),
|
|
948
|
-
/* @__PURE__ */
|
|
949
|
-
className: "flex gap-2",
|
|
1032
|
+
/* @__PURE__ */ jsxs5("div", {
|
|
1033
|
+
className: "flex flex-wrap gap-2",
|
|
950
1034
|
children: [
|
|
951
|
-
/* @__PURE__ */
|
|
1035
|
+
/* @__PURE__ */ jsxs5("button", {
|
|
952
1036
|
type: "button",
|
|
953
1037
|
onClick: () => onAllow(request.id),
|
|
954
1038
|
className: "min-h-11 flex-1 rounded-md bg-primary px-4 font-medium text-primary-foreground hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
955
1039
|
children: [
|
|
956
1040
|
"Allow ",
|
|
957
|
-
|
|
958
|
-
className: "ml-1 rounded bg-primary-foreground/20 px-1 text-[11px]",
|
|
959
|
-
children: "a"
|
|
960
|
-
})
|
|
1041
|
+
kbd("a")
|
|
961
1042
|
]
|
|
962
1043
|
}),
|
|
963
|
-
/* @__PURE__ */
|
|
1044
|
+
onAllowSession && /* @__PURE__ */ jsx6("button", {
|
|
1045
|
+
type: "button",
|
|
1046
|
+
onClick: () => onAllowSession(request.id),
|
|
1047
|
+
className: "min-h-11 flex-1 rounded-md border border-border bg-background px-4 font-medium hover:bg-muted",
|
|
1048
|
+
children: "Allow for this session"
|
|
1049
|
+
}),
|
|
1050
|
+
/* @__PURE__ */ jsxs5("button", {
|
|
964
1051
|
type: "button",
|
|
965
|
-
onClick: () => onDeny(request.id),
|
|
1052
|
+
onClick: () => reasonOpen ? onDeny(request.id, reason.trim() || undefined) : onDeny(request.id),
|
|
966
1053
|
className: "min-h-11 flex-1 rounded-md border border-border bg-background px-4 font-medium hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
967
1054
|
children: [
|
|
968
1055
|
"Deny ",
|
|
969
|
-
|
|
970
|
-
className: "ml-1 rounded bg-muted px-1 text-[11px]",
|
|
971
|
-
children: "d"
|
|
972
|
-
})
|
|
1056
|
+
kbd("d")
|
|
973
1057
|
]
|
|
974
1058
|
})
|
|
975
1059
|
]
|
|
1060
|
+
}),
|
|
1061
|
+
reasonOpen ? /* @__PURE__ */ jsxs5("label", {
|
|
1062
|
+
className: "mt-2 block",
|
|
1063
|
+
children: [
|
|
1064
|
+
/* @__PURE__ */ jsx6("span", {
|
|
1065
|
+
className: "mb-1 block text-[12px] text-muted-foreground",
|
|
1066
|
+
children: "Tell the agent why (sent with the denial)"
|
|
1067
|
+
}),
|
|
1068
|
+
/* @__PURE__ */ jsx6("input", {
|
|
1069
|
+
value: reason,
|
|
1070
|
+
onChange: (e) => setReason(e.target.value),
|
|
1071
|
+
className: "min-h-11 w-full rounded-md border border-border bg-input-background px-3 text-[16px]"
|
|
1072
|
+
})
|
|
1073
|
+
]
|
|
1074
|
+
}) : /* @__PURE__ */ jsx6("button", {
|
|
1075
|
+
type: "button",
|
|
1076
|
+
onClick: () => setReasonOpen(true),
|
|
1077
|
+
className: "mt-2 min-h-9 text-[12px] text-info underline-offset-2 hover:underline",
|
|
1078
|
+
children: "Deny with a reason…"
|
|
1079
|
+
})
|
|
1080
|
+
]
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
// src/components/ApprovalPrompt.tsx
|
|
1084
|
+
import { ShieldAlert as ShieldAlert2 } from "lucide-react";
|
|
1085
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1086
|
+
function ApprovalPrompt({ approval, onDecide, className }) {
|
|
1087
|
+
return /* @__PURE__ */ jsxs6("div", {
|
|
1088
|
+
role: "alertdialog",
|
|
1089
|
+
"aria-label": "Approval needed",
|
|
1090
|
+
className: cn("yx-approval rounded-md border border-warning/50 bg-card p-3 text-sm", className),
|
|
1091
|
+
children: [
|
|
1092
|
+
/* @__PURE__ */ jsxs6("div", {
|
|
1093
|
+
className: "mb-1 flex items-center gap-2 font-medium",
|
|
1094
|
+
children: [
|
|
1095
|
+
/* @__PURE__ */ jsx7(ShieldAlert2, {
|
|
1096
|
+
className: "h-4 w-4 text-warning",
|
|
1097
|
+
"aria-hidden": true
|
|
1098
|
+
}),
|
|
1099
|
+
"The agent stopped before this and needs your approval"
|
|
1100
|
+
]
|
|
1101
|
+
}),
|
|
1102
|
+
/* @__PURE__ */ jsx7("div", {
|
|
1103
|
+
className: "mb-2 text-[12px] text-muted-foreground",
|
|
1104
|
+
children: approval.reason
|
|
1105
|
+
}),
|
|
1106
|
+
/* @__PURE__ */ jsx7("pre", {
|
|
1107
|
+
className: "mb-3 overflow-x-auto whitespace-pre-wrap break-words rounded bg-muted p-2 font-mono text-[12.5px] leading-5",
|
|
1108
|
+
children: approval.command
|
|
1109
|
+
}),
|
|
1110
|
+
/* @__PURE__ */ jsxs6("div", {
|
|
1111
|
+
className: "flex gap-2",
|
|
1112
|
+
children: [
|
|
1113
|
+
/* @__PURE__ */ jsx7("button", {
|
|
1114
|
+
type: "button",
|
|
1115
|
+
onClick: () => onDecide("allow"),
|
|
1116
|
+
className: "min-h-11 flex-1 rounded-md bg-primary px-4 font-medium text-primary-foreground hover:opacity-90",
|
|
1117
|
+
children: "Approve and continue"
|
|
1118
|
+
}),
|
|
1119
|
+
/* @__PURE__ */ jsx7("button", {
|
|
1120
|
+
type: "button",
|
|
1121
|
+
onClick: () => onDecide("deny"),
|
|
1122
|
+
className: "min-h-11 flex-1 rounded-md border border-border px-4 font-medium hover:bg-muted",
|
|
1123
|
+
children: "Don't run it"
|
|
1124
|
+
})
|
|
1125
|
+
]
|
|
976
1126
|
})
|
|
977
1127
|
]
|
|
978
1128
|
});
|
|
979
1129
|
}
|
|
980
1130
|
// src/components/QuestionForm.tsx
|
|
981
|
-
import { useState as
|
|
1131
|
+
import { useState as useState3 } from "react";
|
|
982
1132
|
import { HelpCircle, X } from "lucide-react";
|
|
983
|
-
import { jsx as
|
|
1133
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
984
1134
|
function emptyDraft(questions) {
|
|
985
1135
|
return { selected: questions.map(() => []), notes: questions.map(() => "") };
|
|
986
1136
|
}
|
|
@@ -1003,8 +1153,8 @@ function chip(q, i) {
|
|
|
1003
1153
|
}
|
|
1004
1154
|
function QuestionForm({ request, onSubmit, onDecline, className }) {
|
|
1005
1155
|
const qs = request.questions;
|
|
1006
|
-
const [tab, setTab] =
|
|
1007
|
-
const [draft, setDraft] =
|
|
1156
|
+
const [tab, setTab] = useState3(0);
|
|
1157
|
+
const [draft, setDraft] = useState3(() => emptyDraft(qs));
|
|
1008
1158
|
const q = qs[tab];
|
|
1009
1159
|
if (!q)
|
|
1010
1160
|
return null;
|
|
@@ -1024,38 +1174,38 @@ function QuestionForm({ request, onSubmit, onDecline, className }) {
|
|
|
1024
1174
|
});
|
|
1025
1175
|
const answered = qs.map((_, i) => (draft.selected[i]?.length ?? 0) > 0 || (draft.notes[i] ?? "").trim().length > 0);
|
|
1026
1176
|
const previewOf = (q.options ?? []).find((o) => picked[0] === o.label)?.preview;
|
|
1027
|
-
return /* @__PURE__ */
|
|
1177
|
+
return /* @__PURE__ */ jsxs7("div", {
|
|
1028
1178
|
role: "dialog",
|
|
1029
1179
|
"aria-label": "The agent has a question",
|
|
1030
1180
|
className: cn("yx-question rounded-md border border-info/50 bg-card text-sm", className),
|
|
1031
1181
|
children: [
|
|
1032
|
-
/* @__PURE__ */
|
|
1182
|
+
/* @__PURE__ */ jsxs7("div", {
|
|
1033
1183
|
className: "flex items-center gap-2 border-b border-border px-3 py-2",
|
|
1034
1184
|
children: [
|
|
1035
|
-
/* @__PURE__ */
|
|
1185
|
+
/* @__PURE__ */ jsx8(HelpCircle, {
|
|
1036
1186
|
className: "h-4 w-4 text-info",
|
|
1037
1187
|
"aria-hidden": true
|
|
1038
1188
|
}),
|
|
1039
|
-
/* @__PURE__ */
|
|
1189
|
+
/* @__PURE__ */ jsx8("span", {
|
|
1040
1190
|
className: "font-medium",
|
|
1041
1191
|
children: "The agent needs your input"
|
|
1042
1192
|
}),
|
|
1043
|
-
/* @__PURE__ */
|
|
1193
|
+
/* @__PURE__ */ jsx8("button", {
|
|
1044
1194
|
type: "button",
|
|
1045
1195
|
onClick: () => onDecline(request.id),
|
|
1046
1196
|
"aria-label": "Close and keep talking",
|
|
1047
1197
|
className: "ml-auto flex h-11 w-11 items-center justify-center rounded-md text-muted-foreground hover:bg-muted",
|
|
1048
|
-
children: /* @__PURE__ */
|
|
1198
|
+
children: /* @__PURE__ */ jsx8(X, {
|
|
1049
1199
|
className: "h-4 w-4",
|
|
1050
1200
|
"aria-hidden": true
|
|
1051
1201
|
})
|
|
1052
1202
|
})
|
|
1053
1203
|
]
|
|
1054
1204
|
}),
|
|
1055
|
-
qs.length > 1 && /* @__PURE__ */
|
|
1205
|
+
qs.length > 1 && /* @__PURE__ */ jsx8("div", {
|
|
1056
1206
|
role: "tablist",
|
|
1057
1207
|
className: "flex gap-1 overflow-x-auto border-b border-border px-2 py-1",
|
|
1058
|
-
children: qs.map((qq, i) => /* @__PURE__ */
|
|
1208
|
+
children: qs.map((qq, i) => /* @__PURE__ */ jsx8("button", {
|
|
1059
1209
|
role: "tab",
|
|
1060
1210
|
type: "button",
|
|
1061
1211
|
"aria-selected": i === tab,
|
|
@@ -1064,37 +1214,37 @@ function QuestionForm({ request, onSubmit, onDecline, className }) {
|
|
|
1064
1214
|
children: chip(qq, i)
|
|
1065
1215
|
}, i))
|
|
1066
1216
|
}),
|
|
1067
|
-
/* @__PURE__ */
|
|
1217
|
+
/* @__PURE__ */ jsxs7("div", {
|
|
1068
1218
|
className: "space-y-3 p-3",
|
|
1069
1219
|
children: [
|
|
1070
|
-
/* @__PURE__ */
|
|
1220
|
+
/* @__PURE__ */ jsx8("p", {
|
|
1071
1221
|
className: "font-medium",
|
|
1072
1222
|
children: q.question
|
|
1073
1223
|
}),
|
|
1074
|
-
(q.options ?? []).length > 0 && /* @__PURE__ */
|
|
1224
|
+
(q.options ?? []).length > 0 && /* @__PURE__ */ jsx8("div", {
|
|
1075
1225
|
role: q.multiSelect ? "group" : "radiogroup",
|
|
1076
1226
|
className: "space-y-2",
|
|
1077
1227
|
children: (q.options ?? []).map((o) => {
|
|
1078
1228
|
const on = picked.includes(o.label);
|
|
1079
|
-
return /* @__PURE__ */
|
|
1229
|
+
return /* @__PURE__ */ jsxs7("button", {
|
|
1080
1230
|
type: "button",
|
|
1081
1231
|
role: q.multiSelect ? "checkbox" : "radio",
|
|
1082
1232
|
"aria-checked": on,
|
|
1083
1233
|
onClick: () => toggle(o.label),
|
|
1084
1234
|
className: cn("flex min-h-11 w-full items-start gap-3 rounded-md border px-3 py-2 text-left hover:bg-muted/60", on ? "border-primary bg-muted" : "border-border"),
|
|
1085
1235
|
children: [
|
|
1086
|
-
/* @__PURE__ */
|
|
1236
|
+
/* @__PURE__ */ jsx8("span", {
|
|
1087
1237
|
className: cn("mt-1 h-4 w-4 shrink-0 border", q.multiSelect ? "rounded" : "rounded-full", on ? "border-primary bg-primary" : "border-muted-foreground"),
|
|
1088
1238
|
"aria-hidden": true
|
|
1089
1239
|
}),
|
|
1090
|
-
/* @__PURE__ */
|
|
1240
|
+
/* @__PURE__ */ jsxs7("span", {
|
|
1091
1241
|
className: "min-w-0",
|
|
1092
1242
|
children: [
|
|
1093
|
-
/* @__PURE__ */
|
|
1243
|
+
/* @__PURE__ */ jsx8("span", {
|
|
1094
1244
|
className: "block font-medium",
|
|
1095
1245
|
children: o.label
|
|
1096
1246
|
}),
|
|
1097
|
-
o.description && /* @__PURE__ */
|
|
1247
|
+
o.description && /* @__PURE__ */ jsx8("span", {
|
|
1098
1248
|
className: "block text-muted-foreground",
|
|
1099
1249
|
children: o.description
|
|
1100
1250
|
})
|
|
@@ -1104,18 +1254,18 @@ function QuestionForm({ request, onSubmit, onDecline, className }) {
|
|
|
1104
1254
|
}, o.label);
|
|
1105
1255
|
})
|
|
1106
1256
|
}),
|
|
1107
|
-
previewOf && /* @__PURE__ */
|
|
1257
|
+
previewOf && /* @__PURE__ */ jsx8("pre", {
|
|
1108
1258
|
className: "overflow-x-auto rounded-md border border-border bg-muted p-2 font-mono text-[12px] leading-5",
|
|
1109
1259
|
children: previewOf
|
|
1110
1260
|
}),
|
|
1111
|
-
/* @__PURE__ */
|
|
1261
|
+
/* @__PURE__ */ jsxs7("label", {
|
|
1112
1262
|
className: "block",
|
|
1113
1263
|
children: [
|
|
1114
|
-
/* @__PURE__ */
|
|
1264
|
+
/* @__PURE__ */ jsx8("span", {
|
|
1115
1265
|
className: "mb-1 block text-[12px] text-muted-foreground",
|
|
1116
1266
|
children: (q.options ?? []).length ? "Add a note (optional)" : "Your answer"
|
|
1117
1267
|
}),
|
|
1118
|
-
/* @__PURE__ */
|
|
1268
|
+
/* @__PURE__ */ jsx8("textarea", {
|
|
1119
1269
|
value: draft.notes[tab] ?? "",
|
|
1120
1270
|
onChange: (e) => setNote(e.target.value),
|
|
1121
1271
|
rows: 2,
|
|
@@ -1123,16 +1273,16 @@ function QuestionForm({ request, onSubmit, onDecline, className }) {
|
|
|
1123
1273
|
})
|
|
1124
1274
|
]
|
|
1125
1275
|
}),
|
|
1126
|
-
/* @__PURE__ */
|
|
1276
|
+
/* @__PURE__ */ jsxs7("div", {
|
|
1127
1277
|
className: "flex gap-2",
|
|
1128
1278
|
children: [
|
|
1129
|
-
tab < qs.length - 1 ? /* @__PURE__ */
|
|
1279
|
+
tab < qs.length - 1 ? /* @__PURE__ */ jsx8("button", {
|
|
1130
1280
|
type: "button",
|
|
1131
1281
|
onClick: () => setTab(tab + 1),
|
|
1132
1282
|
className: "min-h-11 flex-1 rounded-md border border-border px-4 font-medium hover:bg-muted",
|
|
1133
1283
|
children: "Next"
|
|
1134
1284
|
}) : null,
|
|
1135
|
-
/* @__PURE__ */
|
|
1285
|
+
/* @__PURE__ */ jsx8("button", {
|
|
1136
1286
|
type: "button",
|
|
1137
1287
|
onClick: () => onSubmit(request.id, buildOutcome(qs, draft)),
|
|
1138
1288
|
disabled: !answered.some(Boolean),
|
|
@@ -1147,11 +1297,11 @@ function QuestionForm({ request, onSubmit, onDecline, className }) {
|
|
|
1147
1297
|
});
|
|
1148
1298
|
}
|
|
1149
1299
|
// src/components/RunStatus.tsx
|
|
1150
|
-
import { useEffect as useEffect4, useState as
|
|
1300
|
+
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
1151
1301
|
import { AlertTriangle, Check as Check3, Loader2 as Loader23, Square } from "lucide-react";
|
|
1152
|
-
import { jsx as
|
|
1153
|
-
function RunStatus({ running, startedAt, activity, lastResult, usageTotal, connection, onStop, onApprove, className, now = Date.now }) {
|
|
1154
|
-
const [, tick] =
|
|
1302
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1303
|
+
function RunStatus({ running, startedAt, activity, waitingOn, lastResult, usageTotal, connection, onStop, onApprove, className, now = Date.now }) {
|
|
1304
|
+
const [, tick] = useState4(0);
|
|
1155
1305
|
useEffect4(() => {
|
|
1156
1306
|
if (!running)
|
|
1157
1307
|
return;
|
|
@@ -1159,11 +1309,11 @@ function RunStatus({ running, startedAt, activity, lastResult, usageTotal, conne
|
|
|
1159
1309
|
return () => clearInterval(h);
|
|
1160
1310
|
}, [running]);
|
|
1161
1311
|
if (connection && connection !== "connected") {
|
|
1162
|
-
return /* @__PURE__ */
|
|
1312
|
+
return /* @__PURE__ */ jsxs8("div", {
|
|
1163
1313
|
className: cn("yx-status flex min-h-9 items-center gap-2 text-[12.5px] text-muted-foreground", className),
|
|
1164
1314
|
role: "status",
|
|
1165
1315
|
children: [
|
|
1166
|
-
/* @__PURE__ */
|
|
1316
|
+
/* @__PURE__ */ jsx9(Loader23, {
|
|
1167
1317
|
className: "h-3.5 w-3.5 animate-spin",
|
|
1168
1318
|
"aria-hidden": true
|
|
1169
1319
|
}),
|
|
@@ -1172,32 +1322,34 @@ function RunStatus({ running, startedAt, activity, lastResult, usageTotal, conne
|
|
|
1172
1322
|
});
|
|
1173
1323
|
}
|
|
1174
1324
|
if (running) {
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
"aria-live": "polite",
|
|
1325
|
+
const label2 = waitingOn === "permission" ? "Waiting for your approval" : waitingOn === "question" ? "Waiting for your answer" : activity ?? "Working";
|
|
1326
|
+
return /* @__PURE__ */ jsxs8("div", {
|
|
1327
|
+
className: cn("yx-status flex min-h-11 items-center gap-2 text-[12.5px] text-muted-foreground", className),
|
|
1179
1328
|
children: [
|
|
1180
|
-
/* @__PURE__ */
|
|
1181
|
-
className: "h-3.5 w-3.5 animate-spin text-accent",
|
|
1329
|
+
/* @__PURE__ */ jsx9(Loader23, {
|
|
1330
|
+
className: cn("h-3.5 w-3.5 animate-spin", waitingOn ? "text-warning" : "text-accent"),
|
|
1182
1331
|
"aria-hidden": true
|
|
1183
1332
|
}),
|
|
1184
|
-
/* @__PURE__ */
|
|
1185
|
-
|
|
1333
|
+
/* @__PURE__ */ jsx9("span", {
|
|
1334
|
+
role: "status",
|
|
1335
|
+
"aria-live": "polite",
|
|
1336
|
+
children: label2
|
|
1186
1337
|
}),
|
|
1187
|
-
startedAt !== undefined && /* @__PURE__ */
|
|
1338
|
+
startedAt !== undefined && /* @__PURE__ */ jsxs8("span", {
|
|
1188
1339
|
className: "font-mono tabular-nums",
|
|
1340
|
+
"aria-hidden": true,
|
|
1189
1341
|
children: [
|
|
1190
1342
|
"· ",
|
|
1191
1343
|
elapsedLabel(now() - startedAt)
|
|
1192
1344
|
]
|
|
1193
1345
|
}),
|
|
1194
|
-
onStop && /* @__PURE__ */
|
|
1346
|
+
onStop && /* @__PURE__ */ jsxs8("button", {
|
|
1195
1347
|
type: "button",
|
|
1196
1348
|
onClick: onStop,
|
|
1197
|
-
className: "ml-auto flex min-h-
|
|
1349
|
+
className: "ml-auto flex min-h-11 items-center gap-1 rounded-md px-3 hover:bg-muted",
|
|
1198
1350
|
"aria-label": "Stop",
|
|
1199
1351
|
children: [
|
|
1200
|
-
/* @__PURE__ */
|
|
1352
|
+
/* @__PURE__ */ jsx9(Square, {
|
|
1201
1353
|
className: "h-3.5 w-3.5",
|
|
1202
1354
|
"aria-hidden": true
|
|
1203
1355
|
}),
|
|
@@ -1211,30 +1363,30 @@ function RunStatus({ running, startedAt, activity, lastResult, usageTotal, conne
|
|
|
1211
1363
|
return null;
|
|
1212
1364
|
const { label, tone } = resultLabel(lastResult);
|
|
1213
1365
|
const needsApproval = lastResult.subtype === "needs_approval";
|
|
1214
|
-
return /* @__PURE__ */
|
|
1366
|
+
return /* @__PURE__ */ jsxs8("div", {
|
|
1215
1367
|
className: cn("yx-status flex min-h-9 flex-wrap items-center gap-2 text-[12.5px]", className),
|
|
1216
1368
|
role: "status",
|
|
1217
1369
|
"data-subtype": lastResult.subtype,
|
|
1218
1370
|
children: [
|
|
1219
|
-
tone === "ok" ? /* @__PURE__ */
|
|
1371
|
+
tone === "ok" ? /* @__PURE__ */ jsx9(Check3, {
|
|
1220
1372
|
className: "h-3.5 w-3.5 text-success",
|
|
1221
1373
|
"aria-hidden": true
|
|
1222
|
-
}) : tone === "bad" ? /* @__PURE__ */
|
|
1374
|
+
}) : tone === "bad" ? /* @__PURE__ */ jsx9(AlertTriangle, {
|
|
1223
1375
|
className: "h-3.5 w-3.5 text-destructive",
|
|
1224
1376
|
"aria-hidden": true
|
|
1225
|
-
}) : /* @__PURE__ */
|
|
1377
|
+
}) : /* @__PURE__ */ jsx9(AlertTriangle, {
|
|
1226
1378
|
className: cn("h-3.5 w-3.5", tone === "warn" ? "text-warning" : "text-muted-foreground"),
|
|
1227
1379
|
"aria-hidden": true
|
|
1228
1380
|
}),
|
|
1229
|
-
/* @__PURE__ */
|
|
1381
|
+
/* @__PURE__ */ jsx9("span", {
|
|
1230
1382
|
className: cn(tone === "ok" && "text-success", tone === "bad" && "text-destructive", tone === "warn" && "text-warning", tone === "muted" && "text-muted-foreground"),
|
|
1231
1383
|
children: label
|
|
1232
1384
|
}),
|
|
1233
|
-
/* @__PURE__ */
|
|
1385
|
+
/* @__PURE__ */ jsx9("span", {
|
|
1234
1386
|
className: "text-muted-foreground",
|
|
1235
1387
|
children: "·"
|
|
1236
1388
|
}),
|
|
1237
|
-
/* @__PURE__ */
|
|
1389
|
+
/* @__PURE__ */ jsxs8("span", {
|
|
1238
1390
|
className: "font-mono tabular-nums text-muted-foreground",
|
|
1239
1391
|
children: [
|
|
1240
1392
|
lastResult.numTurns,
|
|
@@ -1244,42 +1396,19 @@ function RunStatus({ running, startedAt, activity, lastResult, usageTotal, conne
|
|
|
1244
1396
|
formatTokens(usageTotal ?? lastResult.usage)
|
|
1245
1397
|
]
|
|
1246
1398
|
}),
|
|
1247
|
-
needsApproval && lastResult.pendingApproval && /* @__PURE__ */
|
|
1248
|
-
className: "basis-full
|
|
1249
|
-
children:
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
}),
|
|
1254
|
-
/* @__PURE__ */ jsx8("pre", {
|
|
1255
|
-
className: "mb-2 overflow-x-auto whitespace-pre-wrap break-words font-mono text-[12px]",
|
|
1256
|
-
children: lastResult.pendingApproval.command
|
|
1257
|
-
}),
|
|
1258
|
-
onApprove && /* @__PURE__ */ jsxs6("div", {
|
|
1259
|
-
className: "flex gap-2",
|
|
1260
|
-
children: [
|
|
1261
|
-
/* @__PURE__ */ jsx8("button", {
|
|
1262
|
-
type: "button",
|
|
1263
|
-
onClick: () => onApprove("allow"),
|
|
1264
|
-
className: "min-h-11 flex-1 rounded-md bg-primary px-3 font-medium text-primary-foreground",
|
|
1265
|
-
children: "Approve and continue"
|
|
1266
|
-
}),
|
|
1267
|
-
/* @__PURE__ */ jsx8("button", {
|
|
1268
|
-
type: "button",
|
|
1269
|
-
onClick: () => onApprove("deny"),
|
|
1270
|
-
className: "min-h-11 flex-1 rounded-md border border-border px-3 font-medium hover:bg-muted",
|
|
1271
|
-
children: "Don't run it"
|
|
1272
|
-
})
|
|
1273
|
-
]
|
|
1274
|
-
})
|
|
1275
|
-
]
|
|
1399
|
+
needsApproval && lastResult.pendingApproval && onApprove && /* @__PURE__ */ jsx9("div", {
|
|
1400
|
+
className: "basis-full",
|
|
1401
|
+
children: /* @__PURE__ */ jsx9(ApprovalPrompt, {
|
|
1402
|
+
approval: lastResult.pendingApproval,
|
|
1403
|
+
onDecide: onApprove
|
|
1404
|
+
})
|
|
1276
1405
|
})
|
|
1277
1406
|
]
|
|
1278
1407
|
});
|
|
1279
1408
|
}
|
|
1280
1409
|
// src/components/SessionList.tsx
|
|
1281
1410
|
import { Plus } from "lucide-react";
|
|
1282
|
-
import { jsx as
|
|
1411
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1283
1412
|
function groupSessions(rows) {
|
|
1284
1413
|
const groups = new Map;
|
|
1285
1414
|
for (const r of rows) {
|
|
@@ -1299,75 +1428,75 @@ function when(iso) {
|
|
|
1299
1428
|
}
|
|
1300
1429
|
function SessionList({ sessions, selectedId, onSelect, onNew, className }) {
|
|
1301
1430
|
const groups = groupSessions(sessions);
|
|
1302
|
-
return /* @__PURE__ */
|
|
1431
|
+
return /* @__PURE__ */ jsxs9("nav", {
|
|
1303
1432
|
className: cn("yx-sessions text-sm", className),
|
|
1304
1433
|
"aria-label": "Sessions",
|
|
1305
1434
|
children: [
|
|
1306
|
-
onNew && /* @__PURE__ */
|
|
1435
|
+
onNew && /* @__PURE__ */ jsxs9("button", {
|
|
1307
1436
|
type: "button",
|
|
1308
1437
|
onClick: onNew,
|
|
1309
1438
|
className: "mb-2 flex min-h-11 w-full items-center gap-2 rounded-md border border-dashed border-border px-3 text-left hover:bg-muted",
|
|
1310
1439
|
children: [
|
|
1311
|
-
/* @__PURE__ */
|
|
1440
|
+
/* @__PURE__ */ jsx10(Plus, {
|
|
1312
1441
|
className: "h-4 w-4",
|
|
1313
1442
|
"aria-hidden": true
|
|
1314
1443
|
}),
|
|
1315
1444
|
" New session"
|
|
1316
1445
|
]
|
|
1317
1446
|
}),
|
|
1318
|
-
sessions.length === 0 && /* @__PURE__ */
|
|
1447
|
+
sessions.length === 0 && /* @__PURE__ */ jsx10("p", {
|
|
1319
1448
|
className: "px-3 py-2 text-muted-foreground",
|
|
1320
1449
|
children: "No sessions yet."
|
|
1321
1450
|
}),
|
|
1322
|
-
groups.map((g) => /* @__PURE__ */
|
|
1451
|
+
groups.map((g) => /* @__PURE__ */ jsxs9("div", {
|
|
1323
1452
|
className: "mb-2",
|
|
1324
1453
|
children: [
|
|
1325
|
-
g.project && /* @__PURE__ */
|
|
1454
|
+
g.project && /* @__PURE__ */ jsx10("div", {
|
|
1326
1455
|
className: "px-3 py-1 text-[11px] uppercase tracking-wide text-muted-foreground",
|
|
1327
1456
|
children: g.project
|
|
1328
1457
|
}),
|
|
1329
|
-
/* @__PURE__ */
|
|
1458
|
+
/* @__PURE__ */ jsx10("ul", {
|
|
1330
1459
|
children: g.rows.map((s) => {
|
|
1331
1460
|
const on = s.sessionId === selectedId;
|
|
1332
1461
|
const title = s.name || s.title || s.lastMessagePreview || s.sessionId.slice(0, 8);
|
|
1333
|
-
return /* @__PURE__ */
|
|
1334
|
-
children: /* @__PURE__ */
|
|
1462
|
+
return /* @__PURE__ */ jsx10("li", {
|
|
1463
|
+
children: /* @__PURE__ */ jsxs9("button", {
|
|
1335
1464
|
type: "button",
|
|
1336
1465
|
onClick: () => onSelect(s.sessionId),
|
|
1337
1466
|
"aria-current": on ? "true" : undefined,
|
|
1338
1467
|
className: cn("flex min-h-11 w-full flex-col gap-0.5 rounded-md px-3 py-2 text-left hover:bg-muted", on && "bg-muted"),
|
|
1339
1468
|
"data-status": s.status,
|
|
1340
1469
|
children: [
|
|
1341
|
-
/* @__PURE__ */
|
|
1470
|
+
/* @__PURE__ */ jsxs9("span", {
|
|
1342
1471
|
className: "flex items-center gap-2",
|
|
1343
1472
|
children: [
|
|
1344
|
-
/* @__PURE__ */
|
|
1473
|
+
/* @__PURE__ */ jsx10("span", {
|
|
1345
1474
|
className: cn("h-2 w-2 shrink-0 rounded-full", s.live ? "animate-pulse bg-accent" : s.status === "active" ? "bg-success" : s.status === "listening" ? "bg-info" : s.status === "error" ? "bg-destructive" : "bg-muted-foreground/40"),
|
|
1346
1475
|
"aria-label": s.live ? "working" : s.status,
|
|
1347
1476
|
"data-live": s.live ? "true" : undefined
|
|
1348
1477
|
}),
|
|
1349
|
-
/* @__PURE__ */
|
|
1478
|
+
/* @__PURE__ */ jsx10("span", {
|
|
1350
1479
|
className: "min-w-0 flex-1 truncate font-medium",
|
|
1351
1480
|
children: title
|
|
1352
1481
|
}),
|
|
1353
|
-
s.pendingQuestion && /* @__PURE__ */
|
|
1482
|
+
s.pendingQuestion && /* @__PURE__ */ jsx10("span", {
|
|
1354
1483
|
className: "shrink-0 rounded-full bg-warning px-1.5 text-[10px] font-medium text-warning-foreground",
|
|
1355
1484
|
children: "question"
|
|
1356
1485
|
})
|
|
1357
1486
|
]
|
|
1358
1487
|
}),
|
|
1359
|
-
/* @__PURE__ */
|
|
1488
|
+
/* @__PURE__ */ jsxs9("span", {
|
|
1360
1489
|
className: "flex gap-2 truncate text-[11.5px] text-muted-foreground",
|
|
1361
1490
|
children: [
|
|
1362
|
-
s.hop && /* @__PURE__ */
|
|
1491
|
+
s.hop && /* @__PURE__ */ jsx10("span", {
|
|
1363
1492
|
className: "truncate",
|
|
1364
1493
|
children: s.hop
|
|
1365
1494
|
}),
|
|
1366
|
-
s.relCwd && /* @__PURE__ */
|
|
1495
|
+
s.relCwd && /* @__PURE__ */ jsx10("span", {
|
|
1367
1496
|
className: "truncate",
|
|
1368
1497
|
children: s.relCwd
|
|
1369
1498
|
}),
|
|
1370
|
-
/* @__PURE__ */
|
|
1499
|
+
/* @__PURE__ */ jsx10("span", {
|
|
1371
1500
|
className: "ml-auto shrink-0 tabular-nums",
|
|
1372
1501
|
children: when(s.updatedAt)
|
|
1373
1502
|
})
|
|
@@ -1384,9 +1513,9 @@ function SessionList({ sessions, selectedId, onSelect, onNew, className }) {
|
|
|
1384
1513
|
});
|
|
1385
1514
|
}
|
|
1386
1515
|
// src/components/Composer.tsx
|
|
1387
|
-
import { useCallback as useCallback2, useEffect as useEffect5, useRef as useRef3, useState as
|
|
1516
|
+
import { useCallback as useCallback2, useEffect as useEffect5, useRef as useRef3, useState as useState5 } from "react";
|
|
1388
1517
|
import { ArrowUp, ImagePlus, Square as Square2, X as X2 } from "lucide-react";
|
|
1389
|
-
import { jsx as
|
|
1518
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1390
1519
|
var ACCEPT = ["image/png", "image/jpeg", "image/gif", "image/webp"];
|
|
1391
1520
|
async function fileToAttachment(f) {
|
|
1392
1521
|
const buf = new Uint8Array(await f.arrayBuffer());
|
|
@@ -1395,17 +1524,34 @@ async function fileToAttachment(f) {
|
|
|
1395
1524
|
bin += String.fromCharCode(...buf.subarray(i, i + 32768));
|
|
1396
1525
|
return { name: f.name || "image", mediaType: f.type, data: btoa(bin), previewUrl: URL.createObjectURL(f) };
|
|
1397
1526
|
}
|
|
1398
|
-
function
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1527
|
+
function coarsePointer() {
|
|
1528
|
+
return typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(pointer: coarse)").matches;
|
|
1529
|
+
}
|
|
1530
|
+
function Composer({ onSubmit, running, onStop, onSteer, value, onChange, initialValue, submitOnEnter, hideAttach, disabled, disabledReason, placeholder = "Ask yodex to do something…", hopOptions, hop, onHopChange, leading, maxAttachmentBytes = 8 * 1024 * 1024, className, autoFocus }) {
|
|
1531
|
+
const [own, setOwn] = useState5(initialValue ?? "");
|
|
1532
|
+
const text = value ?? own;
|
|
1533
|
+
const setText = (t) => {
|
|
1534
|
+
if (value === undefined)
|
|
1535
|
+
setOwn(t);
|
|
1536
|
+
onChange?.(t);
|
|
1537
|
+
};
|
|
1538
|
+
const [attachments, setAttachments] = useState5([]);
|
|
1539
|
+
const [note, setNote] = useState5(null);
|
|
1402
1540
|
const ref = useRef3(null);
|
|
1403
1541
|
useEffect5(() => {
|
|
1404
1542
|
const el = ref.current;
|
|
1405
1543
|
if (!el)
|
|
1406
1544
|
return;
|
|
1407
|
-
|
|
1408
|
-
|
|
1545
|
+
const fit = () => {
|
|
1546
|
+
el.style.height = "0px";
|
|
1547
|
+
el.style.height = `${Math.min(el.scrollHeight, 240)}px`;
|
|
1548
|
+
};
|
|
1549
|
+
fit();
|
|
1550
|
+
if (typeof ResizeObserver === "undefined")
|
|
1551
|
+
return;
|
|
1552
|
+
const ro = new ResizeObserver(fit);
|
|
1553
|
+
ro.observe(el);
|
|
1554
|
+
return () => ro.disconnect();
|
|
1409
1555
|
}, [text]);
|
|
1410
1556
|
const addFiles = useCallback2(async (files) => {
|
|
1411
1557
|
const list = [...files].filter((f) => ACCEPT.includes(f.type));
|
|
@@ -1426,10 +1572,16 @@ function Composer({ onSubmit, running, onStop, disabled, disabledReason, placeho
|
|
|
1426
1572
|
URL.revokeObjectURL(gone.previewUrl);
|
|
1427
1573
|
return a.filter((_, j) => j !== i);
|
|
1428
1574
|
});
|
|
1429
|
-
const
|
|
1575
|
+
const steering = Boolean(running && onSteer);
|
|
1576
|
+
const canSend = !disabled && (steering ? text.trim().length > 0 : !running && (text.trim().length > 0 || attachments.length > 0));
|
|
1430
1577
|
const submit = () => {
|
|
1431
1578
|
if (!canSend)
|
|
1432
1579
|
return;
|
|
1580
|
+
if (steering) {
|
|
1581
|
+
onSteer(text.trim());
|
|
1582
|
+
setText("");
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1433
1585
|
onSubmit(text.trim(), attachments);
|
|
1434
1586
|
setText("");
|
|
1435
1587
|
for (const a of attachments)
|
|
@@ -1438,10 +1590,13 @@ function Composer({ onSubmit, running, onStop, disabled, disabledReason, placeho
|
|
|
1438
1590
|
setAttachments([]);
|
|
1439
1591
|
};
|
|
1440
1592
|
const onKey = (e) => {
|
|
1441
|
-
if (e.key
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1593
|
+
if (e.key !== "Enter" || e.shiftKey || e.nativeEvent.isComposing)
|
|
1594
|
+
return;
|
|
1595
|
+
const enterSends = submitOnEnter ?? !coarsePointer();
|
|
1596
|
+
if (!enterSends)
|
|
1597
|
+
return;
|
|
1598
|
+
e.preventDefault();
|
|
1599
|
+
submit();
|
|
1445
1600
|
};
|
|
1446
1601
|
const onPaste = (e) => {
|
|
1447
1602
|
const files = [...e.clipboardData.files];
|
|
@@ -1456,39 +1611,42 @@ function Composer({ onSubmit, running, onStop, disabled, disabledReason, placeho
|
|
|
1456
1611
|
addFiles(e.dataTransfer.files);
|
|
1457
1612
|
}
|
|
1458
1613
|
};
|
|
1459
|
-
return /* @__PURE__ */
|
|
1614
|
+
return /* @__PURE__ */ jsxs10("div", {
|
|
1460
1615
|
className: cn("yx-composer rounded-lg border border-border bg-card shadow-sm", disabled && "opacity-70", className),
|
|
1461
1616
|
onDrop,
|
|
1462
1617
|
onDragOver: (e) => e.preventDefault(),
|
|
1463
1618
|
"data-disabled": disabled ? "true" : undefined,
|
|
1464
1619
|
children: [
|
|
1465
|
-
attachments.length > 0 && /* @__PURE__ */
|
|
1620
|
+
attachments.length > 0 && /* @__PURE__ */ jsx11("ul", {
|
|
1466
1621
|
className: "flex flex-wrap gap-2 px-3 pt-3",
|
|
1467
1622
|
"aria-label": "attachments",
|
|
1468
|
-
children: attachments.map((a, i) => /* @__PURE__ */
|
|
1623
|
+
children: attachments.map((a, i) => /* @__PURE__ */ jsxs10("li", {
|
|
1469
1624
|
className: "relative",
|
|
1470
1625
|
children: [
|
|
1471
|
-
a.previewUrl ? /* @__PURE__ */
|
|
1626
|
+
a.previewUrl ? /* @__PURE__ */ jsx11("img", {
|
|
1472
1627
|
src: a.previewUrl,
|
|
1473
1628
|
alt: a.name,
|
|
1474
1629
|
className: "h-14 w-14 rounded-md border border-border object-cover"
|
|
1475
|
-
}) : /* @__PURE__ */
|
|
1630
|
+
}) : /* @__PURE__ */ jsx11("span", {
|
|
1476
1631
|
className: "block h-14 w-14 rounded-md border border-border bg-muted"
|
|
1477
1632
|
}),
|
|
1478
|
-
/* @__PURE__ */
|
|
1633
|
+
/* @__PURE__ */ jsx11("button", {
|
|
1479
1634
|
type: "button",
|
|
1480
1635
|
onClick: () => remove(i),
|
|
1481
1636
|
"aria-label": `Remove ${a.name}`,
|
|
1482
|
-
className: "absolute -right-
|
|
1483
|
-
children: /* @__PURE__ */
|
|
1484
|
-
className: "h-
|
|
1485
|
-
|
|
1637
|
+
className: "absolute -right-4 -top-4 flex h-11 w-11 items-center justify-center rounded-full",
|
|
1638
|
+
children: /* @__PURE__ */ jsx11("span", {
|
|
1639
|
+
className: "flex h-6 w-6 items-center justify-center rounded-full border border-border bg-background",
|
|
1640
|
+
children: /* @__PURE__ */ jsx11(X2, {
|
|
1641
|
+
className: "h-3 w-3",
|
|
1642
|
+
"aria-hidden": true
|
|
1643
|
+
})
|
|
1486
1644
|
})
|
|
1487
1645
|
})
|
|
1488
1646
|
]
|
|
1489
1647
|
}, `${a.name}-${i}`))
|
|
1490
1648
|
}),
|
|
1491
|
-
/* @__PURE__ */
|
|
1649
|
+
/* @__PURE__ */ jsx11("textarea", {
|
|
1492
1650
|
ref,
|
|
1493
1651
|
value: text,
|
|
1494
1652
|
onChange: (e) => setText(e.target.value),
|
|
@@ -1497,35 +1655,35 @@ function Composer({ onSubmit, running, onStop, disabled, disabledReason, placeho
|
|
|
1497
1655
|
disabled,
|
|
1498
1656
|
autoFocus,
|
|
1499
1657
|
rows: 1,
|
|
1500
|
-
placeholder: disabled && disabledReason ? disabledReason : placeholder,
|
|
1501
|
-
"aria-label": "Message",
|
|
1502
|
-
className: "block w-full resize-none bg-transparent px-3 py-3 text-[
|
|
1658
|
+
placeholder: disabled && disabledReason ? disabledReason : steering ? "Steer the agent (it reads this at its next step)…" : placeholder,
|
|
1659
|
+
"aria-label": steering ? "Steer" : "Message",
|
|
1660
|
+
className: "block w-full resize-none bg-transparent px-3 py-3 text-[16px] leading-6 placeholder:text-muted-foreground focus-visible:outline-none"
|
|
1503
1661
|
}),
|
|
1504
|
-
/* @__PURE__ */
|
|
1662
|
+
/* @__PURE__ */ jsxs10("div", {
|
|
1505
1663
|
className: "flex items-center gap-1 px-2 pb-2",
|
|
1506
1664
|
children: [
|
|
1507
1665
|
leading,
|
|
1508
|
-
hopOptions && hopOptions.length > 0 && /* @__PURE__ */
|
|
1666
|
+
hopOptions && hopOptions.length > 0 && /* @__PURE__ */ jsx11("select", {
|
|
1509
1667
|
value: hop ?? "",
|
|
1510
1668
|
onChange: (e) => onHopChange?.(e.target.value),
|
|
1511
1669
|
disabled,
|
|
1512
1670
|
"aria-label": "HOP",
|
|
1513
1671
|
className: "min-h-9 max-w-[45%] rounded-md border border-border bg-background px-2 text-[12.5px]",
|
|
1514
|
-
children: hopOptions.map((o) => /* @__PURE__ */
|
|
1672
|
+
children: hopOptions.map((o) => /* @__PURE__ */ jsx11("option", {
|
|
1515
1673
|
value: o.value,
|
|
1516
1674
|
title: o.description,
|
|
1517
1675
|
children: o.label
|
|
1518
1676
|
}, o.value))
|
|
1519
1677
|
}),
|
|
1520
|
-
/* @__PURE__ */
|
|
1678
|
+
!hideAttach && /* @__PURE__ */ jsxs10("label", {
|
|
1521
1679
|
className: cn("flex h-11 w-11 cursor-pointer items-center justify-center rounded-md text-muted-foreground hover:bg-muted", disabled && "pointer-events-none"),
|
|
1522
1680
|
"aria-label": "Attach image",
|
|
1523
1681
|
children: [
|
|
1524
|
-
/* @__PURE__ */
|
|
1682
|
+
/* @__PURE__ */ jsx11(ImagePlus, {
|
|
1525
1683
|
className: "h-4 w-4",
|
|
1526
1684
|
"aria-hidden": true
|
|
1527
1685
|
}),
|
|
1528
|
-
/* @__PURE__ */
|
|
1686
|
+
/* @__PURE__ */ jsx11("input", {
|
|
1529
1687
|
type: "file",
|
|
1530
1688
|
accept: ACCEPT.join(","),
|
|
1531
1689
|
multiple: true,
|
|
@@ -1535,29 +1693,29 @@ function Composer({ onSubmit, running, onStop, disabled, disabledReason, placeho
|
|
|
1535
1693
|
})
|
|
1536
1694
|
]
|
|
1537
1695
|
}),
|
|
1538
|
-
note && /* @__PURE__ */
|
|
1696
|
+
note && /* @__PURE__ */ jsx11("span", {
|
|
1539
1697
|
className: "truncate text-[12px] text-destructive",
|
|
1540
1698
|
children: note
|
|
1541
1699
|
}),
|
|
1542
|
-
/* @__PURE__ */
|
|
1700
|
+
/* @__PURE__ */ jsx11("span", {
|
|
1543
1701
|
className: "flex-1"
|
|
1544
1702
|
}),
|
|
1545
|
-
running ? /* @__PURE__ */
|
|
1703
|
+
running && onStop && !(steering && text.trim()) ? /* @__PURE__ */ jsx11("button", {
|
|
1546
1704
|
type: "button",
|
|
1547
1705
|
onClick: onStop,
|
|
1548
1706
|
"aria-label": "Stop",
|
|
1549
1707
|
className: "flex h-11 w-11 items-center justify-center rounded-md bg-destructive text-destructive-foreground",
|
|
1550
|
-
children: /* @__PURE__ */
|
|
1708
|
+
children: /* @__PURE__ */ jsx11(Square2, {
|
|
1551
1709
|
className: "h-4 w-4",
|
|
1552
1710
|
"aria-hidden": true
|
|
1553
1711
|
})
|
|
1554
|
-
}) : /* @__PURE__ */
|
|
1712
|
+
}) : /* @__PURE__ */ jsx11("button", {
|
|
1555
1713
|
type: "button",
|
|
1556
1714
|
onClick: submit,
|
|
1557
1715
|
disabled: !canSend,
|
|
1558
1716
|
"aria-label": "Send",
|
|
1559
1717
|
className: "flex h-11 w-11 items-center justify-center rounded-md bg-primary text-primary-foreground disabled:opacity-40",
|
|
1560
|
-
children: /* @__PURE__ */
|
|
1718
|
+
children: /* @__PURE__ */ jsx11(ArrowUp, {
|
|
1561
1719
|
className: "h-4 w-4",
|
|
1562
1720
|
"aria-hidden": true
|
|
1563
1721
|
})
|
|
@@ -1582,6 +1740,7 @@ export {
|
|
|
1582
1740
|
buildOutcome,
|
|
1583
1741
|
applyEvent,
|
|
1584
1742
|
YodexClient,
|
|
1743
|
+
TranscriptRow,
|
|
1585
1744
|
Transcript,
|
|
1586
1745
|
ToolCall,
|
|
1587
1746
|
SessionList,
|
|
@@ -1591,8 +1750,9 @@ export {
|
|
|
1591
1750
|
PermissionPrompt,
|
|
1592
1751
|
DiffView,
|
|
1593
1752
|
Composer,
|
|
1594
|
-
AssistantMessage
|
|
1753
|
+
AssistantMessage,
|
|
1754
|
+
ApprovalPrompt
|
|
1595
1755
|
};
|
|
1596
1756
|
|
|
1597
|
-
//# debugId=
|
|
1757
|
+
//# debugId=C0D62ACAF9016C3D64756E2164756E21
|
|
1598
1758
|
//# sourceMappingURL=index.js.map
|