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