dsh-plugin-prompt-tool 2.0.1 → 3.0.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.
Files changed (231) hide show
  1. package/README.md +100 -233
  2. package/engine/actions/append-context.mjs +3 -24
  3. package/engine/actions/assembly.mjs +70 -94
  4. package/engine/actions/catalog.mjs +65 -28
  5. package/engine/actions/content.mjs +8 -152
  6. package/engine/actions/examples.mjs +8 -4
  7. package/engine/actions/inbox-prepend.mjs +5 -7
  8. package/engine/actions/index.mjs +17 -9
  9. package/engine/actions/inject-text.mjs +24 -4
  10. package/engine/actions/pre-step-filter.mjs +3 -4
  11. package/engine/actions/registration.mjs +20 -28
  12. package/engine/actions/request-params.mjs +21 -1
  13. package/engine/actions/shared.mjs +23 -15
  14. package/engine/actions/stream-output.mjs +26 -0
  15. package/engine/actions/tool-gate.mjs +31 -0
  16. package/engine/actions/tool-result.mjs +36 -0
  17. package/engine/actions/tool-visibility.mjs +248 -0
  18. package/engine/agent-capability.mjs +67 -0
  19. package/engine/anchor-match.mjs +14 -21
  20. package/engine/audience.d.mts +2 -0
  21. package/engine/audience.mjs +102 -0
  22. package/engine/branch.d.mts +4 -0
  23. package/engine/branch.mjs +62 -19
  24. package/engine/compaction-epoch.d.mts +25 -0
  25. package/engine/compaction-epoch.mjs +27 -4
  26. package/engine/compositions/source/local/filesystem-editor.yml +3 -3
  27. package/engine/compositions/source/local/instruction-hint.yml +4 -7
  28. package/engine/compositions/source/local/module-file-tools.yml +2 -0
  29. package/engine/compositions/source/local/module-import-tools.yml +4 -0
  30. package/engine/compositions/source/local/module-manifest-tools.yml +2 -0
  31. package/engine/compositions/source/local/module-rule-tools.yml +5 -0
  32. package/engine/compositions/source/local/module-variable-tools.yml +5 -0
  33. package/engine/compositions/source/local/present-as.yml +26 -0
  34. package/engine/compositions/source/local/tool-config-engine.yml +2 -3
  35. package/engine/compositions/source/local/tool-search.yml +11 -0
  36. package/engine/condition-facts.mjs +84 -0
  37. package/engine/conditions/anchor.mjs +63 -23
  38. package/engine/conditions/availability.mjs +1 -1
  39. package/engine/conditions/composite.mjs +4 -4
  40. package/engine/conditions/count.mjs +43 -13
  41. package/engine/conditions/evaluation.mjs +74 -19
  42. package/engine/conditions/examples.mjs +2 -1
  43. package/engine/conditions/index.d.mts +15 -0
  44. package/engine/conditions/index.mjs +23 -9
  45. package/engine/conditions/operators.mjs +4 -0
  46. package/engine/conditions/phase.mjs +10 -5
  47. package/engine/conditions/preset.mjs +1 -1
  48. package/engine/conditions/session.mjs +8 -2
  49. package/engine/conditions/subject.mjs +144 -65
  50. package/engine/conditions/text.mjs +26 -8
  51. package/engine/conditions/variable.mjs +83 -0
  52. package/engine/context-activation.d.mts +11 -0
  53. package/engine/{st-world-book.mjs → context-activation.mjs} +104 -64
  54. package/engine/delivery.d.mts +2 -0
  55. package/engine/delivery.mjs +93 -0
  56. package/engine/discovery.d.mts +38 -0
  57. package/engine/discovery.mjs +146 -0
  58. package/engine/env-safety.mjs +14 -0
  59. package/engine/executor.d.mts +28 -0
  60. package/engine/executor.mjs +290 -205
  61. package/engine/fillers.mjs +39 -8
  62. package/engine/fixed-registration.mjs +12 -0
  63. package/engine/history.mjs +71 -0
  64. package/engine/instruction-blocks.d.mts +13 -0
  65. package/engine/instruction-blocks.mjs +21 -0
  66. package/engine/instruction-files.d.mts +5 -0
  67. package/engine/instruction-files.mjs +97 -0
  68. package/engine/instruction-hint.mjs +69 -103
  69. package/engine/interpolate.d.mts +7 -0
  70. package/engine/interpolate.mjs +44 -13
  71. package/engine/layers.mjs +165 -230
  72. package/engine/machine-paths.mjs +40 -0
  73. package/engine/module-file-tools.mjs +8 -0
  74. package/engine/module-import-tools.mjs +10 -0
  75. package/engine/module-manifest-tools.mjs +8 -0
  76. package/engine/module-rule-tools.mjs +10 -0
  77. package/engine/module-variable-tools.mjs +10 -0
  78. package/engine/order.d.mts +14 -0
  79. package/engine/order.mjs +0 -3
  80. package/engine/path-safety.d.mts +2 -0
  81. package/engine/path-safety.mjs +58 -0
  82. package/engine/pre-step-source.d.mts +69 -0
  83. package/engine/pre-step-source.mjs +103 -0
  84. package/engine/present-as.mjs +77 -0
  85. package/engine/promotion-pool.d.mts +9 -0
  86. package/engine/promotion-pool.mjs +69 -0
  87. package/engine/record.mjs +2 -0
  88. package/engine/rule-engine.mjs +3 -2
  89. package/engine/rule-facts.d.mts +11 -0
  90. package/engine/rule-facts.mjs +60 -0
  91. package/engine/rule-runtime.d.mts +46 -0
  92. package/engine/rule-runtime.mjs +98 -13
  93. package/engine/rule-spec.d.mts +106 -0
  94. package/engine/rule-spec.mjs +302 -28
  95. package/engine/run-code-env.mjs +73 -19
  96. package/engine/schema.mjs +165 -243
  97. package/engine/sdk-strip.mjs +2 -2
  98. package/engine/service-names.d.mts +10 -0
  99. package/engine/service-names.mjs +10 -0
  100. package/engine/shared.d.mts +21 -0
  101. package/engine/shared.mjs +47 -26
  102. package/engine/skill-search.mjs +125 -53
  103. package/engine/source-kind.d.mts +9 -0
  104. package/engine/source-kind.mjs +16 -0
  105. package/engine/strategy-ids.mjs +5 -0
  106. package/engine/template-evaluation.d.mts +16 -0
  107. package/engine/template-evaluation.mjs +178 -0
  108. package/engine/template-frame.d.mts +16 -0
  109. package/engine/template-frame.mjs +69 -0
  110. package/engine/tool-config-engine.mjs +39 -35
  111. package/engine/tool-definition.d.mts +4 -0
  112. package/engine/tool-definition.mjs +5 -1
  113. package/engine/tool-git-bash.mjs +5 -1
  114. package/engine/tool-scope.mjs +22 -0
  115. package/engine/{dev-tool-search.mjs → tool-search.mjs} +63 -65
  116. package/engine/trigger.mjs +15 -270
  117. package/engine/vendor/yaml/dist/compose/resolve-flow-scalar.js +19 -18
  118. package/engine/vendor/yaml/dist/nodes/Alias.js +25 -23
  119. package/engine/vendor/yaml/package.json +1 -1
  120. package/lib/client.js +8312 -6724
  121. package/lib/client.js.map +1 -1
  122. package/lib/index.d.mts +37 -762
  123. package/lib/index.mjs +26919 -5791
  124. package/modules/ponytail/module.yml +83 -203
  125. package/modules/ptc-mode/module.yml +45 -0
  126. package/modules/soul/assets/core-hard.md +6 -0
  127. package/modules/soul/assets/criteria.md +12 -0
  128. package/modules/soul/assets/echo.md +12 -0
  129. package/modules/soul/assets/layers.md +11 -0
  130. package/modules/soul/assets/ledger.md +9 -0
  131. package/modules/soul/assets/manifest.yml +20 -0
  132. package/modules/soul/assets/reference/00-layers.md +27 -0
  133. package/modules/soul/assets/reference/01-criteria.md +32 -0
  134. package/modules/soul/assets/reference/02-echo.md +158 -0
  135. package/modules/soul/assets/reference/03-vital.md +183 -0
  136. package/modules/soul/assets/reference/04-manifest.json +106 -0
  137. package/modules/soul/assets/reference/05-doctor.md +67 -0
  138. package/modules/soul/assets/reference/06-reference.md +189 -0
  139. package/modules/soul/assets/reference/07-bundle.json +431 -0
  140. package/modules/soul/assets/reference/08-/350/270/251/345/235/221/345/256/236/345/275/225.md +59 -0
  141. package/modules/soul/assets/reference/09-dev-workflow.md +109 -0
  142. package/modules/soul/assets/reference/10-echo-anatomy.md +100 -0
  143. package/modules/soul/assets/reference/11-self.md +80 -0
  144. package/modules/soul/assets/reference/12-ledger.md +159 -0
  145. package/modules/soul/assets/reference/README.md +10 -0
  146. package/modules/soul/assets/templates/agents-template.md +6 -0
  147. package/modules/soul/assets/vital.md +9 -0
  148. package/modules/soul/module.yml +311 -0
  149. package/modules/superpowers/module.yml +122 -0
  150. package/modules/tool-surface/module.yml +51 -47
  151. package/package.json +40 -41
  152. package/skills/dsh-module/SKILL.md +119 -0
  153. package/skills/dsh-module/reference.md +185 -0
  154. package/templates/10-pre-step.yml +2 -3
  155. package/templates/14-first-turn-anchor.yml +10 -14
  156. package/templates/15-guide-auto.yml +32 -28
  157. package/templates/16-custom-fallback.yml +33 -21
  158. package/templates/20-system-section.yml +1 -4
  159. package/templates/50-llm-stream.yml +4 -10
  160. package/templates/60-tool-pipeline.yml +12 -10
  161. package/templates/63-append-context.yml +20 -0
  162. package/templates/64-pre-step-filter.yml +23 -0
  163. package/templates/65-turn-stop.yml +2 -2
  164. package/templates/67-inbox-prepend.yml +22 -0
  165. package/templates/70-subagent-maintenance.yml +9 -10
  166. package/templates/75-subagent-end.yml +2 -2
  167. package/templates/80-tool-surface.yml +41 -57
  168. package/templates/tools/40-delegate-module-import.yml +22 -0
  169. package/templates/tools/50-delegate-module-rules.yml +14 -0
  170. package/templates/tools/60-delegate-module-variables.yml +17 -0
  171. package/templates/tools/70-delegate-module-rules-edit.yml +31 -0
  172. package/engine/actions/decision.mjs +0 -54
  173. package/engine/actions/guard.mjs +0 -80
  174. package/engine/actions/sdk-strip.mjs +0 -30
  175. package/engine/character-tools.mjs +0 -8
  176. package/engine/classify-task.mjs +0 -53
  177. package/engine/compositions/library/agent-instructions.yml +0 -9
  178. package/engine/compositions/library/command-goal.yml +0 -7
  179. package/engine/compositions/library/compaction.yml +0 -22
  180. package/engine/compositions/library/delegation-ptc.yml +0 -58
  181. package/engine/compositions/library/delegation.yml +0 -56
  182. package/engine/compositions/library/persistent-shell.yml +0 -50
  183. package/engine/compositions/library/planning.yml +0 -26
  184. package/engine/compositions/library/skill-filesystem-cordis.yml +0 -10
  185. package/engine/compositions/library/skill-filesystem.yml +0 -7
  186. package/engine/compositions/library/tool-ask-user.yml +0 -7
  187. package/engine/compositions/library/tool-bash.yml +0 -8
  188. package/engine/compositions/library/tool-cordis.yml +0 -7
  189. package/engine/compositions/library/tool-fs-search.yml +0 -9
  190. package/engine/compositions/library/tool-fs.yml +0 -7
  191. package/engine/compositions/library/tool-goal.yml +0 -7
  192. package/engine/compositions/library/tool-jobs.yml +0 -7
  193. package/engine/compositions/library/tool-plugin-manager-disabled.yml +0 -8
  194. package/engine/compositions/library/tool-plugin-manager.yml +0 -8
  195. package/engine/compositions/library/tool-present.yml +0 -7
  196. package/engine/compositions/library/tool-presentation.yml +0 -9
  197. package/engine/compositions/library/tool-pwsh.yml +0 -8
  198. package/engine/compositions/library/tool-skill.yml +0 -7
  199. package/engine/compositions/library/tool-todo.yml +0 -9
  200. package/engine/compositions/library/tool-web.yml +0 -10
  201. package/engine/compositions/source/local/character-tools.yml +0 -5
  202. package/engine/compositions/source/local/declared-triggers.yml +0 -12
  203. package/engine/compositions/source/local/dev-tool-search.yml +0 -11
  204. package/engine/compositions/source/local/session-var-tools.yml +0 -5
  205. package/engine/compositions/source/local/subagent-tool-policy.yml +0 -21
  206. package/engine/compositions/source/local/world-book-tools.yml +0 -5
  207. package/engine/condition.mjs +0 -96
  208. package/engine/declared-triggers.mjs +0 -93
  209. package/engine/session-var-tools.mjs +0 -8
  210. package/engine/session-vars.mjs +0 -54
  211. package/engine/st-macros.d.mts +0 -22
  212. package/engine/st-macros.mjs +0 -208
  213. package/engine/st-render.mjs +0 -109
  214. package/engine/st-world-book.d.mts +0 -10
  215. package/engine/subagent-tool-policy-core.mjs +0 -400
  216. package/engine/subagent-tool-policy.mjs +0 -352
  217. package/engine/trigger-spec.mjs +0 -173
  218. package/engine/world-book-tools.mjs +0 -8
  219. package/lib/migrate-rules.d.mts +0 -1
  220. package/lib/migrate-rules.mjs +0 -39
  221. package/lib/module-package-CHPFweqK.mjs +0 -2
  222. package/lib/module-package-Cnd1_mwx.mjs +0 -2872
  223. package/lib/paths-CyP0IkaM.d.mts +0 -1390
  224. package/lib/preset-transfer.d.mts +0 -2
  225. package/lib/preset-transfer.mjs +0 -3
  226. package/lib/rules-migration-DJ6vASB5.mjs +0 -15334
  227. package/templates/policies/legacy-defaults.yml +0 -34
  228. package/templates/tools/40-delegate-character.yml +0 -15
  229. package/templates/tools/50-delegate-worldbook.yml +0 -15
  230. package/templates/tools/60-delegate-session-var.yml +0 -15
  231. package/templates/tools/70-delegate-worldbook-upsert.yml +0 -36
@@ -1,22 +1,64 @@
1
1
  import { prepareAction } from './actions/index.mjs'
2
2
  import { applyPromptConfigSources } from './executor.mjs'
3
+ import { createPreStepSource, moduleSourceId } from './pre-step-source.mjs'
3
4
  import { wireLayers } from './layers.mjs'
5
+ import { rebindConditions, validateDeliverySources } from './rule-spec.mjs'
4
6
  import { wireTriggerObservers } from './trigger.mjs'
5
7
  import { ruleFrame, actionMatches } from './conditions/evaluation.mjs'
6
- import { createWarnOnce } from './shared.mjs'
8
+ import { createPromotionPool } from './promotion-pool.mjs'
9
+ import { PROMOTE_EVENTS, createWarnOnce, getService } from './shared.mjs'
10
+ import { PRE_STEP_COORDINATOR_SERVICE } from './service-names.mjs'
7
11
 
8
12
  const noNext = new Set(['agent/inbox/inserted', 'agent/turn-stopping', 'subagent/start', 'subagent/end'])
13
+ // 判据与 `order.mjs#compareConfigSequence` 有意不同:这里在同通道同点内按 moduleId 字母序 +
14
+ // 规则声明序(ruleIndex)定位,`compareConfigSequence` 按 `sequence`(= 编辑器顺序,缺省回退
15
+ // `order`)+ `ruleId` 排。收敛到 `ruleId` 会打断现网依赖的「编辑器顺序 = 执行顺序」,别顺手统一。
9
16
  const compare = (a, b) => a.action.channelOrder - b.action.channelOrder
10
17
  || a.moduleId.localeCompare(b.moduleId) || a.ruleIndex - b.ruleIndex || a.action.actionIndex - b.action.actionIndex
11
18
 
12
- /** 所有来源只进入这个装配入口;注入保留原有批处理和协调器所有权。 */
19
+ /** 所有来源只进入这个装配入口;受众限定固定效果要求 ctx 属于 options.agent 的 scope。 */
13
20
  export function mountRuleSources(ctx, sources, options = {}) {
21
+ validateDeliverySources(sources)
22
+ // 晋升相位池先建:条件的挂载期绑定要用它(`phase` 的订阅模式从池取实例,见 promotion-pool.mjs)。
23
+ // 池自己订阅 `session/event` 并统一喂事件;自建的随本挂载释放,注入的由创建者释放。
24
+ const coordinator = (() => {
25
+ const service = getService(ctx, PRE_STEP_COORDINATOR_SERVICE)
26
+ return service !== null && typeof service === 'object' && typeof service.registerPreset === 'function'
27
+ ? service
28
+ : undefined
29
+ })()
30
+ const pool = options.promotionPool ?? coordinator?.promotionPool ?? createPromotionPool(ctx)
31
+ const ownsPool = options.promotionPool === undefined && coordinator?.promotionPool === undefined
32
+ // 条件绑定**在这里**发生:`compileRules` 编译期没有挂载 scope 的 ctx(preset 条件在那边恒
33
+ // UNAVAILABLE 且静默)。必须早于事件订阅与动作注册——动作级 `actionWhen.observe` 是订阅通道,
34
+ // 绑晚了那一类谓词会漏事件。`standingMountFor` 是可选兜底(官方包缺席=没有兜底,不是错误)。
35
+ rebindConditions(sources, { ctx, standingMountFor: options.standingMountFor, promotionPool: pool, variableStore: options.variableStore })
14
36
  const warnOnce = options.warnOnce ?? createWarnOnce(ctx, options.plugin ?? 'rule-engine')
37
+ // 非 pre-step 动作仍共享一次 ruleFrame;规则实例没有来源字段(RuleDefinition 不暴露 moduleId),
38
+ // 因此保留一份局部 rule→module 映射。它不是 pre-step 来源事实的重建,不参与 pre-step 的 source sink。
39
+ const report = options.onOutcome === undefined ? undefined : (() => {
40
+ const moduleOfRule = new Map()
41
+ for (const source of sources) for (const rule of source.rules) if (!moduleOfRule.has(rule)) moduleOfRule.set(rule, source.moduleId)
42
+ return (rule, channel, outcome) => options.onOutcome({ moduleId: moduleOfRule.get(rule), ruleId: rule.id, channel, outcome })
43
+ })()
15
44
  const releases = []
45
+ // 自建池随本挂载释放;协调器/调用方注入的池由创建者释放(生命周期随归属,不跨界代管)。
46
+ if (ownsPool) releases.push(() => pool.dispose())
16
47
  const points = new Map()
17
- const injections = new Map(sources.map(source => [source.moduleId, { sourceId: `module:${source.moduleId}`, configs: [], ruleActions: [], officialInstructions: source.officialInstructions === true }]))
48
+ // 续跑预算按来源模块一份:同模块的 turn-stop 动作共享上限,
49
+ // 不再按动作各建一份。本 mount 可能含多个模块(agent-assembly 一次装载全部启用模块),
50
+ // 因此按 moduleId 分档;来源 id 缺失时落空串兜底键(与 wireTurnStops 同源)。
51
+ const turnStopBudgets = new Map()
52
+ const injections = new Map(sources.map(source => [source.moduleId, { moduleId: source.moduleId, sourceId: moduleSourceId(source.moduleId), configs: [], ruleActions: [] }]))
18
53
  const rules = sources.flatMap(source => source.rules.filter(rule => rule.enabled !== false))
19
- const observer = wireTriggerObservers(ctx, rules, { plugin: options.plugin ?? 'rule-engine', warnOnce })
54
+ // 动作级分支条件(actionWhen)也要喂 session/event:否则 else / 嵌套 if 里的 phase / count
55
+ // 谓词永远收不到事件,状态停在冷扫那一刻(规则级 when 已由 rules 覆盖,动作级单独补齐)。
56
+ const observer = wireTriggerObservers(ctx, [
57
+ ...rules,
58
+ ...rules.flatMap(rule => (rule.actions ?? [])
59
+ .filter(action => typeof action.actionWhen?.observe === 'function')
60
+ .map(action => ({ id: action.id, when: action.actionWhen }))),
61
+ ], { plugin: options.plugin ?? 'rule-engine', warnOnce })
20
62
  if (observer) releases.push(observer)
21
63
  let active = true
22
64
  const bind = (item, on) => prepareAction(item.action, { plugin: options.plugin, warnOnce, promptConfigOptions: item.rule.promptConfigOptions, on })(ctx)
@@ -25,7 +67,6 @@ export function mountRuleSources(ctx, sources, options = {}) {
25
67
  if (rule.enabled === false) continue
26
68
  for (const action of rule.actions) {
27
69
  const item = { moduleId: source.moduleId, ruleIndex, rule, action }
28
- if (action.execution.lifecycle === 'registration' && action.kind === 'guard') { releases.push(bind(item)); continue }
29
70
  const point = action.execution
30
71
  const key = `${point.channel}:${point.phase}:${action.waterfallPosition}`
31
72
  const bucket = points.get(key) ?? { ...point, waterfallPosition: action.waterfallPosition, items: [] }
@@ -39,6 +80,8 @@ export function mountRuleSources(ctx, sources, options = {}) {
39
80
  const flushLayers = () => {
40
81
  if (!textConfigs.length) return
41
82
  releases.push(wireLayers(ctx, textConfigs, warnOnce, {
83
+ agent: options.agent,
84
+ turnStopBudgets,
42
85
  on: (channel, handler) => {
43
86
  if (channel !== point.channel) throw new TypeError(`rule action registered outside ${point.channel}: ${channel}`)
44
87
  handlers.push({ handler }); return () => {}
@@ -49,20 +92,30 @@ export function mountRuleSources(ctx, sources, options = {}) {
49
92
  for (const item of point.items) {
50
93
  const { action, rule, moduleId } = item
51
94
  if (action.kind === 'inject-text') {
52
- const config = { ...action.compiledConfig, rule, sourceModuleId: moduleId, group: undefined, exclusive: false, enabled: true, actionWhen: action.actionWhen, bypassRuleWhen: action.bypassRuleWhen }
95
+ const config = { ...action.compiledConfig, rule, sourceModuleId: moduleId, variableStore: options.variableStore, group: undefined, exclusive: false, enabled: true, actionWhen: action.actionWhen, bypassRuleWhen: action.bypassRuleWhen }
53
96
  if (config.layer === 'pre-step') injections.get(moduleId).configs.push(config)
54
97
  else textConfigs.push(config)
55
98
  continue
56
99
  }
57
100
  flushLayers()
101
+ const created = []
58
102
  const on = (channel, handler) => {
59
103
  if (channel !== point.channel) throw new TypeError(`rule action registered outside ${point.channel}: ${channel}`)
60
104
  const entry = { rule, handler, sequence: action.channelOrder, sourceModuleId: moduleId, ruleId: rule.id, ruleActionIndex: action.actionIndex, id: action.id, actionWhen: action.actionWhen, bypassRuleWhen: action.bypassRuleWhen }
61
105
  if (channel === 'agent/pre-step' && point.waterfallPosition === 'default') injections.get(moduleId).ruleActions.push(entry)
62
106
  else handlers.push(entry)
107
+ created.push(entry)
108
+ // 显式放弃:handler 的存活期由下面唯一的 `ctx.on(point.channel, …)` 统一撤销,
109
+ // 这里再返回一个真 disposer 会与它重复释放同一批 handler。
63
110
  return () => {}
64
111
  }
65
- releases.push(bind(item, on))
112
+ const dispose = bind(item, on)
113
+ // 未命中通知:条件为假时动作不会进入 handler,撤销型动作(tool-visibility 的执行闸)
114
+ // 只能靠这条回调收手——否则第一轮为真后永久留闸。
115
+ if (typeof dispose?.miss === 'function') {
116
+ for (const entry of created) entry.miss = dispose.miss
117
+ }
118
+ releases.push(dispose)
66
119
  }
67
120
  flushLayers()
68
121
  if (!handlers.length) continue
@@ -71,11 +124,23 @@ export function mountRuleSources(ctx, sources, options = {}) {
71
124
  const payload = free ? args : args.slice(0, -1)
72
125
  const next = free ? () => undefined : args[args.length - 1]
73
126
  if (!active) return next()
74
- const frame = ruleFrame(point.channel, payload, warnOnce, ctx)
127
+ // 帧构造失败(如宿主 snapshotEvents 抛错)只告警并按「无事实」跳过本点动作,
128
+ // 不得把异常抛出整条分派。
129
+ let frame
130
+ try {
131
+ frame = ruleFrame(point.channel, payload, warnOnce, ctx, report)
132
+ } catch (error) {
133
+ warnOnce(`rule engine: frame construction failed on ${point.channel}: ${String(error?.message ?? error)}`)
134
+ return next()
135
+ }
75
136
  if (free) {
76
137
  let pending
77
138
  for (const entry of handlers) {
78
- const invoke = () => active && actionMatches(entry, frame) ? entry.handler(...payload, undefined, frame) : undefined
139
+ const invoke = () => {
140
+ if (!active) return undefined
141
+ if (!actionMatches(entry, frame)) { entry.miss?.(frame); return undefined }
142
+ return entry.handler(...payload, undefined, frame)
143
+ }
79
144
  pending = pending?.then ? pending.then(invoke) : invoke()
80
145
  }
81
146
  return pending
@@ -83,7 +148,8 @@ export function mountRuleSources(ctx, sources, options = {}) {
83
148
  if (point.phase === 'after-next') return Promise.resolve(next()).then(async initial => {
84
149
  let result = initial
85
150
  for (const entry of handlers) {
86
- if (!active || !actionMatches(entry, frame)) continue
151
+ if (!active) continue
152
+ if (!actionMatches(entry, frame)) { entry.miss?.(frame); continue }
87
153
  result = await entry.handler(...payload, () => result, frame)
88
154
  }
89
155
  return result
@@ -91,13 +157,32 @@ export function mountRuleSources(ctx, sources, options = {}) {
91
157
  const invoke = index => {
92
158
  if (!active || index === handlers.length) return next()
93
159
  const entry = handlers[index]
94
- return actionMatches(entry, frame) ? entry.handler(...payload, () => invoke(index + 1), frame) : invoke(index + 1)
160
+ if (!actionMatches(entry, frame)) {
161
+ entry.miss?.(frame)
162
+ return invoke(index + 1)
163
+ }
164
+ return entry.handler(...payload, () => invoke(index + 1), frame)
95
165
  }
96
166
  return invoke(0)
97
167
  }, point.waterfallPosition === 'outermost' ? { prepend: true } : undefined))
98
168
  }
99
- const preStep = [...injections.values()].filter(source => source.configs.length || source.ruleActions.length)
100
- if (preStep.length) releases.push(applyPromptConfigSources(ctx, preStep, { layers: false }))
169
+ // 晋升相位实例对:`options.promotion` 注入(托管路径传协调器那两份),否则从池里按配置取
170
+ // ——池在挂载开头已建,条件绑定也用它。共用实例后事件由池统一喂,消费者一律不得再 observe。
171
+ const promotion = options.promotion ?? coordinator?.promotion ?? {
172
+ main: pool.tracker(PROMOTE_EVENTS.either, { includeSubagents: false }),
173
+ withSubagents: pool.tracker(PROMOTE_EVENTS.either, { includeSubagents: true }),
174
+ }
175
+ const preStep = [...injections.values()]
176
+ .filter(source => source.configs.length || source.ruleActions.length)
177
+ .map(source => createPreStepSource({
178
+ sourceId: source.sourceId,
179
+ ctx,
180
+ configs: source.configs,
181
+ ruleActions: source.ruleActions,
182
+ onOutcome: options.onOutcome === undefined ? undefined : report => options.onOutcome({ moduleId: source.moduleId, ...report }),
183
+ promotion,
184
+ }))
185
+ if (preStep.length) releases.push(applyPromptConfigSources(preStep, { layers: false }))
101
186
  } catch (error) {
102
187
  active = false
103
188
  for (const dispose of releases.reverse()) { try { dispose?.() } catch {} }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * `rule-spec.mjs` 的手写声明:只声明 `src/` 与 `test/engine/` 消费的导出,形状按实现写实。
3
+ *
4
+ * 这里不复用插件侧类型(声明文件与 `.mjs` 同目录,`src/` 不在引擎的类型解析面内),
5
+ * 只用结构等价的本地形状;被消费的字段与 `engine/rule-spec.mjs` 的产物逐名对应。
6
+ */
7
+ import type { RuleAudience } from './audience.mjs'
8
+ export type { RuleAudience }
9
+
10
+ /** 编译后的动作;仅覆盖插件依赖面(装配侧只读 id/kind/channelOrder/waterfallPosition/compiledConfig)。 */
11
+ export interface CompiledRuleAction {
12
+ id: string
13
+ kind: string
14
+ channelOrder: number
15
+ waterfallPosition: string
16
+ actionIndex: number
17
+ /** inject-text 动作编译出的注入叶子;其余动作没有这个字段。 */
18
+ compiledConfig?: Record<string, unknown>
19
+ [key: string]: unknown
20
+ }
21
+
22
+ /** 编译后的规则;仅覆盖插件依赖面(装配侧只读 id/enabled/actions)。 */
23
+ export interface CompiledRule {
24
+ id: string
25
+ name?: string
26
+ layer?: string
27
+ enabled: boolean
28
+ exclusive: boolean
29
+ sequence: number
30
+ actions: CompiledRuleAction[]
31
+ [key: string]: unknown
32
+ }
33
+
34
+ /** `options.promptConfigOptions`:模板与策略的取法,交给 `schema.mjs#createPromptConfigs`。 */
35
+ export interface PromptConfigCompileOptions {
36
+ templateBaseUrl?: URL
37
+ templateModuleRoot?: URL
38
+ strategyDir?: string
39
+ loadTemplate?: (file: unknown) => unknown
40
+ }
41
+
42
+ export interface CompileRulesOptions {
43
+ moduleId?: string
44
+ sourceModuleId?: string
45
+ configOrder?: Record<string, number>
46
+ variables?: Record<string, string>
47
+ variablesEnabled?: boolean
48
+ contextActivationRecursive?: boolean
49
+ /** 人设已独占 complete 段时拒绝第二条(宿主聚合用)。 */
50
+ personaComplete?: boolean
51
+ promptConfigOptions?: PromptConfigCompileOptions
52
+ /** 挂载期输入:编译期显式剥掉,绑定由 `rule-runtime.mjs` 完成。 */
53
+ ctx?: unknown
54
+ standingMountFor?: unknown
55
+ }
56
+
57
+ /** 引擎编译出的注入配置叶子;只列编译必产出的字段,宿主按自己的 `PromptConfigSpec` 消费它。 */
58
+ export interface InjectionConfigSpec {
59
+ id: string
60
+ layer: string
61
+ strategy?: string
62
+ order?: number
63
+ sourceKind?: string
64
+ text?: string
65
+ texts?: string[]
66
+ templateFile?: string
67
+ fill?: string
68
+ variables?: Record<string, string>
69
+ params?: Record<string, unknown>
70
+ }
71
+
72
+ /** 规则与动作的执行点目录(编辑器元数据);结构等价于 `src/shared/rules.ts` 的 `RuleEditorMeta`。 */
73
+ export interface RuleEditorMeta {
74
+ predicates: Array<{ kind: string; example: Record<string, unknown> }>
75
+ actions: Array<{
76
+ kind: string
77
+ example: Record<string, unknown>
78
+ channel: string
79
+ phase: string
80
+ lifecycle: 'event' | 'registration'
81
+ supportsWhen: boolean
82
+ }>
83
+ composites: string[]
84
+ waterfallPositions: string[]
85
+ }
86
+
87
+ /** 规则及物化身份的唯一安全边界;非法值抛 `TypeError`。 */
88
+ export function assertRuleId(id: unknown): void
89
+
90
+ export function compileRules(specs: readonly unknown[], options?: CompileRulesOptions): CompiledRule[]
91
+
92
+ /** 该受众下独占的 `complete` 系统段,身份是 `rule.id/action.id`。 */
93
+ export function completeRuleSections(rules: readonly unknown[], audience: RuleAudience): string[]
94
+
95
+
96
+
97
+ /** 动作级受众事实:规则级 when 与动作级 conditions 的合取;else 动作(bypassRuleWhen)只读动作条件。 */
98
+ export function actionAudiences(rule: unknown, actionId: string): Set<RuleAudience>
99
+
100
+ export function injectionConfigSpec(
101
+ rule: { id: string; layer?: string },
102
+ action: { id: string; kind?: string; config?: unknown },
103
+ options?: { variables?: Record<string, string>; variablesEnabled?: boolean },
104
+ ): InjectionConfigSpec
105
+
106
+ export function getRuleEditorMeta(): RuleEditorMeta