@1e0zj/dsh-plugin-mall 0.1.0 → 0.1.1

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/cordis.patch.yml CHANGED
@@ -2,7 +2,7 @@
2
2
  # Mounted at the host plane (profile bundle layer), so its tools land in the
3
3
  # tools registry's global layer and every session sees them.
4
4
  - insert:
5
- - id: dsh-market
5
+ - id: dsh-plugin-mall
6
6
  name: '@1e0zj/dsh-plugin-mall'
7
7
  config:
8
8
  # The profile market_install targets when the caller names none.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1e0zj/dsh-plugin-mall",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "dsh 插件市场:搜索 GitHub dsh-plugin 话题下的插件仓库,一键安装到本地 dsh profile(agent 工具 + 设置页插件市场 tab)",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/client.js CHANGED
@@ -44,6 +44,10 @@ window.__ModuleLoader__.load({
44
44
  ".mkt_ok{color:var(--dsw-alias-state-success-primary,#2f855a)}",
45
45
  ".mkt_badge{display:inline-block;border-radius:999px;padding:1px 8px;font-size:11px;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary)}",
46
46
  ".mkt_link{color:var(--dsw-alias-state-business-primary);font-size:12px;text-decoration:none;cursor:pointer}",
47
+ ".mkt_installedHead{display:flex;align-items:center;gap:8px;width:100%;background:none;border:0;padding:0;margin:0;cursor:pointer;font:inherit;text-align:left}",
48
+ ".mkt_installedHead:hover .mkt_panelTitle{color:var(--dsw-alias-state-business-primary)}",
49
+ ".mkt_depList{display:flex;flex-direction:column;gap:6px;margin-top:8px}",
50
+ ".mkt_depRow{display:flex;justify-content:space-between;align-items:center;gap:8px}",
47
51
  ].join("\n");
48
52
  var tagId = "@1e0zj/dsh-plugin-mall/market-tab.css";
49
53
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
@@ -78,7 +82,7 @@ window.__ModuleLoader__.load({
78
82
  }
79
83
 
80
84
  // ── job polling ─────────────────────────────────────────────────────────
81
- function useJobPolling(call) {
85
+ function useJobPolling(call, onSettled) {
82
86
  var jobsRef = useRef({});
83
87
  var _jobs = useState({});
84
88
  var jobs = _jobs[0];
@@ -94,20 +98,24 @@ window.__ModuleLoader__.load({
94
98
  running.forEach(function (id) {
95
99
  call("job", { jobId: id }).then(function (value) {
96
100
  var snapshot = value.snapshot || {};
97
- setJobs(function (prev) {
98
- var old = prev[id] || {};
99
- var output = (old.output || "") + (value.output || "");
100
- return Object.assign({}, prev, { [id]: Object.assign({}, old, {
101
- status: snapshot.status,
102
- detail: snapshot.detail,
103
- output: output,
104
- }) });
105
- });
101
+ var old = jobsRef.current[id] || {};
102
+ var wasTerminal = old.status === "completed" || old.status === "failed" || old.status === "killed";
103
+ var nowTerminal = snapshot.status === "completed" || snapshot.status === "failed" || snapshot.status === "killed";
104
+ if (!wasTerminal && nowTerminal && onSettled) {
105
+ try { onSettled(id); } catch (e) { /* best effort */ }
106
+ }
107
+ var output = (old.output || "") + (value.output || "");
108
+ jobsRef.current = Object.assign({}, jobsRef.current, { [id]: Object.assign({}, old, {
109
+ status: snapshot.status,
110
+ detail: snapshot.detail,
111
+ output: output,
112
+ }) });
113
+ setJobs(Object.assign({}, jobsRef.current));
106
114
  }).catch(function () { /* keep polling */ });
107
115
  });
108
116
  }, 1200);
109
117
  return function () { clearInterval(timer); };
110
- }, [call]);
118
+ }, [call, onSettled]);
111
119
  var track = useCallback(function (id, spec) {
112
120
  jobsRef.current = Object.assign({}, jobsRef.current, { [id]: { status: "running", spec: spec, output: "" } });
113
121
  setJobs(Object.assign({}, jobsRef.current));
@@ -191,21 +199,35 @@ window.__ModuleLoader__.load({
191
199
  );
192
200
  }
193
201
 
194
- // ── installed panel ─────────────────────────────────────────────────────
202
+ // ── installed panel (collapsible summary) ───────────────────────────────
195
203
  function InstalledPanel(props) {
196
204
  var installed = props.installed;
205
+ var _open = useState(false);
206
+ var open = _open[0];
207
+ var setOpen = _open[1];
197
208
  if (!installed) return null;
209
+ var count = installed.error ? 0 : (installed.deps || []).length;
198
210
  return h("div", { className: "mkt_card" },
199
- h("p", { className: "mkt_panelTitle" }, "已装插件"),
211
+ h("button", {
212
+ type: "button",
213
+ className: "mkt_installedHead",
214
+ onClick: function () { setOpen(!open); },
215
+ "aria-expanded": open ? "true" : "false",
216
+ },
217
+ h("span", { className: "mkt_panelTitle" }, "已装插件"),
218
+ h("span", { className: "mkt_badge" }, count + " 个"),
219
+ h("span", { className: "mkt_meta" }, open ? "收起 ▲" : "展开 ▼")
220
+ ),
200
221
  installed.error
201
222
  ? h("div", { className: "mkt_error" }, installed.error)
202
- : installed.deps && installed.deps.length === 0
223
+ : !open ? null
224
+ : (installed.deps || []).length === 0
203
225
  ? h("div", { className: "mkt_meta" }, "还没有装过插件")
204
- : (installed.deps || []).map(function (dep) {
205
- return h("div", { key: dep.name, style: { display: "flex", justifyContent: "space-between", gap: "8px" } },
226
+ : h("div", { className: "mkt_depList" }, (installed.deps || []).map(function (dep) {
227
+ return h("div", { key: dep.name, className: "mkt_depRow" },
206
228
  h("span", { className: "mkt_desc" }, dep.name + "@" + dep.version),
207
229
  h("span", { className: "mkt_badge" }, kindLabel(dep.kind)));
208
- })
230
+ }))
209
231
  );
210
232
  }
211
233
 
@@ -265,10 +287,24 @@ window.__ModuleLoader__.load({
265
287
  });
266
288
  }, [call]);
267
289
 
268
- var polling = useJobPolling(call);
290
+ var refreshInstalled = useCallback(function () {
291
+ call("installed", {}).then(function (value) {
292
+ setInstalled(value);
293
+ }).catch(function (e) {
294
+ setInstalled({ error: errorText(e) });
295
+ });
296
+ }, [call]);
297
+
298
+ // 点开即自动搜索(空关键词 = 最热插件),安装任务结束自动刷新已装列表。
299
+ var polling = useJobPolling(call, refreshInstalled);
269
300
  var track = polling.track;
270
301
  var jobs = polling.jobs;
271
302
 
303
+ useEffect(function () {
304
+ doSearch();
305
+ // eslint-disable-next-line react-hooks/exhaustive-deps
306
+ }, []);
307
+
272
308
  var doInstall = useCallback(function (repo) {
273
309
  var spec = "github:" + repo;
274
310
  setInstalling(function (prev) {
@@ -289,14 +325,6 @@ window.__ModuleLoader__.load({
289
325
  });
290
326
  }, [call, track]);
291
327
 
292
- var refreshInstalled = useCallback(function () {
293
- call("installed", {}).then(function (value) {
294
- setInstalled(value);
295
- }).catch(function (e) {
296
- setInstalled({ error: errorText(e) });
297
- });
298
- }, [call]);
299
-
300
328
  useEffect(function () {
301
329
  refreshInstalled();
302
330
  }, [refreshInstalled]);
@@ -330,7 +358,7 @@ window.__ModuleLoader__.load({
330
358
  h("div", { className: "mkt_columns" },
331
359
  h("div", { className: "mkt_list" },
332
360
  results == null
333
- ? h("div", { className: "mkt_meta" }, "输入关键词点搜索,或直接搜索浏览最热插件。")
361
+ ? h("div", { className: "mkt_meta" }, loading ? "正在加载最热插件…" : "—")
334
362
  : results.items.length === 0
335
363
  ? h("div", { className: "mkt_meta" }, "没有匹配的仓库。")
336
364
  : h(React.Fragment, null,
@@ -347,9 +375,9 @@ window.__ModuleLoader__.load({
347
375
  )
348
376
  ),
349
377
  h("div", { className: "mkt_rail" },
378
+ h(InstalledPanel, { installed: installed }),
350
379
  h(InfoPanel, { info: info, onInstall: doInstall }),
351
- h(JobsPanel, { jobs: jobs }),
352
- h(InstalledPanel, { installed: installed })
380
+ h(JobsPanel, { jobs: jobs })
353
381
  )
354
382
  )
355
383
  );