dsh-context 0.2.3 → 0.3.1
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/README.md +0 -12
- package/lib/client.js +70 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -67,17 +67,6 @@ node scripts/build.mjs # writes lib/index.js (host) + lib/client.js (client bu
|
|
|
67
67
|
|
|
68
68
|
`build.mjs` also smoke-checks the outputs (both halves must parse; the host half must import with the `name`/`inject`/`apply` plugin shape).
|
|
69
69
|
|
|
70
|
-
## Publishing
|
|
71
|
-
|
|
72
|
-
`scripts/publish.sh` builds and publishes to npm as the authenticated user:
|
|
73
|
-
|
|
74
|
-
```sh
|
|
75
|
-
NPM_TOKEN=<your npmjs access token> ./scripts/publish.sh # patch bump if the current version is already published
|
|
76
|
-
NPM_TOKEN=<token> ./scripts/publish.sh minor # explicit bump level
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
The token is read from the environment only and never written to disk. The script auto-bumps the version when the current one is already on the registry, so re-running it after a successful publish is a no-op.
|
|
80
|
-
|
|
81
70
|
## Files
|
|
82
71
|
|
|
83
72
|
| File | Role |
|
|
@@ -87,7 +76,6 @@ The token is read from the environment only and never written to disk. The scrip
|
|
|
87
76
|
| `package.json` | `dsh.bundle` (patch layer) + `dsh.client` (web UI) manifests |
|
|
88
77
|
| `cordis.patch.yml` | The bundle's patch layer: inserts the `dsh-context` row |
|
|
89
78
|
| `scripts/build.mjs` | Zero-dependency build of `lib/index.js` + `lib/client.js` |
|
|
90
|
-
| `scripts/publish.sh` | npm publish with `NPM_TOKEN` |
|
|
91
79
|
| `docs/screenshot.png` | The UI in action |
|
|
92
80
|
|
|
93
81
|
## License
|
package/lib/client.js
CHANGED
|
@@ -199,6 +199,11 @@ function makeView(ctx, t) {
|
|
|
199
199
|
|
|
200
200
|
// Plot height in px (the marker lane above it is 18px).
|
|
201
201
|
var CHART_H = 112
|
|
202
|
+
// Fixed column geometry: constant bar width keeps sparse histories from
|
|
203
|
+
// stretching bars, and dense histories scroll horizontally instead of
|
|
204
|
+
// compressing. The turn tick row below mirrors the same column grid.
|
|
205
|
+
var BAR_W = 14
|
|
206
|
+
var BAR_GAP = 2
|
|
202
207
|
|
|
203
208
|
function TrendChart(props) {
|
|
204
209
|
var requests = props.requests
|
|
@@ -218,36 +223,67 @@ function makeView(ctx, t) {
|
|
|
218
223
|
}
|
|
219
224
|
}
|
|
220
225
|
|
|
226
|
+
// Consecutive requests of the same turn collapse into one labeled range.
|
|
227
|
+
var groups = []
|
|
228
|
+
for (var g = 0; g < requests.length; g++) {
|
|
229
|
+
var grp = groups.length > 0 ? groups[groups.length - 1] : null
|
|
230
|
+
if (grp === null || grp.turn !== requests[g].turn) {
|
|
231
|
+
grp = { turn: requests[g].turn, count: 0 }
|
|
232
|
+
groups.push(grp)
|
|
233
|
+
}
|
|
234
|
+
grp.count++
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Stick to the newest bars unless the user scrolled away from the end.
|
|
238
|
+
var scrollRef = React.useRef(null)
|
|
239
|
+
React.useEffect(function () {
|
|
240
|
+
var el = scrollRef.current
|
|
241
|
+
if (el === null) return
|
|
242
|
+
if (el.scrollLeft + el.clientWidth >= el.scrollWidth - 24) el.scrollLeft = el.scrollWidth
|
|
243
|
+
})
|
|
244
|
+
|
|
221
245
|
return h('div', { className: 'lc-chartrow' },
|
|
222
246
|
h('div', { className: 'lc-axis' },
|
|
223
247
|
h('span', { className: 'lc-axis-top' }, fmt(maxTotal)),
|
|
224
248
|
h('span', { className: 'lc-axis-mid' }, fmt(Math.round(maxTotal / 2))),
|
|
225
249
|
h('span', { className: 'lc-axis-bot' }, '0')),
|
|
226
|
-
h('div', { className: 'lc-chart' },
|
|
227
|
-
h('div', { className: 'lc-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
250
|
+
h('div', { className: 'lc-chart-scroll', ref: scrollRef },
|
|
251
|
+
h('div', { className: 'lc-chart' },
|
|
252
|
+
h('div', { className: 'lc-grid lc-grid-top' }),
|
|
253
|
+
h('div', { className: 'lc-grid lc-grid-mid' }),
|
|
254
|
+
requests.map(function (req, i) {
|
|
255
|
+
var selected = props.selectedSeq === req.seq
|
|
256
|
+
var tip = tr('tip.step', { t: req.turn, s: req.step }) + ' · ' + fmtTime(req.time) + '\n'
|
|
257
|
+
+ tr('tip.total', { n: fmt(req.total) })
|
|
258
|
+
+ (req.prompt !== undefined ? tr('tip.actual', { n: fmt(req.prompt) }) : '') + '\n'
|
|
259
|
+
+ CATS.map(function (c) { return catLabel(c.key) + ' ' + fmt(req[c.key] || 0) }).join(' / ')
|
|
260
|
+
return h('div', {
|
|
261
|
+
key: req.seq,
|
|
262
|
+
className: 'lc-bar' + (selected ? ' lc-bar-selected' : ''),
|
|
263
|
+
title: tip,
|
|
264
|
+
onClick: function () { props.onSelect(selected ? null : req.seq) },
|
|
265
|
+
},
|
|
266
|
+
markers[i] ? h('span', { className: 'lc-bar-marker', title: eventLabel(markers[i]) }, '✂') : null,
|
|
267
|
+
h('div', { className: 'lc-bar-stack' },
|
|
268
|
+
CATS.map(function (c) {
|
|
269
|
+
var v = req[c.key] || 0
|
|
270
|
+
if (!v) return null
|
|
271
|
+
// px heights: the stack's height is content-driven, so
|
|
272
|
+
// percentage heights would collapse against an indefinite base.
|
|
273
|
+
return h('div', { key: c.key, style: { height: Math.max(1, Math.round(v / maxTotal * CHART_H)) + 'px', background: c.color } })
|
|
274
|
+
})))
|
|
275
|
+
})),
|
|
276
|
+
h('div', { className: 'lc-turns' },
|
|
277
|
+
groups.map(function (grp, gi) {
|
|
278
|
+
// One column per bar plus the shared gap; the flex gap between
|
|
279
|
+
// ticks restores the inter-group gap, so tick spans line up with
|
|
280
|
+
// their bars exactly.
|
|
281
|
+
return h('span', {
|
|
282
|
+
key: 'turn-' + gi,
|
|
283
|
+
className: 'lc-turn',
|
|
284
|
+
style: { width: (grp.count * (BAR_W + BAR_GAP) - BAR_GAP) + 'px' },
|
|
285
|
+
}, 'T' + grp.turn)
|
|
286
|
+
}))))
|
|
251
287
|
}
|
|
252
288
|
|
|
253
289
|
function RequestDetail(props) {
|
|
@@ -433,21 +469,27 @@ var STYLES = [
|
|
|
433
469
|
'.lc-tools { margin-top: 10px; color: var(--dsw-alias-label-secondary); display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }',
|
|
434
470
|
'.lc-tool-chip { background: var(--dsw-alias-bg-layer-2); border-radius: 4px; padding: 1px 7px; font-size: 12px; color: var(--dsw-alias-label-primary); }',
|
|
435
471
|
'.lc-chartrow { display: flex; gap: 6px; align-items: stretch; }',
|
|
436
|
-
'.lc-axis { position: relative; width: 40px; height:
|
|
472
|
+
'.lc-axis { position: relative; width: 40px; height: 150px; padding-top: 18px; box-sizing: border-box; color: var(--dsw-alias-label-secondary); font-size: 11px; }',
|
|
437
473
|
'.lc-axis span { position: absolute; right: 0; line-height: 1; }',
|
|
438
474
|
'.lc-axis-top { top: 13px; }',
|
|
439
475
|
'.lc-axis-mid { top: 69px; }',
|
|
440
476
|
'.lc-axis-bot { top: 125px; }',
|
|
441
|
-
'.lc-chart {
|
|
477
|
+
'.lc-chart-scroll { flex: 1; overflow-x: auto; overflow-y: hidden; min-width: 0; scrollbar-width: thin; }',
|
|
478
|
+
'.lc-chart-scroll::-webkit-scrollbar { height: 6px; }',
|
|
479
|
+
'.lc-chart-scroll::-webkit-scrollbar-thumb { background: var(--dsw-alias-border-l1); border-radius: 3px; }',
|
|
480
|
+
'.lc-chart-scroll::-webkit-scrollbar-track { background: transparent; }',
|
|
481
|
+
'.lc-chart { position: relative; display: flex; align-items: flex-end; gap: 2px; height: 130px; padding-top: 18px; box-sizing: border-box; width: max-content; min-width: 100%; }',
|
|
442
482
|
'.lc-grid { position: absolute; left: 0; right: 0; border-top: 1px dashed var(--dsw-alias-border-l1); pointer-events: none; }',
|
|
443
483
|
'.lc-grid-top { top: 18px; }',
|
|
444
484
|
'.lc-grid-mid { top: 74px; }',
|
|
445
|
-
'.lc-bar { position: relative;
|
|
485
|
+
'.lc-bar { position: relative; width: 14px; flex: none; height: 100%; display: flex; align-items: flex-end; cursor: pointer; border-radius: 2px; }',
|
|
446
486
|
'.lc-bar:hover { background: var(--dsw-alias-bg-layer-2); }',
|
|
447
487
|
'.lc-bar-selected { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 1px; }',
|
|
448
488
|
'.lc-bar-stack { display: flex; flex-direction: column-reverse; width: 100%; }',
|
|
449
489
|
'.lc-bar-stack > div { width: 100%; }',
|
|
450
490
|
'.lc-bar-marker { position: absolute; top: -16px; left: 50%; transform: translateX(-50%); font-size: 11px; color: var(--dsw-alias-state-warn-primary); }',
|
|
491
|
+
'.lc-turns { display: flex; gap: 2px; width: max-content; min-width: 100%; }',
|
|
492
|
+
'.lc-turn { flex: none; min-width: 24px; box-sizing: border-box; text-align: center; font-size: 11px; line-height: 18px; color: var(--dsw-alias-label-secondary); border-top: 1px solid var(--dsw-alias-border-l1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }',
|
|
451
493
|
'.lc-detail { margin-top: 12px; border-top: 1px solid var(--dsw-alias-border-l1); padding-top: 12px; }',
|
|
452
494
|
'.lc-detail-head { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-bottom: 8px; color: var(--dsw-alias-label-secondary); }',
|
|
453
495
|
'.lc-detail-head b { color: var(--dsw-alias-label-primary); }',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-context",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Context insight panel for DeepSeek Harness: a Context tab (beside Chat/Trajectory) showing what the model's context window is made of and how it evolves — composition, per-request history, compactions, injections, and model switches.",
|
|
5
5
|
"author": "bowenliang123",
|
|
6
6
|
"repository": {
|