foliko 1.0.74 → 1.0.76

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 (238) hide show
  1. package/.agent/.shared/ui-ux-pro-max/data/charts.csv +26 -0
  2. package/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
  3. package/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
  4. package/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
  5. package/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
  6. package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
  7. package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
  8. package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  9. package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  10. package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  11. package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  12. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  13. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  14. package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  15. package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
  16. package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  17. package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  18. package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  19. package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  20. package/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
  21. package/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
  22. package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  23. package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  24. package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
  25. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
  26. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
  27. package/.agent/.shared/ui-ux-pro-max/scripts/core.py +258 -0
  28. package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +1067 -0
  29. package/.agent/.shared/ui-ux-pro-max/scripts/search.py +106 -0
  30. package/.agent/ARCHITECTURE.md +288 -0
  31. package/.agent/agents/ambient-agent.md +57 -0
  32. package/.agent/agents/debugger.md +55 -0
  33. package/.agent/agents/email-assistant.md +49 -0
  34. package/.agent/agents/file-manager.md +42 -0
  35. package/.agent/agents/python-developer.md +60 -0
  36. package/.agent/agents/scheduler.md +59 -0
  37. package/.agent/agents/web-developer.md +45 -0
  38. package/.agent/data/default.json +29 -0
  39. package/.agent/data/plugins-state.json +255 -0
  40. package/.agent/mcp_config.json +4 -0
  41. package/.agent/mcp_config_updated.json +12 -0
  42. package/.agent/plugins.json +5 -0
  43. package/.agent/rules/GEMINI.md +273 -0
  44. package/.agent/rules/allow-rule.md +77 -0
  45. package/.agent/rules/log-rule.md +83 -0
  46. package/.agent/rules/security-rule.md +93 -0
  47. package/.agent/scripts/auto_preview.py +148 -0
  48. package/.agent/scripts/checklist.py +217 -0
  49. package/.agent/scripts/session_manager.py +120 -0
  50. package/.agent/scripts/verify_all.py +327 -0
  51. package/.agent/skills/api-patterns/SKILL.md +81 -0
  52. package/.agent/skills/api-patterns/api-style.md +42 -0
  53. package/.agent/skills/api-patterns/auth.md +24 -0
  54. package/.agent/skills/api-patterns/documentation.md +26 -0
  55. package/.agent/skills/api-patterns/graphql.md +41 -0
  56. package/.agent/skills/api-patterns/rate-limiting.md +31 -0
  57. package/.agent/skills/api-patterns/response.md +37 -0
  58. package/.agent/skills/api-patterns/rest.md +40 -0
  59. package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
  60. package/.agent/skills/api-patterns/security-testing.md +122 -0
  61. package/.agent/skills/api-patterns/trpc.md +41 -0
  62. package/.agent/skills/api-patterns/versioning.md +22 -0
  63. package/.agent/skills/app-builder/SKILL.md +75 -0
  64. package/.agent/skills/app-builder/agent-coordination.md +71 -0
  65. package/.agent/skills/app-builder/feature-building.md +53 -0
  66. package/.agent/skills/app-builder/project-detection.md +34 -0
  67. package/.agent/skills/app-builder/scaffolding.md +118 -0
  68. package/.agent/skills/app-builder/tech-stack.md +40 -0
  69. package/.agent/skills/app-builder/templates/SKILL.md +39 -0
  70. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
  71. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
  72. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  73. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
  74. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
  75. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
  76. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
  77. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
  78. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
  79. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
  80. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
  81. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
  82. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
  83. package/.agent/skills/architecture/SKILL.md +55 -0
  84. package/.agent/skills/architecture/context-discovery.md +43 -0
  85. package/.agent/skills/architecture/examples.md +94 -0
  86. package/.agent/skills/architecture/pattern-selection.md +68 -0
  87. package/.agent/skills/architecture/patterns-reference.md +50 -0
  88. package/.agent/skills/architecture/trade-off-analysis.md +77 -0
  89. package/.agent/skills/clean-code/SKILL.md +201 -0
  90. package/.agent/skills/doc.md +177 -0
  91. package/.agent/skills/frontend-design/SKILL.md +418 -0
  92. package/.agent/skills/frontend-design/animation-guide.md +331 -0
  93. package/.agent/skills/frontend-design/color-system.md +311 -0
  94. package/.agent/skills/frontend-design/decision-trees.md +418 -0
  95. package/.agent/skills/frontend-design/motion-graphics.md +306 -0
  96. package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
  97. package/.agent/skills/frontend-design/scripts/ux_audit.py +722 -0
  98. package/.agent/skills/frontend-design/typography-system.md +345 -0
  99. package/.agent/skills/frontend-design/ux-psychology.md +1116 -0
  100. package/.agent/skills/frontend-design/visual-effects.md +383 -0
  101. package/.agent/skills/i18n-localization/SKILL.md +154 -0
  102. package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
  103. package/.agent/skills/mcp-builder/SKILL.md +176 -0
  104. package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
  105. package/.agent/workflows/brainstorm.md +113 -0
  106. package/.agent/workflows/create.md +59 -0
  107. package/.agent/workflows/debug.md +103 -0
  108. package/.agent/workflows/deploy.md +176 -0
  109. package/.agent/workflows/enhance.md +63 -0
  110. package/.agent/workflows/orchestrate.md +237 -0
  111. package/.agent/workflows/plan.md +89 -0
  112. package/.agent/workflows/preview.md +81 -0
  113. package/.agent/workflows/simple-test.md +42 -0
  114. package/.agent/workflows/status.md +86 -0
  115. package/.agent/workflows/structured-orchestrate.md +180 -0
  116. package/.agent/workflows/test.md +144 -0
  117. package/.agent/workflows/ui-ux-pro-max.md +296 -0
  118. package/.claude/settings.local.json +11 -1
  119. package/.editorconfig +56 -0
  120. package/.husky/pre-commit +4 -0
  121. package/.lintstagedrc +7 -0
  122. package/.prettierignore +29 -0
  123. package/.prettierrc +11 -0
  124. package/CLAUDE.md +2 -0
  125. package/README.md +64 -55
  126. package/SPEC.md +102 -61
  127. package/cli/bin/foliko.js +11 -11
  128. package/cli/src/commands/chat.js +143 -141
  129. package/cli/src/commands/list.js +93 -90
  130. package/cli/src/index.js +75 -75
  131. package/cli/src/ui/chat-ui.js +201 -199
  132. package/cli/src/utils/ansi.js +40 -40
  133. package/cli/src/utils/markdown.js +292 -296
  134. package/docker-compose.yml +1 -1
  135. package/docs/ai-sdk-optimization.md +655 -643
  136. package/docs/features.md +80 -80
  137. package/docs/quick-reference.md +49 -46
  138. package/docs/user-manual.md +411 -380
  139. package/examples/ambient-example.js +194 -196
  140. package/examples/basic.js +50 -45
  141. package/examples/bootstrap.js +121 -112
  142. package/examples/mcp-example.js +19 -16
  143. package/examples/skill-example.js +20 -20
  144. package/examples/test-chat.js +137 -135
  145. package/examples/test-mcp.js +85 -79
  146. package/examples/test-reload.js +59 -61
  147. package/examples/test-telegram.js +50 -50
  148. package/examples/test-tg-bot.js +45 -42
  149. package/examples/test-tg-simple.js +47 -46
  150. package/examples/test-tg.js +62 -62
  151. package/examples/test-think.js +43 -37
  152. package/examples/test-web-plugin.js +103 -98
  153. package/examples/test-weixin-feishu.js +103 -100
  154. package/examples/workflow.js +158 -158
  155. package/package.json +37 -3
  156. package/plugins/ai-plugin.js +102 -100
  157. package/plugins/ambient-agent/EventWatcher.js +113 -0
  158. package/plugins/ambient-agent/ExplorerLoop.js +640 -0
  159. package/plugins/ambient-agent/GoalManager.js +197 -0
  160. package/plugins/ambient-agent/Reflector.js +95 -0
  161. package/plugins/ambient-agent/StateStore.js +90 -0
  162. package/plugins/ambient-agent/constants.js +101 -0
  163. package/plugins/ambient-agent/index.js +579 -0
  164. package/plugins/audit-plugin.js +187 -187
  165. package/plugins/default-plugins.js +662 -649
  166. package/plugins/email/constants.js +64 -0
  167. package/plugins/email/handlers.js +461 -0
  168. package/plugins/email/index.js +278 -0
  169. package/plugins/email/monitor.js +269 -0
  170. package/plugins/email/parser.js +138 -0
  171. package/plugins/email/reply.js +151 -0
  172. package/plugins/email/utils.js +124 -0
  173. package/plugins/feishu-plugin.js +481 -477
  174. package/plugins/file-system-plugin.js +826 -476
  175. package/plugins/install-plugin.js +199 -197
  176. package/plugins/python-executor-plugin.js +367 -365
  177. package/plugins/python-plugin-loader.js +481 -479
  178. package/plugins/rules-plugin.js +294 -292
  179. package/plugins/scheduler-plugin.js +691 -689
  180. package/plugins/session-plugin.js +369 -367
  181. package/plugins/shell-executor-plugin.js +197 -197
  182. package/plugins/storage-plugin.js +240 -238
  183. package/plugins/subagent-plugin.js +845 -785
  184. package/plugins/telegram-plugin.js +482 -475
  185. package/plugins/think-plugin.js +345 -343
  186. package/plugins/tools-plugin.js +196 -194
  187. package/plugins/web-plugin.js +606 -604
  188. package/plugins/weixin-plugin.js +545 -538
  189. package/reports/system-health-report-20260401.md +79 -0
  190. package/skills/ambient-agent/SKILL.md +49 -39
  191. package/skills/foliko-dev/AGENTS.md +64 -61
  192. package/skills/foliko-dev/SKILL.md +125 -119
  193. package/skills/mcp-usage/SKILL.md +19 -17
  194. package/skills/python-plugin-dev/SKILL.md +16 -15
  195. package/skills/skill-guide/SKILL.md +12 -12
  196. package/skills/subagent-guide/SKILL.md +237 -0
  197. package/skills/workflow-guide/SKILL.md +90 -45
  198. package/skills/workflow-troubleshooting/DEBUGGING.md +36 -21
  199. package/skills/workflow-troubleshooting/SKILL.md +156 -79
  200. package/src/capabilities/index.js +11 -11
  201. package/src/capabilities/skill-manager.js +609 -595
  202. package/src/capabilities/workflow-engine.js +1109 -1195
  203. package/src/core/agent-chat.js +882 -735
  204. package/src/core/agent.js +892 -688
  205. package/src/core/framework.js +465 -431
  206. package/src/core/index.js +19 -19
  207. package/src/core/plugin-base.js +219 -219
  208. package/src/core/plugin-manager.js +863 -767
  209. package/src/core/provider.js +114 -111
  210. package/src/core/sub-agent-config.js +264 -0
  211. package/src/core/system-prompt-builder.js +120 -0
  212. package/src/core/tool-registry.js +517 -134
  213. package/src/core/tool-router.js +297 -216
  214. package/src/executors/executor-base.js +12 -12
  215. package/src/executors/mcp-executor.js +741 -729
  216. package/src/index.js +25 -37
  217. package/src/utils/circuit-breaker.js +301 -0
  218. package/src/utils/error-boundary.js +363 -0
  219. package/src/utils/error.js +374 -0
  220. package/src/utils/event-emitter.js +97 -97
  221. package/src/utils/id.js +133 -0
  222. package/src/utils/index.js +217 -3
  223. package/src/utils/logger.js +181 -0
  224. package/src/utils/plugin-helpers.js +90 -0
  225. package/src/utils/retry.js +122 -0
  226. package/src/utils/sandbox.js +292 -0
  227. package/test/tool-registry-validation.test.js +218 -0
  228. package/test_report.md +70 -0
  229. package/website/docs/api.html +169 -107
  230. package/website/docs/configuration.html +296 -144
  231. package/website/docs/plugin-development.html +154 -85
  232. package/website/docs/project-structure.html +110 -109
  233. package/website/docs/skill-development.html +117 -61
  234. package/website/index.html +209 -205
  235. package/website/script.js +136 -133
  236. package/website/styles.css +1 -1
  237. package/plugins/ambient-agent-plugin.js +0 -1565
  238. package/plugins/email.js +0 -1142
@@ -1,293 +1,295 @@
1
- /**
2
- * Rules 规则引擎插件
3
- * 控制工具调用权限、内容过滤、触发动作
4
- */
5
-
6
- const { Plugin } = require('../src/core/plugin-base')
7
- const { z } = require('zod')
8
- const fs = require('fs')
9
- const path = require('path')
10
-
11
- /**
12
- * 内置规则类型
13
- */
14
- const RuleType = {
15
- ALLOW: 'allow', // 允许
16
- DENY: 'deny', // 拒绝
17
- TRANSFORM: 'transform', // 转换
18
- RATE_LIMIT: 'rate_limit' // 限流
19
- }
20
-
21
- /**
22
- * 规则评估结果
23
- */
24
- class RuleResult {
25
- constructor(allowed, rule = null, transform = null) {
26
- this.allowed = allowed
27
- this.rule = rule
28
- this.transform = transform
29
- }
30
- }
31
-
32
- class RulesPlugin extends Plugin {
33
- constructor(config = {}) {
34
- super()
35
- this.name = 'rules'
36
- this.version = '1.0.0'
37
- this.description = '规则引擎插件,用于控制工具调用权限、内容过滤、触发动作'
38
- this.priority = 25
39
- this.system = true
40
-
41
- this.config = {
42
- rulesDir: config.rulesDir || '.agent/rules',
43
- autoLoad: config.autoLoad !== false
44
- }
45
-
46
- this._framework = null
47
- this._rules = []
48
- this._ruleStats = {
49
- total: 0,
50
- allowed: 0,
51
- denied: 0,
52
- transformed: 0
53
- }
54
- }
55
-
56
- install(framework) {
57
- this._framework = framework
58
- return this
59
- }
60
-
61
- start(framework) {
62
- // 自动加载规则文件
63
- if (this.config.autoLoad && this.config.rulesDir) {
64
- this.loadFromDirectory(this.config.rulesDir)
65
- }
66
-
67
- // 注册规则管理工具
68
- framework.registerTool({
69
- name: 'rules_list',
70
- description: '列出所有规则',
71
- inputSchema: z.object({}),
72
- execute: async () => {
73
- return {
74
- success: true,
75
- rules: this._rules.map(r => ({
76
- name: r.name,
77
- type: r.type,
78
- target: r.target,
79
- description: r.description,
80
- enabled: r.enabled
81
- })),
82
- total: this._rules.length
83
- }
84
- }
85
- })
86
-
87
- framework.registerTool({
88
- name: 'rules_add',
89
- description: '添加规则',
90
- inputSchema: z.object({
91
- name: z.string().describe('规则名称'),
92
- type: z.enum(['allow', 'deny', 'transform']).describe('规则类型'),
93
- target: z.string().describe('目标 (工具名, *, @event-type)'),
94
- pattern: z.string().optional().describe('匹配模式 (正则表达式)'),
95
- description: z.string().optional().describe('规则描述'),
96
- action: z.object({}).optional().describe('规则动作 (transform 时使用)')
97
- }),
98
- execute: async (args) => {
99
- const rule = {
100
- name: args.name,
101
- type: args.type,
102
- target: args.target,
103
- pattern: args.pattern ? new RegExp(args.pattern) : null,
104
- description: args.description || '',
105
- action: args.action || {},
106
- enabled: true
107
- }
108
- this._rules.push(rule)
109
- return { success: true, rule: rule.name }
110
- }
111
- })
112
-
113
- framework.registerTool({
114
- name: 'rules_remove',
115
- description: '移除规则',
116
- inputSchema: z.object({
117
- name: z.string().describe('规则名称')
118
- }),
119
- execute: async (args) => {
120
- const index = this._rules.findIndex(r => r.name === args.name)
121
- if (index === -1) {
122
- return { success: false, error: 'Rule not found' }
123
- }
124
- this._rules.splice(index, 1)
125
- return { success: true, removed: args.name }
126
- }
127
- })
128
-
129
- framework.registerTool({
130
- name: 'rules_stats',
131
- description: '获取规则统计',
132
- inputSchema: z.object({}),
133
- execute: async () => {
134
- return {
135
- success: true,
136
- stats: { ...this._ruleStats }
137
- }
138
- }
139
- })
140
-
141
- framework.registerTool({
142
- name: 'rules_test',
143
- description: '测试规则匹配',
144
- inputSchema: z.object({
145
- target: z.string().describe('目标 (工具名或事件类型)'),
146
- input: z.object({}).optional().describe('输入参数')
147
- }),
148
- execute: async (args) => {
149
- const result = this.evaluate(args.target, args.input || {})
150
- return {
151
- success: true,
152
- target: args.target,
153
- result: {
154
- allowed: result.allowed,
155
- ruleName: result.rule?.name || null,
156
- ruleType: result.rule?.type || null
157
- }
158
- }
159
- }
160
- })
161
-
162
- return this
163
- }
164
-
165
- /**
166
- * 从目录加载规则文件
167
- */
168
- loadFromDirectory(rulesDir) {
169
- const resolvedDir = path.resolve(process.cwd(), rulesDir)
170
-
171
- if (!fs.existsSync(resolvedDir)) {
172
- console.log(`[RulesPlugin] Rules directory not found: ${resolvedDir}`)
173
- return
174
- }
175
-
176
- try {
177
- const files = fs.readdirSync(resolvedDir).filter(f => f.endsWith('.json'))
178
-
179
- for (const file of files) {
180
- const filePath = path.join(resolvedDir, file)
181
- const content = fs.readFileSync(filePath, 'utf-8')
182
- const rules = JSON.parse(content)
183
-
184
- for (const rule of rules) {
185
- if (rule.pattern) {
186
- rule.pattern = new RegExp(rule.pattern)
187
- }
188
- rule.enabled = rule.enabled !== false
189
- this._rules.push(rule)
190
- }
191
-
192
- console.log(`[RulesPlugin] Loaded ${rules.length} rules from ${file}`)
193
- }
194
- } catch (err) {
195
- console.error(`[RulesPlugin] Failed to load rules: ${err.message}`)
196
- }
197
- }
198
-
199
- /**
200
- * 评估目标是否符合规则
201
- * @param {string} target - 目标 (工具名, *, @event-type)
202
- * @param {Object} input - 输入参数
203
- * @returns {RuleResult}
204
- */
205
- evaluate(target, input = {}) {
206
- this._ruleStats.total++
207
-
208
- // 按优先级排序规则 (先加载的在前)
209
- for (const rule of this._rules) {
210
- if (!rule.enabled) continue
211
-
212
- // 匹配目标
213
- if (rule.target !== '*' && rule.target !== target) continue
214
-
215
- // 匹配模式 (如果有)
216
- if (rule.pattern) {
217
- const targetStr = typeof input === 'string' ? input : JSON.stringify(input)
218
- if (!rule.pattern.test(targetStr)) continue
219
- }
220
-
221
- // 评估规则
222
- if (rule.type === RuleType.DENY) {
223
- this._ruleStats.denied++
224
- return new RuleResult(false, rule)
225
- }
226
-
227
- if (rule.type === RuleType.ALLOW) {
228
- this._ruleStats.allowed++
229
- return new RuleResult(true, rule)
230
- }
231
-
232
- if (rule.type === RuleType.TRANSFORM) {
233
- this._ruleStats.transformed++
234
- return new RuleResult(true, rule, rule.action)
235
- }
236
- }
237
-
238
- // 没有匹配规则,默认允许
239
- this._ruleStats.allowed++
240
- return new RuleResult(true)
241
- }
242
-
243
- /**
244
- * 检查工具调用是否允许
245
- */
246
- checkToolCall(toolName, args) {
247
- return this.evaluate(toolName, args)
248
- }
249
-
250
- /**
251
- * 检查消息是否允许
252
- */
253
- checkMessage(message, context) {
254
- return this.evaluate('@message', { message, context })
255
- }
256
-
257
- /**
258
- * 添加规则
259
- */
260
- addRule(rule) {
261
- this._rules.push(rule)
262
- }
263
-
264
- /**
265
- * 移除规则
266
- */
267
- removeRule(name) {
268
- const index = this._rules.findIndex(r => r.name === name)
269
- if (index !== -1) {
270
- this._rules.splice(index, 1)
271
- return true
272
- }
273
- return false
274
- }
275
-
276
- reload(framework) {
277
- this._framework = framework
278
- this._rules = []
279
- this._ruleStats = { total: 0, allowed: 0, denied: 0, transformed: 0 }
280
-
281
- if (this.config.autoLoad && this.config.rulesDir) {
282
- this.loadFromDirectory(this.config.rulesDir)
283
- }
284
- }
285
-
286
- uninstall(framework) {
287
- this._rules = []
288
- this._ruleStats = { total: 0, allowed: 0, denied: 0, transformed: 0 }
289
- this._framework = null
290
- }
291
- }
292
-
1
+ /**
2
+ * Rules 规则引擎插件
3
+ * 控制工具调用权限、内容过滤、触发动作
4
+ */
5
+
6
+ const { Plugin } = require('../src/core/plugin-base')
7
+ const { logger } = require('../src/utils/logger')
8
+ const log = logger.child('RulesPlugin')
9
+ const { z } = require('zod')
10
+ const fs = require('fs')
11
+ const path = require('path')
12
+
13
+ /**
14
+ * 内置规则类型
15
+ */
16
+ const RuleType = {
17
+ ALLOW: 'allow', // 允许
18
+ DENY: 'deny', // 拒绝
19
+ TRANSFORM: 'transform', // 转换
20
+ RATE_LIMIT: 'rate_limit' // 限流
21
+ }
22
+
23
+ /**
24
+ * 规则评估结果
25
+ */
26
+ class RuleResult {
27
+ constructor(allowed, rule = null, transform = null) {
28
+ this.allowed = allowed
29
+ this.rule = rule
30
+ this.transform = transform
31
+ }
32
+ }
33
+
34
+ class RulesPlugin extends Plugin {
35
+ constructor(config = {}) {
36
+ super()
37
+ this.name = 'rules'
38
+ this.version = '1.0.0'
39
+ this.description = '规则引擎插件,用于控制工具调用权限、内容过滤、触发动作'
40
+ this.priority = 25
41
+ this.system = true
42
+
43
+ this.config = {
44
+ rulesDir: config.rulesDir || '.agent/rules',
45
+ autoLoad: config.autoLoad !== false
46
+ }
47
+
48
+ this._framework = null
49
+ this._rules = []
50
+ this._ruleStats = {
51
+ total: 0,
52
+ allowed: 0,
53
+ denied: 0,
54
+ transformed: 0
55
+ }
56
+ }
57
+
58
+ install(framework) {
59
+ this._framework = framework
60
+ return this
61
+ }
62
+
63
+ start(framework) {
64
+ // 自动加载规则文件
65
+ if (this.config.autoLoad && this.config.rulesDir) {
66
+ this.loadFromDirectory(this.config.rulesDir)
67
+ }
68
+
69
+ // 注册规则管理工具
70
+ framework.registerTool({
71
+ name: 'rules_list',
72
+ description: '列出所有规则',
73
+ inputSchema: z.object({}),
74
+ execute: async () => {
75
+ return {
76
+ success: true,
77
+ rules: this._rules.map(r => ({
78
+ name: r.name,
79
+ type: r.type,
80
+ target: r.target,
81
+ description: r.description,
82
+ enabled: r.enabled
83
+ })),
84
+ total: this._rules.length
85
+ }
86
+ }
87
+ })
88
+
89
+ framework.registerTool({
90
+ name: 'rules_add',
91
+ description: '添加规则',
92
+ inputSchema: z.object({
93
+ name: z.string().describe('规则名称'),
94
+ type: z.enum(['allow', 'deny', 'transform']).describe('规则类型'),
95
+ target: z.string().describe('目标 (工具名, *, @event-type)'),
96
+ pattern: z.string().optional().describe('匹配模式 (正则表达式)'),
97
+ description: z.string().optional().describe('规则描述'),
98
+ action: z.object({}).optional().describe('规则动作 (transform 时使用)')
99
+ }),
100
+ execute: async (args) => {
101
+ const rule = {
102
+ name: args.name,
103
+ type: args.type,
104
+ target: args.target,
105
+ pattern: args.pattern ? new RegExp(args.pattern) : null,
106
+ description: args.description || '',
107
+ action: args.action || {},
108
+ enabled: true
109
+ }
110
+ this._rules.push(rule)
111
+ return { success: true, rule: rule.name }
112
+ }
113
+ })
114
+
115
+ framework.registerTool({
116
+ name: 'rules_remove',
117
+ description: '移除规则',
118
+ inputSchema: z.object({
119
+ name: z.string().describe('规则名称')
120
+ }),
121
+ execute: async (args) => {
122
+ const index = this._rules.findIndex(r => r.name === args.name)
123
+ if (index === -1) {
124
+ return { success: false, error: 'Rule not found' }
125
+ }
126
+ this._rules.splice(index, 1)
127
+ return { success: true, removed: args.name }
128
+ }
129
+ })
130
+
131
+ framework.registerTool({
132
+ name: 'rules_stats',
133
+ description: '获取规则统计',
134
+ inputSchema: z.object({}),
135
+ execute: async () => {
136
+ return {
137
+ success: true,
138
+ stats: { ...this._ruleStats }
139
+ }
140
+ }
141
+ })
142
+
143
+ framework.registerTool({
144
+ name: 'rules_test',
145
+ description: '测试规则匹配',
146
+ inputSchema: z.object({
147
+ target: z.string().describe('目标 (工具名或事件类型)'),
148
+ input: z.object({}).optional().describe('输入参数')
149
+ }),
150
+ execute: async (args) => {
151
+ const result = this.evaluate(args.target, args.input || {})
152
+ return {
153
+ success: true,
154
+ target: args.target,
155
+ result: {
156
+ allowed: result.allowed,
157
+ ruleName: result.rule?.name || null,
158
+ ruleType: result.rule?.type || null
159
+ }
160
+ }
161
+ }
162
+ })
163
+
164
+ return this
165
+ }
166
+
167
+ /**
168
+ * 从目录加载规则文件
169
+ */
170
+ loadFromDirectory(rulesDir) {
171
+ const resolvedDir = path.resolve(process.cwd(), rulesDir)
172
+
173
+ if (!fs.existsSync(resolvedDir)) {
174
+ log.info(` Rules directory not found: ${resolvedDir}`)
175
+ return
176
+ }
177
+
178
+ try {
179
+ const files = fs.readdirSync(resolvedDir).filter(f => f.endsWith('.json'))
180
+
181
+ for (const file of files) {
182
+ const filePath = path.join(resolvedDir, file)
183
+ const content = fs.readFileSync(filePath, 'utf-8')
184
+ const rules = JSON.parse(content)
185
+
186
+ for (const rule of rules) {
187
+ if (rule.pattern) {
188
+ rule.pattern = new RegExp(rule.pattern)
189
+ }
190
+ rule.enabled = rule.enabled !== false
191
+ this._rules.push(rule)
192
+ }
193
+
194
+ log.info(` Loaded ${rules.length} rules from ${file}`)
195
+ }
196
+ } catch (err) {
197
+ log.error(` Failed to load rules: ${err.message}`)
198
+ }
199
+ }
200
+
201
+ /**
202
+ * 评估目标是否符合规则
203
+ * @param {string} target - 目标 (工具名, *, @event-type)
204
+ * @param {Object} input - 输入参数
205
+ * @returns {RuleResult}
206
+ */
207
+ evaluate(target, input = {}) {
208
+ this._ruleStats.total++
209
+
210
+ // 按优先级排序规则 (先加载的在前)
211
+ for (const rule of this._rules) {
212
+ if (!rule.enabled) continue
213
+
214
+ // 匹配目标
215
+ if (rule.target !== '*' && rule.target !== target) continue
216
+
217
+ // 匹配模式 (如果有)
218
+ if (rule.pattern) {
219
+ const targetStr = typeof input === 'string' ? input : JSON.stringify(input)
220
+ if (!rule.pattern.test(targetStr)) continue
221
+ }
222
+
223
+ // 评估规则
224
+ if (rule.type === RuleType.DENY) {
225
+ this._ruleStats.denied++
226
+ return new RuleResult(false, rule)
227
+ }
228
+
229
+ if (rule.type === RuleType.ALLOW) {
230
+ this._ruleStats.allowed++
231
+ return new RuleResult(true, rule)
232
+ }
233
+
234
+ if (rule.type === RuleType.TRANSFORM) {
235
+ this._ruleStats.transformed++
236
+ return new RuleResult(true, rule, rule.action)
237
+ }
238
+ }
239
+
240
+ // 没有匹配规则,默认允许
241
+ this._ruleStats.allowed++
242
+ return new RuleResult(true)
243
+ }
244
+
245
+ /**
246
+ * 检查工具调用是否允许
247
+ */
248
+ checkToolCall(toolName, args) {
249
+ return this.evaluate(toolName, args)
250
+ }
251
+
252
+ /**
253
+ * 检查消息是否允许
254
+ */
255
+ checkMessage(message, context) {
256
+ return this.evaluate('@message', { message, context })
257
+ }
258
+
259
+ /**
260
+ * 添加规则
261
+ */
262
+ addRule(rule) {
263
+ this._rules.push(rule)
264
+ }
265
+
266
+ /**
267
+ * 移除规则
268
+ */
269
+ removeRule(name) {
270
+ const index = this._rules.findIndex(r => r.name === name)
271
+ if (index !== -1) {
272
+ this._rules.splice(index, 1)
273
+ return true
274
+ }
275
+ return false
276
+ }
277
+
278
+ reload(framework) {
279
+ this._framework = framework
280
+ this._rules = []
281
+ this._ruleStats = { total: 0, allowed: 0, denied: 0, transformed: 0 }
282
+
283
+ if (this.config.autoLoad && this.config.rulesDir) {
284
+ this.loadFromDirectory(this.config.rulesDir)
285
+ }
286
+ }
287
+
288
+ uninstall(framework) {
289
+ this._rules = []
290
+ this._ruleStats = { total: 0, allowed: 0, denied: 0, transformed: 0 }
291
+ this._framework = null
292
+ }
293
+ }
294
+
293
295
  module.exports = { RulesPlugin }