prompt-skill-armory 0.10.4 → 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.
package/README.en.md CHANGED
@@ -12,13 +12,13 @@
12
12
  |--|--|--|--|
13
13
  | <img src="docs/preview/preview-6.png" width="220"/> | <img src="docs/preview/preview-7.png" width="220"/> | | |
14
14
 
15
- ![version](https://img.shields.io/badge/version-0.10.4-00ff9c)
15
+ ![version](https://img.shields.io/badge/version-0.11.0-00ff9c)
16
16
  ![license](https://img.shields.io/badge/license-MIT-blue)
17
17
  ![platform](https://img.shields.io/badge/platform-web%20%2B%20desktop-00ff9c)
18
18
  ![CI](https://github.com/Qian-Ning/prompt-skill-armory/actions/workflows/ci.yml/badge.svg)
19
19
 
20
20
  ```
21
- ✦ Armory v0.10.4
21
+ ✦ Armory v0.11.0
22
22
  ┌─────────┬─────────┬─────┬────────────┬──────┬──────┐
23
23
  │ Prompts │ Skills │ MCP │ Wallpaper │ Chat │ Stats│
24
24
  │ global │ merged │ hub │ wallpaper │ sync │ usage│
@@ -125,7 +125,7 @@ Achieved via profile composition (the installer mounts the panel into each profi
125
125
 
126
126
  Every time the panel opens it queries npm for the latest `prompt-skill-armory` version; when a newer version exists a banner appears:
127
127
 
128
- > New version vX.Y.Z (current v0.10.4) [Update now]
128
+ > New version vX.Y.Z (current v0.11.0) [Update now]
129
129
 
130
130
  Clicking "Update now" makes the Host re-run the official installer in place → "Update complete, please restart the client".
131
131
 
package/README.md CHANGED
@@ -12,13 +12,13 @@
12
12
  |--|--|--|--|
13
13
  | <img src="docs/preview/preview-6.png" width="220"/> | <img src="docs/preview/preview-7.png" width="220"/> | | |
14
14
 
15
- ![version](https://img.shields.io/badge/version-0.10.4-00ff9c)
15
+ ![version](https://img.shields.io/badge/version-0.11.0-00ff9c)
16
16
  ![license](https://img.shields.io/badge/license-MIT-blue)
17
17
  ![platform](https://img.shields.io/badge/platform-web%20%2B%20desktop-00ff9c)
18
18
  ![CI](https://github.com/Qian-Ning/prompt-skill-armory/actions/workflows/ci.yml/badge.svg)
19
19
 
20
20
  ```
21
- ✦ Armory v0.10.4
21
+ ✦ Armory v0.11.0
22
22
  ┌─────────┬─────────┬─────┬────────────┬──────┬──────┐
23
23
  │ 提示词 │ 技能 │ MCP │ Wallpaper │ 对话 │ 统计 │
24
24
  │ 全局注入 │ 合并管理 │ 连接 │ 壁纸·特效 │ 导入 │ 用量 │
@@ -128,7 +128,7 @@ pnpm dsh web
128
128
 
129
129
  插件面板每次打开会自动查询 npm 上 `prompt-skill-armory` 的最新版本;发现新版本时顶部显示横幅:
130
130
 
131
- > 有新版本 vX.Y.Z(当前 v0.10.4) [一键更新]
131
+ > 有新版本 vX.Y.Z(当前 v0.11.0) [一键更新]
132
132
 
133
133
  点击「一键更新」→ Host 端运行官方安装器原地重装 → 提示「更新完成,请重启客户端生效」。
134
134
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prompt-skill-armory",
3
- "version": "0.10.4",
3
+ "version": "0.11.0",
4
4
  "description": "One-command installer for Prompt-SkillArmory (prompts + skills manager) into the DeepSeek Harness (web + desktop)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -460,19 +460,18 @@ window.__ModuleLoader__.load({
460
460
  } catch {}
461
461
  applyHintStyle();
462
462
  }
463
- let hintObserver;
464
463
  /** Inject (or clear) the per-surface style for the composer hint + input card.
465
- * DSH 2.0.9 removed the old `[data-decoration="hint"]` row; the composer card
466
- * (`[data-composer-card]`) is the stable surface that carries the input
467
- * placeholder and inline claim hints, so the style lands there. */
464
+ * (2.0.9) the composer stats strip renders as `[data-composer-stats]` with
465
+ * hashed label/pill classes. Everything is driven by ONE style tag: disabling
466
+ * removes the tag (and nothing else), so the UI returns to its exact original
467
+ * state — no inline styles are ever written, and no layout properties are
468
+ * touched (font/color only, applied to text labels, never the flex containers). */
468
469
  function applyHintStyle() {
469
470
  try {
470
471
  const hint = (bgState.value ?? DEFAULT_BACKGROUND).hint ?? DEFAULT_BACKGROUND.hint;
471
472
  const existing = document.getElementById("switchblade-hint");
472
473
  if (!hint.enabled) {
473
474
  if (existing !== null) existing.remove();
474
- hintObserver?.disconnect();
475
- hintObserver = void 0;
476
475
  return;
477
476
  }
478
477
  if (existing === null) {
@@ -485,52 +484,22 @@ window.__ModuleLoader__.load({
485
484
  const size = hint.size || 11;
486
485
  const gradPreset = GRADIENTS.find((g) => g.id === (hint.gradient ?? ""));
487
486
  const grad = gradPreset !== void 0 ? gradPreset.css : "";
488
- const props = [
487
+ const textProps = [
489
488
  "font-size:" + size + "px",
490
489
  "letter-spacing:0.3px",
491
490
  "font-weight:600",
492
491
  "opacity:0.95",
493
492
  grad !== "" ? "display:inline-block;background-image:" + grad + ";-webkit-background-clip:text;background-clip:text;color:transparent" : `color:${color}`
494
493
  ].join(";");
495
- tag.textContent = `[data-composer-placeholder]{${props}}
496
- [data-composer-card] input::placeholder,[data-composer-card] textarea::placeholder{${props}}
497
- [data-composer-card] [class*="_hint"]{${props}}
498
- [data-composer-stats]{${props}}
499
- [data-composer-stats] [class*="_label"]{${props}}
500
- [data-composer-stats] [class*="_pill"]{${props}}`;
501
- const statsStyle = (root) => {
502
- if (grad !== "") {
503
- root.style.backgroundImage = grad;
504
- root.style.webkitBackgroundClip = "text";
505
- root.style.backgroundClip = "text";
506
- root.style.color = "transparent";
507
- } else {
508
- root.style.backgroundImage = "none";
509
- root.style.webkitBackgroundClip = "initial";
510
- root.style.backgroundClip = "initial";
511
- root.style.color = color;
512
- }
513
- root.style.fontSize = `${size}px`;
514
- root.style.fontWeight = "600";
515
- root.style.opacity = "0.95";
516
- };
517
- const applyStats = () => {
518
- try {
519
- const seps = Array.from(document.querySelectorAll("span[aria-hidden]"));
520
- for (const sep of seps) {
521
- if (sep.textContent !== "·" && sep.textContent !== "|") continue;
522
- const root = sep.parentElement;
523
- if (root !== null) statsStyle(root);
524
- }
525
- } catch {}
526
- };
527
- if (hintObserver !== void 0) hintObserver.disconnect();
528
- hintObserver = new MutationObserver(applyStats);
529
- hintObserver.observe(document.body, {
530
- childList: true,
531
- subtree: true
532
- });
533
- applyStats();
494
+ const cardProps = [
495
+ "font-size:" + size + "px",
496
+ "font-weight:600",
497
+ "opacity:0.95",
498
+ grad !== "" ? "background-image:" + grad + ";-webkit-background-clip:text;background-clip:text;color:transparent" : `color:${color}`
499
+ ].join(";");
500
+ tag.textContent = `[data-composer-placeholder]{${cardProps}}
501
+ [data-composer-card] input::placeholder,[data-composer-card] textarea::placeholder{${cardProps}}
502
+ [data-composer-stats] [class*="_label"]{${textProps}}`;
534
503
  } catch {}
535
504
  }
536
505
  //#endregion
@@ -980,7 +949,7 @@ window.__ModuleLoader__.load({
980
949
  });
981
950
  }
982
951
  /** Bump with every release; keep in sync with package.json version + CHANGELOG. */
983
- const ARMORY_VERSION = "0.10.4";
952
+ const ARMORY_VERSION = "0.11.0";
984
953
  /** Compact duration: 45.2s / 2m42s / 1h05m. */
985
954
  function fmtDuration(ms) {
986
955
  const s = ms / 1e3;
@@ -1418,6 +1387,26 @@ window.__ModuleLoader__.load({
1418
1387
  if (chatProject === "" && chatProjects.length > 0) setChatProject(chatProjects[0].key);
1419
1388
  else if (chatProject !== "" && !chatProjects.some((p) => p.key === chatProject)) setChatProject(chatProjects[0]?.key ?? "");
1420
1389
  }, [chatProjects, chatProject]);
1390
+ const scopeProjectOptions = (0, react.useMemo)(() => chatProjects.map((p) => ({
1391
+ value: p.name,
1392
+ label: p.name
1393
+ })), [chatProjects]);
1394
+ const scopeSessionOptions = (0, react.useMemo)(() => {
1395
+ const seen = /* @__PURE__ */ new Set();
1396
+ const out = [];
1397
+ for (const row of chatRows) {
1398
+ if (seen.has(row.sessionId)) continue;
1399
+ seen.add(row.sessionId);
1400
+ const title = (row.title || "").trim();
1401
+ const short = row.sessionId.replace(/^session-/, "").slice(0, 8);
1402
+ const proj = row.cwd ? row.cwd.split(/[\\/]/).filter(Boolean).pop() ?? "" : row.projectKey;
1403
+ out.push({
1404
+ value: row.sessionId,
1405
+ label: `${title !== "" ? title : "(无标题)"} · ${proj} · ${short}`
1406
+ });
1407
+ }
1408
+ return out;
1409
+ }, [chatRows]);
1421
1410
  const doExportChat = async () => {
1422
1411
  setChatBusy(true);
1423
1412
  setChatMsg("");
@@ -1577,13 +1566,21 @@ window.__ModuleLoader__.load({
1577
1566
  };
1578
1567
  const submitPrompt = () => {
1579
1568
  if (promptName.trim() === "" || promptContent.trim() === "") return;
1569
+ if (promptScopeType !== "global" && promptScopeKey.trim() === "") return;
1580
1570
  setBusy(true);
1571
+ const key = promptScopeKey.trim();
1581
1572
  const scope = promptScopeType === "global" ? void 0 : promptScopeType === "project" ? {
1582
1573
  type: "project",
1583
- key: promptScopeKey.trim()
1584
- } : {
1574
+ key
1575
+ } : promptScopeType === "session" ? {
1585
1576
  type: "session",
1586
- id: promptScopeKey.trim()
1577
+ id: key
1578
+ } : promptScopeType === "exclude-project" ? {
1579
+ type: "exclude-project",
1580
+ key
1581
+ } : {
1582
+ type: "exclude-session",
1583
+ id: key
1587
1584
  };
1588
1585
  (editingPromptId !== void 0 ? updatePrompt(editingPromptId, {
1589
1586
  name: promptName,
@@ -1611,9 +1608,9 @@ window.__ModuleLoader__.load({
1611
1608
  setPromptDesc(row.desc);
1612
1609
  setPromptContent(row.content ?? "");
1613
1610
  const s = row.scope;
1614
- if (s !== void 0 && (s.type === "project" || s.type === "session")) {
1611
+ if (s !== void 0 && s.type !== "global") {
1615
1612
  setPromptScopeType(s.type);
1616
- setPromptScopeKey(s.type === "project" ? s.key ?? "" : s.id ?? "");
1613
+ setPromptScopeKey(s.type === "project" || s.type === "exclude-project" ? s.key ?? "" : s.id ?? "");
1617
1614
  } else {
1618
1615
  setPromptScopeType("global");
1619
1616
  setPromptScopeKey("");
@@ -1887,29 +1884,60 @@ window.__ModuleLoader__.load({
1887
1884
  },
1888
1885
  children: "作用域"
1889
1886
  }),
1890
- [
1891
- "global",
1892
- "project",
1893
- "session"
1894
- ].map((st) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1895
- style: {
1896
- ...CSS.actionBtn,
1897
- ...promptScopeType === st ? CSS.tabActive : {}
1898
- },
1899
- onClick: () => setPromptScopeType(st),
1900
- children: st === "global" ? "全局" : st === "project" ? "指定项目" : "指定会话"
1901
- }, st)),
1902
- promptScopeType !== "global" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1887
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1903
1888
  style: {
1904
1889
  ...CSS.input,
1905
- maxWidth: "240px",
1906
- flex: 1,
1907
- minWidth: "120px"
1890
+ flex: "none",
1891
+ minWidth: "150px"
1908
1892
  },
1909
- placeholder: promptScopeType === "project" ? "项目目录名(如 qc)" : "会话 id(session-…)",
1910
- value: promptScopeKey,
1911
- onChange: (e) => setPromptScopeKey(e.target.value)
1912
- })
1893
+ value: promptScopeType,
1894
+ onChange: (e) => {
1895
+ setPromptScopeType(e.target.value);
1896
+ setPromptScopeKey("");
1897
+ },
1898
+ children: [
1899
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1900
+ value: "global",
1901
+ children: "全局(所有项目/会话)"
1902
+ }),
1903
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1904
+ value: "project",
1905
+ children: "仅指定项目"
1906
+ }),
1907
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1908
+ value: "session",
1909
+ children: "仅指定会话"
1910
+ }),
1911
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1912
+ value: "exclude-project",
1913
+ children: "除指定项目外(其余全部生效)"
1914
+ }),
1915
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1916
+ value: "exclude-session",
1917
+ children: "除指定会话外(其余全部生效)"
1918
+ })
1919
+ ]
1920
+ }),
1921
+ promptScopeType !== "global" && (() => {
1922
+ const opts = promptScopeType === "project" || promptScopeType === "exclude-project" ? scopeProjectOptions : scopeSessionOptions;
1923
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1924
+ style: {
1925
+ ...CSS.input,
1926
+ flex: 1,
1927
+ minWidth: "180px",
1928
+ maxWidth: "320px"
1929
+ },
1930
+ value: promptScopeKey,
1931
+ onChange: (e) => setPromptScopeKey(e.target.value),
1932
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1933
+ value: "",
1934
+ children: opts.length === 0 ? "(暂无数据,请先到「对话」标签刷新)" : "请选择…"
1935
+ }), opts.map((o) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1936
+ value: o.value,
1937
+ children: o.label
1938
+ }, o.value))]
1939
+ });
1940
+ })()
1913
1941
  ]
1914
1942
  }),
1915
1943
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -1967,7 +1995,16 @@ window.__ModuleLoader__.load({
1967
1995
  ...CSS.badge,
1968
1996
  ...CSS.badgeInstalled
1969
1997
  },
1970
- children: row.scope.type === "project" ? `项目:${row.scope.key}` : `会话:${row.scope.id.slice(0, 12)}…`
1998
+ children: (() => {
1999
+ const s = row.scope;
2000
+ switch (s.type) {
2001
+ case "project": return `仅项目:${s.key}`;
2002
+ case "session": return `仅会话:${(s.id ?? "").replace(/^session-/, "").slice(0, 8)}`;
2003
+ case "exclude-project": return `除项目 ${s.key} 外`;
2004
+ case "exclude-session": return `除会话 ${(s.id ?? "").replace(/^session-/, "").slice(0, 8)} 外`;
2005
+ default: return "";
2006
+ }
2007
+ })()
1971
2008
  })
1972
2009
  ]
1973
2010
  }),