@aiderdesk/aiderdesk 0.70.0 → 0.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +49 -0
  2. package/out/cli.js +1006 -1
  3. package/out/renderer/assets/{AgentSettings-4fCr6MRo.js → AgentSettings-BKSogFrU.js} +133 -125
  4. package/out/renderer/assets/{InfoIcon-Cend8bQ6.js → InfoIcon-XbMgPv1i.js} +1 -1
  5. package/out/renderer/assets/{Onboarding-SfOrsd7I.js → Onboarding-DsxeAj-M.js} +4 -4
  6. package/out/renderer/assets/{ProviderHeader-IIBa8Q98.js → ProviderHeader-CQHU1_fp.js} +384 -165
  7. package/out/renderer/assets/{SettingsPage-1PPq3lwt.js → SettingsPage-jGXWkGLq.js} +643 -265
  8. package/out/renderer/assets/{UsageDashboard-C73v7_7A.js → UsageDashboard-BcWDkudQ.js} +3 -3
  9. package/out/renderer/assets/{arc-DooaZ_2W.js → arc-CbTCDvhP.js} +1 -1
  10. package/out/renderer/assets/{architectureDiagram-3BPJPVTR-BZRfdU_l.js → architectureDiagram-3BPJPVTR-BYGjkH2o.js} +3 -3
  11. package/out/renderer/assets/{blockDiagram-GPEHLZMM-GVLrld7f.js → blockDiagram-GPEHLZMM-BNslNypY.js} +4 -4
  12. package/out/renderer/assets/{c4Diagram-AAUBKEIU-CuLHxnUp.js → c4Diagram-AAUBKEIU-BOUV-4Hf.js} +2 -2
  13. package/out/renderer/assets/{channel-CBp4QC42.js → channel-gTXtcW6n.js} +1 -1
  14. package/out/renderer/assets/{chunk-2J33WTMH-CLGSY5ry.js → chunk-2J33WTMH-cVAo2nRo.js} +1 -1
  15. package/out/renderer/assets/{chunk-4BX2VUAB-DfOAmq0y.js → chunk-4BX2VUAB-QUppBCep.js} +1 -1
  16. package/out/renderer/assets/{chunk-55IACEB6-CjDMk8wF.js → chunk-55IACEB6-B7ATOpEx.js} +1 -1
  17. package/out/renderer/assets/{chunk-727SXJPM-4GHP5or6.js → chunk-727SXJPM-DNHjk-uw.js} +5 -5
  18. package/out/renderer/assets/{chunk-AQP2D5EJ-B8ex3L6d.js → chunk-AQP2D5EJ-C_nuud1y.js} +3 -3
  19. package/out/renderer/assets/{chunk-FMBD7UC4-DXVKqz45.js → chunk-FMBD7UC4-DoAO6UdZ.js} +1 -1
  20. package/out/renderer/assets/{chunk-ND2GUHAM-CJf331B5.js → chunk-ND2GUHAM-hRnym-e6.js} +1 -1
  21. package/out/renderer/assets/{chunk-QZHKN3VN-CmRmlYwi.js → chunk-QZHKN3VN-BkTqSMpi.js} +1 -1
  22. package/out/renderer/assets/{classDiagram-4FO5ZUOK-BB0WWhct.js → classDiagram-4FO5ZUOK-097_YN8Y.js} +6 -6
  23. package/out/renderer/assets/{classDiagram-v2-Q7XG4LA2-BB0WWhct.js → classDiagram-v2-Q7XG4LA2-097_YN8Y.js} +6 -6
  24. package/out/renderer/assets/{cose-bilkent-S5V4N54A-C1ovVUkK.js → cose-bilkent-S5V4N54A-CU24fSZY.js} +1 -1
  25. package/out/renderer/assets/{dagre-BM42HDAG-BN2vkdYj.js → dagre-BM42HDAG-CXQk6wIx.js} +3 -3
  26. package/out/renderer/assets/{diagram-2AECGRRQ-Gmur2BYD.js → diagram-2AECGRRQ-cp5zubxu.js} +3 -3
  27. package/out/renderer/assets/{diagram-5GNKFQAL-CO-0qbfq.js → diagram-5GNKFQAL-Dz1liaVJ.js} +4 -4
  28. package/out/renderer/assets/{diagram-KO2AKTUF-B0BourUo.js → diagram-KO2AKTUF-C_a_DDR7.js} +3 -3
  29. package/out/renderer/assets/{diagram-LMA3HP47-CZSemlgR.js → diagram-LMA3HP47-DMzt3Wms.js} +3 -3
  30. package/out/renderer/assets/{diagram-OG6HWLK6-DIg_VSi2.js → diagram-OG6HWLK6-DXgo41ZN.js} +4 -4
  31. package/out/renderer/assets/{erDiagram-TEJ5UH35-CeDB_1TN.js → erDiagram-TEJ5UH35-Duy8-ZVE.js} +4 -4
  32. package/out/renderer/assets/{flowDiagram-I6XJVG4X-CAYyZ6xk.js → flowDiagram-I6XJVG4X-C79uBv3j.js} +6 -6
  33. package/out/renderer/assets/{ganttDiagram-6RSMTGT7-28qx3HO3.js → ganttDiagram-6RSMTGT7-COUQHYqH.js} +3 -3
  34. package/out/renderer/assets/{gitGraphDiagram-PVQCEYII-C0C5PVgG.js → gitGraphDiagram-PVQCEYII-D3-KSp5g.js} +4 -4
  35. package/out/renderer/assets/{graph-BmyvWy9U.js → graph-CojOaclU.js} +1 -1
  36. package/out/renderer/assets/{index-CCixlVbO.js → index-BDc7WeA_.js} +1 -1
  37. package/out/renderer/assets/{index-CqkLi8Rn.js → index-BX1dnn54.js} +1 -1
  38. package/out/renderer/assets/{index-BkEUNx2M.js → index-BxH3Vzns.js} +129 -30
  39. package/out/renderer/assets/{index-CleisQX7.js → index-CZVPwEh7.js} +1 -1
  40. package/out/renderer/assets/{index-DHgg9rnw.js → index-CcbWMGtO.js} +1 -1
  41. package/out/renderer/assets/{index-LwoRwQcK.js → index-CoN3I29h.js} +1 -1
  42. package/out/renderer/assets/{index-D4QsfuBU.css → index-DJwDiyPe.css} +8 -0
  43. package/out/renderer/assets/{index-CjWyE7Qc.js → index-DqOJFqtI.js} +1 -1
  44. package/out/renderer/assets/{index-DDyjc4hl.js → index-DqOyb6kJ.js} +1 -1
  45. package/out/renderer/assets/{index-DiXCQ0pX.js → index-LigRSjJQ.js} +2274 -1492
  46. package/out/renderer/assets/{index-D1hWSFOH.js → index-uk-xw9ke.js} +1 -1
  47. package/out/renderer/assets/{infoDiagram-5YYISTIA-BR2qewYU.js → infoDiagram-5YYISTIA-Dhu3XDyU.js} +2 -2
  48. package/out/renderer/assets/{ishikawaDiagram-YF4QCWOH-mBtVTtfu.js → ishikawaDiagram-YF4QCWOH-Zv844Inp.js} +1 -1
  49. package/out/renderer/assets/{journeyDiagram-JHISSGLW-BLwLxSRJ.js → journeyDiagram-JHISSGLW-CiEy0k__.js} +4 -4
  50. package/out/renderer/assets/{jsx-dev-runtime-C3x5nPQV.js → jsx-dev-runtime-BblfdcBq.js} +1 -1
  51. package/out/renderer/assets/{kanban-definition-UN3LZRKU-DEQMBIes.js → kanban-definition-UN3LZRKU-Bg7Tn0_t.js} +2 -2
  52. package/out/renderer/assets/{layout-COZ2dLJC.js → layout-C7gScUZ3.js} +2 -2
  53. package/out/renderer/assets/{linear-BwuiC9BD.js → linear-C8mfmsRG.js} +1 -1
  54. package/out/renderer/assets/{mindmap-definition-RKZ34NQL-BEdOr2LN.js → mindmap-definition-RKZ34NQL-CT41c9xA.js} +3 -3
  55. package/out/renderer/assets/{pieDiagram-4H26LBE5-C2CIjhWa.js → pieDiagram-4H26LBE5-4MIz5Tk3.js} +4 -4
  56. package/out/renderer/assets/{quadrantDiagram-W4KKPZXB-ByG1Fnbm.js → quadrantDiagram-W4KKPZXB-srrdZ4mO.js} +2 -2
  57. package/out/renderer/assets/{requirementDiagram-4Y6WPE33-CPNEbV2R.js → requirementDiagram-4Y6WPE33-hCfEAv72.js} +3 -3
  58. package/out/renderer/assets/{sankeyDiagram-5OEKKPKP-DseN3BYS.js → sankeyDiagram-5OEKKPKP-D3Dmoahf.js} +1 -1
  59. package/out/renderer/assets/{sequenceDiagram-3UESZ5HK-DGbPycPW.js → sequenceDiagram-3UESZ5HK-B_R1OT73.js} +3 -3
  60. package/out/renderer/assets/{stateDiagram-AJRCARHV-I_wGtDx-.js → stateDiagram-AJRCARHV-T81AxWaT.js} +6 -6
  61. package/out/renderer/assets/{stateDiagram-v2-BHNVJYJU-MVwIUdrA.js → stateDiagram-v2-BHNVJYJU-DotM3iTY.js} +4 -4
  62. package/out/renderer/assets/{time-DKSwLtIL.js → time-NQi4RUKr.js} +1 -1
  63. package/out/renderer/assets/{timeline-definition-PNZ67QCA-0o1eLzXF.js → timeline-definition-PNZ67QCA-CuIJOcqs.js} +2 -2
  64. package/out/renderer/assets/{vennDiagram-CIIHVFJN-BbPtgu5r.js → vennDiagram-CIIHVFJN-BP9XceqR.js} +1 -1
  65. package/out/renderer/assets/{wardley-L42UT6IY-C6O9NaAx.js → wardley-L42UT6IY-Cs8sx4Yc.js} +1 -1
  66. package/out/renderer/assets/{wardleyDiagram-YWT4CUSO-C0NB17Hf.js → wardleyDiagram-YWT4CUSO-BleVwqnB.js} +3 -3
  67. package/out/renderer/assets/{xychartDiagram-2RQKCTM6-CM1NB5k6.js → xychartDiagram-2RQKCTM6-CoEiSbj_.js} +2 -2
  68. package/out/renderer/index.html +2 -2
  69. package/out/runner.js +613 -287
  70. package/package.json +20 -20
  71. package/scripts/generate-package.mjs +1 -2
  72. package/scripts/publish-next.mjs +22 -0
  73. package/out/renderer/assets/gemini-cli-BKI4k4GP.png +0 -0
  74. package/out/resources/mcp-server/aider-desk-mcp-server.js +0 -39437
  75. package/patches/ai-sdk-provider-gemini-cli+1.5.1.patch +0 -373
package/out/cli.js CHANGED
@@ -3,9 +3,11 @@ const fs = require("fs");
3
3
  const path = require("path");
4
4
  const commander = require("commander");
5
5
  const child_process = require("child_process");
6
- const piTui = require("@mariozechner/pi-tui");
6
+ const piTui = require("@earendil-works/pi-tui");
7
+ const http = require("http");
7
8
  const READY_PATTERN = /AiderDesk Runner is ready and running on port (\d+)/;
8
9
  const DEFAULT_PORT = 24337;
10
+ const DEFAULT_HOST = "localhost";
9
11
  const MAX_LOG_LINES = 500;
10
12
  const pkgRoot = path.resolve(path.dirname(__filename), "..");
11
13
  const resourcesDir = path.resolve(pkgRoot, "out", "resources");
@@ -548,6 +550,1008 @@ function registerTuiCommand(program2) {
548
550
  runTui(port);
549
551
  });
550
552
  }
553
+ const REASONING_PREVIEW_LINES = 5;
554
+ const TOOL_PREVIEW_LINES = 5;
555
+ const BLOCK_INDENT = 4;
556
+ const HEADER_HINT = c.gray("[Enter]");
557
+ const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
558
+ const SPINNER_INTERVAL_MS = 80;
559
+ const ICON_REASONING = "💭";
560
+ const ICON_TOOL_RUNNING = "⚙";
561
+ const ICON_TOOL_OK = "✓";
562
+ const ICON_TOOL_ERR = "✗";
563
+ const ICON_USER = "🧑";
564
+ function formatToolArgs$1(args) {
565
+ if (!args || typeof args !== "object") {
566
+ return "";
567
+ }
568
+ const entries = Object.entries(args);
569
+ if (entries.length === 0) {
570
+ return "";
571
+ }
572
+ const summary = entries.map(([key, value]) => {
573
+ const str = typeof value === "string" ? value : JSON.stringify(value);
574
+ const truncated = str.length > 60 ? str.substring(0, 57) + "..." : str;
575
+ return `${key}=${truncated}`;
576
+ }).join(", ");
577
+ return `(${summary})`;
578
+ }
579
+ function getSpinnerFrame(elapsedMs) {
580
+ const idx = Math.floor(elapsedMs / SPINNER_INTERVAL_MS) % SPINNER_FRAMES.length;
581
+ return SPINNER_FRAMES[idx] ?? SPINNER_FRAMES[0];
582
+ }
583
+ class RunStreamModel {
584
+ constructor() {
585
+ this.blocks = [];
586
+ this.reasoningByMessageId = /* @__PURE__ */ new Map();
587
+ this.answerByMessageId = /* @__PURE__ */ new Map();
588
+ this.toolById = /* @__PURE__ */ new Map();
589
+ }
590
+ appendReasoning(messageId, text) {
591
+ if (!text) return;
592
+ let block = this.reasoningByMessageId.get(messageId);
593
+ if (!block) {
594
+ block = { type: "reasoning", id: messageId, text: "", streaming: true };
595
+ this.reasoningByMessageId.set(messageId, block);
596
+ this.blocks.push(block);
597
+ }
598
+ block.text += text;
599
+ }
600
+ freezeReasoning(messageId) {
601
+ const block = this.reasoningByMessageId.get(messageId);
602
+ if (block) {
603
+ block.streaming = false;
604
+ }
605
+ }
606
+ appendAnswer(messageId, text) {
607
+ if (!text) return;
608
+ let block = this.answerByMessageId.get(messageId);
609
+ if (!block) {
610
+ this.freezeReasoning(messageId);
611
+ block = { type: "answer", id: messageId, text: "", finished: false };
612
+ this.answerByMessageId.set(messageId, block);
613
+ this.blocks.push(block);
614
+ }
615
+ block.text += text;
616
+ }
617
+ startTool(id, toolName, args) {
618
+ if (this.toolById.has(id)) return;
619
+ const block = {
620
+ type: "tool",
621
+ id,
622
+ toolName,
623
+ argsSummary: formatToolArgs$1(args),
624
+ output: "",
625
+ error: false,
626
+ finished: false
627
+ };
628
+ this.toolById.set(id, block);
629
+ this.blocks.push(block);
630
+ }
631
+ endTool(id, output, error = false) {
632
+ const block = this.toolById.get(id);
633
+ if (!block) return;
634
+ block.output = output ?? "";
635
+ block.error = error;
636
+ block.finished = true;
637
+ }
638
+ completeResponse(messageId, fullContent) {
639
+ let block = this.answerByMessageId.get(messageId);
640
+ if (!block) {
641
+ if (fullContent) {
642
+ this.appendAnswer(messageId, fullContent);
643
+ }
644
+ block = this.answerByMessageId.get(messageId);
645
+ } else if (fullContent && fullContent.startsWith(block.text)) {
646
+ block.text = fullContent;
647
+ } else if (fullContent && !block.text) {
648
+ block.text = fullContent;
649
+ }
650
+ if (block) {
651
+ block.finished = true;
652
+ }
653
+ this.freezeReasoning(messageId);
654
+ }
655
+ getBlocks() {
656
+ return this.blocks;
657
+ }
658
+ getSelectableIndices() {
659
+ const out = [];
660
+ for (let i = 0; i < this.blocks.length; i++) {
661
+ const b = this.blocks[i];
662
+ if (b && (b.type === "reasoning" || b.type === "tool")) {
663
+ out.push(i);
664
+ }
665
+ }
666
+ return out;
667
+ }
668
+ }
669
+ function renderReasoningPreview(block, width, maxLines = REASONING_PREVIEW_LINES) {
670
+ if (!block.text) return [];
671
+ const wrapWidth = Math.max(1, width - BLOCK_INDENT);
672
+ const wrapped = piTui.wrapTextWithAnsi(block.text, wrapWidth);
673
+ const lines = wrapped.length > maxLines ? wrapped.slice(-maxLines) : wrapped;
674
+ return lines.map((line) => c.gray(" ".repeat(BLOCK_INDENT) + piTui.truncateToWidth(line, wrapWidth)));
675
+ }
676
+ function renderToolPreview(block, width, maxLines = TOOL_PREVIEW_LINES) {
677
+ if (!block.output) return [];
678
+ const wrapWidth = Math.max(1, width - BLOCK_INDENT);
679
+ const wrapped = piTui.wrapTextWithAnsi(block.output, wrapWidth);
680
+ const lines = wrapped.length > maxLines ? wrapped.slice(0, maxLines) : wrapped;
681
+ const colorFn = block.error ? c.red : c.gray;
682
+ const out = lines.map((line) => colorFn(" ".repeat(BLOCK_INDENT) + piTui.truncateToWidth(line, wrapWidth)));
683
+ if (wrapped.length > maxLines) {
684
+ const moreCount = wrapped.length - maxLines;
685
+ out.push(c.gray(" ".repeat(BLOCK_INDENT) + `… +${moreCount} more [Enter]`));
686
+ }
687
+ return out;
688
+ }
689
+ function renderReasoningFull(block, width) {
690
+ if (!block.text) return [c.gray("(empty)")];
691
+ const wrapWidth = Math.max(1, width);
692
+ const wrapped = piTui.wrapTextWithAnsi(block.text, wrapWidth);
693
+ if (wrapped.length === 0) {
694
+ return [c.gray("(empty)")];
695
+ }
696
+ const numWidth = String(wrapped.length).length + 2;
697
+ return wrapped.map((line, i) => {
698
+ const num = String(i + 1).padStart(numWidth, " ");
699
+ return c.gray(num + " " + piTui.truncateToWidth(line, wrapWidth - numWidth - 1));
700
+ });
701
+ }
702
+ function renderToolFull(block, width) {
703
+ const wrapWidth = Math.max(1, width);
704
+ const wrapped = block.output ? piTui.wrapTextWithAnsi(block.output, wrapWidth) : [];
705
+ const colorFn = block.error ? c.red : c.gray;
706
+ if (wrapped.length === 0) {
707
+ return [colorFn("(no output)")];
708
+ }
709
+ const numWidth = String(wrapped.length).length + 2;
710
+ return wrapped.map((line, i) => {
711
+ const num = String(i + 1).padStart(numWidth, " ");
712
+ return colorFn(num + " " + piTui.truncateToWidth(line, wrapWidth - numWidth - 1));
713
+ });
714
+ }
715
+ function renderAnswerLines(block, width) {
716
+ if (!block.text) return [];
717
+ const wrapWidth = Math.max(1, width - 2);
718
+ const wrapped = piTui.wrapTextWithAnsi(block.text, wrapWidth);
719
+ return wrapped.map((line) => piTui.truncateToWidth(line, wrapWidth));
720
+ }
721
+ function buildBlockHeader(block, width, selected) {
722
+ if (block.type === "answer") {
723
+ return null;
724
+ }
725
+ const marker = selected ? c.cyan("▶") : " ";
726
+ let icon;
727
+ let body;
728
+ let iconColor;
729
+ let showHint = false;
730
+ if (block.type === "reasoning") {
731
+ icon = ICON_REASONING;
732
+ body = block.streaming ? "Thinking…" : "Thinking";
733
+ iconColor = c.gray;
734
+ showHint = !!block.text;
735
+ } else {
736
+ if (block.finished) {
737
+ icon = block.error ? ICON_TOOL_ERR : ICON_TOOL_OK;
738
+ iconColor = block.error ? c.red : c.green;
739
+ showHint = !!block.output;
740
+ } else {
741
+ icon = ICON_TOOL_RUNNING;
742
+ iconColor = c.yellow;
743
+ showHint = false;
744
+ }
745
+ body = block.toolName + (block.argsSummary || "");
746
+ }
747
+ const left = ` ${marker} ${iconColor(icon)} ${c.bold}${body}${c.reset}`;
748
+ const leftW = piTui.visibleWidth(left);
749
+ const hintStr = showHint ? HEADER_HINT : "";
750
+ const hintW = piTui.visibleWidth(hintStr);
751
+ const pad = Math.max(1, width - leftW - hintW);
752
+ return piTui.truncateToWidth(left + " ".repeat(pad) + hintStr, width);
753
+ }
754
+ class ContentOverlay {
755
+ constructor(title) {
756
+ this.lines = [];
757
+ this.scrollOffset = 0;
758
+ this.title = title;
759
+ }
760
+ setContent(lines) {
761
+ this.lines = lines;
762
+ this.scrollOffset = 0;
763
+ }
764
+ invalidate() {
765
+ }
766
+ handleInput(data) {
767
+ if (piTui.matchesKey(data, piTui.Key.escape) || piTui.matchesKey(data, "q") || piTui.matchesKey(data, piTui.Key.enter)) {
768
+ this.onClose?.();
769
+ return;
770
+ }
771
+ const total = this.lines.length;
772
+ const viewport = this.viewportHeight();
773
+ const maxOffset = Math.max(0, total - viewport);
774
+ if (piTui.matchesKey(data, piTui.Key.up)) {
775
+ this.scrollOffset = Math.min(this.scrollOffset + 1, maxOffset);
776
+ } else if (piTui.matchesKey(data, piTui.Key.down)) {
777
+ this.scrollOffset = Math.max(0, this.scrollOffset - 1);
778
+ } else if (piTui.matchesKey(data, piTui.Key.pageUp)) {
779
+ this.scrollOffset = Math.min(this.scrollOffset + viewport, maxOffset);
780
+ } else if (piTui.matchesKey(data, piTui.Key.pageDown)) {
781
+ this.scrollOffset = Math.max(0, this.scrollOffset - viewport);
782
+ } else if (piTui.matchesKey(data, piTui.Key.home)) {
783
+ this.scrollOffset = maxOffset;
784
+ } else if (piTui.matchesKey(data, piTui.Key.end)) {
785
+ this.scrollOffset = 0;
786
+ }
787
+ }
788
+ viewportHeight() {
789
+ const termRows = process.stdout.rows || 24;
790
+ return Math.max(3, termRows - 5);
791
+ }
792
+ render(width) {
793
+ const viewport = this.viewportHeight();
794
+ const result = [
795
+ c.bgCyanBlack(` ${this.title} `),
796
+ c.gray("─".repeat(width))
797
+ ];
798
+ const start = this.scrollOffset;
799
+ const visible = this.lines.slice(start, start + viewport);
800
+ for (const line of visible) {
801
+ result.push(piTui.truncateToWidth(line, width));
802
+ }
803
+ while (result.length < viewport + 2) {
804
+ result.push("");
805
+ }
806
+ result.push(c.gray("─".repeat(width)));
807
+ const total = this.lines.length;
808
+ const label = total === 0 ? " empty " : ` ${start + 1}-${Math.min(start + viewport, total)} of ${total} `;
809
+ const scrollHint = c.gray(" ↑↓ scroll • Esc/Enter close ");
810
+ const hintW = piTui.visibleWidth(scrollHint);
811
+ const labelStr = c.gray(label);
812
+ const labelW = piTui.visibleWidth(labelStr);
813
+ const pad = Math.max(1, width - hintW - labelW);
814
+ result.push(piTui.truncateToWidth(scrollHint + " ".repeat(pad) + labelStr, width));
815
+ return result;
816
+ }
817
+ }
818
+ class RunStreamView {
819
+ constructor(tui, model, opts) {
820
+ this.selectedSlot = 0;
821
+ this.followSelection = true;
822
+ this.scrollOffset = 0;
823
+ this.autoFollow = true;
824
+ this.finished = false;
825
+ this.status = "streaming";
826
+ this.overlay = null;
827
+ this.loadingMessage = null;
828
+ this.spinnerStartTime = 0;
829
+ this.spinnerIntervalId = null;
830
+ this.tui = tui;
831
+ this.model = model;
832
+ this.opts = opts;
833
+ this.headerText = `AiderDesk Run${opts.taskId ? ` — task:${opts.taskId}` : ""}`;
834
+ }
835
+ notifyChanged() {
836
+ if (this.followSelection) {
837
+ const indices = this.model.getSelectableIndices();
838
+ this.selectedSlot = Math.max(0, indices.length - 1);
839
+ }
840
+ this.tui.requestRender();
841
+ }
842
+ setInterrupted() {
843
+ this.status = "interrupted";
844
+ this.finished = true;
845
+ this.tui.requestRender();
846
+ }
847
+ setFinished() {
848
+ this.finished = true;
849
+ if (this.status === "streaming") {
850
+ this.status = "done";
851
+ }
852
+ this.stopSpinner();
853
+ this.loadingMessage = null;
854
+ this.tui.requestRender();
855
+ }
856
+ setLoadingMessage(message) {
857
+ this.loadingMessage = message;
858
+ if (message) {
859
+ this.startSpinner();
860
+ } else {
861
+ this.stopSpinner();
862
+ }
863
+ this.tui.requestRender();
864
+ }
865
+ startSpinner() {
866
+ if (this.spinnerIntervalId) return;
867
+ this.spinnerStartTime = Date.now();
868
+ this.spinnerIntervalId = setInterval(() => {
869
+ this.tui.requestRender();
870
+ }, SPINNER_INTERVAL_MS);
871
+ }
872
+ stopSpinner() {
873
+ if (this.spinnerIntervalId) {
874
+ clearInterval(this.spinnerIntervalId);
875
+ this.spinnerIntervalId = null;
876
+ }
877
+ }
878
+ invalidate() {
879
+ this.tui.requestRender();
880
+ }
881
+ handleInput(data) {
882
+ if (piTui.matchesKey(data, piTui.Key.ctrl("c"))) {
883
+ return;
884
+ }
885
+ if (this.overlay) {
886
+ return;
887
+ }
888
+ if (piTui.matchesKey(data, piTui.Key.escape)) {
889
+ return;
890
+ }
891
+ if (piTui.matchesKey(data, piTui.Key.enter) || piTui.matchesKey(data, "e")) {
892
+ this.toggleOverlay();
893
+ return;
894
+ }
895
+ if (piTui.matchesKey(data, piTui.Key.up)) {
896
+ const indices = this.model.getSelectableIndices();
897
+ if (indices.length === 0) return;
898
+ this.selectedSlot = (this.selectedSlot - 1 + indices.length) % indices.length;
899
+ this.followSelection = this.selectedSlot === indices.length - 1;
900
+ this.tui.requestRender();
901
+ return;
902
+ }
903
+ if (piTui.matchesKey(data, piTui.Key.down)) {
904
+ const indices = this.model.getSelectableIndices();
905
+ if (indices.length === 0) return;
906
+ this.selectedSlot = (this.selectedSlot + 1) % indices.length;
907
+ this.followSelection = this.selectedSlot === indices.length - 1;
908
+ this.tui.requestRender();
909
+ return;
910
+ }
911
+ const viewportHeight = Math.max(3, (process.stdout.rows || 24) / 2);
912
+ if (piTui.matchesKey(data, piTui.Key.pageUp)) {
913
+ this.scrollOffset += Math.max(3, Math.floor(viewportHeight));
914
+ this.autoFollow = false;
915
+ this.tui.requestRender();
916
+ return;
917
+ }
918
+ if (piTui.matchesKey(data, piTui.Key.pageDown)) {
919
+ this.scrollOffset = Math.max(0, this.scrollOffset - Math.max(3, Math.floor(viewportHeight)));
920
+ if (this.scrollOffset === 0) this.autoFollow = true;
921
+ this.tui.requestRender();
922
+ return;
923
+ }
924
+ if (piTui.matchesKey(data, piTui.Key.end)) {
925
+ this.scrollOffset = 0;
926
+ this.autoFollow = true;
927
+ this.tui.requestRender();
928
+ return;
929
+ }
930
+ if (piTui.matchesKey(data, piTui.Key.home)) {
931
+ this.scrollOffset = Number.MAX_SAFE_INTEGER;
932
+ this.autoFollow = false;
933
+ this.tui.requestRender();
934
+ return;
935
+ }
936
+ }
937
+ toggleOverlay() {
938
+ if (this.overlay) {
939
+ this.overlay.handle.hide();
940
+ this.overlay = null;
941
+ return;
942
+ }
943
+ const indices = this.model.getSelectableIndices();
944
+ if (this.selectedSlot < 0 || this.selectedSlot >= indices.length) return;
945
+ const blockIndex = indices[this.selectedSlot];
946
+ const blocks = this.model.getBlocks();
947
+ const block = blocks[blockIndex];
948
+ if (!block || block.type === "answer") return;
949
+ const overlayWidth = Math.min(160, Math.max(60, (process.stdout.columns || 80) - 4));
950
+ const lines = block.type === "reasoning" ? renderReasoningFull(block, overlayWidth - 6) : renderToolFull(block, overlayWidth - 6);
951
+ const title = block.type === "reasoning" ? `${ICON_REASONING} Thinking` : `${block.error ? ICON_TOOL_ERR : ICON_TOOL_OK} ${block.toolName}${block.argsSummary || ""}`;
952
+ const overlay = new ContentOverlay(title);
953
+ overlay.setContent(lines);
954
+ overlay.onClose = () => {
955
+ if (this.overlay) {
956
+ this.overlay.handle.hide();
957
+ this.overlay = null;
958
+ }
959
+ };
960
+ const handle = this.tui.showOverlay(overlay, {
961
+ width: overlayWidth,
962
+ maxHeight: Math.floor((process.stdout.rows || 24) * 0.8),
963
+ anchor: "center"
964
+ });
965
+ this.overlay = { handle, component: overlay };
966
+ }
967
+ computeSelectedIndex() {
968
+ const indices = this.model.getSelectableIndices();
969
+ if (indices.length === 0) return -1;
970
+ const slot = Math.min(this.selectedSlot, indices.length - 1);
971
+ return indices[slot];
972
+ }
973
+ renderHeader(width) {
974
+ const left = c.gray(` ${this.headerText}`);
975
+ const statusText = this.status === "streaming" ? c.yellow("● streaming") : this.status === "interrupted" ? c.red("● interrupted") : c.green("● done");
976
+ const leftW = piTui.visibleWidth(left);
977
+ const rightW = piTui.visibleWidth(statusText);
978
+ const pad = Math.max(1, width - leftW - rightW);
979
+ return piTui.truncateToWidth(left + " ".repeat(pad) + statusText, width);
980
+ }
981
+ renderUserPrompt(prompt, width) {
982
+ const wrapWidth = Math.max(1, width - BLOCK_INDENT - 3);
983
+ const wrapped = piTui.wrapTextWithAnsi(prompt, wrapWidth);
984
+ const out = wrapped.map((line) => `${c.cyan(ICON_USER)} ${c.bold}${piTui.truncateToWidth(line, wrapWidth)}${c.reset}`);
985
+ return out.length > 0 ? out : [c.cyan(ICON_USER)];
986
+ }
987
+ renderFooter(width) {
988
+ const hint = c.gray(" ↑↓ select • Enter expand • Ctrl+C interrupt ");
989
+ let right = "";
990
+ if (!this.autoFollow) {
991
+ right = c.gray(this.scrollOffset === Number.MAX_SAFE_INTEGER ? " top " : ` ↑${this.scrollOffset} `);
992
+ }
993
+ const hintW = piTui.visibleWidth(hint);
994
+ const rightW = piTui.visibleWidth(right);
995
+ const pad = Math.max(1, width - hintW - rightW);
996
+ return piTui.truncateToWidth(hint + " ".repeat(pad) + right, width);
997
+ }
998
+ render(width) {
999
+ const lines = [];
1000
+ lines.push(this.renderHeader(width));
1001
+ lines.push(c.gray("─".repeat(width)));
1002
+ if (this.opts.prompt) {
1003
+ lines.push(...this.renderUserPrompt(this.opts.prompt, width));
1004
+ lines.push("");
1005
+ }
1006
+ const selectedIndex = this.computeSelectedIndex();
1007
+ const blocks = this.model.getBlocks();
1008
+ for (let i = 0; i < blocks.length; i++) {
1009
+ const block = blocks[i];
1010
+ if (!block) continue;
1011
+ const selected = i === selectedIndex;
1012
+ const header = buildBlockHeader(block, width, selected);
1013
+ if (header !== null) {
1014
+ lines.push(header);
1015
+ }
1016
+ if (block.type === "reasoning") {
1017
+ lines.push(...renderReasoningPreview(block, width));
1018
+ } else if (block.type === "tool") {
1019
+ lines.push(...renderToolPreview(block, width));
1020
+ } else {
1021
+ lines.push(...renderAnswerLines(block, width));
1022
+ }
1023
+ lines.push("");
1024
+ }
1025
+ if (this.loadingMessage) {
1026
+ const elapsed = Date.now() - this.spinnerStartTime;
1027
+ const frame = getSpinnerFrame(elapsed);
1028
+ const msg = this.loadingMessage || "";
1029
+ lines.push(c.yellow(`${frame} ${msg}`));
1030
+ lines.push("");
1031
+ }
1032
+ lines.push(c.gray("─".repeat(width)));
1033
+ lines.push(this.renderFooter(width));
1034
+ const termHeight = process.stdout.rows || 24;
1035
+ const viewport = termHeight;
1036
+ const total = lines.length;
1037
+ let start;
1038
+ if (this.autoFollow) {
1039
+ start = Math.max(0, total - viewport);
1040
+ } else if (this.scrollOffset === Number.MAX_SAFE_INTEGER) {
1041
+ start = 0;
1042
+ } else {
1043
+ start = Math.max(0, Math.min(total - viewport, total - viewport - this.scrollOffset));
1044
+ }
1045
+ const visible = lines.slice(start, start + viewport);
1046
+ while (visible.length < viewport) {
1047
+ visible.push("");
1048
+ }
1049
+ return visible;
1050
+ }
1051
+ }
1052
+ const parseEventData = (raw) => {
1053
+ try {
1054
+ return JSON.parse(raw);
1055
+ } catch {
1056
+ return void 0;
1057
+ }
1058
+ };
1059
+ const createDeferred = () => {
1060
+ let resolve;
1061
+ let reject;
1062
+ const promise = new Promise((res, rej) => {
1063
+ resolve = res;
1064
+ reject = rej;
1065
+ });
1066
+ return { promise, resolve, reject };
1067
+ };
1068
+ const formatToolArgs = (args) => {
1069
+ if (!args || typeof args !== "object") {
1070
+ return "";
1071
+ }
1072
+ const entries = Object.entries(args);
1073
+ if (entries.length === 0) {
1074
+ return "";
1075
+ }
1076
+ const summary = entries.map(([key, value]) => {
1077
+ const str = typeof value === "string" ? value : JSON.stringify(value);
1078
+ const truncated = str.length > 60 ? str.substring(0, 57) + "..." : str;
1079
+ return `${key}=${truncated}`;
1080
+ }).join(", ");
1081
+ return `(${summary})`;
1082
+ };
1083
+ const readStdin = async () => {
1084
+ if (process.stdin.isTTY) {
1085
+ return "";
1086
+ }
1087
+ const chunks = [];
1088
+ for await (const chunk of process.stdin) {
1089
+ chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
1090
+ }
1091
+ return Buffer.concat(chunks).toString("utf-8").trim();
1092
+ };
1093
+ const fetchJSON = async (host, port, path2, method, body) => {
1094
+ return new Promise((resolve, reject) => {
1095
+ const options = {
1096
+ hostname: host,
1097
+ port,
1098
+ path: path2,
1099
+ method,
1100
+ headers: {
1101
+ "Content-Type": "application/json",
1102
+ Accept: "application/json",
1103
+ ...{}
1104
+ }
1105
+ };
1106
+ const req = http.request(options, (res) => {
1107
+ const chunks = [];
1108
+ res.on("data", (chunk) => chunks.push(chunk));
1109
+ res.on("end", () => {
1110
+ const raw = Buffer.concat(chunks).toString("utf-8");
1111
+ let data;
1112
+ try {
1113
+ data = JSON.parse(raw);
1114
+ } catch {
1115
+ data = raw;
1116
+ }
1117
+ resolve({ status: res.statusCode || 200, data });
1118
+ });
1119
+ });
1120
+ req.on("error", reject);
1121
+ req.setTimeout(3e5, () => {
1122
+ req.destroy(new Error("Request timed out"));
1123
+ });
1124
+ req.end();
1125
+ });
1126
+ };
1127
+ const callInterrupt = (host, port, projectDir, taskId) => {
1128
+ if (!taskId) return Promise.resolve();
1129
+ const body = JSON.stringify({ projectDir, taskId });
1130
+ return new Promise((resolve) => {
1131
+ const options = {
1132
+ hostname: host,
1133
+ port,
1134
+ path: "/api/project/interrupt",
1135
+ method: "POST",
1136
+ headers: {
1137
+ "Content-Type": "application/json",
1138
+ Accept: "application/json",
1139
+ "Content-Length": Buffer.byteLength(body)
1140
+ }
1141
+ };
1142
+ const req = http.request(options, (res) => {
1143
+ res.on("data", () => {
1144
+ });
1145
+ res.on("end", () => resolve());
1146
+ });
1147
+ req.on("error", () => resolve());
1148
+ req.setTimeout(2e3, () => {
1149
+ req.destroy();
1150
+ resolve();
1151
+ });
1152
+ req.write(body);
1153
+ req.end();
1154
+ });
1155
+ };
1156
+ const requestSSEStream = (host, port, body) => {
1157
+ return new Promise((resolve, reject) => {
1158
+ const options = {
1159
+ hostname: host,
1160
+ port,
1161
+ path: "/api/run-prompt",
1162
+ method: "POST",
1163
+ headers: {
1164
+ "Content-Type": "application/json",
1165
+ Accept: "text/event-stream",
1166
+ "Cache-Control": "no-cache",
1167
+ "Content-Length": Buffer.byteLength(body)
1168
+ }
1169
+ };
1170
+ const req = http.request(options, (res) => {
1171
+ if (res.statusCode !== 200) {
1172
+ const chunks = [];
1173
+ res.on("data", (chunk) => chunks.push(chunk));
1174
+ res.on("end", () => {
1175
+ const raw = Buffer.concat(chunks).toString("utf-8");
1176
+ reject(new Error(`Server returned ${res.statusCode}: ${raw}`));
1177
+ });
1178
+ return;
1179
+ }
1180
+ const taskId = res.headers["x-task-id"];
1181
+ resolve({ stream: res, taskId: taskId || "" });
1182
+ });
1183
+ req.on("error", reject);
1184
+ req.setTimeout(6e5, () => {
1185
+ req.destroy(new Error("Request timed out"));
1186
+ });
1187
+ req.write(body);
1188
+ req.end();
1189
+ });
1190
+ };
1191
+ const parseSSEEvents = (stream) => {
1192
+ const events = [];
1193
+ let resolve = null;
1194
+ const push = (event) => {
1195
+ events.push(event);
1196
+ if (resolve) {
1197
+ resolve();
1198
+ resolve = null;
1199
+ }
1200
+ };
1201
+ let buffer = "";
1202
+ let currentType = "";
1203
+ let currentData = "";
1204
+ stream.on("data", (chunk) => {
1205
+ buffer += chunk.toString("utf-8");
1206
+ const lines = buffer.split("\n");
1207
+ buffer = lines.pop() || "";
1208
+ for (const line of lines) {
1209
+ if (line.startsWith(":")) {
1210
+ continue;
1211
+ } else if (line.startsWith("event:")) {
1212
+ currentType = line.slice(6).trim();
1213
+ } else if (line.startsWith("data:")) {
1214
+ currentData += (currentData ? "\n" : "") + line.slice(5).trimStart();
1215
+ } else if (line === "") {
1216
+ if (currentType || currentData) {
1217
+ push({ type: currentType, data: currentData });
1218
+ currentType = "";
1219
+ currentData = "";
1220
+ }
1221
+ }
1222
+ }
1223
+ });
1224
+ return {
1225
+ [Symbol.asyncIterator]() {
1226
+ return {
1227
+ async next() {
1228
+ while (events.length === 0) {
1229
+ const d = createDeferred();
1230
+ resolve = d.resolve;
1231
+ await d.promise;
1232
+ }
1233
+ const event = events.shift();
1234
+ return { value: event, done: false };
1235
+ }
1236
+ };
1237
+ }
1238
+ };
1239
+ };
1240
+ const formatJSONLine = (type, raw) => {
1241
+ const { taskId, baseDir, ...data } = raw;
1242
+ return JSON.stringify({ type, taskId, projectDir: baseDir, data }) + "\n";
1243
+ };
1244
+ const runPrompt = async (messages, opts) => {
1245
+ const port = resolvePort(opts.port ? parseInt(opts.port) : void 0);
1246
+ const host = opts.host || DEFAULT_HOST;
1247
+ const format = opts.format === "json" ? "json" : "text";
1248
+ const quiet = opts.quiet;
1249
+ const projectDir = process.cwd();
1250
+ let prompt = messages.join(" ").trim();
1251
+ const stdinContent = await readStdin();
1252
+ if (stdinContent) {
1253
+ prompt = prompt ? `${prompt}
1254
+
1255
+ ${stdinContent}` : stdinContent;
1256
+ }
1257
+ if (!prompt) {
1258
+ process.stderr.write("Error: No prompt provided. Pass a message or pipe stdin.\n");
1259
+ process.exit(1);
1260
+ }
1261
+ try {
1262
+ const health = await fetchJSON(host, port, "/api/health", "GET");
1263
+ if (health.status !== 200 || health.data.status !== "ok") {
1264
+ process.stderr.write("Error: AiderDesk server is not healthy.\n");
1265
+ process.exit(1);
1266
+ }
1267
+ } catch {
1268
+ process.stderr.write(
1269
+ `Error: AiderDesk server is not running on ${host}:${port}. Start it first with 'aiderdesk' or 'aiderdesk start'.
1270
+ `
1271
+ );
1272
+ process.exit(1);
1273
+ }
1274
+ const requestBody = { prompt, projectDir };
1275
+ if (opts.model) {
1276
+ requestBody.model = opts.model;
1277
+ }
1278
+ if (opts.agentProfile) {
1279
+ requestBody.agentProfileId = opts.agentProfile;
1280
+ }
1281
+ if (opts.taskId) {
1282
+ requestBody.taskId = opts.taskId;
1283
+ }
1284
+ const body = JSON.stringify(requestBody);
1285
+ let reqClosed = false;
1286
+ const sseResponse = await requestSSEStream(host, port, body);
1287
+ const taskId = sseResponse.taskId;
1288
+ const eventStream = parseSSEEvents(sseResponse.stream);
1289
+ let interrupted = false;
1290
+ const handleInterrupt = (tui) => {
1291
+ if (interrupted) {
1292
+ process.exit(130);
1293
+ }
1294
+ interrupted = true;
1295
+ if (tui) {
1296
+ tui.stop();
1297
+ }
1298
+ process.stderr.write("\nInterrupting...\n");
1299
+ if (!reqClosed) {
1300
+ sseResponse.stream.destroy();
1301
+ }
1302
+ void callInterrupt(host, port, projectDir, taskId).then(() => process.exit(130));
1303
+ setTimeout(() => process.exit(130), 2e3);
1304
+ };
1305
+ process.on("SIGINT", () => handleInterrupt());
1306
+ process.on("SIGTERM", () => handleInterrupt());
1307
+ const interactive = format === "text" && !quiet && !!process.stdout.isTTY && !!process.stdin.isTTY;
1308
+ if (interactive) {
1309
+ await runInteractiveStream({
1310
+ host,
1311
+ port,
1312
+ projectDir,
1313
+ taskId,
1314
+ prompt,
1315
+ eventStream,
1316
+ sseResponse,
1317
+ onInterrupt: (tui) => handleInterrupt(tui),
1318
+ onDone: (success) => {
1319
+ reqClosed = true;
1320
+ process.exit(success ? 0 : 1);
1321
+ }
1322
+ });
1323
+ return;
1324
+ }
1325
+ let currentResponseText = "";
1326
+ let finished = false;
1327
+ let lastResponseCompleted = null;
1328
+ const seenToolStarts = /* @__PURE__ */ new Set();
1329
+ const seenToolEnds = /* @__PURE__ */ new Set();
1330
+ if (format === "text" && !quiet) {
1331
+ process.stderr.write(`Running prompt in ${projectDir}
1332
+ `);
1333
+ }
1334
+ for await (const event of eventStream) {
1335
+ const eventData = parseEventData(event.data);
1336
+ if (!eventData) continue;
1337
+ switch (event.type) {
1338
+ case "response-chunk": {
1339
+ if (format === "json" && !quiet) {
1340
+ process.stdout.write(formatJSONLine("response-chunk", eventData));
1341
+ } else if (format === "text" && !quiet) {
1342
+ const text = eventData.chunk || "";
1343
+ if (text) {
1344
+ process.stdout.write(text);
1345
+ currentResponseText += text;
1346
+ }
1347
+ }
1348
+ break;
1349
+ }
1350
+ case "response-completed": {
1351
+ if (format === "json" && !quiet) {
1352
+ process.stdout.write(formatJSONLine("response-completed", eventData));
1353
+ } else if (quiet) {
1354
+ lastResponseCompleted = eventData;
1355
+ } else {
1356
+ if (eventData.content) {
1357
+ const remainingContent = eventData.content.startsWith(currentResponseText) ? eventData.content.slice(currentResponseText.length) : eventData.content;
1358
+ if (remainingContent) {
1359
+ process.stdout.write(remainingContent);
1360
+ }
1361
+ if (!eventData.content.endsWith("\n")) {
1362
+ process.stdout.write("\n");
1363
+ }
1364
+ } else if (currentResponseText && !currentResponseText.endsWith("\n")) {
1365
+ process.stdout.write("\n");
1366
+ }
1367
+ }
1368
+ currentResponseText = "";
1369
+ break;
1370
+ }
1371
+ case "stream-end": {
1372
+ if (quiet && lastResponseCompleted) {
1373
+ if (format === "json") {
1374
+ process.stdout.write(formatJSONLine("response-completed", lastResponseCompleted));
1375
+ } else {
1376
+ const content = lastResponseCompleted.content || "";
1377
+ if (content) {
1378
+ process.stdout.write(content);
1379
+ if (!content.endsWith("\n")) {
1380
+ process.stdout.write("\n");
1381
+ }
1382
+ }
1383
+ }
1384
+ }
1385
+ finished = true;
1386
+ break;
1387
+ }
1388
+ case "tool": {
1389
+ const toolId = eventData.id || "";
1390
+ if (toolId && eventData.toolName) {
1391
+ if (!eventData.finished) {
1392
+ if (seenToolStarts.has(toolId)) {
1393
+ break;
1394
+ }
1395
+ seenToolStarts.add(toolId);
1396
+ if (format === "json" && !quiet) {
1397
+ process.stdout.write(formatJSONLine("tool-start", eventData));
1398
+ } else if (format === "text" && !quiet) {
1399
+ const argsSummary = formatToolArgs(eventData.args);
1400
+ process.stderr.write(` \x1B[2m⚙ ${eventData.toolName}${argsSummary}\x1B[0m
1401
+ `);
1402
+ }
1403
+ } else {
1404
+ if (seenToolEnds.has(toolId)) {
1405
+ break;
1406
+ }
1407
+ seenToolEnds.add(toolId);
1408
+ if (format === "json" && !quiet) {
1409
+ process.stdout.write(formatJSONLine("tool-end", eventData));
1410
+ } else if (format === "text" && !quiet) {
1411
+ const hasError = eventData.response === "error";
1412
+ const symbol = hasError ? "✗" : "✓";
1413
+ process.stderr.write(` \x1B[2m${symbol} ${eventData.toolName}\x1B[0m
1414
+ `);
1415
+ }
1416
+ }
1417
+ }
1418
+ break;
1419
+ }
1420
+ case "log": {
1421
+ if (format === "json" && !quiet) {
1422
+ process.stdout.write(formatJSONLine("log", eventData));
1423
+ } else if (format === "text" && eventData.level === "error" && eventData.message) {
1424
+ process.stderr.write(`\x1B[31mError: ${eventData.message}\x1B[0m
1425
+ `);
1426
+ }
1427
+ break;
1428
+ }
1429
+ case "ask-question": {
1430
+ if (format === "json" && !quiet) {
1431
+ process.stdout.write(formatJSONLine("ask-question", eventData));
1432
+ } else if (format === "text" && eventData.question) {
1433
+ process.stderr.write(`
1434
+ ? ${eventData.question}
1435
+ `);
1436
+ }
1437
+ break;
1438
+ }
1439
+ default: {
1440
+ if (format === "json" && !quiet) {
1441
+ process.stdout.write(formatJSONLine(event.type, eventData));
1442
+ }
1443
+ break;
1444
+ }
1445
+ }
1446
+ if (finished) {
1447
+ break;
1448
+ }
1449
+ }
1450
+ reqClosed = true;
1451
+ process.exit(finished ? 0 : 1);
1452
+ };
1453
+ const runInteractiveStream = async (args) => {
1454
+ const terminal = new piTui.ProcessTerminal();
1455
+ const tui = new piTui.TUI(terminal);
1456
+ const model = new RunStreamModel();
1457
+ const view = new RunStreamView(tui, model, {
1458
+ projectDir: args.projectDir,
1459
+ taskId: args.taskId,
1460
+ host: args.host,
1461
+ port: args.port,
1462
+ prompt: args.prompt,
1463
+ onInterrupt: () => {
1464
+ }
1465
+ });
1466
+ tui.addChild(view);
1467
+ tui.setFocus(view);
1468
+ tui.addInputListener((data) => {
1469
+ if (piTui.matchesKey(data, piTui.Key.ctrl("c"))) {
1470
+ view.setInterrupted();
1471
+ args.onInterrupt(tui);
1472
+ return { consume: true };
1473
+ }
1474
+ return void 0;
1475
+ });
1476
+ process.stdout.write("\x1B[2J\x1B[H");
1477
+ tui.start();
1478
+ let success = false;
1479
+ try {
1480
+ for await (const event of args.eventStream) {
1481
+ const eventData = parseEventData(event.data);
1482
+ if (!eventData) continue;
1483
+ switch (event.type) {
1484
+ case "response-chunk": {
1485
+ if (eventData.reasoning && eventData.messageId) {
1486
+ model.appendReasoning(eventData.messageId, eventData.reasoning);
1487
+ }
1488
+ if (eventData.chunk && eventData.messageId) {
1489
+ model.appendAnswer(eventData.messageId, eventData.chunk);
1490
+ }
1491
+ view.notifyChanged();
1492
+ break;
1493
+ }
1494
+ case "response-completed": {
1495
+ if (eventData.messageId) {
1496
+ model.completeResponse(eventData.messageId, eventData.content);
1497
+ }
1498
+ view.notifyChanged();
1499
+ break;
1500
+ }
1501
+ case "tool": {
1502
+ const toolId = eventData.id || "";
1503
+ if (toolId && eventData.toolName) {
1504
+ if (!eventData.finished) {
1505
+ model.startTool(toolId, eventData.toolName, eventData.args);
1506
+ } else {
1507
+ const hasError = eventData.response === "error";
1508
+ model.endTool(toolId, eventData.response, hasError);
1509
+ }
1510
+ view.notifyChanged();
1511
+ }
1512
+ break;
1513
+ }
1514
+ case "log": {
1515
+ if (eventData.level === "loading") {
1516
+ if (eventData.message) {
1517
+ view.setLoadingMessage(eventData.message);
1518
+ } else {
1519
+ view.setLoadingMessage(null);
1520
+ }
1521
+ } else if (eventData.level === "error" && eventData.message) {
1522
+ view.setLoadingMessage(null);
1523
+ }
1524
+ break;
1525
+ }
1526
+ case "stream-end": {
1527
+ success = true;
1528
+ view.setFinished();
1529
+ break;
1530
+ }
1531
+ default:
1532
+ break;
1533
+ }
1534
+ if (success) {
1535
+ break;
1536
+ }
1537
+ }
1538
+ } catch (err) {
1539
+ if (err instanceof Error && err.message === "Request timed out") {
1540
+ view.setInterrupted();
1541
+ }
1542
+ } finally {
1543
+ args.sseResponse.stream.destroy();
1544
+ setTimeout(() => {
1545
+ tui.stop();
1546
+ args.onDone(success);
1547
+ }, 750);
1548
+ }
1549
+ };
1550
+ function registerRunCommand(program2) {
1551
+ program2.command("run [message...]").description("Run a prompt non-interactively and stream output").option("-p, --port <port>", "server port (env: AIDER_DESK_PORT)", parseInt).option("--host <host>", `server host (default: ${DEFAULT_HOST})`).option("-f, --format <format>", "output format: text (default) or json", "text").option("-q, --quiet", "suppress progress indicators").option("-m, --model <model>", "model to use (format: provider/model, e.g. openai/gpt-4o)").option("-a, --agent-profile <id>", "agent profile ID to use").option("-t, --task-id <id>", "run on an existing task instead of creating a new one").action((messages, opts) => {
1552
+ runPrompt(messages, opts);
1553
+ });
1554
+ }
551
1555
  function getVersion() {
552
1556
  try {
553
1557
  const pkg = JSON.parse(fs.readFileSync(path.join(pkgRoot, "package.json"), "utf8"));
@@ -560,4 +1564,5 @@ const program = new commander.Command();
560
1564
  program.name("aiderdesk").description("AiderDesk - AI-Powered Development Platform").version(getVersion(), "-v, --version", "show version number").helpOption("-h, --help", "show help");
561
1565
  registerStartCommand(program);
562
1566
  registerTuiCommand(program);
1567
+ registerRunCommand(program);
563
1568
  program.parse();