@keyou007/agent-bot 0.1.20-alpha.1 → 0.1.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.
Files changed (92) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +27 -4
  3. package/README.zh.md +23 -4
  4. package/dist/cli/AgentPrerequisites.js +11 -47
  5. package/dist/cli/AgentPrerequisites.js.map +1 -1
  6. package/dist/cli/DefaultAgentSelection.js +1 -1
  7. package/dist/cli/DefaultAgentSelection.js.map +1 -1
  8. package/dist/cli.js +15 -0
  9. package/dist/cli.js.map +1 -1
  10. package/dist/codex/CodexEventMapper.js +21 -1
  11. package/dist/codex/CodexEventMapper.js.map +1 -1
  12. package/dist/codex/CodexLocalActivityDetector.js +32 -10
  13. package/dist/codex/CodexLocalActivityDetector.js.map +1 -1
  14. package/dist/codex/CodexProcessManager.js +56 -7
  15. package/dist/codex/CodexProcessManager.js.map +1 -1
  16. package/dist/codex/CodexRuntime.js +361 -168
  17. package/dist/codex/CodexRuntime.js.map +1 -1
  18. package/dist/codex/CodexVersion.js +18 -0
  19. package/dist/codex/CodexVersion.js.map +1 -0
  20. package/dist/codex/ProviderModels.js +159 -0
  21. package/dist/codex/ProviderModels.js.map +1 -0
  22. package/dist/codex/ProviderSwitch.js +32 -0
  23. package/dist/codex/ProviderSwitch.js.map +1 -0
  24. package/dist/commands/CommandRouter.js +8 -3
  25. package/dist/commands/CommandRouter.js.map +1 -1
  26. package/dist/console/ConsoleTurnPresenter.js +2 -1
  27. package/dist/console/ConsoleTurnPresenter.js.map +1 -1
  28. package/dist/feishu/CardRenderer.js +82 -27
  29. package/dist/feishu/CardRenderer.js.map +1 -1
  30. package/dist/feishu/FeishuConnector.js +17 -5
  31. package/dist/feishu/FeishuConnector.js.map +1 -1
  32. package/dist/feishu/FeishuTurnPresenter.js +34 -8
  33. package/dist/feishu/FeishuTurnPresenter.js.map +1 -1
  34. package/dist/feishu/InboundText.js +11 -0
  35. package/dist/feishu/InboundText.js.map +1 -1
  36. package/dist/feishu/MergedForwardMessage.js +17 -5
  37. package/dist/feishu/MergedForwardMessage.js.map +1 -1
  38. package/dist/index.js +3 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/local-files/LocalFileViewerServer.js +164 -19
  41. package/dist/local-files/LocalFileViewerServer.js.map +1 -1
  42. package/dist/local-files/MarkdownFileLinks.js +65 -0
  43. package/dist/local-files/MarkdownFileLinks.js.map +1 -0
  44. package/dist/local-files/TurnPreviewPage.js +725 -0
  45. package/dist/local-files/TurnPreviewPage.js.map +1 -0
  46. package/dist/presentation/OutboundRouter.js +6 -1
  47. package/dist/presentation/OutboundRouter.js.map +1 -1
  48. package/dist/presentation/TurnStateReducer.js +142 -3
  49. package/dist/presentation/TurnStateReducer.js.map +1 -1
  50. package/dist/proxy/ProxySessionController.js +573 -325
  51. package/dist/proxy/ProxySessionController.js.map +1 -1
  52. package/dist/state/StateStore.js +65 -65
  53. package/dist/state/StateStore.js.map +1 -1
  54. package/dist/utils/formatStorageSize.js +15 -0
  55. package/dist/utils/formatStorageSize.js.map +1 -0
  56. package/dist/utils/semanticVersion.js +39 -0
  57. package/dist/utils/semanticVersion.js.map +1 -0
  58. package/docs/technical-reference.md +11 -3
  59. package/docs/technical-reference.zh.md +11 -3
  60. package/npm-shrinkwrap.json +2 -2
  61. package/package.json +1 -1
  62. package/skills/agent-bot/SKILL.md +11 -1
  63. package/src/cli/AgentPrerequisites.ts +14 -40
  64. package/src/cli/DefaultAgentSelection.ts +1 -1
  65. package/src/cli.ts +13 -0
  66. package/src/codex/CodexEventMapper.ts +31 -1
  67. package/src/codex/CodexLocalActivityDetector.ts +41 -9
  68. package/src/codex/CodexProcessManager.ts +48 -7
  69. package/src/codex/CodexRuntime.ts +397 -204
  70. package/src/codex/CodexVersion.ts +18 -0
  71. package/src/codex/ProviderModels.ts +185 -0
  72. package/src/codex/ProviderSwitch.ts +36 -0
  73. package/src/commands/CommandRouter.ts +7 -2
  74. package/src/commands/commandTypes.ts +1 -1
  75. package/src/console/ConsoleTurnPresenter.ts +3 -0
  76. package/src/feishu/CardRenderer.ts +84 -43
  77. package/src/feishu/FeishuConnector.ts +15 -5
  78. package/src/feishu/FeishuTurnPresenter.ts +46 -4
  79. package/src/feishu/InboundText.ts +11 -0
  80. package/src/feishu/MergedForwardMessage.ts +15 -5
  81. package/src/index.ts +3 -1
  82. package/src/local-files/LocalFileViewerServer.ts +179 -20
  83. package/src/local-files/MarkdownFileLinks.ts +64 -0
  84. package/src/local-files/TurnPreviewPage.ts +792 -0
  85. package/src/presentation/OutboundRouter.ts +8 -0
  86. package/src/presentation/TurnStateReducer.ts +175 -2
  87. package/src/presentation/turnViewTypes.ts +13 -0
  88. package/src/proxy/ProxySessionController.ts +547 -297
  89. package/src/runtime/types.ts +33 -3
  90. package/src/state/StateStore.ts +86 -90
  91. package/src/utils/formatStorageSize.ts +13 -0
  92. package/src/utils/semanticVersion.ts +28 -0
@@ -2,6 +2,13 @@ import { createHash } from "node:crypto";
2
2
  import path from "node:path";
3
3
  import { truncateMiddle, truncateText } from "../utils/markdown.js";
4
4
  import { localCardImage } from "./LocalCardImage.js";
5
+ const EXECUTION_SETTING_EFFECTS = {
6
+ agent: "只影响新建任务,不切换当前任务。",
7
+ provider: "只影响当前任务,需空闲时切换。",
8
+ model: "只影响当前任务,下一轮生效。",
9
+ thinking: "只影响当前任务,下一轮生效。",
10
+ permission: "只影响当前任务,下一轮生效。",
11
+ };
5
12
  const DIRECTORY_BROWSER_ROW_COUNT = 16;
6
13
  export class CardRenderer {
7
14
  thinkingCardLayout;
@@ -234,7 +241,7 @@ export class CardRenderer {
234
241
  ];
235
242
  if (view.activeTab === "agent") {
236
243
  elements.push(...view.agents.map((agent) => settingsOptionRow({
237
- label: `${inlineCode(agent.name)} · ${escapeCardHtml(agent.title)}`,
244
+ label: inlineCode(agent.name),
238
245
  current: agent.name === view.currentAgent,
239
246
  action: {
240
247
  text: "Switch",
@@ -257,9 +264,6 @@ export class CardRenderer {
257
264
  elements.push(...view.providers.map((provider) => settingsOptionRow({
258
265
  label: [
259
266
  inlineCode(provider.id),
260
- provider.displayName && provider.displayName !== provider.id
261
- ? ` · ${escapeCardHtml(provider.displayName)}`
262
- : "",
263
267
  provider.isDefault ? " · 默认" : "",
264
268
  ].join(""),
265
269
  current: provider.id === view.currentProvider,
@@ -331,6 +335,7 @@ export class CardRenderer {
331
335
  },
332
336
  })));
333
337
  }
338
+ elements.push(markdown(`> ${EXECUTION_SETTING_EFFECTS[view.activeTab]}`));
334
339
  return sectionCard("运行设置", elements, view.notice ? "green" : "blue");
335
340
  }
336
341
  renderProviderSelector(view) {
@@ -812,7 +817,7 @@ export class CardRenderer {
812
817
  },
813
818
  };
814
819
  }
815
- renderTurn(state) {
820
+ renderTurn(state, previewUrl) {
816
821
  const elements = this.thinkingCardLayout === "timeline"
817
822
  ? renderTurnElements(state, "hidden")
818
823
  : renderGroupedTurnElements(state, "hidden");
@@ -823,17 +828,26 @@ export class CardRenderer {
823
828
  type: "danger",
824
829
  value: { action: "turn_cancel", sessionId: state.sessionId, turnId: state.turnId },
825
830
  });
826
- elements.push({ tag: "hr" }, taskActionRow(footerActions, renderTurnDuration(state)));
831
+ if (previewUrl)
832
+ footerActions.push(turnPreviewAction(previewUrl));
833
+ elements.push({ tag: "hr" }, taskActionRow(footerActions, renderTurnDuration(state), true));
827
834
  }
828
835
  else if (state.status === "completed") {
829
836
  footerActions.push({
830
837
  text: "Reset",
831
838
  value: { action: "turn_reset", sessionId: state.sessionId, turnId: state.turnId },
832
839
  });
833
- elements.push({ tag: "hr" }, taskActionRow(footerActions));
840
+ if (previewUrl)
841
+ footerActions.push(turnPreviewAction(previewUrl));
842
+ elements.push({ tag: "hr" }, taskActionRow(footerActions, undefined, true));
834
843
  }
835
844
  else if (state.status === "starting") {
836
- elements.push({ tag: "hr" }, taskActionRow([], renderTurnDuration(state)));
845
+ if (previewUrl)
846
+ footerActions.push(turnPreviewAction(previewUrl));
847
+ elements.push({ tag: "hr" }, taskActionRow(footerActions, renderTurnDuration(state), true));
848
+ }
849
+ else if (previewUrl) {
850
+ elements.push({ tag: "hr" }, taskActionRow([turnPreviewAction(previewUrl)], renderTurnDuration(state)));
837
851
  }
838
852
  if (state.status === "completed") {
839
853
  elements.push({
@@ -843,11 +857,17 @@ export class CardRenderer {
843
857
  }
844
858
  return turnCard(turnTitle(state.status, state.prompt ?? state.taskTitle), turnTemplate(state.status), elements, renderTurnSubtitle(state));
845
859
  }
846
- renderTurnDetails(state) {
860
+ renderTurnDetails(state, previewUrl) {
847
861
  const title = state.taskTitle
848
862
  ? `任务执行详情:${truncateText(state.taskTitle.replace(/\s+/g, " ").trim(), 60)}`
849
863
  : "任务执行详情";
850
- return turnCard(title, "blue", renderTurnElements(state, "always"), renderTurnSubtitle(state));
864
+ const elements = [markdown(`Turn: \`${state.turnId}\``)];
865
+ if (state.prompt)
866
+ elements.push(markdown(`**Prompt**\n${truncateText(state.prompt, 1_000)}`));
867
+ elements.push(...renderTurnElements(state, "always"));
868
+ if (previewUrl)
869
+ elements.push(taskActionRow([turnPreviewAction(previewUrl)]));
870
+ return turnCard(title, "blue", elements, renderTurnSubtitle(state));
851
871
  }
852
872
  renderActivityHistory(state, requestedPage) {
853
873
  const grouped = this.thinkingCardLayout === "grouped";
@@ -1152,9 +1172,9 @@ export class CardRenderer {
1152
1172
  elements.push(markdown("当前任务还没有成功完成的 turn。"));
1153
1173
  }
1154
1174
  else {
1175
+ const sequenceWidth = `${Math.max(16, ...view.entries.map((entry) => String(entry.sequence).length * 10))}px`;
1155
1176
  view.entries.forEach((entry) => {
1156
- const action = entry.actions?.[0];
1157
- elements.push(resetHistoryEntryRow(entry.graphNodeLine, entry.graphConnectorLine, entry.lines, entry.timestamp, action, entry.current === true, entry.running === true, entry.resetting === true));
1177
+ elements.push(resetHistoryEntryRow(entry, sequenceWidth));
1158
1178
  });
1159
1179
  }
1160
1180
  if (view.footerLines.length > 0) {
@@ -1791,7 +1811,7 @@ function renderToolDetails(tool, projectCwd) {
1791
1811
  const resultText = result ? truncateToolResult(normalizeTerminalOutput(result).trim()) : undefined;
1792
1812
  return codeBlock([`$ ${commandText}`, resultText].filter((part) => part !== undefined).join("\n"), 2_003);
1793
1813
  }
1794
- function formatShellCommandForDisplay(command) {
1814
+ export function formatShellCommandForDisplay(command) {
1795
1815
  const normalized = command.replace(/\r\n/g, "\n");
1796
1816
  let result = "";
1797
1817
  let quote;
@@ -1892,7 +1912,7 @@ function toolPanelTitle(tool) {
1892
1912
  const command = stripAnsi(tool.command ?? tool.title).trim();
1893
1913
  const meaningfulCommand = tool.kind === "web_search"
1894
1914
  ? tool.title
1895
- : unwrapShellCommand(command) ?? tool.title;
1915
+ : displayToolCommand(command) ?? tool.title;
1896
1916
  const duration = toolDuration(tool);
1897
1917
  const prefix = `${icon} `;
1898
1918
  const suffix = duration ? ` · ${duration}` : "";
@@ -1957,6 +1977,10 @@ function shellCommandStatus(view) {
1957
1977
  }
1958
1978
  return { title: "命令执行失败", label: `退出码 ${view.exitCode ?? "未知"}`, template: "red" };
1959
1979
  }
1980
+ export function displayToolCommand(command) {
1981
+ const clean = stripAnsi(command).trim();
1982
+ return unwrapShellCommand(clean);
1983
+ }
1960
1984
  function unwrapShellCommand(command) {
1961
1985
  return unwrapPowerShellCommand(command) ?? unwrapPosixShellCommand(command);
1962
1986
  }
@@ -2295,16 +2319,29 @@ function settingsOptionRow(input) {
2295
2319
  ],
2296
2320
  };
2297
2321
  }
2298
- function resetHistoryEntryRow(graphNodeLine, graphConnectorLine, lines, timestamp, action, current, running, resetting) {
2322
+ function resetHistoryEntryRow(entry, sequenceWidth) {
2323
+ const { graphNodeLine, graphConnectorLine, lines, timestamp, current, running, resetting } = entry;
2324
+ const action = entry.actions?.[0];
2299
2325
  const branchConnectorLine = graphConnectorLine && /[╱╲]/u.test(graphConnectorLine)
2300
2326
  ? graphConnectorLine
2301
2327
  : undefined;
2302
- const graph = [
2303
- `<font color='${current ? "green" : running || resetting ? "orange" : "blue"}'>${escapeCardHtml(graphNodeLine)}</font>`,
2304
- ...(branchConnectorLine
2305
- ? [`<font color='grey'>${escapeCardHtml(branchConnectorLine)}</font>`]
2306
- : []),
2307
- ].join("\n");
2328
+ const color = current ? "green" : running || resetting ? "orange" : "blue";
2329
+ const nodeLanes = graphNodeLine.match(/[●│]/gu) ?? [];
2330
+ const connectorLanes = branchConnectorLine?.split(" ");
2331
+ // Each lane has its own center; shorter connectors and wider turn numbers cannot shift it.
2332
+ const graphColumns = nodeLanes.map((node, lane) => ({
2333
+ tag: "column",
2334
+ width: "16px",
2335
+ vertical_align: "top",
2336
+ padding: "0px",
2337
+ elements: [{
2338
+ ...markdown([
2339
+ `<font color='${color}'>${node}</font>`,
2340
+ ...(connectorLanes?.[lane] ? [`<font color='grey'>${escapeCardHtml(connectorLanes[lane])}</font>`] : []),
2341
+ ].join("\n")),
2342
+ text_align: "center",
2343
+ }],
2344
+ }));
2308
2345
  const trailingElements = current
2309
2346
  ? [markdown("✅ 当前")]
2310
2347
  : resetting
@@ -2325,8 +2362,20 @@ function resetHistoryEntryRow(graphNodeLine, graphConnectorLine, lines, timestam
2325
2362
  width: "auto",
2326
2363
  vertical_align: "top",
2327
2364
  elements: [{
2328
- ...markdown(graph),
2329
- text_align: "center",
2365
+ tag: "column_set",
2366
+ flex_mode: "none",
2367
+ horizontal_spacing: "0px",
2368
+ horizontal_align: "left",
2369
+ columns: [
2370
+ ...graphColumns,
2371
+ {
2372
+ tag: "column",
2373
+ width: sequenceWidth,
2374
+ vertical_align: "top",
2375
+ padding: "0px",
2376
+ elements: [{ ...markdown(`<font color='${color}'>${entry.sequence}</font>`), text_align: "left" }],
2377
+ },
2378
+ ],
2330
2379
  }],
2331
2380
  },
2332
2381
  {
@@ -2444,10 +2493,16 @@ function taskActionElement(action) {
2444
2493
  padding: "0px",
2445
2494
  has_border: false,
2446
2495
  elements: [markdown(`<font color='${action.type === "danger" ? "red" : "blue"}'>${escapeCardActionText(action.text)}</font>`)],
2447
- behaviors: [{
2448
- type: "callback",
2449
- value: action.value,
2450
- }],
2496
+ behaviors: action.url
2497
+ ? [{ type: "open_url", default_url: action.url }]
2498
+ : [{ type: "callback", value: action.value }],
2499
+ };
2500
+ }
2501
+ function turnPreviewAction(previewUrl) {
2502
+ return {
2503
+ text: "Preview",
2504
+ value: {},
2505
+ url: previewUrl,
2451
2506
  };
2452
2507
  }
2453
2508
  function escapeCardActionText(value) {