dsh-ronge-adaptive-skill-archive 5.0.4 → 5.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 CHANGED
@@ -31,7 +31,7 @@
31
31
  <sub>会话右侧的「技能」抽屉:推荐 / 组队计划 / 经验 / 安全与更新,都在一个面板里。</sub>
32
32
  </p>
33
33
 
34
- > **v5.0.4 发布说明**:本 README 是当前发布稿。三大新能力 `plan → compose → draft`(任务拆解 / 技能组队 / 按缺口造技能)与 12 领域包为本次发布新增;每条声明的证据、实测状态与未验证项统一记录在 **[docs/claims.md](docs/claims.md)**。benchmark 数字见 **[docs/benchmark.md](docs/benchmark.md)**(2026-10-30 快照)。
34
+ > **v5.2.0 发布说明**:本 README 是当前发布稿。三大新能力 `plan → compose → draft`(任务拆解 / 技能组队 / 按缺口造技能)与 12 领域包为本次发布新增;每条声明的证据、实测状态与未验证项统一记录在 **[docs/claims.md](docs/claims.md)**。benchmark 数字见 **[docs/benchmark.md](docs/benchmark.md)**(2026-10-30 快照)。
35
35
 
36
36
  ## 为什么需要 v5
37
37
 
@@ -59,8 +59,8 @@ v5 的驾驶舱把这条链路补全:
59
59
  npx dsh-ronge-adaptive-skill-archive
60
60
  # 想先体检:npx dsh-ronge-adaptive-skill-archive doctor
61
61
 
62
- # 2) 把打印出的这一行交给任意 DSH 会话里的 Agent 执行(v5.0.4 发布后可用)
63
- plugin_manager install_bundle target=dsh-ronge-adaptive-skill-archive@5.0.4
62
+ # 2) 把打印出的这一行交给任意 DSH 会话里的 Agent 执行(v5.2.0 发布后可用)
63
+ plugin_manager install_bundle target=dsh-ronge-adaptive-skill-archive@5.2.0
64
64
 
65
65
  # 3) 刷新页面 → 右上角「技能」→ 右侧抽屉;计划模式 / 沉浸模式切换
66
66
  ```
@@ -246,8 +246,8 @@ v5.0.0 在 DSH 里注册三个**只读 / 只出草稿**的工具(面板与 MCP
246
246
  | 方式 | 命令 | 适合 |
247
247
  |---|---|---|
248
248
  | **npx 助手** | `npx dsh-ronge-adaptive-skill-archive`(体检:`npx dsh-ronge-adaptive-skill-archive doctor`) | 第一次用;不装东西,只体检 + 打印安装命令 |
249
- | **npm** | `plugin_manager install_bundle target=dsh-ronge-adaptive-skill-archive@5.0.4` | v5.0.4 发布到 npm 后可用 |
250
- | **GitHub tag** | `plugin_manager install_bundle target=git+https://github.com/bugtakue/dsh-ronge-adaptive-skill-archive.git#v5.0.4` | 固定版本、可审源码 |
249
+ | **npm** | `plugin_manager install_bundle target=dsh-ronge-adaptive-skill-archive@5.2.0` | v5.2.0 发布到 npm 后可用 |
250
+ | **GitHub tag** | `plugin_manager install_bundle target=git+https://github.com/bugtakue/dsh-ronge-adaptive-skill-archive.git#v5.2.0` | 固定版本、可审源码 |
251
251
  | **本地目录** | `plugin_manager install_bundle target="/absolute/path/to/dsh-ronge-adaptive-skill-archive"` | 开发、改代码、离线 |
252
252
 
253
253
  > v5.0.0 打 tag / 发布 npm 之前,`@5.0.0` 会 404:请先用本地目录,或安装当时最新的已发布版本。安装后 DSH 需**重启**才会加载新的 Host 模块;浏览器刷新加载 Client。
@@ -356,7 +356,7 @@ MIT。见 [LICENSE](LICENSE)。索引中的技能元数据归原作者,边界
356
356
  **Install** (in a DSH session):
357
357
 
358
358
  ```bash
359
- plugin_manager install_bundle target=dsh-ronge-adaptive-skill-archive@5.0.4
359
+ plugin_manager install_bundle target=dsh-ronge-adaptive-skill-archive@5.2.0
360
360
  # then open any session → 「技能」 → switch Plan / Immersive
361
361
  ```
362
362
 
package/client.js CHANGED
@@ -271,6 +271,10 @@ window.__ModuleLoader__.load({
271
271
  intelStages: '阶段',
272
272
  intelInstalledCount: '已安装技能',
273
273
  intelReviewGap: '缺少独立复核技能:计划未假装复核',
274
+ intelPlanOptions: '方案',
275
+ intelPlanFast: '快速',
276
+ intelPlanBalanced: '均衡',
277
+ intelPlanQuality: '高质量',
274
278
  intelStage: '阶段',
275
279
  intelRole: '角色',
276
280
  intelSkills: '技能',
@@ -278,6 +282,7 @@ window.__ModuleLoader__.load({
278
282
  intelInput: '输入',
279
283
  intelOutput: '输出',
280
284
  intelHandoff: '交接物',
285
+ intelAcceptance: '验收标准',
281
286
  intelFallback: '失败备选',
282
287
  intelMissing: '缺失能力',
283
288
  intelDraftNeeded: '需生成草稿',
@@ -560,6 +565,10 @@ window.__ModuleLoader__.load({
560
565
  intelStages: 'Stages',
561
566
  intelInstalledCount: 'Installed skills',
562
567
  intelReviewGap: 'No independent reviewer: plan does not fake a review',
568
+ intelPlanOptions: 'Plans',
569
+ intelPlanFast: 'Fast',
570
+ intelPlanBalanced: 'Balanced',
571
+ intelPlanQuality: 'Quality',
563
572
  intelStage: 'Stage',
564
573
  intelRole: 'Role',
565
574
  intelSkills: 'Skills',
@@ -567,6 +576,7 @@ window.__ModuleLoader__.load({
567
576
  intelInput: 'Input',
568
577
  intelOutput: 'Output',
569
578
  intelHandoff: 'Handoff',
579
+ intelAcceptance: 'Acceptance',
570
580
  intelFallback: 'Fallback',
571
581
  intelMissing: 'Missing capabilities',
572
582
  intelDraftNeeded: 'Draft needed',
@@ -1567,6 +1577,7 @@ window.__ModuleLoader__.load({
1567
1577
  const [intelError, setIntelError] = React.useState(null)
1568
1578
  const [intelNotice, setIntelNotice] = React.useState(null)
1569
1579
  const [intelPlan, setIntelPlan] = React.useState(null)
1580
+ const [intelPlans, setIntelPlans] = React.useState([])
1570
1581
  const [intelDraft, setIntelDraft] = React.useState(null)
1571
1582
  const [intelDraftFrom, setIntelDraftFrom] = React.useState(null)
1572
1583
  const [intelCreatedPath, setIntelCreatedPath] = React.useState(null)
@@ -2227,6 +2238,7 @@ window.__ModuleLoader__.load({
2227
2238
  if (stage.output) lines.push(' ' + t('intelOutput') + ': ' + textValue(stage.output))
2228
2239
  if (stage.handoff) lines.push(' ' + t('intelHandoff') + ': ' + textValue(stage.handoff))
2229
2240
  if (stage.fallback) lines.push(' ' + t('intelFallback') + ': ' + textValue(stage.fallback))
2241
+ if (stage.acceptance) lines.push(' ' + t('intelAcceptance') + ': ' + textValue(stage.acceptance))
2230
2242
  })
2231
2243
  }
2232
2244
  const missing = Array.isArray(plan.missing) ? plan.missing.filter(Boolean) : []
@@ -2268,6 +2280,7 @@ window.__ModuleLoader__.load({
2268
2280
  if (intelBusy || (action !== 'plan' && action !== 'compose' && action !== 'draft')) return
2269
2281
  setIntelBusy(action)
2270
2282
  setIntelMode(action)
2283
+ setIntelPlans([])
2271
2284
  setIntelError(null)
2272
2285
  setIntelNotice(null)
2273
2286
  setIntelCreatedPath(null)
@@ -2280,7 +2293,8 @@ window.__ModuleLoader__.load({
2280
2293
  } else {
2281
2294
  if (currentMode && currentMode !== 'off') body.mode = currentMode
2282
2295
  if (data && data.cwd) body.cwd = String(data.cwd)
2283
- if (action === 'compose') body.maxSkills = 4
2296
+ if (state.sessionId) body.sessionId = String(state.sessionId)
2297
+ if (action === 'compose') body.maxSkills = 5
2284
2298
  }
2285
2299
  const response = await abortableFetch('/dsh-ronge-adaptive-skill-archive/intelligence/' + action, {
2286
2300
  method: 'POST',
@@ -2303,6 +2317,7 @@ window.__ModuleLoader__.load({
2303
2317
  setIntelError(t('intelEmpty'))
2304
2318
  } else {
2305
2319
  setIntelPlan(plan)
2320
+ setIntelPlans(Array.isArray(payload.plans) ? payload.plans.filter((item) => item && item.plan) : [])
2306
2321
  setIntelNotice({ kind: 'ok', text: t('intelPlanReady') })
2307
2322
  }
2308
2323
  }
@@ -2335,6 +2350,7 @@ window.__ModuleLoader__.load({
2335
2350
  name: String(intelDraft.name),
2336
2351
  description: String(intelDraft.description || ''),
2337
2352
  whenToUse: String(intelDraft.whenToUse || ''),
2353
+ content: typeof intelDraft.content === 'string' ? intelDraft.content : '',
2338
2354
  }),
2339
2355
  })
2340
2356
  const payload = await response.json().catch(() => ({}))
@@ -4104,6 +4120,25 @@ window.__ModuleLoader__.load({
4104
4120
  plan.reviewGap
4105
4121
  ? h('div', { className: 'sf-intel-note' }, t('intelReviewGap'))
4106
4122
  : null,
4123
+ intelPlans.length > 1
4124
+ ? h(
4125
+ 'div',
4126
+ { className: 'sf-intel-choices' },
4127
+ h('span', { className: 'sf-intel-k' }, t('intelPlanOptions')),
4128
+ intelPlans.map((choice) =>
4129
+ h(
4130
+ 'button',
4131
+ {
4132
+ type: 'button',
4133
+ key: 'choice-' + choice.id,
4134
+ className: 'sf-chip' + (choice.id === plan.variant ? ' sf-chip-active' : ''),
4135
+ onClick: () => setIntelPlan(choice.plan),
4136
+ },
4137
+ choice.id === 'fast' ? t('intelPlanFast') : choice.id === 'quality' ? t('intelPlanQuality') : t('intelPlanBalanced'),
4138
+ ),
4139
+ ),
4140
+ )
4141
+ : null,
4107
4142
  stages.length
4108
4143
  ? h(
4109
4144
  'ol',
@@ -4176,6 +4211,14 @@ window.__ModuleLoader__.load({
4176
4211
  h('span', null, textValue(stage.fallback)),
4177
4212
  )
4178
4213
  : null,
4214
+ stage.acceptance
4215
+ ? h(
4216
+ 'div',
4217
+ { className: 'sf-intel-line' },
4218
+ h('span', { className: 'sf-intel-k' }, t('intelAcceptance')),
4219
+ h('span', null, textValue(stage.acceptance)),
4220
+ )
4221
+ : null,
4179
4222
  ),
4180
4223
  ),
4181
4224
  )
@@ -7,10 +7,10 @@
7
7
 
8
8
  ```bash
9
9
  # npm(推荐)
10
- plugin_manager install_bundle target=dsh-ronge-adaptive-skill-archive@5.0.4
10
+ plugin_manager install_bundle target=dsh-ronge-adaptive-skill-archive@5.2.0
11
11
 
12
12
  # GitHub tag(固定版本、可审源码)
13
- plugin_manager install_bundle target=git+https://github.com/bugtakue/dsh-ronge-adaptive-skill-archive.git#v5.0.4
13
+ plugin_manager install_bundle target=git+https://github.com/bugtakue/dsh-ronge-adaptive-skill-archive.git#v5.2.0
14
14
 
15
15
  # 本地目录(开发)
16
16
  plugin_manager install_bundle target=/absolute/path/to/dsh-ronge-adaptive-skill-archive
@@ -42,7 +42,7 @@ plugin_manager install_bundle target=/absolute/path/to/dsh-ronge-adaptive-skill-
42
42
  - Host E2E:20/20(真实 loopback HTTP + raw.githubusercontent.com)
43
43
  - UI E2E:27/27
44
44
  - `npm run check:dsh`:manifest / factory id / slots / routes / 数据迁移 / market index 全部通过
45
- - npm registry 安装 v3.0.0 历史验证;v5.0.4 发布后以 registry 为准;市场索引 format 1 托管在 `https://bugtakue.github.io/dsh-ronge-adaptive-skill-archive/plugin-market.json`
45
+ - npm registry 安装 v3.0.0 历史验证;v5.2.0 发布后以 registry 为准;市场索引 format 1 托管在 `https://bugtakue.github.io/dsh-ronge-adaptive-skill-archive/plugin-market.json`
46
46
 
47
47
  ## 已知边界
48
48
 
package/index.js CHANGED
@@ -3184,18 +3184,31 @@ function createSkill(payload) {
3184
3184
  if (description.length > 500) throw new HttpError(400, 'description must be at most 500 characters')
3185
3185
  if (whenToUse.length > 500) throw new HttpError(400, 'whenToUse must be at most 500 characters')
3186
3186
 
3187
- const dir = path.join(dshHome(), 'skills', name)
3188
- const file = path.join(dir, 'SKILL.md')
3189
- if (fs.existsSync(dir)) throw new HttpError(409, `skill "${name}" already exists`)
3190
- fs.mkdirSync(dir, { recursive: true })
3191
- const frontmatter = [
3192
- '---',
3193
- `name: ${name}`,
3194
- `description: ${JSON.stringify(description)}`,
3195
- ]
3196
- if (whenToUse) frontmatter.push(`whenToUse: ${JSON.stringify(whenToUse)}`)
3197
- frontmatter.push('---', '')
3198
- const body = `${frontmatter.join('\n')}
3187
+ const suppliedContent = typeof payload?.content === 'string' ? payload.content.trim() : ''
3188
+ let content = ''
3189
+ let security = null
3190
+ if (suppliedContent) {
3191
+ if (Buffer.byteLength(suppliedContent) > 128 * 1024) throw new HttpError(413, 'generated SKILL.md is too large')
3192
+ const front = parseFrontmatter(suppliedContent)
3193
+ if (!suppliedContent.startsWith('---') || !front || typeof front !== 'object') {
3194
+ throw new HttpError(400, 'content must start with SKILL.md frontmatter')
3195
+ }
3196
+ if (String(front.name || '') !== name) throw new HttpError(400, 'content frontmatter name must match name')
3197
+ if (!String(front.description || '').trim()) throw new HttpError(400, 'content frontmatter description is required')
3198
+ security = scanSkillText(suppliedContent)
3199
+ if (security.level === 'high') {
3200
+ throw new HttpError(422, 'high-risk generated SKILL.md blocked: ' + security.findings.map((finding) => finding.rule).join(', '))
3201
+ }
3202
+ content = suppliedContent.endsWith('\n') ? suppliedContent : suppliedContent + '\n'
3203
+ } else {
3204
+ const frontmatter = [
3205
+ '---',
3206
+ `name: ${name}`,
3207
+ `description: ${JSON.stringify(description)}`,
3208
+ ]
3209
+ if (whenToUse) frontmatter.push(`whenToUse: ${JSON.stringify(whenToUse)}`)
3210
+ frontmatter.push('---', '')
3211
+ content = `${frontmatter.join('\n')}
3199
3212
  # ${name}
3200
3213
 
3201
3214
  ## When to use
@@ -3208,10 +3221,18 @@ ${whenToUse || description}
3208
3221
  2. Follow the instructions in this file.
3209
3222
  3. Report the result with concrete evidence.
3210
3223
  `
3211
- atomicWriteFile(file, body, { mode: 0o644 })
3212
- return { ok: true, name, path: file }
3224
+ }
3225
+
3226
+ const dir = path.join(dshHome(), 'skills', name)
3227
+ const file = path.join(dir, 'SKILL.md')
3228
+ if (fs.existsSync(dir)) throw new HttpError(409, `skill "${name}" already exists`)
3229
+ fs.mkdirSync(dir, { recursive: true, mode: 0o755 })
3230
+ atomicWriteFile(file, content, { mode: 0o644 })
3231
+ appendAudit('create', { name, sha256: sha256(content), source: suppliedContent ? 'generated-draft' : 'template' })
3232
+ return { ok: true, name, path: file, bytes: Buffer.byteLength(content), generated: Boolean(suppliedContent), security }
3213
3233
  }
3214
3234
 
3235
+
3215
3236
  let intelligenceModule = null
3216
3237
  let capabilityIndexCache = null
3217
3238
 
@@ -3254,8 +3275,6 @@ async function resolveInstalledSkills(ctx, cwd) {
3254
3275
  } catch {
3255
3276
  registry = []
3256
3277
  }
3257
- // The registry can be agent-scoped/partial; the filesystem scan is what makes
3258
- // the panel complete. Merge both, with registry entries taking precedence.
3259
3278
  const merged = new Map()
3260
3279
  for (const skill of scanSkills(cwd)) {
3261
3280
  if (skill && skill.name) merged.set(skill.name, { ...skill, source: skill.source || 'scan' })
@@ -3286,6 +3305,54 @@ async function resolveInstalledSkills(ctx, cwd) {
3286
3305
  return { skills, source, count: skills.length }
3287
3306
  }
3288
3307
 
3308
+ function planRequestCwd(ctx, payload) {
3309
+ if (payload && payload.cwd) return String(payload.cwd)
3310
+ if (payload && payload.sessionId) {
3311
+ try {
3312
+ const header = ctx.get('agents')?.get?.(payload.sessionId)?.header
3313
+ if (header && header.cwd) return String(header.cwd)
3314
+ } catch {}
3315
+ }
3316
+ return process.cwd()
3317
+ }
3318
+
3319
+ function planRequestContext(cwd) {
3320
+ try {
3321
+ const files = fs
3322
+ .readdirSync(cwd, { withFileTypes: true })
3323
+ .filter((entry) => !entry.name.startsWith('.') && entry.isFile())
3324
+ .slice(0, 20)
3325
+ .map((entry) => entry.name)
3326
+ return files.length ? 'workspace files: ' + files.join(', ') : ''
3327
+ } catch {
3328
+ return ''
3329
+ }
3330
+ }
3331
+
3332
+ function buildPlanAlternatives(intel, base) {
3333
+ const configs = [
3334
+ { id: 'fast', label: 'fast', maxSkills: 3 },
3335
+ { id: 'balanced', label: 'balanced', maxSkills: 4 },
3336
+ { id: 'quality', label: 'quality', maxSkills: 5 },
3337
+ ]
3338
+ const plans = configs.map((config) => {
3339
+ const plan = intel.composeSkillPlan({ ...base, maxSkills: config.maxSkills })
3340
+ plan.variant = config.id
3341
+ return { id: config.id, label: config.label, maxSkills: config.maxSkills, plan }
3342
+ })
3343
+ const bySignature = new Map()
3344
+ for (const choice of plans) {
3345
+ const signature = JSON.stringify({
3346
+ pattern: choice.plan.pattern,
3347
+ stages: choice.plan.stages.map((stage) => (stage.skills || []).map((skill) => skill.name)),
3348
+ missing: choice.plan.missing.map((item) => item.capability),
3349
+ })
3350
+ if (!bySignature.has(signature)) bySignature.set(signature, choice)
3351
+ }
3352
+ const unique = [...bySignature.values()]
3353
+ const selected = unique.find((choice) => choice.id === 'balanced') || unique[0]
3354
+ return { plans: unique, plan: selected.plan, selectedPlan: selected.id }
3355
+ }
3289
3356
 
3290
3357
  function registerIntelligenceTools(ctx) {
3291
3358
  const tools = ctx.get ? ctx.get('tools') : ctx.tools
@@ -3318,9 +3385,10 @@ function registerIntelligenceTools(ctx) {
3318
3385
  installedSkills: resolved.skills,
3319
3386
  libraryEntries: loadLibraryIndex().entries || [],
3320
3387
  capabilityIndex: loadCapabilityIndex(),
3388
+ context: planRequestContext(cwd),
3321
3389
  maxSkills: 5,
3322
3390
  })
3323
- plan.diagnostics = { installedCount: resolved.count, installedSource: resolved.source }
3391
+ plan.diagnostics = { installedCount: resolved.count, installedSource: resolved.source, cwd }
3324
3392
  return { ok: true, plan: { ...plan, stages: plan?.stages?.slice(0, 4) } }
3325
3393
  },
3326
3394
  }),
@@ -3352,9 +3420,10 @@ function registerIntelligenceTools(ctx) {
3352
3420
  installedSkills: resolved.skills,
3353
3421
  libraryEntries: loadLibraryIndex().entries || [],
3354
3422
  capabilityIndex: loadCapabilityIndex(),
3423
+ context: planRequestContext(cwd),
3355
3424
  maxSkills: Number(args?.maxSkills) || 5,
3356
3425
  }),
3357
- diagnostics: { installedCount: resolved.count, installedSource: resolved.source },
3426
+ diagnostics: { installedCount: resolved.count, installedSource: resolved.source, cwd },
3358
3427
  }
3359
3428
  },
3360
3429
  }),
@@ -3737,9 +3806,9 @@ export function apply(ctx, config = {}) {
3737
3806
  const task = String(payload?.task || '').trim()
3738
3807
  if (!task) throw new HttpError(400, 'task is required')
3739
3808
  const intel = await loadIntelligence()
3740
- const cwd = String(payload?.cwd || config?.cwd || process.cwd())
3809
+ const cwd = planRequestCwd(ctx, payload)
3741
3810
  const resolved = await resolveInstalledSkills(ctx, cwd)
3742
- const diagnostics = { installedCount: resolved.count, installedSource: resolved.source }
3811
+ const diagnostics = { installedCount: resolved.count, installedSource: resolved.source, cwd }
3743
3812
  if (action === 'draft') {
3744
3813
  const draft = intel.draftSkill({
3745
3814
  task,
@@ -3749,18 +3818,18 @@ export function apply(ctx, config = {}) {
3749
3818
  sendJson(res, 200, { ok: true, diagnostics, draft })
3750
3819
  return
3751
3820
  }
3752
- const plan = intel.composeSkillPlan({
3821
+ const base = {
3753
3822
  task,
3754
3823
  cwd,
3755
- context: String(payload?.context || ''),
3824
+ context: String(payload?.context || planRequestContext(cwd)),
3756
3825
  mode: String(payload?.mode || ''),
3757
3826
  installedSkills: resolved.skills,
3758
3827
  libraryEntries: loadLibraryIndex().entries || [],
3759
3828
  capabilityIndex: loadCapabilityIndex(),
3760
- maxSkills: Number(payload?.maxSkills) || (action === 'plan' ? 5 : 5),
3761
- })
3762
- plan.diagnostics = diagnostics
3763
- sendJson(res, 200, { ok: true, diagnostics, plan })
3829
+ }
3830
+ const choices = buildPlanAlternatives(intel, base)
3831
+ choices.plan.diagnostics = diagnostics
3832
+ sendJson(res, 200, { ok: true, diagnostics, plans: choices.plans, selectedPlan: choices.selectedPlan, plan: choices.plan })
3764
3833
  }),
3765
3834
  }),
3766
3835
  )
@@ -81,6 +81,30 @@ const INTENT_INPUT = {
81
81
  general: '任务上下文',
82
82
  }
83
83
 
84
+ const INTENT_ACCEPTANCE = {
85
+ 'contract-review': '条款逐条核对完成;金额/日期/主体无遗漏;风险项有出处。',
86
+ 'document-create': '文档结构完整;关键信息齐全;格式符合要求。',
87
+ 'document-edit': '修改点有对照;原文未误删;差异可回滚。',
88
+ 'document-convert': '目标格式可打开;内容无丢失;版式检查通过。',
89
+ 'layout-review': '版式问题有截图/位置;修复建议可执行。',
90
+ 'video-create': '成片时长/画幅正确;字幕与音频同步;关键镜头完整。',
91
+ 'video-edit': '剪辑点符合要求;无黑帧/爆音;输出可播放。',
92
+ 'data-analysis': '口径明确;数字可复算;图表与结论一致。',
93
+ research: '关键结论有来源;不确定项标注;覆盖范围说明。',
94
+ marketing: '目标受众/渠道明确;文案可发布;事实与合规检查。',
95
+ design: '交付物符合品牌/尺寸;图层/资源可编辑;导出检查。',
96
+ 'software-build': '测试通过;关键路径可运行;变更说明完整。',
97
+ 'plugin-development': '插件可安装/启用;slot/工具验证;可卸载回滚。',
98
+ 'security-review': '风险有复现/证据;修复建议可执行;残余风险标注。',
99
+ teaching: '目标/练习匹配;示例可复现;难点有解释。',
100
+ 'business-plan': '假设与数据来源明确;测算可复核;风险与备选方案。',
101
+ planning: '任务有负责人/依赖/验收;关键路径明确。',
102
+ automation: '流程可重跑;失败可恢复;输出可验证。',
103
+ 'meeting-notes': '决议/行动项/负责人齐全;原文可追溯。',
104
+ 'ai-build': '工具/提示词可复现;有评测与失败处理;权限边界明确。',
105
+ general: '交付物可验收;不确定项已标注。',
106
+ }
107
+
84
108
  const ALLOWED_PATTERNS = new Set(PATTERNS)
85
109
 
86
110
  function capabilityDomain(capabilityId) {
@@ -439,6 +463,7 @@ function assignSkillsToStages({ selected, decomposition, covered, required, patt
439
463
  ? '与其它阶段独立,可并行执行;汇总后统一交付'
440
464
  : '上一阶段完成后进入下一阶段',
441
465
  fallback: '若无可用技能:先起草技能或人工完成',
466
+ acceptance: INTENT_ACCEPTANCE[intentId] || INTENT_ACCEPTANCE.general,
442
467
  })
443
468
  }
444
469
 
@@ -455,6 +480,7 @@ function assignSkillsToStages({ selected, decomposition, covered, required, patt
455
480
  output: INTENT_OUTPUT[decomposition.primaryIntent] || INTENT_OUTPUT.general,
456
481
  handoff: '输出任务结果(意图与技能未完全对齐,执行前建议确认)',
457
482
  fallback: '若无可用技能:缩小范围或人工完成',
483
+ acceptance: INTENT_ACCEPTANCE[decomposition.primaryIntent] || INTENT_ACCEPTANCE.general,
458
484
  })
459
485
  for (const candidate of selected) assigned.add(candidate.name)
460
486
  }
@@ -545,6 +571,7 @@ function buildReviewStage({ selected, decomposition, pattern, usedNames = new Se
545
571
  output: INTENT_OUTPUT[decomposition.primaryIntent] || '复核意见',
546
572
  handoff: reviewSkills.length ? '复核通过后交付;不通过则回退上一步' : '由用户/Agent 人工复核后交付;不通过则回退上一步',
547
573
  fallback: '无法复核时:先交付草稿并明确标注未复核项',
574
+ acceptance: '复核项逐条通过;未通过项有回退/修正记录。',
548
575
  gate: true,
549
576
  }
550
577
  }
@@ -637,6 +664,7 @@ export function composeSkillPlan(input = {}) {
637
664
  output: '待确认的能力缺口与补位方案',
638
665
  handoff: '用户确认/安装缺失技能后再执行',
639
666
  fallback: '缩小任务范围或改为纯人工流程',
667
+ acceptance: '缺口清单明确;用户确认安装/取舍后再进入执行。',
640
668
  gate: true,
641
669
  },
642
670
  ])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-ronge-adaptive-skill-archive",
3
- "version": "5.0.4",
3
+ "version": "5.2.0",
4
4
  "description": "DSH-native skill intelligence cockpit: task decomposition, cross-domain multi-skill composition, skill authoring, local recommendations and safety scans for DeepSeek Harness.",
5
5
  "type": "module",
6
6
  "repository": {