@zzusp/dingtalk-dsh-observer 0.5.8 → 0.5.10

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 (2) hide show
  1. package/package.json +1 -1
  2. package/web-client.js +8 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zzusp/dingtalk-dsh-observer",
3
- "version": "0.5.8",
3
+ "version": "0.5.10",
4
4
  "description": "DingTalk task board client for DeepSeek Harness",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
package/web-client.js CHANGED
@@ -95,10 +95,10 @@ window.__ModuleLoader__.load({
95
95
  return value
96
96
  }
97
97
  async function load() {
98
- const [health, groups, tasks, alerts, authorizations] = await Promise.all([
99
- get('/health'), get('/state/groups'), get('/state/tasks'), get('/state/supervisor/alerts'), get('/state/authorizations')
98
+ const [health, groups, tasks, taskTimings, alerts, authorizations] = await Promise.all([
99
+ get('/health'), get('/state/groups'), get('/state/tasks'), get('/state/task-timings'), get('/state/supervisor/alerts'), get('/state/authorizations')
100
100
  ])
101
- return { health, groups, tasks, alerts, authorizations }
101
+ return { health, groups, tasks, taskTimings, alerts, authorizations }
102
102
  }
103
103
  function SidebarAction({ wide }) {
104
104
  const isOpen = useOpen()
@@ -168,6 +168,7 @@ window.__ModuleLoader__.load({
168
168
  return () => document.removeEventListener('click', closeForSession, true)
169
169
  }, [])
170
170
  const groupsById = new Map((data?.groups || []).map((group) => [group.groupId, group]))
171
+ const timingsByTaskId = new Map((data?.taskTimings || []).map((timing) => [timing.taskId, timing]))
171
172
  const navigate = async (sessionId, parentSessionId) => {
172
173
  try { setNavigationError(undefined); setNavigatingSessionId(sessionId); await openSession(sessionId, parentSessionId); setOpen(false) }
173
174
  catch (cause) { setNavigationError(cause instanceof Error ? cause.message : String(cause)) }
@@ -204,6 +205,8 @@ window.__ModuleLoader__.load({
204
205
  const delivery = {
205
206
  delivered: { label: '已投递', state: 'done' },
206
207
  failed: { label: '投递失败', state: 'error' },
208
+ 'decision-failed': { label: '判断失败', state: 'error' },
209
+ steered: { label: '已插话·判断中', state: 'ongoing' },
207
210
  pending: { label: '投递中', state: 'ongoing' },
208
211
  skipped: { label: '历史补拉·未投递', state: 'warning' },
209
212
  unknown: { label: '历史状态未知', state: 'warning' },
@@ -240,6 +243,7 @@ window.__ModuleLoader__.load({
240
243
  })
241
244
  const renderTaskCard = (task) => {
242
245
  const group = groupsById.get(task.groupId)
246
+ const timing = timingsByTaskId.get(task.taskId)
243
247
  const queued = task.state === 'queued'
244
248
  const checkpointEvents = task.checkpoints || []
245
249
  const planCheckpointIndex = checkpointEvents.findLastIndex((checkpoint) => checkpoint.kind === 'plan-confirmed')
@@ -270,6 +274,7 @@ window.__ModuleLoader__.load({
270
274
  React.createElement('div', { role: 'button', tabIndex: 0, 'aria-expanded': checkpointsExpanded, 'aria-label': checkpointsExpanded ? '收起检查点' : `展开全部 ${checkpoints.length} 个检查点`, 'data-task-card-action': 'toggle-checkpoints', onClick: (event) => { event.stopPropagation(); setExpandedCheckpointTaskId(checkpointsExpanded ? '' : task.taskId) }, onKeyDown: (event) => { if (event.key !== 'Enter' && event.key !== ' ') return; event.preventDefault(); event.stopPropagation(); setExpandedCheckpointTaskId(checkpointsExpanded ? '' : task.taskId) }, style: { minHeight: 24, boxSizing: 'border-box', display: 'flex', alignItems: 'center', gap: 8, fontSize: 10.5, cursor: 'pointer' } }, React.createElement('span', { style: { flex: '0 0 auto', display: 'inline-flex', alignItems: 'center', gap: 4, color: colors.muted } }, React.createElement(IconChecklistOutline14, { size: 12, 'aria-label': '任务' }), '任务'), React.createElement('div', { role: 'progressbar', 'aria-label': '检查点进度', 'aria-valuemin': 0, 'aria-valuemax': 100, 'aria-valuenow': progress, style: { flex: '1 1 auto', minWidth: 24, height: 4, borderRadius: 999, overflow: 'hidden', background: `color-mix(in srgb, ${colors.muted} 22%, transparent)` } }, React.createElement('div', { style: { width: `${progress}%`, height: '100%', borderRadius: 'inherit', background: completedCheckpointCount === checkpoints.length ? statusTone.done : colors.accent, transition: 'width 180ms ease' } })), React.createElement('span', { style: { flex: '0 0 auto', color: completedCheckpointCount === checkpoints.length ? statusTone.done : colors.muted } }, `${completedCheckpointCount} / ${checkpoints.length}`), React.createElement(checkpointsExpanded ? IconChevronUpOutline14 : IconChevronDownOutline14, { size: 14, 'aria-hidden': true, style: { flex: '0 0 auto', color: colors.muted } })),
271
275
  checkpointsExpanded ? React.createElement('div', { style: { display: 'grid', gap: 4, padding: '2px 9px 9px' } }, ...checkpoints.map((checkpoint, index) => { const completed = completedCheckpointNames.has(checkpoint); const current = !completed && currentCheckpoint === checkpoint; const tone = completed ? statusTone.done : current ? colors.accent : colors.muted; const duration = checkpointDuration(checkpoint, currentCheckpointEvents, Date.now()); return React.createElement('div', { key: `${index}:${checkpoint}`, title: checkpoint, style: { minWidth: 0, display: 'grid', gridTemplateColumns: '12px minmax(0,1fr) 64px', gap: 5, alignItems: 'start', fontSize: 10.5, lineHeight: 1.4 } }, React.createElement('span', { 'aria-hidden': true, style: { width: 12, height: 14, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', color: tone } }, completed ? React.createElement(CheckpointDoneIcon, { size: 12 }) : current ? React.createElement(StateDot, { state: 'ongoing', size: 10 }) : '○'), React.createElement('span', { style: { color: 'inherit', display: '-webkit-box', WebkitLineClamp: 'unset', WebkitBoxOrient: 'vertical', overflow: 'hidden', overflowWrap: 'anywhere' } }, checkpoint), React.createElement('span', { title: `执行时长 ${duration}`, style: { width: 64, color: colors.muted, textAlign: 'right', whiteSpace: 'nowrap', fontVariantNumeric: 'tabular-nums' } }, duration)) })) : null) : null,
272
276
  task.waitingReason ? React.createElement('div', { title: task.waitingReason, style: { fontSize: 10.5, lineHeight: 1.45, color: colors.warning } }, `等待:${task.waitingReason}`) : null),
277
+ timing ? React.createElement('div', { title: timing.complete ? '当前执行轮次精确统计' : `当前执行轮次统计不完整:${(timing.missing || []).join('、') || '历史数据不足'}`, style: { fontSize: 10.5, lineHeight: 1.45, color: timing.complete ? colors.muted : colors.warning } }, `${timing.complete ? '' : '约 '}总计 ${fmtDuration(timing.wallMs)} · 排队 ${fmtDuration(timing.queuedMs)} · 运行 ${fmtDuration(timing.runningMs)} · 等待 ${fmtDuration(timing.waitingMs)} · 工具 ${fmtDuration(timing.toolMs)} · 其他运行 ${fmtDuration(timing.unclassifiedRunningMs)}`) : null,
273
278
  React.createElement('div', { style: { minWidth: 0, marginTop: 0, paddingTop: 6, borderTop: `1px solid ${colors.border}`, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 } },
274
279
  React.createElement('span', { title: `最后活动 ${fmt(task.updatedAt)}`, style: { minWidth: 0, display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 10.5, color: colors.muted, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, React.createElement('svg', { width: 12, height: 12, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 1.8, strokeLinecap: 'round', strokeLinejoin: 'round', 'aria-label': '最后活动时间' }, React.createElement('circle', { cx: 12, cy: 12, r: 9 }), React.createElement('path', { d: 'M12 7v5l3 2' })), fmt(task.updatedAt)),
275
280
  task.state === 'completed' && !task.archivedAt ? React.createElement('button', { type: 'button', onClick: async (event) => { event.stopPropagation(); try { await post(`/tasks/${encodeURIComponent(task.taskId)}/archive`); await refresh() } catch (cause) { setNavigationError(cause instanceof Error ? cause.message : String(cause)) } }, style: { flex: '0 0 auto', border: `1px solid ${colors.border}`, borderRadius: 7, background: colors.surface2, color: colors.muted, padding: '3px 7px', cursor: 'pointer', fontFamily: 'inherit', fontSize: 10.5 } }, '归档') : null),