@ninkch/dsh-artcraft 0.2.0 → 0.2.2
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.js +74 -66
- package/index.js +2 -1
- package/package.json +2 -2
package/client.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @ninkch/dsh-artcraft — client half.
|
|
2
|
-
//
|
|
2
|
+
// 不占侧栏/主面板:状态与「检查更新」挂在 插件页 → 本插件详情卡 上
|
|
3
|
+
// (plugins.detail.badge / plugins.detail.section)。
|
|
3
4
|
window.__ModuleLoader__.load({
|
|
4
5
|
id: '@ninkch/dsh-artcraft',
|
|
5
6
|
factory(require) {
|
|
@@ -8,28 +9,27 @@ window.__ModuleLoader__.load({
|
|
|
8
9
|
const { useState, useEffect, useCallback, useRef } = React;
|
|
9
10
|
|
|
10
11
|
const NS = 'artcraft';
|
|
11
|
-
const PANEL_ID = 'artcraft';
|
|
12
12
|
const API = '/artcraft/api';
|
|
13
13
|
|
|
14
14
|
const CSS = `
|
|
15
|
-
.dshac-
|
|
16
|
-
.dshac-
|
|
17
|
-
.dshac-
|
|
18
|
-
.dshac-
|
|
19
|
-
.dshac-row { display: flex; align-items: center; gap: 8px; margin: 4px 0; }
|
|
20
|
-
.dshac-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
|
|
15
|
+
.dshac-card { border: 1px solid var(--dsw-border-primary, rgba(128,128,128,.35)); border-radius: 10px; padding: 12px; font-size: 13px; line-height: 1.5; }
|
|
16
|
+
.dshac-title { font-weight: 600; margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center; gap: 8px; }
|
|
17
|
+
.dshac-row { display: flex; align-items: center; gap: 8px; margin: 4px 0; flex-wrap: wrap; }
|
|
18
|
+
.dshac-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; display: inline-block; }
|
|
21
19
|
.dshac-dot.ok { background: #34c759; } .dshac-dot.bad { background: #ff5f57; } .dshac-dot.unknown { background: #8e8e93; }
|
|
22
20
|
.dshac-mono { font-family: ui-monospace, Consolas, monospace; font-size: 12px; word-break: break-all; }
|
|
23
21
|
.dshac-muted { opacity: .65; font-size: 12px; }
|
|
24
22
|
.dshac-btn { border: 1px solid var(--dsw-border-primary, rgba(128,128,128,.4)); background: transparent; color: inherit;
|
|
25
|
-
border-radius: 7px; padding:
|
|
23
|
+
border-radius: 7px; padding: 3px 10px; font-size: 12px; cursor: pointer; }
|
|
26
24
|
.dshac-btn:hover:not(:disabled) { background: rgba(128,128,128,.15); }
|
|
27
25
|
.dshac-btn:disabled { opacity: .5; cursor: default; }
|
|
28
26
|
.dshac-btn.primary { background: rgba(80,120,255,.25); }
|
|
29
27
|
.dshac-out { white-space: pre-wrap; font-family: ui-monospace, Consolas, monospace; font-size: 11px;
|
|
30
|
-
background: rgba(128,128,128,.12); border-radius: 7px; padding: 8px; margin-top: 8px; max-height:
|
|
28
|
+
background: rgba(128,128,128,.12); border-radius: 7px; padding: 8px; margin-top: 8px; max-height: 160px; overflow: auto; }
|
|
31
29
|
.dshac-note { margin-top: 8px; color: var(--dsw-alias-state-warning-primary, #d69e2e); font-size: 12px; }
|
|
32
30
|
.dshac-ok { color: var(--dsw-alias-state-success-primary, #34c759); }
|
|
31
|
+
.dshac-chip { display: inline-flex; align-items: center; border: 1px solid rgba(80,120,255,.5); color: inherit;
|
|
32
|
+
background: rgba(80,120,255,.18); border-radius: 999px; padding: 1px 9px; font-size: 11px; }
|
|
33
33
|
`;
|
|
34
34
|
|
|
35
35
|
async function api(path, opts) {
|
|
@@ -43,25 +43,40 @@ window.__ModuleLoader__.load({
|
|
|
43
43
|
} finally { if (timer) clearTimeout(timer); }
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/** 详情页 subject 兼容提取:判断当前详情页是否本插件 */
|
|
47
|
+
function isOurPage(props) {
|
|
48
|
+
const sub = props && props.subject ? props.subject : props;
|
|
49
|
+
if (!sub) return false;
|
|
50
|
+
const name = sub.packageName ?? sub.name ?? sub.moduleName ?? sub.id ?? (typeof sub === 'string' ? sub : '');
|
|
51
|
+
return typeof name === 'string' && name.includes('dsh-artcraft');
|
|
52
|
+
}
|
|
53
|
+
|
|
46
54
|
function Dot({ ok }) {
|
|
47
55
|
return h('span', { className: 'dshac-dot ' + (ok === true ? 'ok' : ok === false ? 'bad' : 'unknown') });
|
|
48
56
|
}
|
|
49
57
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
/** 详情页标题旁的徽标:有新版本时出现 */
|
|
59
|
+
function UpdateBadge(props) {
|
|
60
|
+
const [latest, setLatest] = useState(null);
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (!isOurPage(props)) return;
|
|
63
|
+
let ok = true;
|
|
64
|
+
api('/update/check').then((u) => { if (ok && u?.updateAvailable) setLatest(u.latest); }).catch(() => {});
|
|
65
|
+
return () => { ok = false; };
|
|
66
|
+
}, []);
|
|
67
|
+
if (!isOurPage(props) || !latest) return null;
|
|
68
|
+
return h('span', { className: 'dshac-chip', title: 'npm 上有新版本,到本页一键更新' }, '有新版本 v' + latest);
|
|
56
69
|
}
|
|
57
70
|
|
|
58
|
-
|
|
71
|
+
/** 详情页内容区:工具链状态 + 更新 */
|
|
72
|
+
function StatusSection(props) {
|
|
59
73
|
const [status, setStatus] = useState(null);
|
|
60
74
|
const [statusErr, setStatusErr] = useState(null);
|
|
61
75
|
const [upd, setUpd] = useState(null);
|
|
62
76
|
const [busy, setBusy] = useState('');
|
|
63
77
|
const [out, setOut] = useState('');
|
|
64
78
|
const [needRestart, setNeedRestart] = useState(false);
|
|
79
|
+
const ours = isOurPage(props);
|
|
65
80
|
const alive = useRef(true);
|
|
66
81
|
useEffect(() => () => { alive.current = false; }, []);
|
|
67
82
|
|
|
@@ -70,10 +85,7 @@ window.__ModuleLoader__.load({
|
|
|
70
85
|
const s = await api('/status');
|
|
71
86
|
if (!alive.current) return;
|
|
72
87
|
setStatus(s); setStatusErr(null);
|
|
73
|
-
} catch (e) {
|
|
74
|
-
if (!alive.current) return;
|
|
75
|
-
setStatusErr(String(e.message || e));
|
|
76
|
-
}
|
|
88
|
+
} catch (e) { if (alive.current) setStatusErr(String(e.message || e)); }
|
|
77
89
|
}, []);
|
|
78
90
|
const checkUpdate = useCallback(async () => {
|
|
79
91
|
setBusy('check'); setOut('');
|
|
@@ -98,7 +110,12 @@ window.__ModuleLoader__.load({
|
|
|
98
110
|
finally { if (alive.current) setBusy(''); }
|
|
99
111
|
}, []);
|
|
100
112
|
|
|
101
|
-
useEffect(() => {
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
if (!ours) return;
|
|
115
|
+
loadStatus(); checkUpdate();
|
|
116
|
+
}, [ours, loadStatus, checkUpdate]);
|
|
117
|
+
|
|
118
|
+
if (!ours) return null;
|
|
102
119
|
|
|
103
120
|
const bins = status?.bins ?? {};
|
|
104
121
|
const binRow = (key, label) => {
|
|
@@ -110,52 +127,39 @@ window.__ModuleLoader__.load({
|
|
|
110
127
|
);
|
|
111
128
|
};
|
|
112
129
|
|
|
113
|
-
return h('div', { className: 'dshac-
|
|
114
|
-
h('div', { className: 'dshac-
|
|
115
|
-
|
|
116
|
-
|
|
130
|
+
return h('div', { className: 'dshac-card' },
|
|
131
|
+
h('div', { className: 'dshac-title' }, 'ArtCraft 工具链与更新',
|
|
132
|
+
h('button', { className: 'dshac-btn', onClick: loadStatus, disabled: busy !== '' }, '刷新')),
|
|
117
133
|
statusErr
|
|
118
|
-
? h('div', { className: 'dshac-
|
|
119
|
-
|
|
120
|
-
h('div', { className: 'dshac-muted' }, statusErr + ' —— 插件可能未注册或 Harness 需要重启。'))
|
|
121
|
-
: h('div', { className: 'dshac-card' },
|
|
122
|
-
h('div', { className: 'dshac-title' }, '工具链',
|
|
123
|
-
h('button', { className: 'dshac-btn', onClick: loadStatus, disabled: busy !== '' }, '刷新')),
|
|
134
|
+
? h('div', { className: 'dshac-muted' }, '未连接:' + statusErr + '(插件可能未注册或 Harness 需要重启)')
|
|
135
|
+
: h('div', null,
|
|
124
136
|
binRow('photocraft', 'PhotoCraft (CLI)'),
|
|
125
137
|
binRow('filmcraft', 'FilmCraft (CLI)'),
|
|
126
138
|
binRow('effectcraft', 'EffectCraft (CLI)'),
|
|
127
139
|
status?.dataRoot ? h('div', { className: 'dshac-row dshac-muted' },
|
|
128
140
|
'数据目录:', h('span', { className: 'dshac-mono' }, status.dataRoot.path)) : null),
|
|
129
|
-
|
|
130
|
-
h('
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
h('button', {
|
|
145
|
-
className: 'dshac-btn primary',
|
|
146
|
-
onClick: applyUpdate,
|
|
147
|
-
disabled: busy !== '' || !upd?.updateAvailable,
|
|
148
|
-
title: upd?.updateAvailable ? '' : '先检查更新,有新版本才可应用',
|
|
149
|
-
}, busy === 'apply' ? '更新中…' : '一键更新')),
|
|
150
|
-
needRestart ? h('div', { className: 'dshac-note' }, '更新已写入 —— 重启 DeepSeek Harness 后生效。') : null,
|
|
151
|
-
out ? h('div', { className: 'dshac-out' }, out) : null),
|
|
141
|
+
h('div', { className: 'dshac-row', style: { marginTop: '10px' } },
|
|
142
|
+
h('span', { className: 'dshac-muted' },
|
|
143
|
+
'当前 v' + (status?.version ?? upd?.current ?? '?') +
|
|
144
|
+
(upd ? ' · npm latest v' + (upd.latest ?? '—') : '') +
|
|
145
|
+
(upd?.mode ? '(' + (upd.mode === 'git' ? 'git 仓库' + (upd.gitClean === false ? ' · 有本地改动' : '') : 'npm 安装') + ')' : '')),
|
|
146
|
+
h('button', { className: 'dshac-btn primary', onClick: checkUpdate, disabled: busy !== '' },
|
|
147
|
+
busy === 'check' ? '检查中…' : '检查更新'),
|
|
148
|
+
h('button', {
|
|
149
|
+
className: 'dshac-btn',
|
|
150
|
+
onClick: applyUpdate,
|
|
151
|
+
disabled: busy !== '' || !upd?.updateAvailable,
|
|
152
|
+
title: upd?.updateAvailable ? '' : '有新版本时才可应用',
|
|
153
|
+
}, busy === 'apply' ? '更新中…' : '一键更新')),
|
|
154
|
+
needRestart ? h('div', { className: 'dshac-note' }, '更新已写入 —— 重启 DeepSeek Harness 后生效。') : null,
|
|
155
|
+
out ? h('div', { className: 'dshac-out' }, out) : null,
|
|
152
156
|
);
|
|
153
157
|
}
|
|
154
158
|
|
|
155
159
|
return {
|
|
156
160
|
inject: ['slots', 'locale'],
|
|
157
161
|
apply(ctx) {
|
|
158
|
-
ctx.effect(() => ctx.locale.register(NS, { zh: {
|
|
162
|
+
ctx.effect(() => ctx.locale.register(NS, { zh: { artcraft: 'ArtCraft' }, en: { artcraft: 'ArtCraft' } }), 'artcraft: dictionaries');
|
|
159
163
|
ctx.effect(() => {
|
|
160
164
|
const el = document.createElement('style');
|
|
161
165
|
el.id = 'dshac-styles';
|
|
@@ -163,18 +167,22 @@ window.__ModuleLoader__.load({
|
|
|
163
167
|
document.head.appendChild(el);
|
|
164
168
|
return () => el.remove();
|
|
165
169
|
}, 'artcraft: styles');
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
170
|
+
// 插件页 → 本插件详情卡:标题旁徽标(有新版本时)
|
|
171
|
+
ctx.slots.inject('plugins.detail.badge', () => ctx.slots.register({
|
|
172
|
+
name: 'plugins.detail.badge',
|
|
173
|
+
id: 'artcraft-update-badge',
|
|
174
|
+
order: 50,
|
|
175
|
+
label: () => 'ArtCraft 更新',
|
|
171
176
|
locale: NS,
|
|
172
|
-
},
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
177
|
+
}, UpdateBadge));
|
|
178
|
+
// 插件页 → 本插件详情卡:内容区(工具链状态 + 检测更新 + 一键更新)
|
|
179
|
+
ctx.slots.inject('plugins.detail.section', () => ctx.slots.register({
|
|
180
|
+
name: 'plugins.detail.section',
|
|
181
|
+
id: 'artcraft-status',
|
|
182
|
+
order: 50,
|
|
183
|
+
label: () => 'ArtCraft 工具链与更新',
|
|
176
184
|
locale: NS,
|
|
177
|
-
},
|
|
185
|
+
}, StatusSection));
|
|
178
186
|
},
|
|
179
187
|
};
|
|
180
188
|
},
|
package/index.js
CHANGED
|
@@ -39,7 +39,7 @@ import crypto from 'node:crypto';
|
|
|
39
39
|
import { fileURLToPath } from 'node:url';
|
|
40
40
|
|
|
41
41
|
const NAME = 'artcraft';
|
|
42
|
-
const VERSION = '0.2.
|
|
42
|
+
const VERSION = '0.2.2';
|
|
43
43
|
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
44
44
|
|
|
45
45
|
const BINS = ['photocraft', 'filmcraft', 'effectcraft'];
|
|
@@ -580,6 +580,7 @@ export function apply(ctx) {
|
|
|
580
580
|
ctx.effect(() => {
|
|
581
581
|
const disposers = [];
|
|
582
582
|
const attempt = (def) => {
|
|
583
|
+
const output = def.output ?? { type: 'object', additionalProperties: true };
|
|
583
584
|
for (const shape of [
|
|
584
585
|
{ name: def.name, description: def.description, parameters: def.schema, execute: def.execute },
|
|
585
586
|
{ name: def.name, description: def.description, inputSchema: def.schema, handler: def.execute },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
2
|
"name": "@ninkch/dsh-artcraft",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Drive the open-source ArtCraft studio apps (PhotoCraft / FilmCraft / EffectCraft) from DeepSeek Harness — agent tools, a same-origin HTTP API, and a sidebar panel with toolchain status and self-update.",
|
|
6
6
|
"keywords": [
|