dsh-plugin-core 0.29.1 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/dist/explorer/FileBrowser.d.ts +2 -0
  2. package/dist/explorer/FileBrowser.d.ts.map +1 -1
  3. package/dist/explorer/FileBrowser.js +2 -0
  4. package/dist/explorer/FileBrowser.js.map +1 -1
  5. package/dist/explorer/open.d.ts +2 -0
  6. package/dist/explorer/open.d.ts.map +1 -1
  7. package/dist/explorer/open.js +1 -0
  8. package/dist/explorer/open.js.map +1 -1
  9. package/dist/explorer/preview/TextPreview.d.ts +2 -0
  10. package/dist/explorer/preview/TextPreview.d.ts.map +1 -1
  11. package/dist/explorer/preview/TextPreview.js +23 -10
  12. package/dist/explorer/preview/TextPreview.js.map +1 -1
  13. package/dist/explorer/preview/index.d.ts +2 -0
  14. package/dist/explorer/preview/index.d.ts.map +1 -1
  15. package/dist/explorer/preview/index.js +1 -0
  16. package/dist/explorer/preview/index.js.map +1 -1
  17. package/dist/session/SessionViewModal.d.ts +3 -8
  18. package/dist/session/SessionViewModal.d.ts.map +1 -1
  19. package/dist/session/SessionViewModal.js +78 -79
  20. package/dist/session/SessionViewModal.js.map +1 -1
  21. package/dist/session/changes.d.ts +1 -1
  22. package/dist/session/changes.d.ts.map +1 -1
  23. package/dist/session/changes.js +1 -1
  24. package/dist/session/changes.js.map +1 -1
  25. package/dist/session/faces.d.ts +24 -0
  26. package/dist/session/faces.d.ts.map +1 -1
  27. package/dist/session/index.d.ts +1 -1
  28. package/dist/session/index.d.ts.map +1 -1
  29. package/dist/session/mirror/AskCard.d.ts +35 -0
  30. package/dist/session/mirror/AskCard.d.ts.map +1 -0
  31. package/dist/session/mirror/AskCard.js +131 -0
  32. package/dist/session/mirror/AskCard.js.map +1 -0
  33. package/dist/session/mirror/ChangedFileDiff.d.ts.map +1 -1
  34. package/dist/session/mirror/ChangedFileDiff.js +8 -2
  35. package/dist/session/mirror/ChangedFileDiff.js.map +1 -1
  36. package/dist/session/mirror/ChangedFilesCard.d.ts.map +1 -1
  37. package/dist/session/mirror/ChangedFilesCard.js +8 -1
  38. package/dist/session/mirror/ChangedFilesCard.js.map +1 -1
  39. package/dist/session/mirror/ChatGroupSeat.d.ts.map +1 -1
  40. package/dist/session/mirror/ChatGroupSeat.js +2 -1
  41. package/dist/session/mirror/ChatGroupSeat.js.map +1 -1
  42. package/dist/session/mirror/ChatNodeSeat.d.ts +1 -1
  43. package/dist/session/mirror/ChatNodeSeat.d.ts.map +1 -1
  44. package/dist/session/mirror/ChatNodeSeat.js +2 -2
  45. package/dist/session/mirror/ChatNodeSeat.js.map +1 -1
  46. package/dist/session/mirror/Deliverables.d.ts.map +1 -1
  47. package/dist/session/mirror/Deliverables.js +30 -4
  48. package/dist/session/mirror/Deliverables.js.map +1 -1
  49. package/dist/session/mirror/GenericCommandCard.d.ts +56 -2
  50. package/dist/session/mirror/GenericCommandCard.d.ts.map +1 -1
  51. package/dist/session/mirror/GenericCommandCard.js +360 -46
  52. package/dist/session/mirror/GenericCommandCard.js.map +1 -1
  53. package/dist/session/mirror/MessageItem.d.ts +5 -0
  54. package/dist/session/mirror/MessageItem.d.ts.map +1 -1
  55. package/dist/session/mirror/MessageItem.js +12 -3
  56. package/dist/session/mirror/MessageItem.js.map +1 -1
  57. package/dist/session/mirror/StatDialog.d.ts.map +1 -1
  58. package/dist/session/mirror/StatDialog.js +14 -1
  59. package/dist/session/mirror/StatDialog.js.map +1 -1
  60. package/dist/session/mirror/ToolDetails.d.ts +65 -0
  61. package/dist/session/mirror/ToolDetails.d.ts.map +1 -0
  62. package/dist/session/mirror/ToolDetails.js +268 -0
  63. package/dist/session/mirror/ToolDetails.js.map +1 -0
  64. package/dist/session/mirror/control-details.d.ts +9 -0
  65. package/dist/session/mirror/control-details.d.ts.map +1 -0
  66. package/dist/session/mirror/control-details.js +549 -0
  67. package/dist/session/mirror/control-details.js.map +1 -0
  68. package/dist/session/mirror/detail-i18n.d.ts +4 -0
  69. package/dist/session/mirror/detail-i18n.d.ts.map +1 -0
  70. package/dist/session/mirror/detail-i18n.js +153 -0
  71. package/dist/session/mirror/detail-i18n.js.map +1 -0
  72. package/dist/session/official-classes.d.ts.map +1 -1
  73. package/dist/session/official-classes.js +4 -0
  74. package/dist/session/official-classes.js.map +1 -1
  75. package/dist/session/pending-inputs.d.ts +11 -0
  76. package/dist/session/pending-inputs.d.ts.map +1 -0
  77. package/dist/session/pending-inputs.js +31 -0
  78. package/dist/session/pending-inputs.js.map +1 -0
  79. package/dist/session/tail-follow.d.ts +29 -0
  80. package/dist/session/tail-follow.d.ts.map +1 -0
  81. package/dist/session/tail-follow.js +106 -0
  82. package/dist/session/tail-follow.js.map +1 -0
  83. package/dist/ui/CodeViewer.d.ts +2 -0
  84. package/dist/ui/CodeViewer.d.ts.map +1 -1
  85. package/dist/ui/CodeViewer.js +13 -1
  86. package/dist/ui/CodeViewer.js.map +1 -1
  87. package/dist/ui/FlipText.d.ts +5 -0
  88. package/dist/ui/FlipText.d.ts.map +1 -1
  89. package/dist/ui/FlipText.js +2 -1
  90. package/dist/ui/FlipText.js.map +1 -1
  91. package/dist/ui/Modal.js +1 -1
  92. package/dist/ui/Modal.js.map +1 -1
  93. package/dist/ui/SideSheet.js +1 -1
  94. package/dist/ui/SideSheet.js.map +1 -1
  95. package/dist/ui/flip-css.generated.d.ts +1 -1
  96. package/dist/ui/flip-css.generated.d.ts.map +1 -1
  97. package/dist/ui/flip-css.generated.js +1 -1
  98. package/dist/ui/flip-css.generated.js.map +1 -1
  99. package/dist/ui/host-data.d.ts +13 -3
  100. package/dist/ui/host-data.d.ts.map +1 -1
  101. package/dist/ui/host-data.js +13 -4
  102. package/dist/ui/host-data.js.map +1 -1
  103. package/dist/utils/i18n.d.ts +1 -1
  104. package/dist/utils/i18n.d.ts.map +1 -1
  105. package/dist/utils/i18n.js +424 -0
  106. package/dist/utils/i18n.js.map +1 -1
  107. package/docs/design/external/dsh-host.md +34 -0
  108. package/docs/help/explorer.doc.ts +9 -0
  109. package/docs/help/explorer.md +1 -0
  110. package/docs/help/integration.doc.ts +1 -1
  111. package/docs/help/integration.md +1 -1
  112. package/docs/help/session.doc.ts +6 -7
  113. package/docs/help/session.md +5 -6
  114. package/docs/help/ui.doc.ts +11 -3
  115. package/docs/help/ui.md +10 -2
  116. package/package.json +1 -1
@@ -6,8 +6,57 @@ export declare const classifyTool: (name: string) => Variant;
6
6
  export declare const toolTitleKey: (name: string) => UtilMessageKey;
7
7
  /** 官方 deriveSummary(tool client.js:221-233)。 */
8
8
  export declare function deriveSummary(variant: Variant, argsRaw: string): string;
9
+ /** 官方 readCallLine(tool client.js:432-436):read 的 offset(1 起)就是落点行,参数非法则无行。 */
10
+ export declare function readCallLine(name: string, argsRaw: string): number | undefined;
9
11
  /** 官方 formatToolBody(tool client.js:255-264):通用展开体的输入正文。 */
10
12
  export declare function formatToolBody(variant: Variant, argsRaw: string): string | null;
13
+ /** 搜索结果卡两面(官方 searchCardModel 的返回;recovery = 截断时的完整结果正文)。 */
14
+ interface SearchFace {
15
+ card: {
16
+ kind: 'matches';
17
+ files: SearchFile[];
18
+ total: number;
19
+ truncated: boolean;
20
+ } | {
21
+ kind: 'paths';
22
+ paths: string[];
23
+ total: number;
24
+ truncated: boolean;
25
+ };
26
+ recovery?: string;
27
+ }
28
+ interface SearchFile {
29
+ path: string;
30
+ matches: {
31
+ lineNumber: number;
32
+ line: string;
33
+ }[];
34
+ }
35
+ /**
36
+ * 官方 searchCardModel(tool client.js:632-667):结算成功 + meta.{truncated,total} 齐全才出卡,
37
+ * 否则落回 ioCard 兜底(与官方 generic 路径一致)。
38
+ */
39
+ export declare function searchCardModel(name: string, argsRaw: string, output: string, meta: unknown, isError: boolean, settled: boolean): SearchFace | null;
40
+ /** 网页卡两面(官方 webCardModel 直接返回的可展开体形状)。 */
41
+ type WebFace = {
42
+ kind: 'search';
43
+ answer?: string;
44
+ sources: WebSource[];
45
+ truncated: boolean;
46
+ } | {
47
+ kind: 'fetch';
48
+ url: string;
49
+ statusCode: number;
50
+ truncated: boolean;
51
+ };
52
+ interface WebSource {
53
+ url: string;
54
+ title?: string;
55
+ snippet?: string;
56
+ publishedAt?: string;
57
+ }
58
+ /** 官方 webCardModel(tool client.js:1070-1094)。 */
59
+ export declare function webCardModel(name: string, argsRaw: string, meta: unknown, isError: boolean, settled: boolean): WebFace | null;
11
60
  /** 终端卡规格(官方 localizeTerminalCardModel 的 card 面;send 的命令/描述在组件侧词典化)。 */
12
61
  export interface TerminalFace {
13
62
  command: string;
@@ -75,8 +124,13 @@ export declare function GenericCommandCard(props: {
75
124
  phase?: 'preparing' | 'start';
76
125
  /** root.error.code === 'interrupted' ⇒ 官方 stopped 态。 */
77
126
  interrupted?: boolean;
78
- /** 统一 openFile 入口:read/write/edit 摘要路径渲染成官方 fileLink。 */
79
- onOpenFile?: (path: string) => void;
127
+ /** root.error.code(ASK_CANCELLED / ASK_ABORTED / …)。 */
128
+ errorCode?: string;
129
+ /** 统一 openFile 入口:read/write/edit 摘要路径渲染成官方 fileLink(read 带 offset 落点行)。 */
130
+ onOpenFile?: (path: string, options?: {
131
+ line?: number;
132
+ }) => void;
80
133
  t: Translate;
81
134
  }): ReturnType<typeof h>;
135
+ export {};
82
136
  //# sourceMappingURL=GenericCommandCard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GenericCommandCard.d.ts","sourceRoot":"","sources":["../../../src/session/mirror/GenericCommandCard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GenericCommandCard.d.ts","sourceRoot":"","sources":["../../../src/session/mirror/GenericCommandCard.ts"],"names":[],"mappings":"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"}
@@ -3,15 +3,21 @@
3
3
  // 本文件名沿用历史,实际镜像 GenericToolCard + ToolRow 一套)。
4
4
  // 展开体分发链照官方 ToolRow(lib/client.js:1598-1688):
5
5
  // TerminalBlock(bash/pwsh/terminal_send,maxLines:∞)→ DiffBlock(write/edit,maxLines:9)
6
- // → ReadBlock(read,maxLines:8 = 头 4 + 尾 4,中间「… 其余 N 行」)→ 兜底 ioCard 灰框(输入/分隔/输出)。
6
+ // → ReadBlock(read,maxLines:8 = 头 4 + 尾 4,中间「… 其余 N 行」)
7
+ // → SearchBlock(grep/glob,maxLines:8 + 截断 recovery 正文)→ WebBlock(web_search/web_fetch)
8
+ // → ToolDetails(goal/schedule 两族)→ 兜底 ioCard 灰框(输入/分隔/输出)。
9
+ // ask_user_question 走 AskQuestionCard,插在整条链之前。
7
10
  // 数据模型照官方 models/*(行号为 lib/client.js):toolRowModel 273、diffCardModel 534、
8
11
  // readCardModel 421、terminalCardModel 929、parseExitStatus 903、hasSpillNotice 692;
9
12
  // 摘要与五态同构:state = preparing|running|ok|error|stopped(成功结算但退出码非 0 ⇒ error,1767);
10
13
  // summary = [generic? 工具名, deriveSummary],终端卡优先 description;error 态摘要 = 输出首行。
11
14
  import { Fragment, createElement as h, useMemo, useState } from 'react';
12
- import { DiffBlock, DisclosureRow, IconApiOutlineRegular, IconBrowseOutlineRegular, IconCodeOutlineRegular, IconEditOutlineRegular, IconSearchOutlineRegular, IconSparkleRegular, ReadBlock, TerminalBlock, TextShimmer, diffTotals, } from '../../ui/official.js';
15
+ import { DiffBlock, DisclosureRow, IconApiOutlineRegular, IconBrowseOutlineRegular, IconCodeOutlineRegular, IconEditOutlineRegular, IconSearchOutlineRegular, IconSparkleRegular, ReadBlock, SearchBlock, TerminalBlock, TextShimmer, WebBlock, diffTotals, } from '../../ui/official.js';
13
16
  import { officialClass } from '../official-classes.js';
14
17
  import { CodeViewer } from '../../ui/CodeViewer.js';
18
+ import { markdownLabels } from '../../explorer/preview/md-labels.js';
19
+ import { AskQuestionCardView, askCardModel } from './AskCard.js';
20
+ import { ToolDetailsView, detailsCardModel, detailsSummary } from './ToolDetails.js';
15
21
  /** 官方 TOOL_VARIANTS(tool client.js:83-100,cordis_* 一并保留)。 */
16
22
  const TOOL_VARIANTS = {
17
23
  bash: 'bash',
@@ -43,12 +49,56 @@ const VARIANT_TITLE_KEYS = {
43
49
  others: 'toolTitleGeneric',
44
50
  };
45
51
  const TOOL_TITLE_KEYS = {
46
- pwsh: 'toolTitleBash',
52
+ pwsh: 'toolTitlePwsh',
47
53
  read_image: 'toolTitleReadImage',
48
54
  grep: 'toolTitleGrep',
49
55
  glob: 'toolTitleGlob',
50
56
  web_search: 'toolTitleWebSearch',
51
57
  web_fetch: 'toolTitleWebFetch',
58
+ todo_write: 'toolTitleTodo',
59
+ ask_user_question: 'toolTitleAsk',
60
+ cordis_package_inspect: 'toolTitleInspect',
61
+ cordis_runtime_inspect: 'toolTitleInspect',
62
+ cordis_run: 'toolTitleRunCordis',
63
+ cordis_stop: 'toolTitleStopCordis',
64
+ cordis_undefine: 'toolTitleRemoveCordis',
65
+ cordis_inspect_list: 'toolTitleInspectProviders',
66
+ cordis_inspect_query: 'toolTitleQueryRuntime',
67
+ cordis_inspect_self: 'toolTitleInspectPlugins',
68
+ create_goal: 'toolTitleCreateGoal',
69
+ get_goal: 'toolTitleGetGoal',
70
+ update_goal: 'toolTitleUpdateGoal',
71
+ schedule_create: 'toolTitleCreateSchedule',
72
+ schedule_list: 'toolTitleListSchedules',
73
+ schedule_delete: 'toolTitleDeleteSchedule',
74
+ schedule_update: 'toolTitleUpdateSchedule',
75
+ workflow: 'toolTitleWorkflow',
76
+ ralph: 'toolTitleRalph',
77
+ session_event_read: 'toolTitleReadEvent',
78
+ session_event_search: 'toolTitleSearchEvents',
79
+ session_event_trace: 'toolTitleTraceEvent',
80
+ session_search: 'toolTitleSearchSessions',
81
+ session_trace: 'toolTitleTraceSession',
82
+ list_subagent_models: 'toolTitleListModels',
83
+ subagent: 'toolTitleSubagent',
84
+ list_agents: 'toolTitleListAgents',
85
+ send_message: 'toolTitleSendMessage',
86
+ interrupt_agent: 'toolTitleInterruptAgent',
87
+ job_list: 'toolTitleListJobs',
88
+ job_output: 'toolTitleReadJob',
89
+ job_kill: 'toolTitleKillJob',
90
+ terminal_open: 'toolTitleOpenTerminal',
91
+ terminal_read: 'toolTitleReadTerminal',
92
+ terminal_list: 'toolTitleListTerminals',
93
+ terminal_signal: 'toolTitleSignalTerminal',
94
+ terminal_close: 'toolTitleCloseTerminal',
95
+ lsp: 'toolTitleLsp',
96
+ spawn_teammate: 'toolTitleSpawnTeammate',
97
+ team_task_create: 'toolTitleCreateTeamTask',
98
+ team_task_get: 'toolTitleGetTeamTask',
99
+ team_task_update: 'toolTitleUpdateTeamTask',
100
+ team_task_list: 'toolTitleListTeamTasks',
101
+ wait_agent: 'toolTitleWaitAgent',
52
102
  };
53
103
  export const toolTitleKey = (name) => TOOL_TITLE_KEYS[name] ?? VARIANT_TITLE_KEYS[classifyTool(name)];
54
104
  /** 官方 VARIANT_ICONS(tool client.js:1749-1757,size 14)。 */
@@ -123,6 +173,22 @@ function deriveFilePath(variant, argsRaw) {
123
173
  const picked = pickString(parsed, ['path', 'file_path']);
124
174
  return picked === undefined ? undefined : firstLine(picked);
125
175
  }
176
+ /** 官方 readCallLine(tool client.js:432-436):read 的 offset(1 起)就是落点行,参数非法则无行。 */
177
+ export function readCallLine(name, argsRaw) {
178
+ if (name !== 'read')
179
+ return undefined;
180
+ const parsed = parseArgs(argsRaw);
181
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
182
+ return undefined;
183
+ const { file_path, offset, limit } = parsed;
184
+ if (typeof file_path !== 'string' || file_path.trim() === '')
185
+ return undefined;
186
+ if (offset !== undefined && !positiveInteger(offset))
187
+ return undefined;
188
+ if (limit !== undefined && !positiveInteger(limit))
189
+ return undefined;
190
+ return positiveInteger(offset) ? offset : undefined;
191
+ }
126
192
  /** 官方 formatToolBody(tool client.js:255-264):通用展开体的输入正文。 */
127
193
  export function formatToolBody(variant, argsRaw) {
128
194
  if (argsRaw === '')
@@ -284,6 +350,164 @@ function readCardModel(name, argsRaw, output, meta, isError, settled) {
284
350
  return null;
285
351
  return face;
286
352
  }
353
+ /** 官方 validInclude(tool client.js:590-597):逗号分隔的多 pattern include 不收。 */
354
+ function validInclude(include) {
355
+ if (include.trim() === '' || include.startsWith('!'))
356
+ return false;
357
+ let braceDepth = 0;
358
+ for (const character of include) {
359
+ if (character === '{')
360
+ braceDepth += 1;
361
+ else if (character === '}')
362
+ braceDepth = Math.max(0, braceDepth - 1);
363
+ else if (character === ',' && braceDepth === 0)
364
+ return false;
365
+ }
366
+ return true;
367
+ }
368
+ /** 官方 validSearchCall(tool client.js:575-589)。 */
369
+ function validSearchCall(name, argsRaw) {
370
+ if (name !== 'grep' && name !== 'glob')
371
+ return null;
372
+ const parsed = parseArgs(argsRaw);
373
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
374
+ return null;
375
+ const { pattern, path, include } = parsed;
376
+ if (typeof pattern !== 'string')
377
+ return null;
378
+ if (name === 'grep' && pattern === '')
379
+ return null;
380
+ if (name === 'glob' && pattern.trim() === '')
381
+ return null;
382
+ if (path !== undefined && (typeof path !== 'string' || path.trim() === ''))
383
+ return null;
384
+ if (name === 'grep' && include !== undefined && (typeof include !== 'string' || !validInclude(include)))
385
+ return null;
386
+ return name;
387
+ }
388
+ /** 官方 searchFiles(tool client.js:598-622):meta.files 收窄。 */
389
+ function searchFiles(value) {
390
+ if (!Array.isArray(value))
391
+ return null;
392
+ const files = [];
393
+ for (const file of value) {
394
+ if (typeof file !== 'object' || file === null || Array.isArray(file))
395
+ return null;
396
+ const { path, matches } = file;
397
+ if (typeof path !== 'string' || !Array.isArray(matches))
398
+ return null;
399
+ const narrowed = [];
400
+ for (const match of matches) {
401
+ if (typeof match !== 'object' || match === null || Array.isArray(match))
402
+ return null;
403
+ const { lineNumber, line } = match;
404
+ if (typeof lineNumber !== 'number' || !Number.isInteger(lineNumber) || lineNumber < 1)
405
+ return null;
406
+ if (typeof line !== 'string')
407
+ return null;
408
+ narrowed.push({ lineNumber, line });
409
+ }
410
+ files.push({ path, matches: narrowed });
411
+ }
412
+ return files;
413
+ }
414
+ /**
415
+ * 官方 searchCardModel(tool client.js:632-667):结算成功 + meta.{truncated,total} 齐全才出卡,
416
+ * 否则落回 ioCard 兜底(与官方 generic 路径一致)。
417
+ */
418
+ export function searchCardModel(name, argsRaw, output, meta, isError, settled) {
419
+ if (!settled || isError)
420
+ return null;
421
+ const tool = validSearchCall(name, argsRaw);
422
+ if (tool === null)
423
+ return null;
424
+ if (typeof meta !== 'object' || meta === null || Array.isArray(meta))
425
+ return null;
426
+ const m = meta;
427
+ if (typeof m.truncated !== 'boolean')
428
+ return null;
429
+ if (typeof m.total !== 'number' || !Number.isInteger(m.total) || m.total < 0)
430
+ return null;
431
+ const common = { total: m.total, truncated: m.truncated };
432
+ // 官方 recovery = flattenContent(block.content):截断时把完整正文摊在卡下方。
433
+ const recovery = m.truncated && output !== '' ? output : undefined;
434
+ if (tool === 'grep') {
435
+ if (m.shape !== 'matches')
436
+ return null;
437
+ const files = searchFiles(m.files);
438
+ return files === null ? null : { card: { kind: 'matches', files, ...common }, ...(recovery === undefined ? {} : { recovery }) };
439
+ }
440
+ if (m.shape !== 'paths' || !Array.isArray(m.paths))
441
+ return null;
442
+ if (!m.paths.every(path => typeof path === 'string'))
443
+ return null;
444
+ return { card: { kind: 'paths', paths: [...m.paths], ...common }, ...(recovery === undefined ? {} : { recovery }) };
445
+ }
446
+ /** 官方 validWebCall(tool client.js:1024-1045)。 */
447
+ function validWebCall(name, argsRaw) {
448
+ if (name !== 'web_search' && name !== 'web_fetch')
449
+ return null;
450
+ const parsed = parseArgs(argsRaw);
451
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
452
+ return null;
453
+ const args = parsed;
454
+ if (name === 'web_search') {
455
+ const { queries } = args;
456
+ if (!Array.isArray(queries) || queries.length === 0)
457
+ return null;
458
+ return queries.every(query => typeof query === 'string' && query.trim() !== '') ? name : null;
459
+ }
460
+ const { url } = args;
461
+ return typeof url === 'string' && url.trim() !== '' ? name : null;
462
+ }
463
+ /** 官方 webSources(tool client.js:1046-1064):meta.sources 收窄(可选字段缺省即不带)。 */
464
+ function webSources(value) {
465
+ if (!Array.isArray(value))
466
+ return null;
467
+ const sources = [];
468
+ for (const source of value) {
469
+ if (typeof source !== 'object' || source === null || Array.isArray(source))
470
+ return null;
471
+ const { url, title, snippet, publishedAt } = source;
472
+ if (typeof url !== 'string')
473
+ return null;
474
+ if (title !== undefined && typeof title !== 'string')
475
+ return null;
476
+ if (snippet !== undefined && typeof snippet !== 'string')
477
+ return null;
478
+ if (publishedAt !== undefined && typeof publishedAt !== 'string')
479
+ return null;
480
+ sources.push({
481
+ url,
482
+ ...(title === undefined ? {} : { title }),
483
+ ...(snippet === undefined ? {} : { snippet }),
484
+ ...(publishedAt === undefined ? {} : { publishedAt }),
485
+ });
486
+ }
487
+ return sources;
488
+ }
489
+ /** 官方 webCardModel(tool client.js:1070-1094)。 */
490
+ export function webCardModel(name, argsRaw, meta, isError, settled) {
491
+ if (!settled || isError)
492
+ return null;
493
+ const tool = validWebCall(name, argsRaw);
494
+ if (tool === null || typeof meta !== 'object' || meta === null || Array.isArray(meta))
495
+ return null;
496
+ const m = meta;
497
+ if (typeof m.truncated !== 'boolean')
498
+ return null;
499
+ if (tool === 'web_search') {
500
+ const sources = webSources(m.sources);
501
+ if (sources === null || (m.answer !== undefined && typeof m.answer !== 'string'))
502
+ return null;
503
+ return { kind: 'search', ...(typeof m.answer === 'string' ? { answer: m.answer } : {}), sources, truncated: m.truncated };
504
+ }
505
+ if (typeof m.url !== 'string')
506
+ return null;
507
+ if (typeof m.statusCode !== 'number' || !Number.isInteger(m.statusCode))
508
+ return null;
509
+ return { kind: 'fetch', url: m.url, statusCode: m.statusCode, truncated: m.truncated };
510
+ }
287
511
  /** 官方 shellCall(tool client.js:831-855):无 description = persistent(结算走 generic)。 */
288
512
  export function shellCall(name, args) {
289
513
  if (name !== 'bash' && name !== 'pwsh')
@@ -403,6 +627,31 @@ function contentKilobytes(argsRaw) {
403
627
  }
404
628
  return any ? Math.ceil(chars / 1024) : null;
405
629
  }
630
+ /** 官方 todo 行摘要(tool client.js:4480-4503):done/total + 首个 in_progress 内容,
631
+ * 多条并行 in_progress ⇒ 额外条数走 summarySuffix「+N」。 */
632
+ function todoSummary(argsRaw, t) {
633
+ if (argsRaw === '')
634
+ return null;
635
+ let parsed;
636
+ try {
637
+ parsed = JSON.parse(argsRaw);
638
+ }
639
+ catch {
640
+ return null;
641
+ }
642
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
643
+ return null;
644
+ const todos = parsed.todos;
645
+ if (!Array.isArray(todos) || !todos.every(item => typeof item === 'object' && item !== null))
646
+ return null;
647
+ const list = todos;
648
+ const done = list.filter(item => item.status === 'completed').length;
649
+ const active = list.filter(item => item.status === 'in_progress');
650
+ const first = active[0]?.content;
651
+ const named = typeof first === 'string' && first.trim() !== '';
652
+ const head = t('todoCompleted', { done, total: list.length });
653
+ return { text: named ? `${head} · ${first}` : head, extra: named ? active.length - 1 : 0 };
654
+ }
406
655
  /** 词典:代码工具栏(官方 codeToolbarLabels,tool client.js:1098-1104)。 */
407
656
  const codeToolbarLabels = (t) => ({
408
657
  codeLabel: t('codeBlockLabel'),
@@ -430,6 +679,30 @@ const readLabels = (t) => ({
430
679
  collapse: t('collapseLabel'),
431
680
  expand: (count) => t('readExpandRest', { count }),
432
681
  });
682
+ /** 官方 searchBlockLabels(tool client.js:1222-1240)。 */
683
+ const searchLabels = (t) => ({
684
+ pathsSummary: (shown, total, truncated) => truncated
685
+ ? t('searchPathsTruncated', { shown, total })
686
+ : t('searchPaths', { shown }),
687
+ matchesSummary: (shown, total, files, truncated) => truncated
688
+ ? t('searchMatchesTruncated', { shown, total, files })
689
+ : t('searchMatches', { shown, files }),
690
+ copy: t('copyLabel'),
691
+ copied: t('copiedLabel'),
692
+ noResults: t('searchNoResults'),
693
+ collapseAria: t('searchCollapseAria'),
694
+ expandAria: (count) => t('searchExpandAria', { count }),
695
+ collapse: t('collapseLabel'),
696
+ expand: (count) => t('searchExpandRest', { count }),
697
+ });
698
+ /** 官方 webBlockLabels(tool client.js:1247-1255);markdown 复用 core 的 MarkdownText 文案。 */
699
+ const webLabels = (t) => ({
700
+ noResults: t('webNoResults'),
701
+ sourcesTruncated: t('webSourcesTruncated'),
702
+ http: t('webHttp'),
703
+ contentTruncated: t('webContentTruncated'),
704
+ markdown: markdownLabels(),
705
+ });
433
706
  /** 官方 terminalBlockLabels(tool client.js:708-737 的键面)。 */
434
707
  export const terminalLabels = (t) => ({
435
708
  // 官方 terminalBlockLabels(ui-tool terminal-card-model.ts):commandLine 是**函数**,
@@ -465,7 +738,7 @@ export function ExitCodeBadge({ label }) {
465
738
  * 折叠行 = 图标 + 标题 [+ 分隔点 + 摘要(文件路径链接化)+ 后缀];展开体按官方分发链。
466
739
  */
467
740
  export function GenericCommandCard(props) {
468
- const { name, argsRaw, output, isError, meta, settled = true, phase, interrupted, onOpenFile, t } = props;
741
+ const { name, argsRaw, output, isError, meta, settled = true, phase, interrupted, errorCode, onOpenFile, t } = props;
469
742
  const [expanded, setExpanded] = useState(false);
470
743
  const variant = classifyTool(name);
471
744
  const titleKey = toolTitleKey(name);
@@ -475,6 +748,10 @@ export function GenericCommandCard(props) {
475
748
  const terminalFace = useMemo(() => terminalCardModel(name, argsRaw, output, isError, settled), [name, argsRaw, output, isError, settled]);
476
749
  const read = useMemo(() => readCardModel(name, argsRaw, output, meta, isError, settled), [name, argsRaw, output, meta, isError, settled]);
477
750
  const diffs = useMemo(() => diffCardModel(name, argsRaw, meta, isError, settled), [name, argsRaw, meta, isError, settled]);
751
+ const search = useMemo(() => searchCardModel(name, argsRaw, output, meta, isError, settled), [name, argsRaw, output, meta, isError, settled]);
752
+ const web = useMemo(() => webCardModel(name, argsRaw, meta, isError, settled), [name, argsRaw, meta, isError, settled]);
753
+ const ask = useMemo(() => askCardModel(name, argsRaw, output, errorCode, settled, t), [name, argsRaw, output, errorCode, settled, t]);
754
+ const details = useMemo(() => detailsCardModel(name, argsRaw, output, settled, isError, t), [name, argsRaw, output, settled, isError, t]);
478
755
  // 终端卡展开体(官方 localizeTerminalCardModel:send 命令空 = (发送输入),描述 = 终端 {sessionId})。
479
756
  const terminal = useMemo(() => {
480
757
  if (terminalFace === null)
@@ -486,13 +763,17 @@ export function GenericCommandCard(props) {
486
763
  // 官方 terminalFailed(tool client.js:763-766):成功结算但退出码非 0 / 有信号 ⇒ 整行 error。
487
764
  const failedTerminal = terminal !== null && terminal.running !== true
488
765
  && ((terminal.exitCode !== undefined && terminal.exitCode !== 0) || terminal.signal !== undefined);
489
- const rowState = state === 'ok' && failedTerminal ? 'error' : state;
766
+ // 官方 AskQuestionRow 强制态(2298-2316):取消 ⇒ ok、中断 ⇒ stopped,优先于 error。
767
+ const rowState = ask?.state ?? (state === 'ok' && failedTerminal ? 'error' : state);
490
768
  const running = rowState === 'running' || rowState === 'preparing';
491
769
  // 摘要(官方 toolRowModel 273-295 + ToolRow 1527-1528):generic 标题补工具名;
492
770
  // 终端卡优先 description;error 态摘要 = 输出首行。
493
771
  const generic = titleKey === 'toolTitleGeneric';
494
772
  const base = argsRaw === '' ? '' : deriveSummary(variant, argsRaw);
495
773
  const plainSummary = [generic ? name : '', base].filter(Boolean).join(' · ');
774
+ const todoInfo = name === 'todo_write' ? todoSummary(argsRaw, t) : null;
775
+ const detailsText = details === null ? undefined : detailsSummary(details);
776
+ const normalSummary = ask !== null ? ask.summary : detailsText ?? (todoInfo !== null ? todoInfo.text : terminal?.description ?? plainSummary);
496
777
  const errorSummary = rowState === 'error' && output !== '' ? firstLine(output) : null;
497
778
  // 官方 terminalExitLabel(tool client.js:801-809):已失败前台命令才出退出码徽章。
498
779
  const exitLabel = failedTerminal
@@ -502,17 +783,28 @@ export function GenericCommandCard(props) {
502
783
  ? t('terminalNoExitCode')
503
784
  : t('terminalExitCode', { code: terminal.exitCode })
504
785
  : null;
505
- const summaryText = (rowState === 'error' && exitLabel === null ? errorSummary ?? (terminal?.description ?? plainSummary) : null) ?? terminal?.description ?? plainSummary;
786
+ const summaryText = (rowState === 'error' && exitLabel === null ? errorSummary ?? normalSummary : null) ?? normalSummary;
506
787
  // 官方 ToolRow 两个独立后缀槽(1600-1602):summarySuffix(edit/write 内容 KB)与 diffStat(+N -M)。
507
788
  const totals = diffs === null ? null : diffTotals(diffs);
508
789
  const settledWithCue = rowState === 'error' || rowState === 'stopped';
509
790
  const kilobytes = variant === 'edit' || variant === 'write' ? contentKilobytes(argsRaw) : null;
510
- const summarySuffix = settledWithCue || kilobytes === null || summaryText === '' ? null : t('toolPreparingContent', { kilobytes });
791
+ const summarySuffix = settledWithCue
792
+ ? null
793
+ : todoInfo !== null
794
+ ? (todoInfo.extra > 0 ? `+${todoInfo.extra}` : null)
795
+ : (kilobytes === null || summaryText === '' ? null : t('toolPreparingContent', { kilobytes }));
511
796
  const diffStatTotals = settledWithCue ? null : totals;
512
797
  // 官方 fileLink(1536-1545):read/write/edit 摘要路径 + onOpenFile + 非 error/stopped ⇒ 链接钮。
513
798
  const filePath = argsRaw === '' ? undefined : deriveFilePath(variant, argsRaw);
799
+ // 官方 readCallLine(tool client.js:432-436):read 的 offset 就是落点行,链接可带过去。
800
+ const filePathLine = filePath === undefined ? undefined : readCallLine(name, argsRaw);
514
801
  const openFile = filePath !== undefined && onOpenFile !== undefined && !settledWithCue
515
- ? () => { onOpenFile(filePath); }
802
+ ? () => {
803
+ if (filePathLine === undefined)
804
+ onOpenFile(filePath);
805
+ else
806
+ onOpenFile(filePath, { line: filePathLine });
807
+ }
516
808
  : undefined;
517
809
  // 官方 linkHref(tool client.js:1100-1110):web_fetch 且 args.url 为 http(s) ⇒ 摘要外链。
518
810
  const linkHref = (() => {
@@ -533,14 +825,21 @@ export function GenericCommandCard(props) {
533
825
  }
534
826
  })();
535
827
  // 展开体(官方 1514-1550):input/output/card 三源;bodyText 仅展开且无专属卡时格式化。
536
- const inputRaw = argsRaw === '' ? null : argsRaw;
828
+ // 官方 singleFile(1876/1885):摘要已是文件路径链接的工具(read)不再摊原始输入 JSON。
829
+ const inputRaw = argsRaw === '' || filePath !== undefined ? null : argsRaw;
537
830
  const outputText = output === '' ? null : output;
538
- const card = terminal !== null ? 'terminal' : diffs !== null ? 'diff' : read !== null ? 'read' : null;
831
+ const card = terminal !== null ? 'terminal' : diffs !== null ? 'diff' : read !== null ? 'read' : search !== null ? 'search' : web !== null ? 'web' : details !== null ? 'details' : null;
539
832
  const bodyText = expanded && card === null && inputRaw !== null ? formatToolBody(variant, inputRaw) : null;
540
833
  const cardBody = variant === 'code' ? null : bodyText;
541
834
  const expandable = rowState !== 'preparing' && (inputRaw !== null || outputText !== null || card !== null);
542
835
  const open = expanded && expandable;
543
- const blockLabels = useMemo(() => ({ diff: diffLabels(t), read: readLabels(t), terminal: terminalLabels(t) }), [t]);
836
+ const blockLabels = useMemo(() => ({
837
+ diff: diffLabels(t),
838
+ read: readLabels(t),
839
+ search: searchLabels(t),
840
+ web: webLabels(t),
841
+ terminal: terminalLabels(t),
842
+ }), [t]);
544
843
  const statusText = rowState === 'preparing' ? t('rowPreparing')
545
844
  : rowState === 'running' ? t('rowRunning')
546
845
  : rowState === 'error' ? t('rowFailed')
@@ -573,41 +872,56 @@ export function GenericCommandCard(props) {
573
872
  active: running,
574
873
  }, h('span', { className: officialClass('ToolRow', 'diffAdded') ?? '' }, `+${diffStatTotals.added}`), ' ', h('span', { className: officialClass('ToolRow', 'diffRemoved') ?? '' }, `-${diffStatTotals.removed}`))
575
874
  : null);
576
- const expandedContent = open ? h('div', { className: officialClass('ToolRow', 'bodyWrap') ?? '' }, terminal !== null
577
- ? h(TerminalBlock, {
578
- command: terminal.command,
579
- cwd: terminal.cwd,
580
- output: terminal.output,
581
- exitCode: terminal.exitCode,
582
- signal: terminal.signal,
583
- running: terminal.running,
584
- maxLines: Infinity,
585
- labels: blockLabels.terminal,
586
- className: officialClass('ToolRow', 'terminalBody') ?? '',
587
- })
588
- : diffs !== null
589
- ? h(DiffBlock, { diffs, labels: blockLabels.diff, maxLines: 9, className: officialClass('ToolRow', 'diffBody') ?? '' })
590
- : read !== null
591
- ? h(ReadBlock, {
592
- label: read.label,
593
- lines: read.lines,
594
- totalLines: read.totalLines,
595
- lang: read.lang,
596
- labels: blockLabels.read,
597
- maxLines: 8,
598
- className: officialClass('ToolRow', 'readBody') ?? '',
599
- })
600
- : h(Fragment, null, variant === 'code' && bodyText !== null
601
- ? h('div', { className: officialClass('ToolRow', 'bodyScroll') ?? '' }, h(CodeViewer, {
602
- text: bodyText,
603
- path: 'tool-code.ts',
604
- t,
605
- className: officialClass('ToolRow', 'codeBody') ?? '',
606
- height: 'auto',
607
- style: { height: 'auto' },
608
- }))
609
- : null, (cardBody !== null || outputText !== null) && h('div', { className: officialClass('ToolRow', 'ioCard') ?? '' }, cardBody !== null && h('div', { className: officialClass('ToolRow', 'ioSection') ?? '' }, h('span', { className: officialClass('ToolRow', 'ioLabel') ?? '' }, t('toolInputLabel')), h('span', { className: officialClass('ToolRow', 'ioText') ?? '' }, cardBody)), cardBody !== null && outputText !== null
610
- && h('span', { className: officialClass('ToolRow', 'ioDivider') ?? '', 'aria-hidden': true }), outputText !== null && h('div', { className: officialClass('ToolRow', 'ioSection') ?? '' }, h('span', { className: officialClass('ToolRow', 'ioLabel') ?? '' }, t('toolOutputLabel')), h('span', { className: officialClass('ToolRow', 'ioText') ?? '', 'data-error': rowState === 'error' || undefined }, outputText))))) : undefined;
875
+ const expandedContent = open ? h('div', { className: officialClass('ToolRow', 'bodyWrap') ?? '' }, ask?.card !== undefined
876
+ ? h(AskQuestionCardView, { card: ask.card })
877
+ : terminal !== null
878
+ ? h(TerminalBlock, {
879
+ command: terminal.command,
880
+ cwd: terminal.cwd,
881
+ output: terminal.output,
882
+ exitCode: terminal.exitCode,
883
+ signal: terminal.signal,
884
+ running: terminal.running,
885
+ maxLines: Infinity,
886
+ labels: blockLabels.terminal,
887
+ className: officialClass('ToolRow', 'terminalBody') ?? '',
888
+ })
889
+ : diffs !== null
890
+ ? h(DiffBlock, { diffs, labels: blockLabels.diff, maxLines: 9, className: officialClass('ToolRow', 'diffBody') ?? '' })
891
+ : read !== null
892
+ ? h(ReadBlock, {
893
+ label: read.label,
894
+ lines: read.lines,
895
+ totalLines: read.totalLines,
896
+ lang: read.lang,
897
+ labels: blockLabels.read,
898
+ maxLines: 8,
899
+ className: officialClass('ToolRow', 'readBody') ?? '',
900
+ })
901
+ : search !== null
902
+ ? h(Fragment, null, h(SearchBlock, {
903
+ ...search.card,
904
+ labels: blockLabels.search,
905
+ maxLines: 8,
906
+ className: officialClass('ToolRow', 'searchBody') ?? '',
907
+ }), search.recovery !== undefined
908
+ ? h('div', { className: officialClass('ToolRow', 'searchRecovery') ?? '' }, search.recovery)
909
+ : null)
910
+ : web !== null
911
+ ? h(WebBlock, { ...web, labels: blockLabels.web, className: officialClass('ToolRow', 'webBody') ?? '' })
912
+ : details !== null
913
+ ? h(ToolDetailsView, { model: details, t, onOpenFile })
914
+ : h(Fragment, null, variant === 'code' && bodyText !== null
915
+ ? h('div', { className: officialClass('ToolRow', 'bodyScroll') ?? '' }, h(CodeViewer, {
916
+ text: bodyText,
917
+ path: 'tool-code.ts',
918
+ t,
919
+ className: officialClass('ToolRow', 'codeBody') ?? '',
920
+ height: 'auto',
921
+ style: { height: 'auto' },
922
+ }))
923
+ : null, (cardBody !== null || outputText !== null) && h('div', { className: officialClass('ToolRow', 'ioCard') ?? '' }, cardBody !== null && h('div', { className: officialClass('ToolRow', 'ioSection') ?? '' }, h('span', { className: officialClass('ToolRow', 'ioLabel') ?? '' }, t('toolInputLabel')), h('span', { className: officialClass('ToolRow', 'ioText') ?? '' }, cardBody)), cardBody !== null && outputText !== null
924
+ && h('span', { className: officialClass('ToolRow', 'ioDivider') ?? '', 'aria-hidden': true }), outputText !== null && h('div', { className: officialClass('ToolRow', 'ioSection') ?? '' }, h('span', { className: officialClass('ToolRow', 'ioLabel') ?? '' }, t('toolOutputLabel')), h('span', { className: officialClass('ToolRow', 'ioText') ?? '', 'data-error': rowState === 'error' || undefined }, outputText))))) : undefined;
611
925
  return h('div', {
612
926
  className: officialClass('ToolRow', 'root') ?? '',
613
927
  'data-variant': variant,