dsh-context 0.10.2 → 0.10.3

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 +1 -1
  2. package/lib/client.js +82 -37
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -40,7 +40,7 @@ Type `/context` (or pick it from the `/` menu) and press Enter: a centered dialo
40
40
 
41
41
  ### 📊 Context stats — the session at a glance
42
42
 
43
- Turns, steps, how much context has been recycled by compactions and prunes, how many injections happened, model switches, and the estimated total tokens sent — next to the provider-reported actuals, so you can see how the estimate holds up.
43
+ Turns, steps, how many injections, compactions, and prunes have happened.
44
44
 
45
45
  ### 🧱 Current composition — what's in the window right now
46
46
 
package/lib/client.js CHANGED
@@ -25,13 +25,15 @@ var DICT_ZH = {
25
25
  "stats.hint": "\u7EDF\u8BA1\u5F53\u524D\u4FDD\u7559\u7684\u5386\u53F2\u7A97\u53E3\uFF08\u4E0E\u8D8B\u52BF\u56FE\u4E00\u81F4\uFF09",
26
26
  "stats.turns": "\u8F6E\u6B21",
27
27
  "stats.steps": "\u6B65\u6570",
28
- "stats.recycled": "\u2702 \u56DE\u6536",
29
- "stats.recycleSub": "\u538B\u7F29 {c} \u6B21 \xB7 \u526A\u679D {p} \u6B21",
30
- "stats.injects": "\uFF0B \u6CE8\u5165",
31
- "stats.switches": "\u21C4 \u6A21\u578B\u5207\u6362",
32
- "stats.est": "\u2248 \u7D2F\u8BA1\u4F30\u7B97",
33
- "stats.actualPrompt": "\u5B9E\u9645 prompt",
34
- "stats.output": "\u8F93\u51FA",
28
+ "stats.injects": "\u6CE8\u5165",
29
+ "stats.compactions": "\u538B\u7F29",
30
+ "stats.prunes": "\u526A\u679D",
31
+ "plugin.title": "\u63D2\u4EF6\u4FE1\u606F",
32
+ "plugin.hint": "\u611F\u8C22\u4F7F\u7528 \xB7 \u6B22\u8FCE Star \u4E0E\u53CD\u9988 \u2B50",
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",
35
37
  "tools.top": "\u5DE5\u5177\u5B9A\u4E49 Top\uFF1A",
36
38
  "tools.more": "\u7B49 {n} \u4E2A",
37
39
  "trend.title": "\u5386\u53F2\u8D8B\u52BF",
@@ -98,13 +100,15 @@ var DICT_EN = {
98
100
  "stats.hint": "Over the retained history window (same as the History chart)",
99
101
  "stats.turns": "Turns",
100
102
  "stats.steps": "Steps",
101
- "stats.recycled": "\u2702 Recycled",
102
- "stats.recycleSub": "{c} compactions \xB7 {p} prunes",
103
- "stats.injects": "\uFF0B Injections",
104
- "stats.switches": "\u21C4 Model switches",
105
- "stats.est": "\u2248 Estimated total",
106
- "stats.actualPrompt": "actual prompt",
107
- "stats.output": "output",
103
+ "stats.injects": "Injections",
104
+ "stats.compactions": "Compactions",
105
+ "stats.prunes": "Prunes",
106
+ "plugin.title": "Plugin info",
107
+ "plugin.hint": "Thanks for using \u2014 stars & feedback welcome \u2B50",
108
+ "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)",
108
112
  "tools.top": "Top tool schemas:",
109
113
  "tools.more": "of {n}",
110
114
  "trend.title": "History",
@@ -656,8 +660,8 @@ var STYLES = [
656
660
  ".lc-card-title { font-weight: 600; margin-bottom: 10px; display: flex; align-items: baseline; gap: 8px; }",
657
661
  ".lc-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); gap: 8px; }",
658
662
  ".lc-stat { background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l1); border-radius: 8px; padding: 8px 10px; display: flex; flex-direction: column; gap: 2px; min-width: 0; }",
659
- ".lc-stat-label { color: var(--dsw-alias-label-secondary); font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }",
660
- ".lc-stat-value { color: var(--dsw-alias-label-primary); font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }",
663
+ ".lc-stat-label { color: var(--dsw-alias-label-secondary); font-size: 11px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }",
664
+ ".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; }",
661
665
  ".lc-stat-sub { color: var(--dsw-alias-label-secondary); font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }",
662
666
  ".lc-card-sub { font-weight: 400; color: var(--dsw-alias-label-secondary); font-size: 12px; }",
663
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; }",
@@ -746,6 +750,19 @@ var STYLES = [
746
750
  ".lc-detail-pct { width: 34px; text-align: right; color: var(--dsw-alias-label-secondary); }",
747
751
  ".lc-cols { display: flex; gap: 14px; flex-wrap: wrap; }",
748
752
  ".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; }",
749
766
  ".lc-events, .lc-nodes { display: flex; flex-direction: column; gap: 2px; max-height: 320px; overflow-y: auto; }",
750
767
  ".lc-event { display: flex; align-items: center; gap: 8px; padding: 3px 0; }",
751
768
  ".lc-event-icon { width: 18px; text-align: center; color: var(--dsw-alias-state-warn-primary); }",
@@ -867,36 +884,63 @@ function makeNodeList(kit) {
867
884
  };
868
885
  }
869
886
 
887
+ // src/client/meta.ts
888
+ var PLUGIN_NAME = "dsh-context";
889
+ var PLUGIN_VERSION = true ? "0.10.3" : "0.0.0-dev";
890
+ 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
+ var PLUGIN_REPO_SHORT = PLUGIN_REPO.replace(/^https?:\/\/github\.com\//, "");
893
+
894
+ // src/client/components/pluginInfo.tsx
895
+ var latestCache;
896
+ function makePluginInfo(kit) {
897
+ const { t, tr } = kit;
898
+ return function PluginInfo() {
899
+ const [latest, setLatest] = React.useState(latestCache);
900
+ 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);
911
+ });
912
+ return () => {
913
+ alive = false;
914
+ };
915
+ }, []);
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)));
924
+ };
925
+ }
926
+
870
927
  // src/client/components/statsBoard.tsx
871
928
  function makeStatsBoard(kit) {
872
- const { t, tr, fmt: fmt3 } = kit;
929
+ const { t, fmt: fmt3 } = kit;
873
930
  return function StatsBoard(props) {
874
931
  const turns = /* @__PURE__ */ new Set();
875
- let steps = 0, compactions = 0, prunes = 0, injects = 0, switches = 0;
876
- let recycled = 0, est = 0, prompt = 0, output = 0;
932
+ let steps = 0, compactions = 0, prunes = 0, injects = 0;
877
933
  for (const req of props.requests) {
878
934
  turns.add(req.turn ?? 0);
879
935
  steps++;
880
- est += req.total;
881
- if (typeof req.prompt === "number") prompt += req.prompt;
882
- if (typeof req.output === "number") output += req.output;
883
936
  }
884
937
  for (const ev of props.events) {
885
- if (ev.kind === "compaction") {
886
- compactions++;
887
- recycled += ev.tokens || 0;
888
- } else if (ev.kind === "prune") {
889
- prunes++;
890
- recycled += ev.tokens || 0;
891
- } else if (ev.kind === "inject") injects++;
892
- else if (ev.kind === "model") switches++;
938
+ if (ev.kind === "compaction") compactions++;
939
+ else if (ev.kind === "prune") prunes++;
940
+ else if (ev.kind === "inject") injects++;
893
941
  }
894
- const cell = (label, value, sub) => /* @__PURE__ */ React.createElement("div", { className: "lc-stat" }, /* @__PURE__ */ React.createElement("span", { className: "lc-stat-label" }, label), /* @__PURE__ */ React.createElement("b", { className: "lc-stat-value" }, value), sub !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-stat-sub" }, sub) : null);
895
- return /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("stats.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("stats.hint"))), /* @__PURE__ */ React.createElement("div", { className: "lc-stats" }, cell(t("stats.turns"), fmt3(turns.size)), cell(t("stats.steps"), fmt3(steps)), cell(
896
- t("stats.recycled"),
897
- recycled > 0 ? "\u2212" + fmt3(recycled) : "0",
898
- tr("stats.recycleSub", { c: compactions, p: prunes })
899
- ), cell(t("stats.injects"), fmt3(injects)), cell(t("stats.switches"), fmt3(switches)), cell(t("stats.est"), "\u2248 " + fmt3(est)), cell(t("stats.actualPrompt"), fmt3(prompt)), cell(t("stats.output"), fmt3(output))));
942
+ const cell = (label, value) => /* @__PURE__ */ React.createElement("div", { className: "lc-stat" }, /* @__PURE__ */ React.createElement("span", { className: "lc-stat-label" }, label), /* @__PURE__ */ React.createElement("b", { className: "lc-stat-value" }, value));
943
+ return /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col lc-col-stats" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("stats.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("stats.hint"))), /* @__PURE__ */ React.createElement("div", { className: "lc-stats" }, cell(t("stats.turns"), fmt3(turns.size)), cell(t("stats.steps"), fmt3(steps)), cell(t("stats.injects"), fmt3(injects)), cell(t("stats.compactions"), fmt3(compactions)), cell(t("stats.prunes"), fmt3(prunes))));
900
944
  };
901
945
  }
902
946
 
@@ -911,6 +955,7 @@ function makeContextView(ctx, kit) {
911
955
  const EventList = makeEventList(kit);
912
956
  const NodeList = makeNodeList(kit);
913
957
  const StatsBoard = makeStatsBoard(kit);
958
+ const PluginInfo = makePluginInfo(kit);
914
959
  return function ContextView(props) {
915
960
  const sessionId = props.sessionId;
916
961
  const data = typeof props.useProjection === "function" ? timelineOf(props.useProjection("contextTimeline")) : null;
@@ -975,7 +1020,7 @@ function makeContextView(ctx, kit) {
975
1020
  }
976
1021
  }
977
1022
  const head = headlineOf(data, pressure);
978
- return /* @__PURE__ */ React.createElement("div", { className: "lc-root", ref: rootRef }, /* @__PURE__ */ React.createElement(StatsBoard, { requests, events }), /* @__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) => {
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) => {
979
1024
  return /* @__PURE__ */ React.createElement("span", { key: tool.name, className: "lc-tool-chip" }, tool.name + " " + fmt3(tool.tokens));
980
1025
  }), 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(
981
1026
  "button",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-context",
3
- "version": "0.10.2",
3
+ "version": "0.10.3",
4
4
  "description": "A DeepSeek Harness plugin for context dashboard and context command, for understanding how the context is made of, and how it evolves.",
5
5
  "author": "bowenliang123",
6
6
  "repository": {