@banana-peeljj12/dsh-trellis 0.3.2 → 0.3.4
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 +2 -1
- package/README_EN.md +1 -1
- package/lib/client.js +71 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -67,7 +67,8 @@ dsh plugin --profile web add @banana-peeljj12/dsh-trellis@latest
|
|
|
67
67
|
为避免非预期介入,插件默认不会拦截未授权的目录。请在 Web 端或配置文件中添加生效路径:
|
|
68
68
|
|
|
69
69
|
1. 打开 DSH Web 客户端,进入左下角 **设置 → 插件 → Trellis 工作流**;
|
|
70
|
-
2. 在 **白名单项目 (allowlist)**
|
|
70
|
+
2. 在 **白名单项目 (allowlist)** 中添加需要启用该工作流的项目根目录绝对路径——既可手动输入,
|
|
71
|
+
也可点击 **浏览…** 按钮弹出系统文件夹选择器直接选取,保存后即时生效。
|
|
71
72
|
|
|
72
73
|
> **提示**:若希望在方案定稿前限制模型修改源码,可在该设置页同时开启 **规划期只读保护 (enforceReadonlyPlanning)** 开关。
|
|
73
74
|
|
package/README_EN.md
CHANGED
|
@@ -67,7 +67,7 @@ After installation, **restart the DSH service**.
|
|
|
67
67
|
By default, the plugin will not intercept any unconfigured workspaces. Add your target workspace directory to the allowlist:
|
|
68
68
|
|
|
69
69
|
1. Open the DSH Web UI and navigate to bottom-left **Settings → Plugins → Trellis Workflow**;
|
|
70
|
-
2. Under **Allowed Projects (allowlist)**, add the absolute path of your workspace root directory
|
|
70
|
+
2. Under **Allowed Projects (allowlist)**, add the absolute path of your workspace root directory — either type it manually or click **Browse…** to pick a folder via the system folder picker, then click Save (hot-reloaded).
|
|
71
71
|
|
|
72
72
|
> **Note**: To prevent the model from editing source code prior to plan approval, enable **Enforce Read-Only Planning (`enforceReadonlyPlanning`)** in the same settings panel.
|
|
73
73
|
|
package/lib/client.js
CHANGED
|
@@ -44,7 +44,7 @@ window.__ModuleLoader__.load({
|
|
|
44
44
|
const LOCALE_NS = 'settings.trellisWorkflow';
|
|
45
45
|
|
|
46
46
|
/** Services required by this client half. */
|
|
47
|
-
const inject = ['slots', 'locale', 'settingsScope', 'sidebarRight'];
|
|
47
|
+
const inject = ['slots', 'locale', 'settingsScope', 'sidebarRight', 'uiWorkspace'];
|
|
48
48
|
|
|
49
49
|
const zh = {
|
|
50
50
|
tab: 'Trellis 工作流',
|
|
@@ -65,6 +65,9 @@ window.__ModuleLoader__.load({
|
|
|
65
65
|
'开启后,命中白名单的项目里:新对话(未建任务)只裁剪 write/edit 与任务写工具(trellis_task_update / trellis_artifact_update / trellis_task_archive / trellis_ui_update),其余工具(含其他插件的工具)保留;规划中的任务只裁剪 write/edit 与创建/跳过/归档类 trellis 工具,其余工具保留;经 trellis_task_skip 跳过任务的会话恢复完整工具。',
|
|
66
66
|
saved: '已保存',
|
|
67
67
|
writeFailed: '保存失败',
|
|
68
|
+
browse: '浏览…',
|
|
69
|
+
browseBusy: '选择中…',
|
|
70
|
+
browseFailed: '调用文件夹选择器失败,请手动输入路径',
|
|
68
71
|
chipTitle: 'Trellis Task',
|
|
69
72
|
chipNoTask: '无活动任务',
|
|
70
73
|
chipNoSummary: '尚无状态,点击刷新',
|
|
@@ -133,6 +136,9 @@ window.__ModuleLoader__.load({
|
|
|
133
136
|
allowlistHint: 'Sessions whose cwd matches these project roots receive the workflow breadcrumb.',
|
|
134
137
|
addPlaceholder: 'Project root path, e.g. F:/Projects/FordProject',
|
|
135
138
|
add: 'Add',
|
|
139
|
+
browse: 'Browse…',
|
|
140
|
+
browseBusy: 'Picking…',
|
|
141
|
+
browseFailed: 'Could not open the directory picker — enter the path manually',
|
|
136
142
|
remove: 'Remove',
|
|
137
143
|
empty: '(empty)',
|
|
138
144
|
injectStep: 'Inject step (injectStep)',
|
|
@@ -245,6 +251,50 @@ window.__ModuleLoader__.load({
|
|
|
245
251
|
setDraftPath('');
|
|
246
252
|
};
|
|
247
253
|
|
|
254
|
+
/**
|
|
255
|
+
* Folder picker browse button: open the Host's native directory picker
|
|
256
|
+
* (`ctx.uiWorkspace.pickDirectory()`), normalize the picked path
|
|
257
|
+
* (backslashes → forward slashes) and append it to the allowlist
|
|
258
|
+
* directly (deduped). Cancel (`null`) is a no-op; failures surface the
|
|
259
|
+
* `browseFailed` copy and keep the manual input path untouched.
|
|
260
|
+
*/
|
|
261
|
+
const [picking, setPicking] = react.useState(false);
|
|
262
|
+
const [pickError, setPickError] = react.useState(false);
|
|
263
|
+
react.useEffect(() => {
|
|
264
|
+
if (!pickError) return undefined;
|
|
265
|
+
const timer = setTimeout(() => setPickError(false), 2600);
|
|
266
|
+
return () => clearTimeout(timer);
|
|
267
|
+
}, [pickError]);
|
|
268
|
+
|
|
269
|
+
const browsePath = () => {
|
|
270
|
+
if (picking) return;
|
|
271
|
+
const workspaces = clientCtx && clientCtx.uiWorkspace;
|
|
272
|
+
if (!workspaces || typeof workspaces.pickDirectory !== 'function') {
|
|
273
|
+
setPickError(true);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
setPicking(true);
|
|
277
|
+
// Reuse the saved-flag effect's timer slot: browse errors auto-clear
|
|
278
|
+
// via pickError's own effect above; picking ends on any outcome.
|
|
279
|
+
workspaces
|
|
280
|
+
.pickDirectory()
|
|
281
|
+
.then((picked) => {
|
|
282
|
+
setPicking(false);
|
|
283
|
+
if (picked === null || picked === undefined) return; // user cancelled
|
|
284
|
+
const normalized = String(picked).trim().replace(/\\/g, '/');
|
|
285
|
+
if (!normalized) {
|
|
286
|
+
setPickError(true);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if (!allowlist.includes(normalized)) write('allowlist', allowlist.concat(normalized));
|
|
290
|
+
else setSaved(true); // already present — still confirm the click landed
|
|
291
|
+
})
|
|
292
|
+
.catch(() => {
|
|
293
|
+
setPicking(false);
|
|
294
|
+
setPickError(true);
|
|
295
|
+
});
|
|
296
|
+
};
|
|
297
|
+
|
|
248
298
|
const rowStyle = { display: 'flex', gap: 8, alignItems: 'center', marginBottom: 6 };
|
|
249
299
|
const inputStyle = {
|
|
250
300
|
flex: 1,
|
|
@@ -303,8 +353,28 @@ window.__ModuleLoader__.load({
|
|
|
303
353
|
onChange: (e) => setDraftPath(e.target.value),
|
|
304
354
|
onKeyDown: (e) => { if (e.key === 'Enter') addPath(); },
|
|
305
355
|
}),
|
|
356
|
+
react.createElement(
|
|
357
|
+
'button',
|
|
358
|
+
{
|
|
359
|
+
type: 'button',
|
|
360
|
+
style: { ...btnStyle, opacity: picking ? 0.6 : 1, cursor: picking ? 'wait' : 'pointer' },
|
|
361
|
+
disabled: picking,
|
|
362
|
+
onClick: browsePath,
|
|
363
|
+
},
|
|
364
|
+
picking ? t('browseBusy') : t('browse'),
|
|
365
|
+
),
|
|
306
366
|
react.createElement('button', { type: 'button', style: btnStyle, onClick: addPath }, t('add')),
|
|
307
367
|
),
|
|
368
|
+
pickError
|
|
369
|
+
? react.createElement(
|
|
370
|
+
'p',
|
|
371
|
+
{
|
|
372
|
+
style: { margin: 0, color: 'var(--dsw-alias-state-error-primary)', fontSize: 12 },
|
|
373
|
+
role: 'alert',
|
|
374
|
+
},
|
|
375
|
+
t('browseFailed'),
|
|
376
|
+
)
|
|
377
|
+
: null,
|
|
308
378
|
react.createElement('label', { style: labelStyle }, t('injectStep')),
|
|
309
379
|
react.createElement('input', {
|
|
310
380
|
type: 'number',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@banana-peeljj12/dsh-trellis",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Self-contained Trellis workflow trigger for DeepSeek Harness: per-turn breadcrumb injection via agent/pre-step, a bundled skill provider, and DSH-native task/phase state resolution. No Trellis AGPL code is vendored; workflow semantics are rewritten and licensed MIT.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|