@muyichengshayu/promptx 0.1.30 → 0.1.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.32
4
+
5
+ - 继续收敛执行过程面板:统一过程事件卡片为白底轻边框,过程区与输入区统一等宽字体,移动端优先折行显示,减少横向滚动与样式不一致带来的阅读负担。
6
+ - 精简子代理展示:`Codex / Claude Code / OpenCode` 的子代理事件统一为更轻量的一行摘要,移动端最多显示两行、桌面端单行;同时去掉多余的“更新”标签、局部展开/收起和重色块背景。
7
+ - 下线执行过程中的代码类自动识别兼容:移除 `code_text / code_snippet / numbered_lines / build_error / search_results` 等旧分支,统一回退为稳定的文本或少量明确结构块,减少误判和错误代码块渲染。
8
+ - 优化前端打包输出:为 `tiptap`、图标与 markdown 等依赖拆分 vendor chunk,消除 Vite 的大包告警,降低工作台主包体积。
9
+
10
+ ## 0.1.31
11
+
12
+ - 继续打磨执行过程展示:统一 `Codex / Claude Code / OpenCode` 的终端输出、搜索命中、构建报错与 diff 渲染,补齐移动端横向滚动、代码字体统一和多余元信息收敛,整体阅读更稳定。
13
+ - 修复执行过程中的多处展示问题:去掉“目标”“退出码 0”“完成 reasoning”等低价值噪音,长命令与路径改为更紧凑的 mono 展示,单条搜索结果、编号源码、build error 与混合 prose/code 内容都能更一致地渲染。
14
+ - 加固执行过程展开状态与文本解析:避免 block 重排后展开/收起状态串位;过程文本不再错误吞掉前导缩进;同时补齐相关单测与构建验证。
15
+
3
16
  ## 0.1.30
4
17
 
5
18
  - 工作台编辑器升级为基于 Tiptap 的图文混排块编辑器,支持图片、文本文件与 PDF 导入;修复输入、焦点、滚动与移动端布局问题,并清理旧编辑器实现。
@@ -132,6 +132,45 @@ function flushBufferedText(buffer = '') {
132
132
  return tail ? [...lines, tail] : lines
133
133
  }
134
134
 
135
+ function extractAgentTargetFromTexts(...values) {
136
+ const matcher = /(?:^|[\s`'"])([A-Za-z]:[\\/][^\s`'"]+\.[A-Za-z0-9]+|\/[^\s`'"]+\.[A-Za-z0-9]+|(?:[A-Za-z0-9._-]+\/)*[A-Za-z0-9._-]+\.[A-Za-z0-9]+)(?=$|[\s`'"])/i
137
+ for (const value of values) {
138
+ const text = String(value || '').trim()
139
+ if (!text) {
140
+ continue
141
+ }
142
+
143
+ const matched = text.match(matcher)
144
+ if (!matched?.[1]) {
145
+ continue
146
+ }
147
+
148
+ const normalized = matched[1].replace(/\\/g, '/')
149
+ const parts = normalized.split('/').filter(Boolean)
150
+ return parts[parts.length - 1] || normalized
151
+ }
152
+
153
+ return ''
154
+ }
155
+
156
+ function normalizeCollabAgentStatus(status = '') {
157
+ const normalized = String(status || '').trim().toLowerCase()
158
+ if (['completed', 'complete', 'succeeded', 'success', 'done'].includes(normalized)) {
159
+ return 'completed'
160
+ }
161
+ if (['failed', 'error', 'errored', 'cancelled', 'canceled', 'stopped'].includes(normalized)) {
162
+ return 'failed'
163
+ }
164
+ if (['running', 'in_progress', 'in-progress', 'pending_init', 'pending'].includes(normalized)) {
165
+ return normalized === 'pending_init' ? 'pending_init' : 'running'
166
+ }
167
+ return normalized || 'pending_init'
168
+ }
169
+
170
+ function isClaudeCollabToolName(name = '') {
171
+ return ['agent', 'task'].includes(String(name || '').trim().toLowerCase())
172
+ }
173
+
135
174
  function collectTextParts(value, parts = []) {
136
175
  if (!value) {
137
176
  return parts
@@ -180,6 +219,29 @@ export function extractClaudeAssistantText(event = {}) {
180
219
  return parts.join('\n').trim()
181
220
  }
182
221
 
222
+ function stringifyClaudeToolResultContent(value) {
223
+ const parts = []
224
+ collectTextParts(value, parts)
225
+ if (parts.length) {
226
+ return parts.join('\n').trim()
227
+ }
228
+
229
+ if (typeof value === 'string') {
230
+ return value.trim()
231
+ }
232
+
233
+ if (value == null) {
234
+ return ''
235
+ }
236
+
237
+ try {
238
+ const compact = JSON.stringify(value)
239
+ return compact.length <= 12000 ? compact : `${compact.slice(0, 11997)}...`
240
+ } catch {
241
+ return String(value || '').trim()
242
+ }
243
+ }
244
+
183
245
  export function extractClaudeResultText(event = {}) {
184
246
  const parts = []
185
247
  if (event?.result) {
@@ -206,6 +268,8 @@ export function extractClaudeSessionId(event = {}) {
206
268
  export function createClaudeNormalizationState() {
207
269
  return {
208
270
  toolUses: new Map(),
271
+ taskIdToToolUseId: new Map(),
272
+ completedCollabToolUseIds: new Set(),
209
273
  }
210
274
  }
211
275
 
@@ -246,19 +310,61 @@ function buildClaudeToolCommand(name = '', input = {}) {
246
310
  return inputSummary ? `${toolName}: ${inputSummary}` : toolName
247
311
  }
248
312
 
313
+ function buildClaudeCollabState(toolUse = {}, overrides = {}) {
314
+ const taskId = String(overrides.taskId || '').trim()
315
+ const message = stringifyClaudeToolResultContent(overrides.message)
316
+ const baseStatus = overrides.status ?? (message ? 'completed' : 'running')
317
+ const status = normalizeCollabAgentStatus(baseStatus)
318
+
319
+ return {
320
+ status,
321
+ message,
322
+ title: String(overrides.title || toolUse.description || '').trim(),
323
+ role: String(overrides.role || toolUse.role || '').trim(),
324
+ target: String(overrides.target || toolUse.target || '').trim(),
325
+ model: String(overrides.model || toolUse.model || '').trim(),
326
+ ...(taskId ? { task_id: taskId } : {}),
327
+ }
328
+ }
329
+
249
330
  function createClaudeToolUseEvent(block = {}, state = createClaudeNormalizationState()) {
250
331
  const toolUseId = String(block?.id || '').trim()
251
332
  const name = String(block?.name || block?.tool_name || 'Claude Code tool').trim() || 'Claude Code tool'
252
333
  const input = block?.input && typeof block.input === 'object' ? block.input : {}
253
334
  const command = buildClaudeToolCommand(name, input)
335
+ const isCollabTool = isClaudeCollabToolName(name)
336
+ const collabPrompt = String(input.prompt || '').trim()
337
+ const collabDescription = String(input.description || '').trim()
338
+ const collabRole = String(input.subagent_type || input.agent || '').trim()
339
+ const collabModel = String(input.model || '').trim()
340
+ const collabTarget = extractAgentTargetFromTexts(collabDescription, collabPrompt)
254
341
 
255
342
  if (toolUseId) {
256
343
  state.toolUses.set(toolUseId, {
257
344
  name,
258
345
  command,
346
+ kind: isCollabTool ? 'collab' : 'command',
347
+ prompt: collabPrompt || collabDescription,
348
+ description: collabDescription,
349
+ role: collabRole,
350
+ model: collabModel,
351
+ target: collabTarget,
352
+ taskIds: [],
259
353
  })
260
354
  }
261
355
 
356
+ if (isCollabTool) {
357
+ return {
358
+ ...createItemStartedEvent({
359
+ type: AGENT_RUN_ITEM_TYPES.COLLAB_TOOL_CALL,
360
+ tool: 'spawn_agent',
361
+ receiver_thread_ids: [],
362
+ prompt: collabPrompt || collabDescription,
363
+ agents_states: {},
364
+ }),
365
+ }
366
+ }
367
+
262
368
  return {
263
369
  ...createItemStartedEvent({
264
370
  type: AGENT_RUN_ITEM_TYPES.COMMAND_EXECUTION,
@@ -271,12 +377,47 @@ function createClaudeToolUseEvent(block = {}, state = createClaudeNormalizationS
271
377
  function createClaudeToolResultEvent(block = {}, state = createClaudeNormalizationState()) {
272
378
  const toolUseId = String(block?.tool_use_id || block?.toolUseId || '').trim()
273
379
  const remembered = toolUseId ? state.toolUses.get(toolUseId) : null
274
- const output = String(block?.content || block?.result || '').trim()
380
+ const output = stringifyClaudeToolResultContent(block?.content ?? block?.result)
275
381
  const isError = Boolean(block?.is_error)
382
+ const taskIds = Array.isArray(remembered?.taskIds) ? remembered.taskIds.filter(Boolean) : []
383
+ const collabTool = remembered?.kind === 'collab'
384
+
385
+ if (toolUseId && state.completedCollabToolUseIds.has(toolUseId)) {
386
+ return null
387
+ }
276
388
 
277
389
  if (toolUseId) {
278
390
  state.toolUses.delete(toolUseId)
279
391
  }
392
+ taskIds.forEach((taskId) => {
393
+ state.taskIdToToolUseId.delete(taskId)
394
+ })
395
+
396
+ if (collabTool) {
397
+ if (toolUseId) {
398
+ state.completedCollabToolUseIds.add(toolUseId)
399
+ }
400
+ const receiverThreadIds = taskIds.length
401
+ ? taskIds
402
+ : (toolUseId ? [`claude-agent-${toolUseId}`] : [])
403
+ const agentsStates = Object.fromEntries(
404
+ receiverThreadIds.map((taskId) => [taskId, buildClaudeCollabState(remembered, {
405
+ taskId,
406
+ status: isError ? 'failed' : 'completed',
407
+ message: output,
408
+ })])
409
+ )
410
+
411
+ return {
412
+ ...createItemCompletedEvent({
413
+ type: AGENT_RUN_ITEM_TYPES.COLLAB_TOOL_CALL,
414
+ tool: 'wait',
415
+ receiver_thread_ids: receiverThreadIds,
416
+ prompt: remembered?.prompt || remembered?.description || '',
417
+ agents_states: agentsStates,
418
+ }),
419
+ }
420
+ }
280
421
 
281
422
  return {
282
423
  ...createItemCompletedEvent({
@@ -289,6 +430,105 @@ function createClaudeToolResultEvent(block = {}, state = createClaudeNormalizati
289
430
  }
290
431
  }
291
432
 
433
+ function resolveClaudeTaskToolUseId(event = {}, state = createClaudeNormalizationState()) {
434
+ const explicitToolUseId = String(event?.tool_use_id || event?.toolUseId || '').trim()
435
+ if (explicitToolUseId) {
436
+ return explicitToolUseId
437
+ }
438
+
439
+ const taskId = String(event?.task_id || event?.taskId || '').trim()
440
+ if (!taskId) {
441
+ return ''
442
+ }
443
+
444
+ return String(state.taskIdToToolUseId.get(taskId) || '').trim()
445
+ }
446
+
447
+ function createClaudeTaskStartedEvent(event = {}, state = createClaudeNormalizationState()) {
448
+ const toolUseId = resolveClaudeTaskToolUseId(event, state)
449
+ const taskId = String(event?.task_id || event?.taskId || '').trim()
450
+ const remembered = toolUseId ? state.toolUses.get(toolUseId) : null
451
+
452
+ if (!remembered || remembered.kind !== 'collab' || !taskId) {
453
+ return null
454
+ }
455
+
456
+ if (!Array.isArray(remembered.taskIds)) {
457
+ remembered.taskIds = []
458
+ }
459
+ if (!remembered.taskIds.includes(taskId)) {
460
+ remembered.taskIds.push(taskId)
461
+ }
462
+ state.taskIdToToolUseId.set(taskId, toolUseId)
463
+
464
+ return {
465
+ ...createItemCompletedEvent({
466
+ type: AGENT_RUN_ITEM_TYPES.COLLAB_TOOL_CALL,
467
+ tool: 'spawn_agent',
468
+ receiver_thread_ids: [taskId],
469
+ prompt: remembered.prompt || String(event?.prompt || event?.description || '').trim(),
470
+ agents_states: {
471
+ [taskId]: buildClaudeCollabState(remembered, {
472
+ taskId,
473
+ status: 'running',
474
+ title: String(event?.description || remembered.description || '').trim(),
475
+ target: extractAgentTargetFromTexts(event?.description, event?.prompt, remembered.target),
476
+ }),
477
+ },
478
+ }),
479
+ }
480
+ }
481
+
482
+ function createClaudeTaskFinishedEvent(event = {}, state = createClaudeNormalizationState()) {
483
+ const subtype = String(event?.subtype || '').trim().toLowerCase()
484
+ const toolUseId = resolveClaudeTaskToolUseId(event, state)
485
+ const taskId = String(event?.task_id || event?.taskId || '').trim()
486
+ const remembered = toolUseId ? state.toolUses.get(toolUseId) : null
487
+
488
+ if (!remembered || remembered.kind !== 'collab') {
489
+ return null
490
+ }
491
+
492
+ if (toolUseId && state.completedCollabToolUseIds.has(toolUseId)) {
493
+ return null
494
+ }
495
+
496
+ const failed = subtype === 'task_failed'
497
+ const output = stringifyClaudeToolResultContent(
498
+ event?.result
499
+ ?? event?.message
500
+ ?? event?.content
501
+ ?? event?.error
502
+ ?? event?.task_result
503
+ )
504
+
505
+ if (toolUseId) {
506
+ state.toolUses.delete(toolUseId)
507
+ state.completedCollabToolUseIds.add(toolUseId)
508
+ }
509
+ if (taskId) {
510
+ state.taskIdToToolUseId.delete(taskId)
511
+ }
512
+
513
+ return {
514
+ ...createItemCompletedEvent({
515
+ type: AGENT_RUN_ITEM_TYPES.COLLAB_TOOL_CALL,
516
+ tool: 'wait',
517
+ receiver_thread_ids: taskId ? [taskId] : (Array.isArray(remembered.taskIds) ? remembered.taskIds.filter(Boolean) : []),
518
+ prompt: remembered.prompt || remembered.description || '',
519
+ agents_states: {
520
+ [(taskId || `claude-agent-${toolUseId}`)]: buildClaudeCollabState(remembered, {
521
+ taskId,
522
+ status: failed ? 'failed' : 'completed',
523
+ message: output,
524
+ title: String(event?.description || remembered.description || '').trim(),
525
+ target: extractAgentTargetFromTexts(event?.description, event?.prompt, remembered.target),
526
+ }),
527
+ },
528
+ }),
529
+ }
530
+ }
531
+
292
532
  function buildClaudeApiRetryReason(event = {}) {
293
533
  const status = Number(event?.error_status) || 0
294
534
  const code = String(event?.error || '').trim()
@@ -323,6 +563,19 @@ export function normalizeClaudeEvents(event = {}, state = createClaudeNormalizat
323
563
  return [createThreadStartedEvent(extractClaudeSessionId(event))]
324
564
  }
325
565
 
566
+ if (eventType === 'system' && String(event?.subtype || '').trim().toLowerCase() === 'task_started') {
567
+ const collabEvent = createClaudeTaskStartedEvent(event, state)
568
+ return collabEvent ? [collabEvent] : []
569
+ }
570
+
571
+ if (
572
+ eventType === 'system'
573
+ && ['task_result', 'task_completed', 'task_failed'].includes(String(event?.subtype || '').trim().toLowerCase())
574
+ ) {
575
+ const collabEvent = createClaudeTaskFinishedEvent(event, state)
576
+ return collabEvent ? [collabEvent] : []
577
+ }
578
+
326
579
  if (eventType === 'system' && String(event?.subtype || '').trim().toLowerCase() === 'api_retry') {
327
580
  if (isClaudeFatalAuthRetry(event)) {
328
581
  return [createErrorEvent(formatClaudeFatalAuthMessage(event))]
@@ -378,7 +631,10 @@ export function normalizeClaudeEvents(event = {}, state = createClaudeNormalizat
378
631
  blocks.forEach((block) => {
379
632
  const blockType = String(block?.type || '').trim().toLowerCase()
380
633
  if (blockType === 'tool_result') {
381
- normalizedEvents.push(createClaudeToolResultEvent(block, state))
634
+ const toolResultEvent = createClaudeToolResultEvent(block, state)
635
+ if (toolResultEvent) {
636
+ normalizedEvents.push(toolResultEvent)
637
+ }
382
638
  }
383
639
  })
384
640
  return normalizedEvents
@@ -133,6 +133,41 @@ function flushBufferedText(buffer = '') {
133
133
  return tail ? [...lines, tail] : lines
134
134
  }
135
135
 
136
+ function extractAgentTargetFromTexts(...values) {
137
+ const matcher = /(?:^|[\s`'"])([A-Za-z]:[\\/][^\s`'"]+\.[A-Za-z0-9]+|\/[^\s`'"]+\.[A-Za-z0-9]+|(?:[A-Za-z0-9._-]+\/)*[A-Za-z0-9._-]+\.[A-Za-z0-9]+)(?=$|[\s`'"])/i
138
+ for (const value of values) {
139
+ const text = String(value || '').trim()
140
+ if (!text) {
141
+ continue
142
+ }
143
+
144
+ const matched = text.match(matcher)
145
+ if (!matched?.[1]) {
146
+ continue
147
+ }
148
+
149
+ const normalized = matched[1].replace(/\\/g, '/')
150
+ const parts = normalized.split('/').filter(Boolean)
151
+ return parts[parts.length - 1] || normalized
152
+ }
153
+
154
+ return ''
155
+ }
156
+
157
+ function normalizeCollabAgentStatus(status = '') {
158
+ const normalized = String(status || '').trim().toLowerCase()
159
+ if (['completed', 'complete', 'succeeded', 'success', 'done'].includes(normalized)) {
160
+ return 'completed'
161
+ }
162
+ if (['failed', 'error', 'errored', 'cancelled', 'canceled', 'stopped'].includes(normalized)) {
163
+ return 'failed'
164
+ }
165
+ if (['running', 'in_progress', 'in-progress', 'pending_init', 'pending'].includes(normalized)) {
166
+ return normalized === 'pending_init' ? 'pending_init' : 'running'
167
+ }
168
+ return normalized || 'pending_init'
169
+ }
170
+
136
171
  function summarizeOpenCodeInput(input = {}) {
137
172
  if (!input || typeof input !== 'object') {
138
173
  return ''
@@ -295,6 +330,73 @@ export function createOpenCodeNormalizationState() {
295
330
  }
296
331
  }
297
332
 
333
+ function isOpenCodeSubAgentTask(event = {}) {
334
+ const part = event?.part && typeof event.part === 'object' ? event.part : {}
335
+ const tool = String(part?.tool || '').trim().toLowerCase()
336
+ const input = part?.state?.input && typeof part.state.input === 'object'
337
+ ? part.state.input
338
+ : {}
339
+ return tool === 'task' && Boolean(String(input.subagent_type || '').trim())
340
+ }
341
+
342
+ function extractOpenCodeSubAgentSessionId(event = {}, output = '') {
343
+ const metadataSessionId = String(event?.part?.state?.metadata?.sessionId || '').trim()
344
+ if (metadataSessionId) {
345
+ return metadataSessionId
346
+ }
347
+
348
+ const matched = String(output || '').match(/task_id:\s*([^\s)]+)/i)
349
+ return matched?.[1] ? String(matched[1]).trim() : ''
350
+ }
351
+
352
+ function createOpenCodeSubAgentEvents(event = {}) {
353
+ const part = event?.part && typeof event.part === 'object' ? event.part : {}
354
+ const state = part?.state && typeof part.state === 'object' ? part.state : {}
355
+ const input = state?.input && typeof state.input === 'object' ? state.input : {}
356
+ const output = stringifyOpenCodeOutput(state?.output)
357
+ const sessionId = extractOpenCodeSubAgentSessionId(event, output)
358
+ const receiverThreadIds = sessionId ? [sessionId] : []
359
+ const collabPrompt = String(input.prompt || input.description || '').trim()
360
+ const collabStatus = normalizeCollabAgentStatus(state?.status)
361
+ const target = extractAgentTargetFromTexts(input.description, input.prompt, output)
362
+ const modelId = String(state?.metadata?.model?.modelID || '').trim()
363
+ const providerId = String(state?.metadata?.model?.providerID || '').trim()
364
+ const model = modelId
365
+ ? `${providerId ? `${providerId}/` : ''}${modelId}`
366
+ : ''
367
+ const agentsStates = sessionId
368
+ ? {
369
+ [sessionId]: {
370
+ status: collabStatus,
371
+ message: output,
372
+ title: String(input.description || part?.title || '').trim(),
373
+ role: String(input.subagent_type || '').trim(),
374
+ target,
375
+ model,
376
+ },
377
+ }
378
+ : {}
379
+ const spawnPayload = {
380
+ type: AGENT_RUN_ITEM_TYPES.COLLAB_TOOL_CALL,
381
+ tool: 'spawn_agent',
382
+ receiver_thread_ids: receiverThreadIds,
383
+ prompt: collabPrompt,
384
+ agents_states: agentsStates,
385
+ }
386
+
387
+ if (['completed', 'failed'].includes(collabStatus)) {
388
+ return [
389
+ createItemCompletedEvent(spawnPayload),
390
+ createItemCompletedEvent({
391
+ ...spawnPayload,
392
+ tool: 'wait',
393
+ }),
394
+ ]
395
+ }
396
+
397
+ return [createItemStartedEvent(spawnPayload)]
398
+ }
399
+
298
400
  export function normalizeOpenCodeEvents(event = {}, state = createOpenCodeNormalizationState()) {
299
401
  const eventType = String(event?.type || '').trim().toLowerCase()
300
402
  const normalizedEvents = []
@@ -308,6 +410,10 @@ export function normalizeOpenCodeEvents(event = {}, state = createOpenCodeNormal
308
410
  }
309
411
 
310
412
  if (eventType === 'tool_use') {
413
+ if (isOpenCodeSubAgentTask(event)) {
414
+ return createOpenCodeSubAgentEvents(event)
415
+ }
416
+
311
417
  const command = buildOpenCodeToolCommand(event)
312
418
  const status = String(event?.part?.state?.status || '').trim().toLowerCase()
313
419
  const output = stringifyOpenCodeOutput(event?.part?.state?.output)