@zhin.js/agent 0.0.20 → 0.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 (116) hide show
  1. package/README.md +5 -2
  2. package/lib/cron-engine.d.ts +16 -1
  3. package/lib/cron-engine.d.ts.map +1 -1
  4. package/lib/cron-engine.js +47 -13
  5. package/lib/cron-engine.js.map +1 -1
  6. package/lib/discover-skills.d.ts +3 -1
  7. package/lib/discover-skills.d.ts.map +1 -1
  8. package/lib/discover-skills.js +7 -9
  9. package/lib/discover-skills.js.map +1 -1
  10. package/lib/discover-tools.d.ts +1 -6
  11. package/lib/discover-tools.d.ts.map +1 -1
  12. package/lib/discover-tools.js +2 -6
  13. package/lib/discover-tools.js.map +1 -1
  14. package/lib/index.d.ts +2 -4
  15. package/lib/index.d.ts.map +1 -1
  16. package/lib/index.js +1 -2
  17. package/lib/index.js.map +1 -1
  18. package/lib/init/create-zhin-agent.d.ts.map +1 -1
  19. package/lib/init/create-zhin-agent.js +58 -21
  20. package/lib/init/create-zhin-agent.js.map +1 -1
  21. package/lib/init/register-ai-trigger.d.ts.map +1 -1
  22. package/lib/init/register-ai-trigger.js +10 -3
  23. package/lib/init/register-ai-trigger.js.map +1 -1
  24. package/lib/init/register-builtin-tools.d.ts.map +1 -1
  25. package/lib/init/register-builtin-tools.js +46 -14
  26. package/lib/init/register-builtin-tools.js.map +1 -1
  27. package/lib/init/register-db-models.d.ts.map +1 -1
  28. package/lib/init/register-db-models.js +1 -3
  29. package/lib/init/register-db-models.js.map +1 -1
  30. package/lib/init/register-db-upgrade.d.ts.map +1 -1
  31. package/lib/init/register-db-upgrade.js +1 -8
  32. package/lib/init/register-db-upgrade.js.map +1 -1
  33. package/lib/init/register-management-tools.d.ts.map +1 -1
  34. package/lib/init/register-management-tools.js +33 -20
  35. package/lib/init/register-management-tools.js.map +1 -1
  36. package/lib/service.d.ts +4 -0
  37. package/lib/service.d.ts.map +1 -1
  38. package/lib/service.js +3 -8
  39. package/lib/service.js.map +1 -1
  40. package/lib/zhin-agent/builtin-tools.d.ts +0 -2
  41. package/lib/zhin-agent/builtin-tools.d.ts.map +1 -1
  42. package/lib/zhin-agent/builtin-tools.js +0 -55
  43. package/lib/zhin-agent/builtin-tools.js.map +1 -1
  44. package/lib/zhin-agent/config.d.ts +4 -1
  45. package/lib/zhin-agent/config.d.ts.map +1 -1
  46. package/lib/zhin-agent/config.js +2 -1
  47. package/lib/zhin-agent/config.js.map +1 -1
  48. package/lib/zhin-agent/index.d.ts +11 -6
  49. package/lib/zhin-agent/index.d.ts.map +1 -1
  50. package/lib/zhin-agent/index.js +147 -81
  51. package/lib/zhin-agent/index.js.map +1 -1
  52. package/lib/zhin-agent/prompt.d.ts.map +1 -1
  53. package/lib/zhin-agent/prompt.js +31 -76
  54. package/lib/zhin-agent/prompt.js.map +1 -1
  55. package/lib/zhin-agent/tool-collector.d.ts.map +1 -1
  56. package/lib/zhin-agent/tool-collector.js +7 -7
  57. package/lib/zhin-agent/tool-collector.js.map +1 -1
  58. package/package.json +7 -4
  59. package/CHANGELOG.md +0 -170
  60. package/lib/follow-up.d.ts +0 -131
  61. package/lib/follow-up.d.ts.map +0 -1
  62. package/lib/follow-up.js +0 -265
  63. package/lib/follow-up.js.map +0 -1
  64. package/src/agent.ts +0 -6
  65. package/src/bootstrap.ts +0 -309
  66. package/src/builtin-tools.ts +0 -958
  67. package/src/compaction.ts +0 -28
  68. package/src/context-manager.ts +0 -15
  69. package/src/conversation-memory.ts +0 -5
  70. package/src/cron-engine.ts +0 -338
  71. package/src/discover-agents.ts +0 -138
  72. package/src/discover-skills.ts +0 -325
  73. package/src/discover-tools.ts +0 -302
  74. package/src/discovery-utils.ts +0 -96
  75. package/src/file-policy.ts +0 -333
  76. package/src/follow-up.ts +0 -357
  77. package/src/hooks.ts +0 -223
  78. package/src/index.ts +0 -183
  79. package/src/init/create-zhin-agent.ts +0 -136
  80. package/src/init/register-ai-service.ts +0 -53
  81. package/src/init/register-ai-trigger.ts +0 -253
  82. package/src/init/register-builtin-tools.ts +0 -308
  83. package/src/init/register-db-models.ts +0 -31
  84. package/src/init/register-db-upgrade.ts +0 -77
  85. package/src/init/register-management-tools.ts +0 -71
  86. package/src/init/register-message-recorder.ts +0 -31
  87. package/src/init/register-tool-service.ts +0 -9
  88. package/src/init/shared-refs.ts +0 -20
  89. package/src/init/types.ts +0 -18
  90. package/src/init.ts +0 -50
  91. package/src/output.ts +0 -15
  92. package/src/rate-limiter.ts +0 -5
  93. package/src/service.ts +0 -224
  94. package/src/session.ts +0 -13
  95. package/src/storage.ts +0 -9
  96. package/src/subagent.ts +0 -209
  97. package/src/tone-detector.ts +0 -5
  98. package/src/tools.ts +0 -214
  99. package/src/user-profile.ts +0 -182
  100. package/src/zhin-agent/builtin-tools.ts +0 -247
  101. package/src/zhin-agent/config.ts +0 -121
  102. package/src/zhin-agent/exec-policy.ts +0 -285
  103. package/src/zhin-agent/index.ts +0 -559
  104. package/src/zhin-agent/prompt.ts +0 -305
  105. package/src/zhin-agent/tool-collector.ts +0 -249
  106. package/tests/ai/follow-up.test.ts +0 -175
  107. package/tests/ai/integration.test.ts +0 -582
  108. package/tests/ai/multimodal.test.ts +0 -106
  109. package/tests/ai/setup.ts +0 -186
  110. package/tests/ai/subagent.test.ts +0 -270
  111. package/tests/ai/tools-builtin.test.ts +0 -310
  112. package/tests/ai/user-profile.test.ts +0 -73
  113. package/tests/ai/zhin-agent.test.ts +0 -306
  114. package/tests/exec-policy.test.ts +0 -355
  115. package/tests/file-policy.test.ts +0 -405
  116. package/tsconfig.json +0 -22
@@ -1,405 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import {
3
- checkFileAccess, assertFileAccess, checkBashCommandSafety, shellEscape,
4
- isBlockedDevicePath, classifyBashCommand, isFileStale,
5
- MAX_READ_FILE_SIZE, MAX_EDIT_FILE_SIZE,
6
- } from '../src/file-policy.js';
7
-
8
- describe('file-policy', () => {
9
- // ── checkFileAccess ──
10
-
11
- describe('checkFileAccess', () => {
12
- describe('应阻止敏感文件', () => {
13
- const blocked = [
14
- '.env',
15
- '.env.local',
16
- '.env.production',
17
- '.env.development.local',
18
- 'id_rsa',
19
- 'id_ed25519',
20
- 'server.pem',
21
- 'private.key',
22
- 'cert.p12',
23
- 'keystore.pfx',
24
- 'store.jks',
25
- 'app.keystore',
26
- '.npmrc',
27
- '.pypirc',
28
- '.netrc',
29
- 'credentials',
30
- 'credentials.json',
31
- 'service_account.json',
32
- 'service-account-key.json',
33
- 'token.json',
34
- '.pgpass',
35
- '.my.cnf',
36
- '.passwd',
37
- '.bash_history',
38
- '.zsh_history',
39
- '.node_repl_history',
40
- '.python_history',
41
- ];
42
-
43
- for (const name of blocked) {
44
- it(`阻止 ${name}`, () => {
45
- const result = checkFileAccess(`/home/user/${name}`);
46
- expect(result.allowed).toBe(false);
47
- expect(result.reason).toBeTruthy();
48
- });
49
- }
50
- });
51
-
52
- describe('应阻止敏感目录', () => {
53
- const blockedPaths = [
54
- '/home/user/.ssh/id_rsa.pub',
55
- '/home/user/.gnupg/secring.gpg',
56
- '/home/user/.aws/credentials',
57
- '/home/user/.azure/config',
58
- '/home/user/.gcloud/properties',
59
- '/home/user/.kube/config',
60
- '/root/.ssh/authorized_keys',
61
- 'data/memory/notes.md', // data 目录为敏感目录,禁止访问
62
- ];
63
-
64
- for (const p of blockedPaths) {
65
- it(`阻止 ${p}`, () => {
66
- const result = checkFileAccess(p);
67
- expect(result.allowed).toBe(false);
68
- });
69
- }
70
- });
71
-
72
- describe('应阻止系统敏感路径', () => {
73
- it('阻止 /etc/shadow', () => {
74
- expect(checkFileAccess('/etc/shadow').allowed).toBe(false);
75
- });
76
-
77
- it('阻止 /etc/gshadow', () => {
78
- expect(checkFileAccess('/etc/gshadow').allowed).toBe(false);
79
- });
80
-
81
- it('阻止 /etc/ssl/private/key.pem', () => {
82
- expect(checkFileAccess('/etc/ssl/private/key.pem').allowed).toBe(false);
83
- });
84
- });
85
-
86
- describe('应允许正常文件', () => {
87
- const allowed = [
88
- '/home/user/project/src/index.ts',
89
- '/home/user/project/package.json',
90
- '/home/user/project/README.md',
91
- '/home/user/project/tsconfig.json',
92
- './src/utils.ts',
93
- '/tmp/test.txt',
94
- ];
95
-
96
- for (const p of allowed) {
97
- it(`允许 ${p}`, () => {
98
- expect(checkFileAccess(p).allowed).toBe(true);
99
- });
100
- }
101
- });
102
- });
103
-
104
- // ── assertFileAccess ──
105
-
106
- describe('assertFileAccess', () => {
107
- it('对敏感文件抛出错误', () => {
108
- expect(() => assertFileAccess('/home/user/.env')).toThrow('敏感文件');
109
- });
110
-
111
- it('对正常文件不抛出', () => {
112
- expect(() => assertFileAccess('/home/user/src/index.ts')).not.toThrow();
113
- });
114
- });
115
-
116
- // ── checkBashCommandSafety ──
117
-
118
- describe('checkBashCommandSafety', () => {
119
- describe('应阻止环境变量泄漏命令', () => {
120
- const blocked = [
121
- 'env',
122
- 'printenv',
123
- 'export',
124
- 'set',
125
- 'env | grep SECRET',
126
- 'printenv TOKEN',
127
- ' env ',
128
- ];
129
-
130
- for (const cmd of blocked) {
131
- it(`阻止: ${cmd}`, () => {
132
- const result = checkBashCommandSafety(cmd);
133
- expect(result.safe).toBe(false);
134
- expect(result.reason).toContain('环境变量');
135
- });
136
- }
137
- });
138
-
139
- describe('应阻止 echo 敏感环境变量', () => {
140
- const blocked = [
141
- 'echo $SECRET_KEY',
142
- 'echo ${API_KEY}',
143
- 'echo $TOKEN',
144
- 'echo $PASSWORD',
145
- 'printf "%s" $AUTH_TOKEN',
146
- 'echo $MY_CREDENTIAL',
147
- ];
148
-
149
- for (const cmd of blocked) {
150
- it(`阻止: ${cmd}`, () => {
151
- expect(checkBashCommandSafety(cmd).safe).toBe(false);
152
- });
153
- }
154
- });
155
-
156
- describe('应阻止 cat 敏感文件', () => {
157
- const blocked = [
158
- 'cat .env',
159
- 'cat /path/to/.env.local',
160
- 'cat server.pem',
161
- 'cat private.key',
162
- 'cat cert.p12',
163
- ];
164
-
165
- for (const cmd of blocked) {
166
- it(`阻止: ${cmd}`, () => {
167
- expect(checkBashCommandSafety(cmd).safe).toBe(false);
168
- });
169
- }
170
- });
171
-
172
- describe('应允许安全命令', () => {
173
- const safe = [
174
- 'ls -la',
175
- 'cat README.md',
176
- 'node --version',
177
- 'pnpm install',
178
- 'git status',
179
- 'tsc --build',
180
- 'echo "hello world"',
181
- 'grep -rn "function" src/',
182
- ];
183
-
184
- for (const cmd of safe) {
185
- it(`允许: ${cmd}`, () => {
186
- expect(checkBashCommandSafety(cmd).safe).toBe(true);
187
- });
188
- }
189
- });
190
- });
191
-
192
- // ── shellEscape ──
193
-
194
- describe('shellEscape', () => {
195
- it('普通字符串加引号', () => {
196
- expect(shellEscape('hello')).toBe("'hello'");
197
- });
198
-
199
- it('转义单引号', () => {
200
- expect(shellEscape("it's")).toBe("'it'\\''s'");
201
- });
202
-
203
- it('空字符串', () => {
204
- expect(shellEscape('')).toBe("''");
205
- });
206
-
207
- it('含特殊字符', () => {
208
- const escaped = shellEscape('$(rm -rf /)');
209
- expect(escaped).toBe("'$(rm -rf /)'");
210
- // 被单引号包裹后 shell 不会执行内部的命令替换
211
- });
212
-
213
- it('含分号', () => {
214
- expect(shellEscape('foo; rm -rf /')).toBe("'foo; rm -rf /'");
215
- });
216
-
217
- it('含反引号', () => {
218
- expect(shellEscape('`whoami`')).toBe("'`whoami`'");
219
- });
220
- });
221
-
222
- // ── isBlockedDevicePath(设备路径拦截)──
223
-
224
- describe('isBlockedDevicePath', () => {
225
- describe('应阻止危险设备路径', () => {
226
- const blocked = [
227
- '/dev/zero',
228
- '/dev/random',
229
- '/dev/urandom',
230
- '/dev/full',
231
- '/dev/stdin',
232
- '/dev/tty',
233
- '/dev/console',
234
- '/dev/stdout',
235
- '/dev/stderr',
236
- '/dev/fd/0',
237
- '/dev/fd/1',
238
- '/dev/fd/2',
239
- ];
240
- for (const p of blocked) {
241
- it(`阻止 ${p}`, () => {
242
- expect(isBlockedDevicePath(p)).toBe(true);
243
- });
244
- }
245
- });
246
-
247
- describe('应阻止 Linux /proc/ fd 别名', () => {
248
- it('阻止 /proc/self/fd/0', () => {
249
- expect(isBlockedDevicePath('/proc/self/fd/0')).toBe(true);
250
- });
251
- it('阻止 /proc/1234/fd/1', () => {
252
- expect(isBlockedDevicePath('/proc/1234/fd/1')).toBe(true);
253
- });
254
- it('阻止 /proc/self/fd/2', () => {
255
- expect(isBlockedDevicePath('/proc/self/fd/2')).toBe(true);
256
- });
257
- });
258
-
259
- describe('应允许安全设备路径', () => {
260
- it('允许 /dev/null', () => {
261
- expect(isBlockedDevicePath('/dev/null')).toBe(false);
262
- });
263
- it('允许普通文件', () => {
264
- expect(isBlockedDevicePath('/home/user/file.txt')).toBe(false);
265
- });
266
- it('允许 /proc/self/fd/3', () => {
267
- expect(isBlockedDevicePath('/proc/self/fd/3')).toBe(false);
268
- });
269
- });
270
- });
271
-
272
- // ── classifyBashCommand(命令读写分类)──
273
-
274
- describe('classifyBashCommand', () => {
275
- describe('只读搜索命令', () => {
276
- it('grep 是搜索', () => {
277
- const r = classifyBashCommand('grep -rn pattern src/');
278
- expect(r.isSearch).toBe(true);
279
- expect(r.isReadOnly).toBe(true);
280
- });
281
-
282
- it('rg 是搜索', () => {
283
- const r = classifyBashCommand('rg "hello" .');
284
- expect(r.isSearch).toBe(true);
285
- expect(r.isReadOnly).toBe(true);
286
- });
287
-
288
- it('find 是搜索', () => {
289
- const r = classifyBashCommand('find . -name "*.ts"');
290
- expect(r.isSearch).toBe(true);
291
- expect(r.isReadOnly).toBe(true);
292
- });
293
- });
294
-
295
- describe('只读读取命令', () => {
296
- it('cat 是读取', () => {
297
- const r = classifyBashCommand('cat README.md');
298
- expect(r.isRead).toBe(true);
299
- expect(r.isReadOnly).toBe(true);
300
- });
301
-
302
- it('head 是读取', () => {
303
- const r = classifyBashCommand('head -50 file.ts');
304
- expect(r.isRead).toBe(true);
305
- expect(r.isReadOnly).toBe(true);
306
- });
307
-
308
- it('wc -l 是读取', () => {
309
- expect(classifyBashCommand('wc -l file.txt').isRead).toBe(true);
310
- });
311
-
312
- it('jq 是读取', () => {
313
- expect(classifyBashCommand('jq .name package.json').isRead).toBe(true);
314
- });
315
- });
316
-
317
- describe('只读列出命令', () => {
318
- it('ls 是列出', () => {
319
- const r = classifyBashCommand('ls -la');
320
- expect(r.isList).toBe(true);
321
- expect(r.isReadOnly).toBe(true);
322
- });
323
-
324
- it('tree 是列出', () => {
325
- expect(classifyBashCommand('tree .').isList).toBe(true);
326
- });
327
- });
328
-
329
- describe('管道组合', () => {
330
- it('cat | grep 是只读', () => {
331
- const r = classifyBashCommand('cat file.txt | grep pattern');
332
- expect(r.isReadOnly).toBe(true);
333
- });
334
-
335
- it('cat file && echo done 是只读(echo 是中性命令)', () => {
336
- const r = classifyBashCommand('cat file && echo done');
337
- expect(r.isReadOnly).toBe(true);
338
- });
339
-
340
- it('cat | sort | uniq 是只读', () => {
341
- expect(classifyBashCommand('cat file | sort | uniq').isReadOnly).toBe(true);
342
- });
343
- });
344
-
345
- describe('写/执行命令', () => {
346
- it('rm 不是只读', () => {
347
- expect(classifyBashCommand('rm file.txt').isReadOnly).toBe(false);
348
- });
349
-
350
- it('npm install 不是只读', () => {
351
- expect(classifyBashCommand('npm install').isReadOnly).toBe(false);
352
- });
353
-
354
- it('git push 不是只读', () => {
355
- expect(classifyBashCommand('git push').isReadOnly).toBe(false);
356
- });
357
-
358
- it('混合管道 cat | xargs rm 不是只读', () => {
359
- expect(classifyBashCommand('cat files.txt | xargs rm').isReadOnly).toBe(false);
360
- });
361
- });
362
-
363
- describe('纯中性命令', () => {
364
- it('echo "hello" 是只读', () => {
365
- expect(classifyBashCommand('echo "hello"').isReadOnly).toBe(true);
366
- });
367
-
368
- it(': (noop) 是只读', () => {
369
- expect(classifyBashCommand(':').isReadOnly).toBe(true);
370
- });
371
- });
372
- });
373
-
374
- // ── isFileStale ──
375
-
376
- describe('isFileStale', () => {
377
- it('相同 mtime 不是 stale', () => {
378
- expect(isFileStale(1000, 1000)).toBe(false);
379
- });
380
-
381
- it('1ms 误差内不是 stale', () => {
382
- expect(isFileStale(1000, 1000.5)).toBe(false);
383
- });
384
-
385
- it('超过 1ms 差异是 stale', () => {
386
- expect(isFileStale(1000, 1002)).toBe(true);
387
- });
388
-
389
- it('mtime 变小也是 stale', () => {
390
- expect(isFileStale(1000, 997)).toBe(true);
391
- });
392
- });
393
-
394
- // ── 常量导出 ──
395
-
396
- describe('常量', () => {
397
- it('MAX_READ_FILE_SIZE 为 256 MiB', () => {
398
- expect(MAX_READ_FILE_SIZE).toBe(256 * 1024 * 1024);
399
- });
400
-
401
- it('MAX_EDIT_FILE_SIZE 为 1 GiB', () => {
402
- expect(MAX_EDIT_FILE_SIZE).toBe(1024 * 1024 * 1024);
403
- });
404
- });
405
- });
package/tsconfig.json DELETED
@@ -1,22 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "outDir": "./lib",
7
- "rootDir": "./src",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "resolveJsonModule": true,
13
- "isolatedModules": true,
14
- "allowSyntheticDefaultImports": true,
15
- "declaration": true,
16
- "declarationMap": true,
17
- "sourceMap": true,
18
- "verbatimModuleSyntax": false
19
- },
20
- "include": ["src/**/*"],
21
- "exclude": ["lib", "node_modules"]
22
- }