diff --git a/style.css b/style.css index 0260fb9..b7348e8 100644 --- a/style.css +++ b/style.css @@ -618,6 +618,910 @@ display: flex; } +/* ==================== Task-Mode (对称 config-mode) ==================== */ + +#st-bme-panel.task-mode .bme-tab-content { + display: none; +} + +#st-bme-panel.task-mode .bme-task-sidebar { + display: flex; +} + +#st-bme-panel.task-mode .bme-graph-workspace { + display: none; +} + +#st-bme-panel.task-mode .bme-task-workspace { + display: flex; +} + +.bme-task-sidebar { + display: none; + flex-direction: column; + gap: 2px; + padding: 12px 8px; + overflow-y: auto; +} + +.bme-task-sidebar-header { + padding: 8px 10px 12px; + margin-bottom: 4px; +} + +.bme-task-sidebar-kicker { + font-size: 10px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 1.2px; + color: var(--bme-primary); + margin-bottom: 4px; +} + +.bme-task-sidebar-title { + font-size: 14px; + font-weight: 700; + color: var(--bme-on-surface); +} + +.bme-task-sidebar-help { + font-size: 11px; + color: var(--bme-on-surface-dim); + margin-top: 4px; + line-height: 1.4; +} + +.bme-task-nav-btn { + display: flex; + align-items: center; + gap: 10px; + padding: 10px 14px; + border-radius: 8px; + border: none; + border-left: 3px solid transparent; + background: transparent; + color: var(--bme-on-surface-dim); + font-size: 12px; + font-weight: 500; + cursor: pointer; + transition: all 0.15s ease; + white-space: nowrap; +} + +.bme-task-nav-btn:hover { + background: rgba(255, 255, 255, 0.04); + color: var(--bme-on-surface); +} + +.bme-task-nav-btn.active { + border-left-color: var(--bme-primary); + background: var(--bme-primary-dim); + color: var(--bme-primary); + font-weight: 600; +} + +.bme-task-nav-btn i { + width: 16px; + text-align: center; + font-size: 13px; +} + +.bme-task-nav-btn .bme-task-nav-badge { + margin-left: auto; + font-size: 10px; + padding: 2px 6px; + border-radius: 10px; + background: var(--bme-primary-dim); + color: var(--bme-primary); + font-weight: 600; +} + +.bme-task-workspace { + display: none; + flex: 1; + flex-direction: column; + min-height: 0; + overflow-y: auto; + background: + radial-gradient( + circle at top right, + var(--bme-primary-dim, rgba(233, 69, 96, 0.15)), + transparent 32% + ), + linear-gradient(180deg, rgba(255, 255, 255, 0.02), transparent 20%), + var(--bme-surface-lowest, #0e0e11); +} + +.bme-task-workspace-header { + padding: 20px 24px 14px; + border-bottom: 1px solid var(--bme-border); + flex-shrink: 0; +} + +.bme-task-workspace-kicker { + font-size: 10px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 1.2px; + color: var(--bme-primary); + margin-bottom: 4px; +} + +.bme-task-workspace-title { + font-size: 20px; + font-weight: 700; + color: var(--bme-on-surface); + margin-bottom: 4px; +} + +.bme-task-workspace-desc { + font-size: 12px; + color: var(--bme-on-surface-dim); + line-height: 1.5; +} + +.bme-task-workspace-body { + padding: 16px 24px 32px; + flex: 1; + min-height: 0; + overflow-y: auto; +} + +.bme-task-section { + display: none; +} + +.bme-task-section.active { + display: block; +} + +/* --- Task nav mobile pill selector (visible only on mobile) --- */ +.bme-task-nav-mobile { + display: none; + gap: 6px; + padding: 8px 16px; + overflow-x: auto; + flex-shrink: 0; + border-bottom: 1px solid var(--bme-border); + -webkit-overflow-scrolling: touch; +} + +.bme-task-nav-mobile .bme-task-nav-pill { + display: flex; + align-items: center; + gap: 4px; + padding: 6px 12px; + border-radius: 20px; + border: 1px solid var(--bme-border); + background: transparent; + color: var(--bme-on-surface-dim); + font-size: 11px; + font-weight: 500; + cursor: pointer; + white-space: nowrap; + transition: all 0.15s ease; +} + +.bme-task-nav-mobile .bme-task-nav-pill:hover { + border-color: var(--bme-primary); + color: var(--bme-on-surface); +} + +.bme-task-nav-mobile .bme-task-nav-pill.active { + background: var(--bme-primary); + border-color: var(--bme-primary); + color: #fff; + font-weight: 600; +} + +/* ==================== Pipeline Overview ==================== */ + +.bme-pipeline-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; + margin-bottom: 16px; +} + +.bme-pipeline-card { + display: flex; + align-items: flex-start; + gap: 10px; + padding: 12px 14px; + background: var(--bme-surface, #131316); + border: 1px solid var(--bme-border); + border-radius: 8px; + border-left: 3px solid var(--bme-border); + transition: border-color 0.2s; +} + +.bme-pipeline-card[data-status="idle"], +.bme-pipeline-card[data-status="ready"] { + border-left-color: #2ecc71; +} +.bme-pipeline-card[data-status="running"], +.bme-pipeline-card[data-status="building"] { + border-left-color: #00d4ff; +} +.bme-pipeline-card[data-status="queued"], +.bme-pipeline-card[data-status="warning"] { + border-left-color: #f39c12; +} +.bme-pipeline-card[data-status="error"], +.bme-pipeline-card[data-status="blocked"] { + border-left-color: #e74c3c; +} + +.bme-pipeline-dot { + width: 10px; + height: 10px; + border-radius: 50%; + margin-top: 3px; + flex-shrink: 0; +} + +.bme-pipeline-dot.green { background: #2ecc71; box-shadow: 0 0 6px rgba(46,204,113,.4); } +.bme-pipeline-dot.cyan { background: #00d4ff; box-shadow: 0 0 6px rgba(0,212,255,.4); animation: bme-pulse-dot 1.5s ease-in-out infinite; } +.bme-pipeline-dot.amber { background: #f39c12; box-shadow: 0 0 6px rgba(243,156,18,.4); } +.bme-pipeline-dot.red { background: #e74c3c; box-shadow: 0 0 6px rgba(231,76,60,.4); } + +@keyframes bme-pulse-dot { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.4; } +} + +.bme-pipeline-info { + flex: 1; + min-width: 0; +} + +.bme-pipeline-name { + font-size: 12px; + font-weight: 700; + color: var(--bme-on-surface); + margin-bottom: 2px; +} + +.bme-pipeline-status { + font-size: 11px; + font-weight: 600; + margin-bottom: 2px; +} + +.bme-pipeline-status.green { color: #2ecc71; } +.bme-pipeline-status.cyan { color: #00d4ff; } +.bme-pipeline-status.amber { color: #f39c12; } +.bme-pipeline-status.red { color: #e74c3c; } + +.bme-pipeline-detail { + font-size: 10px; + color: var(--bme-on-surface-dim); +} + +/* --- Batch Progress --- */ + +.bme-batch-progress { + background: var(--bme-surface, #131316); + border: 1px solid var(--bme-border); + border-radius: 8px; + padding: 16px; + margin-bottom: 16px; +} + +.bme-batch-stages { + display: flex; + align-items: flex-start; + gap: 0; + margin-bottom: 12px; +} + +.bme-batch-stage { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: 6px; + position: relative; +} + +.bme-batch-stage-dot { + width: 28px; + height: 28px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 11px; + z-index: 1; + border: 2px solid var(--bme-border); + background: var(--bme-surface-lowest, #0e0e11); + color: var(--bme-on-surface-dim); +} + +.bme-batch-stage-dot.done { + background: #2ecc71; + border-color: #2ecc71; + color: #fff; +} + +.bme-batch-stage-dot.running { + background: #00d4ff; + border-color: #00d4ff; + color: #fff; + animation: bme-pulse-dot 1.5s ease-in-out infinite; +} + +.bme-batch-stage-label { + font-size: 11px; + font-weight: 600; + color: var(--bme-on-surface-dim); + text-align: center; +} + +.bme-batch-stage-detail { + font-size: 10px; + color: var(--bme-on-surface-dim); + text-align: center; + max-width: 100px; + opacity: 0.7; +} + +.bme-batch-stage-line { + position: absolute; + top: 14px; + left: calc(50% + 18px); + width: calc(100% - 36px); + height: 2px; + background: var(--bme-border); + z-index: 0; +} + +.bme-batch-stage-line.done { background: #2ecc71; } +.bme-batch-stage-line.running { background: linear-gradient(90deg, #2ecc71, #00d4ff); } + +.bme-batch-stage:last-child .bme-batch-stage-line { display: none; } + +.bme-batch-meta { + display: flex; + gap: 16px; + font-size: 11px; + color: var(--bme-on-surface-dim); + padding-top: 10px; + border-top: 1px solid var(--bme-border); +} + +.bme-batch-meta i { + font-size: 10px; + color: var(--bme-primary); + opacity: 0.6; + margin-right: 4px; +} + +/* --- Status Summary --- */ + +.bme-status-summary { + background: var(--bme-surface, #131316); + border: 1px solid var(--bme-border); + border-radius: 8px; + padding: 12px 16px; +} + +.bme-status-summary-title { + font-size: 12px; + font-weight: 700; + color: var(--bme-on-surface); + margin-bottom: 8px; + display: flex; + align-items: center; + gap: 6px; +} + +.bme-status-summary-title i { + color: var(--bme-primary); + font-size: 11px; +} + +.bme-status-row { + display: flex; + align-items: baseline; + gap: 10px; + padding: 6px 0; + border-bottom: 1px solid rgba(255, 255, 255, 0.03); +} + +.bme-status-row:last-child { border-bottom: none; } + +.bme-status-row-label { + font-size: 11px; + font-weight: 600; + width: 56px; + flex-shrink: 0; + display: flex; + align-items: center; + gap: 6px; + color: var(--bme-on-surface); +} + +.bme-status-row-label .bme-sdot { + width: 6px; + height: 6px; + border-radius: 50%; + flex-shrink: 0; +} + +.bme-status-row-value { + font-size: 11px; + color: var(--bme-on-surface-dim); + flex: 1; + min-width: 0; +} + +/* ==================== Task Timeline ==================== */ + +.bme-timeline-toolbar { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + background: var(--bme-surface, #131316); + border: 1px solid var(--bme-border); + border-radius: 8px; + margin-bottom: 12px; + flex-wrap: wrap; + position: sticky; + top: 0; + z-index: 5; +} + +.bme-timeline-filter { + padding: 4px 10px; + border-radius: 6px; + border: 1px solid var(--bme-border); + background: transparent; + color: var(--bme-on-surface-dim); + font-size: 11px; + cursor: pointer; +} + +.bme-timeline-filter:hover { + border-color: var(--bme-primary); + color: var(--bme-on-surface); +} + +.bme-timeline-search { + flex: 1; + min-width: 100px; + border: none; + background: transparent; + color: var(--bme-on-surface); + font-size: 12px; + outline: none; +} + +.bme-timeline-search::placeholder { + color: var(--bme-on-surface-dim); + opacity: 0.5; +} + +.bme-timeline-divider { + width: 1px; + height: 16px; + background: var(--bme-border); +} + +.bme-timeline-action { + padding: 4px 8px; + border-radius: 6px; + border: none; + background: transparent; + color: var(--bme-on-surface-dim); + cursor: pointer; + font-size: 11px; + display: flex; + align-items: center; + gap: 4px; +} + +.bme-timeline-action:hover { color: var(--bme-on-surface); } +.bme-timeline-action.active { color: var(--bme-primary); } + +.bme-timeline-stack { + display: flex; + flex-direction: column; + gap: 0; +} + +.bme-timeline-entry { + position: relative; + padding: 12px 14px; + background: var(--bme-surface, #131316); + border: 1px solid var(--bme-border); + border-radius: 8px; + margin-bottom: 2px; + transition: border-color 0.15s; +} + +.bme-timeline-entry:hover { + border-color: rgba(255, 255, 255, 0.1); +} + +.bme-timeline-entry__head { + display: flex; + align-items: center; + gap: 8px; + cursor: pointer; +} + +.bme-timeline-entry__title { + font-size: 12px; + font-weight: 600; + color: var(--bme-on-surface); + flex: 1; + min-width: 0; +} + +.bme-timeline-entry__meta { + font-size: 10px; + color: var(--bme-on-surface-dim); +} + +.bme-timeline-entry__toggle { + background: transparent; + border: none; + color: var(--bme-on-surface-dim); + cursor: pointer; + padding: 2px; + font-size: 11px; + transition: transform 0.2s; +} + +.bme-timeline-entry.is-collapsed .bme-timeline-entry__toggle { + transform: rotate(-90deg); +} + +.bme-timeline-entry__detail { + margin-top: 10px; + padding-top: 10px; + border-top: 1px solid var(--bme-border); +} + +.bme-timeline-entry.is-collapsed .bme-timeline-entry__detail { + display: none; +} + +.bme-timeline-substage { + display: flex; + align-items: baseline; + gap: 8px; + padding: 4px 0; + font-size: 11px; + color: var(--bme-on-surface-dim); +} + +.bme-timeline-substage i { + font-size: 10px; + width: 14px; + text-align: center; +} + +.bme-timeline-connector { + width: 2px; + height: 6px; + background: var(--bme-border); + margin: 0 auto; +} + +.bme-timeline-bottom-bar { + padding: 8px 14px; + font-size: 11px; + color: var(--bme-on-surface-dim); + text-align: center; +} + +/* ==================== Memory Browser Master-Detail ==================== */ + +.bme-memory-master-detail { + display: flex; + height: 100%; + min-height: 400px; + gap: 0; +} + +.bme-memory-list-panel { + width: 40%; + min-width: 200px; + max-width: 360px; + display: flex; + flex-direction: column; + border-right: 1px solid var(--bme-border); + overflow: hidden; +} + +.bme-memory-list-filters { + padding: 10px; + display: flex; + flex-direction: column; + gap: 6px; + border-bottom: 1px solid var(--bme-border); + flex-shrink: 0; +} + +.bme-memory-list-scroll { + flex: 1; + overflow-y: auto; +} + +.bme-memory-node-item { + padding: 10px 12px; + border-bottom: 1px solid rgba(255, 255, 255, 0.03); + border-left: 3px solid transparent; + cursor: pointer; + transition: all 0.12s; +} + +.bme-memory-node-item:hover { + background: rgba(255, 255, 255, 0.03); +} + +.bme-memory-node-item.selected { + border-left-color: var(--bme-primary); + background: var(--bme-primary-dim); +} + +.bme-memory-node-item__header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 4px; +} + +.bme-memory-node-item__type { + font-size: 10px; + font-weight: 700; + padding: 2px 6px; + border-radius: 4px; + text-transform: uppercase; +} + +.bme-memory-node-item__type.type-character { background: rgba(155,89,182,.2); color: #c084fc; } +.bme-memory-node-item__type.type-event { background: rgba(0,212,255,.15); color: #00d4ff; } +.bme-memory-node-item__type.type-location { background: rgba(46,204,113,.15); color: #2ecc71; } +.bme-memory-node-item__type.type-rule { background: rgba(243,156,18,.15); color: #f39c12; } +.bme-memory-node-item__type.type-thread { background: rgba(59,130,246,.15); color: #3b82f6; } +.bme-memory-node-item__type.type-default { background: rgba(255,255,255,.08); color: var(--bme-on-surface-dim); } + +.bme-memory-node-item__imp { + font-size: 10px; + font-family: monospace; + color: var(--bme-primary); +} + +.bme-memory-node-item__title { + font-size: 12px; + font-weight: 600; + color: var(--bme-on-surface); + margin-bottom: 4px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.bme-memory-node-item__preview { + font-size: 11px; + color: var(--bme-on-surface-dim); + line-height: 1.4; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + margin-bottom: 4px; +} + +.bme-memory-node-item__meta { + display: flex; + gap: 8px; + font-size: 10px; + color: var(--bme-on-surface-dim); + opacity: 0.6; +} + +.bme-memory-detail-panel { + flex: 1; + overflow-y: auto; + padding: 20px; + min-width: 0; +} + +.bme-memory-detail-empty { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + color: var(--bme-on-surface-dim); + font-size: 12px; +} + +.bme-memory-detail__title { + font-size: 18px; + font-weight: 700; + color: var(--bme-on-surface); + margin-bottom: 8px; +} + +.bme-memory-detail__badges { + display: flex; + gap: 6px; + flex-wrap: wrap; + margin-bottom: 14px; +} + +.bme-memory-detail__desc { + font-size: 12px; + line-height: 1.6; + color: var(--bme-on-surface); + margin-bottom: 16px; + white-space: pre-wrap; +} + +.bme-memory-detail__fields { + margin-bottom: 16px; +} + +.bme-memory-detail__field-row { + display: flex; + gap: 8px; + padding: 4px 0; + font-size: 11px; + border-bottom: 1px solid rgba(255, 255, 255, 0.03); +} + +.bme-memory-detail__field-key { + color: var(--bme-on-surface-dim); + min-width: 80px; + font-weight: 600; +} + +.bme-memory-detail__field-val { + color: var(--bme-on-surface); +} + +.bme-memory-detail__stats { + display: flex; + gap: 14px; + flex-wrap: wrap; + font-size: 11px; + color: var(--bme-on-surface-dim); + margin-bottom: 16px; + padding: 10px 0; + border-top: 1px solid var(--bme-border); + border-bottom: 1px solid var(--bme-border); +} + +.bme-memory-detail__actions { + display: flex; + gap: 8px; + flex-wrap: wrap; +} + +/* ==================== Injection Preview ==================== */ + +.bme-injection-token-bar { + display: flex; + align-items: center; + gap: 12px; + padding: 10px 14px; + background: var(--bme-surface, #131316); + border: 1px solid var(--bme-border); + border-radius: 8px; + margin-bottom: 12px; +} + +.bme-injection-token-bar__label { + font-size: 13px; + font-weight: 700; + color: var(--bme-on-surface); + white-space: nowrap; +} + +.bme-injection-token-bar__track { + flex: 1; + height: 6px; + border-radius: 3px; + background: var(--bme-border); + overflow: hidden; +} + +.bme-injection-token-bar__fill { + height: 100%; + border-radius: 3px; + background: var(--bme-primary); + transition: width 0.3s; +} + +.bme-injection-token-bar__breakdown { + font-size: 10px; + color: var(--bme-on-surface-dim); + white-space: nowrap; +} + +.bme-injection-card-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; + margin-bottom: 16px; +} + +.bme-injection-card { + background: var(--bme-surface, #131316); + border: 1px solid var(--bme-border); + border-radius: 8px; + padding: 14px; + border-top: 2px solid var(--bme-border); +} + +.bme-injection-card__header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 8px; +} + +.bme-injection-card__type { + font-size: 10px; + font-weight: 700; + padding: 2px 6px; + border-radius: 4px; +} + +.bme-injection-card__tokens { + font-size: 10px; + color: var(--bme-on-surface-dim); +} + +.bme-injection-card__body { + font-size: 11px; + line-height: 1.5; + color: var(--bme-on-surface-dim); + max-height: 120px; + overflow-y: auto; + white-space: pre-wrap; +} + +/* ==================== Persistence Status ==================== */ + +.bme-persist-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; + margin-bottom: 16px; +} + +.bme-persist-kv { + background: var(--bme-surface, #131316); + border: 1px solid var(--bme-border); + border-radius: 8px; + padding: 14px 16px; +} + +.bme-persist-kv__row { + display: flex; + justify-content: space-between; + align-items: baseline; + padding: 5px 0; + border-bottom: 1px solid rgba(255, 255, 255, 0.03); + font-size: 11px; +} + +.bme-persist-kv__row:last-child { border-bottom: none; } +.bme-persist-kv__row span { color: var(--bme-on-surface-dim); } +.bme-persist-kv__row strong { color: var(--bme-on-surface); font-weight: 600; } + +.bme-persist-actions { + display: flex; + gap: 8px; + flex-wrap: wrap; +} + .bme-graph-toolbar { display: flex; align-items: center; @@ -5985,3 +6889,52 @@ flex-direction: column; } } + +/* ═══════════════════════════════════════════════════════════ + Task Monitor Mobile Responsive + ═══════════════════════════════════════════════════════════ */ + +@media (max-width: 768px) { + #st-bme-panel.task-mode .bme-task-sidebar { + display: none; + } + .bme-task-nav-mobile { + display: flex; + } + .bme-task-workspace-header { + padding: 14px 16px 10px; + } + .bme-task-workspace-body { + padding: 12px 12px 24px; + } + .bme-pipeline-grid { + grid-template-columns: 1fr; + } + .bme-injection-card-grid { + grid-template-columns: 1fr; + } + .bme-persist-grid { + grid-template-columns: 1fr; + } + .bme-memory-master-detail { + flex-direction: column; + min-height: 0; + } + .bme-memory-list-panel { + width: 100%; + max-width: none; + border-right: none; + border-bottom: 1px solid var(--bme-border); + max-height: 40vh; + } + .bme-memory-detail-panel { + padding: 14px; + } + .bme-batch-stages { + flex-wrap: wrap; + gap: 4px; + } + .bme-batch-stage-line { + display: none; + } +} diff --git a/ui/panel.html b/ui/panel.html index ea83d8a..1ddb734 100644 --- a/ui/panel.html +++ b/ui/panel.html @@ -69,13 +69,9 @@ 总览 - - - + + + + + + + +
@@ -271,45 +319,6 @@
    -
    - -
      -
      - -
      -
      -
      -
      -
      @@ -2638,20 +2647,6 @@ /> -
      -
      -
      消息追踪
      -

      这一轮到底发了什么?

      -

      - 用更白话的方式展示最近一次注入主 AI 的内容,以及送去提取模型的实际请求。 -

      -
      -
      -
      -
      + +
      +
      +
      +
      任务监控
      +

      ST-BME 任务流工作区

      +

      + 实时查看所有任务管线的运行状态与当前批次进度。 +

      +
      +
      + +
      + + + + + + +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      总览 - - +
      +
      + ${detail ? `
      ${_escHtml(detail)}
      ` : ""} + ${substages} +
      +
      + `; + }).join(""); + + el.innerHTML = ` +
      + + ${timeline.length} 条记录 +
      +
      ${entries}
      + `; +} + +// ---------- Memory Browser (Master-Detail) ---------- + +function _refreshTaskMemoryBrowser() { + const el = document.getElementById("bme-task-memory"); + if (!el) return; + + const graph = _getGraph?.(); + if (!graph) { + el.innerHTML = '
      图谱未加载
      '; + return; + } + + const nodes = graph.nodes || []; + const sorted = nodes.slice().sort((a, b) => (b.importance || 0) - (a.importance || 0)); + + const typeClass = (type) => { + switch (type) { + case "pov_memory": case "character": return "type-character"; + case "event": return "type-event"; + case "location": return "type-location"; + case "rule": return "type-rule"; + case "thread": return "type-thread"; + default: return "type-default"; + } + }; + + const typeLabel = (node) => { + if (node.scope === "characterPov") return "角色POV"; + if (node.scope === "userPov") return "用户POV"; + return node.type || "memory"; + }; + + const listItems = sorted.map((node) => { + const sel = node.id === currentSelectedMemoryNodeId ? "selected" : ""; + const preview = (node.description || "").slice(0, 80); + return ` +
      +
      + ${_escHtml(typeLabel(node))} + IMP: ${typeof node.importance === "number" ? node.importance.toFixed(1) : "—"} +
      +
      ${_escHtml(node.label || node.id)}
      +
      ${_escHtml(preview)}
      +
      + SEQ: ${node.lastSeq ?? "—"} + ${node.region ? `LOC: ${_escHtml(node.region)}` : ""} +
      +
      `; + }).join(""); + + const detailHtml = _renderMemoryDetailPanel(sorted.find((n) => n.id === currentSelectedMemoryNodeId) || null, graph); + + el.innerHTML = ` +
      +
      +
      + + +
      +
      + ${listItems || '
      无节点
      '} +
      +
      +
      + ${detailHtml} +
      +
      + `; + + _bindTaskMemoryListClick(); +} + +function _bindTaskMemoryListClick() { + const list = document.getElementById("bme-task-memory-list"); + if (!list) return; + list.addEventListener("click", (e) => { + const item = e.target.closest(".bme-memory-node-item"); + if (!item) return; + currentSelectedMemoryNodeId = item.dataset.nodeId || ""; + list.querySelectorAll(".bme-memory-node-item").forEach((n) => n.classList.toggle("selected", n.dataset.nodeId === currentSelectedMemoryNodeId)); + const graph = _getGraph?.(); + const node = (graph?.nodes || []).find((n) => n.id === currentSelectedMemoryNodeId) || null; + const detailEl = document.getElementById("bme-task-memory-detail"); + if (detailEl) detailEl.innerHTML = _renderMemoryDetailPanel(node, graph); + }); +} + +function _renderMemoryDetailPanel(node, graph) { + if (!node) return '
      选择左侧节点查看详情
      '; + + const edges = (graph?.edges || []).filter((e) => e.source === node.id || e.target === node.id); + const badges = [ + node.type ? `${_escHtml(node.type)}` : "", + node.scope ? `${_escHtml(node.scope)}` : "", + node.archived ? 'ARCHIVED' : "", + ].filter(Boolean).join(""); + + const fields = [ + ["ID", node.id], + ["Owner", node.owner || "—"], + ["Region", node.region || "—"], + ["Importance", typeof node.importance === "number" ? node.importance.toFixed(2) : "—"], + ["Last Seq", node.lastSeq ?? "—"], + ["Created", node.createdAt || "—"], + ["Updated", node.updatedAt || "—"], + ]; + + return ` +
      ${_escHtml(node.label || node.id)}
      +
      ${badges}
      +
      ${_escHtml(node.description || "无描述")}
      +
      + ${fields.map(([k, v]) => `
      ${_escHtml(k)}${_escHtml(String(v))}
      `).join("")} +
      +
      + ${edges.length} 条连接 + recall ${node.recallCount ?? 0} +
      + `; +} + +// ---------- Injection Preview ---------- + +function _refreshTaskInjectionPreview() { + const el = document.getElementById("bme-task-injection"); + if (!el) return; + + const debug = _getRuntimeDebugSnapshot?.() || {}; + const rd = debug.runtimeDebug || {}; + const injection = rd?.injections?.recall || null; + + if (!injection) { + el.innerHTML = '
      暂无注入数据
      '; + return; + } + + const totalTokens = injection.tokenCount || 0; + const budgetTokens = injection.budgetTokens || totalTokens || 1; + const pct = Math.min(100, Math.round((totalTokens / budgetTokens) * 100)); + + const sections = Array.isArray(injection.sections) ? injection.sections : []; + const injectionText = injection.text || injection.injectionText || ""; + + const cardsHtml = sections.length + ? sections.map((s) => ` +
      +
      + ${_escHtml(s.title || s.type || "section")} + ${typeof s.tokenCount === "number" ? `${s.tokenCount} tok` : ""} +
      +
      ${_escHtml(s.text || s.content || "")}
      +
      + `).join("") + : `
      +
      + Full Injection + ${totalTokens} tok +
      +
      ${_escHtml(injectionText.slice(0, 2000))}${injectionText.length > 2000 ? "…" : ""}
      +
      `; + + el.innerHTML = ` +
      + ${totalTokens} / ${budgetTokens} tok +
      +
      +
      + ${pct}% +
      +
      ${cardsHtml}
      + `; +} + +// ---------- Message Trace ---------- + +function _refreshTaskMessageTrace() { + const el = document.getElementById("bme-task-trace"); + if (!el) return; + + const settings = _getSettings?.() || {}; + const state = _getMessageTraceWorkspaceState(settings); + el.innerHTML = _renderMessageTraceWorkspace(state); +} + +// ---------- Persistence Status ---------- + +function _refreshTaskPersistence() { + const el = document.getElementById("bme-task-persistence"); + if (!el) return; + + const graph = _getGraph?.() || {}; + const ps = graph.graphPersistenceState || {}; + const rs = graph.runtimeState || {}; + + const kvs = [ + ["Load State", ps.loadState || "unknown"], + ["Storage Tier", ps.acceptedStorageTier || "—"], + ["Last Accepted Rev", ps.lastAcceptedRevision ?? "—"], + ["Commit Marker", ps.currentCommitMarker ? "present" : "none"], + ["Blocked Reason", ps.blockedReason || "—"], + ["IDB Snapshot Rev", ps.indexedDbSnapshotRevision ?? "—"], + ["Chat State Rev", ps.chatStateSnapshotRevision ?? "—"], + ["Shadow Snapshot", ps.hasShadowSnapshot ? "yes" : "no"], + ]; + + const kvHtml = kvs.map(([k, v]) => `
      ${_escHtml(k)}${_escHtml(String(v))}
      `).join(""); + + const journalCount = Array.isArray(rs.historyState?.batchJournal) ? rs.historyState.batchJournal.length : 0; + const secondaryKvs = [ + ["Graph Nodes", String((graph.nodes || []).length)], + ["Graph Edges", String((graph.edges || []).length)], + ["Batch Journal", String(journalCount)], + ["Runtime Rev", String(rs.graphRevision ?? "—")], + ]; + const secondaryHtml = secondaryKvs.map(([k, v]) => `
      ${_escHtml(k)}${_escHtml(v)}
      `).join(""); + + el.innerHTML = ` +
      +
      +
      Persistence State
      + ${kvHtml} +
      +
      +
      Runtime Stats
      + ${secondaryHtml} +
      +
      + `; } // ==================== 图谱视图切换 ==================== @@ -4025,19 +4514,8 @@ function _bindActions() { if (!result?.skipDashboardRefresh) { _refreshDashboard(); _refreshGraph(); - if ( - document - .getElementById("bme-pane-memory") - ?.classList.contains("active") - ) { - _refreshMemoryBrowser(); - } - if ( - document - .getElementById("bme-pane-injection") - ?.classList.contains("active") - ) { - await _refreshInjectionPreview(); + if (currentTabId === "task") { + _refreshTaskMonitor(); } } if (!result?.handledToast) { @@ -4117,13 +4595,7 @@ function _bindActions() { }); _refreshDashboard(); _refreshGraph(); - if ( - document - .getElementById("bme-pane-memory") - ?.classList.contains("active") - ) { - _refreshMemoryBrowser(); - } + if (currentTabId === "task") _refreshTaskMonitor(); } catch (error) { console.error("[ST-BME] Action extractTask failed:", error); toastr.error(`重新提取失败: ${error?.message || error}`, "ST-BME"); @@ -4204,13 +4676,7 @@ function _bindActions() { }); _refreshDashboard(); _refreshGraph(); - if ( - document - .getElementById("bme-pane-memory") - ?.classList.contains("active") - ) { - _refreshMemoryBrowser(); - } + if (currentTabId === "task") _refreshTaskMonitor(); } catch (error) { console.error("[ST-BME] Action rebuildSummaryState failed:", error); toastr.error(`重建总结状态失败: ${error?.message || error}`, "ST-BME"); @@ -4248,13 +4714,7 @@ function _bindActions() { ); _refreshDashboard(); _refreshGraph(); - if ( - document - .getElementById("bme-pane-memory") - ?.classList.contains("active") - ) { - _refreshMemoryBrowser(); - } + if (currentTabId === "task") _refreshTaskMonitor(); } catch (error) { console.error("[ST-BME] Action clearGraphRange failed:", error); toastr.error(`按楼层范围清理失败: ${error?.message || error}`, "ST-BME"); @@ -4410,8 +4870,7 @@ function _bindActions() { _refreshDashboard(); _refreshGraph(); _refreshSummaryWorkspace(); - _refreshMemoryBrowser(); - void _refreshInjectionPreview(); + if (currentTabId === "task") _refreshTaskMonitor(); } catch (error) { console.error(`[ST-BME] summary workspace action failed: ${actionKey}`, error); toastr.error(String(error?.message || error || "操作失败"), "ST-BME");