@zhin.js/core 1.1.0 → 1.1.2

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 (122) hide show
  1. package/lib/adapter.d.ts +1 -26
  2. package/lib/adapter.d.ts.map +1 -1
  3. package/lib/adapter.js +20 -117
  4. package/lib/adapter.js.map +1 -1
  5. package/lib/built/adapter-process.d.ts +0 -4
  6. package/lib/built/adapter-process.d.ts.map +1 -1
  7. package/lib/built/adapter-process.js +0 -95
  8. package/lib/built/adapter-process.js.map +1 -1
  9. package/lib/built/agent-preset.d.ts +2 -0
  10. package/lib/built/agent-preset.d.ts.map +1 -1
  11. package/lib/built/agent-preset.js +4 -0
  12. package/lib/built/agent-preset.js.map +1 -1
  13. package/lib/built/command.d.ts +4 -0
  14. package/lib/built/command.d.ts.map +1 -1
  15. package/lib/built/command.js +6 -0
  16. package/lib/built/command.js.map +1 -1
  17. package/lib/built/component.d.ts.map +1 -1
  18. package/lib/built/component.js +1 -0
  19. package/lib/built/component.js.map +1 -1
  20. package/lib/built/dispatcher.d.ts.map +1 -1
  21. package/lib/built/dispatcher.js +0 -13
  22. package/lib/built/dispatcher.js.map +1 -1
  23. package/lib/built/message-filter.d.ts +2 -0
  24. package/lib/built/message-filter.d.ts.map +1 -1
  25. package/lib/built/message-filter.js +5 -0
  26. package/lib/built/message-filter.js.map +1 -1
  27. package/lib/built/skill.d.ts +11 -0
  28. package/lib/built/skill.d.ts.map +1 -1
  29. package/lib/built/skill.js +14 -0
  30. package/lib/built/skill.js.map +1 -1
  31. package/lib/built/tool.d.ts +11 -44
  32. package/lib/built/tool.d.ts.map +1 -1
  33. package/lib/built/tool.js +14 -353
  34. package/lib/built/tool.js.map +1 -1
  35. package/lib/plugin.d.ts +1 -25
  36. package/lib/plugin.d.ts.map +1 -1
  37. package/lib/plugin.js +1 -77
  38. package/lib/plugin.js.map +1 -1
  39. package/lib/types.d.ts +0 -25
  40. package/lib/types.d.ts.map +1 -1
  41. package/package.json +10 -7
  42. package/CHANGELOG.md +0 -561
  43. package/REFACTORING_COMPLETE.md +0 -178
  44. package/REFACTORING_STATUS.md +0 -263
  45. package/src/adapter.ts +0 -275
  46. package/src/ai/index.ts +0 -55
  47. package/src/ai/providers/anthropic.ts +0 -379
  48. package/src/ai/providers/base.ts +0 -175
  49. package/src/ai/providers/index.ts +0 -13
  50. package/src/ai/providers/ollama.ts +0 -302
  51. package/src/ai/providers/openai.ts +0 -174
  52. package/src/ai/types.ts +0 -348
  53. package/src/bot.ts +0 -37
  54. package/src/built/adapter-process.ts +0 -177
  55. package/src/built/agent-preset.ts +0 -136
  56. package/src/built/ai-trigger.ts +0 -259
  57. package/src/built/command.ts +0 -108
  58. package/src/built/common-adapter-tools.ts +0 -242
  59. package/src/built/component.ts +0 -130
  60. package/src/built/config.ts +0 -335
  61. package/src/built/cron.ts +0 -156
  62. package/src/built/database.ts +0 -134
  63. package/src/built/dispatcher.ts +0 -496
  64. package/src/built/login-assist.ts +0 -131
  65. package/src/built/message-filter.ts +0 -390
  66. package/src/built/permission.ts +0 -151
  67. package/src/built/schema-feature.ts +0 -190
  68. package/src/built/skill.ts +0 -221
  69. package/src/built/tool.ts +0 -948
  70. package/src/command.ts +0 -87
  71. package/src/component.ts +0 -565
  72. package/src/cron.ts +0 -4
  73. package/src/errors.ts +0 -46
  74. package/src/feature.ts +0 -7
  75. package/src/index.ts +0 -53
  76. package/src/jsx-dev-runtime.ts +0 -2
  77. package/src/jsx-runtime.ts +0 -12
  78. package/src/jsx.ts +0 -135
  79. package/src/message.ts +0 -48
  80. package/src/models/system-log.ts +0 -20
  81. package/src/models/user.ts +0 -15
  82. package/src/notice.ts +0 -98
  83. package/src/plugin.ts +0 -896
  84. package/src/prompt.ts +0 -293
  85. package/src/request.ts +0 -95
  86. package/src/scheduler/index.ts +0 -19
  87. package/src/scheduler/scheduler.ts +0 -372
  88. package/src/scheduler/types.ts +0 -74
  89. package/src/tool-zod.ts +0 -115
  90. package/src/types-generator.ts +0 -78
  91. package/src/types.ts +0 -505
  92. package/src/utils.ts +0 -227
  93. package/tests/adapter.test.ts +0 -638
  94. package/tests/ai/ai-trigger.test.ts +0 -368
  95. package/tests/ai/providers.integration.test.ts +0 -227
  96. package/tests/ai/setup.ts +0 -308
  97. package/tests/ai/tool.test.ts +0 -800
  98. package/tests/bot.test.ts +0 -151
  99. package/tests/command.test.ts +0 -737
  100. package/tests/component-new.test.ts +0 -361
  101. package/tests/config.test.ts +0 -372
  102. package/tests/cron.test.ts +0 -82
  103. package/tests/dispatcher.test.ts +0 -293
  104. package/tests/errors.test.ts +0 -21
  105. package/tests/expression-evaluation.test.ts +0 -258
  106. package/tests/features-builtin.test.ts +0 -191
  107. package/tests/jsx-runtime.test.ts +0 -45
  108. package/tests/jsx.test.ts +0 -319
  109. package/tests/message-filter.test.ts +0 -566
  110. package/tests/message.test.ts +0 -402
  111. package/tests/notice.test.ts +0 -198
  112. package/tests/plugin.test.ts +0 -779
  113. package/tests/prompt.test.ts +0 -78
  114. package/tests/redos-protection.test.ts +0 -198
  115. package/tests/request.test.ts +0 -221
  116. package/tests/schema.test.ts +0 -248
  117. package/tests/skill-feature.test.ts +0 -179
  118. package/tests/test-utils.ts +0 -59
  119. package/tests/tool-feature.test.ts +0 -254
  120. package/tests/types.test.ts +0 -162
  121. package/tests/utils.test.ts +0 -135
  122. package/tsconfig.json +0 -24
@@ -1,372 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest'
2
- import { ConfigLoader } from '../src/built/config'
3
- import fs from 'fs'
4
- import path from 'path'
5
-
6
- describe('ConfigLoader', () => {
7
- const testConfigPath = path.join(process.cwd(), 'test-config.json')
8
-
9
- afterEach(() => {
10
- // 清理测试文件
11
- if (fs.existsSync(testConfigPath)) {
12
- fs.unlinkSync(testConfigPath)
13
- }
14
- })
15
-
16
- describe('Proxy behavior', () => {
17
- it('should handle array methods correctly', () => {
18
- const config = {
19
- items: ['item1', 'item2', 'item3'],
20
- bots: [
21
- { context: 'sandbox', name: 'bot1' },
22
- { context: 'sandbox', name: 'bot2' }
23
- ]
24
- }
25
-
26
- const loader = new ConfigLoader(testConfigPath, config)
27
- const proxiedData = loader.data
28
-
29
- // 测试数组的 map 方法
30
- expect(() => {
31
- const mapped = proxiedData.items.map((item: string) => item.toUpperCase())
32
- expect(mapped).toEqual(['ITEM1', 'ITEM2', 'ITEM3'])
33
- }).not.toThrow()
34
-
35
- // 测试数组的 filter 方法
36
- expect(() => {
37
- const filtered = proxiedData.bots.filter((bot: any) => bot.name === 'bot1')
38
- expect(filtered).toHaveLength(1)
39
- }).not.toThrow()
40
- })
41
-
42
- it('should handle nested objects', () => {
43
- const config = {
44
- database: {
45
- dialect: 'sqlite',
46
- filename: './data/bot.db'
47
- },
48
- http: {
49
- port: 8086,
50
- username: '${username}',
51
- password: '${password}'
52
- }
53
- }
54
-
55
- const loader = new ConfigLoader(testConfigPath, config)
56
- const proxiedData = loader.data
57
-
58
- expect(proxiedData.database.dialect).toBe('sqlite')
59
- expect(proxiedData.http.port).toBe(8086)
60
- })
61
-
62
- it('should resolve environment variables', () => {
63
- process.env.TEST_VAR = 'test_value'
64
-
65
- const config = {
66
- testValue: '${TEST_VAR}'
67
- }
68
-
69
- const loader = new ConfigLoader(testConfigPath, config)
70
- const proxiedData = loader.data
71
-
72
- expect(proxiedData.testValue).toBe('test_value')
73
-
74
- delete process.env.TEST_VAR
75
- })
76
-
77
- it('should handle escaped environment variables', () => {
78
- const config = {
79
- escapedValue: '\\${NOT_A_VAR}'
80
- }
81
-
82
- const loader = new ConfigLoader(testConfigPath, config)
83
- const proxiedData = loader.data
84
-
85
- expect(proxiedData.escapedValue).toBe('${NOT_A_VAR}')
86
- })
87
-
88
- it('should handle default values for missing env vars', () => {
89
- const config = {
90
- valueWithDefault: '${MISSING_VAR:default_value}'
91
- }
92
-
93
- const loader = new ConfigLoader(testConfigPath, config)
94
- const proxiedData = loader.data
95
-
96
- expect(proxiedData.valueWithDefault).toBe('default_value')
97
- })
98
-
99
- it('should not proxy function properties', () => {
100
- const config = {
101
- items: [1, 2, 3]
102
- }
103
-
104
- const loader = new ConfigLoader(testConfigPath, config)
105
- const proxiedData = loader.data
106
-
107
- // 确保数组方法可以正常调用
108
- expect(typeof proxiedData.items.map).toBe('function')
109
- expect(typeof proxiedData.items.filter).toBe('function')
110
- expect(typeof proxiedData.items.reduce).toBe('function')
111
- })
112
-
113
- it('should handle Set operations from array', () => {
114
- const config = {
115
- bots: [
116
- { context: 'sandbox', name: 'bot1' },
117
- { context: 'process', name: 'bot2' },
118
- { context: 'sandbox', name: 'bot3' }
119
- ]
120
- }
121
-
122
- const loader = new ConfigLoader(testConfigPath, config)
123
- const proxiedData = loader.data
124
-
125
- // 模拟 setup.ts 中的操作
126
- expect(() => {
127
- const contexts = new Set(proxiedData.bots.map((bot: any) => bot.context))
128
- expect(contexts.size).toBe(2)
129
- expect(contexts.has('sandbox')).toBe(true)
130
- expect(contexts.has('process')).toBe(true)
131
- }).not.toThrow()
132
- })
133
- })
134
-
135
- describe('Raw data access', () => {
136
- it('should provide raw data without proxy', () => {
137
- const config = {
138
- value: '${TEST_VAR}'
139
- }
140
-
141
- const loader = new ConfigLoader(testConfigPath, config)
142
-
143
- // raw 应该返回原始值,不解析环境变量
144
- expect(loader.raw.value).toBe('${TEST_VAR}')
145
-
146
- // data 应该尝试解析环境变量
147
- expect(loader.data.value).toBeTruthy()
148
- })
149
- })
150
-
151
- describe('File operations', () => {
152
- it('should save and load JSON config', () => {
153
- const jsonPath = path.join(process.cwd(), 'test-config.json')
154
- const config = {
155
- name: 'test',
156
- value: 123
157
- }
158
-
159
- const loader = new ConfigLoader(jsonPath, config)
160
- loader.save(jsonPath)
161
-
162
- expect(fs.existsSync(jsonPath)).toBe(true)
163
-
164
- const content = fs.readFileSync(jsonPath, 'utf-8')
165
- const parsed = JSON.parse(content)
166
- expect(parsed.name).toBe('test')
167
- expect(parsed.value).toBe(123)
168
-
169
- fs.unlinkSync(jsonPath)
170
- })
171
-
172
- it('should save and load YAML config', () => {
173
- const yamlPath = path.join(process.cwd(), 'test-config.yml')
174
- const config = {
175
- name: 'test',
176
- value: 123
177
- }
178
-
179
- const loader = new ConfigLoader(yamlPath, config)
180
- loader.save(yamlPath)
181
-
182
- expect(fs.existsSync(yamlPath)).toBe(true)
183
-
184
- fs.unlinkSync(yamlPath)
185
- })
186
-
187
- it('should auto-save on property change', () => {
188
- const config = {
189
- value: 'initial'
190
- }
191
-
192
- const loader = new ConfigLoader(testConfigPath, config)
193
- loader.save(testConfigPath)
194
-
195
- // 修改属性应该触发自动保存
196
- const proxiedData = loader.data
197
- proxiedData.value = 'changed'
198
-
199
- // 重新读取文件验证保存
200
- const content = fs.readFileSync(testConfigPath, 'utf-8')
201
- const parsed = JSON.parse(content)
202
- expect(parsed.value).toBe('changed')
203
- })
204
-
205
- it('should auto-save on property deletion', () => {
206
- const config = {
207
- value: 'test',
208
- other: 'keep'
209
- }
210
-
211
- const loader = new ConfigLoader(testConfigPath, config)
212
- loader.save(testConfigPath)
213
-
214
- // 删除属性应该触发自动保存
215
- const proxiedData = loader.data as any
216
- delete proxiedData.value
217
-
218
- // 重新读取文件验证保存
219
- const content = fs.readFileSync(testConfigPath, 'utf-8')
220
- const parsed = JSON.parse(content)
221
- expect(parsed.value).toBeUndefined()
222
- expect(parsed.other).toBe('keep')
223
- })
224
- })
225
-
226
- describe('ConfigService', () => {
227
- it('should load and cache configs', async () => {
228
- const { ConfigService } = await import('../src/built/config')
229
- const service = new ConfigService()
230
-
231
- const config = { test: 'value' }
232
- service.load('test-config.json', config)
233
-
234
- expect(service.configs.has('test-config.json')).toBe(true)
235
- })
236
-
237
- it('should throw error for unsupported format', async () => {
238
- const { ConfigService } = await import('../src/built/config')
239
- const service = new ConfigService()
240
-
241
- expect(() => {
242
- service.load('test.txt', {})
243
- }).toThrow('不支持的配置文件格式')
244
- })
245
-
246
- it('should get config data', async () => {
247
- const { ConfigService } = await import('../src/built/config')
248
- const service = new ConfigService()
249
-
250
- const config = { test: 'value' }
251
- service.load(testConfigPath, config)
252
-
253
- const data = service.get(testConfigPath)
254
- expect(data.test).toBe('value')
255
- })
256
-
257
- it('should get raw config data', async () => {
258
- const { ConfigService } = await import('../src/built/config')
259
- const service = new ConfigService()
260
-
261
- const config = { test: '${VAR}' }
262
- service.load(testConfigPath, config)
263
-
264
- const raw = service.getRaw(testConfigPath)
265
- expect(raw.test).toBe('${VAR}')
266
- })
267
-
268
- it('should update config data', async () => {
269
- const { ConfigService } = await import('../src/built/config')
270
- const service = new ConfigService()
271
-
272
- const config = { test: 'initial' }
273
- service.load(testConfigPath, config)
274
-
275
- service.set(testConfigPath, { test: 'updated' })
276
-
277
- const data = service.get(testConfigPath)
278
- expect(data.test).toBe('updated')
279
- })
280
-
281
- it('should throw error when getting non-existent config', async () => {
282
- const { ConfigService } = await import('../src/built/config')
283
- const service = new ConfigService()
284
-
285
- service.load(testConfigPath, { test: 'value' })
286
- service.configs.delete(testConfigPath) // 手动删除以模拟不存在的情况
287
-
288
- // 由于 get 会自动加载,我们需要测试 set
289
- expect(() => {
290
- service.set('non-existent.json', {})
291
- }).toThrow('配置文件 non-existent.json 未加载')
292
- })
293
-
294
- it('should auto-load config if not cached', async () => {
295
- const { ConfigService } = await import('../src/built/config')
296
- const service = new ConfigService()
297
-
298
- const config = { test: 'value' }
299
- // 先保存文件
300
- const loader = new ConfigLoader(testConfigPath, config)
301
- loader.save(testConfigPath)
302
-
303
- // 不预先加载,直接 get
304
- const data = service.get(testConfigPath, config)
305
- expect(data.test).toBe('value')
306
- expect(service.configs.has(testConfigPath)).toBe(true)
307
- })
308
- })
309
-
310
- describe('Extension detection', () => {
311
- it('should detect .json extension', () => {
312
- const loader = new ConfigLoader('config.json', {})
313
- expect(loader.extension).toBe('.json')
314
- })
315
-
316
- it('should detect .yml extension', () => {
317
- const loader = new ConfigLoader('config.yml', {})
318
- expect(loader.extension).toBe('.yml')
319
- })
320
-
321
- it('should detect .yaml extension', () => {
322
- const loader = new ConfigLoader('config.yaml', {})
323
- expect(loader.extension).toBe('.yaml')
324
- })
325
- })
326
- })
327
-
328
- // ============================================================================
329
- // ConfigFeature 补全测试
330
- // ============================================================================
331
- describe('ConfigFeature', () => {
332
- let feature: import('../src/built/config.js').ConfigFeature
333
-
334
- beforeEach(async () => {
335
- const { ConfigFeature } = await import('../src/built/config.js')
336
- feature = new ConfigFeature()
337
- })
338
-
339
- it('应有正确的元数据', () => {
340
- expect(feature.name).toBe('config')
341
- expect(feature.icon).toBe('Settings')
342
- expect(feature.desc).toBe('配置')
343
- })
344
-
345
- it('add 应添加配置记录', () => {
346
- const record = { key: 'debug', defaultValue: false }
347
- const dispose = feature.add(record, 'test-plugin')
348
- expect(feature.items).toHaveLength(1)
349
- expect(feature.items[0]).toBe(record)
350
- expect(typeof dispose).toBe('function')
351
- })
352
-
353
- it('toJSON 应返回正确结构', () => {
354
- feature.add({ key: 'debug', defaultValue: false }, 'test-plugin')
355
- feature.add({ key: 'port', defaultValue: 8080 }, 'test-plugin')
356
-
357
- const json = feature.toJSON()
358
- expect(json.name).toBe('config')
359
- expect(json.count).toBe(2)
360
- expect(json.items[0]).toEqual({ name: 'debug' })
361
- expect(json.items[1]).toEqual({ name: 'port' })
362
- })
363
-
364
- it('toJSON(pluginName) 应按插件过滤', () => {
365
- feature.add({ key: 'a', defaultValue: 1 }, 'plugin-a')
366
- feature.add({ key: 'b', defaultValue: 2 }, 'plugin-b')
367
-
368
- const json = feature.toJSON('plugin-a')
369
- expect(json.count).toBe(1)
370
- expect(json.items[0].name).toBe('a')
371
- })
372
- })
@@ -1,82 +0,0 @@
1
- /**
2
- * CronFeature 测试(Cron 类测试已迁移到 @zhin.js/kernel)
3
- */
4
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
5
- import { Cron } from '../src/cron'
6
-
7
- describe('CronFeature', () => {
8
- let feature: import('../src/built/cron.js').CronFeature
9
- let mockCallback: ReturnType<typeof vi.fn>
10
-
11
- beforeEach(async () => {
12
- vi.useFakeTimers()
13
- mockCallback = vi.fn()
14
- const { CronFeature } = await import('../src/built/cron.js')
15
- feature = new CronFeature()
16
- })
17
-
18
- afterEach(() => {
19
- feature?.dispose()
20
- vi.useRealTimers()
21
- })
22
-
23
- it('add 应自动启动任务', () => {
24
- const cron = new Cron('* * * * * *', mockCallback)
25
- feature.add(cron, 'test-plugin')
26
- expect(cron.running).toBe(true)
27
- expect(feature.items).toHaveLength(1)
28
- })
29
-
30
- it('add 应返回 dispose 函数', () => {
31
- const cron = new Cron('* * * * * *', mockCallback)
32
- const dispose = feature.add(cron, 'test-plugin')
33
- expect(typeof dispose).toBe('function')
34
- })
35
-
36
- it('remove 应自动停止任务', () => {
37
- const cron = new Cron('* * * * * *', mockCallback)
38
- feature.add(cron, 'test-plugin')
39
- feature.remove(cron)
40
- expect(cron.running).toBe(false)
41
- expect(feature.items).toHaveLength(0)
42
- })
43
-
44
- it('stopAll 应停止所有任务', () => {
45
- const cron1 = new Cron('* * * * * *', mockCallback)
46
- const cron2 = new Cron('*/2 * * * * *', mockCallback)
47
- feature.add(cron1, 'p1')
48
- feature.add(cron2, 'p2')
49
- feature.stopAll()
50
- expect(cron1.running).toBe(false)
51
- expect(cron2.running).toBe(false)
52
- })
53
-
54
- it('startAll 应启动所有已停止的任务', () => {
55
- const cron1 = new Cron('* * * * * *', mockCallback)
56
- const cron2 = new Cron('*/2 * * * * *', mockCallback)
57
- feature.add(cron1, 'p1')
58
- feature.add(cron2, 'p2')
59
- feature.stopAll()
60
- feature.startAll()
61
- expect(cron1.running).toBe(true)
62
- expect(cron2.running).toBe(true)
63
- })
64
-
65
- it('toJSON 应返回正确结构', () => {
66
- const cron = new Cron('* * * * * *', mockCallback)
67
- feature.add(cron, 'test-plugin')
68
- const json = feature.toJSON()
69
- expect(json.name).toBe('cron')
70
- expect(json.icon).toBe('Clock')
71
- expect(json.count).toBe(1)
72
- expect(json.items[0]).toHaveProperty('expression')
73
- expect(json.items[0]).toHaveProperty('running', true)
74
- })
75
-
76
- it('dispose 应停止所有任务', () => {
77
- const cron = new Cron('* * * * * *', mockCallback)
78
- feature.add(cron, 'test-plugin')
79
- feature.dispose()
80
- expect(cron.running).toBe(false)
81
- })
82
- })