dsh-more 0.1.2 → 0.1.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.
package/dist/client.js CHANGED
@@ -48,7 +48,8 @@ var PATCH_CATALOG = [
48
48
  { "id": "fast-mode", "name": "\u52A0\u901F", "description": "\u5728\u8F93\u5165\u6846\u548C /fast \u547D\u4EE4\u4E2D\u5F00\u5173\u52A0\u901F\u3002\u54CD\u5E94\u66F4\u5FEB\uFF0C\u4F46\u4F1A\u66F4\u5FEB\u6D88\u8017\u989D\u5EA6", "defaultEnabled": true, "order": 550, "clientKind": "standalone" },
49
49
  { "id": "session-auto-title", "name": "\u4F1A\u8BDD\u81EA\u52A8\u547D\u540D", "description": "\u65B0\u4F1A\u8BDD\u9996\u6761\u9700\u6C42\u540E\uFF0C\u4F7F\u7528\u5F53\u524D\u6A21\u578B\u751F\u6210\u300C\u7C7B\u578B \xB7 \u5177\u4F53\u4EFB\u52A1\u300D\u6807\u9898\uFF1B\u4FDD\u7559\u624B\u52A8\u547D\u540D\uFF0C\u5931\u8D25\u65F6\u4FDD\u7559\u539F\u6709\u6807\u9898", "defaultEnabled": true, "order": 600, "clientKind": "standalone" },
50
50
  { "id": "projectless-tasks", "name": "\u72EC\u7ACB\u4EFB\u52A1", "description": "\u5728\u5DE5\u4F5C\u533A\u4E0B\u62C9\u6846\u521B\u5EFA\u72EC\u7ACB\u4EFB\u52A1\u5E76\u4FDD\u7559\u8349\u7A3F\uFF0C\u4E5F\u53EF\u5C06\u672A\u5206\u7EC4\u4F1A\u8BDD\u79FB\u5165\u5DE5\u4F5C\u533A\u5217\u8868", "defaultEnabled": true, "order": 700, "clientKind": "standalone" },
51
- { "id": "terminal-clipboard", "name": "\u7EC8\u7AEF\u590D\u5236\u7C98\u8D34", "description": "\u53F3\u4FA7\u7EC8\u7AEF\u9009\u4E2D\u81EA\u52A8\u590D\u5236\u3001\u53F3\u952E\u7C98\u8D34\uFF0C\u652F\u6301 Ctrl+Shift+C/V \u548C Shift+Insert\uFF1B\u65E0\u9009\u533A\u65F6\u4FDD\u7559 Ctrl+C \u4E2D\u65AD", "defaultEnabled": true, "order": 800, "clientKind": "standalone" }
51
+ { "id": "terminal-clipboard", "name": "\u7EC8\u7AEF\u590D\u5236\u7C98\u8D34", "description": "\u53F3\u4FA7\u7EC8\u7AEF\u9009\u4E2D\u81EA\u52A8\u590D\u5236\u3002Ctrl+C \u590D\u5236\u9009\u533A\uFF0C\u65E0\u9009\u533A\u65F6\u4E2D\u65AD\u547D\u4EE4\u3002Ctrl+V \u6216\u53F3\u952E\u7C98\u8D34\u7EAF\u6587\u672C\uFF0C\u81EA\u52A8\u6E05\u9664\u7EC8\u7AEF\u989C\u8272\u63A7\u5236\u7801\u3002", "defaultEnabled": true, "order": 800, "clientKind": "standalone" },
52
+ { "id": "terminal-host-stats", "name": "\u7EC8\u7AEF\u4E3B\u673A\u72B6\u6001", "description": "\u5728\u53F3\u4FA7\u7EC8\u7AEF\u9876\u90E8\u663E\u793A\u4E3B\u673A CPU\u3001\u5185\u5B58\u3001\u78C1\u76D8\u53EF\u7528\u7A7A\u95F4\u548C\u5B9E\u65F6\u8BFB\u5199\u901F\u7387", "defaultEnabled": true, "order": 810, "clientKind": "standalone" }
52
53
  ];
53
54
  var DEFAULT_PATCH_SETTINGS = {
54
55
  "message-edit": true,
@@ -59,7 +60,8 @@ var DEFAULT_PATCH_SETTINGS = {
59
60
  "fast-mode": true,
60
61
  "session-auto-title": true,
61
62
  "projectless-tasks": true,
62
- "terminal-clipboard": true
63
+ "terminal-clipboard": true,
64
+ "terminal-host-stats": true
63
65
  };
64
66
  function decodePatchSettings(value) {
65
67
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
@@ -2493,6 +2495,10 @@ function resolveTerminal(root) {
2493
2495
  }
2494
2496
 
2495
2497
  // src/patches/terminal-clipboard/client/clipboard.ts
2498
+ function pasteText(term, text) {
2499
+ const plain = text.replace(/(?:\x1b\[|\x9b)[\d:;]*m/g, "").replace(/(?:\x1b\]|\x9d)(?:[45]|1\d|10[45]|11\d)(?:;[^\x00-\x1f\x7f-\x9f]*)?(?:\x07|\x1b\\|\x9c)/g, "");
2500
+ if (plain) term.paste(plain);
2501
+ }
2496
2502
  function installTerminalClipboard(doc, resolve = resolveTerminal) {
2497
2503
  let active = true;
2498
2504
  let gesture;
@@ -2500,6 +2506,7 @@ function installTerminalClipboard(doc, resolve = resolveTerminal) {
2500
2506
  let notice;
2501
2507
  let noticeTimer;
2502
2508
  const clipboard = doc.defaultView?.navigator.clipboard;
2509
+ const macShortcuts = /^(Mac|iPhone|iPad|iPod)/.test(doc.defaultView?.navigator.platform ?? "");
2503
2510
  const rootAt = (target) => {
2504
2511
  if (!(target instanceof Element)) return;
2505
2512
  return target.closest(".xterm") ?? void 0;
@@ -2536,7 +2543,7 @@ function installTerminalClipboard(doc, resolve = resolveTerminal) {
2536
2543
  if (!clipboard?.readText) throw new Error("Clipboard unavailable");
2537
2544
  const text = await clipboard.readText();
2538
2545
  if (!active || revision !== pasteRevision || !root.isConnected || resolve(root) !== term || term.options.disableStdin || !root.contains(doc.activeElement)) return;
2539
- if (text) term.paste(text);
2546
+ pasteText(term, text);
2540
2547
  } catch {
2541
2548
  report("\u7C98\u8D34");
2542
2549
  }
@@ -2545,6 +2552,14 @@ function installTerminalClipboard(doc, resolve = resolveTerminal) {
2545
2552
  event.preventDefault();
2546
2553
  event.stopImmediatePropagation();
2547
2554
  };
2555
+ const nativePaste = (event) => {
2556
+ const root = rootAt(event.target);
2557
+ const term = root && resolve(root);
2558
+ if (!term || term.options.disableStdin || !event.clipboardData) return;
2559
+ consume(event);
2560
+ pasteRevision++;
2561
+ pasteText(term, event.clipboardData.getData("text/plain"));
2562
+ };
2548
2563
  const contextmenu = (event) => {
2549
2564
  if (event.shiftKey) return;
2550
2565
  const root = rootAt(event.target);
@@ -2565,8 +2580,12 @@ function installTerminalClipboard(doc, resolve = resolveTerminal) {
2565
2580
  if (event.metaKey && !event.ctrlKey) return;
2566
2581
  consume(event);
2567
2582
  if (!event.repeat) void copy(selection);
2568
- } else if (key === "v" && event.ctrlKey && event.shiftKey && !event.metaKey || key === "insert" && event.shiftKey && !event.ctrlKey && !event.metaKey) {
2583
+ } else if (key === "v" && event.ctrlKey && !event.metaKey || key === "insert" && event.shiftKey && !event.ctrlKey && !event.metaKey) {
2569
2584
  if (term.options.disableStdin) return;
2585
+ if (key === "v" && !event.shiftKey && !macShortcuts && !event.repeat) {
2586
+ event.stopImmediatePropagation();
2587
+ return;
2588
+ }
2570
2589
  consume(event);
2571
2590
  if (!event.repeat) void paste(root, term);
2572
2591
  }
@@ -2593,6 +2612,7 @@ function installTerminalClipboard(doc, resolve = resolveTerminal) {
2593
2612
  pasteRevision++;
2594
2613
  };
2595
2614
  doc.addEventListener("contextmenu", contextmenu, true);
2615
+ doc.addEventListener("paste", nativePaste, true);
2596
2616
  doc.addEventListener("keydown", keydown, true);
2597
2617
  doc.addEventListener("mousedown", mousedown, true);
2598
2618
  doc.addEventListener("mouseup", mouseup, true);
@@ -2601,6 +2621,7 @@ function installTerminalClipboard(doc, resolve = resolveTerminal) {
2601
2621
  active = false;
2602
2622
  blur();
2603
2623
  doc.removeEventListener("contextmenu", contextmenu, true);
2624
+ doc.removeEventListener("paste", nativePaste, true);
2604
2625
  doc.removeEventListener("keydown", keydown, true);
2605
2626
  doc.removeEventListener("mousedown", mousedown, true);
2606
2627
  doc.removeEventListener("mouseup", mouseup, true);
@@ -2634,9 +2655,174 @@ var clientPatch7 = {
2634
2655
  }
2635
2656
  };
2636
2657
 
2658
+ // src/patches/terminal-host-stats/shared.ts
2659
+ var TERMINAL_HOST_STATS_ID = "terminal-host-stats";
2660
+
2661
+ // src/patches/terminal-host-stats/client/bar.ts
2662
+ var units = ["B", "KiB", "MiB", "GiB", "TiB", "PiB"];
2663
+ function unit(bytes) {
2664
+ return Math.min(units.length - 1, Math.max(0, Math.floor(Math.log2(Math.max(1, bytes)) / 10)));
2665
+ }
2666
+ function amount(bytes, index) {
2667
+ return Number((bytes / 1024 ** index).toFixed(1)).toString();
2668
+ }
2669
+ function capacity(value, total) {
2670
+ const index = unit(total);
2671
+ const valueUnit = unit(value);
2672
+ if (value > 0 && valueUnit < index) {
2673
+ return amount(value, valueUnit) + " " + units[valueUnit] + "/" + amount(total, index) + " " + units[index];
2674
+ }
2675
+ return amount(value, index) + "/" + amount(total, index) + " " + units[index];
2676
+ }
2677
+ function rate(bytes) {
2678
+ const index = unit(bytes);
2679
+ return amount(bytes, index) + " " + units[index] + "/s";
2680
+ }
2681
+ function createBar(doc) {
2682
+ const node = doc.createElement("div");
2683
+ node.className = "dshmore-host-stats";
2684
+ node.setAttribute("role", "group");
2685
+ node.setAttribute("aria-label", "\u7EC8\u7AEF\u4E3B\u673A\u72B6\u6001");
2686
+ node.style.cssText = "display:flex;flex:none;order:-1;flex-wrap:wrap;align-items:center;gap:3px 14px;padding:4px 10px 6px;border-bottom:1px solid var(--dsw-alias-border-primary, #8884);font-size:11px;line-height:1.5;font-variant-numeric:tabular-nums";
2687
+ const fields = [
2688
+ ["CPU", "\u6240\u6709\u903B\u8F91\u6838\u5FC3\u7684\u5E73\u5747\u4F7F\u7528\u7387"],
2689
+ ["\u5185\u5B58", "\u4E3B\u673A\u5DF2\u7528 / \u603B\u7269\u7406\u5185\u5B58"],
2690
+ ["\u78C1\u76D8\u53EF\u7528", "\u4E3B\u673A\u4E3B\u76EE\u5F55\u6240\u5728\u5377\u7684\u53EF\u7528 / \u603B\u7A7A\u95F4"],
2691
+ ["\u8BFB", "\u4E3B\u673A\u78C1\u76D8\u6BCF\u79D2\u8BFB\u53D6\u7684\u5B57\u8282\u6570"],
2692
+ ["\u5199", "\u4E3B\u673A\u78C1\u76D8\u6BCF\u79D2\u5199\u5165\u7684\u5B57\u8282\u6570"]
2693
+ ];
2694
+ const values = fields.map(([label, hint]) => {
2695
+ const cell = doc.createElement("span");
2696
+ cell.title = hint;
2697
+ cell.style.whiteSpace = "nowrap";
2698
+ const key = doc.createElement("span");
2699
+ key.style.color = "var(--dsw-alias-label-secondary, inherit)";
2700
+ key.textContent = label + " ";
2701
+ const value = doc.createTextNode("\u2014");
2702
+ cell.append(key, value);
2703
+ node.append(cell);
2704
+ return value;
2705
+ });
2706
+ function render(stats, failed = false) {
2707
+ node.title = failed ? "\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u4E3B\u673A\u72B6\u6001\uFF0C\u5C06\u81EA\u52A8\u91CD\u8BD5" : "\u7EC8\u7AEF\u4E3B\u673A\u72B6\u6001 \xB7 \u2014 \u8868\u793A\u7B49\u5F85\u91C7\u6837\u6216\u7CFB\u7EDF\u672A\u63D0\u4F9B\u6B64\u6307\u6807";
2708
+ const display = [
2709
+ stats?.cpuPercent != null ? stats.cpuPercent + "%" : "\u2014",
2710
+ stats?.memory ? capacity(stats.memory.used, stats.memory.total) : "\u2014",
2711
+ stats?.disk ? capacity(stats.disk.available, stats.disk.total) : "\u2014",
2712
+ stats?.io ? rate(stats.io.read) : "\u2014",
2713
+ stats?.io ? rate(stats.io.write) : "\u2014"
2714
+ ];
2715
+ values.forEach((value, i) => {
2716
+ if (value.data !== display[i]) value.data = display[i];
2717
+ });
2718
+ }
2719
+ render(null);
2720
+ return { node, render };
2721
+ }
2722
+
2723
+ // src/patches/terminal-host-stats/client/monitor.ts
2724
+ var selector = "[data-sidebar-terminal]";
2725
+ function installMonitor(doc, sample) {
2726
+ const bars = /* @__PURE__ */ new Map();
2727
+ const visible = /* @__PURE__ */ new Set();
2728
+ let disposed = false;
2729
+ let pending = false;
2730
+ let timer;
2731
+ const active = () => !disposed && !doc.hidden && visible.size > 0;
2732
+ const update = async () => {
2733
+ timer = void 0;
2734
+ if (!active() || pending) return;
2735
+ pending = true;
2736
+ let stats = null;
2737
+ try {
2738
+ stats = await sample();
2739
+ } catch {
2740
+ }
2741
+ pending = false;
2742
+ if (!active()) return;
2743
+ for (const root of visible) bars.get(root)?.render(stats, stats === null);
2744
+ timer = setTimeout(update, 2e3);
2745
+ };
2746
+ const sync = () => {
2747
+ if (!active()) {
2748
+ clearTimeout(timer);
2749
+ timer = void 0;
2750
+ } else if (!pending && timer === void 0) void update();
2751
+ };
2752
+ const visibility = new IntersectionObserver((entries) => {
2753
+ for (const entry of entries) {
2754
+ if (bars.has(entry.target) && entry.isIntersecting) visible.add(entry.target);
2755
+ else visible.delete(entry.target);
2756
+ }
2757
+ sync();
2758
+ });
2759
+ const attach = (root) => {
2760
+ if (bars.has(root) || !root.isConnected) return;
2761
+ const bar = createBar(doc);
2762
+ bars.set(root, bar);
2763
+ root.prepend(bar.node);
2764
+ visibility.observe(root);
2765
+ };
2766
+ const discover = (element) => {
2767
+ if (element.matches(selector)) attach(element);
2768
+ else element.querySelectorAll(selector).forEach(attach);
2769
+ };
2770
+ const observer = new MutationObserver((records) => {
2771
+ for (const [root, bar] of bars) {
2772
+ if (root.isConnected) continue;
2773
+ visibility.unobserve(root);
2774
+ visible.delete(root);
2775
+ bars.delete(root);
2776
+ bar.node.remove();
2777
+ }
2778
+ for (const record2 of records) {
2779
+ if (record2.target instanceof Element && record2.target.closest(selector)) continue;
2780
+ for (const added of record2.addedNodes) if (added instanceof Element) discover(added);
2781
+ }
2782
+ sync();
2783
+ });
2784
+ discover(doc.body);
2785
+ observer.observe(doc.body, { childList: true, subtree: true });
2786
+ doc.addEventListener("visibilitychange", sync);
2787
+ return () => {
2788
+ disposed = true;
2789
+ clearTimeout(timer);
2790
+ doc.removeEventListener("visibilitychange", sync);
2791
+ observer.disconnect();
2792
+ visibility.disconnect();
2793
+ for (const bar of bars.values()) bar.node.remove();
2794
+ bars.clear();
2795
+ visible.clear();
2796
+ };
2797
+ }
2798
+
2799
+ // src/patches/terminal-host-stats/client/index.ts
2800
+ var clientPatch8 = {
2801
+ id: TERMINAL_HOST_STATS_ID,
2802
+ install: (ctx, activation) => {
2803
+ ctx.effect(() => {
2804
+ let dispose;
2805
+ const sync = () => {
2806
+ if (activation.getSnapshot()[TERMINAL_HOST_STATS_ID]) {
2807
+ dispose ??= installMonitor(document, () => callPatchApi(TERMINAL_HOST_STATS_ID, "sample", {}));
2808
+ } else {
2809
+ dispose?.();
2810
+ dispose = void 0;
2811
+ }
2812
+ };
2813
+ const unsubscribe = activation.subscribe(sync);
2814
+ sync();
2815
+ return () => {
2816
+ unsubscribe();
2817
+ dispose?.();
2818
+ };
2819
+ });
2820
+ }
2821
+ };
2822
+
2637
2823
  // src/generated/client-registry.ts
2638
2824
  var MESSAGE_ACTION_PATCHES = [{ id: "message-edit", order: 100, useActions: useMessageActions }, { id: "message-delete", order: 200, useActions: useMessageActions2 }];
2639
- var CLIENT_PATCHES = [clientPatch, clientPatch2, clientPatch3, clientPatch4, clientPatch5, clientPatch6, clientPatch7];
2825
+ var CLIENT_PATCHES = [clientPatch, clientPatch2, clientPatch3, clientPatch4, clientPatch5, clientPatch6, clientPatch7, clientPatch8];
2640
2826
 
2641
2827
  // src/kernel/client/activation.ts
2642
2828
  var ClientPatchActivation = class {
@@ -2897,8 +3083,8 @@ function trajectorySourceSeq(row) {
2897
3083
  return Number.isSafeInteger(seq) && seq >= 0 ? seq : void 0;
2898
3084
  }
2899
3085
  function useMessageTargets(props, hiddenSeqs, hiddenTrajectoryKeys, active = true) {
2900
- const selector = (0, import_react14.useMemo)(() => createMessageSurfaceSelector(active), [active, props.sessionId]);
2901
- const surface = props.useChat(selector);
3086
+ const selector2 = (0, import_react14.useMemo)(() => createMessageSurfaceSelector(active), [active, props.sessionId]);
3087
+ const surface = props.useChat(selector2);
2902
3088
  const surfaceRef = (0, import_react14.useRef)(surface);
2903
3089
  const hiddenSeqsRef = (0, import_react14.useRef)(hiddenSeqs);
2904
3090
  const hiddenTrajectoryKeysRef = (0, import_react14.useRef)(hiddenTrajectoryKeys);
package/dist/index.js CHANGED
@@ -760,11 +760,11 @@ function installLiveSessionHandleTracker(ctx) {
760
760
  tracker.originalResume = originalResume;
761
761
  tracker.createDescriptor = Object.getOwnPropertyDescriptor(registry, "create");
762
762
  tracker.resumeDescriptor = Object.getOwnPropertyDescriptor(registry, "resume");
763
- tracker.wrappedCreate = async function(options) {
764
- return trackedHandle(tracker, await originalCreate.call(this, options));
763
+ tracker.wrappedCreate = async function(options2) {
764
+ return trackedHandle(tracker, await originalCreate.call(this, options2));
765
765
  };
766
- tracker.wrappedResume = async function(options) {
767
- return trackedHandle(tracker, await originalResume.call(this, options));
766
+ tracker.wrappedResume = async function(options2) {
767
+ return trackedHandle(tracker, await originalResume.call(this, options2));
768
768
  };
769
769
  tracker.references = 1;
770
770
  registry[TRACKER] = tracker;
@@ -994,7 +994,7 @@ function sourceLabel(event) {
994
994
  if (source.kind === "plugin") return `\u4E0A\u4E0B\u6587 \xB7 ${singleLine(source.plugin ?? "") || "\u63D2\u4EF6"}`;
995
995
  return "\u4E0A\u4E0B\u6587";
996
996
  }
997
- function conversationMarkdown(events, options) {
997
+ function conversationMarkdown(events, options2) {
998
998
  const sections = [];
999
999
  const renderedCalls = /* @__PURE__ */ new Set();
1000
1000
  const callNames = /* @__PURE__ */ new Map();
@@ -1036,11 +1036,11 @@ function conversationMarkdown(events, options) {
1036
1036
  ));
1037
1037
  }
1038
1038
  }
1039
- const title = singleLine(options.title) || "\u672A\u547D\u540D\u4F1A\u8BDD";
1040
- const exportedAt = isoTime(options.exportedAt ?? Date.now());
1039
+ const title = singleLine(options2.title) || "\u672A\u547D\u540D\u4F1A\u8BDD";
1040
+ const exportedAt = isoTime(options2.exportedAt ?? Date.now());
1041
1041
  const header2 = [
1042
1042
  `# ${title}`,
1043
- `- \u4F1A\u8BDD ID\uFF1A${singleLine(options.sessionId)}`,
1043
+ `- \u4F1A\u8BDD ID\uFF1A${singleLine(options2.sessionId)}`,
1044
1044
  `- \u5BFC\u51FA\u65F6\u95F4\uFF1A${exportedAt}`,
1045
1045
  `- \u8BB0\u5F55\u6761\u76EE\uFF1A${String(sections.length)}`
1046
1046
  ].join("\n\n");
@@ -1236,9 +1236,9 @@ function installDeepSeekReasoning(ctx) {
1236
1236
  if (config.reasoningEffort !== void 0 || revised.reasoningEffort === void 0) return prepared;
1237
1237
  return Object.freeze({ ...prepared, adapterDefaults: Object.freeze({ ...prepared.adapterDefaults, reasoningEffort: true }) });
1238
1238
  };
1239
- const stream = (options) => {
1239
+ const stream = (options2) => {
1240
1240
  try {
1241
- return originalStream.call(llm, revise(options, active ? ruleFor(scope, options.provider, options.model) : void 0));
1241
+ return originalStream.call(llm, revise(options2, active ? ruleFor(scope, options2.provider, options2.model) : void 0));
1242
1242
  } catch (error) {
1243
1243
  if (!(error instanceof LlmError)) throw error;
1244
1244
  return (async function* () {
@@ -1532,7 +1532,7 @@ function patchFastRequest(input, init) {
1532
1532
  }
1533
1533
  function bindFastStream(stream, store) {
1534
1534
  const iterator = stream[Symbol.asyncIterator]();
1535
- const pull = (run) => activeFastSessionStorage.run(store, run);
1535
+ const pull = (run2) => activeFastSessionStorage.run(store, run2);
1536
1536
  const bound = {
1537
1537
  [Symbol.asyncIterator]() {
1538
1538
  return bound;
@@ -1570,9 +1570,9 @@ var hostPatch6 = {
1570
1570
  if (namespace === FAST_MODE_SETTINGS_NS) refreshSettings();
1571
1571
  });
1572
1572
  installFastModeInterceptor();
1573
- const dispose = ctx.on("llm/stream", (options, next) => {
1574
- if (options?.purpose === "session-title" || options?.purpose === "compaction") return next();
1575
- const sessionId = options?.sessionId === void 0 ? void 0 : String(options.sessionId);
1573
+ const dispose = ctx.on("llm/stream", (options2, next) => {
1574
+ if (options2?.purpose === "session-title" || options2?.purpose === "compaction") return next();
1575
+ const sessionId = options2?.sessionId === void 0 ? void 0 : String(options2.sessionId);
1576
1576
  const enabled = sessionId !== void 0 && isFastSession(sessionId) || currentSettings.defaultEnabled;
1577
1577
  if (!enabled) return next();
1578
1578
  return bindFastStream(next(), { sessionId, isFast: true });
@@ -1689,14 +1689,14 @@ var hostPatch7 = {
1689
1689
  const lifetime = new AbortController();
1690
1690
  const forwarded = /* @__PURE__ */ new WeakSet();
1691
1691
  const fiber = ctx.inject(["llm"], (scope) => {
1692
- scope.on("llm/stream", (options, next) => {
1693
- if (options.purpose !== "session-title" || forwarded.has(options)) return next();
1692
+ scope.on("llm/stream", (options2, next) => {
1693
+ if (options2.purpose !== "session-title" || forwarded.has(options2)) return next();
1694
1694
  status.requests += 1;
1695
1695
  const signal = AbortSignal.any([
1696
1696
  lifetime.signal,
1697
- ...options.signal ? [options.signal] : []
1697
+ ...options2.signal ? [options2.signal] : []
1698
1698
  ]);
1699
- const revised = { ...options, system: TITLE_SYSTEM_PROMPT, maxTokens: Math.max(options.maxTokens ?? 0, 2048), signal };
1699
+ const revised = { ...options2, system: TITLE_SYSTEM_PROMPT, maxTokens: Math.max(options2.maxTokens ?? 0, 2048), signal };
1700
1700
  async function* dispatch() {
1701
1701
  if (revised.reasoningEffort === void 0) {
1702
1702
  const info = await scope.llm.resolveModelInfo(revised.provider, revised.model, signal);
@@ -1821,8 +1821,135 @@ var hostPatch9 = {
1821
1821
  routes: () => ({ status: () => ({ available: true }) })
1822
1822
  };
1823
1823
 
1824
+ // src/patches/terminal-host-stats/shared.ts
1825
+ var TERMINAL_HOST_STATS_ID = "terminal-host-stats";
1826
+
1827
+ // src/patches/terminal-host-stats/host/sample.ts
1828
+ import { statfs } from "node:fs/promises";
1829
+ import { cpus, freemem, homedir as homedir2, totalmem } from "node:os";
1830
+
1831
+ // src/patches/terminal-host-stats/host/disks.ts
1832
+ import { execFile } from "node:child_process";
1833
+ import { readdir, readFile } from "node:fs/promises";
1834
+ import { join as join2 } from "node:path";
1835
+ import { promisify } from "node:util";
1836
+ var run = promisify(execFile);
1837
+ var options = { timeout: 4e3, maxBuffer: 1024 * 1024, windowsHide: true };
1838
+ function linuxCounters(source, wholeDisks) {
1839
+ const disks = /* @__PURE__ */ new Map();
1840
+ for (const line of source.trim().split("\n")) {
1841
+ const fields = line.trim().split(/\s+/);
1842
+ const name2 = fields[2];
1843
+ if (!name2 || !wholeDisks.has(name2) || /^(?:loop|ram|zram|dm-|md\d)/.test(name2)) continue;
1844
+ const read2 = Number(fields[5]) * 512;
1845
+ const write2 = Number(fields[9]) * 512;
1846
+ if (Number.isSafeInteger(read2) && read2 >= 0 && Number.isSafeInteger(write2) && write2 >= 0) disks.set(name2, { read: read2, write: write2 });
1847
+ }
1848
+ return disks;
1849
+ }
1850
+ function macCounters(source) {
1851
+ const disks = /* @__PURE__ */ new Map();
1852
+ for (const block of source.split(/(?=^\+-o )/m)) {
1853
+ const id = block.match(/^\+-o .*?\bid (0x[\da-f]+)/i)?.[1];
1854
+ const stats = block.match(/"Statistics"\s*=\s*\{([^}\n]*)\}/)?.[1];
1855
+ if (!id || !stats) continue;
1856
+ const read2 = stats.match(/"Bytes \(Read\)"\s*=\s*(\d+)/)?.[1];
1857
+ const write2 = stats.match(/"Bytes \(Write\)"\s*=\s*(\d+)/)?.[1];
1858
+ if (read2 && write2) disks.set(id, { read: Number(read2), write: Number(write2) });
1859
+ }
1860
+ return disks;
1861
+ }
1862
+ function windowsCounters(source) {
1863
+ const disks = /* @__PURE__ */ new Map();
1864
+ for (const line of source.trim().split(/\r?\n/)) {
1865
+ const match = /^(\d+)(?:\s[^|]*)?\|(\d+)\|(\d+)$/.exec(line.trim());
1866
+ if (match) disks.set(match[1], { read: Number(match[2]), write: Number(match[3]) });
1867
+ }
1868
+ return disks;
1869
+ }
1870
+ async function readDiskCounters() {
1871
+ if (process.platform === "linux") {
1872
+ const [devices, stats] = await Promise.all([readdir("/sys/block"), readFile("/proc/diskstats", "utf8")]);
1873
+ return linuxCounters(stats, new Set(devices));
1874
+ }
1875
+ if (process.platform === "darwin") {
1876
+ const { stdout } = await run("/usr/sbin/ioreg", ["-r", "-c", "IOBlockStorageDriver", "-d", "1", "-w", "0"], options);
1877
+ return macCounters(stdout);
1878
+ }
1879
+ if (process.platform === "win32" && process.env.SystemRoot) {
1880
+ const powershell = join2(process.env.SystemRoot, "System32/WindowsPowerShell/v1.0/powershell.exe");
1881
+ const script = "Get-CimInstance Win32_PerfRawData_PerfDisk_PhysicalDisk | ForEach-Object { '{0}|{1}|{2}' -f $_.Name,$_.DiskReadBytesPersec,$_.DiskWriteBytesPersec }";
1882
+ const { stdout } = await run(powershell, ["-NoProfile", "-NonInteractive", "-Command", script], options);
1883
+ return windowsCounters(stdout);
1884
+ }
1885
+ return /* @__PURE__ */ new Map();
1886
+ }
1887
+
1888
+ // src/patches/terminal-host-stats/host/sample.ts
1889
+ async function readHost() {
1890
+ const [disk, counters] = await Promise.all([
1891
+ statfs(homedir2()).then(({ bavail, blocks, bsize }) => blocks > 0 && bavail >= 0 ? { available: bavail * bsize, total: blocks * bsize } : null).catch(() => null),
1892
+ readDiskCounters().catch(() => /* @__PURE__ */ new Map())
1893
+ ]);
1894
+ const cores = cpus();
1895
+ const cpu = { count: cores.length, idle: 0, total: 0 };
1896
+ for (const { times } of cores) {
1897
+ cpu.idle += times.idle;
1898
+ cpu.total += times.user + times.nice + times.sys + times.idle + times.irq;
1899
+ }
1900
+ const total = totalmem();
1901
+ const memory = total > 0 ? { used: total - freemem(), total } : null;
1902
+ return { at: performance.now(), cpu, memory, disk, counters };
1903
+ }
1904
+ function diskRate(before, after, seconds) {
1905
+ let matched = false;
1906
+ let read2 = 0;
1907
+ let write2 = 0;
1908
+ for (const [id, now] of after) {
1909
+ const prev = before.get(id);
1910
+ if (!prev || now.read < prev.read || now.write < prev.write) continue;
1911
+ read2 += now.read - prev.read;
1912
+ write2 += now.write - prev.write;
1913
+ matched = true;
1914
+ }
1915
+ return matched ? { read: read2 / seconds, write: write2 / seconds } : null;
1916
+ }
1917
+ function createSampler(collect = readHost) {
1918
+ let previous;
1919
+ let cached;
1920
+ let pending;
1921
+ const sample = async () => {
1922
+ const now = await collect();
1923
+ const result = { cpuPercent: null, memory: now.memory, disk: now.disk, io: null };
1924
+ const elapsed = now.at - (previous?.at ?? now.at);
1925
+ if (previous && elapsed > 0 && elapsed <= 15e3) {
1926
+ const total = now.cpu.total - previous.cpu.total;
1927
+ const idle = now.cpu.idle - previous.cpu.idle;
1928
+ if (now.cpu.count === previous.cpu.count && total > 0 && idle >= 0 && idle <= total) {
1929
+ result.cpuPercent = Math.round(100 * (1 - idle / total));
1930
+ }
1931
+ result.io = diskRate(previous.counters, now.counters, elapsed / 1e3);
1932
+ }
1933
+ previous = now;
1934
+ cached = result;
1935
+ return result;
1936
+ };
1937
+ return () => {
1938
+ if (previous && cached && performance.now() - previous.at < 1e3) return Promise.resolve(cached);
1939
+ return pending ??= sample().finally(() => {
1940
+ pending = void 0;
1941
+ });
1942
+ };
1943
+ }
1944
+
1945
+ // src/patches/terminal-host-stats/host/index.ts
1946
+ var hostPatch10 = {
1947
+ id: TERMINAL_HOST_STATS_ID,
1948
+ routes: () => ({ sample: createSampler() })
1949
+ };
1950
+
1824
1951
  // src/generated/host-registry.ts
1825
- var HOST_PATCHES = [hostPatch, hostPatch2, hostPatch3, hostPatch4, hostPatch5, hostPatch6, hostPatch7, hostPatch8, hostPatch9];
1952
+ var HOST_PATCHES = [hostPatch, hostPatch2, hostPatch3, hostPatch4, hostPatch5, hostPatch6, hostPatch7, hostPatch8, hostPatch9, hostPatch10];
1826
1953
 
1827
1954
  // src/generated/patch-catalog.ts
1828
1955
  var PATCH_CATALOG = [
@@ -1834,7 +1961,8 @@ var PATCH_CATALOG = [
1834
1961
  { "id": "fast-mode", "name": "\u52A0\u901F", "description": "\u5728\u8F93\u5165\u6846\u548C /fast \u547D\u4EE4\u4E2D\u5F00\u5173\u52A0\u901F\u3002\u54CD\u5E94\u66F4\u5FEB\uFF0C\u4F46\u4F1A\u66F4\u5FEB\u6D88\u8017\u989D\u5EA6", "defaultEnabled": true, "order": 550, "clientKind": "standalone" },
1835
1962
  { "id": "session-auto-title", "name": "\u4F1A\u8BDD\u81EA\u52A8\u547D\u540D", "description": "\u65B0\u4F1A\u8BDD\u9996\u6761\u9700\u6C42\u540E\uFF0C\u4F7F\u7528\u5F53\u524D\u6A21\u578B\u751F\u6210\u300C\u7C7B\u578B \xB7 \u5177\u4F53\u4EFB\u52A1\u300D\u6807\u9898\uFF1B\u4FDD\u7559\u624B\u52A8\u547D\u540D\uFF0C\u5931\u8D25\u65F6\u4FDD\u7559\u539F\u6709\u6807\u9898", "defaultEnabled": true, "order": 600, "clientKind": "standalone" },
1836
1963
  { "id": "projectless-tasks", "name": "\u72EC\u7ACB\u4EFB\u52A1", "description": "\u5728\u5DE5\u4F5C\u533A\u4E0B\u62C9\u6846\u521B\u5EFA\u72EC\u7ACB\u4EFB\u52A1\u5E76\u4FDD\u7559\u8349\u7A3F\uFF0C\u4E5F\u53EF\u5C06\u672A\u5206\u7EC4\u4F1A\u8BDD\u79FB\u5165\u5DE5\u4F5C\u533A\u5217\u8868", "defaultEnabled": true, "order": 700, "clientKind": "standalone" },
1837
- { "id": "terminal-clipboard", "name": "\u7EC8\u7AEF\u590D\u5236\u7C98\u8D34", "description": "\u53F3\u4FA7\u7EC8\u7AEF\u9009\u4E2D\u81EA\u52A8\u590D\u5236\u3001\u53F3\u952E\u7C98\u8D34\uFF0C\u652F\u6301 Ctrl+Shift+C/V \u548C Shift+Insert\uFF1B\u65E0\u9009\u533A\u65F6\u4FDD\u7559 Ctrl+C \u4E2D\u65AD", "defaultEnabled": true, "order": 800, "clientKind": "standalone" }
1964
+ { "id": "terminal-clipboard", "name": "\u7EC8\u7AEF\u590D\u5236\u7C98\u8D34", "description": "\u53F3\u4FA7\u7EC8\u7AEF\u9009\u4E2D\u81EA\u52A8\u590D\u5236\u3002Ctrl+C \u590D\u5236\u9009\u533A\uFF0C\u65E0\u9009\u533A\u65F6\u4E2D\u65AD\u547D\u4EE4\u3002Ctrl+V \u6216\u53F3\u952E\u7C98\u8D34\u7EAF\u6587\u672C\uFF0C\u81EA\u52A8\u6E05\u9664\u7EC8\u7AEF\u989C\u8272\u63A7\u5236\u7801\u3002", "defaultEnabled": true, "order": 800, "clientKind": "standalone" },
1965
+ { "id": "terminal-host-stats", "name": "\u7EC8\u7AEF\u4E3B\u673A\u72B6\u6001", "description": "\u5728\u53F3\u4FA7\u7EC8\u7AEF\u9876\u90E8\u663E\u793A\u4E3B\u673A CPU\u3001\u5185\u5B58\u3001\u78C1\u76D8\u53EF\u7528\u7A7A\u95F4\u548C\u5B9E\u65F6\u8BFB\u5199\u901F\u7387", "defaultEnabled": true, "order": 810, "clientKind": "standalone" }
1838
1966
  ];
1839
1967
  var DEFAULT_PATCH_SETTINGS = {
1840
1968
  "message-edit": true,
@@ -1845,7 +1973,8 @@ var DEFAULT_PATCH_SETTINGS = {
1845
1973
  "fast-mode": true,
1846
1974
  "session-auto-title": true,
1847
1975
  "projectless-tasks": true,
1848
- "terminal-clipboard": true
1976
+ "terminal-clipboard": true,
1977
+ "terminal-host-stats": true
1849
1978
  };
1850
1979
  function decodePatchSettings(value) {
1851
1980
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
@@ -1934,7 +2063,8 @@ var PatchSettingsSchema = z4.object({
1934
2063
  "fast-mode": z4.boolean().default(true),
1935
2064
  "session-auto-title": z4.boolean().default(true),
1936
2065
  "projectless-tasks": z4.boolean().default(true),
1937
- "terminal-clipboard": z4.boolean().default(true)
2066
+ "terminal-clipboard": z4.boolean().default(true),
2067
+ "terminal-host-stats": z4.boolean().default(true)
1938
2068
  });
1939
2069
 
1940
2070
  // src/kernel/host/settings.ts
@@ -9,6 +9,7 @@ export declare const PatchSettingsSchema: z<Schemastery.ObjectS<NoInfer<{
9
9
  "session-auto-title": z<boolean, boolean, "defined">;
10
10
  "projectless-tasks": z<boolean, boolean, "defined">;
11
11
  "terminal-clipboard": z<boolean, boolean, "defined">;
12
+ "terminal-host-stats": z<boolean, boolean, "defined">;
12
13
  }>>, Schemastery.ObjectT<NoInfer<{
13
14
  "message-edit": z<boolean, boolean, "defined">;
14
15
  "message-delete": z<boolean, boolean, "defined">;
@@ -19,4 +20,5 @@ export declare const PatchSettingsSchema: z<Schemastery.ObjectS<NoInfer<{
19
20
  "session-auto-title": z<boolean, boolean, "defined">;
20
21
  "projectless-tasks": z<boolean, boolean, "defined">;
21
22
  "terminal-clipboard": z<boolean, boolean, "defined">;
23
+ "terminal-host-stats": z<boolean, boolean, "defined">;
22
24
  }>>, "plain">;
@@ -57,10 +57,17 @@ export declare const PATCH_CATALOG: readonly [{
57
57
  }, {
58
58
  readonly id: "terminal-clipboard";
59
59
  readonly name: "终端复制粘贴";
60
- readonly description: "右侧终端选中自动复制、右键粘贴,支持 Ctrl+Shift+C/V 和 Shift+Insert;无选区时保留 Ctrl+C 中断";
60
+ readonly description: "右侧终端选中自动复制。Ctrl+C 复制选区,无选区时中断命令。Ctrl+V 或右键粘贴纯文本,自动清除终端颜色控制码。";
61
61
  readonly defaultEnabled: true;
62
62
  readonly order: 800;
63
63
  readonly clientKind: "standalone";
64
+ }, {
65
+ readonly id: "terminal-host-stats";
66
+ readonly name: "终端主机状态";
67
+ readonly description: "在右侧终端顶部显示主机 CPU、内存、磁盘可用空间和实时读写速率";
68
+ readonly defaultEnabled: true;
69
+ readonly order: 810;
70
+ readonly clientKind: "standalone";
64
71
  }];
65
72
  export type PatchId = typeof PATCH_CATALOG[number]['id'];
66
73
  export interface PatchSettings {
@@ -73,6 +80,7 @@ export interface PatchSettings {
73
80
  "session-auto-title": boolean;
74
81
  "projectless-tasks": boolean;
75
82
  "terminal-clipboard": boolean;
83
+ "terminal-host-stats": boolean;
76
84
  }
77
85
  export declare const DEFAULT_PATCH_SETTINGS: PatchSettings;
78
86
  export declare function decodePatchSettings(value: unknown): PatchSettings | undefined;
@@ -0,0 +1,5 @@
1
+ import type { HostStats } from '../shared.js';
2
+ export declare function createBar(doc: Document): {
3
+ node: HTMLDivElement;
4
+ render: (stats: HostStats | null, failed?: boolean) => void;
5
+ };
@@ -0,0 +1,2 @@
1
+ import type { ClientPatch } from '../../../kernel/client/patch.js';
2
+ export declare const clientPatch: ClientPatch;
@@ -0,0 +1,2 @@
1
+ import type { HostStats } from '../shared.js';
2
+ export declare function installMonitor(doc: Document, sample: () => Promise<HostStats>): () => void;
@@ -0,0 +1,8 @@
1
+ export type Counters = Map<string, {
2
+ read: number;
3
+ write: number;
4
+ }>;
5
+ export declare function linuxCounters(source: string, wholeDisks: ReadonlySet<string>): Counters;
6
+ export declare function macCounters(source: string): Counters;
7
+ export declare function windowsCounters(source: string): Counters;
8
+ export declare function readDiskCounters(): Promise<Counters>;
@@ -0,0 +1,2 @@
1
+ import type { HostPatch } from '../../../kernel/host/patch.js';
2
+ export declare const hostPatch: HostPatch;
@@ -0,0 +1,16 @@
1
+ import type { HostStats } from '../shared.js';
2
+ import { type Counters } from './disks.js';
3
+ interface Reading {
4
+ at: number;
5
+ cpu: {
6
+ count: number;
7
+ idle: number;
8
+ total: number;
9
+ };
10
+ memory: HostStats['memory'];
11
+ disk: HostStats['disk'];
12
+ counters: Counters;
13
+ }
14
+ declare function readHost(): Promise<Reading>;
15
+ export declare function createSampler(collect?: typeof readHost): () => Promise<HostStats>;
16
+ export {};
@@ -0,0 +1,16 @@
1
+ export declare const TERMINAL_HOST_STATS_ID = "terminal-host-stats";
2
+ export interface HostStats {
3
+ cpuPercent: number | null;
4
+ memory: {
5
+ used: number;
6
+ total: number;
7
+ } | null;
8
+ disk: {
9
+ available: number;
10
+ total: number;
11
+ } | null;
12
+ io: {
13
+ read: number;
14
+ write: number;
15
+ } | null;
16
+ }
package/dsh.plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-more",
3
3
  "description": "Practical patches for missing DSH Web context and history controls",
4
- "version": "0.1.2",
4
+ "version": "0.1.3",
5
5
  "entry": {
6
6
  "name": "dsh-more",
7
7
  "inject": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-more",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Practical patches for missing DeepSeek Harness Web context and history controls.",
5
5
  "type": "module",
6
6
  "license": "MIT",