dshmarket 1.0.2 → 1.0.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/client/client.js CHANGED
@@ -133,7 +133,7 @@ const CSS = `
133
133
  .dshm-top{position:absolute;right:18px;bottom:18px;z-index:20;width:38px;height:38px;border-radius:99px;border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#6b7280);font-size:16px;cursor:pointer;box-shadow:0 4px 14px rgba(0,0,0,.12)}
134
134
  .dshm-top:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}
135
135
  .dshm-chip{font:inherit;font-size:12px;border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);border-radius:99px;padding:3px 11px;cursor:pointer;color:var(--dsw-alias-label-secondary,#6b7280)}
136
- .dshm-chip.on{background:var(--dsw-alias-brand-primary,#4f6ef7);border-color:var(--dsw-alias-brand-primary,#4f6ef7);color:#fff}
136
+ .dshm-chip.on{background:var(--dsw-alias-button-primary-fill,#4f6ef7);border-color:var(--dsw-alias-button-primary-fill,#4f6ef7);color:var(--dsw-alias-label-primary-foreground,#fff)}
137
137
  .dshm-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:10px}
138
138
  .dshm-card{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l1,#e5e7eb);border-radius:10px;padding:12px 14px;display:flex;flex-direction:column;gap:6px}
139
139
  .dshm-row1{display:flex;align-items:center;gap:9px;min-width:0}
@@ -147,7 +147,7 @@ const CSS = `
147
147
  .dshm-src{font-size:11px;color:var(--dsw-alias-label-secondary,#9ca3af);text-decoration:none}
148
148
  .dshm-src:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}
149
149
  .dshm-btn{border:none;border-radius:7px;padding:5px 14px;font:inherit;font-size:12px;cursor:pointer;font-weight:600}
150
- .dshm-btn.install{background:var(--dsw-alias-brand-primary,#4f6ef7);color:#fff}
150
+ .dshm-btn.install{background:var(--dsw-alias-button-primary-fill,#4f6ef7);color:var(--dsw-alias-label-primary-foreground,#fff)}
151
151
  .dshm-btn.busy{opacity:.65;cursor:default}
152
152
  .dshm-btn.done{background:transparent;color:var(--dsw-alias-state-success-primary,#16a34a);cursor:default}
153
153
  .dshm-btn.ghost{background:var(--dsw-alias-bg-layer-2,#f3f4f6);color:var(--dsw-alias-label-secondary,#6b7280)}
package/lib/routes.js CHANGED
@@ -33,11 +33,31 @@ function dshArgv() {
33
33
  }
34
34
  /** Whether `pnpm` resolves on PATH; success is cached, absence is re-probed. */
35
35
  let pnpmReady = false;
36
+ /**
37
+ * Windows npm/corepack/pnpm are `.cmd` shims. Node's `spawn` without a shell
38
+ * cannot start them (ENOENT / EINVAL). Same pattern as dsh's `plugin` forwarder.
39
+ */
40
+ const winCmdShim = process.platform === 'win32';
41
+ /**
42
+ * Kill a spawned child and, on Windows, its whole process tree — `kill()`
43
+ * there only terminates the wrapper, leaving pnpm children running.
44
+ * (Contributed in #7 by @mraing.)
45
+ */
46
+ function killChild(child) {
47
+ if (process.platform === 'win32' && child.pid !== undefined) {
48
+ try {
49
+ spawn('taskkill', ['/pid', String(child.pid), '/t', '/f'], { stdio: 'ignore' });
50
+ return;
51
+ }
52
+ catch { /* fall through */ }
53
+ }
54
+ child.kill('SIGKILL');
55
+ }
36
56
  function probePnpm() {
37
57
  if (pnpmReady)
38
58
  return Promise.resolve(true);
39
59
  return new Promise((resolvePromise) => {
40
- const child = spawn('pnpm', ['--version'], { stdio: 'ignore' });
60
+ const child = spawn('pnpm', ['--version'], { stdio: 'ignore', shell: winCmdShim });
41
61
  child.on('error', () => resolvePromise(false));
42
62
  child.on('close', (code) => {
43
63
  pnpmReady = code === 0;
@@ -47,9 +67,13 @@ function probePnpm() {
47
67
  }
48
68
  function runQuiet(file, args, timeoutMs) {
49
69
  return new Promise((resolvePromise) => {
50
- const child = spawn(file, args, { env: { ...process.env, CI: 'true' }, stdio: ['ignore', 'pipe', 'pipe'] });
70
+ const child = spawn(file, args, {
71
+ env: { ...process.env, CI: 'true' },
72
+ stdio: ['ignore', 'pipe', 'pipe'],
73
+ shell: winCmdShim,
74
+ });
51
75
  let output = '';
52
- const timer = setTimeout(() => child.kill('SIGKILL'), timeoutMs);
76
+ const timer = setTimeout(() => killChild(child), timeoutMs);
53
77
  const collect = (chunk) => { output = (output + chunk.toString()).slice(-8 * 1024); };
54
78
  child.stdout.on('data', collect);
55
79
  child.stderr.on('data', collect);
@@ -99,7 +123,7 @@ function runDshPlugin(profile, pluginArgs) {
99
123
  let timedOut = false;
100
124
  const timer = setTimeout(() => {
101
125
  timedOut = true;
102
- child.kill('SIGKILL');
126
+ killChild(child);
103
127
  }, INSTALL_TIMEOUT_MS);
104
128
  child.stdout.on('data', (chunk) => {
105
129
  const text = chunk.toString();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dshmarket",
3
3
  "description": "Visual plugin market inside DeepSeek Harness — browse, search, and one-click install community plugins. · DSH 可视化插件市场:逛一逛,点一下,装好。",
4
- "version": "1.0.2",
4
+ "version": "1.0.3",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/types/index.d.ts",
package/src/routes.ts CHANGED
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  import { spawn } from 'node:child_process'
10
+ import type { ChildProcess } from 'node:child_process'
10
11
  import { readFileSync } from 'node:fs'
11
12
  import { homedir } from 'node:os'
12
13
  import { dirname, join } from 'node:path'
@@ -65,10 +66,31 @@ interface InstallResult {
65
66
  /** Whether `pnpm` resolves on PATH; success is cached, absence is re-probed. */
66
67
  let pnpmReady = false
67
68
 
69
+ /**
70
+ * Windows npm/corepack/pnpm are `.cmd` shims. Node's `spawn` without a shell
71
+ * cannot start them (ENOENT / EINVAL). Same pattern as dsh's `plugin` forwarder.
72
+ */
73
+ const winCmdShim = process.platform === 'win32'
74
+
75
+ /**
76
+ * Kill a spawned child and, on Windows, its whole process tree — `kill()`
77
+ * there only terminates the wrapper, leaving pnpm children running.
78
+ * (Contributed in #7 by @mraing.)
79
+ */
80
+ function killChild(child: ChildProcess): void {
81
+ if (process.platform === 'win32' && child.pid !== undefined) {
82
+ try {
83
+ spawn('taskkill', ['/pid', String(child.pid), '/t', '/f'], { stdio: 'ignore' })
84
+ return
85
+ } catch { /* fall through */ }
86
+ }
87
+ child.kill('SIGKILL')
88
+ }
89
+
68
90
  function probePnpm(): Promise<boolean> {
69
91
  if (pnpmReady) return Promise.resolve(true)
70
92
  return new Promise((resolvePromise) => {
71
- const child = spawn('pnpm', ['--version'], { stdio: 'ignore' })
93
+ const child = spawn('pnpm', ['--version'], { stdio: 'ignore', shell: winCmdShim })
72
94
  child.on('error', () => resolvePromise(false))
73
95
  child.on('close', (code) => {
74
96
  pnpmReady = code === 0
@@ -79,9 +101,13 @@ function probePnpm(): Promise<boolean> {
79
101
 
80
102
  function runQuiet(file: string, args: string[], timeoutMs: number): Promise<{ code: number | null; output: string }> {
81
103
  return new Promise((resolvePromise) => {
82
- const child = spawn(file, args, { env: { ...process.env, CI: 'true' }, stdio: ['ignore', 'pipe', 'pipe'] })
104
+ const child = spawn(file, args, {
105
+ env: { ...process.env, CI: 'true' },
106
+ stdio: ['ignore', 'pipe', 'pipe'],
107
+ shell: winCmdShim,
108
+ })
83
109
  let output = ''
84
- const timer = setTimeout(() => child.kill('SIGKILL'), timeoutMs)
110
+ const timer = setTimeout(() => killChild(child), timeoutMs)
85
111
  const collect = (chunk: Buffer): void => { output = (output + chunk.toString()).slice(-8 * 1024) }
86
112
  child.stdout.on('data', collect)
87
113
  child.stderr.on('data', collect)
@@ -142,7 +168,7 @@ function runDshPlugin(profile: string, pluginArgs: string[]): Promise<InstallRes
142
168
  let timedOut = false
143
169
  const timer = setTimeout(() => {
144
170
  timedOut = true
145
- child.kill('SIGKILL')
171
+ killChild(child)
146
172
  }, INSTALL_TIMEOUT_MS)
147
173
  child.stdout.on('data', (chunk: Buffer) => {
148
174
  const text = chunk.toString()