@ai-setting/roy-agent-cli 1.7.20 → 1.7.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -359,6 +359,97 @@ var init_markdown_renderer = __esm(() => {
359
359
  ], MarkdownRenderer.prototype, "push", null);
360
360
  });
361
361
 
362
+ // src/services/stdout-batcher.ts
363
+ function createStdoutBatcher(options = {}) {
364
+ const flushIntervalMs = options.flushIntervalMs ?? 16;
365
+ const maxBufferBytes = options.maxBufferBytes ?? 4096;
366
+ const writeFn = options.writeFn ?? ((chunk) => {
367
+ process.stdout.write(chunk);
368
+ return true;
369
+ });
370
+ const onFlush = options.onFlush;
371
+ let buffer = "";
372
+ let queuedWrites = 0;
373
+ let timer = null;
374
+ let totalBatches = 0;
375
+ let totalWrites = 0;
376
+ let totalBytes = 0;
377
+ let lastBatchWrites = 0;
378
+ function performFlush() {
379
+ if (buffer.length === 0)
380
+ return;
381
+ const chunk = buffer;
382
+ buffer = "";
383
+ lastBatchWrites = queuedWrites;
384
+ queuedWrites = 0;
385
+ totalBatches += 1;
386
+ totalBytes += chunk.length;
387
+ writeFn(chunk);
388
+ if (onFlush) {
389
+ onFlush({
390
+ writesInLastBatch: lastBatchWrites,
391
+ totalBatches,
392
+ totalBytes
393
+ });
394
+ }
395
+ }
396
+ function scheduleFlush() {
397
+ if (timer !== null)
398
+ return;
399
+ timer = setTimeout(() => {
400
+ timer = null;
401
+ performFlush();
402
+ }, flushIntervalMs);
403
+ }
404
+ function maybeForceFlush() {
405
+ if (buffer.length >= maxBufferBytes) {
406
+ if (timer !== null) {
407
+ clearTimeout(timer);
408
+ timer = null;
409
+ }
410
+ performFlush();
411
+ }
412
+ }
413
+ function write(chunk) {
414
+ if (chunk.length === 0)
415
+ return;
416
+ buffer += chunk;
417
+ queuedWrites += 1;
418
+ totalWrites += 1;
419
+ scheduleFlush();
420
+ maybeForceFlush();
421
+ }
422
+ function flushNow() {
423
+ if (timer !== null) {
424
+ clearTimeout(timer);
425
+ timer = null;
426
+ }
427
+ performFlush();
428
+ }
429
+ function cancel() {
430
+ if (timer !== null) {
431
+ clearTimeout(timer);
432
+ timer = null;
433
+ }
434
+ buffer = "";
435
+ queuedWrites = 0;
436
+ }
437
+ function getStats() {
438
+ return {
439
+ batches: totalBatches,
440
+ queuedWrites: totalWrites,
441
+ totalBytes,
442
+ writesInLastBatch: lastBatchWrites
443
+ };
444
+ }
445
+ return {
446
+ write,
447
+ flushNow,
448
+ cancel,
449
+ getStats
450
+ };
451
+ }
452
+
362
453
  // src/services/stream-output.service.ts
363
454
  var exports_stream_output_service = {};
364
455
  __export(exports_stream_output_service, {
@@ -369,14 +460,26 @@ __export(exports_stream_output_service, {
369
460
  COLORS: () => COLORS
370
461
  });
371
462
  import chalk2 from "chalk";
372
- import { createLogger as createLogger2, TracedAs as TracedAs2 } from "@ai-setting/roy-agent-core";
463
+ import {
464
+ createLogger as createLogger2,
465
+ TracedAs as TracedAs2,
466
+ wrapFunction
467
+ } from "@ai-setting/roy-agent-core";
468
+ function isStdoutBatchEnabled() {
469
+ const v = process.env.ROY_AGENT_BATCH_STDOUT;
470
+ if (v === undefined)
471
+ return true;
472
+ if (v === "0" || v === "false" || v === "no")
473
+ return false;
474
+ return true;
475
+ }
373
476
  function resetStreamAbort() {
374
477
  streamAbortSignal.aborted = false;
375
478
  }
376
479
  function abortStream() {
377
480
  streamAbortSignal.aborted = true;
378
481
  }
379
- var logger2, COLORS, streamAbortSignal, StreamOutputService;
482
+ var logger2, COLORS, emitBatchFlushSpanImpl = (stats) => {}, emitBatchFlushSpan, emitSilentModeSkippedSpanImpl = (textLength) => {}, emitSilentModeSkippedSpan, streamAbortSignal, StreamOutputService;
380
483
  var init_stream_output_service = __esm(() => {
381
484
  init_markdown_renderer();
382
485
  logger2 = createLogger2("stream-output");
@@ -396,6 +499,28 @@ var init_stream_output_service = __esm(() => {
396
499
  error: chalk2.red,
397
500
  progress: chalk2.dim
398
501
  };
502
+ emitBatchFlushSpan = wrapFunction(emitBatchFlushSpanImpl, "cli.stream-output.writeStdout-batched", {
503
+ recordParams: true,
504
+ recordResult: false,
505
+ log: false,
506
+ paramFilter: (args) => {
507
+ const s = args[0] ?? {};
508
+ return {
509
+ writesInLastBatch: s.writesInLastBatch ?? 0,
510
+ totalBatches: s.batches ?? 0,
511
+ totalBytes: s.totalBytes ?? 0
512
+ };
513
+ }
514
+ });
515
+ emitSilentModeSkippedSpan = wrapFunction(emitSilentModeSkippedSpanImpl, "stream-output.silent-mode-skipped", {
516
+ recordParams: true,
517
+ recordResult: false,
518
+ log: false,
519
+ paramFilter: (args) => ({
520
+ "text.length": typeof args[0] === "number" ? args[0] : 0,
521
+ reason: "silent=true (Ink mode)"
522
+ })
523
+ });
399
524
  streamAbortSignal = {
400
525
  aborted: false
401
526
  };
@@ -414,6 +539,7 @@ var init_stream_output_service = __esm(() => {
414
539
  reasoningClosedByText = false;
415
540
  chunkCallback = undefined;
416
541
  silent = false;
542
+ stdoutBatcher = null;
417
543
  constructor(options = {}) {
418
544
  this.options = options;
419
545
  this.silent = options.silent ?? false;
@@ -438,9 +564,33 @@ var init_stream_output_service = __esm(() => {
438
564
  }
439
565
  }
440
566
  writeStdout(text) {
441
- if (this.silent)
567
+ if (this.silent) {
568
+ emitSilentModeSkippedSpan(text.length);
569
+ return;
570
+ }
571
+ if (!isStdoutBatchEnabled()) {
572
+ process.stdout.write(text);
442
573
  return;
443
- process.stdout.write(text);
574
+ }
575
+ if (this.stdoutBatcher === null) {
576
+ this.stdoutBatcher = createStdoutBatcher({
577
+ flushIntervalMs: 16,
578
+ onFlush: (stats) => {
579
+ emitBatchFlushSpan(stats);
580
+ }
581
+ });
582
+ }
583
+ this.stdoutBatcher.write(text);
584
+ }
585
+ flushStdout() {
586
+ if (this.stdoutBatcher !== null) {
587
+ this.stdoutBatcher.flushNow();
588
+ }
589
+ }
590
+ cancelStdout() {
591
+ if (this.stdoutBatcher !== null) {
592
+ this.stdoutBatcher.cancel();
593
+ }
444
594
  }
445
595
  logStdout(message) {
446
596
  if (this.silent)
@@ -685,8 +835,60 @@ ${COLORS.system("[已中断]")}
685
835
  this.reasoningStarted = false;
686
836
  this.reasoningClosedByText = false;
687
837
  this.thinkingPrinted = false;
838
+ this.flushStdout();
688
839
  }
689
840
  };
841
+ __legacyDecorateClassTS([
842
+ TracedAs2("cli.stream-output.writeStdout", {
843
+ recordParams: true,
844
+ recordResult: false,
845
+ log: false,
846
+ paramFilter: (args) => ({
847
+ "text.length": typeof args[0] === "string" ? args[0].length : 0,
848
+ "text.head": typeof args[0] === "string" ? args[0].slice(0, 32) : "",
849
+ "text.tail": typeof args[0] === "string" ? args[0].slice(-32) : "",
850
+ "batch.enabled": isStdoutBatchEnabled() ? 1 : 0
851
+ })
852
+ }),
853
+ __legacyMetadataTS("design:type", Function),
854
+ __legacyMetadataTS("design:paramtypes", [
855
+ String
856
+ ]),
857
+ __legacyMetadataTS("design:returntype", undefined)
858
+ ], StreamOutputService.prototype, "writeStdout", null);
859
+ __legacyDecorateClassTS([
860
+ TracedAs2("stream.handle-event", {
861
+ recordParams: true,
862
+ recordResult: false,
863
+ paramFilter: (args) => {
864
+ const e = args[0] ?? {};
865
+ const payload = e.payload ?? {};
866
+ return {
867
+ "event.type": e.type ?? "unknown",
868
+ "event.payload.kind": payload && typeof payload === "object" ? Object.keys(payload).join(",") : ""
869
+ };
870
+ }
871
+ }),
872
+ __legacyMetadataTS("design:type", Function),
873
+ __legacyMetadataTS("design:paramtypes", [
874
+ typeof EnvEvent === "undefined" ? Object : EnvEvent
875
+ ]),
876
+ __legacyMetadataTS("design:returntype", undefined)
877
+ ], StreamOutputService.prototype, "handleEvent", null);
878
+ __legacyDecorateClassTS([
879
+ TracedAs2("stream.handle-start", {
880
+ recordParams: true,
881
+ recordResult: false,
882
+ paramFilter: (args) => ({
883
+ model: args[0]?.metadata?.model ?? ""
884
+ })
885
+ }),
886
+ __legacyMetadataTS("design:type", Function),
887
+ __legacyMetadataTS("design:paramtypes", [
888
+ Object
889
+ ]),
890
+ __legacyMetadataTS("design:returntype", undefined)
891
+ ], StreamOutputService.prototype, "handleStart", null);
690
892
  __legacyDecorateClassTS([
691
893
  TracedAs2("stream.handle-text", {
692
894
  recordParams: true,
@@ -702,6 +904,102 @@ ${COLORS.system("[已中断]")}
702
904
  ]),
703
905
  __legacyMetadataTS("design:returntype", undefined)
704
906
  ], StreamOutputService.prototype, "handleText", null);
907
+ __legacyDecorateClassTS([
908
+ TracedAs2("stream.handle-reasoning", {
909
+ recordParams: true,
910
+ recordResult: false,
911
+ paramFilter: (args) => ({
912
+ "delta.length": args[0]?.delta?.length ?? 0,
913
+ "content.length": args[0]?.content?.length ?? 0,
914
+ phase: args[0]?.phase ?? ""
915
+ })
916
+ }),
917
+ __legacyMetadataTS("design:type", Function),
918
+ __legacyMetadataTS("design:paramtypes", [
919
+ Object
920
+ ]),
921
+ __legacyMetadataTS("design:returntype", undefined)
922
+ ], StreamOutputService.prototype, "handleReasoning", null);
923
+ __legacyDecorateClassTS([
924
+ TracedAs2("stream.handle-tool-call", {
925
+ recordParams: true,
926
+ recordResult: false,
927
+ log: true,
928
+ paramFilter: (args) => {
929
+ const p = args[0] ?? {};
930
+ return {
931
+ "tool.name": p.name ?? "unknown",
932
+ "tool.id": p.id ?? "",
933
+ "tool.args.keys": p.arguments ? Object.keys(p.arguments).join(",") : ""
934
+ };
935
+ }
936
+ }),
937
+ __legacyMetadataTS("design:type", Function),
938
+ __legacyMetadataTS("design:paramtypes", [
939
+ Object
940
+ ]),
941
+ __legacyMetadataTS("design:returntype", undefined)
942
+ ], StreamOutputService.prototype, "handleToolCall", null);
943
+ __legacyDecorateClassTS([
944
+ TracedAs2("stream.handle-tool-result", {
945
+ recordParams: true,
946
+ recordResult: false,
947
+ log: true,
948
+ paramFilter: (args) => {
949
+ const p = args[0] ?? {};
950
+ const result = p.result?.output ?? p.result?.error;
951
+ return {
952
+ "tool.name": p.name ?? "unknown",
953
+ "tool.result.kind": result !== undefined ? typeof result : "none",
954
+ "tool.result.preview": typeof result === "string" ? result.substring(0, 80) : typeof result === "object" && result !== null ? JSON.stringify(result).substring(0, 80) : ""
955
+ };
956
+ }
957
+ }),
958
+ __legacyMetadataTS("design:type", Function),
959
+ __legacyMetadataTS("design:paramtypes", [
960
+ Object
961
+ ]),
962
+ __legacyMetadataTS("design:returntype", undefined)
963
+ ], StreamOutputService.prototype, "handleToolResult", null);
964
+ __legacyDecorateClassTS([
965
+ TracedAs2("stream.handle-tool-error", {
966
+ recordParams: true,
967
+ recordResult: false,
968
+ log: true,
969
+ paramFilter: (args) => {
970
+ const p = args[0] ?? {};
971
+ return {
972
+ "tool.name": p.toolName ?? "unknown",
973
+ "tool.error.preview": typeof p.error === "string" ? p.error.substring(0, 120) : ""
974
+ };
975
+ }
976
+ }),
977
+ __legacyMetadataTS("design:type", Function),
978
+ __legacyMetadataTS("design:paramtypes", [
979
+ Object
980
+ ]),
981
+ __legacyMetadataTS("design:returntype", undefined)
982
+ ], StreamOutputService.prototype, "handleToolError", null);
983
+ __legacyDecorateClassTS([
984
+ TracedAs2("stream.handle-completed", {
985
+ recordParams: true,
986
+ recordResult: false,
987
+ paramFilter: (args) => {
988
+ const meta = args[0]?.metadata;
989
+ return {
990
+ model: meta?.model ?? "",
991
+ "usage.promptTokens": meta?.usage?.promptTokens ?? 0,
992
+ "usage.completionTokens": meta?.usage?.completionTokens ?? 0,
993
+ "usage.totalTokens": meta?.usage?.totalTokens ?? 0
994
+ };
995
+ }
996
+ }),
997
+ __legacyMetadataTS("design:type", Function),
998
+ __legacyMetadataTS("design:paramtypes", [
999
+ Object
1000
+ ]),
1001
+ __legacyMetadataTS("design:returntype", undefined)
1002
+ ], StreamOutputService.prototype, "handleCompleted", null);
705
1003
  });
706
1004
 
707
1005
  // src/commands/ui/mascot/glasses-girl.ts
@@ -1087,9 +1385,10 @@ var init_slash_command_popup = __esm(() => {
1087
1385
  });
1088
1386
  });
1089
1387
 
1090
- // src/render/markdown.js
1388
+ // src/render/markdown.ts
1091
1389
  import { Marked } from "marked";
1092
1390
  import { highlight } from "cli-highlight";
1391
+ import { wrapFunction as wrapFunction2 } from "@ai-setting/roy-agent-core";
1093
1392
  function setMarkdownEnabled(enabled) {
1094
1393
  markdownEnabled = enabled;
1095
1394
  }
@@ -1332,7 +1631,50 @@ function wrapLine(line, width) {
1332
1631
  return out.join(`
1333
1632
  `);
1334
1633
  }
1335
- function renderMarkdown(text, options = {}) {
1634
+ function cacheLookup(key) {
1635
+ for (let i = 0;i < renderCache.length; i++) {
1636
+ if (renderCache[i].key === key) {
1637
+ const entry = renderCache[i];
1638
+ if (i > 0) {
1639
+ renderCache.splice(i, 1);
1640
+ renderCache.unshift(entry);
1641
+ }
1642
+ return entry.value;
1643
+ }
1644
+ }
1645
+ return;
1646
+ }
1647
+ function cacheInsert(key, value, text, width) {
1648
+ if (renderCache.length >= MAX_CACHE_ENTRIES) {
1649
+ renderCache.pop();
1650
+ }
1651
+ renderCache.unshift({ key, value, text, width });
1652
+ renderCacheStats.size = renderCache.length;
1653
+ }
1654
+ function findPrefixCacheEntry(text, width) {
1655
+ let best;
1656
+ let bestLen = -1;
1657
+ for (let i = 0;i < renderCache.length; i++) {
1658
+ const e = renderCache[i];
1659
+ if (e.width !== width)
1660
+ continue;
1661
+ if (e.text.length === 0)
1662
+ continue;
1663
+ if (text.startsWith(e.text) && e.text.length > bestLen) {
1664
+ best = e;
1665
+ bestLen = e.text.length;
1666
+ }
1667
+ }
1668
+ return best;
1669
+ }
1670
+ function isSuffixSafeToLexIndependently(suffix) {
1671
+ if (suffix.length === 0)
1672
+ return true;
1673
+ if (suffix.charCodeAt(0) !== 10)
1674
+ return true;
1675
+ return false;
1676
+ }
1677
+ function renderMarkdownImpl(text, options = {}) {
1336
1678
  const width = options.width ?? 80;
1337
1679
  if (!markdownEnabled) {
1338
1680
  return wrapLine(text, width);
@@ -1340,6 +1682,28 @@ function renderMarkdown(text, options = {}) {
1340
1682
  if (!text || text.trim() === "") {
1341
1683
  return "";
1342
1684
  }
1685
+ const key = text + "\x00" + width;
1686
+ const cached = cacheLookup(key);
1687
+ if (cached !== undefined) {
1688
+ renderCacheStats.hits++;
1689
+ renderCacheStats.cachedHits++;
1690
+ return cached;
1691
+ }
1692
+ const prefixEntry = findPrefixCacheEntry(text, width);
1693
+ if (prefixEntry !== undefined) {
1694
+ const suffix = text.slice(prefixEntry.text.length);
1695
+ if (isSuffixSafeToLexIndependently(suffix)) {
1696
+ const suffixRender = renderMarkdownImpl(suffix, { width });
1697
+ const combined = prefixEntry.value + suffixRender;
1698
+ cacheInsert(key, combined, text, width);
1699
+ renderCacheStats.hits++;
1700
+ renderCacheStats.prefixHits++;
1701
+ renderCacheStats.partialParses++;
1702
+ return combined;
1703
+ }
1704
+ }
1705
+ renderCacheStats.misses++;
1706
+ renderCacheStats.partialParses++;
1343
1707
  let tokens;
1344
1708
  try {
1345
1709
  tokens = marked.lexer(text);
@@ -1353,9 +1717,11 @@ function renderMarkdown(text, options = {}) {
1353
1717
  lines.push(block);
1354
1718
  }
1355
1719
  }
1356
- return lines.join(`
1720
+ const result = lines.join(`
1357
1721
 
1358
1722
  `);
1723
+ cacheInsert(key, result, text, width);
1724
+ return result;
1359
1725
  }
1360
1726
  function truncateForTerminal(text, maxLines) {
1361
1727
  if (maxLines <= 0) {
@@ -1451,7 +1817,7 @@ function tailTruncateToRows(line, rows, width) {
1451
1817
  const tail = segments.join("");
1452
1818
  return tail + ANSI2.reset;
1453
1819
  }
1454
- var ANSI2, DEFAULT_THEME, markdownEnabled = true, marked, ANSI_CSI_RE;
1820
+ var ANSI2, DEFAULT_THEME, markdownEnabled = true, marked, MAX_CACHE_ENTRIES = 32, renderCache, renderCacheStats, renderMarkdown, ANSI_CSI_RE;
1455
1821
  var init_markdown = __esm(() => {
1456
1822
  ANSI2 = {
1457
1823
  reset: "\x1B[0m",
@@ -1493,11 +1859,36 @@ var init_markdown = __esm(() => {
1493
1859
  breaks: false,
1494
1860
  pedantic: false
1495
1861
  });
1862
+ renderCache = [];
1863
+ renderCacheStats = {
1864
+ hits: 0,
1865
+ prefixHits: 0,
1866
+ misses: 0,
1867
+ partialParses: 0,
1868
+ cachedHits: 0,
1869
+ size: 0
1870
+ };
1871
+ renderMarkdown = wrapFunction2(renderMarkdownImpl, "markdown.render", {
1872
+ recordParams: true,
1873
+ recordResult: true,
1874
+ paramFilter: (args) => ({
1875
+ "input.length": typeof args[0] === "string" ? args[0].length : 0,
1876
+ "options.width": typeof args[1]?.width === "number" ? args[1].width : 0
1877
+ }),
1878
+ resultFilter: (result) => ({
1879
+ "output.length": typeof result === "string" ? result.length : 0,
1880
+ "cache.hits": renderCacheStats.hits,
1881
+ "cache.prefixHits": renderCacheStats.prefixHits,
1882
+ "cache.misses": renderCacheStats.misses,
1883
+ "cache.partialParses": renderCacheStats.partialParses,
1884
+ "cache.size": renderCacheStats.size
1885
+ }),
1886
+ log: false
1887
+ });
1496
1888
  ANSI_CSI_RE = /\u001b\[[0-9;?]*[ -/]*[@-~]/g;
1497
1889
  });
1498
1890
 
1499
- // src/tui/Markdown.js
1500
- import React2 from "react";
1891
+ // src/tui/Markdown.tsx
1501
1892
  import { Text as Text2 } from "ink";
1502
1893
  import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
1503
1894
  var Markdown = ({ text, width }) => {
@@ -1514,7 +1905,7 @@ var init_Markdown = __esm(() => {
1514
1905
  init_markdown();
1515
1906
  });
1516
1907
 
1517
- // src/tui/theme.js
1908
+ // src/tui/theme.ts
1518
1909
  function shouldSuppressColors(env) {
1519
1910
  if (env.NO_COLOR && env.NO_COLOR !== "0" && env.NO_COLOR !== "false") {
1520
1911
  return true;
@@ -1558,11 +1949,14 @@ var init_theme = __esm(() => {
1558
1949
  };
1559
1950
  });
1560
1951
 
1561
- // src/tui/StatusBar.js
1562
- import React3 from "react";
1952
+ // src/tui/StatusBar.tsx
1563
1953
  import { Box as Box2, Text as Text3 } from "ink";
1564
1954
  import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
1565
- var StatusBar = ({ model, workdir, tokenCount }) => {
1955
+ var StatusBar = ({
1956
+ model,
1957
+ workdir,
1958
+ tokenCount
1959
+ }) => {
1566
1960
  const theme = getTheme();
1567
1961
  return /* @__PURE__ */ jsxDEV3(Box2, {
1568
1962
  borderStyle: "single",
@@ -1673,7 +2067,7 @@ __export(exports_repl_ink, {
1673
2067
  REPLInk: () => REPLInk,
1674
2068
  MultilineInput: () => MultilineInput
1675
2069
  });
1676
- import * as React4 from "react";
2070
+ import * as React2 from "react";
1677
2071
  import { Box as Box3, Text as Text4, Static, useApp, useInput as useInput2 } from "ink";
1678
2072
  import { createLogger as createLogger5 } from "@ai-setting/roy-agent-core";
1679
2073
  import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
@@ -1698,7 +2092,7 @@ function REPLInk(props) {
1698
2092
  onEscape
1699
2093
  } = props;
1700
2094
  const { exit: appExit } = useApp();
1701
- const [messages, setMessages] = React4.useState(() => [
2095
+ const [messages, setMessages] = React2.useState(() => [
1702
2096
  withMessageId({
1703
2097
  role: "system",
1704
2098
  kind: "welcome",
@@ -1706,47 +2100,47 @@ function REPLInk(props) {
1706
2100
  }),
1707
2101
  ...initialMessages.map(withMessageId)
1708
2102
  ]);
1709
- const [mode, setMode] = React4.useState(initialMode);
1710
- const [statusBarCtx, setStatusBarCtxState] = React4.useState({
2103
+ const [mode, setMode] = React2.useState(initialMode);
2104
+ const [statusBarCtx, setStatusBarCtxState] = React2.useState({
1711
2105
  mode: initialMode,
1712
2106
  cwd: initialStatusBarCtx.cwd ?? initialContext.cwd,
1713
2107
  gitBranch: initialStatusBarCtx.gitBranch,
1714
2108
  model: initialStatusBarCtx.model ?? initialContext.model
1715
2109
  });
1716
- const [inputValue, setInputValue] = React4.useState("");
1717
- const [popupIndex, setPopupIndex] = React4.useState(0);
1718
- const filteredCmds = React4.useMemo(() => {
2110
+ const [inputValue, setInputValue] = React2.useState("");
2111
+ const [popupIndex, setPopupIndex] = React2.useState(0);
2112
+ const filteredCmds = React2.useMemo(() => {
1719
2113
  if (!/^\/\S*$/.test(inputValue))
1720
2114
  return [];
1721
2115
  return filterCommands(inputValue);
1722
2116
  }, [inputValue]);
1723
2117
  const showPopup = filteredCmds.length > 0;
1724
- React4.useEffect(() => {
2118
+ React2.useEffect(() => {
1725
2119
  setPopupIndex(0);
1726
2120
  }, [filteredCmds]);
1727
2121
  const safePopupIndex = clampSelectedIndex(popupIndex, filteredCmds.length);
1728
- const handlePopupSelect = React4.useCallback((cmd) => {
2122
+ const handlePopupSelect = React2.useCallback((cmd) => {
1729
2123
  multilineInputRef.current?.setBuffer(cmd.cmd + " ");
1730
2124
  setInputValue(cmd.cmd + " ");
1731
2125
  }, []);
1732
- const handlePopupClose = React4.useCallback(() => {
2126
+ const handlePopupClose = React2.useCallback(() => {
1733
2127
  const current = multilineInputRef.current?.getBuffer() ?? "";
1734
2128
  const stripped = current.replace(/^\/+/, "");
1735
2129
  multilineInputRef.current?.setBuffer(stripped);
1736
2130
  setInputValue(stripped);
1737
2131
  }, []);
1738
- const handlePopupIndexChange = React4.useCallback((idx) => {
2132
+ const handlePopupIndexChange = React2.useCallback((idx) => {
1739
2133
  setPopupIndex(idx);
1740
2134
  }, []);
1741
- const streamingIndexRef = React4.useRef(-1);
1742
- const lastFlushTsRef = React4.useRef(0);
2135
+ const streamingIndexRef = React2.useRef(-1);
2136
+ const lastFlushTsRef = React2.useRef(0);
1743
2137
  const STALE_STREAM_THRESHOLD_MS = 1000;
1744
- const multilineInputRef = React4.useRef(null);
1745
- const lastEscapeTsRef = React4.useRef(0);
1746
- const pendingDeltaRef = React4.useRef("");
1747
- const throttleTimerRef = React4.useRef(null);
1748
- const isFirstDeltaInStreamRef = React4.useRef(true);
1749
- const flushStreamingDelta = React4.useCallback(() => {
2138
+ const multilineInputRef = React2.useRef(null);
2139
+ const lastEscapeTsRef = React2.useRef(0);
2140
+ const pendingDeltaRef = React2.useRef("");
2141
+ const throttleTimerRef = React2.useRef(null);
2142
+ const isFirstDeltaInStreamRef = React2.useRef(true);
2143
+ const flushStreamingDelta = React2.useCallback(() => {
1750
2144
  const delta = pendingDeltaRef.current;
1751
2145
  pendingDeltaRef.current = "";
1752
2146
  throttleTimerRef.current = null;
@@ -1775,7 +2169,7 @@ function REPLInk(props) {
1775
2169
  });
1776
2170
  lastFlushTsRef.current = Date.now();
1777
2171
  }, []);
1778
- React4.useEffect(() => {
2172
+ React2.useEffect(() => {
1779
2173
  return () => {
1780
2174
  if (throttleTimerRef.current !== null) {
1781
2175
  clearTimeout(throttleTimerRef.current);
@@ -1783,8 +2177,8 @@ function REPLInk(props) {
1783
2177
  }
1784
2178
  };
1785
2179
  }, []);
1786
- const apiRef = React4.useRef(null);
1787
- React4.useEffect(() => {
2180
+ const apiRef = React2.useRef(null);
2181
+ React2.useEffect(() => {
1788
2182
  const api = {
1789
2183
  appendMessage: (msg) => {
1790
2184
  setMessages((msgs) => [...msgs, withMessageId(msg)]);
@@ -1860,7 +2254,7 @@ function REPLInk(props) {
1860
2254
  apiRef.current = api;
1861
2255
  onReady?.(api);
1862
2256
  }, [appExit, onCommand, onReady]);
1863
- const handleEscapeCascade = React4.useCallback(() => {
2257
+ const handleEscapeCascade = React2.useCallback(() => {
1864
2258
  const now = Date.now();
1865
2259
  if (now - lastEscapeTsRef.current < 100) {
1866
2260
  return;
@@ -1904,7 +2298,7 @@ function REPLInk(props) {
1904
2298
  }
1905
2299
  }
1906
2300
  });
1907
- const handleSubmit = React4.useCallback(async (value) => {
2301
+ const handleSubmit = React2.useCallback(async (value) => {
1908
2302
  if (!value || value.trim() === "") {
1909
2303
  return;
1910
2304
  }
@@ -1933,7 +2327,7 @@ function REPLInk(props) {
1933
2327
  ]);
1934
2328
  }
1935
2329
  }, [onCommand, onSubmit]);
1936
- const staticItems = React4.useMemo(() => {
2330
+ const staticItems = React2.useMemo(() => {
1937
2331
  if (messages.length <= 1)
1938
2332
  return [];
1939
2333
  return messages.slice(0, -1);
@@ -1941,8 +2335,8 @@ function REPLInk(props) {
1941
2335
  const tailMsg = messages.length > 0 ? messages[messages.length - 1] : null;
1942
2336
  const terminalWidth = process.stdout.columns ?? 80;
1943
2337
  const terminalHeight = process.stdout.rows ?? 24;
1944
- const dynamicTailBounds = React4.useMemo(() => computeDynamicTailBounds(terminalHeight, 12, showPopup), [terminalHeight, showPopup]);
1945
- const staticTailBounds = React4.useMemo(() => computeDynamicTailBounds(terminalHeight, 12, showPopup), [terminalHeight, showPopup]);
2338
+ const dynamicTailBounds = React2.useMemo(() => computeDynamicTailBounds(terminalHeight, 12, showPopup), [terminalHeight, showPopup]);
2339
+ const staticTailBounds = React2.useMemo(() => computeDynamicTailBounds(terminalHeight, 12, showPopup), [terminalHeight, showPopup]);
1946
2340
  const tailKey = messages.length > 0 ? tailMsg?.id ?? `tail-${messages.length - 1}` : "tail-empty";
1947
2341
  const statusBarModel = shortModel(statusBarCtx.model);
1948
2342
  const statusBarWorkdir = statusBarCtx.cwd;
@@ -2009,7 +2403,7 @@ function shortModel(model) {
2009
2403
  }
2010
2404
  async function renderInkREPL(props) {
2011
2405
  const ink = await import("ink");
2012
- const { waitUntilExit } = ink.render(React4.createElement(REPLInk, props));
2406
+ const { waitUntilExit } = ink.render(React2.createElement(REPLInk, props));
2013
2407
  await waitUntilExit();
2014
2408
  }
2015
2409
  var MarkdownBounded, inkLogger, _msgIdCounter = 0, MultilineInput, MessageView;
@@ -2021,7 +2415,7 @@ var init_repl_ink = __esm(() => {
2021
2415
  init_Markdown();
2022
2416
  init_StatusBar();
2023
2417
  init_dynamic_tail();
2024
- MarkdownBounded = React4.memo(({ text, bounds, width }) => {
2418
+ MarkdownBounded = React2.memo(({ text, bounds, width }) => {
2025
2419
  const out = renderBoundedAssistant(text, bounds, width);
2026
2420
  if (!out) {
2027
2421
  return null;
@@ -2031,16 +2425,16 @@ var init_repl_ink = __esm(() => {
2031
2425
  }, undefined, false, undefined, this);
2032
2426
  });
2033
2427
  inkLogger = createLogger5("repl-ink");
2034
- MultilineInput = React4.memo(React4.forwardRef(function MultilineInput2(props, ref) {
2428
+ MultilineInput = React2.memo(React2.forwardRef(function MultilineInput2(props, ref) {
2035
2429
  const { onSubmit, placeholder, popupActive, onChange, onEscape } = props;
2036
- const [buffer, setBuffer] = React4.useState("");
2037
- const [cursor, setCursor] = React4.useState(0);
2038
- React4.useEffect(() => {
2430
+ const [buffer, setBuffer] = React2.useState("");
2431
+ const [cursor, setCursor] = React2.useState(0);
2432
+ React2.useEffect(() => {
2039
2433
  if (popupActive || buffer.startsWith("/")) {
2040
2434
  onChange?.(buffer);
2041
2435
  }
2042
2436
  }, [buffer, onChange, popupActive]);
2043
- React4.useImperativeHandle(ref, () => ({
2437
+ React2.useImperativeHandle(ref, () => ({
2044
2438
  clearBuffer: () => {
2045
2439
  setBuffer("");
2046
2440
  setCursor(0);
@@ -2278,7 +2672,7 @@ var init_repl_ink = __esm(() => {
2278
2672
  })
2279
2673
  }, undefined, false, undefined, this);
2280
2674
  }));
2281
- MessageView = React4.memo(function MessageView2({
2675
+ MessageView = React2.memo(function MessageView2({
2282
2676
  msg,
2283
2677
  terminalWidth,
2284
2678
  tailBounds
@@ -9458,7 +9852,7 @@ class CliQuietModeService {
9458
9852
  // package.json
9459
9853
  var package_default = {
9460
9854
  name: "@ai-setting/roy-agent-cli",
9461
- version: "1.7.20",
9855
+ version: "1.7.21",
9462
9856
  type: "module",
9463
9857
  description: "CLI for roy-agent - Non-interactive command execution",
9464
9858
  main: "./dist/index.js",
@@ -10613,6 +11007,21 @@ function finalizeActStdout(args) {
10613
11007
  output.log(result);
10614
11008
  }
10615
11009
 
11010
+ // src/commands/shared/debug-trace.ts
11011
+ function printTraceIdAfterResponse(traceId, options) {
11012
+ const enabled = typeof options === "boolean" ? options : options.enabled;
11013
+ if (!enabled)
11014
+ return;
11015
+ const writer = typeof options === "object" && options.write ? options.write : (chunk) => process.stderr.write(chunk);
11016
+ writer(`[Trace] ${traceId}
11017
+ `);
11018
+ if (typeof options === "object" && typeof options.tuiSink === "function") {
11019
+ try {
11020
+ options.tuiSink(traceId);
11021
+ } catch (_tuiErr) {}
11022
+ }
11023
+ }
11024
+
10616
11025
  // src/commands/act.ts
10617
11026
  function detectWorkspaceRoot(cwd = process.cwd(), runGit = execFileSync) {
10618
11027
  try {
@@ -10680,6 +11089,10 @@ function createActCommand(externalEnvService) {
10680
11089
  describe: "附加图片到消息(可多次传入;支持本地路径 / http(s) URL / data:base64)",
10681
11090
  type: "array",
10682
11091
  string: true
11092
+ }).option("debug-on", {
11093
+ describe: "调试模式:响应结束后输出 [Trace] <traceId>(stderr),便于追踪调用 trace",
11094
+ type: "boolean",
11095
+ default: false
10683
11096
  }),
10684
11097
  async handler(args) {
10685
11098
  const quiet = args.quiet ?? true;
@@ -10916,9 +11329,6 @@ function createActCommand(externalEnvService) {
10916
11329
  }
10917
11330
  });
10918
11331
  const traceId = rootSpan.spanContext.traceId;
10919
- if (!quiet) {
10920
- output.info(`[Trace] ${traceId}`);
10921
- }
10922
11332
  provider.setGlobalContext(rootSpan.spanContext);
10923
11333
  const contextHandler = new ContextHandlerService(env, sessionComponent, { maxRetries: 1, autoCompact: true });
10924
11334
  const context = {
@@ -10953,6 +11363,7 @@ function createActCommand(externalEnvService) {
10953
11363
  streamService,
10954
11364
  output
10955
11365
  });
11366
+ printTraceIdAfterResponse(traceId, args.debugOn ?? false);
10956
11367
  if (!quiet) {
10957
11368
  if (isWorkflowPausedActResult(result)) {
10958
11369
  output.warn("工作流已暂停,等待用户输入(见上方 resume 提示)");
@@ -11271,6 +11682,35 @@ class QueryExecutor {
11271
11682
  }
11272
11683
  }
11273
11684
  }
11685
+ __legacyDecorateClassTS([
11686
+ TracedAs4("cli.query-executor.setChunkCallback", {
11687
+ recordParams: true,
11688
+ recordResult: false,
11689
+ log: true,
11690
+ paramFilter: (args) => ({
11691
+ "cb.isFunction": typeof args[0] === "function"
11692
+ })
11693
+ }),
11694
+ __legacyMetadataTS("design:type", Function),
11695
+ __legacyMetadataTS("design:paramtypes", [
11696
+ typeof StreamChunkCallback === "undefined" ? Object : StreamChunkCallback
11697
+ ]),
11698
+ __legacyMetadataTS("design:returntype", undefined)
11699
+ ], QueryExecutor.prototype, "setChunkCallback", null);
11700
+ __legacyDecorateClassTS([
11701
+ TracedAs4("cli.query-executor.handleEvent", {
11702
+ recordParams: true,
11703
+ recordResult: false,
11704
+ paramFilter: (args) => ({
11705
+ "event.type": args[0]?.type ?? "unknown"
11706
+ })
11707
+ }),
11708
+ __legacyMetadataTS("design:type", Function),
11709
+ __legacyMetadataTS("design:paramtypes", [
11710
+ Object
11711
+ ]),
11712
+ __legacyMetadataTS("design:returntype", undefined)
11713
+ ], QueryExecutor.prototype, "handleEvent", null);
11274
11714
  __legacyDecorateClassTS([
11275
11715
  TracedAs4("cli.query-executor.execute", { recordParams: true, log: true }),
11276
11716
  __legacyMetadataTS("design:type", Function),
@@ -11697,6 +12137,16 @@ class EventHandler {
11697
12137
  return new Promise((resolve) => setTimeout(resolve, ms));
11698
12138
  }
11699
12139
  }
12140
+ __legacyDecorateClassTS([
12141
+ TracedAs5("cli.event-handler.start", {
12142
+ recordParams: false,
12143
+ recordResult: false,
12144
+ log: true
12145
+ }),
12146
+ __legacyMetadataTS("design:type", Function),
12147
+ __legacyMetadataTS("design:paramtypes", []),
12148
+ __legacyMetadataTS("design:returntype", Function)
12149
+ ], EventHandler.prototype, "start", null);
11700
12150
  __legacyDecorateClassTS([
11701
12151
  TracedAs5("cli.event-handler.handleEvent", { recordParams: true }),
11702
12152
  __legacyMetadataTS("design:type", Function),
@@ -11705,6 +12155,16 @@ __legacyDecorateClassTS([
11705
12155
  ]),
11706
12156
  __legacyMetadataTS("design:returntype", undefined)
11707
12157
  ], EventHandler.prototype, "handleEvent", null);
12158
+ __legacyDecorateClassTS([
12159
+ TracedAs5("cli.event-handler.processQueue", {
12160
+ recordParams: false,
12161
+ recordResult: false,
12162
+ log: true
12163
+ }),
12164
+ __legacyMetadataTS("design:type", Function),
12165
+ __legacyMetadataTS("design:paramtypes", []),
12166
+ __legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
12167
+ ], EventHandler.prototype, "processQueue", null);
11708
12168
 
11709
12169
  // src/commands/shared/esc-active-descendant.ts
11710
12170
  function hasActiveDescendants(env, parentSessionId) {
@@ -12651,8 +13111,23 @@ ${COLORS.system("[没有正在执行的请求]")}`);
12651
13111
  onSubmit: async (input) => {
12652
13112
  this.isExecuting = true;
12653
13113
  inkApiRef?.setMode("executing");
13114
+ const inkTracerProvider = getTracerProvider3();
13115
+ const inkTracer = inkTracerProvider.getTracer("roy-tracer");
13116
+ const inkExistingContext = inkTracerProvider.getGlobalContext();
13117
+ let inkRootSpan;
13118
+ let inkTurnTraceId;
13119
+ if (inkExistingContext) {
13120
+ inkRootSpan = inkTracer.startSpan("interactive.execute", {
13121
+ parent: inkExistingContext
13122
+ });
13123
+ inkTurnTraceId = inkExistingContext.traceId;
13124
+ } else {
13125
+ inkRootSpan = inkTracer.startSpan("interactive.execute");
13126
+ inkTurnTraceId = inkRootSpan.spanContext.traceId;
13127
+ inkTracerProvider.setGlobalContext(inkRootSpan.spanContext);
13128
+ }
12654
13129
  try {
12655
- await this.options.onExecute(input);
13130
+ await this.options.onExecute(input, inkTurnTraceId, undefined);
12656
13131
  inkApiRef?.setMode("ready");
12657
13132
  if (this.options.onAfterExecute) {
12658
13133
  try {
@@ -12667,6 +13142,26 @@ ${COLORS.system("[没有正在执行的请求]")}`);
12667
13142
  inkApiRef?.appendMessage({ role: "system", content: `[Error] ${msg}` });
12668
13143
  throw err;
12669
13144
  } finally {
13145
+ try {
13146
+ printTraceIdAfterResponse(inkTurnTraceId, {
13147
+ enabled: this.options.debugOn ?? false,
13148
+ tuiSink: (traceId) => {
13149
+ inkApiRef?.appendMessage({
13150
+ role: "system",
13151
+ content: `\uD83D\uDD0D [Trace] ${traceId}`
13152
+ });
13153
+ }
13154
+ });
13155
+ } catch (traceErr) {
13156
+ logger5.warn("printTraceIdAfterResponse failed (ink path)", {
13157
+ error: String(traceErr)
13158
+ });
13159
+ }
13160
+ try {
13161
+ inkRootSpan.end();
13162
+ } catch (spanErr) {
13163
+ logger5.warn("inkRootSpan.end failed", { error: String(spanErr) });
13164
+ }
12670
13165
  this.isExecuting = false;
12671
13166
  }
12672
13167
  },
@@ -12936,7 +13431,6 @@ ${COLORS.system("[通知2] ❯ " + message.replace(/\n/g, `
12936
13431
  traceId = rootSpan.spanContext.traceId;
12937
13432
  provider.setGlobalContext(rootSpan.spanContext);
12938
13433
  }
12939
- console.log(`${COLORS.system("[Trace] " + traceId)}`);
12940
13434
  console.log(`${COLORS.progress("[thinking...]")}`);
12941
13435
  try {
12942
13436
  await this.options.onExecute(message, traceId, agentContext);
@@ -12959,6 +13453,7 @@ ${COLORS.error("❌ 执行失败: " + error)}
12959
13453
  }
12960
13454
  } finally {
12961
13455
  rootSpan.end();
13456
+ printTraceIdAfterResponse(traceId, this.options.debugOn ?? false);
12962
13457
  if (existingContext) {
12963
13458
  provider.setGlobalContext(existingContext);
12964
13459
  } else {
@@ -13299,6 +13794,10 @@ function createInteractiveCommand(externalEnvService) {
13299
13794
  describe: "Default agent 名字(默认 Roy,可被覆盖)",
13300
13795
  type: "string",
13301
13796
  default: "Roy"
13797
+ }).option("debug-on", {
13798
+ describe: "调试模式:每次 turn 结束后输出 [Trace] <traceId>(stderr),便于追踪调用 trace",
13799
+ type: "boolean",
13800
+ default: false
13302
13801
  }),
13303
13802
  async handler(args) {
13304
13803
  CliQuietModeService.getInstance().setQuiet(true);
@@ -13465,6 +13964,7 @@ function createInteractiveCommand(externalEnvService) {
13465
13964
  model: args.model,
13466
13965
  version: getPackageVersion(),
13467
13966
  useInk,
13967
+ debugOn: args.debugOn ?? false,
13468
13968
  onExecute: async (message, traceId, agentContext) => {
13469
13969
  resetStreamAbort();
13470
13970
  const preloadedPrompts = eventSourceSystemPrompts;
@@ -13639,25 +14139,28 @@ function createInteractiveCommand(externalEnvService) {
13639
14139
  var InteractiveCommand = createInteractiveCommand();
13640
14140
 
13641
14141
  // src/commands/run.ts
13642
- import React9 from "react";
14142
+ import React8 from "react";
13643
14143
  import { render } from "ink";
13644
14144
 
13645
- // src/RunTui.js
13646
- import React8, { useState as useState6, useCallback as useCallback4, useRef as useRef2, useEffect as useEffect5 } from "react";
13647
- import { Box as Box6, Text as Text8, useApp as useApp2 } from "ink";
14145
+ // src/RunTui.tsx
14146
+ import { useState as useState6, useCallback as useCallback4, useRef as useRef5, useEffect as useEffect7, useMemo as useMemo3 } from "react";
14147
+ import { Box as Box7, Text as Text9, useApp as useApp2 } from "ink";
13648
14148
 
13649
- // src/tui/App.js
14149
+ // src/tui/App.tsx
13650
14150
  init_Markdown();
13651
- import React6 from "react";
14151
+ import React4, { useEffect as useEffect4, useRef as useRef2 } from "react";
13652
14152
  import { Box as Box4, Static as Static2, Text as Text6 } from "ink";
13653
14153
 
13654
- // src/tui/Spinner.js
14154
+ // src/tui/Spinner.tsx
13655
14155
  init_theme();
13656
- import React5, { useEffect as useEffect3, useState as useState3 } from "react";
14156
+ import { useEffect as useEffect3, useState as useState3 } from "react";
13657
14157
  import { Text as Text5 } from "ink";
13658
14158
  import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
13659
14159
  var FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
13660
- var Spinner = ({ label, intervalMs = 80 }) => {
14160
+ var Spinner = ({
14161
+ label,
14162
+ intervalMs = 80
14163
+ }) => {
13661
14164
  const [frame, setFrame] = useState3(0);
13662
14165
  const theme = getTheme();
13663
14166
  useEffect3(() => {
@@ -13681,15 +14184,48 @@ var Spinner = ({ label, intervalMs = 80 }) => {
13681
14184
  }, undefined, true, undefined, this);
13682
14185
  };
13683
14186
 
13684
- // src/tui/App.js
14187
+ // src/tui/App.tsx
13685
14188
  init_StatusBar();
13686
14189
  init_theme();
14190
+ import { wrapFunction as wrapFunction3 } from "@ai-setting/roy-agent-core";
13687
14191
  import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
13688
14192
  var ROLE_PREFIX = {
13689
14193
  user: "\uD83D\uDC64 You",
13690
14194
  assistant: "\uD83E\uDD16 Agent",
13691
14195
  tool: "\uD83D\uDD27 Tool"
13692
14196
  };
14197
+ var emitAppRenderSpanImpl = (snapshot) => {};
14198
+ var emitAppRenderSpan = wrapFunction3(emitAppRenderSpanImpl, "tui.app.render", {
14199
+ recordParams: true,
14200
+ recordResult: false,
14201
+ log: true,
14202
+ paramFilter: (args) => {
14203
+ const s = args[0] ?? {};
14204
+ return {
14205
+ renderCount: s.renderCount ?? 0,
14206
+ historyLength: s.historyLength ?? 0,
14207
+ status: s.status ?? "unknown"
14208
+ };
14209
+ }
14210
+ });
14211
+ var emitRenderScheduledSpanImpl = (parentRenderCount) => {};
14212
+ var emitRenderScheduledSpan = wrapFunction3(emitRenderScheduledSpanImpl, "tui.app.render-scheduled", {
14213
+ recordParams: true,
14214
+ recordResult: false,
14215
+ log: false,
14216
+ paramFilter: (args) => ({
14217
+ parentRenderCount: args[0] ?? 0
14218
+ })
14219
+ });
14220
+ var emitRenderThrottledSpanImpl = (parentRenderCount) => {};
14221
+ var emitRenderThrottledSpan = wrapFunction3(emitRenderThrottledSpanImpl, "tui.app.render-throttled", {
14222
+ recordParams: true,
14223
+ recordResult: false,
14224
+ log: false,
14225
+ paramFilter: (args) => ({
14226
+ parentRenderCount: args[0] ?? 0
14227
+ })
14228
+ });
13693
14229
  var RoleLabel = ({ role }) => {
13694
14230
  const theme = getTheme();
13695
14231
  const roleColor = role === "user" ? theme.user : role === "assistant" ? theme.assistant : theme.tool;
@@ -13752,8 +14288,23 @@ var HistoryEntry = ({ item }) => {
13752
14288
  ]
13753
14289
  }, undefined, true, undefined, this);
13754
14290
  };
13755
- var App = ({ history, status, model, workdir, streamingText, tokenCount }) => {
14291
+ var App = ({
14292
+ history,
14293
+ status,
14294
+ model,
14295
+ workdir,
14296
+ tokenCount
14297
+ }) => {
13756
14298
  const theme = getTheme();
14299
+ const renderCountRef = useRef2(0);
14300
+ renderCountRef.current += 1;
14301
+ useEffect4(() => {
14302
+ emitAppRenderSpan({
14303
+ renderCount: renderCountRef.current,
14304
+ historyLength: history.length,
14305
+ status
14306
+ });
14307
+ });
13757
14308
  return /* @__PURE__ */ jsxDEV6(Box4, {
13758
14309
  flexDirection: "column",
13759
14310
  minHeight: 20,
@@ -13787,21 +14338,7 @@ var App = ({ history, status, model, workdir, streamingText, tokenCount }) => {
13787
14338
  label: "Agent is thinking..."
13788
14339
  }, undefined, false, undefined, this)
13789
14340
  }, undefined, false, undefined, this) : null,
13790
- status === "streaming" && streamingText ? /* @__PURE__ */ jsxDEV6(Box4, {
13791
- flexDirection: "column",
13792
- marginBottom: 1,
13793
- children: [
13794
- /* @__PURE__ */ jsxDEV6(RoleLabel, {
13795
- role: "assistant"
13796
- }, undefined, false, undefined, this),
13797
- /* @__PURE__ */ jsxDEV6(Box4, {
13798
- marginLeft: 2,
13799
- children: /* @__PURE__ */ jsxDEV6(Markdown, {
13800
- text: streamingText
13801
- }, undefined, false, undefined, this)
13802
- }, undefined, false, undefined, this)
13803
- ]
13804
- }, undefined, true, undefined, this) : status === "streaming" ? /* @__PURE__ */ jsxDEV6(Box4, {
14341
+ status === "streaming" ? /* @__PURE__ */ jsxDEV6(Box4, {
13805
14342
  marginBottom: 1,
13806
14343
  children: /* @__PURE__ */ jsxDEV6(Spinner, {
13807
14344
  label: "Generating response..."
@@ -13818,20 +14355,156 @@ var App = ({ history, status, model, workdir, streamingText, tokenCount }) => {
13818
14355
  ]
13819
14356
  }, undefined, true, undefined, this);
13820
14357
  };
13821
-
13822
- // src/tui/index.js
14358
+ function areAppPropsEqual(prev, next) {
14359
+ if (prev.status !== next.status)
14360
+ return false;
14361
+ if (prev.model !== next.model)
14362
+ return false;
14363
+ if (prev.workdir !== next.workdir)
14364
+ return false;
14365
+ if (prev.tokenCount !== next.tokenCount)
14366
+ return false;
14367
+ if (prev.history !== next.history)
14368
+ return false;
14369
+ return true;
14370
+ }
14371
+ var parentRenderCountRef = { current: 0 };
14372
+ var AppThrottledImpl = (props) => {
14373
+ parentRenderCountRef.current += 1;
14374
+ emitRenderScheduledSpan(parentRenderCountRef.current);
14375
+ return /* @__PURE__ */ jsxDEV6(App, {
14376
+ ...props
14377
+ }, undefined, false, undefined, this);
14378
+ };
14379
+ var AppThrottled = React4.memo(AppThrottledImpl, areAppPropsEqual);
14380
+ AppThrottled.displayName = "App(throttled)";
14381
+ var lastMemoResult = null;
14382
+ var instrumentedAreEqual = (prev, next) => {
14383
+ const equal = areAppPropsEqual(prev, next);
14384
+ if (equal && lastMemoResult !== true) {
14385
+ emitRenderThrottledSpan(parentRenderCountRef.current);
14386
+ }
14387
+ lastMemoResult = equal;
14388
+ return equal;
14389
+ };
14390
+ var AppMemo = React4.memo(AppThrottledImpl, instrumentedAreEqual);
14391
+ AppMemo.displayName = "App(memo-throttled)";
14392
+ // src/tui/StreamingOverlay.tsx
13823
14393
  init_Markdown();
13824
- init_StatusBar();
13825
-
13826
- // src/tui/TextInput.js
13827
- import React7, { useEffect as useEffect4, useState as useState4 } from "react";
13828
- import { Box as Box5, Text as Text7, useInput as useInput3 } from "ink";
14394
+ import { useEffect as useEffect5, useRef as useRef3 } from "react";
14395
+ import { Box as Box5, Text as Text7 } from "ink";
14396
+ import { wrapFunction as wrapFunction4 } from "@ai-setting/roy-agent-core";
13829
14397
  import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
13830
- var TextInput = ({ label, prefix, onSubmit, onCancel, placeholder, history = [] }) => {
13831
- const [value, setValue] = useState4("");
13832
- const [historyIndex, setHistoryIndex] = useState4(-1);
13833
- const [draft, setDraft] = useState4("");
13834
- useEffect4(() => {
14398
+ var emitOverlayRenderSpanImpl = (snapshot) => {};
14399
+ var emitOverlayRenderSpan = wrapFunction4(emitOverlayRenderSpanImpl, "streaming-overlay.render", {
14400
+ recordParams: true,
14401
+ recordResult: false,
14402
+ log: false,
14403
+ paramFilter: (args) => {
14404
+ const s = args[0] ?? {};
14405
+ return {
14406
+ renderCount: s.renderCount ?? 0,
14407
+ streamingTextLength: s.streamingTextLength ?? 0,
14408
+ status: s.status ?? "unknown"
14409
+ };
14410
+ }
14411
+ });
14412
+ var emitOverlayMarkdownSpanImpl = (snapshot) => {};
14413
+ var emitOverlayMarkdownSpan = wrapFunction4(emitOverlayMarkdownSpanImpl, "streaming-overlay.markdown-render", {
14414
+ recordParams: true,
14415
+ recordResult: false,
14416
+ log: false,
14417
+ paramFilter: (args) => {
14418
+ const s = args[0] ?? {};
14419
+ return {
14420
+ inputLength: s.inputLength ?? 0,
14421
+ renderCount: s.renderCount ?? 0
14422
+ };
14423
+ }
14424
+ });
14425
+ var StreamingOverlay = ({
14426
+ streamingText,
14427
+ status,
14428
+ markdownEnabled: markdownEnabled2,
14429
+ width
14430
+ }) => {
14431
+ const renderCountRef = useRef3(0);
14432
+ renderCountRef.current += 1;
14433
+ useEffect5(() => {
14434
+ emitOverlayRenderSpan({
14435
+ renderCount: renderCountRef.current,
14436
+ streamingTextLength: streamingText.length,
14437
+ status
14438
+ });
14439
+ });
14440
+ if (status === "thinking") {
14441
+ return /* @__PURE__ */ jsxDEV7(Box5, {
14442
+ marginBottom: 1,
14443
+ children: /* @__PURE__ */ jsxDEV7(Text7, {
14444
+ dimColor: true,
14445
+ children: "\uD83E\uDD14 thinking..."
14446
+ }, undefined, false, undefined, this)
14447
+ }, undefined, false, undefined, this);
14448
+ }
14449
+ if (status === "idle") {
14450
+ return null;
14451
+ }
14452
+ if (!streamingText) {
14453
+ return /* @__PURE__ */ jsxDEV7(Box5, {
14454
+ marginBottom: 1,
14455
+ children: /* @__PURE__ */ jsxDEV7(Text7, {
14456
+ dimColor: true,
14457
+ children: "⏳ generating response..."
14458
+ }, undefined, false, undefined, this)
14459
+ }, undefined, false, undefined, this);
14460
+ }
14461
+ const effectiveWidth = width ?? process.stdout.columns ?? 80;
14462
+ emitOverlayMarkdownSpan({
14463
+ inputLength: streamingText.length,
14464
+ renderCount: renderCountRef.current
14465
+ });
14466
+ return /* @__PURE__ */ jsxDEV7(Box5, {
14467
+ flexDirection: "column",
14468
+ marginBottom: 1,
14469
+ children: [
14470
+ /* @__PURE__ */ jsxDEV7(Text7, {
14471
+ bold: true,
14472
+ color: "cyan",
14473
+ children: "\uD83E\uDD16 Agent"
14474
+ }, undefined, false, undefined, this),
14475
+ /* @__PURE__ */ jsxDEV7(Box5, {
14476
+ marginLeft: 2,
14477
+ children: markdownEnabled2 ? /* @__PURE__ */ jsxDEV7(Markdown, {
14478
+ text: streamingText,
14479
+ width: effectiveWidth
14480
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV7(Text7, {
14481
+ children: streamingText
14482
+ }, undefined, false, undefined, this)
14483
+ }, undefined, false, undefined, this)
14484
+ ]
14485
+ }, undefined, true, undefined, this);
14486
+ };
14487
+
14488
+ // src/tui/index.ts
14489
+ init_Markdown();
14490
+ init_StatusBar();
14491
+
14492
+ // src/tui/TextInput.tsx
14493
+ import { useEffect as useEffect6, useState as useState4 } from "react";
14494
+ import { Box as Box6, Text as Text8, useInput as useInput3 } from "ink";
14495
+ import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
14496
+ var TextInput = ({
14497
+ label,
14498
+ prefix,
14499
+ onSubmit,
14500
+ onCancel,
14501
+ placeholder,
14502
+ history = []
14503
+ }) => {
14504
+ const [value, setValue] = useState4("");
14505
+ const [historyIndex, setHistoryIndex] = useState4(-1);
14506
+ const [draft, setDraft] = useState4("");
14507
+ useEffect6(() => {
13835
14508
  setHistoryIndex(-1);
13836
14509
  }, [history.length]);
13837
14510
  useInput3((input, key) => {
@@ -13885,9 +14558,9 @@ var TextInput = ({ label, prefix, onSubmit, onCancel, placeholder, history = []
13885
14558
  setValue((v) => v + input);
13886
14559
  }
13887
14560
  });
13888
- return /* @__PURE__ */ jsxDEV7(Box5, {
14561
+ return /* @__PURE__ */ jsxDEV8(Box6, {
13889
14562
  children: [
13890
- /* @__PURE__ */ jsxDEV7(Text7, {
14563
+ /* @__PURE__ */ jsxDEV8(Text8, {
13891
14564
  bold: true,
13892
14565
  color: "green",
13893
14566
  children: [
@@ -13895,21 +14568,21 @@ var TextInput = ({ label, prefix, onSubmit, onCancel, placeholder, history = []
13895
14568
  " "
13896
14569
  ]
13897
14570
  }, undefined, true, undefined, this),
13898
- /* @__PURE__ */ jsxDEV7(Text7, {
14571
+ /* @__PURE__ */ jsxDEV8(Text8, {
13899
14572
  bold: true,
13900
14573
  children: [
13901
14574
  label,
13902
14575
  ": "
13903
14576
  ]
13904
14577
  }, undefined, true, undefined, this),
13905
- /* @__PURE__ */ jsxDEV7(Text7, {
14578
+ /* @__PURE__ */ jsxDEV8(Text8, {
13906
14579
  children: value
13907
14580
  }, undefined, false, undefined, this),
13908
- !value && placeholder ? /* @__PURE__ */ jsxDEV7(Text7, {
14581
+ !value && placeholder ? /* @__PURE__ */ jsxDEV8(Text8, {
13909
14582
  dimColor: true,
13910
14583
  children: placeholder
13911
14584
  }, undefined, false, undefined, this) : null,
13912
- historyIndex !== -1 ? /* @__PURE__ */ jsxDEV7(Text7, {
14585
+ historyIndex !== -1 ? /* @__PURE__ */ jsxDEV8(Text8, {
13913
14586
  dimColor: true,
13914
14587
  children: " (history)"
13915
14588
  }, undefined, false, undefined, this) : null
@@ -13917,49 +14590,110 @@ var TextInput = ({ label, prefix, onSubmit, onCancel, placeholder, history = []
13917
14590
  }, undefined, true, undefined, this);
13918
14591
  };
13919
14592
 
13920
- // src/tui/index.js
14593
+ // src/tui/index.ts
13921
14594
  init_theme();
14595
+ init_welcome_card2();
13922
14596
 
13923
- // src/tui/welcome-card.js
13924
- init_welcome_card();
13925
- // src/tui/use-streaming-accumulator.js
13926
- import { useCallback as useCallback3, useState as useState5 } from "react";
14597
+ // src/tui/use-streaming-accumulator.ts
14598
+ import { useCallback as useCallback3, useRef as useRef4, useState as useState5 } from "react";
14599
+ import { wrapFunction as wrapFunction5 } from "@ai-setting/roy-agent-core";
13927
14600
  function useStreamingAccumulator() {
13928
14601
  const [status, setStatus] = useState5("idle");
13929
14602
  const [streamingText, setStreamingText] = useState5("");
13930
- const start = useCallback3(() => {
14603
+ const appendCountRef = useRef4(0);
14604
+ const pendingBufferRef = useRef4("");
14605
+ const flushScheduledRef = useRef4(false);
14606
+ const flushBuffer = useCallback3(() => {
14607
+ flushScheduledRef.current = false;
14608
+ const buf = pendingBufferRef.current;
14609
+ if (buf.length === 0)
14610
+ return;
14611
+ pendingBufferRef.current = "";
14612
+ setStreamingText((prev) => prev + buf);
14613
+ }, []);
14614
+ const lastStatusRef = useRef4("idle");
14615
+ const startImpl = useCallback3(() => {
13931
14616
  setStreamingText("");
13932
14617
  setStatus("thinking");
14618
+ lastStatusRef.current = "thinking";
14619
+ appendCountRef.current = 0;
13933
14620
  }, []);
13934
- const append = useCallback3((chunk) => {
13935
- setStatus("streaming");
13936
- setStreamingText((prev) => prev + chunk);
13937
- }, []);
13938
- const finish = useCallback3(() => {
13939
- setStatus("idle");
14621
+ const appendImpl = useCallback3((chunk) => {
14622
+ pendingBufferRef.current += chunk;
14623
+ if (!flushScheduledRef.current) {
14624
+ flushScheduledRef.current = true;
14625
+ queueMicrotask(flushBuffer);
14626
+ }
14627
+ if (lastStatusRef.current !== "streaming") {
14628
+ setStatus("streaming");
14629
+ lastStatusRef.current = "streaming";
14630
+ }
14631
+ appendCountRef.current += 1;
14632
+ }, [flushBuffer]);
14633
+ const finishImpl = useCallback3(() => {
14634
+ if (pendingBufferRef.current.length > 0) {
14635
+ flushBuffer();
14636
+ }
13940
14637
  let snapshot = "";
13941
14638
  setStreamingText((prev) => {
13942
14639
  snapshot = prev;
13943
14640
  return "";
13944
14641
  });
13945
- return snapshot;
13946
- }, []);
13947
- const fail = useCallback3((_err) => {
13948
14642
  setStatus("idle");
14643
+ lastStatusRef.current = "idle";
14644
+ return snapshot;
14645
+ }, [flushBuffer]);
14646
+ const failImpl = useCallback3((_err) => {
14647
+ if (pendingBufferRef.current.length > 0) {
14648
+ flushBuffer();
14649
+ }
13949
14650
  let snapshot = "";
13950
14651
  setStreamingText((prev) => {
13951
14652
  snapshot = prev;
13952
14653
  return "";
13953
14654
  });
14655
+ setStatus("idle");
14656
+ lastStatusRef.current = "idle";
13954
14657
  return snapshot;
13955
- }, []);
14658
+ }, [flushBuffer]);
14659
+ const start = wrapFunction5(startImpl, "streaming.start", {
14660
+ recordParams: false,
14661
+ recordResult: false,
14662
+ log: true
14663
+ });
14664
+ const append = wrapFunction5(appendImpl, "streaming.append", {
14665
+ recordParams: true,
14666
+ recordResult: false,
14667
+ log: true,
14668
+ paramFilter: (args) => ({
14669
+ "chunk.length": typeof args[0] === "string" ? args[0].length : 0,
14670
+ "chunk.head": typeof args[0] === "string" ? args[0].slice(0, 32) : "",
14671
+ "chunk.tail": typeof args[0] === "string" ? args[0].slice(-32) : ""
14672
+ })
14673
+ });
14674
+ const finish = wrapFunction5(finishImpl, "streaming.finish", {
14675
+ recordParams: false,
14676
+ recordResult: true,
14677
+ log: true,
14678
+ resultFilter: (result) => ({
14679
+ "snapshot.length": typeof result === "string" ? result.length : 0
14680
+ })
14681
+ });
14682
+ const fail = wrapFunction5(failImpl, "streaming.fail", {
14683
+ recordParams: true,
14684
+ recordResult: false,
14685
+ log: true,
14686
+ paramFilter: (args) => ({
14687
+ "err.message": args[0] instanceof Error ? args[0].message : String(args[0])
14688
+ })
14689
+ });
13956
14690
  return { status, streamingText, start, append, finish, fail };
13957
14691
  }
13958
14692
 
13959
- // src/RunTui.js
14693
+ // src/RunTui.tsx
13960
14694
  init_markdown();
13961
14695
 
13962
- // src/slash.js
14696
+ // src/slash.ts
13963
14697
  var CLEAR_SENTINEL = "__CLEAR__";
13964
14698
  function dispatchSlashCommand(raw, ctx) {
13965
14699
  const text = raw.trim();
@@ -14031,9 +14765,19 @@ function dispatchSlashCommand(raw, ctx) {
14031
14765
  }
14032
14766
  }
14033
14767
 
14034
- // src/RunTui.js
14035
- import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
14036
- var RunScreen = ({ handleQuery, streamHandleQuery, model, workdir, maxLines: initialMaxLines, markdownEnabled: markdownEnabled2, onExit, onRegisterHandlers }) => {
14768
+ // src/RunTui.tsx
14769
+ import { wrapFunction as wrapFunction6 } from "@ai-setting/roy-agent-core";
14770
+ import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
14771
+ var RunScreen = ({
14772
+ handleQuery,
14773
+ streamHandleQuery,
14774
+ model,
14775
+ workdir,
14776
+ maxLines: initialMaxLines,
14777
+ markdownEnabled: markdownEnabled2,
14778
+ onExit,
14779
+ onRegisterHandlers
14780
+ }) => {
14037
14781
  const [history, setHistory] = useState6([]);
14038
14782
  const [errorMessage, setErrorMessage] = useState6(null);
14039
14783
  const [maxLines, setMaxLines] = useState6(initialMaxLines);
@@ -14041,17 +14785,17 @@ var RunScreen = ({ handleQuery, streamHandleQuery, model, workdir, maxLines: ini
14041
14785
  const stream = useStreamingAccumulator();
14042
14786
  const status = stream.status;
14043
14787
  const { exit } = useApp2();
14044
- const userTurnCountRef = useRef2(0);
14045
- const assistantTurnCountRef = useRef2(0);
14046
- const isProcessingRef = useRef2(0);
14047
- const executeQueryRef = useRef2(null);
14048
- const historyIdRef = useRef2(0);
14788
+ const userTurnCountRef = useRef5(0);
14789
+ const assistantTurnCountRef = useRef5(0);
14790
+ const isProcessingRef = useRef5(0);
14791
+ const executeQueryRef = useRef5(null);
14792
+ const historyIdRef = useRef5(0);
14049
14793
  const width = process.stdout.columns ?? 80;
14050
14794
  const doExit = useCallback4(() => {
14051
14795
  onExit?.();
14052
14796
  exit();
14053
14797
  }, [onExit, exit]);
14054
- const executeQuery = useCallback4(async (message) => {
14798
+ const executeQueryImpl = useCallback4(async (message) => {
14055
14799
  isProcessingRef.current += 1;
14056
14800
  stream.start();
14057
14801
  try {
@@ -14083,1234 +14827,232 @@ var RunScreen = ({ handleQuery, streamHandleQuery, model, workdir, maxLines: ini
14083
14827
  isProcessingRef.current -= 1;
14084
14828
  }
14085
14829
  }, [handleQuery, markdownEnabled2, maxLines, stream, streamHandleQuery, width]);
14086
- useEffect5(() => {
14830
+ const executeQuery = useMemo3(() => wrapFunction6(executeQueryImpl, "tui.run-tui.executeQuery", {
14831
+ recordParams: true,
14832
+ recordResult: false,
14833
+ log: true,
14834
+ paramFilter: (args) => ({
14835
+ "message.length": typeof args[0] === "string" ? args[0].length : 0,
14836
+ "message.head": typeof args[0] === "string" ? args[0].slice(0, 60) : "",
14837
+ "isProcessingRef.before": (isProcessingRef.current ?? 0) + 1,
14838
+ streaming: !!streamHandleQuery
14839
+ })
14840
+ }), [executeQueryImpl, streamHandleQuery]);
14841
+ useEffect7(() => {
14087
14842
  executeQueryRef.current = executeQuery;
14088
14843
  }, [executeQuery]);
14089
- useEffect5(() => {
14844
+ useEffect7(() => {
14090
14845
  if (!onRegisterHandlers)
14091
14846
  return;
14092
- const handleNotification = async (message, _envEvent) => {
14847
+ const handleNotificationImpl = async (message, _envEvent) => {
14093
14848
  const notifId = `h${++historyIdRef.current}`;
14094
- setHistory((h) => [
14095
- ...h,
14096
- { role: "tool", content: `\uD83D\uDCE2 ${message}`, id: notifId }
14097
- ]);
14098
- if (executeQueryRef.current) {
14099
- await executeQueryRef.current(message);
14100
- }
14101
- };
14102
- const isIdle = () => {
14103
- return isProcessingRef.current === 0;
14104
- };
14105
- onRegisterHandlers({ onNotification: handleNotification, isIdle });
14106
- }, [onRegisterHandlers]);
14107
- const handleSubmit = useCallback4(async (raw) => {
14108
- const trimmed = raw.trim();
14109
- if (!trimmed)
14110
- return;
14111
- const slashCtx = {
14112
- model,
14113
- workdir,
14114
- maxLines,
14115
- userTurnCount: userTurnCountRef.current,
14116
- assistantTurnCount: assistantTurnCountRef.current
14117
- };
14118
- const result = dispatchSlashCommand(trimmed, slashCtx);
14119
- if (result.kind === "exit") {
14120
- const userId2 = `h${++historyIdRef.current}`;
14121
- const toolId = `h${++historyIdRef.current}`;
14122
- setHistory((h) => [
14123
- ...h,
14124
- { role: "user", content: trimmed, id: userId2 },
14125
- { role: "tool", content: "\uD83D\uDC4B Goodbye!", id: toolId }
14126
- ]);
14127
- doExit();
14128
- return;
14129
- }
14130
- if (result.kind === "handled") {
14131
- if (result.message === CLEAR_SENTINEL) {
14132
- setHistory([]);
14133
- setUserHistory([]);
14134
- userTurnCountRef.current = 0;
14135
- assistantTurnCountRef.current = 0;
14136
- setErrorMessage(null);
14137
- return;
14138
- }
14139
- const userId2 = `h${++historyIdRef.current}`;
14140
- const toolId = `h${++historyIdRef.current}`;
14141
- setHistory((h) => [
14142
- ...h,
14143
- { role: "user", content: trimmed, id: userId2 },
14144
- { role: "tool", content: result.message, id: toolId }
14145
- ]);
14146
- return;
14147
- }
14148
- if (result.kind === "unknown") {
14149
- const userId2 = `h${++historyIdRef.current}`;
14150
- const toolId = `h${++historyIdRef.current}`;
14151
- setHistory((h) => [
14152
- ...h,
14153
- { role: "user", content: trimmed, id: userId2 },
14154
- { role: "tool", content: `⚠ ${result.message}`, id: toolId }
14155
- ]);
14156
- return;
14157
- }
14158
- if (result.kind === "set-max-lines") {
14159
- setMaxLines(result.value);
14160
- const userId2 = `h${++historyIdRef.current}`;
14161
- const toolId = `h${++historyIdRef.current}`;
14162
- setHistory((h) => [
14163
- ...h,
14164
- { role: "user", content: trimmed, id: userId2 },
14165
- {
14166
- role: "tool",
14167
- content: `max-lines set to ${result.value}`,
14168
- id: toolId
14169
- }
14170
- ]);
14171
- return;
14172
- }
14173
- setErrorMessage(null);
14174
- const userId = `h${++historyIdRef.current}`;
14175
- setHistory((h) => [
14176
- ...h,
14177
- { role: "user", content: trimmed, id: userId }
14178
- ]);
14179
- setUserHistory((uh) => [trimmed, ...uh]);
14180
- userTurnCountRef.current += 1;
14181
- await executeQuery(trimmed);
14182
- }, [
14183
- doExit,
14184
- exit,
14185
- executeQuery,
14186
- maxLines,
14187
- model,
14188
- workdir
14189
- ]);
14190
- const handleCancel = useCallback4(() => {
14191
- doExit();
14192
- }, [doExit]);
14193
- return /* @__PURE__ */ jsxDEV8(Box6, {
14194
- flexDirection: "column",
14195
- children: [
14196
- /* @__PURE__ */ jsxDEV8(App, {
14197
- history,
14198
- status,
14199
- model,
14200
- workdir,
14201
- streamingText: stream.streamingText
14202
- }, undefined, false, undefined, this),
14203
- status === "idle" ? /* @__PURE__ */ jsxDEV8(Box6, {
14204
- marginTop: 1,
14205
- children: /* @__PURE__ */ jsxDEV8(TextInput, {
14206
- label: "You",
14207
- prefix: "\uD83D\uDC64",
14208
- placeholder: 'Type a message, "/help", or "exit"',
14209
- onSubmit: handleSubmit,
14210
- onCancel: handleCancel,
14211
- history: userHistory
14212
- }, undefined, false, undefined, this)
14213
- }, undefined, false, undefined, this) : null,
14214
- errorMessage ? /* @__PURE__ */ jsxDEV8(Box6, {
14215
- marginTop: 1,
14216
- children: /* @__PURE__ */ jsxDEV8(Text8, {
14217
- color: "red",
14218
- children: [
14219
- "⚠ ",
14220
- errorMessage
14221
- ]
14222
- }, undefined, true, undefined, this)
14223
- }, undefined, false, undefined, this) : null
14224
- ]
14225
- }, undefined, true, undefined, this);
14226
- };
14227
- var RunTui_default = RunScreen;
14228
-
14229
- // src/commands/run.ts
14230
- init_markdown();
14231
-
14232
- // src/commands/shared/session-manager.js
14233
- import { parseImageInput as parseImageInput3 } from "@ai-setting/roy-agent-core";
14234
-
14235
- class SessionManager2 {
14236
- sessionComponent;
14237
- output;
14238
- quiet;
14239
- attachedImagesMap = new Map;
14240
- constructor(options) {
14241
- this.sessionComponent = options.sessionComponent;
14242
- this.output = options.output;
14243
- this.quiet = options.quiet;
14244
- }
14245
- async init(sessionId, isContinue) {
14246
- let targetSessionId = sessionId;
14247
- let isNewSession = false;
14248
- if (isContinue && !targetSessionId) {
14249
- const activeSession = await this.sessionComponent.getActiveSession();
14250
- if (activeSession) {
14251
- targetSessionId = activeSession.id;
14252
- if (!this.quiet) {
14253
- this.output.info(`继续会话: ${activeSession.title} (${targetSessionId})`);
14254
- }
14255
- } else {
14256
- this.output.warn("没有找到上次会话,将创建新会话");
14257
- }
14258
- }
14259
- if (targetSessionId) {
14260
- await this.sessionComponent.setActiveSession(targetSessionId);
14261
- const session2 = await this.sessionComponent.get(targetSessionId);
14262
- if (session2) {
14263
- if (!this.quiet) {
14264
- this.output.info(`会话: ${session2.title} (${targetSessionId})`);
14265
- }
14266
- } else {
14267
- this.output.warn(`会话不存在: ${targetSessionId},将创建新会话`);
14268
- targetSessionId = undefined;
14269
- }
14270
- }
14271
- if (!targetSessionId) {
14272
- const newSession = await this.sessionComponent.create({
14273
- title: `Session - ${new Date().toLocaleString("zh-CN")}`
14274
- });
14275
- targetSessionId = newSession.id;
14276
- isNewSession = true;
14277
- await this.sessionComponent.setActiveSession(targetSessionId);
14278
- if (!this.quiet) {
14279
- this.output.info(`创建新会话: ${newSession.title} (${targetSessionId})`);
14280
- }
14281
- }
14282
- this.clearAttachments();
14283
- const session = await this.sessionComponent.get(targetSessionId);
14284
- return {
14285
- sessionId: targetSessionId,
14286
- isNewSession,
14287
- sessionTitle: session?.title || "Unknown"
14288
- };
14289
- }
14290
- async switchSession(sessionId) {
14291
- return this.init(sessionId, false);
14292
- }
14293
- async getCurrentSession() {
14294
- return this.sessionComponent.getActiveSession();
14295
- }
14296
- async attachImage(rawPath) {
14297
- const normalized = rawPath.trim();
14298
- if (!normalized) {
14299
- throw new Error("attachImage: empty path");
14300
- }
14301
- const existing = this.attachedImagesMap.get(normalized);
14302
- if (existing) {
14303
- return existing;
14304
- }
14305
- const part = await parseImageInput3(normalized);
14306
- this.attachedImagesMap.set(normalized, part);
14307
- return part;
14308
- }
14309
- listAttachments() {
14310
- return Array.from(this.attachedImagesMap.values());
14311
- }
14312
- clearAttachments() {
14313
- this.attachedImagesMap.clear();
14314
- }
14315
- async getQueryPayload(text) {
14316
- if (this.attachedImagesMap.size === 0) {
14317
- return text;
14318
- }
14319
- return [
14320
- { type: "text", text },
14321
- ...this.listAttachments()
14322
- ];
14323
- }
14324
- }
14325
-
14326
- // src/commands/shared/query-executor.js
14327
- init_stream_output_service();
14328
- import { ContextError as ContextError4, ErrorCodes as ErrorCodes4, TracedAs as TracedAs7 } from "@ai-setting/roy-agent-core";
14329
- var __decorate = function(decorators, target, key, desc) {
14330
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
14331
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
14332
- r = Reflect.decorate(decorators, target, key, desc);
14333
- else
14334
- for (var i = decorators.length - 1;i >= 0; i--)
14335
- if (d = decorators[i])
14336
- r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14337
- return c > 3 && r && Object.defineProperty(target, key, r), r;
14338
- };
14339
-
14340
- class QueryExecutor2 {
14341
- env;
14342
- sessionComponent;
14343
- output;
14344
- quiet;
14345
- silent = false;
14346
- streamService = null;
14347
- unsubscribe = null;
14348
- streamOptions = {
14349
- showReasoning: true,
14350
- showToolCalls: true,
14351
- showToolResults: false
14352
- };
14353
- _pendingContextConfig = null;
14354
- _pendingChunkCallback = undefined;
14355
- constructor(options) {
14356
- this.env = options.env;
14357
- this.sessionComponent = options.sessionComponent;
14358
- this.output = options.output;
14359
- this.quiet = options.quiet;
14360
- this.silent = options.silent ?? false;
14361
- }
14362
- initSummaryAgent(llmComponent, promptComponent) {
14363
- const session = this.sessionComponent;
14364
- if (typeof session.setSummaryComponents === "function") {
14365
- session.setSummaryComponents(promptComponent, llmComponent);
14366
- }
14367
- }
14368
- initStreamOutput(llmComponent, providerId = "minimax") {
14369
- if (llmComponent) {
14370
- const contextConfig = llmComponent.getContextThresholdConfig(providerId);
14371
- this._pendingContextConfig = contextConfig;
14372
- }
14373
- }
14374
- subscribeToEvents(options) {
14375
- this.streamOptions = options;
14376
- if (this.streamService) {
14377
- this.streamService.setOptions(options);
14378
- }
14379
- if (this.unsubscribe) {
14380
- return;
14381
- }
14382
- this.streamService = new StreamOutputService({
14383
- ...options,
14384
- silent: this.silent ?? false
14385
- });
14386
- if (this._pendingChunkCallback !== undefined) {
14387
- this.streamService.setChunkCallback(this._pendingChunkCallback);
14388
- this._pendingChunkCallback = undefined;
14389
- }
14390
- if (this._pendingContextConfig) {
14391
- this.streamService.setContextInfo(this._pendingContextConfig.contextWindow, this._pendingContextConfig.contextWindow * this._pendingContextConfig.thresholdRatio);
14392
- this._pendingContextConfig = null;
14393
- }
14394
- this.unsubscribe = this.env.subscribeTo([
14395
- "llm.start",
14396
- "llm.text",
14397
- "llm.reasoning",
14398
- "llm.completed",
14399
- "llm.error",
14400
- "tool.call",
14401
- "tool.result",
14402
- "tool.error",
14403
- "context.threshold_exceeded",
14404
- "context.compacting",
14405
- "context.compacted"
14406
- ], (event) => this.handleEvent(event));
14407
- }
14408
- setChunkCallback(cb) {
14409
- if (this.streamService) {
14410
- this.streamService.setChunkCallback(cb);
14411
- } else {
14412
- this._pendingChunkCallback = cb;
14413
- }
14414
- }
14415
- handleEvent(event) {
14416
- if (event.type === "context.threshold_exceeded" && !this.quiet) {
14417
- const payload = event.payload;
14418
- this.output.warn(`⚙ 上下文阈值 (${payload.totalTokens}/${payload.contextWindow})`);
14419
- }
14420
- if (event.type === "context.compacting" && !this.quiet) {
14421
- this.output.info("⚙ 压缩中...");
14422
- }
14423
- if (event.type === "context.compacted" && !this.quiet) {
14424
- this.output.success(`✓ 已压缩 (${event.payload.checkpointId})`);
14425
- }
14426
- this.streamService?.handleEvent(event);
14427
- }
14428
- async execute(message, sessionId, streamOptions, traceId, agentContext) {
14429
- const options = {
14430
- showReasoning: streamOptions?.showReasoning ?? this.streamOptions.showReasoning,
14431
- showToolCalls: streamOptions?.showToolCalls ?? this.streamOptions.showToolCalls,
14432
- showToolResults: streamOptions?.showToolResults ?? this.streamOptions.showToolResults
14433
- };
14434
- this.subscribeToEvents(options);
14435
- this.streamService?.reset();
14436
- if (!this.quiet) {
14437
- this.output.info(`执行: ${message}`);
14438
- }
14439
- const contextHandler = new ContextHandlerService(this.env, this.sessionComponent, { maxRetries: 1, autoCompact: true });
14440
- const { systemPrompt: agentContextSystemPrompt, eventSourceSystemPrompt: agentContextPreloadedPrompts, ...restAgentContext } = agentContext ?? {};
14441
- let eventSourceFinalPrompt;
14442
- if (typeof agentContextSystemPrompt === "string" && agentContextSystemPrompt.length > 0) {
14443
- eventSourceFinalPrompt = agentContextSystemPrompt;
14444
- } else if (typeof agentContextPreloadedPrompts === "string" && agentContextPreloadedPrompts.length > 0) {
14445
- eventSourceFinalPrompt = agentContextPreloadedPrompts;
14446
- }
14447
- const context = {
14448
- sessionId,
14449
- metadata: {
14450
- originalQuery: message,
14451
- traceId,
14452
- systemPrompt: eventSourceFinalPrompt
14453
- },
14454
- ...restAgentContext
14455
- };
14456
- let result;
14457
- try {
14458
- result = await contextHandler.handleQueryWithContext(message, context);
14459
- } catch (error) {
14460
- if (error instanceof ContextError4 && error.code === ErrorCodes4.CONTEXT_THRESHOLD_EXCEEDED) {
14461
- this.output.error(`上下文阈值超出限制: ${error.usage?.totalTokens}/${error.contextWindow}`);
14462
- this.output.info("请手动压缩会话: roy-agent sessions compact " + sessionId);
14463
- }
14464
- throw error;
14465
- }
14466
- if (!this.quiet) {
14467
- this.output.success("执行完成");
14468
- }
14469
- return result;
14470
- }
14471
- dispose() {
14472
- if (this.unsubscribe) {
14473
- this.unsubscribe();
14474
- this.unsubscribe = null;
14475
- }
14476
- }
14477
- getFullText() {
14478
- return this.streamService?.getFullText() ?? "";
14479
- }
14480
- getLastUsage() {
14481
- return this.streamService?.getUsageInfo() ?? null;
14482
- }
14483
- resetStream() {
14484
- this.streamService?.reset();
14485
- }
14486
- async compact(sessionId) {
14487
- try {
14488
- const envCore = this.env.getComponent("core");
14489
- if (envCore?.pushEnvEvent) {
14490
- envCore.pushEnvEvent({
14491
- type: "context.compacting",
14492
- metadata: { sessionId },
14493
- payload: {}
14494
- });
14495
- }
14496
- const result = await this.sessionComponent.compact(sessionId, {
14497
- summary: "Manual compact from interactive mode"
14498
- });
14499
- if (envCore?.pushEnvEvent) {
14500
- envCore.pushEnvEvent({
14501
- type: "context.compacted",
14502
- metadata: { sessionId },
14503
- payload: {
14504
- checkpointId: result.checkpoint.id,
14505
- messagesCompacted: result.deletedMessageCount
14506
- }
14507
- });
14508
- }
14509
- return {
14510
- success: true,
14511
- checkpoint: result.checkpoint,
14512
- deletedMessageCount: result.deletedMessageCount
14513
- };
14514
- } catch (error) {
14515
- const errorMessage = error instanceof Error ? error.message : String(error);
14516
- this.output.error(`压缩失败: ${errorMessage}`);
14517
- return {
14518
- success: false,
14519
- error: errorMessage
14520
- };
14521
- }
14522
- }
14523
- }
14524
- __decorate([
14525
- TracedAs7("cli.query-executor.execute", { recordParams: true, log: true })
14526
- ], QueryExecutor2.prototype, "execute", null);
14527
-
14528
- // src/commands/interactive-event-sources.js
14529
- import { TracedAs as TracedAs8 } from "@ai-setting/roy-agent-core";
14530
- var __decorate2 = function(decorators, target, key, desc) {
14531
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
14532
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
14533
- r = Reflect.decorate(decorators, target, key, desc);
14534
- else
14535
- for (var i = decorators.length - 1;i >= 0; i--)
14536
- if (d = decorators[i])
14537
- r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14538
- return c > 3 && r && Object.defineProperty(target, key, r), r;
14539
- };
14540
- async function startSingleEventSource2(eventSourceComponent, output, eventSourceId) {
14541
- return EventSourceStarter2.instance.runSingle(eventSourceComponent, output, eventSourceId);
14542
- }
14543
- async function startEventSources2(eventSourceIds, eventSourceComponent, output) {
14544
- return EventSourceStarter2.instance.run(eventSourceIds, eventSourceComponent, output);
14545
- }
14546
-
14547
- class EventSourceStarter2 {
14548
- static instance = new EventSourceStarter2;
14549
- async run(eventSourceIds, eventSourceComponent, output) {
14550
- return startEventSourcesImpl2(eventSourceIds, eventSourceComponent, output);
14551
- }
14552
- async runSingle(eventSourceComponent, output, eventSourceId) {
14553
- return startSingleEventSourceImpl2(eventSourceComponent, output, eventSourceId);
14554
- }
14555
- }
14556
- __decorate2([
14557
- TracedAs8("interactive.startEventSources", { recordParams: false, log: false })
14558
- ], EventSourceStarter2.prototype, "run", null);
14559
- __decorate2([
14560
- TracedAs8("interactive.startSingleEventSource", { recordParams: false, log: false })
14561
- ], EventSourceStarter2.prototype, "runSingle", null);
14562
- async function startEventSourcesImpl2(eventSourceIds, eventSourceComponent, output) {
14563
- const results = [];
14564
- if (!eventSourceIds || eventSourceIds.length === 0) {
14565
- return { results, total: 0, successCount: 0, failedCount: 0 };
14566
- }
14567
- for (const id of eventSourceIds) {
14568
- if (!id)
14569
- continue;
14570
- const result = await startSingleEventSource2(eventSourceComponent, output, id);
14571
- results.push(result);
14572
- }
14573
- const successCount = results.filter((r) => r.success).length;
14574
- const failedCount = results.length - successCount;
14575
- if (results.length > 1) {
14576
- if (failedCount > 0) {
14577
- output.info(`
14578
- ✅ 成功启动 ${successCount}/${results.length} 个事件源`);
14579
- } else {
14580
- output.success(`
14581
- ✅ 成功启动 ${successCount}/${results.length} 个事件源`);
14582
- }
14583
- }
14584
- return { results, total: results.length, successCount, failedCount };
14585
- }
14586
- async function startSingleEventSourceImpl2(eventSourceComponent, output, eventSourceId) {
14587
- const sources = eventSourceComponent.list();
14588
- const matchedSource = sources.find((s) => s.id === eventSourceId || s.id.startsWith(eventSourceId));
14589
- if (!matchedSource) {
14590
- output.error(`❌ 事件源不存在: ${eventSourceId}`);
14591
- output.info(`可用的事件源:`);
14592
- for (const s of sources) {
14593
- output.info(` - ${s.id.substring(0, 8)}: ${s.name} (${s.type})`);
14594
- }
14595
- return {
14596
- id: eventSourceId,
14597
- name: eventSourceId,
14598
- success: false,
14599
- status: "not_found",
14600
- error: `EventSource not found: ${eventSourceId}`
14601
- };
14602
- }
14603
- const actualId = matchedSource.id;
14604
- const status = eventSourceComponent.getStatus(actualId);
14605
- if (status === "running") {
14606
- output.info(`\uD83D\uDCE1 事件源 ${matchedSource.name} 已在运行中`);
14607
- return {
14608
- id: actualId,
14609
- name: matchedSource.name,
14610
- success: true,
14611
- status: "skipped"
14612
- };
14613
- }
14614
- try {
14615
- await eventSourceComponent.startSource(actualId);
14616
- const verifyStatus = eventSourceComponent.getStatus(actualId);
14617
- if (verifyStatus !== "running") {
14618
- const errMsg = `启动后状态异常: ${verifyStatus}`;
14619
- output.error(`❌ ${errMsg}`);
14620
- return {
14621
- id: actualId,
14622
- name: matchedSource.name,
14623
- success: false,
14624
- status: "failed",
14625
- error: errMsg
14626
- };
14627
- }
14628
- output.success(`\uD83D\uDCE1 已启动事件源: ${matchedSource.name} (${verifyStatus})`);
14629
- return {
14630
- id: actualId,
14631
- name: matchedSource.name,
14632
- success: true,
14633
- status: "started"
14634
- };
14635
- } catch (error) {
14636
- const errMsg = error instanceof Error ? error.message : String(error);
14637
- output.error(`❌ 启动事件源失败: ${matchedSource.name} - ${errMsg}`);
14638
- return {
14639
- id: actualId,
14640
- name: matchedSource.name,
14641
- success: false,
14642
- status: "failed",
14643
- error: errMsg
14644
- };
14645
- }
14646
- }
14647
-
14648
- // src/commands/collect-event-source-system-prompts.js
14649
- import { resolveBountyIMSystemPrompt as resolveBountyIMSystemPrompt2 } from "@ai-setting/roy-agent-core";
14650
- function resolveSystemPromptForSource2(config) {
14651
- if (config.type === "bounty-im") {
14652
- const imServerUrl = config.imServerUrl || config.options && config.options.imServerUrl;
14653
- const address = config.address || config.options && config.options.address || "unknown";
14654
- return resolveBountyIMSystemPrompt2({
14655
- configSystemPrompt: config.systemPrompt,
14656
- currentAddress: address,
14657
- imServerUrl
14658
- });
14659
- }
14660
- return config.systemPrompt;
14661
- }
14662
- function collectEventSourceSystemPrompts2(eventSourceIds, eventSourceComponent) {
14663
- const result = [];
14664
- for (const id of eventSourceIds) {
14665
- const config = eventSourceComponent.get(id);
14666
- if (!config)
14667
- continue;
14668
- const prompt = resolveSystemPromptForSource2(config);
14669
- if (!prompt)
14670
- continue;
14671
- result.push({ id, type: config.type, prompt });
14672
- }
14673
- return result;
14674
- }
14675
- function joinResolvedSystemPrompts2(prompts) {
14676
- return prompts.map((p) => p.prompt).join(`
14677
-
14678
- ---
14679
-
14680
- `);
14681
- }
14682
-
14683
- // src/commands/act-agent-validation.js
14684
- function validateActAgent2(agentComponent, agentName) {
14685
- if (!agentName || agentName === "default") {
14686
- return { valid: true };
14687
- }
14688
- if (!agentComponent?.getAgent(agentName)) {
14689
- return {
14690
- valid: false,
14691
- message: `Agent "${agentName}" 不存在`
14692
- };
14693
- }
14694
- return { valid: true };
14695
- }
14696
- function buildActAgentContext2(agentName) {
14697
- if (!agentName || agentName === "default") {
14698
- return;
14699
- }
14700
- return { agentType: agentName };
14701
- }
14702
-
14703
- // src/commands/shared/event-handler.js
14704
- import { TracedAs as TracedAs9 } from "@ai-setting/roy-agent-core";
14705
- var __decorate3 = function(decorators, target, key, desc) {
14706
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
14707
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
14708
- r = Reflect.decorate(decorators, target, key, desc);
14709
- else
14710
- for (var i = decorators.length - 1;i >= 0; i--)
14711
- if (d = decorators[i])
14712
- r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14713
- return c > 3 && r && Object.defineProperty(target, key, r), r;
14714
- };
14715
-
14716
- class EventHandler2 {
14717
- env;
14718
- eventTypes;
14719
- onEvent;
14720
- onEventWithEnv;
14721
- formatter;
14722
- isIdle;
14723
- idleCheckInterval;
14724
- queue = [];
14725
- isProcessing = false;
14726
- isStopped = false;
14727
- unsubscribe = null;
14728
- sessionComponent = null;
14729
- activeEventSessionId = null;
14730
- constructor(options) {
14731
- this.env = options.env;
14732
- this.eventTypes = options.eventTypes;
14733
- this.onEvent = options.onEvent;
14734
- this.onEventWithEnv = options.onEventWithEnv;
14735
- this.formatter = options.formatter ?? new EventMessageFormatter;
14736
- this.isIdle = options.isIdle ?? (() => true);
14737
- this.idleCheckInterval = options.idleCheckInterval ?? 100;
14738
- this.sessionComponent = options.sessionComponent ?? null;
14739
- }
14740
- start() {
14741
- this.isStopped = false;
14742
- this.unsubscribe = this.env.subscribeAll((event) => {
14743
- if (this.matchesEventType(event.type)) {
14744
- this.handleEvent(event);
14745
- }
14746
- });
14747
- return () => this.stop();
14748
- }
14749
- matchesEventType(eventType) {
14750
- for (const pattern of this.eventTypes) {
14751
- if (this.matchPattern(eventType, pattern)) {
14752
- return true;
14753
- }
14754
- }
14755
- return false;
14756
- }
14757
- matchPattern(eventType, pattern) {
14758
- if (pattern === "*")
14759
- return true;
14760
- if (pattern.endsWith(".*")) {
14761
- const prefix = pattern.slice(0, -2);
14762
- return eventType === prefix || eventType.startsWith(prefix + ".");
14763
- }
14764
- return eventType === pattern;
14765
- }
14766
- stop() {
14767
- this.isStopped = true;
14768
- if (this.unsubscribe) {
14769
- this.unsubscribe();
14770
- this.unsubscribe = null;
14771
- }
14772
- this.queue = [];
14773
- this.isProcessing = false;
14774
- this.clearActiveSession();
14775
- }
14776
- handleEvent(event) {
14777
- if (this.isStopped) {
14778
- return;
14779
- }
14780
- const formatted = this.formatter.formatWithEvent(event);
14781
- this.enqueue(formatted);
14782
- }
14783
- enqueue(formattedEvent) {
14784
- if (this.isStopped) {
14785
- return;
14786
- }
14787
- this.queue.push(formattedEvent);
14788
- if (!this.isProcessing) {
14789
- this.processQueue();
14790
- }
14791
- }
14792
- getQueueLength() {
14793
- return this.queue.length;
14794
- }
14795
- isQueueEmpty() {
14796
- return this.queue.length === 0;
14797
- }
14798
- async processQueue() {
14799
- this.isProcessing = true;
14800
- const sessionId = await this.ensureActiveSession();
14801
- if (this.isStopped) {
14802
- this.clearActiveSession();
14803
- this.isProcessing = false;
14804
- return;
14805
- }
14806
- while (!this.isStopped && this.queue.length > 0) {
14807
- await this.waitForIdle();
14808
- if (this.isStopped) {
14809
- break;
14810
- }
14811
- const item = this.queue.shift();
14812
- if (!item) {
14813
- break;
14814
- }
14815
- if (sessionId) {
14816
- item.eventSessionId = sessionId;
14817
- }
14818
- try {
14819
- if (this.onEventWithEnv) {
14820
- await this.onEventWithEnv(item);
14821
- continue;
14822
- }
14823
- await this.onEvent(item.message);
14824
- } catch (error) {
14825
- console.error(`[EventHandler] 处理事件失败:`, error);
14826
- }
14827
- }
14828
- this.isProcessing = false;
14829
- }
14830
- async ensureActiveSession() {
14831
- if (!this.sessionComponent)
14832
- return null;
14833
- if (this.activeEventSessionId)
14834
- return this.activeEventSessionId;
14835
- const triggerSessionId = this.queue.map((item) => item.triggerSessionId).find((id) => !!id);
14836
- if (triggerSessionId) {
14837
- try {
14838
- const existing = await this.sessionComponent.get(triggerSessionId);
14839
- if (existing) {
14840
- if (this.isStopped) {
14841
- return null;
14842
- }
14843
- this.activeEventSessionId = existing.id;
14844
- await this.sessionComponent.setActiveSession(existing.id);
14845
- return existing.id;
14846
- }
14847
- console.warn(`[EventHandler] Parent session ${triggerSessionId} not found, trying global active session`);
14848
- } catch (error) {
14849
- console.error(`[EventHandler] Failed to lookup parent session ${triggerSessionId}:`, error);
14850
- }
14851
- }
14852
- try {
14853
- const activeId = this.sessionComponent.getActiveSessionId();
14854
- if (activeId) {
14855
- const existing = await this.sessionComponent.get(activeId);
14856
- if (existing) {
14857
- if (this.isStopped) {
14858
- return null;
14859
- }
14860
- this.activeEventSessionId = existing.id;
14861
- return existing.id;
14862
- }
14863
- }
14864
- } catch (error) {
14865
- console.error(`[EventHandler] Failed to lookup global active session:`, error);
14866
- }
14867
- return this.createNewEventSession();
14868
- }
14869
- async createNewEventSession() {
14870
- try {
14871
- const session = await this.sessionComponent.create({
14872
- title: `Event Session - ${new Date().toLocaleString()}`
14873
- });
14874
- if (this.isStopped) {
14875
- this.activeEventSessionId = null;
14876
- return null;
14877
- }
14878
- this.activeEventSessionId = session.id;
14879
- await this.sessionComponent.setActiveSession(session.id);
14880
- return session.id;
14881
- } catch (error) {
14882
- console.error(`[EventHandler] 创建事件 session 失败:`, error);
14883
- return null;
14884
- }
14885
- }
14886
- clearActiveSession() {
14887
- this.activeEventSessionId = null;
14888
- }
14889
- getActiveEventSessionId() {
14890
- return this.activeEventSessionId;
14891
- }
14892
- async waitForIdle() {
14893
- while (!this.isStopped && !this.isIdle()) {
14894
- await this.sleep(this.idleCheckInterval);
14895
- }
14896
- }
14897
- sleep(ms) {
14898
- return new Promise((resolve) => setTimeout(resolve, ms));
14899
- }
14900
- }
14901
- __decorate3([
14902
- TracedAs9("cli.event-handler.handleEvent", { recordParams: true })
14903
- ], EventHandler2.prototype, "handleEvent", null);
14904
-
14905
- // src/commands/shared/task-event-handler.js
14906
- import { createLogger as createLogger7 } from "@ai-setting/roy-agent-core";
14907
- var logger6 = createLogger7("task-event-handler");
14908
- var TASK_EVENTS2 = {
14909
- CREATED: "task.created",
14910
- UPDATED: "task.updated",
14911
- COMPLETED: "task.completed",
14912
- DELETED: "task.deleted",
14913
- OPERATION_ADDED: "task.operation_added",
14914
- DELEGATED: "task.delegated"
14915
- };
14916
-
14917
- class TaskEventHandler2 {
14918
- env;
14919
- enabled;
14920
- unsubscribe = null;
14921
- constructor(options) {
14922
- this.env = options.env;
14923
- this.enabled = options.enabled ?? true;
14924
- }
14925
- start() {
14926
- if (!this.enabled) {
14927
- return () => {};
14928
- }
14929
- this.unsubscribe = this.env.subscribeAll((event) => {
14930
- if (event.type.startsWith("task.")) {
14931
- this.handleEvent(event);
14932
- }
14933
- });
14934
- logger6.info("[TaskEventHandler] Started");
14935
- return () => this.stop();
14936
- }
14937
- stop() {
14938
- if (this.unsubscribe) {
14939
- this.unsubscribe();
14940
- this.unsubscribe = null;
14941
- logger6.info("[TaskEventHandler] Stopped");
14942
- }
14943
- }
14944
- handleEvent(event) {
14945
- const payload = event.payload;
14946
- switch (event.type) {
14947
- case TASK_EVENTS2.CREATED:
14948
- this.logTaskCreated(payload);
14949
- break;
14950
- case TASK_EVENTS2.UPDATED:
14951
- this.logTaskUpdated(payload);
14952
- break;
14953
- case TASK_EVENTS2.COMPLETED:
14954
- this.logTaskCompleted(payload);
14955
- break;
14956
- case TASK_EVENTS2.DELETED:
14957
- this.logTaskDeleted(payload);
14958
- break;
14959
- case TASK_EVENTS2.OPERATION_ADDED:
14960
- this.logOperationAdded(payload);
14961
- break;
14962
- case TASK_EVENTS2.DELEGATED:
14963
- this.logTaskDelegated(payload);
14964
- break;
14965
- default:
14966
- logger6.info(`[${event.type}]`, payload);
14967
- }
14968
- }
14969
- logTaskCreated(payload) {
14970
- const task = payload.task;
14971
- logger6.info(`\uD83D\uDCDD Task created: #${task.id} - ${task.title}`);
14972
- logger6.info(` Status: ${task.status}, Priority: ${task.priority}, Type: ${task.type || "normal"}`);
14973
- if (task.project_path) {
14974
- logger6.info(` Project: ${task.project_path}`);
14975
- }
14976
- if (task.context) {
14977
- logger6.info(` Context: ${task.context}`);
14978
- }
14979
- }
14980
- logTaskUpdated(payload) {
14981
- const task = payload.task;
14982
- const changes = payload.changes;
14983
- logger6.info(`✏️ Task updated: #${task.id} - ${task.title}`);
14984
- logger6.info(` Status: ${task.status}, Priority: ${task.priority}, Type: ${task.type || "normal"}, Progress: ${task.progress}%`);
14985
- if (changes) {
14986
- logger6.info(` Changes: ${JSON.stringify(changes)}`);
14987
- }
14988
- }
14989
- logTaskCompleted(payload) {
14990
- const task = payload.task;
14991
- logger6.info(`✅ Task completed: #${task.id} - ${task.title}`);
14992
- logger6.info(` Progress: ${task.progress}%, Updated: ${task.updatedAt}`);
14993
- }
14994
- logTaskDeleted(payload) {
14995
- logger6.info(`\uD83D\uDDD1️ Task deleted: #${payload.taskId}`);
14996
- }
14997
- logOperationAdded(payload) {
14998
- const op = payload.operation;
14999
- logger6.info(`\uD83D\uDCCB Operation added to task #${payload.taskId}:`);
15000
- logger6.info(` [${op.milestoneType}] ${op.milestoneTitle}`);
15001
- logger6.info(` Session: ${op.sessionId}`);
15002
- }
15003
- logTaskDelegated(payload) {
15004
- logger6.info(`\uD83D\uDE80 Task delegated: #${payload.taskId}`);
15005
- logger6.info(` Background: ${payload.backgroundTaskId}, Type: ${payload.subagentType}`);
15006
- logger6.info(` ${payload.description}`);
15007
- }
15008
- }
15009
-
15010
- // src/commands/shared/event-message-formatter.js
15011
- var TaskEventTypes2 = {
15012
- TASK_STARTED: "task.background.started",
15013
- TASK_PROGRESS: "task.background.progress",
15014
- TASK_COMPLETED: "task.background.completed",
15015
- TASK_FAILED: "task.background.failed",
15016
- TASK_TIMEOUT: "task.background.timeout",
15017
- TASK_STOPPED: "task.background.stopped",
15018
- TASK_ASK_USER: "task.background.ask_user"
15019
- };
15020
- var EventSourceEventTypes2 = {
15021
- EVENT_SOURCE_STARTED: "event-source.started",
15022
- EVENT_SOURCE_STOPPED: "event-source.stopped",
15023
- EVENT_SOURCE_EVENT_PREFIX: "event-source.event."
15024
- };
15025
-
15026
- class EventMessageFormatter2 {
15027
- prefix;
15028
- showTimestamp;
15029
- constructor(options = {}) {
15030
- this.prefix = options.prefix ?? "[通知]";
15031
- this.showTimestamp = options.showTimestamp ?? false;
15032
- }
15033
- format(event) {
15034
- const { type, payload } = event;
15035
- switch (type) {
15036
- case TaskEventTypes2.TASK_STARTED:
15037
- return this.formatTaskStarted(payload);
15038
- case TaskEventTypes2.TASK_PROGRESS:
15039
- return this.formatTaskProgress(payload);
15040
- case TaskEventTypes2.TASK_COMPLETED:
15041
- return this.formatTaskCompleted(payload);
15042
- case TaskEventTypes2.TASK_FAILED:
15043
- return this.formatTaskFailed(payload);
15044
- case TaskEventTypes2.TASK_TIMEOUT:
15045
- return this.formatTaskTimeout(payload);
15046
- case TaskEventTypes2.TASK_STOPPED:
15047
- return this.formatTaskStopped(payload);
15048
- case TaskEventTypes2.TASK_ASK_USER:
15049
- return this.formatTaskAskUser(payload);
15050
- case EventSourceEventTypes2.EVENT_SOURCE_STARTED:
15051
- return this.formatEventSourceStarted(payload);
15052
- case EventSourceEventTypes2.EVENT_SOURCE_STOPPED:
15053
- return this.formatEventSourceStopped(payload);
15054
- default:
15055
- if (type.startsWith(EventSourceEventTypes2.EVENT_SOURCE_EVENT_PREFIX)) {
15056
- return this.formatEventSourceEvent(event);
15057
- }
15058
- return this.formatGeneric(event);
15059
- }
15060
- }
15061
- formatTaskStarted(payload) {
15062
- const desc = payload.description || "未命名任务";
15063
- return `${this.prefix} \uD83D\uDCE2 后台任务「${desc}」已启动`;
15064
- }
15065
- formatTaskProgress(payload) {
15066
- const desc = payload.description || "未命名任务";
15067
- const message = payload.progressMessage || "";
15068
- const taskId = payload.associatedTaskId;
15069
- let result = `${this.prefix} \uD83D\uDD04 后台任务「${desc}」`;
15070
- if (taskId !== undefined) {
15071
- result += `[Task #${taskId}] `;
15072
- }
15073
- result += `还在进行中,请耐心等待。需查询具体进度可调用 task_get / task_operation_list 等工具`;
15074
- if (message)
15075
- result += ` - ${message}`;
15076
- return result;
15077
- }
15078
- formatTaskCompleted(payload) {
15079
- const desc = payload.description || "未命名任务";
15080
- const result = payload.result;
15081
- const time = payload.executionTimeMs ? `(${this.formatDuration(payload.executionTimeMs)})` : "";
15082
- const bgProcessId = payload.backgroundTaskId || "";
15083
- const taskId = payload.associatedTaskId;
15084
- let message = `${this.prefix} ✅ 后台任务「${desc}」已完成 ${time}`;
15085
- if (bgProcessId) {
15086
- message += `
15087
- bgprocess: ${bgProcessId}`;
15088
- }
15089
- if (taskId !== undefined) {
15090
- message += `
15091
- Task #${taskId}`;
15092
- }
15093
- if (result) {
15094
- message += `
15095
- 结果: ${result}`;
15096
- }
15097
- message += this.appendSubSessionId(payload);
15098
- return message;
15099
- }
15100
- formatTaskFailed(payload) {
15101
- const desc = payload.description || "未命名任务";
15102
- const error = payload.error || "未知错误";
15103
- const time = payload.executionTimeMs ? `(${this.formatDuration(payload.executionTimeMs)})` : "";
15104
- const bgProcessId = payload.backgroundTaskId || "";
15105
- const taskId = payload.associatedTaskId;
15106
- let message = `${this.prefix} ❌ 后台任务「${desc}」失败 ${time}`;
15107
- if (bgProcessId) {
15108
- message += `
15109
- bgprocess: ${bgProcessId}`;
15110
- }
15111
- if (taskId !== undefined) {
15112
- message += `
15113
- Task #${taskId}`;
15114
- }
15115
- if (error) {
15116
- const truncatedError = error.length > 100 ? error.substring(0, 100) + "..." : error;
15117
- message += `
15118
- 错误: ${truncatedError}`;
15119
- }
15120
- message += this.appendSubSessionId(payload);
15121
- return message;
15122
- }
15123
- formatTaskTimeout(payload) {
15124
- const desc = payload.description || "未命名任务";
15125
- const time = payload.executionTimeMs ? `(${this.formatDuration(payload.executionTimeMs)})` : "";
15126
- const bgProcessId = payload.backgroundTaskId || "";
15127
- const taskId = payload.associatedTaskId;
15128
- let message = `${this.prefix} ⏱️ 后台任务「${desc}」超时 ${time}`;
15129
- if (bgProcessId) {
15130
- message += `
15131
- bgprocess: ${bgProcessId}`;
15132
- }
15133
- if (taskId !== undefined) {
15134
- message += `
15135
- Task #${taskId}`;
15136
- }
15137
- message += this.appendSubSessionId(payload);
15138
- return message;
15139
- }
15140
- formatTaskStopped(payload) {
15141
- const desc = payload.description || "未命名任务";
15142
- const time = payload.executionTimeMs ? `(${this.formatDuration(payload.executionTimeMs)})` : "";
15143
- const bgProcessId = payload.backgroundTaskId || "";
15144
- const taskId = payload.associatedTaskId;
15145
- let message = `${this.prefix} \uD83D\uDED1 后台任务「${desc}」已停止 ${time}`;
15146
- if (bgProcessId) {
15147
- message += `
15148
- bgprocess: ${bgProcessId}`;
15149
- }
15150
- if (taskId !== undefined) {
15151
- message += `
15152
- Task #${taskId}`;
15153
- }
15154
- message += this.appendSubSessionId(payload);
15155
- return message;
15156
- }
15157
- formatTaskAskUser(payload) {
15158
- const desc = payload.description || "未命名任务";
15159
- const bgProcessId = payload.backgroundTaskId || "";
15160
- const subSessionId = payload.subSessionId || "";
15161
- const query = payload.query || "(空问题)";
15162
- let message = `${this.prefix} ❓ 后台子代理「${desc}」请求用户输入`;
15163
- if (bgProcessId) {
15164
- message += `
15165
- bgprocess: ${bgProcessId}`;
15166
- }
15167
- if (subSessionId) {
15168
- message += `
15169
- subSessionId: ${subSessionId}`;
15170
- }
15171
- message += `
15172
-
15173
- ${query}`;
15174
- if (payload.hints && payload.hints.length > 0) {
15175
- message += `
15176
-
15177
- [\uD83E\uDD16 Agent 操作提示]`;
15178
- for (const hint of payload.hints) {
15179
- message += `
15180
- ${hint}`;
15181
- }
15182
- }
15183
- return message;
15184
- }
15185
- appendSubSessionId(payload) {
15186
- if (payload.subSessionId) {
15187
- return `
15188
- subSessionId: ${payload.subSessionId}`;
15189
- }
15190
- return "";
15191
- }
15192
- formatGeneric(event) {
15193
- return `${this.prefix} 收到事件: ${event.type}`;
15194
- }
15195
- formatEventSourceStarted(payload) {
15196
- return `${this.prefix} \uD83D\uDCE1 事件源「${payload.sourceId}」(类型: ${payload.sourceType}) 已启动`;
15197
- }
15198
- formatEventSourceStopped(payload) {
15199
- return `${this.prefix} \uD83D\uDCE1 事件源「${payload.sourceId}」(类型: ${payload.sourceType}) 已停止`;
15200
- }
15201
- formatEventSourceEvent(event) {
15202
- const payload = event.payload;
15203
- const sourceType = payload?.sourceType || "unknown";
15204
- const message = payload?.message || "";
15205
- if (message) {
15206
- return `[${sourceType}] ${message}`;
15207
- }
15208
- return `[${sourceType}] ${JSON.stringify(payload, null, 2)}`;
15209
- }
15210
- formatDuration(ms) {
15211
- if (ms < 1000)
15212
- return `${ms}ms`;
15213
- if (ms < 60000)
15214
- return `${(ms / 1000).toFixed(1)}秒`;
15215
- const minutes = Math.floor(ms / 60000);
15216
- const seconds = Math.floor(ms % 60000 / 1000);
15217
- return `${minutes}分${seconds}秒`;
15218
- }
15219
- formatWithEvent(event) {
15220
- const triggerSessionId = extractTriggerSessionId2(event);
15221
- return {
15222
- message: this.format(event),
15223
- envEvent: event,
15224
- triggerSessionId
14849
+ setHistory((h) => [
14850
+ ...h,
14851
+ { role: "tool", content: `\uD83D\uDCE2 ${message}`, id: notifId }
14852
+ ]);
14853
+ if (executeQueryRef.current) {
14854
+ await executeQueryRef.current(message);
14855
+ }
15225
14856
  };
15226
- }
15227
- }
15228
- function extractTriggerSessionId2(event) {
15229
- const triggerSessionId = event?.metadata?.trigger_session_id;
15230
- if (typeof triggerSessionId === "string" && triggerSessionId.length > 0) {
15231
- return triggerSessionId;
15232
- }
15233
- return;
15234
- }
15235
-
15236
- // src/commands/lifecycle.js
15237
- var DEFAULT_LOGGER2 = {
15238
- warn: (msg) => console.error(`[shutdown] ${msg}`)
15239
- };
15240
- function registerShutdownHandlers2(cleanup, options = {}) {
15241
- const logger7 = options.logger ?? DEFAULT_LOGGER2;
15242
- const exitCode = options.exitCode ?? 0;
15243
- const shutdownMessage = options.shutdownMessage ?? "Cleaning up...";
15244
- let shuttingDown = false;
15245
- const shutdown = async (signal) => {
15246
- if (shuttingDown) {
14857
+ const handleNotification = wrapFunction6(handleNotificationImpl, "tui.run-tui.handleNotification", {
14858
+ recordParams: true,
14859
+ recordResult: false,
14860
+ log: true,
14861
+ paramFilter: (args) => ({
14862
+ "message.length": typeof args[0] === "string" ? args[0].length : 0,
14863
+ "message.head": typeof args[0] === "string" ? args[0].slice(0, 60) : "",
14864
+ isProcessingRef: isProcessingRef.current ?? 0
14865
+ })
14866
+ });
14867
+ const isIdle = () => {
14868
+ return isProcessingRef.current === 0;
14869
+ };
14870
+ const appendTraceId = (traceId) => {
14871
+ const traceIdItemId = `h${++historyIdRef.current}`;
14872
+ setHistory((h) => [
14873
+ ...h,
14874
+ { role: "tool", content: `\uD83D\uDD0D [Trace] ${traceId}`, id: traceIdItemId }
14875
+ ]);
14876
+ };
14877
+ onRegisterHandlers({
14878
+ onNotification: handleNotification,
14879
+ isIdle,
14880
+ appendTraceId
14881
+ });
14882
+ }, [onRegisterHandlers]);
14883
+ const handleSubmit = useCallback4(async (raw) => {
14884
+ const trimmed = raw.trim();
14885
+ if (!trimmed)
14886
+ return;
14887
+ const slashCtx = {
14888
+ model,
14889
+ workdir,
14890
+ maxLines,
14891
+ userTurnCount: userTurnCountRef.current,
14892
+ assistantTurnCount: assistantTurnCountRef.current
14893
+ };
14894
+ const result = dispatchSlashCommand(trimmed, slashCtx);
14895
+ if (result.kind === "exit") {
14896
+ const userId2 = `h${++historyIdRef.current}`;
14897
+ const toolId = `h${++historyIdRef.current}`;
14898
+ setHistory((h) => [
14899
+ ...h,
14900
+ { role: "user", content: trimmed, id: userId2 },
14901
+ { role: "tool", content: "\uD83D\uDC4B Goodbye!", id: toolId }
14902
+ ]);
14903
+ doExit();
15247
14904
  return;
15248
14905
  }
15249
- shuttingDown = true;
15250
- try {
15251
- logger7.debug?.(`[${signal}] ${shutdownMessage}`);
15252
- } catch {}
15253
- if (cleanup) {
15254
- try {
15255
- await cleanup();
15256
- } catch (err) {
15257
- const message = err instanceof Error ? err.message : String(err);
15258
- try {
15259
- logger7.warn(`Cleanup failed: ${message}`);
15260
- } catch {
15261
- try {
15262
- process.stderr.write(`[shutdown] Cleanup failed: ${message}
15263
- `);
15264
- } catch {}
15265
- }
14906
+ if (result.kind === "handled") {
14907
+ if (result.message === CLEAR_SENTINEL) {
14908
+ setHistory([]);
14909
+ setUserHistory([]);
14910
+ userTurnCountRef.current = 0;
14911
+ assistantTurnCountRef.current = 0;
14912
+ setErrorMessage(null);
14913
+ return;
15266
14914
  }
14915
+ const userId2 = `h${++historyIdRef.current}`;
14916
+ const toolId = `h${++historyIdRef.current}`;
14917
+ setHistory((h) => [
14918
+ ...h,
14919
+ { role: "user", content: trimmed, id: userId2 },
14920
+ { role: "tool", content: result.message, id: toolId }
14921
+ ]);
14922
+ return;
15267
14923
  }
15268
- try {
15269
- process.exit(exitCode);
15270
- } catch {}
15271
- };
15272
- process.on("SIGINT", shutdown);
15273
- process.on("SIGTERM", shutdown);
15274
- return {
15275
- dispose: () => {
15276
- process.removeListener("SIGINT", shutdown);
15277
- process.removeListener("SIGTERM", shutdown);
14924
+ if (result.kind === "unknown") {
14925
+ const userId2 = `h${++historyIdRef.current}`;
14926
+ const toolId = `h${++historyIdRef.current}`;
14927
+ setHistory((h) => [
14928
+ ...h,
14929
+ { role: "user", content: trimmed, id: userId2 },
14930
+ { role: "tool", content: `⚠ ${result.message}`, id: toolId }
14931
+ ]);
14932
+ return;
15278
14933
  }
15279
- };
15280
- }
14934
+ if (result.kind === "set-max-lines") {
14935
+ setMaxLines(result.value);
14936
+ const userId2 = `h${++historyIdRef.current}`;
14937
+ const toolId = `h${++historyIdRef.current}`;
14938
+ setHistory((h) => [
14939
+ ...h,
14940
+ { role: "user", content: trimmed, id: userId2 },
14941
+ {
14942
+ role: "tool",
14943
+ content: `max-lines set to ${result.value}`,
14944
+ id: toolId
14945
+ }
14946
+ ]);
14947
+ return;
14948
+ }
14949
+ setErrorMessage(null);
14950
+ const userId = `h${++historyIdRef.current}`;
14951
+ setHistory((h) => [
14952
+ ...h,
14953
+ { role: "user", content: trimmed, id: userId }
14954
+ ]);
14955
+ setUserHistory((uh) => [trimmed, ...uh]);
14956
+ userTurnCountRef.current += 1;
14957
+ await executeQuery(trimmed);
14958
+ }, [
14959
+ doExit,
14960
+ exit,
14961
+ executeQuery,
14962
+ maxLines,
14963
+ model,
14964
+ workdir
14965
+ ]);
14966
+ const handleCancel = useCallback4(() => {
14967
+ doExit();
14968
+ }, [doExit]);
14969
+ return /* @__PURE__ */ jsxDEV9(Box7, {
14970
+ flexDirection: "column",
14971
+ children: [
14972
+ /* @__PURE__ */ jsxDEV9(AppMemo, {
14973
+ history,
14974
+ status,
14975
+ model,
14976
+ workdir
14977
+ }, undefined, false, undefined, this),
14978
+ status !== "idle" ? /* @__PURE__ */ jsxDEV9(StreamingOverlay, {
14979
+ streamingText: stream.streamingText,
14980
+ status,
14981
+ markdownEnabled: markdownEnabled2,
14982
+ width
14983
+ }, undefined, false, undefined, this) : null,
14984
+ status === "idle" ? /* @__PURE__ */ jsxDEV9(Box7, {
14985
+ marginTop: 1,
14986
+ children: /* @__PURE__ */ jsxDEV9(TextInput, {
14987
+ label: "You",
14988
+ prefix: "\uD83D\uDC64",
14989
+ placeholder: 'Type a message, "/help", or "exit"',
14990
+ onSubmit: handleSubmit,
14991
+ onCancel: handleCancel,
14992
+ history: userHistory
14993
+ }, undefined, false, undefined, this)
14994
+ }, undefined, false, undefined, this) : null,
14995
+ errorMessage ? /* @__PURE__ */ jsxDEV9(Box7, {
14996
+ marginTop: 1,
14997
+ children: /* @__PURE__ */ jsxDEV9(Text9, {
14998
+ color: "red",
14999
+ children: [
15000
+ "⚠ ",
15001
+ errorMessage
15002
+ ]
15003
+ }, undefined, true, undefined, this)
15004
+ }, undefined, false, undefined, this) : null
15005
+ ]
15006
+ }, undefined, true, undefined, this);
15007
+ };
15008
+ var RunTui_default = RunScreen;
15281
15009
 
15282
- // src/commands/run-shutdown.js
15010
+ // src/commands/run.ts
15011
+ init_markdown();
15012
+
15013
+ // src/commands/run-shutdown.ts
15283
15014
  import { TempFileManager as TempFileManager3 } from "@ai-setting/roy-agent-core/utils/temp-file-manager";
15284
15015
  async function shutdownRunSteps(deps) {
15285
- const { lspManagerDispose, pluginAdapterDispose, stopEventHandler, stopTaskEventHandler, queryExecutor, env, envService, shouldDisposeEnvService, output, logger: logger7 } = deps;
15016
+ const {
15017
+ lspManagerDispose,
15018
+ pluginAdapterDispose,
15019
+ stopEventHandler,
15020
+ stopTaskEventHandler,
15021
+ queryExecutor,
15022
+ env,
15023
+ envService,
15024
+ shouldDisposeEnvService,
15025
+ output,
15026
+ logger: logger6
15027
+ } = deps;
15286
15028
  try {
15287
15029
  stopEventHandler();
15288
15030
  } catch (err) {
15289
- logger7?.warn?.(`[Shutdown] EventHandler.stop failed: ${err}`);
15031
+ logger6?.warn?.(`[Shutdown] EventHandler.stop failed: ${err}`);
15290
15032
  }
15291
15033
  try {
15292
15034
  stopTaskEventHandler();
15293
15035
  } catch (err) {
15294
- logger7?.warn?.(`[Shutdown] TaskEventHandler.stop failed: ${err}`);
15036
+ logger6?.warn?.(`[Shutdown] TaskEventHandler.stop failed: ${err}`);
15295
15037
  }
15296
15038
  if (lspManagerDispose) {
15297
15039
  try {
15298
15040
  await lspManagerDispose();
15299
15041
  } catch (err) {
15300
- logger7?.warn?.(`[Shutdown] LSP Manager dispose failed: ${err}`);
15042
+ logger6?.warn?.(`[Shutdown] LSP Manager dispose failed: ${err}`);
15301
15043
  }
15302
15044
  }
15303
15045
  if (pluginAdapterDispose) {
15304
15046
  try {
15305
15047
  await pluginAdapterDispose();
15306
15048
  } catch (err) {
15307
- logger7?.warn?.(`[Shutdown] PluginAdapter dispose failed: ${err}`);
15049
+ logger6?.warn?.(`[Shutdown] PluginAdapter dispose failed: ${err}`);
15308
15050
  }
15309
15051
  }
15310
15052
  try {
15311
15053
  queryExecutor.dispose();
15312
15054
  } catch (err) {
15313
- logger7?.warn?.(`[Shutdown] QueryExecutor.dispose failed: ${err}`);
15055
+ logger6?.warn?.(`[Shutdown] QueryExecutor.dispose failed: ${err}`);
15314
15056
  }
15315
15057
  try {
15316
15058
  const eventSourceComponent = env.getComponent("event-source");
@@ -15319,7 +15061,7 @@ async function shutdownRunSteps(deps) {
15319
15061
  if (sources && sources.length > 0) {
15320
15062
  for (const source of sources) {
15321
15063
  const status = eventSourceComponent.getStatus?.(source.id);
15322
- logger7?.debug?.(`[Shutdown] 检查事件源: ${source.id}, 状态: ${status}`);
15064
+ logger6?.debug?.(`[Shutdown] 检查事件源: ${source.id}, 状态: ${status}`);
15323
15065
  if (status !== "stopped" && status !== "created") {
15324
15066
  try {
15325
15067
  await eventSourceComponent.stopSource(source.id);
@@ -15332,25 +15074,29 @@ async function shutdownRunSteps(deps) {
15332
15074
  }
15333
15075
  }
15334
15076
  } catch (err) {
15335
- logger7?.warn?.(`[Shutdown] EventSource cleanup failed: ${err}`);
15077
+ logger6?.warn?.(`[Shutdown] EventSource cleanup failed: ${err}`);
15336
15078
  }
15337
15079
  if (shouldDisposeEnvService) {
15338
15080
  try {
15339
15081
  await envService.dispose();
15340
15082
  } catch (err) {
15341
- logger7?.warn?.(`[Shutdown] envService.dispose failed: ${err}`);
15083
+ logger6?.warn?.(`[Shutdown] envService.dispose failed: ${err}`);
15342
15084
  }
15343
15085
  }
15344
15086
  try {
15345
15087
  await TempFileManager3.getInstance().cleanupAll();
15346
- logger7?.debug?.("[Shutdown] TempFileManager cleaned up");
15088
+ logger6?.debug?.("[Shutdown] TempFileManager cleaned up");
15347
15089
  } catch (err) {
15348
- logger7?.warn?.(`[Shutdown] TempFileManager cleanup failed: ${err}`);
15090
+ logger6?.warn?.(`[Shutdown] TempFileManager cleanup failed: ${err}`);
15349
15091
  }
15350
15092
  }
15351
15093
 
15352
15094
  // src/commands/run.ts
15353
- async function loadHandleQuery(options, hooks) {
15095
+ import {
15096
+ wrapFunction as wrapFunction7,
15097
+ getTracerProvider as getTracerProvider4
15098
+ } from "@ai-setting/roy-agent-core";
15099
+ async function loadHandleQueryImpl(options, hooks) {
15354
15100
  const quiet = CliQuietModeService.getInstance().isQuiet();
15355
15101
  const output = new OutputService2;
15356
15102
  output.configure({ quiet });
@@ -15371,14 +15117,14 @@ async function loadHandleQuery(options, hooks) {
15371
15117
  if (!sessionComponent) {
15372
15118
  throw new Error("Failed to create session component");
15373
15119
  }
15374
- const sessionManager = new SessionManager2({
15120
+ const sessionManager = new SessionManager({
15375
15121
  sessionComponent,
15376
15122
  output,
15377
15123
  quiet: true
15378
15124
  });
15379
15125
  const sessionResult = await sessionManager.init(options.session, options.continue);
15380
15126
  const sessionId = sessionResult.sessionId;
15381
- const queryExecutor = new QueryExecutor2({
15127
+ const queryExecutor = new QueryExecutor({
15382
15128
  env,
15383
15129
  sessionComponent,
15384
15130
  output,
@@ -15388,13 +15134,13 @@ async function loadHandleQuery(options, hooks) {
15388
15134
  let agentContext = undefined;
15389
15135
  if (options.agent && options.agent !== "default") {
15390
15136
  const agentComponent = env.getComponent("agent");
15391
- const validation = validateActAgent2(agentComponent, options.agent);
15137
+ const validation = validateActAgent(agentComponent, options.agent);
15392
15138
  if (!validation.valid) {
15393
15139
  output.error(validation.message);
15394
15140
  output.info("提示: roy-agent agents list");
15395
15141
  process.exit(1);
15396
15142
  }
15397
- agentContext = buildActAgentContext2(options.agent);
15143
+ agentContext = buildActAgentContext(options.agent);
15398
15144
  }
15399
15145
  let eventSourceSystemPrompt;
15400
15146
  const rawEventSourceIds = options.eventSource;
@@ -15406,16 +15152,16 @@ async function loadHandleQuery(options, hooks) {
15406
15152
  output.info("请确保 EventSourceComponent 已正确注册");
15407
15153
  process.exit(1);
15408
15154
  }
15409
- const summary = await startEventSources2(eventSourceIds, eventSourceComponent, output);
15410
- const preloadedPrompts = collectEventSourceSystemPrompts2(eventSourceIds, eventSourceComponent);
15411
- eventSourceSystemPrompt = preloadedPrompts.length > 0 ? joinResolvedSystemPrompts2(preloadedPrompts) : undefined;
15155
+ const summary = await startEventSources(eventSourceIds, eventSourceComponent, output);
15156
+ const preloadedPrompts = collectEventSourceSystemPrompts(eventSourceIds, eventSourceComponent);
15157
+ eventSourceSystemPrompt = preloadedPrompts.length > 0 ? joinResolvedSystemPrompts(preloadedPrompts) : undefined;
15412
15158
  if (eventSourceIds.length === 1 && summary.failedCount > 0) {
15413
15159
  process.exit(1);
15414
15160
  }
15415
15161
  }
15416
15162
  const llmComponent = envService.getLLM();
15417
15163
  queryExecutor.initStreamOutput(llmComponent ?? null);
15418
- const handleQuery = async (message) => {
15164
+ const handleQueryImpl = async (message) => {
15419
15165
  const mergedContext = {
15420
15166
  ...agentContext,
15421
15167
  model: options.model,
@@ -15432,14 +15178,22 @@ async function loadHandleQuery(options, hooks) {
15432
15178
  }, undefined, mergedContext);
15433
15179
  return String(result ?? "");
15434
15180
  };
15435
- const taskEventHandler = new TaskEventHandler2({
15181
+ const handleQuery = wrapFunction7(handleQueryImpl, "cli.run.handleQuery", {
15182
+ recordParams: true,
15183
+ recordResult: false,
15184
+ log: true,
15185
+ paramFilter: (args) => ({
15186
+ "message.length": typeof args[0] === "string" ? args[0].length : 0
15187
+ })
15188
+ });
15189
+ const taskEventHandler = new TaskEventHandler({
15436
15190
  env,
15437
15191
  enabled: true
15438
15192
  });
15439
- const eventHandler = new EventHandler2({
15193
+ const eventHandler = new EventHandler({
15440
15194
  env,
15441
15195
  eventTypes: ["task.background.*", "event-source.event.*"],
15442
- formatter: new EventMessageFormatter2({ prefix: "[通知]" }),
15196
+ formatter: new EventMessageFormatter({ prefix: "[通知]" }),
15443
15197
  isIdle: hooks?.isIdle ?? (() => true),
15444
15198
  sessionComponent,
15445
15199
  onEvent: async (_message) => {},
@@ -15463,17 +15217,80 @@ async function loadHandleQuery(options, hooks) {
15463
15217
  sessionManager
15464
15218
  };
15465
15219
  }
15466
- function createStreamHandleQuery(queryExecutor, sessionId, options, agentContext, eventSourceSystemPrompt) {
15467
- return async (message, onChunk) => {
15468
- queryExecutor.setChunkCallback((event) => {
15220
+ var loadHandleQuery = wrapFunction7(loadHandleQueryImpl, "cli.run.loadHandleQuery", {
15221
+ recordParams: true,
15222
+ recordResult: false,
15223
+ log: true,
15224
+ paramFilter: (args) => {
15225
+ const opts = args[0] ?? {};
15226
+ return {
15227
+ "options.model": opts.model ?? "",
15228
+ "options.workdir": opts.workdir ?? "",
15229
+ "options.session": opts.session ?? "",
15230
+ "options.eventSource": Array.isArray(opts.eventSource) ? opts.eventSource.join(",") : opts.eventSource ?? "",
15231
+ "has.onNotification": !!args[1]?.onNotification
15232
+ };
15233
+ }
15234
+ });
15235
+ function createStreamHandleQuery(queryExecutor, sessionId, options, agentContext, eventSourceSystemPrompt, onTraceId) {
15236
+ const innerStreamHandler = async (message, onChunk) => {
15237
+ const onChunkInstrumented = wrapFunction7((chunk) => {
15238
+ onChunk(chunk);
15239
+ }, "cli.run.chunkCallbackImpl.onChunk-called", {
15240
+ recordParams: true,
15241
+ recordResult: false,
15242
+ log: false,
15243
+ paramFilter: (args) => ({
15244
+ "chunk.length": typeof args[0] === "string" ? args[0].length : 0,
15245
+ "chunk.head": typeof args[0] === "string" ? args[0].slice(0, 32) : ""
15246
+ })
15247
+ });
15248
+ const chunkCallbackImpl = (event) => {
15469
15249
  if (event.type === "llm.text") {
15470
15250
  if (event.delta) {
15471
- onChunk(event.delta);
15251
+ onChunkInstrumented(event.delta);
15472
15252
  } else if (event.content) {
15473
- onChunk(event.content);
15253
+ onChunkInstrumented(event.content);
15474
15254
  }
15255
+ return;
15475
15256
  }
15476
- });
15257
+ if (event.type === "tool.call") {
15258
+ const toolName = event.toolName || "unknown";
15259
+ const toolId = event.toolId || "";
15260
+ onChunkInstrumented(`
15261
+ \uD83D\uDD27 tool: ${toolName} (${toolId})
15262
+ `);
15263
+ return;
15264
+ }
15265
+ if (event.type === "tool.result") {
15266
+ onChunkInstrumented(`
15267
+ ✓ done
15268
+ `);
15269
+ return;
15270
+ }
15271
+ if (event.type === "tool.error") {
15272
+ const msg = event.toolError || "error";
15273
+ onChunkInstrumented(`
15274
+ ✗ ${msg}
15275
+ `);
15276
+ return;
15277
+ }
15278
+ };
15279
+ queryExecutor.setChunkCallback(wrapFunction7(chunkCallbackImpl, "cli.run.chunkCallback", {
15280
+ recordParams: true,
15281
+ recordResult: false,
15282
+ log: true,
15283
+ paramFilter: (args) => {
15284
+ const e = args[0] ?? {};
15285
+ return {
15286
+ "event.type": e.type ?? "unknown",
15287
+ "event.delta.length": typeof e.delta === "string" ? e.delta.length : 0,
15288
+ "event.content.length": typeof e.content === "string" ? e.content.length : 0,
15289
+ "event.toolName": e.toolName ?? "",
15290
+ "event.toolId": e.toolId ?? ""
15291
+ };
15292
+ }
15293
+ }));
15477
15294
  const mergedContext = {
15478
15295
  ...agentContext,
15479
15296
  model: options.model,
@@ -15483,13 +15300,37 @@ function createStreamHandleQuery(queryExecutor, sessionId, options, agentContext
15483
15300
  defaultAgentName: options.defaultAgentName
15484
15301
  }
15485
15302
  };
15486
- const result = await queryExecutor.execute(message, sessionId, {
15487
- showReasoning: options.reasoning ?? true,
15488
- showToolCalls: options.toolCalls ?? true,
15489
- showToolResults: options.toolResults ?? false
15490
- }, undefined, mergedContext);
15303
+ const turnSpan = getTracerProvider4().getTracer("roy-tracer").startSpan("cli.run.turn");
15304
+ const turnTraceId = turnSpan.spanContext.traceId;
15305
+ let result;
15306
+ try {
15307
+ result = await queryExecutor.execute(message, sessionId, {
15308
+ showReasoning: options.reasoning ?? true,
15309
+ showToolCalls: options.toolCalls ?? true,
15310
+ showToolResults: options.toolResults ?? false
15311
+ }, undefined, mergedContext);
15312
+ turnSpan.end(result);
15313
+ } catch (error) {
15314
+ turnSpan.setAttribute("error", String(error));
15315
+ turnSpan.end(undefined, error instanceof Error ? error : new Error(String(error)));
15316
+ throw error;
15317
+ } finally {
15318
+ try {
15319
+ onTraceId?.(turnTraceId);
15320
+ } catch (cbErr) {
15321
+ console.warn(`[Trace] sink failed: ${cbErr instanceof Error ? cbErr.message : String(cbErr)}`);
15322
+ }
15323
+ }
15491
15324
  return String(result ?? "");
15492
15325
  };
15326
+ return wrapFunction7(innerStreamHandler, "cli.run.createStreamHandleQuery", {
15327
+ recordParams: true,
15328
+ recordResult: false,
15329
+ log: true,
15330
+ paramFilter: (args) => ({
15331
+ "message.length": typeof args[0] === "string" ? args[0].length : 0
15332
+ })
15333
+ });
15493
15334
  }
15494
15335
  function createRunCommand() {
15495
15336
  return {
@@ -15562,6 +15403,10 @@ function createRunCommand() {
15562
15403
  type: "string",
15563
15404
  describe: "Default agent 名字(默认 Roy,可被覆盖)",
15564
15405
  default: "Roy"
15406
+ }).option("debug-on", {
15407
+ type: "boolean",
15408
+ describe: "调试模式:每次 turn 结束后输出 [Trace] <traceId>(stderr),便于追踪调用 trace",
15409
+ default: false
15565
15410
  }),
15566
15411
  handler: async (argv) => {
15567
15412
  if (argv.markdown === false) {
@@ -15589,7 +15434,7 @@ function createRunCommand() {
15589
15434
  isIdle: () => runState.isIdle(),
15590
15435
  onNotification: (msg, envEvent) => runState.onNotification(msg, envEvent)
15591
15436
  });
15592
- const shutdownHandle = registerShutdownHandlers2(async () => {
15437
+ const shutdownHandle = registerShutdownHandlers(async () => {
15593
15438
  await shutdownRunSteps({
15594
15439
  lspManagerDispose: null,
15595
15440
  pluginAdapterDispose: null,
@@ -15603,10 +15448,17 @@ function createRunCommand() {
15603
15448
  logger: undefined
15604
15449
  });
15605
15450
  });
15606
- const streamHandleQuery = createStreamHandleQuery(queryExecutor, sessionId, argv, agentContext, eventSourceSystemPrompt);
15451
+ const debugOn = argv.debugOn ?? false;
15452
+ let appendTraceIdTui;
15453
+ const streamHandleQuery = createStreamHandleQuery(queryExecutor, sessionId, argv, agentContext, eventSourceSystemPrompt, (traceId) => {
15454
+ printTraceIdAfterResponse(traceId, {
15455
+ enabled: debugOn,
15456
+ tuiSink: appendTraceIdTui
15457
+ });
15458
+ });
15607
15459
  const stopEventHandler = eventHandler.start();
15608
15460
  const stopTaskEventHandler = taskEventHandler.start();
15609
- const { waitUntilExit } = render(React9.createElement(RunTui_default, {
15461
+ const { waitUntilExit } = render(React8.createElement(RunTui_default, {
15610
15462
  handleQuery,
15611
15463
  streamHandleQuery,
15612
15464
  model: argv.model,
@@ -15616,6 +15468,7 @@ function createRunCommand() {
15616
15468
  onRegisterHandlers: (handlers) => {
15617
15469
  runState.onNotification = handlers.onNotification;
15618
15470
  runState.isIdle = handlers.isIdle;
15471
+ appendTraceIdTui = handlers.appendTraceId;
15619
15472
  },
15620
15473
  onExit: () => {}
15621
15474
  }), { exitOnCtrlC: true });
@@ -15643,23 +15496,31 @@ function createRunCommand() {
15643
15496
  var RunCommand = createRunCommand();
15644
15497
 
15645
15498
  // src/commands/chat.ts
15646
- import React11 from "react";
15499
+ import React10 from "react";
15647
15500
  import { render as render2 } from "ink";
15648
15501
 
15649
- // src/ChatTui.js
15650
- import React10, { useEffect as useEffect6, useRef as useRef3, useState as useState7 } from "react";
15651
- import { Box as Box7, useApp as useApp3 } from "ink";
15502
+ // src/ChatTui.tsx
15503
+ import { useEffect as useEffect8, useRef as useRef6, useState as useState7 } from "react";
15504
+ import { Box as Box8, useApp as useApp3 } from "ink";
15652
15505
  init_markdown();
15653
- import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
15654
- var ChatScreen = ({ handleQuery, streamHandleQuery, message, model, workdir, maxLines, markdownEnabled: markdownEnabled2 }) => {
15506
+ import { jsxDEV as jsxDEV10 } from "react/jsx-dev-runtime";
15507
+ var ChatScreen = ({
15508
+ handleQuery,
15509
+ streamHandleQuery,
15510
+ message,
15511
+ model,
15512
+ workdir,
15513
+ maxLines,
15514
+ markdownEnabled: markdownEnabled2
15515
+ }) => {
15655
15516
  const [history, setHistory] = useState7([
15656
15517
  { role: "user", content: message, id: "h-init-1" }
15657
15518
  ]);
15658
- const historyIdRef = useRef3(1);
15519
+ const historyIdRef = useRef6(1);
15659
15520
  const stream = useStreamingAccumulator();
15660
15521
  const { exit } = useApp3();
15661
15522
  const width = process.stdout.columns ?? 80;
15662
- useEffect6(() => {
15523
+ useEffect8(() => {
15663
15524
  let cancelled = false;
15664
15525
  stream.start();
15665
15526
  (async () => {
@@ -15698,16 +15559,23 @@ var ChatScreen = ({ handleQuery, streamHandleQuery, message, model, workdir, max
15698
15559
  cancelled = true;
15699
15560
  };
15700
15561
  }, [handleQuery, streamHandleQuery, message, maxLines, markdownEnabled2, exit, width, stream]);
15701
- return /* @__PURE__ */ jsxDEV9(Box7, {
15562
+ return /* @__PURE__ */ jsxDEV10(Box8, {
15702
15563
  flexDirection: "column",
15703
- children: /* @__PURE__ */ jsxDEV9(App, {
15704
- history,
15705
- status: stream.status,
15706
- model,
15707
- workdir,
15708
- streamingText: stream.streamingText
15709
- }, undefined, false, undefined, this)
15710
- }, undefined, false, undefined, this);
15564
+ children: [
15565
+ /* @__PURE__ */ jsxDEV10(AppMemo, {
15566
+ history,
15567
+ status: stream.status,
15568
+ model,
15569
+ workdir
15570
+ }, undefined, false, undefined, this),
15571
+ stream.status !== "idle" ? /* @__PURE__ */ jsxDEV10(StreamingOverlay, {
15572
+ streamingText: stream.streamingText,
15573
+ status: stream.status,
15574
+ markdownEnabled: markdownEnabled2,
15575
+ width
15576
+ }, undefined, false, undefined, this) : null
15577
+ ]
15578
+ }, undefined, true, undefined, this);
15711
15579
  };
15712
15580
  var ChatTui_default = ChatScreen;
15713
15581
 
@@ -15786,7 +15654,7 @@ function createChatCommand() {
15786
15654
  }
15787
15655
  const maxLines = Number.parseInt(argv.maxLines ?? "500", 10);
15788
15656
  const handleQuery = await loadHandleQuery2(argv);
15789
- const { waitUntilExit } = render2(React11.createElement(ChatTui_default, {
15657
+ const { waitUntilExit } = render2(React10.createElement(ChatTui_default, {
15790
15658
  handleQuery,
15791
15659
  message: argv.message,
15792
15660
  model: argv.model,
@@ -25157,9 +25025,9 @@ import chalk73 from "chalk";
25157
25025
  import fs5 from "fs";
25158
25026
  import path8 from "path";
25159
25027
  import { createRunWorkflowTool } from "@ai-setting/roy-agent-core/env/workflow/tools";
25160
- import { getTracerProvider as getTracerProvider4, propagation, wrapFunction } from "@ai-setting/roy-agent-core";
25028
+ import { getTracerProvider as getTracerProvider5, propagation, wrapFunction as wrapFunction8 } from "@ai-setting/roy-agent-core";
25161
25029
  import { isValidSessionId } from "@ai-setting/roy-agent-core/env/session";
25162
- var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
25030
+ var runWorkflow = wrapFunction8(async function runWorkflowImpl(args) {
25163
25031
  const output = new OutputService2;
25164
25032
  const envService = new EnvironmentService(output);
25165
25033
  const traceparent = process.env.TRACEPARENT;
@@ -25179,7 +25047,7 @@ var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
25179
25047
  output.info(`[OTel Trace] TRACEPARENT=${traceparent || "none"}, traceId=${traceId}, parentSpanId=${parentSpanId}`);
25180
25048
  let workflowSpan = undefined;
25181
25049
  try {
25182
- const provider = getTracerProvider4();
25050
+ const provider = getTracerProvider5();
25183
25051
  await provider.initialize();
25184
25052
  const tracer = provider.getTracer("roy-tracer");
25185
25053
  const restoredContext = tracer.getCurrentContext();
@@ -25436,8 +25304,8 @@ var WorkflowRunCommand = {
25436
25304
  // src/commands/workflow/commands/stop.ts
25437
25305
  import chalk74 from "chalk";
25438
25306
  import { createWorkflowRunStopTool } from "@ai-setting/roy-agent-core/env/workflow/tools";
25439
- import { wrapFunction as wrapFunction2 } from "@ai-setting/roy-agent-core";
25440
- var stopWorkflow = wrapFunction2(async function stopWorkflowImpl(args) {
25307
+ import { wrapFunction as wrapFunction9 } from "@ai-setting/roy-agent-core";
25308
+ var stopWorkflow = wrapFunction9(async function stopWorkflowImpl(args) {
25441
25309
  const output = new OutputService2;
25442
25310
  const envService = new EnvironmentService(output);
25443
25311
  try {
@@ -26092,7 +25960,7 @@ Error: ${error.message}`));
26092
25960
 
26093
25961
  // src/commands/workflow/commands/search.ts
26094
25962
  import chalk78 from "chalk";
26095
- import { wrapFunction as wrapFunction3 } from "@ai-setting/roy-agent-core";
25963
+ import { wrapFunction as wrapFunction10 } from "@ai-setting/roy-agent-core";
26096
25964
  var WorkflowSearchCommand = {
26097
25965
  command: "search",
26098
25966
  describe: "Search workflows by keyword and/or tags (multiple tags use AND filter). v2: returns available_tags.",
@@ -26267,14 +26135,14 @@ var _runWorkflowSearchImpl = async function(opts) {
26267
26135
  }
26268
26136
  }
26269
26137
  };
26270
- var runWorkflowSearch = wrapFunction3(_runWorkflowSearchImpl, "workflow.cli.search", {
26138
+ var runWorkflowSearch = wrapFunction10(_runWorkflowSearchImpl, "workflow.cli.search", {
26271
26139
  recordParams: true,
26272
26140
  recordResult: false,
26273
26141
  log: false
26274
26142
  });
26275
26143
 
26276
26144
  // src/commands/workflow/commands/tag.ts
26277
- import { wrapFunction as wrapFunction4 } from "@ai-setting/roy-agent-core";
26145
+ import { wrapFunction as wrapFunction11 } from "@ai-setting/roy-agent-core";
26278
26146
  import chalk79 from "chalk";
26279
26147
  var WorkflowTagListCommand = {
26280
26148
  command: "list",
@@ -26474,12 +26342,12 @@ function formatDate2(iso) {
26474
26342
  return iso;
26475
26343
  }
26476
26344
  }
26477
- var runWorkflowTagList = wrapFunction4(_runWorkflowTagListImpl, "workflow.cli.tag.list", {
26345
+ var runWorkflowTagList = wrapFunction11(_runWorkflowTagListImpl, "workflow.cli.tag.list", {
26478
26346
  recordParams: true,
26479
26347
  recordResult: false,
26480
26348
  log: false
26481
26349
  });
26482
- var runWorkflowTagGet = wrapFunction4(_runWorkflowTagGetImpl, "workflow.cli.tag.get", {
26350
+ var runWorkflowTagGet = wrapFunction11(_runWorkflowTagGetImpl, "workflow.cli.tag.get", {
26483
26351
  recordParams: true,
26484
26352
  recordResult: false,
26485
26353
  log: false
@@ -26747,7 +26615,7 @@ import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync
26747
26615
  import { join as join6, resolve } from "node:path";
26748
26616
  import { homedir as homedir4 } from "node:os";
26749
26617
 
26750
- // src/commands/install/cleanup-stale-plugin-copies.js
26618
+ // src/commands/install/cleanup-stale-plugin-copies.ts
26751
26619
  import { existsSync as existsSync4, readFileSync as readFileSync3, rmSync, cpSync } from "node:fs";
26752
26620
  import { join as join5 } from "node:path";
26753
26621
  import { homedir as nodeHomedir, tmpdir as nodeTmpdir } from "node:os";