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