@ash-qw/dsh-theme-prts 1.4.1 → 1.4.2
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 +11 -0
- package/lib/client.js +469 -80
- package/package.json +1 -1
- package/src/client/index.js +1 -2
- package/src/client/session-lifeline.js +1 -1
- package/src/client/session-summary-preview.js +116 -2
- package/src/client/sidebar-control-adapter.js +365 -43
- package/src/client/theme-settings-workbench.js +15 -48
- package/src/styles/facility-vector.css +105 -21
- package/src/styles/prts.css +5 -5
- package/src/styles/refinement.css +1 -1
- package/src/styles/theme-settings-workbench.css +6 -32
package/package.json
CHANGED
package/src/client/index.js
CHANGED
|
@@ -96,11 +96,10 @@ export function applyPrtsPlugin(ctx, environment) {
|
|
|
96
96
|
const sidebarControls = createSidebarControlAdapter({
|
|
97
97
|
document,
|
|
98
98
|
window,
|
|
99
|
-
sessions: contextService(ctx, 'sessions'),
|
|
100
|
-
workspaces: contextService(ctx, 'workspaces'),
|
|
101
99
|
getSessionStatus: () => contextService(ctx, 'uiSession')?.sessionStatus,
|
|
102
100
|
getUiWorkspace: () => contextService(ctx, 'uiWorkspace'),
|
|
103
101
|
getSessions: () => contextService(ctx, 'sessions'),
|
|
102
|
+
getWorkspaces: () => contextService(ctx, 'workspaces'),
|
|
104
103
|
getUiConversation: () => contextService(ctx, 'uiConversation'),
|
|
105
104
|
})
|
|
106
105
|
const floatingGlass = createFloatingGlassAdapter({ document, window })
|
|
@@ -138,7 +138,7 @@ export function createSessionLifelineAnimator({ document, window }) {
|
|
|
138
138
|
return Boolean(
|
|
139
139
|
row?.isConnected
|
|
140
140
|
&& lifeline?.isConnected
|
|
141
|
-
&& row.getAttribute('aria-selected') === 'true'
|
|
141
|
+
&& (row.hasAttribute('data-prts-selection-target') ? row.getAttribute('data-prts-selection-target') === 'true' : row.getAttribute('aria-selected') === 'true')
|
|
142
142
|
&& document?.visibilityState !== 'hidden'
|
|
143
143
|
&& document?.documentElement?.dataset?.prtsSessionFlow !== 'off'
|
|
144
144
|
&& document?.documentElement?.dataset?.prtsMotion !== 'reduced'
|
|
@@ -91,7 +91,25 @@ function previewStatusFields(status) {
|
|
|
91
91
|
const pending = status?.pendingInteraction
|
|
92
92
|
return [status?.running, status?.completionUnread, pending, pending?.answer,
|
|
93
93
|
JSON.stringify([pending?.kind, pending?.answerable, pending?.getSnapshot?.().closed,
|
|
94
|
-
pending?.questions, pending?.toolName, pending?.reason, pending?.displayReason])]
|
|
94
|
+
pending?.questions, pending?.callId, pending?.toolName, pending?.reason, pending?.displayReason])]
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function approvalCallDetails(snapshot, pending) {
|
|
98
|
+
if (!pending?.callId) return undefined
|
|
99
|
+
for (const node of snapshot?.nodes?.values?.() ?? []) {
|
|
100
|
+
const root = node.kind === 'tool-call' ? node.data?.root : undefined
|
|
101
|
+
if (!root || root.callId !== pending.callId || 'kind' in root || root.phase !== 'start') continue
|
|
102
|
+
const raw = root.argsRaw
|
|
103
|
+
if (typeof raw !== 'string') return undefined
|
|
104
|
+
try {
|
|
105
|
+
const args = JSON.parse(raw)
|
|
106
|
+
if (args && typeof args === 'object' && !Array.isArray(args) && typeof args.command === 'string') {
|
|
107
|
+
const {command, ...rest} = args
|
|
108
|
+
return {command, parameters: Object.keys(rest).length ? JSON.stringify(rest, null, 2) : ''}
|
|
109
|
+
}
|
|
110
|
+
return {parameters: JSON.stringify(args, null, 2)}
|
|
111
|
+
} catch { return {parameters: raw} }
|
|
112
|
+
}
|
|
95
113
|
}
|
|
96
114
|
|
|
97
115
|
export function createSessionSummaryPreview({ document, window, sessions, getSessions, getUiConversation, getSessionStatus, openSession, getPreviewPreferences, onPreviewClosed, onAnswerSubmitted }) {
|
|
@@ -211,6 +229,73 @@ export function createSessionSummaryPreview({ document, window, sessions, getSes
|
|
|
211
229
|
panel.ownerDocument.body.append(panel)
|
|
212
230
|
current.detached = true
|
|
213
231
|
panel.showPopover?.()
|
|
232
|
+
let positionFrame
|
|
233
|
+
const positionPanels = () => {
|
|
234
|
+
positionFrame = undefined
|
|
235
|
+
if (active !== current) return
|
|
236
|
+
const viewport = window.visualViewport
|
|
237
|
+
const left = (viewport?.offsetLeft ?? 0) + 8, top = (viewport?.offsetTop ?? 0) + 8
|
|
238
|
+
const width = Math.max(1, (viewport?.width ?? window.innerWidth) - 16)
|
|
239
|
+
const height = Math.max(1, (viewport?.height ?? window.innerHeight) - 16)
|
|
240
|
+
const place = (surface, reference, preferredTop, noticeOwner, anchorBottom = preferredTop) => {
|
|
241
|
+
surface.style.maxWidth = 'none'
|
|
242
|
+
surface.style.maxHeight = 'none'
|
|
243
|
+
const bounds = surface.getBoundingClientRect()
|
|
244
|
+
const x = reference ? reference.right + 10 : left
|
|
245
|
+
const fitsVertically = y => y >= top && y + bounds.height <= top + height
|
|
246
|
+
const above = anchorBottom - bounds.height
|
|
247
|
+
const y = !fitsVertically(preferredTop) && fitsVertically(above) ? above : preferredTop
|
|
248
|
+
const insufficient = Boolean(reference) && (x < left || x + bounds.width > left + width || !fitsVertically(y))
|
|
249
|
+
surface.toggleAttribute('data-prts-preview-no-space', insufficient)
|
|
250
|
+
const noticeKey = surface === panel ? 'spaceNotice' : 'detailSpaceNotice'
|
|
251
|
+
if (insufficient && noticeOwner) {
|
|
252
|
+
let notice = current[noticeKey]
|
|
253
|
+
if (!notice) {
|
|
254
|
+
notice = panel.ownerDocument.createElement('div')
|
|
255
|
+
notice.setAttribute('data-prts-preview-space-notice', '')
|
|
256
|
+
notice.setAttribute('role', 'status')
|
|
257
|
+
const guidance = '空间不足,无法展开预览。可点击会话进入;建议扩大窗口,或在辅助功能中关闭对应预览。'
|
|
258
|
+
notice.textContent = surface === panel ? '空间不足,无法展开正文预览' : guidance
|
|
259
|
+
notice.title = guidance
|
|
260
|
+
current[noticeKey] = notice
|
|
261
|
+
}
|
|
262
|
+
if (notice.parentElement !== noticeOwner) noticeOwner.append(notice)
|
|
263
|
+
} else { current[noticeKey]?.remove(); current[noticeKey] = undefined }
|
|
264
|
+
surface.style.left = x + 'px'
|
|
265
|
+
surface.style.top = y + 'px'
|
|
266
|
+
return !insufficient
|
|
267
|
+
}
|
|
268
|
+
const menu = current.anchor?.closest('[data-prts-session-summary-popover]')
|
|
269
|
+
const reference = menu?.getBoundingClientRect()
|
|
270
|
+
const row = current.anchor?.getBoundingClientRect()
|
|
271
|
+
const visible = place(panel, reference, row?.top ?? (parseFloat(panel.style.top) || top), menu, row?.bottom)
|
|
272
|
+
if (current.detail && !current.detail.hidden) {
|
|
273
|
+
if (visible) place(current.detail, panel.getBoundingClientRect(), panel.getBoundingClientRect().top, panel, panel.getBoundingClientRect().bottom)
|
|
274
|
+
else current.detail.setAttribute('data-prts-preview-no-space', '')
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
}
|
|
278
|
+
const schedulePosition = () => {
|
|
279
|
+
if (positionFrame === undefined) positionFrame = window.requestAnimationFrame(positionPanels)
|
|
280
|
+
}
|
|
281
|
+
const positionObserver = window.ResizeObserver ? new window.ResizeObserver(schedulePosition) : undefined
|
|
282
|
+
positionObserver?.observe(panel)
|
|
283
|
+
window.addEventListener('resize', schedulePosition)
|
|
284
|
+
window.visualViewport?.addEventListener('resize', schedulePosition)
|
|
285
|
+
window.visualViewport?.addEventListener('scroll', schedulePosition)
|
|
286
|
+
const cleanupHover = current.cleanupHover
|
|
287
|
+
current.cleanupHover = () => {
|
|
288
|
+
cleanupHover()
|
|
289
|
+
current.spaceNotice?.remove()
|
|
290
|
+
current.detailSpaceNotice?.remove()
|
|
291
|
+
panel.removeAttribute('data-prts-preview-no-space')
|
|
292
|
+
positionObserver?.disconnect()
|
|
293
|
+
window.cancelAnimationFrame(positionFrame)
|
|
294
|
+
window.removeEventListener('resize', schedulePosition)
|
|
295
|
+
window.visualViewport?.removeEventListener('resize', schedulePosition)
|
|
296
|
+
window.visualViewport?.removeEventListener('scroll', schedulePosition)
|
|
297
|
+
}
|
|
298
|
+
schedulePosition()
|
|
214
299
|
const label = panel.querySelector('strong')
|
|
215
300
|
let sessionTitle = panel.querySelector('[data-prts-preview-session-title]')
|
|
216
301
|
if (!sessionTitle) {
|
|
@@ -248,6 +333,7 @@ export function createSessionSummaryPreview({ document, window, sessions, getSes
|
|
|
248
333
|
const pending = pendingNow()
|
|
249
334
|
if (!canAnswerPreview(pending)) return
|
|
250
335
|
current.editor = true
|
|
336
|
+
current.editingPending = pending
|
|
251
337
|
// Detach from the hover menu before promoting again to the top layer.
|
|
252
338
|
panel.setAttribute('data-prts-preview-editing', '')
|
|
253
339
|
panel.setAttribute('role', 'dialog')
|
|
@@ -358,6 +444,8 @@ export function createSessionSummaryPreview({ document, window, sessions, getSes
|
|
|
358
444
|
const hideDetail = () => {
|
|
359
445
|
current.detail?.hidePopover?.()
|
|
360
446
|
if (current.detail) current.detail.hidden = true
|
|
447
|
+
current.detailSpaceNotice?.remove()
|
|
448
|
+
current.detailSpaceNotice = undefined
|
|
361
449
|
detailKey = undefined
|
|
362
450
|
detailEntry?.removeAttribute('data-prts-reply-active')
|
|
363
451
|
detailEntry = undefined
|
|
@@ -377,6 +465,7 @@ export function createSessionSummaryPreview({ document, window, sessions, getSes
|
|
|
377
465
|
detail.append(heading, content)
|
|
378
466
|
panel.append(detail)
|
|
379
467
|
current.detail = detail
|
|
468
|
+
positionObserver?.observe(detail)
|
|
380
469
|
}
|
|
381
470
|
const detail = current.detail
|
|
382
471
|
detailKey = reply.key
|
|
@@ -395,14 +484,38 @@ export function createSessionSummaryPreview({ document, window, sessions, getSes
|
|
|
395
484
|
detail.style.left = (beside ? rect.right + 10 : Math.max(8, Math.min(rect.left, window.innerWidth - width - 8))) + 'px'
|
|
396
485
|
detail.style.top = Math.max(8, Math.min(beside ? rect.top : rect.bottom + 8, window.innerHeight - 240)) + 'px'
|
|
397
486
|
detail.showPopover?.()
|
|
487
|
+
schedulePosition()
|
|
488
|
+
}
|
|
489
|
+
const renderApprovalDetails = pending => {
|
|
490
|
+
if (pending?.kind !== 'approval') return
|
|
491
|
+
const details = approvalCallDetails(source?.getSnapshot(), pending)
|
|
492
|
+
let section = body.querySelector('[data-prts-approval-details]')
|
|
493
|
+
const signature = JSON.stringify(details ?? null)
|
|
494
|
+
if (section?.dataset.signature === signature) return
|
|
495
|
+
if (!section) { section = document.createElement('div'); section.setAttribute('data-prts-approval-details', ''); body.append(section) }
|
|
496
|
+
section.dataset.signature = signature
|
|
497
|
+
section.replaceChildren()
|
|
498
|
+
if (!details) {
|
|
499
|
+
section.textContent = source ? '暂无可用的操作参数,请进入会话核对详情。' : '正在读取操作详情…'
|
|
500
|
+
return
|
|
501
|
+
}
|
|
502
|
+
for (const [name, value] of [['命令', details.command], ['参数', details.parameters]]) {
|
|
503
|
+
if (!value) continue
|
|
504
|
+
const heading = document.createElement('div')
|
|
505
|
+
heading.textContent = name
|
|
506
|
+
const code = document.createElement('pre')
|
|
507
|
+
code.textContent = value
|
|
508
|
+
section.append(heading, code)
|
|
509
|
+
}
|
|
398
510
|
}
|
|
399
511
|
const render = () => {
|
|
400
512
|
if (active !== current) return
|
|
401
|
-
if (current.editor) { current.validate?.(); return }
|
|
513
|
+
if (current.editor) { current.validate?.(); if (pendingNow() === current.editingPending) renderApprovalDetails(current.editingPending); return }
|
|
402
514
|
const status = getSessionStatus?.()?.getSnapshot().get(id)
|
|
403
515
|
const pending = status?.pendingInteraction === current.answeredPending
|
|
404
516
|
? undefined : status?.pendingInteraction
|
|
405
517
|
const approval = pending?.kind === 'approval'
|
|
518
|
+
panel.toggleAttribute('data-prts-preview-approval', approval)
|
|
406
519
|
const question = approval || pending?.kind === 'question' || pending?.kind === 'plan-review'
|
|
407
520
|
const state = question ? 'warning' : status?.running || (current.answeredPending && status?.pendingInteraction === current.answeredPending) ? 'ongoing'
|
|
408
521
|
: status?.completionUnread || status?.running === false ? 'done' : current.group?.getAttribute('data-prts-session-summary-group') || ''
|
|
@@ -506,6 +619,7 @@ export function createSessionSummaryPreview({ document, window, sessions, getSes
|
|
|
506
619
|
previousQuestion = question
|
|
507
620
|
if (!extendsReply) body.scrollTop = 0
|
|
508
621
|
}
|
|
622
|
+
if (approval) renderApprovalDetails(pending)
|
|
509
623
|
if (canAnswerPreview(pending)) enableAnswer()
|
|
510
624
|
}
|
|
511
625
|
let statusFields = previewStatusFields(getSessionStatus?.()?.getSnapshot().get(id))
|