dsh-context 0.10.3 → 0.11.0

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 (3) hide show
  1. package/README.md +12 -7
  2. package/lib/client.js +122 -51
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -5,21 +5,26 @@
5
5
  [![npm version](https://img.shields.io/npm/v/dsh-context)](https://www.npmjs.com/package/dsh-context)
6
6
  [![GitHub stars](https://img.shields.io/github/stars/bowenliang123/dsh-context?style=social)](https://github.com/bowenliang123/dsh-context)
7
7
 
8
- **A DeepSeek Harness plugin for context dashboard and context command, for understanding how the context is made of, and how it evolves.**
8
+ **The best [DeepSeek Harness plugin](https://www.deepseek.com/harness/) for Agent's context insights and management.**
9
9
 
10
- `dsh-context` is a [DeepSeek Harness](https://github.com/deepseek-ai/DeepSeek-Harness) plugin for context insight.
10
+ `dsh-context` provides full context lifecycle management features.
11
+ - **Context tab** — an UI context dashboard for DeepSeek Harness’s context stats, composition, history, events, and messages.
12
+ - **`/context` command** — the slash command shows the context model for current context composition and recent context evolution.
11
13
 
12
- - **The Context tab** — a full insight panel for context composition, per-turn context history, context compactions, and the message surface, etc.
13
- - **The `/context` command** — the same headline and recent trend as a centered dialog straight from the composer (the screenshot above).
14
+ ## Install / Update
14
15
 
15
- ## Install
16
-
17
- One command, from any DeepSeek Harness installation:
16
+ To Install from any DeepSeek Harness installation:
18
17
 
19
18
  ```sh
20
19
  dsh plugin --profile web add dsh-context
21
20
  ```
22
21
 
22
+ Or to update the `dsh-context` plugin:
23
+
24
+ ```sh
25
+ dsh plugin --profile web update dsh-context@latest
26
+ ```
27
+
23
28
  Then start the web UI with `dsh web`. No build step, no restart.
24
29
 
25
30
  ## Use it
package/lib/client.js CHANGED
@@ -29,11 +29,9 @@ var DICT_ZH = {
29
29
  "stats.compactions": "\u538B\u7F29",
30
30
  "stats.prunes": "\u526A\u679D",
31
31
  "plugin.title": "\u63D2\u4EF6\u4FE1\u606F",
32
- "plugin.hint": "\u611F\u8C22\u4F7F\u7528 \xB7 \u6B22\u8FCE Star \u4E0E\u53CD\u9988 \u2B50",
32
+ "plugin.hint": "The best DSH context plugin \u2B50",
33
33
  "plugin.name": "\u63D2\u4EF6",
34
- "plugin.version": "\u7248\u672C",
35
- "plugin.updateBadge": "Update!",
36
- "plugin.updateTip": "\u65B0\u7248\u672C v{v} \u53EF\u7528 \xB7 \u6267\u884C dsh plugin --profile web add dsh-context \u66F4\u65B0\uFF08\u70B9\u51FB\u524D\u5F80 npm\uFF09",
34
+ "plugin.github": "GitHub",
37
35
  "tools.top": "\u5DE5\u5177\u5B9A\u4E49 Top\uFF1A",
38
36
  "tools.more": "\u7B49 {n} \u4E2A",
39
37
  "trend.title": "\u5386\u53F2\u8D8B\u52BF",
@@ -52,6 +50,10 @@ var DICT_ZH = {
52
50
  "events.at": "\u7B2C {t} \u8F6E \xB7 \u7B2C {s} \u6B65",
53
51
  "events.range": "\u7B2C {t} \u8F6E \xB7 \u7B2C {a}\u2192{b} \u6B65",
54
52
  "events.rangeTo": "\u7B2C {a} \u8F6E \xB7 \u7B2C {as} \u6B65 \u2192 \u7B2C {b} \u8F6E \xB7 \u7B2C {bs} \u6B65",
53
+ "kind.inject": "\u6CE8\u5165",
54
+ "kind.compaction": "\u538B\u7F29",
55
+ "kind.prune": "\u526A\u679D",
56
+ "kind.model": "\u5207\u6362",
55
57
  "nodes.title": "\u6D88\u606F\u6784\u6210",
56
58
  "nodes.hint": "\u5F53\u524D\u6A21\u578B\u53EF\u89C1\u7684\u6D88\u606F\uFF0C\u6700\u65B0\u5728\u524D",
57
59
  "nodes.more": "\u2026 \u66F4\u65E9\u7684 {n} \u6761\u6D88\u606F\u5DF2\u7701\u7565",
@@ -104,11 +106,9 @@ var DICT_EN = {
104
106
  "stats.compactions": "Compactions",
105
107
  "stats.prunes": "Prunes",
106
108
  "plugin.title": "Plugin info",
107
- "plugin.hint": "Thanks for using \u2014 stars & feedback welcome \u2B50",
109
+ "plugin.hint": "The best DSH context plugin \u2B50",
108
110
  "plugin.name": "Plugin",
109
- "plugin.version": "Version",
110
- "plugin.updateBadge": "Update!",
111
- "plugin.updateTip": "v{v} available \u2014 run `dsh plugin --profile web add dsh-context` to update (click for npm)",
111
+ "plugin.github": "GitHub",
112
112
  "tools.top": "Top tool schemas:",
113
113
  "tools.more": "of {n}",
114
114
  "trend.title": "History",
@@ -127,6 +127,10 @@ var DICT_EN = {
127
127
  "events.at": "Turn {t} \xB7 Step {s}",
128
128
  "events.range": "Turn {t} \xB7 Step {a}\u2192{b}",
129
129
  "events.rangeTo": "Turn {a} \xB7 Step {as} \u2192 Turn {b} \xB7 Step {bs}",
130
+ "kind.inject": "Inject",
131
+ "kind.compaction": "Compact",
132
+ "kind.prune": "Prune",
133
+ "kind.model": "Switch",
130
134
  "nodes.title": "Messages",
131
135
  "nodes.hint": "currently model-visible, newest first",
132
136
  "nodes.more": "\u2026 {n} earlier messages omitted",
@@ -664,7 +668,7 @@ var STYLES = [
664
668
  ".lc-stat-value { color: var(--dsw-alias-label-primary); font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: center; }",
665
669
  ".lc-stat-sub { color: var(--dsw-alias-label-secondary); font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }",
666
670
  ".lc-card-sub { font-weight: 400; color: var(--dsw-alias-label-secondary); font-size: 12px; }",
667
- ".lc-gran { margin-left: auto; display: flex; gap: 2px; background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; padding: 1px; }",
671
+ ".lc-gran, .lc-kinds { margin-left: auto; display: flex; gap: 2px; background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; padding: 1px; }",
668
672
  ".lc-gran-btn { border: 0; background: transparent; color: var(--dsw-alias-label-secondary); font-size: 11px; line-height: 1; padding: 3px 8px; border-radius: 5px; cursor: pointer; font-family: inherit; }",
669
673
  ".lc-gran-btn:hover { color: var(--dsw-alias-label-primary); }",
670
674
  ".lc-gran-on, .lc-gran-on:hover { background: var(--dsw-alias-button-primary-fill); color: var(--dsw-alias-label-primary-foreground); }",
@@ -750,27 +754,47 @@ var STYLES = [
750
754
  ".lc-detail-pct { width: 34px; text-align: right; color: var(--dsw-alias-label-secondary); }",
751
755
  ".lc-cols { display: flex; gap: 14px; flex-wrap: wrap; }",
752
756
  ".lc-col { flex: 1; min-width: 280px; }",
753
- // Head row: the stats board (five cells) takes the wider share, the plugin
754
- // card (three cells) the narrower both wrap onto their own line when tight.
755
- ".lc-col-stats { flex: 3; min-width: 380px; }",
756
- ".lc-col-plugin { flex: 2; min-width: 260px; }",
757
- ".lc-stat-link { color: var(--dsw-alias-brand-primary); text-decoration: none; font-weight: 600; }",
758
- // Whole-cell link (Plugin info): the anchor carries the stat-cell chrome,
759
- // so the entire padded box is one hit target; hovering anywhere on it
760
- // underlines the value and tints the border for affordance.
761
- ".lc-stat-cell { text-decoration: none; cursor: pointer; transition: border-color 120ms ease; }",
762
- ".lc-stat-cell:hover { border-color: var(--dsw-alias-brand-primary); }",
763
- ".lc-stat:hover .lc-stat-link { text-decoration: underline; }",
764
- // "Update!" pill inside the version cell (update = good news -> brand fill).
765
- ".lc-update-badge { margin-left: 6px; font-size: 10px; font-weight: 600; background: var(--dsw-alias-button-primary-fill); color: var(--dsw-alias-label-primary-foreground); border-radius: 4px; padding: 1px 6px; }",
757
+ // Head row: stats board + plugin info sit side by side under the shared
758
+ // `lc-cols` flex stats takes ~7/10 of the row, plugin info ~3/10, both
759
+ // wrap onto their own line when the available width falls below each card's
760
+ // min-width (so a narrow viewport keeps both readable). Both children are
761
+ // `.lc-card` themselves (rendered by StatsBoard / PluginInfo); the flex
762
+ // sizing lives on the head row's direct children so the existing card
763
+ // chrome doesn't change.
764
+ ".lc-head > .lc-card { margin-bottom: 0; }",
765
+ ".lc-head > .lc-card:first-child { flex: 7 1 0; min-width: 360px; }",
766
+ ".lc-head > .lc-card:last-child { flex: 3 1 0; min-width: 220px; }",
767
+ // Plugin info: two full-width rows (Plugin / GitHub), each one horizontal
768
+ // line with the label on the left and the value on the right a compact
769
+ // definition list rather than a multi-cell grid.
770
+ ".lc-pi-grid { display: grid; grid-template-columns: 1fr; gap: 8px; }",
771
+ // The row IS the link: an `<a>` with the label + value on one baseline.
772
+ // Hovering a row underlines its value — the only hover affordance.
773
+ ".lc-pi-row { display: flex; flex-direction: row; justify-content: space-between; align-items: baseline; gap: 12px; min-width: 0; text-decoration: none; color: inherit; }",
774
+ ".lc-pi-row:hover .lc-pi-value { text-decoration: underline; }",
775
+ // Upgrade chip appended to the Plugin value when the npm registry has a
776
+ // newer version than the baked-in one.
777
+ ".lc-pi-update { color: var(--dsw-alias-state-warn-primary); font-size: 11px; margin-left: 6px; white-space: nowrap; }",
778
+ ".lc-pi-label { flex: none; color: var(--dsw-alias-label-secondary); font-size: 11px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }",
779
+ // min-width: 0 lets the value shrink inside the flex row and truncate with
780
+ // an ellipsis; without it a narrow card pushes the value over the label.
781
+ ".lc-pi-value { min-width: 0; color: var(--dsw-alias-label-primary); font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: right; }",
766
782
  ".lc-events, .lc-nodes { display: flex; flex-direction: column; gap: 2px; max-height: 320px; overflow-y: auto; }",
767
783
  ".lc-event { display: flex; align-items: center; gap: 8px; padding: 3px 0; }",
768
784
  ".lc-event-icon { width: 18px; text-align: center; color: var(--dsw-alias-state-warn-primary); }",
769
785
  ".lc-event-icon.lc-event-inject { color: #a855f7; }",
770
786
  ".lc-event-icon.lc-event-model { color: var(--dsw-alias-brand-primary); }",
787
+ // Kind chip: the event classification at a glance; the tint matches the
788
+ // impact direction (inject = adds context, compaction/prune = frees it,
789
+ // model switch = neutral), mirroring the token sign colors below.
790
+ ".lc-kind { flex: none; font-size: 10px; font-weight: 600; padding: 1px 6px; border-radius: 4px; white-space: nowrap; }",
791
+ ".lc-kind-inject { background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent); color: var(--dsw-alias-state-success-primary); }",
792
+ ".lc-kind-compaction { background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 15%, transparent); color: var(--dsw-alias-state-error-primary); }",
793
+ ".lc-kind-prune { background: color-mix(in srgb, #8b5cf6 15%, transparent); color: #8b5cf6; }",
794
+ ".lc-kind-model { background: color-mix(in srgb, var(--dsw-alias-brand-primary) 15%, transparent); color: var(--dsw-alias-brand-primary); }",
771
795
  ".lc-event-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }",
772
796
  ".lc-event-at { flex: none; color: var(--dsw-alias-label-secondary); font-size: 11px; white-space: nowrap; }",
773
- ".lc-event-tokens { color: var(--dsw-alias-state-success-primary); }",
797
+ ".lc-event-tokens { color: var(--dsw-alias-state-success-primary); font-weight: 600; white-space: nowrap; }",
774
798
  ".lc-event-tokens.lc-up { color: var(--dsw-alias-state-warn-primary); }",
775
799
  ".lc-event-time { color: var(--dsw-alias-label-secondary); font-size: 12px; }",
776
800
  ".lc-node { display: flex; align-items: center; gap: 8px; padding: 3px 0; }",
@@ -846,12 +870,25 @@ function makeEventList(kit) {
846
870
  if (props.events.length === 0) {
847
871
  return /* @__PURE__ */ React.createElement("div", { className: "lc-empty" }, t("events.empty"));
848
872
  }
873
+ const rootRef = React.useRef(null);
874
+ React.useLayoutEffect(() => {
875
+ const root = rootRef.current;
876
+ if (!root) return;
877
+ const sync = () => {
878
+ for (const el of root.querySelectorAll(".lc-event-label")) {
879
+ el.title = el.scrollWidth > el.clientWidth ? el.textContent || "" : "";
880
+ }
881
+ };
882
+ sync();
883
+ window.addEventListener("resize", sync);
884
+ return () => window.removeEventListener("resize", sync);
885
+ });
849
886
  const sorted = props.events.slice().reverse();
850
- return /* @__PURE__ */ React.createElement("div", { className: "lc-events" }, sorted.map((ev, i) => {
887
+ return /* @__PURE__ */ React.createElement("div", { className: "lc-events", ref: rootRef }, sorted.map((ev, i) => {
851
888
  const label = eventLabel(ev);
852
889
  const at = eventAt(ev);
853
890
  const glyph = ev.kind === "inject" ? /* @__PURE__ */ React.createElement(import_dsh_client_ui_primitives.IconPlusOutline16, null) : ev.kind === "model" ? /* @__PURE__ */ React.createElement(import_dsh_client_ui_primitives.IconBranchOutline16, null) : EVENT_ICONS[ev.kind] || "\u2022";
854
- return /* @__PURE__ */ React.createElement("div", { key: ev.seq + "-" + i, className: "lc-event" }, /* @__PURE__ */ React.createElement("span", { className: "lc-event-icon lc-event-" + ev.kind }, glyph), /* @__PURE__ */ React.createElement("span", { className: "lc-event-label", title: label }, label), at !== null ? /* @__PURE__ */ React.createElement("span", { className: "lc-event-at" }, at) : null, ev.tokens ? /* @__PURE__ */ React.createElement("span", { className: "lc-event-tokens" + (ev.kind === "inject" ? " lc-up" : " lc-down") }, (ev.kind === "inject" ? "+" : "\u2212") + fmt3(ev.tokens)) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-event-time" }, fmtTime2(ev.time)));
891
+ return /* @__PURE__ */ React.createElement("div", { key: ev.seq + "-" + i, className: "lc-event" }, /* @__PURE__ */ React.createElement("span", { className: "lc-event-icon lc-event-" + ev.kind }, glyph), /* @__PURE__ */ React.createElement("span", { className: "lc-kind lc-kind-" + ev.kind }, t("kind." + ev.kind)), /* @__PURE__ */ React.createElement("span", { className: "lc-event-label" }, label), at !== null ? /* @__PURE__ */ React.createElement("span", { className: "lc-event-at" }, at) : null, ev.tokens ? /* @__PURE__ */ React.createElement("span", { className: "lc-event-tokens" + (ev.kind === "inject" ? " lc-up" : " lc-down") }, (ev.kind === "inject" ? "+" : "\u2212") + fmt3(ev.tokens)) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-event-time" }, fmtTime2(ev.time)));
855
892
  }));
856
893
  };
857
894
  }
@@ -886,41 +923,55 @@ function makeNodeList(kit) {
886
923
 
887
924
  // src/client/meta.ts
888
925
  var PLUGIN_NAME = "dsh-context";
889
- var PLUGIN_VERSION = true ? "0.10.3" : "0.0.0-dev";
926
+ var PLUGIN_VERSION = true ? "0.11.0" : "0.0.0-dev";
890
927
  var PLUGIN_REPO = true ? "https://github.com/bowenliang123/dsh-context" : "https://github.com/bowenliang123/dsh-context";
891
- var PLUGIN_NPM = "https://www.npmjs.com/package/" + PLUGIN_NAME;
892
928
  var PLUGIN_REPO_SHORT = PLUGIN_REPO.replace(/^https?:\/\/github\.com\//, "");
893
929
 
930
+ // src/client/latestVersion.ts
931
+ var REGISTRY_URL = "https://registry.npmjs.org/" + PLUGIN_NAME + "/latest";
932
+ var TTL_MS = 60 * 60 * 1e3;
933
+ var cached = null;
934
+ function fetchLatestVersion() {
935
+ if (!cached || Date.now() - cached.at >= TTL_MS) {
936
+ cached = {
937
+ at: Date.now(),
938
+ promise: fetch(REGISTRY_URL).then((res) => res.ok ? res.json() : null).then((body) => body && typeof body.version === "string" ? body.version : null).catch(() => null)
939
+ };
940
+ }
941
+ return cached.promise;
942
+ }
943
+ function isNewerVersion(latest, current) {
944
+ const parse = (v) => v.replace(/^v/, "").split("-", 1)[0].split(".").map((n) => parseInt(n, 10) || 0);
945
+ const a = parse(latest);
946
+ const b = parse(current);
947
+ for (let i = 0; i < Math.max(a.length, b.length); i++) {
948
+ const x = a[i] || 0;
949
+ const y = b[i] || 0;
950
+ if (x !== y) return x > y;
951
+ }
952
+ return false;
953
+ }
954
+
894
955
  // src/client/components/pluginInfo.tsx
895
- var latestCache;
896
956
  function makePluginInfo(kit) {
897
- const { t, tr } = kit;
957
+ const { t } = kit;
958
+ const row = (label, value, href) => /* @__PURE__ */ React.createElement("a", { className: "lc-pi-row", href, target: "_blank", rel: "noreferrer" }, /* @__PURE__ */ React.createElement("div", { className: "lc-pi-label" }, label), /* @__PURE__ */ React.createElement("div", { className: "lc-pi-value" }, value));
898
959
  return function PluginInfo() {
899
- const [latest, setLatest] = React.useState(latestCache);
960
+ const [latest, setLatest] = React.useState(null);
900
961
  React.useEffect(() => {
901
- if (latestCache !== void 0) return void 0;
902
- let alive = true;
903
- fetch("https://registry.npmjs.org/" + PLUGIN_NAME + "/latest").then((res) => res.ok ? res.json() : null).then((body) => {
904
- if (!alive) return;
905
- latestCache = body && typeof body.version === "string" ? body.version : null;
906
- setLatest(latestCache);
907
- }).catch(() => {
908
- if (!alive) return;
909
- latestCache = null;
910
- setLatest(null);
962
+ if (PLUGIN_VERSION.includes("-dev")) return;
963
+ let on = true;
964
+ fetchLatestVersion().then((v) => {
965
+ if (on && v) setLatest(v);
911
966
  });
912
967
  return () => {
913
- alive = false;
968
+ on = false;
914
969
  };
915
970
  }, []);
916
- const update = typeof latest === "string" && latest !== PLUGIN_VERSION;
917
- const cell = (label, value, href, title) => /* @__PURE__ */ React.createElement("a", { className: "lc-stat lc-stat-cell", href, target: "_blank", rel: "noreferrer", title }, /* @__PURE__ */ React.createElement("span", { className: "lc-stat-label" }, label), /* @__PURE__ */ React.createElement("b", { className: "lc-stat-value lc-stat-link" }, value));
918
- return /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col lc-col-plugin" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("plugin.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("plugin.hint"))), /* @__PURE__ */ React.createElement("div", { className: "lc-stats" }, cell(t("plugin.name"), PLUGIN_NAME, PLUGIN_REPO), cell(
919
- t("plugin.version"),
920
- /* @__PURE__ */ React.createElement(React.Fragment, null, "v" + PLUGIN_VERSION, update ? /* @__PURE__ */ React.createElement("span", { className: "lc-update-badge" }, t("plugin.updateBadge")) : null),
921
- PLUGIN_NPM,
922
- update ? tr("plugin.updateTip", { v: latest ?? "" }) : void 0
923
- ), cell("GitHub", PLUGIN_REPO_SHORT + " \u2197", PLUGIN_REPO)));
971
+ const update = latest !== null && isNewerVersion(latest, PLUGIN_VERSION) ? latest : null;
972
+ const nameValue = [PLUGIN_NAME + " (v" + PLUGIN_VERSION + ")"];
973
+ if (update) nameValue.push(/* @__PURE__ */ React.createElement("span", { key: "update", className: "lc-pi-update" }, "\u2191 v" + update));
974
+ return /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("plugin.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("plugin.hint"))), /* @__PURE__ */ React.createElement("div", { className: "lc-pi-grid" }, row(t("plugin.name"), nameValue, PLUGIN_REPO + "/releases"), row(t("plugin.github"), PLUGIN_REPO_SHORT, PLUGIN_REPO)));
924
975
  };
925
976
  }
926
977
 
@@ -946,6 +997,7 @@ function makeStatsBoard(kit) {
946
997
 
947
998
  // src/client/components/contextView.tsx
948
999
  var viewScroll = /* @__PURE__ */ new Map();
1000
+ var EVENT_KINDS = ["inject", "compaction", "prune", "model"];
949
1001
  function makeContextView(ctx, kit) {
950
1002
  const { t, tr, fmt: fmt3, fmtTime: fmtTime2, catLabel } = kit;
951
1003
  const StackedBar = makeStackedBar(kit);
@@ -966,6 +1018,14 @@ function makeContextView(ctx, kit) {
966
1018
  const [tick, setTick] = React.useState(0);
967
1019
  const [granularity, setGranularity] = React.useState("step");
968
1020
  const [hoverCat, setHoverCat] = React.useState(null);
1021
+ const [pickedKinds, setPickedKinds] = React.useState([...EVENT_KINDS]);
1022
+ const toggleKind = (k) => {
1023
+ setPickedKinds((p) => {
1024
+ if (p.length === EVENT_KINDS.length) return [k];
1025
+ if (!p.includes(k)) return [...p, k];
1026
+ return p.length === 1 ? [...EVENT_KINDS] : p.filter((x) => x !== k);
1027
+ });
1028
+ };
969
1029
  const rootRef = React.useRef(null);
970
1030
  const scrollerRef = React.useRef(null);
971
1031
  const restoredRef = React.useRef(null);
@@ -997,6 +1057,7 @@ function makeContextView(ctx, kit) {
997
1057
  }
998
1058
  const requests = data.requests || [];
999
1059
  const events = data.events || [];
1060
+ const shownEvents = pickedKinds.length === EVENT_KINDS.length ? events : events.filter((e) => pickedKinds.includes(e.kind));
1000
1061
  const nodes = data.nodes || [];
1001
1062
  const displayRequests = granularity === "turn" ? aggregateByTurn(requests) : requests;
1002
1063
  const markers = attachMarkers(displayRequests, events);
@@ -1020,7 +1081,7 @@ function makeContextView(ctx, kit) {
1020
1081
  }
1021
1082
  }
1022
1083
  const head = headlineOf(data, pressure);
1023
- return /* @__PURE__ */ React.createElement("div", { className: "lc-root", ref: rootRef }, /* @__PURE__ */ React.createElement("div", { className: "lc-cols" }, /* @__PURE__ */ React.createElement(StatsBoard, { requests, events }), /* @__PURE__ */ React.createElement(PluginInfo, null)), /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("overview.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, (data.model ? data.model : "") + (data.provider ? " \xB7 " + data.provider : ""))), /* @__PURE__ */ React.createElement("div", { className: "lc-overview-num" }, /* @__PURE__ */ React.createElement("b", null, fmt3(head.tokens)), /* @__PURE__ */ React.createElement("span", null, head.window ? " / " + fmt3(head.window) + " " + tr("overview.ofWindow", { p: head.pct ?? 0 }) : " " + t("overview.estimate")), !head.estimated ? /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("overview.splitEst")) : null), /* @__PURE__ */ React.createElement(StackedBar, { parts: head.parts, height: 16, max: head.window, hoverKey: hoverCat, onHoverKey: setHoverCat }), /* @__PURE__ */ React.createElement(Legend, { parts: head.parts, hoverKey: hoverCat, onHoverKey: setHoverCat }), data.toolList && data.toolList.length > 0 ? /* @__PURE__ */ React.createElement("div", { className: "lc-tools" }, t("tools.top"), data.toolList.slice().sort((a, b) => b.tokens - a.tokens).slice(0, 5).map((tool) => {
1084
+ return /* @__PURE__ */ React.createElement("div", { className: "lc-root", ref: rootRef }, /* @__PURE__ */ React.createElement("div", { className: "lc-cols lc-head" }, /* @__PURE__ */ React.createElement(StatsBoard, { requests, events }), /* @__PURE__ */ React.createElement(PluginInfo, null)), /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("overview.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, (data.model ? data.model : "") + (data.provider ? " \xB7 " + data.provider : ""))), /* @__PURE__ */ React.createElement("div", { className: "lc-overview-num" }, /* @__PURE__ */ React.createElement("b", null, fmt3(head.tokens)), /* @__PURE__ */ React.createElement("span", null, head.window ? " / " + fmt3(head.window) + " " + tr("overview.ofWindow", { p: head.pct ?? 0 }) : " " + t("overview.estimate")), !head.estimated ? /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("overview.splitEst")) : null), /* @__PURE__ */ React.createElement(StackedBar, { parts: head.parts, height: 16, max: head.window, hoverKey: hoverCat, onHoverKey: setHoverCat }), /* @__PURE__ */ React.createElement(Legend, { parts: head.parts, hoverKey: hoverCat, onHoverKey: setHoverCat }), data.toolList && data.toolList.length > 0 ? /* @__PURE__ */ React.createElement("div", { className: "lc-tools" }, t("tools.top"), data.toolList.slice().sort((a, b) => b.tokens - a.tokens).slice(0, 5).map((tool) => {
1024
1085
  return /* @__PURE__ */ React.createElement("span", { key: tool.name, className: "lc-tool-chip" }, tool.name + " " + fmt3(tool.tokens));
1025
1086
  }), data.toolList.length > 5 ? /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, " " + tr("tools.more", { n: data.toolList.length })) : null) : null), /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("trend.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("trend.hint")), /* @__PURE__ */ React.createElement("div", { className: "lc-gran" }, /* @__PURE__ */ React.createElement(
1026
1087
  "button",
@@ -1054,7 +1115,17 @@ function makeContextView(ctx, kit) {
1054
1115
  onHover: setHoveredSeq,
1055
1116
  onHoverTurn: setHoverTurn
1056
1117
  }
1057
- ), /* @__PURE__ */ React.createElement(RequestDetail, { request: activeReq, marker: activeReq !== null ? markerOf(activeReq) : void 0 }))), /* @__PURE__ */ React.createElement("div", { className: "lc-cols" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("events.title")), /* @__PURE__ */ React.createElement(EventList, { events })), /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("nodes.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("nodes.hint"))), /* @__PURE__ */ React.createElement(NodeList, { nodes, dropped: data.droppedNodes || 0 }))), /* @__PURE__ */ React.createElement("div", { className: "lc-foot" }, t("footer")));
1118
+ ), /* @__PURE__ */ React.createElement(RequestDetail, { request: activeReq, marker: activeReq !== null ? markerOf(activeReq) : void 0 }))), /* @__PURE__ */ React.createElement("div", { className: "lc-cols" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("events.title"), /* @__PURE__ */ React.createElement("div", { className: "lc-kinds" }, EVENT_KINDS.map((k) => /* @__PURE__ */ React.createElement(
1119
+ "button",
1120
+ {
1121
+ key: k,
1122
+ className: "lc-gran-btn" + (pickedKinds.includes(k) ? " lc-gran-on lc-kind-" + k : ""),
1123
+ onClick: () => {
1124
+ toggleKind(k);
1125
+ }
1126
+ },
1127
+ t("kind." + k)
1128
+ )))), /* @__PURE__ */ React.createElement(EventList, { events: shownEvents })), /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("nodes.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("nodes.hint"))), /* @__PURE__ */ React.createElement(NodeList, { nodes, dropped: data.droppedNodes || 0 }))), /* @__PURE__ */ React.createElement("div", { className: "lc-foot" }, t("footer")));
1058
1129
  };
1059
1130
  }
1060
1131
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-context",
3
- "version": "0.10.3",
4
- "description": "A DeepSeek Harness plugin for context dashboard and context command, for understanding how the context is made of, and how it evolves.",
3
+ "version": "0.11.0",
4
+ "description": "A DeepSeek Harness plugin for context insight and management, with context dashboard and context command, for understanding how the context is made of, and how it evolves.",
5
5
  "author": "bowenliang123",
6
6
  "repository": {
7
7
  "type": "git",