dsh-split-view 0.2.2 → 0.2.4
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/demo.gif +0 -0
- package/demo2.png +0 -0
- package/demo3.png +0 -0
- package/lib/client.js +150 -0
- package/package.json +5 -2
package/demo.gif
ADDED
|
Binary file
|
package/demo2.png
ADDED
|
Binary file
|
package/demo3.png
ADDED
|
Binary file
|
package/lib/client.js
CHANGED
|
@@ -434,6 +434,9 @@ function collectSyncedStorage() {
|
|
|
434
434
|
const PREFS_KEY = "dsh-split:prefs";
|
|
435
435
|
/** Locale namespace of the settings section and its rows. */
|
|
436
436
|
const SETTINGS_NS = "settings.splitView";
|
|
437
|
+
// Keep in sync with the "version" field in package.json — the client bundle
|
|
438
|
+
// has no runtime version source (boot manifest entries carry no version).
|
|
439
|
+
const PLUGIN_VERSION = "0.2.4";
|
|
437
440
|
const ACTION_IDS = ["split-right", "split-down", "close", "maximize"];
|
|
438
441
|
const DEFAULT_SHORTCUTS = Object.freeze({
|
|
439
442
|
"split-right": "Mod+Shift+D",
|
|
@@ -626,6 +629,12 @@ function collectSyncedStorage() {
|
|
|
626
629
|
"reset.title": "恢复默认",
|
|
627
630
|
"reset.button": "恢复默认设置",
|
|
628
631
|
"reset.hint": "把快捷键、选中高亮色、标题栏开关全部还原为默认值。",
|
|
632
|
+
"version.current": "当前版本",
|
|
633
|
+
"version.latest": "最新",
|
|
634
|
+
"version.upToDate": "已是最新",
|
|
635
|
+
"version.upgrade": "升级",
|
|
636
|
+
"version.copied": "已复制",
|
|
637
|
+
"version.upgradeHint": "在终端执行上面的命令后,重启 dsh web 生效。",
|
|
629
638
|
"reset.confirm": "确定把分屏设置全部恢复为默认值吗?"
|
|
630
639
|
};
|
|
631
640
|
|
|
@@ -654,6 +663,12 @@ function collectSyncedStorage() {
|
|
|
654
663
|
"reset.title": "Restore Defaults",
|
|
655
664
|
"reset.button": "Restore default settings",
|
|
656
665
|
"reset.hint": "Reset shortcuts, focus highlight color and the title-bar switch back to their defaults.",
|
|
666
|
+
"version.current": "Current version",
|
|
667
|
+
"version.latest": "Latest",
|
|
668
|
+
"version.upToDate": "Up to date",
|
|
669
|
+
"version.upgrade": "Upgrade",
|
|
670
|
+
"version.copied": "Copied",
|
|
671
|
+
"version.upgradeHint": "Run the command above in a terminal, then restart dsh web to apply.",
|
|
657
672
|
"reset.confirm": "Restore all split-view settings to their defaults?"
|
|
658
673
|
};
|
|
659
674
|
//#endregion
|
|
@@ -1012,6 +1027,43 @@ function collectSyncedStorage() {
|
|
|
1012
1027
|
boxSizing: "border-box"
|
|
1013
1028
|
},
|
|
1014
1029
|
buttonDanger: { color: "var(--dsw-alias-state-error-primary,#e5484d)" },
|
|
1030
|
+
versionRow: { display: "flex", alignItems: "center", gap: "8px", flexWrap: "wrap" },
|
|
1031
|
+
versionText: { color: "var(--dsw-alias-label-tertiary)", fontSize: "12px", lineHeight: "18px" },
|
|
1032
|
+
versionBadge: {
|
|
1033
|
+
display: "inline-flex",
|
|
1034
|
+
alignItems: "center",
|
|
1035
|
+
height: "18px",
|
|
1036
|
+
padding: "0 8px",
|
|
1037
|
+
borderRadius: "999px",
|
|
1038
|
+
fontSize: "12px",
|
|
1039
|
+
lineHeight: "18px"
|
|
1040
|
+
},
|
|
1041
|
+
// Green intentionally uses a raw hex: no theme token is known for success.
|
|
1042
|
+
versionBadgeOk: { color: "#1a7f37", background: "rgba(26,127,55,.12)" },
|
|
1043
|
+
versionBadgeBehind: { color: "var(--dsw-alias-state-warning-primary,#b8860b)", background: "rgba(184,134,11,.14)" },
|
|
1044
|
+
versionButton: {
|
|
1045
|
+
height: "24px",
|
|
1046
|
+
padding: "0 10px",
|
|
1047
|
+
borderRadius: "7px",
|
|
1048
|
+
border: "1px solid var(--dsw-alias-border-l2)",
|
|
1049
|
+
background: "var(--dsw-alias-button-elevated-fill)",
|
|
1050
|
+
color: "var(--dsw-alias-label-primary)",
|
|
1051
|
+
cursor: "pointer",
|
|
1052
|
+
fontSize: "12px",
|
|
1053
|
+
font: "inherit",
|
|
1054
|
+
boxSizing: "border-box"
|
|
1055
|
+
},
|
|
1056
|
+
versionCommand: {
|
|
1057
|
+
marginTop: "8px",
|
|
1058
|
+
padding: "6px 10px",
|
|
1059
|
+
borderRadius: "6px",
|
|
1060
|
+
border: "1px solid var(--dsw-alias-border-l2)",
|
|
1061
|
+
background: "var(--dsw-alias-bg-layer-1)",
|
|
1062
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
1063
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
1064
|
+
fontSize: "12px",
|
|
1065
|
+
userSelect: "text"
|
|
1066
|
+
},
|
|
1015
1067
|
comboChip: {
|
|
1016
1068
|
height: "28px",
|
|
1017
1069
|
minWidth: "110px",
|
|
@@ -1266,6 +1318,95 @@ function collectSyncedStorage() {
|
|
|
1266
1318
|
);
|
|
1267
1319
|
}
|
|
1268
1320
|
|
|
1321
|
+
/** Compare two dotted numeric versions; returns -1 / 0 / 1. */
|
|
1322
|
+
function compareVersions(a, b) {
|
|
1323
|
+
const pa = String(a).split(".").map((n) => parseInt(n, 10) || 0);
|
|
1324
|
+
const pb = String(b).split(".").map((n) => parseInt(n, 10) || 0);
|
|
1325
|
+
const len = Math.max(pa.length, pb.length);
|
|
1326
|
+
for (let i = 0; i < len; i += 1) {
|
|
1327
|
+
const da = pa[i] || 0;
|
|
1328
|
+
const db = pb[i] || 0;
|
|
1329
|
+
if (da < db) return -1;
|
|
1330
|
+
if (da > db) return 1;
|
|
1331
|
+
}
|
|
1332
|
+
return 0;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
/**
|
|
1336
|
+
* Version footer at the bottom of the settings section: current version +
|
|
1337
|
+
* latest-version badge (queried straight from npmmirror/npmjs in the browser,
|
|
1338
|
+
* both registries are CORS-open) + an upgrade entry when behind. Upgrade =
|
|
1339
|
+
* copy the install command for the terminal; the client bundle cannot run
|
|
1340
|
+
* shell itself, and a one-click upgrade would need server-side orchestration
|
|
1341
|
+
* (the market plugin's approach), which this plugin deliberately avoids.
|
|
1342
|
+
*/
|
|
1343
|
+
function VersionRow({ t }) {
|
|
1344
|
+
const [latest, setLatest] = React.useState(null);
|
|
1345
|
+
const [copied, setCopied] = React.useState(false);
|
|
1346
|
+
const [showCommand, setShowCommand] = React.useState(false);
|
|
1347
|
+
React.useEffect(() => {
|
|
1348
|
+
let alive = true;
|
|
1349
|
+
(async () => {
|
|
1350
|
+
// Debug hook: localStorage dsh-split:debugLatest forces the
|
|
1351
|
+
// "latest" value (exercises the upgrade path without a release).
|
|
1352
|
+
try {
|
|
1353
|
+
const forced = window.localStorage.getItem("dsh-split:debugLatest");
|
|
1354
|
+
if (forced && forced.trim()) {
|
|
1355
|
+
if (alive) setLatest(forced.trim());
|
|
1356
|
+
return;
|
|
1357
|
+
}
|
|
1358
|
+
} catch {
|
|
1359
|
+
// storage unavailable — fall through to the network
|
|
1360
|
+
}
|
|
1361
|
+
const sources = [
|
|
1362
|
+
"https://registry.npmmirror.com/dsh-split-view/latest",
|
|
1363
|
+
"https://registry.npmjs.org/dsh-split-view/latest"
|
|
1364
|
+
];
|
|
1365
|
+
for (const url of sources) {
|
|
1366
|
+
try {
|
|
1367
|
+
const res = await fetch(url, { cache: "no-store" });
|
|
1368
|
+
if (!res.ok) continue;
|
|
1369
|
+
const data = await res.json();
|
|
1370
|
+
if (data && typeof data.version === "string") {
|
|
1371
|
+
if (alive) setLatest(data.version.trim());
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
} catch {
|
|
1375
|
+
// try the next source
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
// Every source failed: stay on the current version alone —
|
|
1379
|
+
// the badge and the upgrade button simply do not render.
|
|
1380
|
+
})();
|
|
1381
|
+
return () => { alive = false; };
|
|
1382
|
+
}, []);
|
|
1383
|
+
const behind = latest !== null && compareVersions(PLUGIN_VERSION, latest) < 0;
|
|
1384
|
+
const command = "dsh plugin --profile web add dsh-split-view@latest";
|
|
1385
|
+
const upgrade = async () => {
|
|
1386
|
+
setShowCommand(true);
|
|
1387
|
+
try {
|
|
1388
|
+
await navigator.clipboard.writeText(command);
|
|
1389
|
+
setCopied(true);
|
|
1390
|
+
setTimeout(() => setCopied(false), 2500);
|
|
1391
|
+
} catch {
|
|
1392
|
+
// clipboard refused — the command box is already on the page
|
|
1393
|
+
}
|
|
1394
|
+
};
|
|
1395
|
+
return React.createElement("div", { style: { padding: "14px 0 2px" } },
|
|
1396
|
+
React.createElement("div", { style: settingsStyles.versionRow },
|
|
1397
|
+
React.createElement("span", { style: settingsStyles.versionText }, t("version.current") + " v" + PLUGIN_VERSION),
|
|
1398
|
+
latest !== null
|
|
1399
|
+
? behind
|
|
1400
|
+
? React.createElement("span", { style: Object.assign({}, settingsStyles.versionBadge, settingsStyles.versionBadgeBehind) }, t("version.latest") + " v" + latest)
|
|
1401
|
+
: React.createElement("span", { style: Object.assign({}, settingsStyles.versionBadge, settingsStyles.versionBadgeOk) }, t("version.upToDate"))
|
|
1402
|
+
: null,
|
|
1403
|
+
behind ? React.createElement("button", { type: "button", style: settingsStyles.versionButton, onClick: upgrade }, copied ? t("version.copied") : t("version.upgrade")) : null
|
|
1404
|
+
),
|
|
1405
|
+
behind && showCommand ? React.createElement("div", { style: settingsStyles.versionCommand }, command) : null,
|
|
1406
|
+
behind && showCommand ? React.createElement("div", { style: settingsStyles.hint }, t("version.upgradeHint")) : null
|
|
1407
|
+
);
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1269
1410
|
/**
|
|
1270
1411
|
* Register the settings section + rows.
|
|
1271
1412
|
* @param ctx - client cordis context.
|
|
@@ -1350,6 +1491,15 @@ function collectSyncedStorage() {
|
|
|
1350
1491
|
inject: bindRow
|
|
1351
1492
|
}, ResetRow));
|
|
1352
1493
|
|
|
1494
|
+
ctx.slots.inject("settings.splitView.item", () => ctx.slots.register({
|
|
1495
|
+
name: "settings.splitView.item",
|
|
1496
|
+
id: "split-view-version",
|
|
1497
|
+
order: 95,
|
|
1498
|
+
store: rowStore,
|
|
1499
|
+
locale: SETTINGS_NS,
|
|
1500
|
+
inject: bindRow
|
|
1501
|
+
}, VersionRow));
|
|
1502
|
+
|
|
1353
1503
|
// The shell's settings nav hard-codes the per-section icon by entry id
|
|
1354
1504
|
// (models / agent-presets / plugins get distinct icons, everything else
|
|
1355
1505
|
// falls back to the generic gear) and the settings.section contract
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-split-view",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Multi-session split view for the DeepSeek Harness web GUI: the top window shadows the root slot with a resizable split container; each pane is an iframe running a full DSH client pinned to its own session, with per-pane title bars, LRU hibernation and a dual-loopback origin pool.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,10 @@
|
|
|
18
18
|
"lib/index.js",
|
|
19
19
|
"lib/client.js",
|
|
20
20
|
"cordis.patch.yml",
|
|
21
|
-
"api.md"
|
|
21
|
+
"api.md",
|
|
22
|
+
"demo.gif",
|
|
23
|
+
"demo2.png",
|
|
24
|
+
"demo3.png"
|
|
22
25
|
],
|
|
23
26
|
"author": "dsh-split-view contributors",
|
|
24
27
|
"repository": {
|