pulls.review 0.3.0 → 0.3.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.
Files changed (95) hide show
  1. package/README.md +1 -1
  2. package/dist/client/assets/ActionButton-wEgApzce.js +1 -0
  3. package/dist/client/assets/ActionIconButton-wh9iuTi4.js +1 -0
  4. package/dist/client/assets/{ChatMessage-Ccffh_8Z.js → ChatMessage-wZOblr2O.js} +23 -23
  5. package/dist/client/assets/ChatWidget-Dbic6F6V.js +1 -0
  6. package/dist/client/assets/DisplayFileIcon-DffhOXN6.js +151 -0
  7. package/dist/client/assets/GithubAvatar-eLlc5vap.js +1 -0
  8. package/dist/client/assets/LandingHero-Bb_CGwOP.js +1 -0
  9. package/dist/client/assets/LocalAgentSettings-CWvSCuNr.js +1 -0
  10. package/dist/client/assets/ModelPicker-CLoBWotf.js +3 -0
  11. package/dist/client/assets/SelectViewport-Dt28PIGK.js +1 -0
  12. package/dist/client/assets/_repo_-BIF9MuRW.js +22 -0
  13. package/dist/client/assets/analyze-B3YV6_zK.js +1 -0
  14. package/dist/client/assets/{core-messages-CsAgH4H9.js → core-messages-E0LWb5xA.js} +1 -1
  15. package/dist/client/assets/de-BfUc2exP.js +1 -0
  16. package/dist/client/assets/{diagnostics-CrG4-M7r.js → diagnostics-DundJi2s.js} +1 -1
  17. package/dist/client/assets/diff-BwixkBTz.js +1 -0
  18. package/dist/client/assets/{diff-Bq6jHPox.js → diff-Coo81SbJ.js} +3 -3
  19. package/dist/client/assets/diffs-store-BPvgHGVY.js +1431 -0
  20. package/dist/client/assets/en-OkC_9BLh.js +1 -0
  21. package/dist/client/assets/es-DuVRv3jP.js +1 -0
  22. package/dist/client/assets/fr-BI5_M_ty.js +1 -0
  23. package/dist/client/assets/glimmer-js-BheR6Tf0.js +1 -0
  24. package/dist/client/assets/glimmer-ts-B3Q3-uij.js +1 -0
  25. package/dist/client/assets/handlebars-qjPKy-PP.js +1 -0
  26. package/dist/client/assets/i18n-DtZTpAlH.js +2 -0
  27. package/dist/client/assets/id-BU9INgNZ.js +1 -0
  28. package/dist/client/assets/{index-DP4XBqUv.js → index-Buksdj5x.js} +2 -2
  29. package/dist/client/assets/index-m8kW8Q0V.css +1 -0
  30. package/dist/client/assets/{install-DKy8VRs5.js → install-BrSGg9K8.js} +3 -3
  31. package/dist/client/assets/it-C2TUiK_A.js +1 -0
  32. package/dist/client/assets/ja-BQDWzjgo.js +1 -0
  33. package/dist/client/assets/ko-Ca7kDPia.js +1 -0
  34. package/dist/client/assets/{llm-XBWohzAo.js → llm-5e9k-gOP.js} +5 -4
  35. package/dist/client/assets/llm-store-1j45N-6d.js +1 -0
  36. package/dist/client/assets/local-agents-0SHBuj0A.js +1 -0
  37. package/dist/client/assets/{pages-Tf2MYsp8.js → pages-hDJHVoGR.js} +1 -1
  38. package/dist/client/assets/pages-local-0BoMyVi4.js +1 -0
  39. package/dist/client/assets/pages-web-QiNoFNlt.js +21 -0
  40. package/dist/client/assets/{portalTarget-DQg8GgWm.js → portalTarget-I9JDQCD2.js} +1 -1
  41. package/dist/client/assets/pt-BR-DcjGEP2y.js +1 -0
  42. package/dist/client/assets/{rpc-backends-CLzNPIWN.js → rpc-backends-arDnFRtp.js} +1 -1
  43. package/dist/client/assets/ru-DhCHBcLb.js +1 -0
  44. package/dist/client/assets/{ruby-CfFGiaYl.js → ruby-CaMjWH7T.js} +1 -1
  45. package/dist/client/assets/runtime-dom.esm-bundler-DL194Z-s.js +2 -0
  46. package/dist/client/assets/{source-Dk1PNoY7.js → source-CvnvCX42.js} +1 -1
  47. package/dist/client/assets/upload-Bi-0MPhd.js +1 -0
  48. package/dist/client/assets/useDocumentTitle-DSsMzDvH.js +92 -0
  49. package/dist/client/assets/useNonce-DujRSGP5.js +1 -0
  50. package/dist/client/assets/useTypeahead-CV0JPPYe.js +1 -0
  51. package/dist/client/assets/utils-bzkWQhBP.js +1 -0
  52. package/dist/client/assets/vue-i18n-B4RRzKT-.js +5 -0
  53. package/dist/client/assets/zh-CN-DKqrk-nJ.js +1 -0
  54. package/dist/client/assets/zh-TW-CXhwUL4C.js +1 -0
  55. package/dist/client/index.html +8 -8
  56. package/dist/{devframe-D66W-pHy.mjs → devframe-Z3sgjlMJ.mjs} +325 -56
  57. package/dist/devframe.mjs +1 -1
  58. package/dist/index.mjs +2 -2
  59. package/package.json +2 -2
  60. package/dist/client/assets/ActionButton-V4dY2wPS.js +0 -1
  61. package/dist/client/assets/ActionIconButton-4b5xelMn.js +0 -1
  62. package/dist/client/assets/ChatWidget-BFjNWi3R.js +0 -1
  63. package/dist/client/assets/DisplayFileIcon-DIcJdZir.js +0 -151
  64. package/dist/client/assets/GithubAvatar-DGJrpCsX.js +0 -1
  65. package/dist/client/assets/LandingHero-CS9lP7Qs.js +0 -1
  66. package/dist/client/assets/LocalAgentSettings-C4AeYCZ0.js +0 -1
  67. package/dist/client/assets/ModelPicker-CDTiUMZ3.js +0 -3
  68. package/dist/client/assets/SelectViewport-DF4P4Akh.js +0 -1
  69. package/dist/client/assets/_repo_-DtGh1V5_.js +0 -22
  70. package/dist/client/assets/analyze-CTcNbJBk.js +0 -1
  71. package/dist/client/assets/de-DQCc3irO.js +0 -1
  72. package/dist/client/assets/diff-BsZcYqbE.js +0 -1
  73. package/dist/client/assets/diffs-store-CzecLzBW.js +0 -1431
  74. package/dist/client/assets/en-CBwAorrh.js +0 -1
  75. package/dist/client/assets/es-hetdr90_.js +0 -1
  76. package/dist/client/assets/fr-Cayf6fbk.js +0 -1
  77. package/dist/client/assets/i18n-CgsK6PK3.js +0 -2
  78. package/dist/client/assets/id-lw2zLhUO.js +0 -1
  79. package/dist/client/assets/index-DSHKSKKf.css +0 -1
  80. package/dist/client/assets/it-BfFzmCsC.js +0 -1
  81. package/dist/client/assets/ja-DxaV4C1r.js +0 -1
  82. package/dist/client/assets/ko-D93r2P2k.js +0 -1
  83. package/dist/client/assets/llm-store-7CdL0d74.js +0 -1
  84. package/dist/client/assets/local-agents-BQLn-Ppw.js +0 -1
  85. package/dist/client/assets/pages-local-iBHcLWBK.js +0 -1
  86. package/dist/client/assets/pages-web-Bmq8l7JI.js +0 -21
  87. package/dist/client/assets/pt-BR-Isafy_5V.js +0 -1
  88. package/dist/client/assets/ru-Bx9Wj7Aa.js +0 -1
  89. package/dist/client/assets/runtime-dom.esm-bundler-Du_ZCcVN.js +0 -2
  90. package/dist/client/assets/upload-CFwsDMhO.js +0 -1
  91. package/dist/client/assets/useDocumentTitle-ByFCALbG.js +0 -92
  92. package/dist/client/assets/useNonce-CwUrgryd.js +0 -1
  93. package/dist/client/assets/vue-i18n-CGHHpbTP.js +0 -5
  94. package/dist/client/assets/zh-CN-CgGEKuLF.js +0 -1
  95. package/dist/client/assets/zh-TW-DzNR26_1.js +0 -1
@@ -1,11 +1,10 @@
1
- import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
1
+ import { mkdir, rm, writeFile } from "node:fs/promises";
2
2
  import process from "node:process";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { promisify } from "node:util";
5
5
  import { join, relative, resolve } from "node:path";
6
6
  import { AGENT_SESSION_LOST, LOCAL_AGENT_CHANNEL, LOCAL_DEVFRAME_ID, LOCAL_RPC, LocalAgentInfoSchema } from "@pulls.review/core/local-rpc";
7
7
  import { defineDevframe, defineRpcFunction } from "devframe";
8
- import { tmpdir } from "node:os";
9
8
  import { LOCAL_AGENT_NAMES } from "@pulls.review/core/analyze";
10
9
  import { LOCALES } from "@pulls.review/core/locales";
11
10
  import { AgentSessionRefSchema, DiffsPayloadSchema } from "@pulls.review/core/types";
@@ -19,7 +18,7 @@ import { githubTokenFromEnv } from "@pulls.review/core/env";
19
18
  import fsDriver from "unstorage/drivers/fs";
20
19
  //#region package.json
21
20
  var name = "pulls.review";
22
- var version = "0.3.0";
21
+ var version = "0.3.2";
23
22
  //#endregion
24
23
  //#region src/agents/run.ts
25
24
  var AgentRunError = class extends Error {
@@ -183,7 +182,8 @@ async function runAgentAnalysis({ cli, model, diff, locale, cwd, patchDir, emit,
183
182
  cwd,
184
183
  system,
185
184
  prompt,
186
- model
185
+ model,
186
+ sessionDir: patchDir
187
187
  }, transcript, {
188
188
  ...turn,
189
189
  step: 1
@@ -201,7 +201,8 @@ async function runAgentAnalysis({ cli, model, diff, locale, cwd, patchDir, emit,
201
201
  system,
202
202
  prompt: answer.fix,
203
203
  model,
204
- resume: outcome.session.id
204
+ resume: outcome.session.id,
205
+ sessionDir: patchDir
205
206
  }, transcript, {
206
207
  ...turn,
207
208
  step: 2
@@ -332,7 +333,8 @@ async function runAgentChat({ cli, model, diff, locale, cwd, patchDir, emit, sig
332
333
  system,
333
334
  prompt: message,
334
335
  model,
335
- resume: resume.id
336
+ resume: resume.id,
337
+ sessionDir: patchDir
336
338
  }, transcript, {
337
339
  emit,
338
340
  signal,
@@ -439,7 +441,7 @@ const MODELS = [
439
441
  name: "Haiku (latest)"
440
442
  }
441
443
  ];
442
- const READ_ONLY_TOOLS = [
444
+ const READ_ONLY_TOOLS$1 = [
443
445
  "Read",
444
446
  "Grep",
445
447
  "Glob"
@@ -474,7 +476,7 @@ const Content = v.variant("type", [
474
476
  is_error: v.optional(v.boolean())
475
477
  })
476
478
  ]);
477
- const Line$1 = v.variant("type", [
479
+ const Line$2 = v.variant("type", [
478
480
  v.object({
479
481
  type: v.literal("system"),
480
482
  subtype: v.string(),
@@ -500,12 +502,12 @@ const Line$1 = v.variant("type", [
500
502
  session_id: v.string()
501
503
  })
502
504
  ]);
503
- function textOf(content) {
505
+ function textOf$1(content) {
504
506
  if (typeof content === "string") return content;
505
507
  return (content ?? []).map((part) => typeof part.text === "string" ? part.text : "").join("");
506
508
  }
507
509
  /** Claude validates the answer itself against the grouping schema, so `final.structured` is already parsed. */
508
- function args$1({ system, model, resume }) {
510
+ function args$3({ system, model, resume }) {
509
511
  const list = [
510
512
  "-p",
511
513
  "--output-format",
@@ -516,7 +518,7 @@ function args$1({ system, model, resume }) {
516
518
  "--permission-mode",
517
519
  "dontAsk",
518
520
  "--allowedTools",
519
- ...READ_ONLY_TOOLS,
521
+ ...READ_ONLY_TOOLS$1,
520
522
  "--disallowedTools",
521
523
  ...WRITE_TOOLS,
522
524
  "--json-schema",
@@ -553,7 +555,7 @@ function mapLine(line, model, toolNames) {
553
555
  if (typeof line.message.content === "string") return [];
554
556
  return line.message.content.flatMap((part) => part.type === "tool_result" ? [{
555
557
  kind: "message",
556
- message: toolResultMessage(part.tool_use_id, toolNames.get(part.tool_use_id) ?? "tool", textOf(part.content), part.is_error ?? false)
558
+ message: toolResultMessage(part.tool_use_id, toolNames.get(part.tool_use_id) ?? "tool", textOf$1(part.content), part.is_error ?? false)
557
559
  }] : []);
558
560
  case "result": return [{
559
561
  kind: "final",
@@ -571,7 +573,7 @@ const claude = {
571
573
  async *run(input) {
572
574
  let model = input.model ?? "claude";
573
575
  const toolNames = /* @__PURE__ */ new Map();
574
- for await (const item of spawnJsonLines("claude", args$1(input), {
576
+ for await (const item of spawnJsonLines("claude", args$3(input), {
575
577
  cwd: input.cwd,
576
578
  signal: input.signal,
577
579
  stdin: input.prompt
@@ -584,7 +586,7 @@ const claude = {
584
586
  };
585
587
  return;
586
588
  }
587
- const parsed = v.safeParse(Line$1, item.line);
589
+ const parsed = v.safeParse(Line$2, item.line);
588
590
  if (!parsed.success) continue;
589
591
  for (const event of mapLine(parsed.output, model, toolNames)) {
590
592
  if (event.kind === "session" && event.model) model = event.model;
@@ -594,6 +596,152 @@ const claude = {
594
596
  }
595
597
  };
596
598
  //#endregion
599
+ //#region src/agents/codex.ts
600
+ const Item = v.variant("type", [
601
+ v.object({
602
+ type: v.literal("agent_message"),
603
+ id: v.string(),
604
+ text: v.string()
605
+ }),
606
+ v.object({
607
+ type: v.literal("reasoning"),
608
+ id: v.string(),
609
+ text: v.string()
610
+ }),
611
+ v.object({
612
+ type: v.literal("command_execution"),
613
+ id: v.string(),
614
+ command: v.string(),
615
+ aggregated_output: v.string(),
616
+ exit_code: v.nullable(v.number()),
617
+ status: v.string()
618
+ })
619
+ ]);
620
+ const Line$1 = v.variant("type", [
621
+ v.object({
622
+ type: v.literal("thread.started"),
623
+ thread_id: v.string()
624
+ }),
625
+ v.object({
626
+ type: v.literal("item.started"),
627
+ item: Item
628
+ }),
629
+ v.object({
630
+ type: v.literal("item.completed"),
631
+ item: Item
632
+ }),
633
+ v.object({ type: v.literal("turn.completed") }),
634
+ v.object({
635
+ type: v.literal("turn.failed"),
636
+ error: v.object({ message: v.string() })
637
+ }),
638
+ v.object({
639
+ type: v.literal("error"),
640
+ message: v.string()
641
+ })
642
+ ]);
643
+ function args$2({ model, resume }) {
644
+ const list = [
645
+ "exec",
646
+ "--json",
647
+ "--sandbox",
648
+ "read-only",
649
+ "-c",
650
+ "approval_policy=\"never\"",
651
+ "--skip-git-repo-check"
652
+ ];
653
+ if (model) list.push("--model", model);
654
+ if (resume) list.push("resume", resume);
655
+ list.push("-");
656
+ return list;
657
+ }
658
+ function itemEvents(line, state) {
659
+ const item = line.item;
660
+ if (item.type !== "command_execution") {
661
+ if (line.type !== "item.completed") return [];
662
+ if (item.type === "agent_message") state.lastText = item.text;
663
+ return [{
664
+ kind: "message",
665
+ message: assistantMessage("codex", state.model, [{
666
+ type: "text",
667
+ text: item.text
668
+ }])
669
+ }];
670
+ }
671
+ const events = [];
672
+ if (!state.commands.has(item.id)) {
673
+ state.commands.add(item.id);
674
+ events.push({
675
+ kind: "message",
676
+ message: assistantMessage("codex", state.model, [toolCall(item.id, "shell", { command: item.command })])
677
+ });
678
+ }
679
+ if (line.type === "item.completed") events.push({
680
+ kind: "message",
681
+ message: toolResultMessage(item.id, "shell", item.aggregated_output, item.status === "failed" || item.exit_code !== null && item.exit_code !== 0)
682
+ });
683
+ return events;
684
+ }
685
+ function lineEvents$1(line, state, model) {
686
+ switch (line.type) {
687
+ case "thread.started": return [{
688
+ kind: "session",
689
+ id: line.thread_id,
690
+ model
691
+ }];
692
+ case "error":
693
+ state.errorText = line.message;
694
+ return [];
695
+ case "turn.failed":
696
+ state.errorText = line.error.message;
697
+ return [{
698
+ kind: "final",
699
+ text: state.errorText,
700
+ isError: true
701
+ }];
702
+ case "turn.completed": return [{
703
+ kind: "final",
704
+ text: state.lastText
705
+ }];
706
+ default: return itemEvents(line, state);
707
+ }
708
+ }
709
+ /** Codex exec persists threads in its own storage; JSONL carries the thread id, not the model. */
710
+ const codex = {
711
+ name: "codex",
712
+ label: "Codex",
713
+ detect: () => readVersion("codex"),
714
+ models: async () => [],
715
+ async *run(input) {
716
+ const state = {
717
+ model: input.model ?? "default",
718
+ errorText: "",
719
+ commands: /* @__PURE__ */ new Set()
720
+ };
721
+ for await (const event of spawnJsonLines("codex", args$2(input), {
722
+ cwd: input.cwd,
723
+ signal: input.signal,
724
+ stdin: `${input.system}\n\n${input.prompt}`
725
+ })) {
726
+ if ("exit" in event) {
727
+ if (event.exit.code !== 0 && !input.signal.aborted) yield {
728
+ kind: "final",
729
+ text: state.errorText || event.exit.stderr,
730
+ isError: true
731
+ };
732
+ yield {
733
+ kind: "exit",
734
+ ...event.exit,
735
+ sessionLost: /no (?:saved )?(?:session|conversation).*found|(?:session|thread|conversation).*not found|failed to (?:load|resume).*session/i.test(`${state.errorText}\n${event.exit.stderr}`)
736
+ };
737
+ return;
738
+ }
739
+ const parsed = v.safeParse(Line$1, event.line);
740
+ if (parsed.success) yield* lineEvents$1(parsed.output, state, input.model);
741
+ }
742
+ }
743
+ };
744
+ //#endregion
597
745
  //#region src/agents/opencode.ts
598
746
  /** `opencode run --format json`: one event per line, each a part of the assistant's message. */
599
747
  const Part = v.variant("type", [
@@ -628,7 +776,7 @@ async function listModels() {
628
776
  name: id
629
777
  }));
630
778
  }
631
- function args({ model, resume }) {
779
+ function args$1({ model, resume }) {
632
780
  const list = [
633
781
  "run",
634
782
  "--format",
@@ -658,51 +806,175 @@ function mapPart(part, model) {
658
806
  message: toolResultMessage(part.callID, part.tool, failed ? part.state.error ?? "failed" : part.state.output ?? "", failed)
659
807
  }];
660
808
  }
809
+ const opencode = {
810
+ name: "opencode",
811
+ label: "OpenCode",
812
+ detect: () => readVersion("opencode"),
813
+ models: () => listModels().catch(() => []),
814
+ async *run(input) {
815
+ const { cwd, system, prompt, model, signal } = input;
816
+ let session;
817
+ let lastText;
818
+ for await (const item of spawnJsonLines("opencode", args$1(input), {
819
+ cwd,
820
+ signal,
821
+ stdin: `${system}\n\n${prompt}`
822
+ })) {
823
+ if ("exit" in item) {
824
+ if (item.exit.code === 0) yield {
825
+ kind: "final",
826
+ text: lastText
827
+ };
828
+ yield {
829
+ kind: "exit",
830
+ ...item.exit,
831
+ sessionLost: /Session not found/i.test(item.exit.stderr)
832
+ };
833
+ return;
834
+ }
835
+ const parsed = v.safeParse(Line, item.line);
836
+ if (!parsed.success) continue;
837
+ const { sessionID, part } = parsed.output;
838
+ if (sessionID && sessionID !== session) {
839
+ session = sessionID;
840
+ yield {
841
+ kind: "session",
842
+ id: sessionID
843
+ };
844
+ }
845
+ if (part?.type === "text") lastText = part.text;
846
+ if (part) yield* mapPart(part, model ?? "opencode");
847
+ }
848
+ }
849
+ };
850
+ //#endregion
851
+ //#region src/agents/pi.ts
852
+ const READ_ONLY_TOOLS = "read,grep,find,ls";
853
+ function args(input, sessionId) {
854
+ const list = [
855
+ "--mode",
856
+ "json",
857
+ input.resume ? "--session" : "--session-id",
858
+ input.resume ?? sessionId,
859
+ "--name",
860
+ "pulls.review",
861
+ "--system-prompt",
862
+ input.system,
863
+ "--tools",
864
+ READ_ONLY_TOOLS,
865
+ "--no-skills",
866
+ "--no-prompt-templates",
867
+ "--no-context-files",
868
+ "--no-approve"
869
+ ];
870
+ if (input.sessionDir) list.push("--session-dir", input.sessionDir);
871
+ if (input.model) list.push("--model", input.model);
872
+ else if (process.env.PI_PROVIDER && process.env.PI_MODEL) list.push("--provider", process.env.PI_PROVIDER, "--model", process.env.PI_MODEL);
873
+ return list;
874
+ }
875
+ function record(value) {
876
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
877
+ }
878
+ function isAssistantMessage(value) {
879
+ const message = record(value);
880
+ return message?.role === "assistant" && Array.isArray(message.content);
881
+ }
882
+ function isToolResultMessage(value) {
883
+ const message = record(value);
884
+ return message?.role === "toolResult" && Array.isArray(message.content);
885
+ }
886
+ function textOf(message) {
887
+ return message.content.filter((part) => part.type === "text").map((part) => part.text).join("") || void 0;
888
+ }
889
+ function modelOf(message) {
890
+ return message.provider && message.model ? `${message.provider}/${message.model}` : message.model;
891
+ }
892
+ function finalEvent(state) {
893
+ return {
894
+ kind: "final",
895
+ text: state.finalError ?? state.finalText,
896
+ isError: state.finalError !== void 0
897
+ };
898
+ }
899
+ function isLostSession(stderr) {
900
+ return /session.*not found/i.test(stderr) || /no session found/i.test(stderr) || /session.*does not exist/i.test(stderr) || /session found in different project/i.test(stderr);
901
+ }
902
+ function messageEvents(value, state) {
903
+ if (isToolResultMessage(value)) return [{
904
+ kind: "message",
905
+ message: value
906
+ }];
907
+ if (!isAssistantMessage(value)) return [];
908
+ const events = [{
909
+ kind: "message",
910
+ message: value
911
+ }];
912
+ const model = modelOf(value);
913
+ if (state.session && model && model !== state.model) {
914
+ state.model = model;
915
+ events.push({
916
+ kind: "session",
917
+ id: state.session,
918
+ model
919
+ });
920
+ }
921
+ const text = textOf(value);
922
+ if (text) state.finalText = text;
923
+ if (value.stopReason === "error" || value.stopReason === "aborted") state.finalError = value.errorMessage ?? text ?? `Pi stopped: ${value.stopReason}`;
924
+ return events;
925
+ }
926
+ function lineEvents(value, state) {
927
+ const line = record(value);
928
+ if (!line || typeof line.type !== "string") return [];
929
+ if (line.type === "session" && typeof line.id === "string") {
930
+ state.session = line.id;
931
+ return [{
932
+ kind: "session",
933
+ id: line.id
934
+ }];
935
+ }
936
+ if (line.type === "message_end") return messageEvents(line.message, state);
937
+ if (line.type === "agent_settled" && !state.finalSent) {
938
+ state.finalSent = true;
939
+ return [finalEvent(state)];
940
+ }
941
+ return [];
942
+ }
661
943
  //#endregion
662
944
  //#region src/agents/index.ts
663
945
  const agents = {
664
946
  claude,
665
- opencode: {
666
- name: "opencode",
667
- label: "OpenCode",
668
- detect: () => readVersion("opencode"),
669
- models: () => listModels().catch(() => []),
947
+ opencode,
948
+ pi: {
949
+ name: "pi",
950
+ label: "Pi",
951
+ detect: () => readVersion("pi"),
952
+ models: async () => [],
670
953
  async *run(input) {
671
- const { cwd, system, prompt, model, signal } = input;
672
- let session;
673
- let lastText;
674
- for await (const item of spawnJsonLines("opencode", args(input), {
675
- cwd,
676
- signal,
677
- stdin: `${system}\n\n${prompt}`
954
+ const state = {
955
+ session: input.resume,
956
+ finalSent: false
957
+ };
958
+ const sessionId = randomUUID();
959
+ for await (const item of spawnJsonLines("pi", args(input, sessionId), {
960
+ cwd: input.cwd,
961
+ signal: input.signal,
962
+ stdin: input.prompt
678
963
  })) {
679
- if ("exit" in item) {
680
- if (item.exit.code === 0) yield {
681
- kind: "final",
682
- text: lastText
683
- };
684
- yield {
685
- kind: "exit",
686
- ...item.exit,
687
- sessionLost: /Session not found/i.test(item.exit.stderr)
688
- };
689
- return;
690
- }
691
- const parsed = v.safeParse(Line, item.line);
692
- if (!parsed.success) continue;
693
- const { sessionID, part } = parsed.output;
694
- if (sessionID && sessionID !== session) {
695
- session = sessionID;
696
- yield {
697
- kind: "session",
698
- id: sessionID
699
- };
964
+ if ("line" in item) {
965
+ yield* lineEvents(item.line, state);
966
+ continue;
700
967
  }
701
- if (part?.type === "text") lastText = part.text;
702
- if (part) yield* mapPart(part, model ?? "opencode");
968
+ if (!state.finalSent && (state.finalText !== void 0 || state.finalError !== void 0)) yield finalEvent(state);
969
+ yield {
970
+ kind: "exit",
971
+ ...item.exit,
972
+ sessionLost: isLostSession(item.exit.stderr)
973
+ };
703
974
  }
704
975
  }
705
- }
976
+ },
977
+ codex
706
978
  };
707
979
  /** The agent CLIs on `PATH`, with their versions and model catalogs. */
708
980
  async function detectAgents() {
@@ -746,7 +1018,8 @@ function agentRpcFunctions({ cwd, patchDir, channel }) {
746
1018
  running.set(sink.id, controller);
747
1019
  sink.signal.addEventListener("abort", () => controller.abort());
748
1020
  (async () => {
749
- const scratch = args.diff.ref.kind === "local" ? void 0 : await mkdtemp(join(tmpdir(), "pulls-review-agent-"));
1021
+ const scratch = args.diff.ref.kind === "local" ? void 0 : join(patchDir, "workspace");
1022
+ if (scratch) await mkdir(scratch, { recursive: true });
750
1023
  try {
751
1024
  await run({
752
1025
  cli: agents[args.agent],
@@ -777,10 +1050,6 @@ function agentRpcFunctions({ cwd, patchDir, channel }) {
777
1050
  } finally {
778
1051
  running.delete(sink.id);
779
1052
  sink.close();
780
- if (scratch) await rm(scratch, {
781
- recursive: true,
782
- force: true
783
- });
784
1053
  }
785
1054
  })();
786
1055
  return { streamId: sink.id };
package/dist/devframe.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { t as devframe_default } from "./devframe-D66W-pHy.mjs";
1
+ import { t as devframe_default } from "./devframe-Z3sgjlMJ.mjs";
2
2
  export { devframe_default as default };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as devframe_default } from "./devframe-D66W-pHy.mjs";
1
+ import { t as devframe_default } from "./devframe-Z3sgjlMJ.mjs";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import process from "node:process";
4
4
  import { fileURLToPath } from "node:url";
@@ -51,7 +51,7 @@ Target (GitHub):
51
51
  Uses the GitHub token from GITHUB_TOKEN, else from \`gh auth token\`.
52
52
 
53
53
  AI analysis uses a key from Settings, or a coding agent installed here (Claude
54
- Code, OpenCode) when "Local agent" is the provider in Settings.
54
+ Code, OpenCode, Pi) when "Local agent" is the provider in Settings.
55
55
 
56
56
  Options:
57
57
  --worktree open the uncommitted changes against HEAD
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pulls.review",
3
3
  "type": "module",
4
- "version": "0.3.0",
4
+ "version": "0.3.2",
5
5
  "description": "Review local git changes - the working tree, a commit or any range - grouped and summarized in the browser.",
6
6
  "author": "Anthony Fu <hi@antfu.me>",
7
7
  "license": "MIT",
@@ -34,7 +34,7 @@
34
34
  "node": ">=20"
35
35
  },
36
36
  "dependencies": {
37
- "@pulls.review/core": "^0.3.0",
37
+ "@pulls.review/core": "^0.3.2",
38
38
  "devframe": "^1.2.0",
39
39
  "h3": "^2.0.1-rc.32",
40
40
  "unstorage": "^1.17.5",
@@ -1 +0,0 @@
1
- import{Bt as e,Cr as t,Er as n,G as r,H as i,K as a,W as o,Xt as s,qt as c,tt as l,yn as u}from"./vue-i18n-CGHHpbTP.js";var d=l({__name:`FeedbackSpinner`,props:{size:{default:`1em`}},setup(t){let r=t,o=i(()=>typeof r.size==`number`?`${r.size}px`:r.size);return(t,r)=>(e(),a(`span`,{class:`border-2 border-current border-t-transparent rounded-full inline-block animate-spin`,style:n({width:o.value,height:o.value}),role:`status`,"aria-label":`Loading`},null,4))}}),f=l({__name:`ActionButton`,props:{as:{},to:{},href:{},icon:{},variant:{default:`action`},size:{default:`md`},loading:{type:Boolean},disabled:{type:Boolean}},setup(n){let l=n,f=i(()=>l.as?l.as:l.href!=null||l.to!=null?`a`:`button`),p=i(()=>f.value===`a`),m=i(()=>f.value===`button`),h=i(()=>l.size===`sm`),g=i(()=>l.variant===`primary`?h.value?`btn-primary text-sm`:`btn-primary`:l.variant===`text`?h.value?`btn-text text-sm`:`btn-text`:h.value?`btn-action-sm`:`btn-action`),_=i(()=>l.disabled||l.loading);return(i,l)=>(e(),o(s(f.value),{class:t([g.value,{"pointer-events-none op-mute":_.value&&!m.value}]),href:p.value?n.href??n.to:void 0,to:n.as&&n.to!=null?n.to:void 0,disabled:m.value?_.value:void 0,"aria-disabled":_.value||void 0,"aria-busy":n.loading||void 0},{default:u(()=>[n.loading?(e(),o(d,{key:0,size:`1em`})):n.icon?(e(),a(`span`,{key:1,class:t(n.icon),"aria-hidden":`true`},null,2)):r(``,!0),c(i.$slots,`default`)]),_:3},8,[`class`,`href`,`to`,`disabled`,`aria-disabled`,`aria-busy`]))}});export{d as n,f as t};
@@ -1 +0,0 @@
1
- import{At as e,Bt as t,Cr as n,Dt as r,G as i,H as a,Hn as o,Ht as s,K as c,Mt as l,Ot as u,Pt as d,W as f,Wn as p,Xt as m,bt as ee,er as h,ft as g,lt as _,mn as v,qt as y,tt as b,xn as x,yn as S}from"./vue-i18n-CGHHpbTP.js";import{i as C}from"./runtime-dom.esm-bundler-Du_ZCcVN.js";import{a as w,c as T,f as te,i as ne,l as E,n as D,t as O}from"./floating-ui.dom-CfpSQvPs.js";var k=[`auto`,`top`,`bottom`,`left`,`right`].reduce((e,t)=>e.concat([t,`${t}-start`,`${t}-end`]),[]),A={targetNodes:{type:Function,required:!0},referenceNode:{type:Function,default:null},popperNode:{type:Function,required:!0},shown:{type:Boolean,default:!1},ariaId:{default:null},delay:{type:[String,Number,Object],default:0},triggers:{type:Array,default:()=>[]},showTriggers:{type:[Array,Function],default:void 0},hideTriggers:{type:[Array,Function],default:void 0},popperShowTriggers:{type:[Array,Function],default:void 0},popperHideTriggers:{type:[Array,Function],default:void 0},autoHide:{type:[Boolean,Function],default:!1},handleResize:{type:Boolean,default:!1},eagerMount:{type:Boolean,default:!1},popperClass:{type:[String,Array,Object],default:void 0},noAutoFocus:{type:Boolean,default:!1},disabled:{type:Boolean,default:void 0},placement:{type:String,validator:e=>k.includes(e),default:void 0},distance:{type:[Number,String],default:void 0},skidding:{type:[Number,String],default:void 0},popperTriggers:{type:Array,default:void 0},container:{type:[String,Object,Boolean],default:void 0},boundary:{type:[String,Object],default:void 0},strategy:{type:String,validator:e=>[`absolute`,`fixed`].includes(e),default:void 0},instantMove:{type:Boolean,default:void 0},preventOverflow:{type:Boolean,default:void 0},overflowPadding:{type:[Number,String],default:void 0},arrowPadding:{type:[Number,String],default:void 0},noArrow:{type:Boolean,default:void 0},flip:{type:Boolean,default:void 0},shift:{type:Boolean,default:void 0},shiftCrossAxis:{type:Boolean,default:void 0},disposeTimeout:{type:Number,default:void 0}},j={show:()=>!0,hide:()=>!0,"update:shown":e=>!0,"apply-show":()=>!0,"apply-hide":()=>!0,"close-directive":()=>!0,"auto-hide":()=>!0,resize:()=>!0},M=Object.freeze({disabled:!1,placement:`bottom`,distance:5,skidding:0,container:`body`,boundary:void 0,instantMove:!1,disposeTimeout:150,popperTriggers:[],strategy:`absolute`,preventOverflow:!0,flip:!0,shift:!0,shiftCrossAxis:!1,overflowPadding:0,arrowPadding:0,noArrow:!1,autoHideOnMousedown:!1});function re(){return _()?.appContext.provides.$_vueAfloatGlobalOptions??{}}function N(e){let t={};if(!e)return t;for(let n in e)e[n]!==void 0&&(t[n]=e[n]);return t}function ie(e,t=re()){return Object.assign({},M,N(t),N(e))}var ae={hover:`mouseenter`,focus:`focus`,click:`click`,touch:`touchstart`,pointer:`pointerdown`},oe={hover:`mouseleave`,focus:`blur`,click:`click`,touch:`touchend`,pointer:`pointerup`};function se(){return new Promise(e=>requestAnimationFrame(()=>{requestAnimationFrame(e)}))}var P=0,F=0,I=0,L=0,R=0;function ce(e){P=I,F=L,I=e.clientX,L=e.clientY}function le(){R++,R===1&&window.addEventListener(`mousemove`,ce,{passive:!0})}function ue(){R--,R===0&&window.removeEventListener(`mousemove`,ce)}function de(e,t){let n=e.getBoundingClientRect();if(I>=n.left&&I<=n.right&&L>=n.top&&L<=n.bottom){let e=t.getBoundingClientRect(),n=I-P,r=L-F,i=e.left+e.width/2-P+(e.top+e.height/2)-F+e.width+e.height,a=P+n*i,o=F+r*i;return z(P,F,a,o,e.left,e.top,e.left,e.bottom)||z(P,F,a,o,e.left,e.top,e.right,e.top)||z(P,F,a,o,e.right,e.top,e.right,e.bottom)||z(P,F,a,o,e.left,e.bottom,e.right,e.bottom)}return!1}function z(e,t,n,r,i,a,o,s){let c=((o-i)*(t-a)-(s-a)*(e-i))/((s-a)*(n-e)-(o-i)*(r-t)),l=((n-e)*(t-a)-(r-t)*(e-i))/((s-a)*(n-e)-(o-i)*(r-t));return c>=0&&c<=1&&l>=0&&l<=1}var fe=typeof window<`u`&&typeof navigator<`u`&&/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream,B=null,V=0;function pe(){return V++,B||=U(),B}function me(){V--,V===0&&B&&(B.dispose(),B=null)}function H(){if(B)for(let e of B.shownPoppers)e.computePosition()}function U(){let e=new Set,t=new Map;function n(){for(let t of e)if(t.options.value.autoHideOnMousedown)return!0;return!1}function r(t,r){if(n())a(t,r);else{let n=t.composedPath();for(let t of e)try{t.mouseDownContains=n.includes(t.popperNode())}catch{}}}function i(e,t){n()||a(e,t)}function a(t,n){let r={},i=t.composedPath(),a=[...e].reverse();for(let e of a)try{let o=Array.from(e.shownChildren).some(e=>{let t=a.find(t=>t.randomId===e);return t&&i.includes(t.popperNode())}),s=e.containsGlobalTarget=e.mouseDownContains||i.includes(e.popperNode())||o;e.pendingHide=!1,requestAnimationFrame(()=>{if(e.pendingHide=!1,!r[e.randomId]&&W(e,s,t)){if(e.handleGlobalClose(t,n),!t.closeAllPopover&&t.closePopover&&s){let t=e.parentPopper;for(;t;)r[t.randomId]=!0,t=t.parentPopper;return}let i=e.parentPopper;for(;i&&W(i,i.containsGlobalTarget,t);)i.handleGlobalClose(t,n),i=i.parentPopper}})}catch{}}let o=e=>r(e,!1),s=e=>i(e,!1),c=e=>r(e,!0),l=e=>i(e,!0);if(fe){let e={passive:!0,capture:!0};document.addEventListener(`touchstart`,c,e),document.addEventListener(`touchend`,l,e)}else window.addEventListener(`mousedown`,o,!0),window.addEventListener(`click`,s,!0);window.addEventListener(`resize`,H);function u(e){let t=e.popperNode().getRootNode();return t instanceof ShadowRoot?t.host:document.body}function d(e){e&&![...t.values()].includes(e)&&e.classList.remove(`vue-afloat--some-open`)}let f={shownPoppers:e,hidingPopper:null,markShown(n){e.add(n);let r=t.get(n),i=u(n);t.set(n,i),d(r),i.classList.add(`vue-afloat--some-open`)},markHidden(n){e.delete(n);let r=t.get(n);t.delete(n),d(r),f.hidingPopper===n&&(f.hidingPopper=null)},dispose(){fe?(document.removeEventListener(`touchstart`,c,{capture:!0}),document.removeEventListener(`touchend`,l,{capture:!0})):(window.removeEventListener(`mousedown`,o,!0),window.removeEventListener(`click`,s,!0)),window.removeEventListener(`resize`,H)}};return f}function W(e,t,n){return n.closeAllPopover||n.closePopover&&t||G(e,n)&&!t}function G(e,t){if(typeof e.autoHide==`function`){let n=e.autoHide(t);return e.lastAutoHide=n,n}return e.autoHide}function he(e,t){let n=[],r={strategy:e.strategy,middleware:n},i=e.boundary;(e.distance||e.skidding)&&n.push(T({mainAxis:e.distance,crossAxis:e.skidding}));let a=e.placement.startsWith(`auto`);return a?n.push(D({alignment:e.placement.split(`-`)[1]??``})):r.placement=e.placement,e.preventOverflow&&(e.shift&&n.push(E({padding:e.overflowPadding,boundary:i,crossAxis:e.shiftCrossAxis})),!a&&e.flip&&n.push(w({padding:e.overflowPadding,boundary:i}))),n.push(O({element:t,padding:e.arrowPadding})),r}var ge=class{entries=[];add(e,t,n){this.entries.push({targetNodes:e,eventType:t,handler:n});for(let r of e)r.addEventListener(t,n,{passive:!0})}addTriggers(e,t,n,r,i){let a=n;r!=null&&(a=typeof r==`function`?r(a):r);for(let n of a){let r=t[n];r&&this.add(e,r,i)}}remove(e){this.entries=this.entries.filter(t=>{if(!e||e===t.eventType){for(let e of t.targetNodes)e.removeEventListener(t.eventType,t.handler);return!1}return!0})}},_e=`__floating-vue__popper`;function ve(t,n){let r=_(),i=re(),c=a(()=>ie(t,i)),f=p(!1),m=p(!1),h=p(!1),g=o({showFrom:!1,showTo:!1,hideFrom:!1,hideTo:!0}),y=o({x:0,y:0,placement:``,strategy:c.value.strategy,arrow:{x:0,y:0,centerOffset:0}}),b=p(!0),x=`popper_${[Math.random(),Date.now()].map(e=>e.toString(36).substring(2,10)).join(`_`)}`,S=new Set,C=!0,w=!1,T=!1,E=!1,D,O,k,A=[],j,M,N=new ge,P=null,F=!1,I=ee(_e,null)?.parentPopper??null,L={randomId:x,options:c,get autoHide(){return t.autoHide},parentPopper:I,lockedChild:null,lockedChildTimer:null,shownChildren:S,pendingHide:!1,mouseDownContains:!1,containsGlobalTarget:!1,get lastAutoHide(){return b.value},set lastAutoHide(e){b.value=e},popperNode:()=>t.popperNode(),hide:V,applyHide:J,computePosition:()=>{G()},handleGlobalClose:Te};s(_e,{parentPopper:L});let R=a(()=>t.ariaId??x),ce=a(()=>t.eagerMount||m.value),z=a(()=>c.value.popperTriggers.includes(`hover`)||Array.isArray(t.popperShowTriggers)&&t.popperShowTriggers.includes(`hover`)),fe=a(()=>({popperId:R.value,isShown:f.value,shouldMountContent:ce.value,skipTransition:h.value,noArrow:c.value.noArrow,autoHide:typeof t.autoHide==`function`?b.value:t.autoHide,show:B,hide:V,handleResize:t.handleResize,onResize:W,classes:{...g,popperClass:t.popperClass},result:y}));function B({skipDelay:e=!1,force:t=!1}={}){I?.lockedChild&&I.lockedChild!==L||(L.pendingHide=!1,(t||!c.value.disabled)&&(I?.lockedChild===L&&(I.lockedChild=null),ve(e),n(`show`),T=!0,requestAnimationFrame(()=>{T=!1})),n(`update:shown`,!0))}function V({skipDelay:e=!1}={}){if(!E){if(S.size>0){L.pendingHide=!0;return}if(z.value&&de(k,j)){I&&(I.lockedChild=L,I.lockedChildTimer&&clearTimeout(I.lockedChildTimer),I.lockedChildTimer=setTimeout(()=>{I.lockedChild===L&&(I.lockedChild.hide({skipDelay:e}),I.lockedChild=null)},1e3));return}I?.lockedChild===L&&(I.lockedChild=null),L.pendingHide=!1,ye(e),n(`hide`),n(`update:shown`,!1)}}function H(){C&&(C=!1,m.value=!1,w=!1,k=t.referenceNode?.()??r.proxy.$el,A=t.targetNodes().filter(e=>e.nodeType===e.ELEMENT_NODE),j=t.popperNode(),M=j.querySelector(`.vue-afloat__arrow-container`),Z(`title`,`data-original-title`),X(),P=pe(),Y(),t.triggers.length&&Ce(),t.shown&&B())}function U(){C||(C=!0,N.remove(),V({skipDelay:!0}),X(),m.value=!1,f.value=!1,$(!1),Z(`data-original-title`,`title`),Y(),P&&=(me(),null))}async function W(){f.value&&(await G(),n(`resize`))}async function G(){if(C)return;let e=he(c.value,M),t=await ne(k,j,e);Object.assign(y,{x:t.x,y:t.y,placement:t.placement,strategy:t.strategy,arrow:t.middlewareData.arrow})}function ve(e=!1){$(!0),E=!1,clearTimeout(D);let t=P?.hidingPopper;if(t&&c.value.instantMove&&t.options.value.instantMove&&t!==I){t.applyHide(!0),q(!0);return}e?q():D=setTimeout(q,K(`show`))}function ye(e=!1){if(S.size>0){L.pendingHide=!0;return}$(!1),E=!0,clearTimeout(D),f.value&&P&&(P.hidingPopper=L),e?J():D=setTimeout(J,K(`hide`))}function K(e){let n=t.delay;return parseInt(n&&n[e]||n||0)}async function q(e=!1){clearTimeout(O),clearTimeout(D),h.value=e,!f.value&&(Se(),await se(),await G(),await be(),N.add([...te(k),...te(j)],`scroll`,()=>{G()}))}async function be(){E||(f.value=!0,Q({"aria-describedby":R.value,"data-popper-shown":``}),P?.markShown(L),n(`apply-show`),g.showFrom=!0,g.showTo=!1,g.hideFrom=!1,g.hideTo=!1,await se(),g.showFrom=!1,g.showTo=!0,t.noAutoFocus||j.focus())}async function J(e=!1){if(S.size>0){L.pendingHide=!0,E=!1;return}if(clearTimeout(D),!f.value)return;h.value=e,P?.markHidden(L),f.value=!1,Q({"aria-describedby":void 0,"data-popper-shown":void 0}),clearTimeout(O);let t=c.value.disposeTimeout;t!==null&&(O=setTimeout(()=>{j&&(X(),m.value=!1)},t)),N.remove(`scroll`),n(`apply-hide`),g.showFrom=!1,g.showTo=!1,g.hideFrom=!0,g.hideTo=!1,await se(),g.hideFrom=!1,g.hideTo=!0}function xe(){t.shown?B():V()}function Se(){if(C)return;let e=c.value.container,t;if(typeof e==`string`){let n=k.getRootNode();t=n instanceof ShadowRoot?e===`body`?n:n.querySelector(e):k.ownerDocument.querySelector(e)}else t=e===!1?A[0].parentNode:e;if(!t)throw Error(`No container for popover: ${e}`);t.appendChild(j),m.value=!0}function Ce(){let e=e=>{(!f.value||E)&&(e.usedByTooltip=!0,!w&&B({event:e}))};N.addTriggers(A,ae,t.triggers,t.showTriggers,e),N.addTriggers([j],ae,c.value.popperTriggers,t.popperShowTriggers,e);let n=e=>{e.usedByTooltip||V({event:e})};N.addTriggers(A,oe,t.triggers,t.hideTriggers,n),N.addTriggers([j],oe,c.value.popperTriggers,t.popperHideTriggers,n)}function we(){C||(N.remove(),Ce(),Y())}function Y(){let e=!C&&z.value;e!==F&&(F=e,e?le():ue())}function Te(e,t){T||(V({event:e}),e.closePopover?n(`close-directive`):n(`auto-hide`),t&&(w=!0,setTimeout(()=>{w=!1},300)))}function X(){j.parentNode&&j.parentNode.removeChild(j)}function Z(e,t){for(let n of A){let r=n.getAttribute(e);r&&(n.removeAttribute(e),n.setAttribute(t,r))}}function Q(e){for(let t of A)for(let n in e){let r=e[n];r==null?t.removeAttribute(n):t.setAttribute(n,r)}}function $(e){let t=I;for(;t;)e?t.shownChildren.add(x):(t.shownChildren.delete(x),t.pendingHide&&t.hide()),t=t.parentPopper}return v(()=>t.shown,xe),v(()=>c.value.disabled,e=>{e?U():H()}),v(()=>c.value.container,async()=>{f.value&&(Se(),P?.markShown(L),await G())}),v(()=>t.triggers,we,{deep:!0}),v(c,()=>G()),d(()=>{H(),X()}),u(xe),l(()=>{V()}),e(U),{show:B,hide:V,dispose:U,onResize:W,slotData:fe}}var ye=b({name:`VPopperRoot`,props:A,emits:j,setup(e,{emit:t,slots:n,expose:r}){let{show:i,hide:a,dispose:o,onResize:s,slotData:c}=ve(e,t);return r({show:i,hide:a,dispose:o,onResize:s}),()=>g(`div`,{ref:`reference`,class:[`vue-afloat`,{"vue-afloat--shown":c.value.isShown}]},n.default?.(c.value))}}),K=b({name:`VPopperContent`,props:{popperId:String,shown:Boolean,mounted:Boolean,skipTransition:Boolean,noArrow:Boolean,autoHide:Boolean,handleResize:Boolean,classes:{type:Object,required:!0},result:{type:Object,required:!0}},emits:[`hide`,`resize`],setup(t,{emit:n,slots:r}){let i=p(),a;d(()=>{t.handleResize&&(a=new ResizeObserver(()=>n(`resize`)),a.observe(i.value))}),e(()=>{a?.disconnect()});function o(e){return e!=null&&!Number.isNaN(e)?`${e}px`:null}return()=>{let{autoHide:e,classes:a,result:s,shown:c}=t,l=s.placement.split(`-`)[0];return g(`div`,{id:t.popperId,ref:`popover`,"data-allow-mismatch":``,class:[`vue-afloat`,`vue-afloat--${l}`,a.popperClass,{"vue-afloat--shown":c,"vue-afloat--hidden":!c,"vue-afloat--show-from":a.showFrom,"vue-afloat--show-to":a.showTo,"vue-afloat--hide-from":a.hideFrom,"vue-afloat--hide-to":a.hideTo,"vue-afloat--skip-transition":t.skipTransition,"vue-afloat--no-arrow":t.noArrow}],style:{position:s.strategy,transform:`translate3d(${Math.round(s.x)}px,${Math.round(s.y)}px,0)`},"aria-hidden":c||e?`false`:`true`,tabindex:e?0:void 0,"data-popper-placement":s.placement,onKeyup:t=>{t.key===`Escape`&&e&&n(`hide`)}},[g(`div`,{class:`vue-afloat__backdrop`,onClick:()=>e&&n(`hide`)}),g(`div`,{class:`vue-afloat__wrapper`},[g(`div`,{ref:i,class:`vue-afloat__inner`},t.mounted?[g(`div`,r.default?.())]:void 0),g(`div`,{ref:`arrow`,class:`vue-afloat__arrow-container`,style:{left:o(s.arrow.x),top:o(s.arrow.y)}},[g(`div`,{class:`vue-afloat__arrow-outer`}),g(`div`,{class:`vue-afloat__arrow-inner`})])])])}}}),q=new Set([`targetNodes`,`popperNode`]);function be(e){let t={};for(let n in A){if(q.has(n))continue;let r=A[n];t[n]=n in e?{...r,default:e[n]}:r}return t}function J(e,t,n={}){return b({name:e,props:be(n),emits:j,setup(e,{emit:n,slots:r,expose:i}){let a,o;function s(){return Array.from(a.$el.children).filter(e=>e!==o.$el)}return i({show:(...e)=>a.show(...e),hide:(...e)=>a.hide(...e),dispose:()=>a.dispose(),onResize:()=>a.onResize()}),()=>g(ye,{ref:e=>{a=e},...e,targetNodes:s,popperNode:()=>o.$el,class:t,onShow:()=>n(`show`),onHide:()=>n(`hide`),"onUpdate:shown":e=>n(`update:shown`,e),onApplyShow:()=>n(`apply-show`),onApplyHide:()=>n(`apply-hide`),onCloseDirective:()=>n(`close-directive`),onAutoHide:()=>n(`auto-hide`),onResize:()=>n(`resize`)},{default:({popperId:e,isShown:n,shouldMountContent:i,skipTransition:a,noArrow:s,autoHide:c,show:l,hide:u,handleResize:d,onResize:f,classes:p,result:m})=>[r.default?.({shown:n,show:l,hide:u}),g(K,{ref:e=>{o=e},class:t,popperId:e,shown:n,mounted:i,skipTransition:a,noArrow:s,autoHide:c,handleResize:d,classes:p,result:m,onHide:u,onResize:f},{default:()=>r.popper?.({shown:n,hide:u})})]})}})}J(`VDropdown`,`vue-afloat-dropdown`,{placement:`bottom`,triggers:()=>[`click`],delay:0,handleResize:!0,autoHide:!0}),J(`VMenu`,`vue-afloat-menu`,{placement:`bottom`,triggers:()=>[`hover`,`focus`],popperTriggers:()=>[`hover`],delay:()=>({show:0,hide:400}),handleResize:!0,autoHide:!0,noArrow:!0}),J(`VTooltip`,`vue-afloat-tooltip`,{placement:`top`,triggers:()=>[`hover`,`focus`,`touch`],hideTriggers:()=>e=>[...e,`click`],delay:()=>({show:200,hide:0})});function xe(){return b({name:`VPopper`,props:A,emits:j,setup(e,{emit:t,slots:n,expose:r}){let{show:i,hide:a,dispose:o,onResize:s,slotData:c}=ve(e,t);return r({show:i,hide:a,dispose:o,onResize:s}),()=>n.default?.(c.value)}})}var Se=xe(),Ce=b({name:`VTooltipDirective`,inheritAttrs:!1,props:{html:{type:Boolean,default:!1},content:{type:[String,Number,Function],default:null},loadingContent:{type:String,default:`...`},targetNodes:{type:Function,required:!0}},setup(e,{attrs:t,expose:n}){let i=p(null),o=a(()=>typeof e.content==`function`),s=a(()=>o.value&&i.value==null),c=a(()=>o.value?s.value?e.loadingContent:i.value:e.content),l,u,d=!1,f=!1,m=0;function ee(t=!1){if(typeof e.content==`function`&&d&&(t||!f&&i.value==null)){i.value=null,f=!0;let t=++m,n=e.content(e);n.then?n.then(e=>h(t,e)):h(t,n)}}function h(e,t){e===m&&(f=!1,i.value=t)}v(()=>e.content,()=>ee(!0),{immediate:!0}),v(c,async()=>{await r(),l.onResize()});function _(){d=!0,ee()}function y(){d=!1}return n({show:(...e)=>l.show(...e),hide:(...e)=>l.hide(...e),dispose:()=>l.dispose(),onResize:()=>l.onResize()}),()=>g(Se,{ref:e=>{l=e},placement:`top`,triggers:[`hover`,`focus`,`touch`],hideTriggers:e=>[...e,`click`],delay:{show:200,hide:0},...t,targetNodes:e.targetNodes,popperNode:()=>u.$el,onApplyShow:_,onApplyHide:y},{default:({popperId:t,isShown:n,shouldMountContent:r,skipTransition:i,noArrow:a,autoHide:o,hide:l,handleResize:d,onResize:f,classes:p,result:m})=>g(K,{ref:e=>{u=e},class:[`vue-afloat-tooltip`,{"vue-afloat--tooltip-loading":s.value}],popperId:t,shown:n,mounted:r,skipTransition:i,noArrow:a,autoHide:o,handleResize:d,classes:p,result:m,onHide:l,onResize:f},{default:()=>e.html?g(`div`,{innerHTML:c.value}):g(`div`,{textContent:c.value})})})}}),we=`vue-afloat--has-tooltip`;function Y(e,t){let n=e.placement;if(!n&&t)for(let e of k)t[e]&&(n=e);return n||=`top`,n}function Te(e,t,n){let r,i=typeof t;return r=i===`string`?{content:t}:t&&i===`object`?t:{content:!1},r.placement=Y(r,n),r.targetNodes=()=>[e],r.referenceNode=()=>e,r}var X,Z,Q=0;function $(){if(X)return;Z=p([]),X=C({name:`VTooltipDirectiveApp`,setup(){return{directives:Z}},render(){return this.directives.map(e=>{let t={...e.options,shown:e.shown||e.options.shown,key:e.id};return g(Ce,t)})},devtools:{hide:!0}});let e=document.createElement(`div`);X.mount(e)}function Ee(e,t,n){$();let r=p(Te(e,t,n)),i=p(!1),a={id:Q++,options:r,shown:i};return Z.value.push(a),e.classList&&e.classList.add(we),e.$_vueAfloat={options:r,item:a,show(){i.value=!0},hide(){i.value=!1}}}function De(e){if(e.$_vueAfloat){let t=Z.value.indexOf(e.$_vueAfloat.item);t!==-1&&Z.value.splice(t,1),delete e.$_vueAfloat,delete e.$_vueAfloatOldShown,delete e.$_vueAfloatMountTarget}e.classList&&e.classList.remove(we)}function Oe(e,{value:t,modifiers:n}){let r=Te(e,t,n);if(!r.content||M.disabled)De(e);else{let i;e.$_vueAfloat?(i=e.$_vueAfloat,i.options.value=r):i=Ee(e,t,n);let a=typeof t==`object`?t.shown:void 0;a!==void 0&&a!==e.$_vueAfloatOldShown&&(e.$_vueAfloatOldShown=a,a?i.show():i.hide())}}var ke={beforeMount:Oe,updated:Oe,beforeUnmount(e){De(e)}},Ae=b({__name:`ActionIconButton`,props:{as:{},to:{},href:{},icon:{},tooltip:{},active:{type:Boolean},disabled:{type:Boolean},label:{},compact:{type:Boolean},activeClass:{}},setup(e){let r=e,o=a(()=>r.as?r.as:r.href!=null||r.to!=null?`a`:`button`),s=a(()=>o.value===`a`),l=a(()=>o.value===`button`),u=a(()=>r.compact?`btn-icon-compact`:`btn-icon`),d=a(()=>r.compact?`w-auto! h-auto! p-[0.25em]`:`w-auto! h-auto! p-[0.5em]`),p=a(()=>r.active?r.activeClass||`color-active bg-active op100`:``);return(r,a)=>x((t(),f(m(o.value),{type:l.value?`button`:void 0,class:n([u.value,d.value,p.value,{"pointer-events-none op-mute":e.disabled&&!l.value}]),href:s.value?e.href??e.to:void 0,to:e.as&&e.to!=null?e.to:void 0,disabled:l.value?e.disabled:void 0,"aria-disabled":e.disabled&&!l.value||void 0,"aria-label":e.label??e.tooltip,"aria-pressed":e.active||void 0},{default:S(()=>[e.icon?(t(),c(`span`,{key:0,class:n(e.icon),"aria-hidden":`true`},null,2)):i(``,!0),y(r.$slots,`default`),y(r.$slots,`badge`)]),_:3},8,[`type`,`class`,`href`,`to`,`disabled`,`aria-disabled`,`aria-label`,`aria-pressed`])),[[h(ke),e.tooltip??``]])}});export{ke as n,Ae as t};
@@ -1 +0,0 @@
1
- import{$ as e,Bt as t,Dr as n,G as r,H as i,K as a,Kt as o,M as s,Q as c,Tt as l,U as u,W as d,Wn as f,h as p,sn as m,tt as h,un as g,xn as _,yn as v}from"./vue-i18n-CGHHpbTP.js";import{x as y}from"./runtime-dom.esm-bundler-Du_ZCcVN.js";import{t as b}from"./ActionButton-V4dY2wPS.js";import{t as x}from"./ActionIconButton-4b5xelMn.js";import{t as S}from"./ChatMessage-Ccffh_8Z.js";var C={class:`fixed bottom-4 right-4 z-dropdown`},w={key:1,class:`h-140 max-h-[calc(100vh-2rem)] max-w-[calc(100vw-2rem)] w-100 flex flex-col overflow-hidden border border-base rounded-lg bg-base shadow-xl`},T={class:`flex items-center gap-2 border-b border-base px-3 py-2`},E={class:`flex-auto text-sm font-semibold`},D={key:0,class:`flex flex-auto items-center justify-center p-6 text-center text-sm op-mute`},O={key:0,class:`flex items-center gap-1.5 text-xs op-mute`,role:`status`},k={key:0,class:`break-words px-3 pb-2 text-xs text-red-500`},A={class:`flex items-end gap-2 border-t border-base p-2`},j=[`placeholder`,`aria-label`,`disabled`],M=h({__name:`ChatWidget`,props:l({store:{}},{open:{type:Boolean,default:!1},openModifiers:{}}),emits:[`update:open`],setup(l){let h=l,M=i(()=>h.store.llm.chat),N=m(l,`open`),P=f(``),F=i(()=>M.value.isStreaming||h.store.llm.isAnalyzing),I=i(()=>M.value.messages.length-1),L=i(()=>{let e=M.value.messages.at(-1);return e?.role===`assistant`&&e.stopReason===`error`}),R=i(()=>{if(!M.value.isStreaming)return!1;let e=M.value.messages.at(-1),t=e?.role===`assistant`?e.content.at(-1):void 0;return!(t?.type===`text`&&t.text.trim())}),z=g(`listEl`),B=g(`contentEl`),V=f(!0);function H(){let e=z.value;e&&(V.value=e.scrollHeight-e.scrollTop-e.clientHeight<40)}p(B,()=>{V.value&&z.value&&(z.value.scrollTop=z.value.scrollHeight)});async function U(){let e=P.value;e.trim()&&!F.value&&(P.value=``,V.value=!0,await M.value.send(e))}function W(e){e.key!==`Enter`||e.shiftKey||e.isComposing||(e.preventDefault(),U())}return(i,l)=>(t(),a(`div`,C,[N.value?(t(),a(`div`,w,[u(`div`,T,[l[7]||=u(`span`,{class:`i-ph:chat-circle-dots-duotone op-mute`,"aria-hidden":`true`},null,-1),u(`span`,E,n(i.$t(`chat.title`)),1),M.value.available?(t(),d(b,{key:0,size:`sm`,variant:`text`,onClick:l[1]||=e=>M.value.clear()},{default:v(()=>[c(n(i.$t(`common.clear`)),1)]),_:1})):r(``,!0),e(x,{compact:``,icon:`i-ph:caret-down`,tooltip:i.$t(`chat.collapse`),onClick:l[2]||=e=>N.value=!1},null,8,[`tooltip`])]),M.value.available?(t(),a(s,{key:1},[u(`div`,{ref_key:`listEl`,ref:z,class:`min-w-0 flex-auto overflow-y-auto overscroll-contain p-3`,onScroll:H},[u(`div`,{ref_key:`contentEl`,ref:B,class:`flex flex-col gap-3`},[(t(!0),a(s,null,o(M.value.messages,(e,n)=>(t(),d(S,{key:n,message:e,retryable:n===I.value&&!M.value.isStreaming,onRetry:l[3]||=e=>M.value.retry()},null,8,[`message`,`retryable`]))),128)),R.value?(t(),a(`div`,O,[l[8]||=u(`span`,{class:`i-ph:spinner-duotone animate-spin`,"aria-hidden":`true`},null,-1),c(` `+n(i.$t(`chat.thinking`)),1)])):r(``,!0)],512)],544),M.value.error&&!L.value?(t(),a(`p`,k,n(M.value.error.message),1)):r(``,!0),u(`div`,A,[_(u(`textarea`,{"onUpdate:modelValue":l[4]||=e=>P.value=e,rows:`2`,placeholder:i.$t(`chat.placeholder`),"aria-label":i.$t(`chat.title`),disabled:F.value,class:`flex-auto resize-none border border-base rounded bg-raised p-2 text-sm outline-none disabled:op-mute focus-visible:ring-2 focus-visible:ring-primary-500/40`,onKeydown:W},null,40,j),[[y,P.value]]),M.value.isStreaming?(t(),d(b,{key:0,size:`sm`,icon:`i-ph:stop-duotone`,onClick:l[5]||=e=>M.value.stop()},{default:v(()=>[c(n(i.$t(`common.stop`)),1)]),_:1})):(t(),d(b,{key:1,size:`sm`,variant:`primary`,icon:`i-ph:paper-plane-right-duotone`,disabled:F.value||!P.value.trim(),onClick:l[6]||=e=>U()},{default:v(()=>[c(n(i.$t(`common.send`)),1)]),_:1},8,[`disabled`]))])],64)):(t(),a(`div`,D,n(i.$t(`chat.reanalyzeToEnable`)),1))])):(t(),d(x,{key:0,icon:`i-ph:chat-circle-dots-duotone`,title:i.$t(`chat.title`),label:i.$t(`chat.title`),class:`border border-base bg-base text-xl shadow-lg`,onClick:l[0]||=e=>N.value=!0},null,8,[`title`,`label`]))]))}});export{M as default};