dsh-plugin-workspace-move-top 0.0.0-stage → 0.2.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.md +14 -2
- package/client/client.js +133 -0
- package/cordis.patch.yml +4 -0
- package/dsh-plugin.naming.json +33 -0
- package/lib/index.d.ts +11 -0
- package/lib/index.js +15 -0
- package/lib/move-route.d.ts +17 -0
- package/lib/move-route.js +40 -0
- package/lib/service.d.ts +47 -0
- package/lib/service.js +48 -0
- package/package.json +67 -4
package/README.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 工作区移到最上面
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
在 DSH 工作区 `…` 菜单中添加“移到最上面”。点击只调整一次顺序,随后仍可自由拖动;顺序由 Host 的 `workspaceRegistry.insertBefore` 保存。插件不保存运行时排序或收藏状态,启动与同步时不重新排序。
|
|
4
|
+
|
|
5
|
+
仅支持 **DSH 0.2.1-rc.5**。
|
|
6
|
+
|
|
7
|
+
安装:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
dsh plugin --profile desktop add dsh-plugin-workspace-move-top@0.2.0
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
当前 Host 没有工作区菜单扩展 slot。客户端依赖工作区行和菜单的 DOM 结构;宿主改变 DOM 后,菜单项可能不出现。Node 测试不能代替真实 Electron DOM 验证。
|
|
14
|
+
|
|
15
|
+
验证:`npm run check`。
|
package/client/client.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// One-shot workspace reorder. No favorites, pins, persistent state or row icons.
|
|
2
|
+
window.__ModuleLoader__.load({
|
|
3
|
+
id: 'dsh-plugin-workspace-move-top',
|
|
4
|
+
factory: function (require) {
|
|
5
|
+
var module = { exports: {} }
|
|
6
|
+
var exports = module.exports
|
|
7
|
+
var MENU_ITEM = 'data-wshub-move-top'
|
|
8
|
+
var API_PATH = 'api/plugins/wshub-workspace-move-top/move'
|
|
9
|
+
|
|
10
|
+
function apply(ctx) {
|
|
11
|
+
ctx.effect(function () {
|
|
12
|
+
var workspaceId = null
|
|
13
|
+
var busy = false
|
|
14
|
+
var observer = null
|
|
15
|
+
var timer = null
|
|
16
|
+
var buttons = new Set()
|
|
17
|
+
|
|
18
|
+
function rowId(target) {
|
|
19
|
+
var row = target && target.closest && target.closest('[data-row-key^="workspace:"]')
|
|
20
|
+
if (!row) return null
|
|
21
|
+
var key = row.getAttribute('data-row-key') || ''
|
|
22
|
+
return key.slice(10) || null
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Capture the row whose native workspace action button opened this menu.
|
|
26
|
+
function onPointerDown(event) {
|
|
27
|
+
if (!(event.target instanceof Element)) return
|
|
28
|
+
var button = event.target.closest('button[aria-label]')
|
|
29
|
+
if (event.target.closest('[role="menu"]')) return
|
|
30
|
+
if (!button || button.hasAttribute('aria-keyshortcuts')) {
|
|
31
|
+
workspaceId = null
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
var row = button.closest('[data-row-key^="workspace:"]')
|
|
35
|
+
workspaceId = row && row.querySelector('button[aria-label]') === button ? rowId(button) : null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function moveToTop(button) {
|
|
39
|
+
var id = button.dataset.wshubWorkspaceId
|
|
40
|
+
if (!id || busy) return
|
|
41
|
+
busy = true
|
|
42
|
+
button.disabled = true
|
|
43
|
+
button.title = '正在调整顺序…'
|
|
44
|
+
try {
|
|
45
|
+
var response = await fetch(API_PATH, {
|
|
46
|
+
method: 'POST',
|
|
47
|
+
headers: { 'content-type': 'application/json' },
|
|
48
|
+
body: JSON.stringify({ workspaceId: id, action: 'move-to-top' }),
|
|
49
|
+
})
|
|
50
|
+
var result = await response.json().catch(function () { return null })
|
|
51
|
+
if (!response.ok || !result || result.ok !== true) throw new Error((result && result.message) || ('HTTP ' + response.status))
|
|
52
|
+
button.title = '已移到最上面'
|
|
53
|
+
// Closing the native menu removes the extension row with it.
|
|
54
|
+
var trigger = document.activeElement
|
|
55
|
+
if (trigger && trigger.closest && trigger.closest('[data-row-key^="workspace:"]')) trigger.click()
|
|
56
|
+
var event = new KeyboardEvent('keydown', { key: 'Escape', bubbles: true })
|
|
57
|
+
document.dispatchEvent(event)
|
|
58
|
+
// DOM teardown is authoritative; the Host publishes the new order.
|
|
59
|
+
} catch (error) {
|
|
60
|
+
button.disabled = false
|
|
61
|
+
button.title = '调整失败:' + (error instanceof Error ? error.message : String(error))
|
|
62
|
+
button.setAttribute('aria-label', button.title)
|
|
63
|
+
} finally {
|
|
64
|
+
busy = false
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function decorate() {
|
|
69
|
+
observer.disconnect()
|
|
70
|
+
try {
|
|
71
|
+
var menus = document.querySelectorAll('[role="menu"][data-menu-material="translucent"]')
|
|
72
|
+
for (var i = 0; i < menus.length; i++) {
|
|
73
|
+
var menu = menus[i]
|
|
74
|
+
if (!workspaceId || menu.querySelector('[' + MENU_ITEM + ']')) continue
|
|
75
|
+
var viewport = menu.querySelector('[role="presentation"]')
|
|
76
|
+
var template = viewport && viewport.querySelector('button[role="menuitem"]')
|
|
77
|
+
if (!template) continue
|
|
78
|
+
// Clone only native menu classes/row structure; do not copy its actions.
|
|
79
|
+
var wrapper = template.parentElement.cloneNode(false)
|
|
80
|
+
var button = template.cloneNode(false)
|
|
81
|
+
button.setAttribute(MENU_ITEM, '1')
|
|
82
|
+
button.dataset.wshubWorkspaceId = workspaceId
|
|
83
|
+
button.removeAttribute('class')
|
|
84
|
+
button.className = template.className
|
|
85
|
+
button.setAttribute('aria-label', '移到最上面')
|
|
86
|
+
button.title = '只调整一次顺序,之后仍可自由拖动'
|
|
87
|
+
var spans = template.querySelectorAll('span')
|
|
88
|
+
if (spans[0]) {
|
|
89
|
+
var icon = document.createElement('span')
|
|
90
|
+
icon.className = spans[0].className
|
|
91
|
+
icon.textContent = '↑'
|
|
92
|
+
button.appendChild(icon)
|
|
93
|
+
}
|
|
94
|
+
var label = document.createElement('span')
|
|
95
|
+
var labelTemplate = spans[1] || spans[0]
|
|
96
|
+
if (labelTemplate) label.className = labelTemplate.className
|
|
97
|
+
label.textContent = '移到最上面'
|
|
98
|
+
button.appendChild(label)
|
|
99
|
+
button.addEventListener('click', function (event) {
|
|
100
|
+
event.preventDefault()
|
|
101
|
+
event.stopPropagation()
|
|
102
|
+
void moveToTop(event.currentTarget)
|
|
103
|
+
})
|
|
104
|
+
wrapper.appendChild(button)
|
|
105
|
+
viewport.insertBefore(wrapper, viewport.firstChild)
|
|
106
|
+
buttons.add(button)
|
|
107
|
+
}
|
|
108
|
+
} finally {
|
|
109
|
+
observer.observe(document.documentElement, { childList: true, subtree: true })
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function schedule() {
|
|
113
|
+
if (timer !== null) return
|
|
114
|
+
timer = setTimeout(function () { timer = null; decorate() }, 40)
|
|
115
|
+
}
|
|
116
|
+
observer = new MutationObserver(schedule)
|
|
117
|
+
observer.observe(document.documentElement, { childList: true, subtree: true })
|
|
118
|
+
document.addEventListener('pointerdown', onPointerDown, true)
|
|
119
|
+
document.addEventListener('keydown', onPointerDown, true)
|
|
120
|
+
return function () {
|
|
121
|
+
document.removeEventListener('pointerdown', onPointerDown, true)
|
|
122
|
+
document.removeEventListener('keydown', onPointerDown, true)
|
|
123
|
+
observer.disconnect()
|
|
124
|
+
if (timer !== null) clearTimeout(timer)
|
|
125
|
+
buttons.forEach(function (button) { button.remove() })
|
|
126
|
+
buttons.clear()
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
exports.apply = apply
|
|
131
|
+
return module.exports
|
|
132
|
+
},
|
|
133
|
+
})
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"policy": "dsh-plugin-naming/v1",
|
|
4
|
+
"plugin": {
|
|
5
|
+
"namespace": "wshub",
|
|
6
|
+
"name": "workspace-move-top",
|
|
7
|
+
"coordinate": "wshub/workspace-move-top",
|
|
8
|
+
"packageName": "dsh-plugin-workspace-move-top"
|
|
9
|
+
},
|
|
10
|
+
"names": {
|
|
11
|
+
"pluginNames": [
|
|
12
|
+
"workspace-move-top"
|
|
13
|
+
],
|
|
14
|
+
"loaderIds": [
|
|
15
|
+
"wshub-workspace-move-top"
|
|
16
|
+
],
|
|
17
|
+
"services": [
|
|
18
|
+
"wshubWorkspaceMoveTop"
|
|
19
|
+
],
|
|
20
|
+
"tools": [],
|
|
21
|
+
"commands": [],
|
|
22
|
+
"skills": [],
|
|
23
|
+
"skillProviders": [],
|
|
24
|
+
"events": [],
|
|
25
|
+
"settingsNamespaces": [],
|
|
26
|
+
"routes": [
|
|
27
|
+
{
|
|
28
|
+
"kind": "exact",
|
|
29
|
+
"path": "/api/plugins/wshub-workspace-move-top/move"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
export declare const name = "workspace-move-top";
|
|
3
|
+
export declare const inject: string[];
|
|
4
|
+
export { WorkspaceMoveTopService, SERVICE_NAME } from './service.js';
|
|
5
|
+
export { MOVE_ROUTE, handleMoveRequest } from './move-route.js';
|
|
6
|
+
/** Activate the stateless move-to-top service. No startup reordering: the
|
|
7
|
+
* host's durable registry order is left untouched until a client asks to move
|
|
8
|
+
* one workspace to the top.
|
|
9
|
+
* @param ctx injected plugin scope
|
|
10
|
+
*/
|
|
11
|
+
export declare function apply(ctx: Context): Promise<void>;
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { WorkspaceMoveTopService } from './service.js';
|
|
2
|
+
import { installMoveRoute } from './move-route.js';
|
|
3
|
+
export const name = 'workspace-move-top';
|
|
4
|
+
export const inject = ['workspaceRegistry'];
|
|
5
|
+
export { WorkspaceMoveTopService, SERVICE_NAME } from './service.js';
|
|
6
|
+
export { MOVE_ROUTE, handleMoveRequest } from './move-route.js';
|
|
7
|
+
/** Activate the stateless move-to-top service. No startup reordering: the
|
|
8
|
+
* host's durable registry order is left untouched until a client asks to move
|
|
9
|
+
* one workspace to the top.
|
|
10
|
+
* @param ctx injected plugin scope
|
|
11
|
+
*/
|
|
12
|
+
export async function apply(ctx) {
|
|
13
|
+
const moveTop = new WorkspaceMoveTopService(ctx);
|
|
14
|
+
installMoveRoute(ctx, moveTop);
|
|
15
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { WorkspaceMoveTopService } from './service.js';
|
|
3
|
+
/** Exact connection route the client calls for a one-shot move. */
|
|
4
|
+
export declare const MOVE_ROUTE = "/api/plugins/wshub-workspace-move-top/move";
|
|
5
|
+
export declare const MOVE_ACTION = "move-to-top";
|
|
6
|
+
/** Handle an authenticated request.
|
|
7
|
+
* @param moveTop serialized service
|
|
8
|
+
* @param request owner authenticated request
|
|
9
|
+
* @returns JSON response
|
|
10
|
+
*/
|
|
11
|
+
export declare function handleMoveRequest(moveTop: WorkspaceMoveTopService, request: Request): Promise<Response>;
|
|
12
|
+
/** Register the optional connection route with an effect disposer.
|
|
13
|
+
* @param ctx plugin context
|
|
14
|
+
* @param moveTop serialized service
|
|
15
|
+
* @returns nothing
|
|
16
|
+
*/
|
|
17
|
+
export declare function installMoveRoute(ctx: Context, moveTop: WorkspaceMoveTopService): void;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** Exact connection route the client calls for a one-shot move. */
|
|
2
|
+
export const MOVE_ROUTE = '/api/plugins/wshub-workspace-move-top/move';
|
|
3
|
+
export const MOVE_ACTION = 'move-to-top';
|
|
4
|
+
/** Handle an authenticated request.
|
|
5
|
+
* @param moveTop serialized service
|
|
6
|
+
* @param request owner authenticated request
|
|
7
|
+
* @returns JSON response
|
|
8
|
+
*/
|
|
9
|
+
export async function handleMoveRequest(moveTop, request) {
|
|
10
|
+
const headers = { 'cache-control': 'no-store' };
|
|
11
|
+
try {
|
|
12
|
+
if (request.method !== 'POST')
|
|
13
|
+
return Response.json({ ok: false, message: '不支持的请求方式' }, { status: 405, headers });
|
|
14
|
+
let body;
|
|
15
|
+
try {
|
|
16
|
+
body = await request.json();
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return Response.json({ ok: false, message: '请求不是合法 JSON' }, { status: 400, headers });
|
|
20
|
+
}
|
|
21
|
+
if (!body || typeof body !== 'object' || Array.isArray(body) || !('workspaceId' in body) || typeof body.workspaceId !== 'string' || !body.workspaceId.trim() || !('action' in body) || body.action !== MOVE_ACTION) {
|
|
22
|
+
return Response.json({ ok: false, message: `需要工作区 ID 与 action: '${MOVE_ACTION}'` }, { status: 400, headers });
|
|
23
|
+
}
|
|
24
|
+
const result = await moveTop.moveToTop(body.workspaceId);
|
|
25
|
+
return Response.json(result, { status: result.ok ? 200 : 409, headers });
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return Response.json({ ok: false, message: '移动未完成,请刷新后重试' }, { status: 500, headers });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Register the optional connection route with an effect disposer.
|
|
32
|
+
* @param ctx plugin context
|
|
33
|
+
* @param moveTop serialized service
|
|
34
|
+
* @returns nothing
|
|
35
|
+
*/
|
|
36
|
+
export function installMoveRoute(ctx, moveTop) {
|
|
37
|
+
ctx.inject(['connection'], scope => {
|
|
38
|
+
scope.effect(() => scope.connection.fetch.register({ path: MOVE_ROUTE, methods: ['POST'], requestBody: 'buffered', fetch: request => handleMoveRequest(moveTop, request) }));
|
|
39
|
+
});
|
|
40
|
+
}
|
package/lib/service.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Service, type Context } from '@deepseek-ai/cordis';
|
|
2
|
+
export declare const SERVICE_NAME = "wshubWorkspaceMoveTop";
|
|
3
|
+
declare module '@deepseek-ai/cordis' {
|
|
4
|
+
interface Context {
|
|
5
|
+
wshubWorkspaceMoveTop: WorkspaceMoveTopService;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/** Registry projection needed for ordering and the route payload. */
|
|
9
|
+
export interface WorkspaceEntryView {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly path: string;
|
|
12
|
+
readonly title: string;
|
|
13
|
+
}
|
|
14
|
+
/** One successful move-to-top result. */
|
|
15
|
+
export interface MoveToTopResult {
|
|
16
|
+
readonly ok: true;
|
|
17
|
+
/** Whether an `insertBefore` actually moved the workspace. */
|
|
18
|
+
readonly moved: boolean;
|
|
19
|
+
/** The complete durable order after the operation (top first). */
|
|
20
|
+
readonly order: readonly string[];
|
|
21
|
+
readonly workspaces: readonly WorkspaceEntryView[];
|
|
22
|
+
}
|
|
23
|
+
/** Failure result for an empty registry or an unknown workspace. */
|
|
24
|
+
export interface MoveToTopError {
|
|
25
|
+
readonly ok: false;
|
|
26
|
+
readonly reason: 'none';
|
|
27
|
+
readonly message: string;
|
|
28
|
+
}
|
|
29
|
+
/** Stateless "move to top" service. Owns the registry ordering queue but no
|
|
30
|
+
* file or saved state: it never reorders on activation and keeps no ordering
|
|
31
|
+
* or favorites state. */
|
|
32
|
+
export declare class WorkspaceMoveTopService extends Service {
|
|
33
|
+
private queue;
|
|
34
|
+
constructor(ctx: Context);
|
|
35
|
+
private enqueue;
|
|
36
|
+
private list;
|
|
37
|
+
/** Move one workspace to the top of the durable display order, exactly once.
|
|
38
|
+
*
|
|
39
|
+
* Reads the real registry order; an already-first workspace is a no-op and an
|
|
40
|
+
* unknown workspace is rejected without touching the order. Otherwise it asks
|
|
41
|
+
* the host for `insertBefore(id, firstId)` — the same durable write the
|
|
42
|
+
* official sidebar drag uses — so the result survives restart and no plugin
|
|
43
|
+
* startup pass re-applies it.
|
|
44
|
+
* @param workspaceId exact registry ID
|
|
45
|
+
*/
|
|
46
|
+
moveToTop(workspaceId: string): Promise<MoveToTopResult | MoveToTopError>;
|
|
47
|
+
}
|
package/lib/service.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Service } from '@deepseek-ai/cordis';
|
|
2
|
+
export const SERVICE_NAME = 'wshubWorkspaceMoveTop';
|
|
3
|
+
function toEntryView(entry) {
|
|
4
|
+
return { id: String(entry.id), path: entry.path, title: entry.title };
|
|
5
|
+
}
|
|
6
|
+
/** Stateless "move to top" service. Owns the registry ordering queue but no
|
|
7
|
+
* file or saved state: it never reorders on activation and keeps no ordering
|
|
8
|
+
* or favorites state. */
|
|
9
|
+
export class WorkspaceMoveTopService extends Service {
|
|
10
|
+
queue = Promise.resolve();
|
|
11
|
+
constructor(ctx) {
|
|
12
|
+
super(ctx, SERVICE_NAME);
|
|
13
|
+
}
|
|
14
|
+
enqueue(action) {
|
|
15
|
+
const run = this.queue.then(action);
|
|
16
|
+
this.queue = run.then(() => undefined, () => undefined);
|
|
17
|
+
return run;
|
|
18
|
+
}
|
|
19
|
+
list() {
|
|
20
|
+
return this.ctx.workspaceRegistry.list().map(toEntryView);
|
|
21
|
+
}
|
|
22
|
+
/** Move one workspace to the top of the durable display order, exactly once.
|
|
23
|
+
*
|
|
24
|
+
* Reads the real registry order; an already-first workspace is a no-op and an
|
|
25
|
+
* unknown workspace is rejected without touching the order. Otherwise it asks
|
|
26
|
+
* the host for `insertBefore(id, firstId)` — the same durable write the
|
|
27
|
+
* official sidebar drag uses — so the result survives restart and no plugin
|
|
28
|
+
* startup pass re-applies it.
|
|
29
|
+
* @param workspaceId exact registry ID
|
|
30
|
+
*/
|
|
31
|
+
moveToTop(workspaceId) {
|
|
32
|
+
return this.enqueue(async () => {
|
|
33
|
+
const registry = this.ctx.workspaceRegistry;
|
|
34
|
+
const order = registry.list();
|
|
35
|
+
const first = order[0];
|
|
36
|
+
if (first === undefined)
|
|
37
|
+
return { ok: false, reason: 'none', message: '工作区列表为空' };
|
|
38
|
+
if (first.id === workspaceId) {
|
|
39
|
+
return { ok: true, moved: false, order: order.map(entry => String(entry.id)), workspaces: order.map(toEntryView) };
|
|
40
|
+
}
|
|
41
|
+
if (!order.some(entry => entry.id === workspaceId)) {
|
|
42
|
+
return { ok: false, reason: 'none', message: '工作区已不存在,请刷新列表' };
|
|
43
|
+
}
|
|
44
|
+
const next = await registry.insertBefore(workspaceId, first.id);
|
|
45
|
+
return { ok: true, moved: true, order: next.map(id => String(id)), workspaces: this.list() };
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,69 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-workspace-move-top",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "DSH 工作区菜单:移到最上面。一次调整顺序,保留自由拖动,无收藏或固定置顶。",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./lib/index.js",
|
|
8
|
+
"types": "./lib/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./lib/index.d.ts",
|
|
12
|
+
"default": "./lib/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./client": "./client/client.js",
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"lib/",
|
|
19
|
+
"client/",
|
|
20
|
+
"cordis.patch.yml",
|
|
21
|
+
"README.md",
|
|
22
|
+
"dsh-plugin.naming.json"
|
|
23
|
+
],
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/dongsheng123132/workspace-hub.git",
|
|
27
|
+
"directory": "plugins/dsh-workspace-move-top"
|
|
28
|
+
},
|
|
29
|
+
"dsh": {
|
|
30
|
+
"bundle": {
|
|
31
|
+
"patch": "./cordis.patch.yml"
|
|
32
|
+
},
|
|
33
|
+
"client": { "platform": "web" }
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc -p tsconfig.json",
|
|
37
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
38
|
+
"test": "node --test test/{client,composition}.test.mjs",
|
|
39
|
+
"check": "npm run typecheck && npm run build && npm test",
|
|
40
|
+
"prepack": "npm run build",
|
|
41
|
+
"pretest": "npm run build"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@deepseek-ai/cordis": "4.0.5",
|
|
45
|
+
"@deepseek-ai/dsh-workspace": "0.2.1-rc.5",
|
|
46
|
+
"@deepseek-ai/dsh-client-connection": "0.2.1-rc.5"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@deepseek-ai/cordis": "4.0.5",
|
|
50
|
+
"@deepseek-ai/dsh-workspace": "0.2.1-rc.5",
|
|
51
|
+
"@deepseek-ai/dsh-client-connection": "0.2.1-rc.5",
|
|
52
|
+
"@types/node": "24.10.1",
|
|
53
|
+
"typescript": "5.9.3"
|
|
54
|
+
},
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=22"
|
|
57
|
+
},
|
|
58
|
+
"keywords": [
|
|
59
|
+
"dsh-plugin",
|
|
60
|
+
"workspace",
|
|
61
|
+
"move-top",
|
|
62
|
+
"ordering"
|
|
63
|
+
],
|
|
64
|
+
"peerDependenciesMeta": {
|
|
65
|
+
"@deepseek-ai/dsh-client-connection": {
|
|
66
|
+
"optional": true
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|