@godv61/dsh-task-engine 0.22.4 → 0.22.6
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/.p0-test.mjs +15 -0
- package/README.md +18 -2
- package/docs/manual.html +6 -2
- package/lib/client.js +110 -4
- package/lib/client.js.map +2 -2
- package/lib/controller.d.ts +18 -0
- package/lib/controller.js +86 -1
- package/lib/controller.js.map +1 -1
- package/lib/index.d.ts +6 -0
- package/lib/index.js +6 -0
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/.p0-test.mjs
CHANGED
|
@@ -708,4 +708,19 @@ function memProbe(files) {
|
|
|
708
708
|
assert(ctl.checkedPath('D:/proj/one') === 'D:/proj/one', 'strict mode still admits registered workspaces')
|
|
709
709
|
}
|
|
710
710
|
|
|
711
|
+
// ── 36. 0.22.5: directory-bundle skill install Remote ──────────────────────
|
|
712
|
+
{
|
|
713
|
+
const controller = readFileSync('./lib/controller.js', 'utf8')
|
|
714
|
+
assert(controller.includes('installSkill'), 'installSkill Remote is registered')
|
|
715
|
+
assert(controller.includes('源目录必须是绝对路径'), 'install rejects a non-absolute source directory')
|
|
716
|
+
assert(controller.includes('SKILL.md'), 'install requires SKILL.md in the source directory')
|
|
717
|
+
assert(controller.includes('node_modules'), 'install skips dependency caches')
|
|
718
|
+
assert(controller.includes('内置技能,不可覆盖'), 'install refuses to shadow a bundled skill')
|
|
719
|
+
}
|
|
720
|
+
{
|
|
721
|
+
const client = readFileSync('./lib/client.js', 'utf8')
|
|
722
|
+
assert(client.includes('installSkill'), 'client declares the installSkill Remote contract')
|
|
723
|
+
assert(client.includes('sourceDir'), 'client schema carries the source directory')
|
|
724
|
+
}
|
|
725
|
+
|
|
711
726
|
console.log(`\nP0 acceptance: ${passed} checks passed`)
|
package/README.md
CHANGED
|
@@ -56,6 +56,20 @@ dsh plugin --profile <name> add github:<你的org>/dsh-task-engine
|
|
|
56
56
|
dsh plugin --profile <name> add .
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
+
### host 集成 API(0.22.4,供 harness 层接入)
|
|
60
|
+
|
|
61
|
+
`./agent`(工具面)无需额外集成;工作台 Remote 的 workspace 边界可由宿主收紧:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { registerWorkspace, enableStrictWorkspaces } from '@godv61/dsh-task-engine'
|
|
65
|
+
// 每个会话工作区挂载时注册(未注册的路径被 Remote 拒绝):
|
|
66
|
+
registerWorkspace('/absolute/workspace/path')
|
|
67
|
+
// 生产模式:空 registry 不再回退放行(不调用则保持兼容的防误用校验):
|
|
68
|
+
enableStrictWorkspaces()
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
根治性的 Typert 调用上下文(Remote 携带 session/workspace)与任务状态的 host 侧 HMAC 签名仍在 harness 层,本包已预留接入点并在「门禁边界」说明三层分工。
|
|
72
|
+
|
|
59
73
|
## 启用(点选即用)
|
|
60
74
|
|
|
61
75
|
装完 bundle、重启 web,预设列表里会**自动多出一个「工程化开发引擎」**——host 半在首次启动时把它对齐当前 `standard` 生成(换好工程人设 + 加好 agent 行),落在 `~/.dsh/.agent-presets/eng/`。
|
|
@@ -158,7 +172,7 @@ dsh plugin --profile <name> add .
|
|
|
158
172
|
|
|
159
173
|
## 状态与待办
|
|
160
174
|
|
|
161
|
-
-
|
|
175
|
+
- **当前验证基线(0.22.4)**:`npm test` 123 项验收全过(引擎状态机 / 守卫 / 快照 hash / 回执门 / 并发 CAS / Remote 路径 / 沙箱策略断言);`npm run typecheck` host + client 双面零错误;`npm run verify:package` 发布包黑盒 16 项(pack → 白名单 → 真实安装 → 主入口 import → client 注册 → 包内测试 → CLI);真实 git 临时仓库 e2e(合法放行 / 阶段·范围·快照篡改·敏感路径拦截);headless Chrome 实测侧栏入口与设置按钮逐像素对齐。发布前必跑 `npm test` + `npm run verify:package`。
|
|
162
176
|
- **真实模型端到端(0.4.1)**:headless + NewAPI DeepSeek 下让真模型走 `dev_task` 全流程,抓到并修掉一个真实 bug——`readText`/`writeText` 调 `fs.resolve()` 漏了 `await`,把 `Promise<FsTarget>` 当 `target` 传给了读写方法,导致 create/record/advance/commit 全部写不了任务文件、读永远返回 undefined。0.4.1 修复(`await fs.resolve(relPath)`),并把 `task_id` 在 create 也必填的说明补进工具 schema 与技能。修复后走真实 `ctx.fs` 路径冒烟全绿。
|
|
163
177
|
- **网页图形化配置界面(0.5.0)**:新增 `src/client/` 设置页「工程流程配置」+ Host 端 `task-engine` Remote 控制器;`@godv61/dsh-task-engine` 升级为双端包(`dsh.client` manifest + `./client` 出品,`exports` 暴露)。已实机验证:`dsh web` 起服务后 boot 数据里 `@godv61/dsh-task-engine` 以 `inject:["@deepseek-ai/dsh-api-gateway"]` 进入 application batch、`/plugins/…/client.js` 正常服务;headless 冒烟确认 boot + `dev_task` 未被新控制器破坏。浏览器点击级 e2e 留到发布后用真浏览器收尾。
|
|
164
178
|
- **skill/rule 挂载与渐进披露(0.6.0)**:`WorkflowConfig` 新增 `stage_bindings`(每阶段挂 skills/rules,可选字段),`dev_task` 的 `status`/`advance` 按当前阶段披露挂载的 skill 名 + rule 正文;内置 6 技能 + 3 规则库;Host 控制器新增 `listSkills`/`listRules`/`writeSkill`/`writeRule`;设置页新增「节点挂载」和「新建 skill / rule」两块,同时补上 `dev_task` 缺失的 `items` 操作(更新实施项状态)。引擎层 `stage_bindings` 校验(未知阶段/空名)与合并已单测通过。
|
|
@@ -187,4 +201,6 @@ dsh plugin --profile <name> add .
|
|
|
187
201
|
- **沙箱写入修复(0.22.1)**:`dev_task` 的文件写入此前没有携带按调用传递的沙箱策略(`writeText` 的 `sandboxPolicy` 参数),在 DSH 文件沙箱下会把 workspace 内的任务记录写入误判为越界而拒绝(`file access denied under workspace-write mode`,且会话策略变化无法影响它);现在每次写入显式携带 `{ mode, workspaceRoot: 会话目录 }`,并新增 `sandbox_permissions` 参数(`workspace-write` / `danger-full-access`)作为被拒后的一次性升级路径。
|
|
188
202
|
- **质量修补(0.22.2,采纳 codex 评审五项)**:① client typecheck 修复——`project.ts` 不再依赖 `node:path`,浏览器面可完整类型检查;② sandbox 升级补审批——`sandbox_permissions` 必须与 `justification` 成对出现,`danger-full-access` 需人工一次批准,无审批服务即拒绝;③ Remote 任意路径设防——工作台 Remote 拒绝非绝对路径与系统级根目录;④ `set_risk` 升到 `high_risk` 时受流程能力门约束(`minimal`/`agile` 拒绝,不再绕过 `create` 的检查);⑤ `loadTask` 补齐旧记录缺失字段(items / verification / review / commits),损坏记录 fail-closed 而非引擎裸崩。
|
|
189
203
|
- **可信边界加固(0.22.3,采纳 GPT 评审)**:① 验证命令统一在任务记录的项目根运行(monorepo 子目录不再跑错目录),receipt.root 与任务根强校验;② 旧任务(无 frozen 快照)禁止升 `high_risk`——迁移或重建后才可;③ `init apply` 强制 `expected_hash`,新增 `existing_hash` 防审批期间文件被换(TOCTOU);④ 任务记录新增 `revision`,每次写入 compare-and-swap,并发覆盖直接报错(`changed concurrently`);⑤ 工作台 Remote 增加 host workspace registry(`registerWorkspace` 供 harness 集成,注册后未授权路径一律拒绝);⑥ sandbox 升级审批展示 workspace;⑦ 文档明确 hook(本地反馈)/ host(工具流约束)/ CI(最终可信门禁)三层职责边界。
|
|
190
|
-
- **并发与发布闭环(0.22.4,采纳 REVIEW-0.22.3)**:① `init apply` 在目标文件存在时**强制** `existing_hash`(不再可选),propose→apply 之间文件被篡改直接 fail-closed;② 任务写入升级为真正的原子 CAS——逻辑 `revision` 检查 + dsh-fs 的 `lstat` 版本号 `replaceIfVersion` write intent,并发写入报 `FS_STALE_VERSION` 而非静默覆盖;③ workspace registry 增加 `enableStrictWorkspaces()` 生产模式(空 registry 不再回退放行);④ `exports["./client"]` 补 `types` 条件(`lib/client.d.ts` 随构建生成);⑤ 新增 `npm run verify:package` 发布包黑盒验证(pack → 白名单一致性 → 真实安装 → 主入口 import → client 注册 → 包内
|
|
204
|
+
- **并发与发布闭环(0.22.4,采纳 REVIEW-0.22.3)**:① `init apply` 在目标文件存在时**强制** `existing_hash`(不再可选),propose→apply 之间文件被篡改直接 fail-closed;② 任务写入升级为真正的原子 CAS——逻辑 `revision` 检查 + dsh-fs 的 `lstat` 版本号 `replaceIfVersion` write intent,并发写入报 `FS_STALE_VERSION` 而非静默覆盖;③ workspace registry 增加 `enableStrictWorkspaces()` 生产模式(空 registry 不再回退放行);④ `exports["./client"]` 补 `types` 条件(`lib/client.d.ts` 随构建生成);⑤ 新增 `npm run verify:package` 发布包黑盒验证(pack → 白名单一致性 → 真实安装 → 主入口 import → client 注册 → 包内 123 checks → CLI 语法);⑥ 工作台 UI 优化——侧栏「工程流程」入口与设置按钮逐像素对齐(实测对齐 36 圆形 rail / 42 高 12 圆角展开行)、流程预设改卡片式选择器、工作台 header 品牌化、初始化预览容器化。REVIEW 指出的 Typert invocation context、host 可信状态签名、CI 最终门禁仍属 harness 层,集成点已在文档标注。
|
|
205
|
+
- **目录型 skill 安装(0.22.5)**:工作台「技能」页新增「安装 skill」——把本机已有的目录型 skill(`SKILL.md` + references / scripts / agents 等文件)一键装到<b>项目级</b>(工作区 `.dsh/skills`,团队共享)或<b>用户级</b>(`$DSH_HOME/skills`,个人所有项目可用);安装校验 SKILL.md frontmatter、拒绝覆盖内置同名、拒绝覆盖已装同名、自动排除 node_modules / .git / `__pycache__` 等缓存目录并限制 200 文件 / 20 MB;实机验证 `software-testing` 目录型 skill 从 UI 安装完整落盘(含 references + scripts)。
|
|
206
|
+
- **文案收尾(0.22.6)**:「安装 skill」输入框 placeholder 去掉示例绝对路径,改为通用提示「本机 skill 目录,需含 SKILL.md」。
|
package/docs/manual.html
CHANGED
|
@@ -198,7 +198,7 @@ pnpm install && pnpm run build && pnpm dsh web</code></pre>
|
|
|
198
198
|
<li><strong>选流程预设</strong>:standard / agile / minimal 点一下即切。</li>
|
|
199
199
|
<li><strong>给节点挂 skill / rule</strong>:先选一个节点(如「开发」),再勾选它用什么 skill、守哪条 rule,保存。</li>
|
|
200
200
|
</ol>
|
|
201
|
-
<p
|
|
201
|
+
<p>「技能」页支持新建 / <b>安装</b> / 查看 / 编辑 / 删除:内置资源只读(正文以 markdown 富文本渲染);项目级 / 用户级资源可编辑、可删除(两步确认)。「安装 skill」把本机已有的<b>目录型 skill</b>(含 <code>SKILL.md</code>,可带 references / scripts 等文件)一键装到项目级(工作区 <code>.dsh/skills</code>,团队共享)或用户级(<code>$DSH_HOME/skills</code>,个人所有项目可用);自动排除 node_modules / <code>.git</code> / <code>__pycache__</code> 等缓存,同名内置或已装技能拒绝覆盖。</p>
|
|
202
202
|
<pre><code>// .dsh/eng.json 等价内容
|
|
203
203
|
{
|
|
204
204
|
"flow": "standard",
|
|
@@ -309,6 +309,7 @@ pnpm install && pnpm run build && pnpm dsh web</code></pre>
|
|
|
309
309
|
<li>无法联调外部系统时必须如实写「未联调」,不能把编译成功说成功能通过。</li>
|
|
310
310
|
<li><code>high_risk</code> 任务过验证门必须跑真实命令回执(引擎运行命令、取退出码,非自报通过)。</li>
|
|
311
311
|
<li><code>verify</code> 不带 <code>command</code> 时引擎自动选命令:<code>.dsh/eng.json</code> 的 <code>verify_command</code> 优先,其次按项目语言用默认(node → <code>npm test</code>、java → <code>mvn -q test</code>、python → <code>python -m pytest</code>、go → <code>go test ./...</code>、rust → <code>cargo test</code>);识别不出语言且未配置时保留自报路径。跑命令依赖宿主 shell 服务,未挂载会明确报错。</li>
|
|
312
|
+
<li><b>验证命令始终在任务记录的项目根运行</b>(任务创建时自动发现并固化 <code>root</code>),不是会话当前目录——monorepo 里会话停在子目录时,<code>npm test</code> 等也会在放清单文件的项目根执行;回执记录的 <code>root</code> 与任务根强校验,不一致直接拒绝。</li>
|
|
312
313
|
</ul>
|
|
313
314
|
<h3>评审</h3>
|
|
314
315
|
<p>开发阶段每项做「规格 + 质量」两阶段评审,都 pass 才标 done;缺评审或任一阶段 fail 会挡住「开发 → 交付」。</p>
|
|
@@ -370,8 +371,11 @@ risk_level: high_risk // 涉及鉴权,验证要加证据
|
|
|
370
371
|
<details><summary>任务文档要不要提交?</summary><div>要。<code>.dsh/task-*.json</code> 是团队共享、跨会话恢复的任务事实,随分支提交——引擎已豁免 <code>.dsh/task-*.json</code> 与 <code>.dsh/eng.json</code>,不受文件范围门拦截;忽略它别人只能看到代码,看不到确认内容和进度。</div></details>
|
|
371
372
|
<details><summary>一个会话能同时做两个需求吗?</summary><div>一个任务对应一份状态文档、一个分支。新需求保存当前进度后切新分支,切回原分支即可恢复。</div></details>
|
|
372
373
|
<details><summary>提交被拒是怎么回事?</summary><div>通常是四类:没建 dev_task 任务、阶段没到提交检查点、消息格式不符、提交文件不在任务范围内。按拒绝原因修正即可。</div></details>
|
|
374
|
+
<details><summary>git 钩子能防住所有绕过吗?</summary><div>不能,这是它的定位:<code>.git/hooks/commit-msg</code> 是<b>本地即时反馈</b>,拦常规 <code>git commit</code>(校验任务、阶段、范围、消息、快照 hash、敏感路径),但挡不住 <code>git commit --no-verify</code>、<code>core.hooksPath</code> 替换或直接手改 task 记录。<b>最终可信门禁在 CI</b>:CI 里重新校验 task id、快照 hash、staged 范围、提交消息、真实验证退出码、高风险回执,并检测钩子是否被绕过。三层分工:钩子 = 本地反馈,host 工具流 = 正常路径强约束,CI = 最终验证。</div></details>
|
|
375
|
+
<details><summary>任务记录被手改会怎样?</summary><div>引擎会拒绝:任务创建时把流程配置固化成 SHA-256 快照,工具和钩子每次读任务记录都校验——<b>被改过的快照一律拒绝继续</b>(提示修复或重建任务)。另外每次写入带 <code>revision</code> 版本号做 compare-and-swap,多个会话同时改同一任务会报「changed concurrently」而不是静默互相覆盖。</div></details>
|
|
376
|
+
<details><summary>dev_task 写文件被沙箱拒绝(file access denied)怎么办?</summary><div>沙箱按调用策略放行写入,偶发的越界误判可用一次性升级重试:同一操作加 <code>sandbox_permissions: "workspace-write"(或 "danger-full-access")</code> 并配 <code>justification</code>(一句话说明原因),升级需要<b>人工批准</b>;无审批服务时直接拒绝。日常任务记录写入默认已在会话工作区内放行,通常无需升级。</div></details>
|
|
373
377
|
<details><summary>「完成」等于上线了吗?</summary><div>不等于。<code>done</code> 只表示本地验证与必要评审通过;上线、合并、发布需人另行决定。</div></details>
|
|
374
|
-
<p class="stamp">当前结构基线:三套流程预设 · 工作台项目初始化(0.19.0)· 通用项目适配(0.21.0)· 审计与发布质量(0.22.0)· 最后更新:2026-09-
|
|
378
|
+
<p class="stamp">当前结构基线:三套流程预设 · 工作台项目初始化(0.19.0)· 通用项目适配(0.21.0)· 审计与发布质量(0.22.0)· 可信边界加固(0.22.3)· 并发与发布闭环(0.22.4)· 最后更新:2026-09-14</p>
|
|
375
379
|
</section>
|
|
376
380
|
</main>
|
|
377
381
|
</div>
|
package/lib/client.js
CHANGED
|
@@ -4134,6 +4134,11 @@ var writeSkillRequestSchema = external_exports.object({
|
|
|
4134
4134
|
level: external_exports.enum(["project", "user"]),
|
|
4135
4135
|
path: external_exports.string().optional()
|
|
4136
4136
|
});
|
|
4137
|
+
var installSkillRequestSchema = external_exports.object({
|
|
4138
|
+
sourceDir: external_exports.string(),
|
|
4139
|
+
level: external_exports.enum(["project", "user"]),
|
|
4140
|
+
path: external_exports.string().optional()
|
|
4141
|
+
});
|
|
4137
4142
|
var writeRuleRequestSchema = external_exports.object({
|
|
4138
4143
|
name: external_exports.string(),
|
|
4139
4144
|
content: external_exports.string(),
|
|
@@ -4308,6 +4313,22 @@ var TYPERT_REMOTE = {
|
|
|
4308
4313
|
],
|
|
4309
4314
|
result: { mode: "strict", typeSymbol: `${PACKAGE}/types#WriteResourceResult`, schema: writeResourceResultSchema }
|
|
4310
4315
|
},
|
|
4316
|
+
{
|
|
4317
|
+
id: `${PACKAGE}#task-engine/installSkill`,
|
|
4318
|
+
service: "taskEngineController",
|
|
4319
|
+
namespace: "task-engine",
|
|
4320
|
+
method: "installSkill",
|
|
4321
|
+
invocation: { kind: "direct" },
|
|
4322
|
+
parameters: [
|
|
4323
|
+
{
|
|
4324
|
+
name: "request",
|
|
4325
|
+
wire: "request",
|
|
4326
|
+
source: "json",
|
|
4327
|
+
codec: { mode: "strict", typeSymbol: `${PACKAGE}/types#InstallSkillRequest`, schema: installSkillRequestSchema }
|
|
4328
|
+
}
|
|
4329
|
+
],
|
|
4330
|
+
result: { mode: "strict", typeSymbol: `${PACKAGE}/types#WriteResourceResult`, schema: writeResourceResultSchema }
|
|
4331
|
+
},
|
|
4311
4332
|
{
|
|
4312
4333
|
id: `${PACKAGE}#task-engine/writeRule`,
|
|
4313
4334
|
service: "taskEngineController",
|
|
@@ -5423,6 +5444,9 @@ function SkillManager({ workspace, remote }) {
|
|
|
5423
5444
|
const [whenToUse, setWhenToUse] = (0, import_react4.useState)("");
|
|
5424
5445
|
const [body2, setBody] = (0, import_react4.useState)("");
|
|
5425
5446
|
const [msg, setMsg] = (0, import_react4.useState)("");
|
|
5447
|
+
const [installing, setInstalling] = (0, import_react4.useState)(false);
|
|
5448
|
+
const [installDir, setInstallDir] = (0, import_react4.useState)("");
|
|
5449
|
+
const [installLevel, setInstallLevel] = (0, import_react4.useState)("project");
|
|
5426
5450
|
const refresh = (0, import_react4.useCallback)(() => {
|
|
5427
5451
|
void remote.listSkills(workspace).then((r) => {
|
|
5428
5452
|
if (r.ok) setSkills(r.value.skills);
|
|
@@ -5446,6 +5470,7 @@ function SkillManager({ workspace, remote }) {
|
|
|
5446
5470
|
setEditing(null);
|
|
5447
5471
|
setCreating(true);
|
|
5448
5472
|
setViewing(false);
|
|
5473
|
+
setInstalling(false);
|
|
5449
5474
|
setLevel("project");
|
|
5450
5475
|
setName("");
|
|
5451
5476
|
setDescription("");
|
|
@@ -5453,6 +5478,34 @@ function SkillManager({ workspace, remote }) {
|
|
|
5453
5478
|
setBody("");
|
|
5454
5479
|
setMsg("");
|
|
5455
5480
|
};
|
|
5481
|
+
const startInstall = () => {
|
|
5482
|
+
setEditing(null);
|
|
5483
|
+
setCreating(false);
|
|
5484
|
+
setViewing(false);
|
|
5485
|
+
setInstalling(true);
|
|
5486
|
+
setInstallDir("");
|
|
5487
|
+
setInstallLevel("project");
|
|
5488
|
+
setMsg("");
|
|
5489
|
+
};
|
|
5490
|
+
const submitInstall = async () => {
|
|
5491
|
+
setMsg("");
|
|
5492
|
+
const result = await remote.installSkill({
|
|
5493
|
+
sourceDir: installDir,
|
|
5494
|
+
level: installLevel,
|
|
5495
|
+
path: installLevel === "project" ? workspace : void 0
|
|
5496
|
+
});
|
|
5497
|
+
if (!result.ok) {
|
|
5498
|
+
setMsg("\u5B89\u88C5\u5931\u8D25\uFF1A" + describeError(result.error));
|
|
5499
|
+
return;
|
|
5500
|
+
}
|
|
5501
|
+
if (!result.value.ok) {
|
|
5502
|
+
setMsg("\u5B89\u88C5\u5931\u8D25\uFF1A" + (result.value.error ?? "\u672A\u77E5\u9519\u8BEF"));
|
|
5503
|
+
return;
|
|
5504
|
+
}
|
|
5505
|
+
setMsg(`\u5DF2\u5B89\u88C5 skill\u300C${result.value.name}\u300D\u2192 ${result.value.path}`);
|
|
5506
|
+
setInstalling(false);
|
|
5507
|
+
refresh();
|
|
5508
|
+
};
|
|
5456
5509
|
const loadSkill = (skillName, lvl) => {
|
|
5457
5510
|
setMsg("");
|
|
5458
5511
|
void remote.readSkill({ name: skillName, level: lvl, path: workspace }).then((r) => {
|
|
@@ -5524,7 +5577,7 @@ function SkillManager({ workspace, remote }) {
|
|
|
5524
5577
|
setConfirming(null);
|
|
5525
5578
|
refresh();
|
|
5526
5579
|
};
|
|
5527
|
-
const formOpen = editing !== null || creating;
|
|
5580
|
+
const formOpen = editing !== null || creating || installing;
|
|
5528
5581
|
const renderRow = (sk) => (0, import_react4.createElement)(
|
|
5529
5582
|
"div",
|
|
5530
5583
|
{
|
|
@@ -5614,6 +5667,53 @@ function SkillManager({ workspace, remote }) {
|
|
|
5614
5667
|
msg !== "" ? (0, import_react4.createElement)("p", { style: styles.status }, msg) : null
|
|
5615
5668
|
);
|
|
5616
5669
|
};
|
|
5670
|
+
const renderInstallForm = () => (0, import_react4.createElement)(
|
|
5671
|
+
ResourceModal,
|
|
5672
|
+
{
|
|
5673
|
+
title: "\u5B89\u88C5\u73B0\u6709 skill\uFF08\u76EE\u5F55\u578B\uFF09",
|
|
5674
|
+
description: "\u628A\u4E00\u4E2A\u672C\u673A\u5DF2\u6709\u7684 skill \u76EE\u5F55\uFF08\u542B SKILL.md\uFF0C\u53EF\u5E26 references / scripts \u7B49\u6587\u4EF6\uFF09\u5B89\u88C5\u5230\u9879\u76EE\u7EA7\u6216\u7528\u6237\u7EA7\u3002",
|
|
5675
|
+
onClose: () => {
|
|
5676
|
+
setInstalling(false);
|
|
5677
|
+
setMsg("");
|
|
5678
|
+
},
|
|
5679
|
+
footer: (0, import_react4.createElement)(
|
|
5680
|
+
"div",
|
|
5681
|
+
{ style: styles.row },
|
|
5682
|
+
(0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, {
|
|
5683
|
+
variant: "primary",
|
|
5684
|
+
size: "sm",
|
|
5685
|
+
disabled: installDir.trim() === "",
|
|
5686
|
+
onClick: () => {
|
|
5687
|
+
void submitInstall();
|
|
5688
|
+
}
|
|
5689
|
+
}, "\u5B89\u88C5"),
|
|
5690
|
+
(0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "ghost", size: "sm", onClick: () => {
|
|
5691
|
+
setInstalling(false);
|
|
5692
|
+
setMsg("");
|
|
5693
|
+
} }, "\u53D6\u6D88")
|
|
5694
|
+
)
|
|
5695
|
+
},
|
|
5696
|
+
(0, import_react4.createElement)(
|
|
5697
|
+
"div",
|
|
5698
|
+
{ style: styles.chips },
|
|
5699
|
+
(0, import_react4.createElement)(import_dsh_client_ui_primitives4.Pill, { active: installLevel === "project", onClick: () => {
|
|
5700
|
+
setInstallLevel("project");
|
|
5701
|
+
}, title: "\u88C5\u5230\u5DE5\u4F5C\u533A .dsh/skills\uFF0C\u56E2\u961F\u5171\u4EAB" }, "\u9879\u76EE\u7EA7"),
|
|
5702
|
+
(0, import_react4.createElement)(import_dsh_client_ui_primitives4.Pill, { active: installLevel === "user", onClick: () => {
|
|
5703
|
+
setInstallLevel("user");
|
|
5704
|
+
}, title: "\u88C5\u5230 $DSH_HOME/skills\uFF0C\u4E2A\u4EBA\u6240\u6709\u9879\u76EE\u53EF\u7528" }, "\u7528\u6237\u7EA7")
|
|
5705
|
+
),
|
|
5706
|
+
(0, import_react4.createElement)("input", {
|
|
5707
|
+
style: control,
|
|
5708
|
+
placeholder: "\u6E90\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u672C\u673A skill \u76EE\u5F55\uFF0C\u9700\u542B SKILL.md\uFF09",
|
|
5709
|
+
value: installDir,
|
|
5710
|
+
onChange: (ev) => {
|
|
5711
|
+
setInstallDir(ev.target.value);
|
|
5712
|
+
}
|
|
5713
|
+
}),
|
|
5714
|
+
(0, import_react4.createElement)("p", { style: styles.hint }, "\u8981\u6C42\uFF1A\u76EE\u5F55\u5185\u6709 SKILL.md\uFF08frontmatter \u542B name + description\uFF09\u3002\u5B89\u88C5\u4F1A\u590D\u5236\u6574\u4E2A\u76EE\u5F55\uFF08\u81EA\u52A8\u6392\u9664 node_modules / .git \u7B49\u7F13\u5B58\uFF09\uFF0C\u540C\u540D\u5185\u7F6E\u6280\u80FD\u62D2\u7EDD\u8986\u76D6\uFF0C\u540C\u540D\u5DF2\u88C5\u6280\u80FD\u9700\u5148\u5220\u9664\u3002"),
|
|
5715
|
+
msg !== "" ? (0, import_react4.createElement)("p", { style: styles.status }, msg) : null
|
|
5716
|
+
);
|
|
5617
5717
|
return (0, import_react4.createElement)(
|
|
5618
5718
|
"div",
|
|
5619
5719
|
{ style: styles.section },
|
|
@@ -5624,15 +5724,21 @@ function SkillManager({ workspace, remote }) {
|
|
|
5624
5724
|
"div",
|
|
5625
5725
|
{ style: styles.bindingStage },
|
|
5626
5726
|
(0, import_react4.createElement)("span", { style: styles.bindingLabel }, "\u5DF2\u5B89\u88C5\u7684 skill"),
|
|
5627
|
-
skills.length === 0 ? (0, import_react4.createElement)("p", { style: styles.muted }, "\u6682\u65E0 skill\uFF0C\u70B9\u4E0B\u65B9\u300C\u65B0\u5EFA skill\u300D\u521B\u5EFA\
|
|
5727
|
+
skills.length === 0 ? (0, import_react4.createElement)("p", { style: styles.muted }, "\u6682\u65E0 skill\uFF0C\u70B9\u4E0B\u65B9\u300C\u65B0\u5EFA skill\u300D\u521B\u5EFA\uFF0C\u6216\u300C\u5B89\u88C5 skill\u300D\u5BFC\u5165\u672C\u673A\u5DF2\u6709\u7684 skill \u76EE\u5F55\u3002") : (0, import_react4.createElement)(
|
|
5628
5728
|
"div",
|
|
5629
5729
|
{ style: styles.section },
|
|
5630
5730
|
...skills.map(renderRow)
|
|
5631
5731
|
)
|
|
5632
5732
|
),
|
|
5633
|
-
(0, import_react4.createElement)(
|
|
5733
|
+
(0, import_react4.createElement)(
|
|
5734
|
+
"div",
|
|
5735
|
+
{ style: styles.row },
|
|
5736
|
+
(0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", size: "md", onClick: startCreate }, "\u65B0\u5EFA skill"),
|
|
5737
|
+
(0, import_react4.createElement)(import_dsh_client_ui_primitives4.Button, { variant: "outline", size: "md", onClick: startInstall }, "\u5B89\u88C5 skill")
|
|
5738
|
+
)
|
|
5634
5739
|
),
|
|
5635
|
-
|
|
5740
|
+
installing ? renderInstallForm() : null,
|
|
5741
|
+
formOpen && !installing ? renderForm() : null
|
|
5636
5742
|
);
|
|
5637
5743
|
}
|
|
5638
5744
|
|