dsh-locator 0.2.1 → 0.3.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/CHANGELOG.md +6 -0
- package/README-zh.md +1 -1
- package/README.md +1 -1
- package/client.js +12 -2
- package/lib/http.d.ts.map +1 -1
- package/lib/http.js +28 -0
- package/lib/http.js.map +1 -1
- package/lib/reveal.d.ts +13 -0
- package/lib/reveal.d.ts.map +1 -0
- package/lib/reveal.js +50 -0
- package/lib/reveal.js.map +1 -0
- package/package.json +3 -3
- package/src/http.ts +26 -0
- package/src/reveal.ts +48 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0 — 2026-11-09
|
|
4
|
+
|
|
5
|
+
* Web panel: double-click a row to reveal it in the platform file manager (Explorer `/select`, Finder `open -R`, `xdg-open` on the directory). The path must be inside the configured roots and is passed as an argument vector, never through a shell; failure falls back to copying the path.
|
|
6
|
+
* DSH compatibility widened to `>=0.2.1-rc.2 <0.3.0` (peer `dsh-tools` `>=0.2.1-0`). Verified end to end on DSH 0.2.1-rc.5: plugin loads, reuses the snapshot, HTTP search answers, and the panel returns 964 matches in 24.4 ms with no console errors.
|
|
7
|
+
* `locator_export` and the rest of 0.2.x are unchanged.
|
|
8
|
+
|
|
3
9
|
## 0.2.1 — 2026-11-09
|
|
4
10
|
|
|
5
11
|
* Rebuild `lib/` before packing: 0.2.0's npm tarball was built from a stale
|
package/README-zh.md
CHANGED
|
@@ -55,7 +55,7 @@ npm 包内置 `linux-x64`、`linux-arm64`、`win32-x64`、`win32-arm64`、`darwi
|
|
|
55
55
|
* 空查询按修改时间倒序列出最近条目;输入后 110 ms 防抖,走和工具完全相同的 Everything 风格语法。
|
|
56
56
|
* 点列头按名称、大小、修改时间、路径排序,再点切换升降序。
|
|
57
57
|
* `只看文件` / `只看目录` 过滤类型;底栏显示命中数、分页上限和查询耗时。
|
|
58
|
-
* `↑`/`↓` 选择,`Enter`
|
|
58
|
+
* `↑`/`↓` 选择,`Enter` 复制选中路径,**双击在文件管理器中定位**(Explorer / Finder / `xdg-open`),`Esc` 关闭。
|
|
59
59
|
* 面板是可选的:没有 Web server 的 profile 不会挂载它,三个工具照常工作。
|
|
60
60
|
|
|
61
61
|
## 工具
|
package/README.md
CHANGED
|
@@ -55,7 +55,7 @@ Press `Ctrl+Shift+F` anywhere in the Web GUI, or click the magnifier at the side
|
|
|
55
55
|
* Empty query lists the most recently modified entries; typing runs the same Everything-style syntax as the tool after a 110 ms debounce.
|
|
56
56
|
* Click a column header to sort by name, size, modification time or path; toggle ascending/descending.
|
|
57
57
|
* `只看文件` / `只看目录` filter the kind; the footer reports matches, the page cap and query latency.
|
|
58
|
-
* `↑`/`↓` select, `Enter` copies the selected path, `Esc` closes.
|
|
58
|
+
* `↑`/`↓` select, `Enter` copies the selected path, **double-click reveals it** in Explorer/Finder/`xdg-open`, `Esc` closes.
|
|
59
59
|
* The panel is optional: profiles without a Web server never mount it, and the three tools keep working.
|
|
60
60
|
|
|
61
61
|
## Tools
|
package/client.js
CHANGED
|
@@ -262,6 +262,16 @@ window.__ModuleLoader__.load({
|
|
|
262
262
|
}
|
|
263
263
|
}, [])
|
|
264
264
|
|
|
265
|
+
const reveal = useCallback(hit => {
|
|
266
|
+
if (!hit) return
|
|
267
|
+
post('/dsh-locator/reveal', { path: hit.path }).then(() => {
|
|
268
|
+
setToast('已在文件管理器中定位')
|
|
269
|
+
setTimeout(() => setToast(''), 1500)
|
|
270
|
+
}).catch(() => {
|
|
271
|
+
copy(hit)
|
|
272
|
+
})
|
|
273
|
+
}, [copy])
|
|
274
|
+
|
|
265
275
|
const onKeyDown = useCallback(event => {
|
|
266
276
|
if (event.key === 'Escape') {
|
|
267
277
|
event.preventDefault()
|
|
@@ -362,7 +372,7 @@ window.__ModuleLoader__.load({
|
|
|
362
372
|
className: 'dsh-locator-row' + (index === selected ? ' sel' : ''),
|
|
363
373
|
title: hit.path,
|
|
364
374
|
onClick: () => setSelected(index),
|
|
365
|
-
onDoubleClick: () =>
|
|
375
|
+
onDoubleClick: () => reveal(hit),
|
|
366
376
|
},
|
|
367
377
|
h('td', null, h('div', { className: 'dsh-locator-name' },
|
|
368
378
|
h('span', { className: 'dsh-locator-badge' }, hit.dir ? '目录' : (hit.ext || '文件').toUpperCase()),
|
|
@@ -383,7 +393,7 @@ window.__ModuleLoader__.load({
|
|
|
383
393
|
+ (status && status.scanning ? ' · 索引构建中,结果可能不完整' : '')),
|
|
384
394
|
h('span', { className: 'grow' }),
|
|
385
395
|
toast === '' ? null : h('span', { className: 'dsh-locator-toast' }, toast),
|
|
386
|
-
h('span', null, '↑↓ 选择 · Enter 复制路径 · Esc 关闭'),
|
|
396
|
+
h('span', null, '↑↓ 选择 · Enter 复制路径 · 双击定位 · Esc 关闭'),
|
|
387
397
|
),
|
|
388
398
|
))
|
|
389
399
|
}
|
package/lib/http.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,cAAc,CAAA;AA+B9D,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,cAAc,GAAG,IAAI,CAwBnE"}
|
package/lib/http.js
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* service, and the plugin still works there through its tools.
|
|
12
12
|
* @module dsh-locator/http
|
|
13
13
|
*/
|
|
14
|
+
import { revealInFileManager, withinRoots } from "./reveal.js";
|
|
15
|
+
import { statSync } from 'node:fs';
|
|
14
16
|
const BODY_LIMIT = 64 * 1024;
|
|
15
17
|
/** Mount the panel's routes when this profile runs a Web server. */
|
|
16
18
|
export function registerHttp(ctx, rt) {
|
|
@@ -31,6 +33,11 @@ export function registerHttp(ctx, rt) {
|
|
|
31
33
|
path: '/dsh-locator/status',
|
|
32
34
|
handler: handler(scoped, async () => await status(rt)),
|
|
33
35
|
}));
|
|
36
|
+
scoped.effect(() => server.register({
|
|
37
|
+
kind: 'exact',
|
|
38
|
+
path: '/dsh-locator/reveal',
|
|
39
|
+
handler: handler(scoped, async (body) => await reveal(rt, body)),
|
|
40
|
+
}));
|
|
34
41
|
});
|
|
35
42
|
}
|
|
36
43
|
function handler(scoped, run) {
|
|
@@ -83,6 +90,27 @@ async function search(rt, raw) {
|
|
|
83
90
|
hits: result.hits,
|
|
84
91
|
};
|
|
85
92
|
}
|
|
93
|
+
async function reveal(rt, raw) {
|
|
94
|
+
const path = typeof raw.path === 'string' ? raw.path : '';
|
|
95
|
+
if (path === '' || !withinRoots(path, rt.roots)) {
|
|
96
|
+
return { ok: false, error: 'path is outside the indexed roots' };
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const info = statSync(path);
|
|
100
|
+
if (!info.isFile() && !info.isDirectory())
|
|
101
|
+
return { ok: false, error: 'not a file or directory' };
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return { ok: false, error: 'path does not exist' };
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
await revealInFileManager(path);
|
|
108
|
+
return { ok: true };
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
return { ok: false, error: messageOf(error) };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
86
114
|
async function status(rt) {
|
|
87
115
|
rt.start();
|
|
88
116
|
const engine = await rt.engineStatus();
|
package/lib/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|
package/lib/reveal.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reveal one indexed path in the platform file manager.
|
|
3
|
+
* @module dsh-locator/reveal
|
|
4
|
+
*/
|
|
5
|
+
/** Whether target is one of the roots or lives below one of them. */
|
|
6
|
+
export declare function withinRoots(target: string, roots: readonly string[]): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Ask the platform file manager to select a path. Uses an argument vector, not
|
|
9
|
+
* a shell, so a path can never be interpreted as a command. The child is
|
|
10
|
+
* detached: the opener outlives the plugin call.
|
|
11
|
+
*/
|
|
12
|
+
export declare function revealInFileManager(target: string): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=reveal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reveal.d.ts","sourceRoot":"","sources":["../src/reveal.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,qEAAqE;AACrE,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAS7E;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBvE"}
|
package/lib/reveal.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reveal one indexed path in the platform file manager.
|
|
3
|
+
* @module dsh-locator/reveal
|
|
4
|
+
*/
|
|
5
|
+
import { spawn } from 'node:child_process';
|
|
6
|
+
import { dirname, isAbsolute, relative, resolve } from 'node:path';
|
|
7
|
+
/** Whether target is one of the roots or lives below one of them. */
|
|
8
|
+
export function withinRoots(target, roots) {
|
|
9
|
+
if (!isAbsolute(target))
|
|
10
|
+
return false;
|
|
11
|
+
const absolute = resolve(target);
|
|
12
|
+
for (const root of roots) {
|
|
13
|
+
const base = resolve(root);
|
|
14
|
+
const rel = relative(base, absolute);
|
|
15
|
+
if (rel === '' || (!rel.startsWith('..') && !isAbsolute(rel)))
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Ask the platform file manager to select a path. Uses an argument vector, not
|
|
22
|
+
* a shell, so a path can never be interpreted as a command. The child is
|
|
23
|
+
* detached: the opener outlives the plugin call.
|
|
24
|
+
*/
|
|
25
|
+
export async function revealInFileManager(target) {
|
|
26
|
+
const absolute = resolve(target);
|
|
27
|
+
let command;
|
|
28
|
+
let args;
|
|
29
|
+
if (process.platform === 'win32') {
|
|
30
|
+
command = 'explorer.exe';
|
|
31
|
+
args = [`/select,${absolute}`];
|
|
32
|
+
}
|
|
33
|
+
else if (process.platform === 'darwin') {
|
|
34
|
+
command = 'open';
|
|
35
|
+
args = ['-R', absolute];
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
command = 'xdg-open';
|
|
39
|
+
args = [dirname(absolute)];
|
|
40
|
+
}
|
|
41
|
+
await new Promise((resolvePromise, reject) => {
|
|
42
|
+
const child = spawn(command, args, { detached: true, stdio: 'ignore', windowsHide: true });
|
|
43
|
+
child.once('error', reject);
|
|
44
|
+
child.once('spawn', () => {
|
|
45
|
+
child.unref();
|
|
46
|
+
resolvePromise();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=reveal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reveal.js","sourceRoot":"","sources":["../src/reveal.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAElE,qEAAqE;AACrE,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,KAAwB;IAClE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAA;IACrC,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAChC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QAC1B,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;QACpC,IAAI,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAAE,OAAO,IAAI,CAAA;IAC5E,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAc;IACtD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAChC,IAAI,OAAe,CAAA;IACnB,IAAI,IAAc,CAAA;IAClB,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,OAAO,GAAG,cAAc,CAAA;QACxB,IAAI,GAAG,CAAC,WAAW,QAAQ,EAAE,CAAC,CAAA;IAChC,CAAC;SAAM,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACzC,OAAO,GAAG,MAAM,CAAA;QAChB,IAAI,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;IACzB,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,UAAU,CAAA;QACpB,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC5B,CAAC;IACD,MAAM,IAAI,OAAO,CAAO,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE;QACjD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAA;QAC1F,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAC3B,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;YACvB,KAAK,CAAC,KAAK,EAAE,CAAA;YACb,cAAc,EAAE,CAAA;QAClB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-locator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Whole-disk, millisecond file search for DeepSeek Harness without Everything: a self-built cross-platform index, an Everything-style query language, agent tools and a Web search panel (Ctrl+Shift+F). Windows, macOS and Linux.",
|
|
5
5
|
"author": "PerryLink contributors",
|
|
6
6
|
"repository": {
|
|
@@ -62,12 +62,12 @@
|
|
|
62
62
|
],
|
|
63
63
|
"engines": {
|
|
64
64
|
"node": "^22.19.0 || >=24.9.0",
|
|
65
|
-
"dsh": ">=0.2.
|
|
65
|
+
"dsh": ">=0.2.1-rc.2 <0.3.0"
|
|
66
66
|
},
|
|
67
67
|
"packageManager": "pnpm@12.16.1",
|
|
68
68
|
"peerDependencies": {
|
|
69
69
|
"@deepseek-ai/cordis": "^4.0.5-alpha.1",
|
|
70
|
-
"@deepseek-ai/dsh-tools": ">=0.2.
|
|
70
|
+
"@deepseek-ai/dsh-tools": ">=0.2.1-0 <0.3.0",
|
|
71
71
|
"@deepseek-ai/schemastery": "^3.18.5-alpha.1"
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {},
|
package/src/http.ts
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
import type { Context } from '@deepseek-ai/cordis'
|
|
16
16
|
import type { IncomingMessage, ServerResponse } from 'node:http'
|
|
17
17
|
import type { LocatorRuntime, SearchArgs } from './runtime.ts'
|
|
18
|
+
import { revealInFileManager, withinRoots } from './reveal.ts'
|
|
19
|
+
import { statSync } from 'node:fs'
|
|
18
20
|
|
|
19
21
|
interface WebServerLike {
|
|
20
22
|
register(route: {
|
|
@@ -62,6 +64,11 @@ export function registerHttp(ctx: Context, rt: LocatorRuntime): void {
|
|
|
62
64
|
path: '/dsh-locator/status',
|
|
63
65
|
handler: handler(scoped, async () => await status(rt)),
|
|
64
66
|
}))
|
|
67
|
+
scoped.effect(() => server.register({
|
|
68
|
+
kind: 'exact',
|
|
69
|
+
path: '/dsh-locator/reveal',
|
|
70
|
+
handler: handler(scoped, async body => await reveal(rt, body)),
|
|
71
|
+
}))
|
|
65
72
|
})
|
|
66
73
|
}
|
|
67
74
|
|
|
@@ -119,6 +126,25 @@ async function search(rt: LocatorRuntime, raw: Record<string, unknown>): Promise
|
|
|
119
126
|
}
|
|
120
127
|
}
|
|
121
128
|
|
|
129
|
+
async function reveal(rt: LocatorRuntime, raw: Record<string, unknown>): Promise<unknown> {
|
|
130
|
+
const path = typeof raw.path === 'string' ? raw.path : ''
|
|
131
|
+
if (path === '' || !withinRoots(path, rt.roots)) {
|
|
132
|
+
return { ok: false, error: 'path is outside the indexed roots' }
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
const info = statSync(path)
|
|
136
|
+
if (!info.isFile() && !info.isDirectory()) return { ok: false, error: 'not a file or directory' }
|
|
137
|
+
} catch {
|
|
138
|
+
return { ok: false, error: 'path does not exist' }
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
await revealInFileManager(path)
|
|
142
|
+
return { ok: true }
|
|
143
|
+
} catch (error) {
|
|
144
|
+
return { ok: false, error: messageOf(error) }
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
122
148
|
async function status(rt: LocatorRuntime): Promise<unknown> {
|
|
123
149
|
rt.start()
|
|
124
150
|
const engine = await rt.engineStatus()
|
package/src/reveal.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reveal one indexed path in the platform file manager.
|
|
3
|
+
* @module dsh-locator/reveal
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { spawn } from 'node:child_process'
|
|
7
|
+
import { dirname, isAbsolute, relative, resolve } from 'node:path'
|
|
8
|
+
|
|
9
|
+
/** Whether target is one of the roots or lives below one of them. */
|
|
10
|
+
export function withinRoots(target: string, roots: readonly string[]): boolean {
|
|
11
|
+
if (!isAbsolute(target)) return false
|
|
12
|
+
const absolute = resolve(target)
|
|
13
|
+
for (const root of roots) {
|
|
14
|
+
const base = resolve(root)
|
|
15
|
+
const rel = relative(base, absolute)
|
|
16
|
+
if (rel === '' || (!rel.startsWith('..') && !isAbsolute(rel))) return true
|
|
17
|
+
}
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Ask the platform file manager to select a path. Uses an argument vector, not
|
|
23
|
+
* a shell, so a path can never be interpreted as a command. The child is
|
|
24
|
+
* detached: the opener outlives the plugin call.
|
|
25
|
+
*/
|
|
26
|
+
export async function revealInFileManager(target: string): Promise<void> {
|
|
27
|
+
const absolute = resolve(target)
|
|
28
|
+
let command: string
|
|
29
|
+
let args: string[]
|
|
30
|
+
if (process.platform === 'win32') {
|
|
31
|
+
command = 'explorer.exe'
|
|
32
|
+
args = [`/select,${absolute}`]
|
|
33
|
+
} else if (process.platform === 'darwin') {
|
|
34
|
+
command = 'open'
|
|
35
|
+
args = ['-R', absolute]
|
|
36
|
+
} else {
|
|
37
|
+
command = 'xdg-open'
|
|
38
|
+
args = [dirname(absolute)]
|
|
39
|
+
}
|
|
40
|
+
await new Promise<void>((resolvePromise, reject) => {
|
|
41
|
+
const child = spawn(command, args, { detached: true, stdio: 'ignore', windowsHide: true })
|
|
42
|
+
child.once('error', reject)
|
|
43
|
+
child.once('spawn', () => {
|
|
44
|
+
child.unref()
|
|
45
|
+
resolvePromise()
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
}
|