zhitalk 0.0.0 → 0.0.3

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 (83) hide show
  1. package/CLAUDE.md +98 -0
  2. package/README.md +36 -1
  3. package/dist/agent/agent.d.ts +24 -0
  4. package/dist/agent/agent.js +345 -0
  5. package/dist/agent/cli.d.ts +1 -0
  6. package/dist/agent/cli.js +185 -0
  7. package/dist/agent/colors.d.ts +19 -0
  8. package/dist/agent/colors.js +81 -0
  9. package/dist/agent/commands.d.ts +7 -0
  10. package/dist/agent/commands.js +69 -0
  11. package/dist/agent/config.d.ts +38 -0
  12. package/dist/agent/config.js +116 -0
  13. package/dist/agent/context.d.ts +3 -0
  14. package/dist/agent/context.js +107 -0
  15. package/dist/agent/db.d.ts +21 -0
  16. package/dist/agent/db.js +159 -0
  17. package/dist/agent/hooks.d.ts +27 -0
  18. package/dist/agent/hooks.js +115 -0
  19. package/dist/agent/mcp/client.d.ts +25 -0
  20. package/dist/agent/mcp/client.js +113 -0
  21. package/dist/agent/mcp/index.d.ts +4 -0
  22. package/dist/agent/mcp/index.js +27 -0
  23. package/dist/agent/mcp/wrapper.d.ts +7 -0
  24. package/dist/agent/mcp/wrapper.js +25 -0
  25. package/dist/agent/model.d.ts +5 -0
  26. package/dist/agent/model.js +31 -0
  27. package/dist/agent/permission/dangerous-path.json +115 -0
  28. package/dist/agent/permission/exec.d.ts +11 -0
  29. package/dist/agent/permission/exec.js +34 -0
  30. package/dist/agent/permission/is-dangerous-path.d.ts +1 -0
  31. package/dist/agent/permission/is-dangerous-path.js +53 -0
  32. package/dist/agent/permission/is-safe-domains.d.ts +1 -0
  33. package/dist/agent/permission/is-safe-domains.js +142 -0
  34. package/dist/agent/permission/network.d.ts +8 -0
  35. package/dist/agent/permission/network.js +14 -0
  36. package/dist/agent/permission/read.d.ts +9 -0
  37. package/dist/agent/permission/read.js +17 -0
  38. package/dist/agent/permission/util.d.ts +11 -0
  39. package/dist/agent/permission/util.js +160 -0
  40. package/dist/agent/permission/write.d.ts +11 -0
  41. package/dist/agent/permission/write.js +21 -0
  42. package/dist/agent/prompt.d.ts +1 -0
  43. package/dist/agent/prompt.js +50 -0
  44. package/dist/agent/skills.d.ts +8 -0
  45. package/dist/agent/skills.js +91 -0
  46. package/dist/agent/tools/agent_tool.d.ts +3 -0
  47. package/dist/agent/tools/agent_tool.js +44 -0
  48. package/dist/agent/tools/exec_tool.d.ts +3 -0
  49. package/dist/agent/tools/exec_tool.js +28 -0
  50. package/dist/agent/tools/load_skill_tool.d.ts +3 -0
  51. package/dist/agent/tools/load_skill_tool.js +15 -0
  52. package/dist/agent/tools/memory_create_tool.d.ts +6 -0
  53. package/dist/agent/tools/memory_create_tool.js +37 -0
  54. package/dist/agent/tools/memory_delete_tool.d.ts +3 -0
  55. package/dist/agent/tools/memory_delete_tool.js +28 -0
  56. package/dist/agent/tools/memory_retrieve_tool.d.ts +4 -0
  57. package/dist/agent/tools/memory_retrieve_tool.js +24 -0
  58. package/dist/agent/tools/profile_update_tool.d.ts +3 -0
  59. package/dist/agent/tools/profile_update_tool.js +50 -0
  60. package/dist/agent/tools/read_file_tool.d.ts +3 -0
  61. package/dist/agent/tools/read_file_tool.js +16 -0
  62. package/dist/agent/tools/run_js_tool.d.ts +3 -0
  63. package/dist/agent/tools/run_js_tool.js +36 -0
  64. package/dist/agent/tools/run_py_tool.d.ts +3 -0
  65. package/dist/agent/tools/run_py_tool.js +27 -0
  66. package/dist/agent/tools/search.d.ts +3 -0
  67. package/dist/agent/tools/search.js +10 -0
  68. package/dist/agent/tools/web_fetch_tool.d.ts +3 -0
  69. package/dist/agent/tools/web_fetch_tool.js +33 -0
  70. package/dist/agent/tools/web_search_tool.d.ts +3 -0
  71. package/dist/agent/tools/web_search_tool.js +38 -0
  72. package/dist/agent/tools/write_file_tool.d.ts +4 -0
  73. package/dist/agent/tools/write_file_tool.js +15 -0
  74. package/dist/agent/tools.d.ts +8 -0
  75. package/dist/agent/tools.js +193 -0
  76. package/dist/agent/utils.d.ts +2 -0
  77. package/dist/agent/utils.js +30 -0
  78. package/dist/index.d.ts +2 -0
  79. package/dist/index.js +72 -0
  80. package/dist/install.d.ts +1 -0
  81. package/dist/install.js +108 -0
  82. package/package.json +43 -6
  83. package/index.js +0 -1
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkExecPermission = checkExecPermission;
4
+ const util_1 = require("./util");
5
+ function checkExecPermission(toolCall) {
6
+ const command = toolCall.args?.command;
7
+ if (typeof command !== 'string') {
8
+ return { action: 'confirm' };
9
+ }
10
+ if ((0, util_1.isSafeCommand)(command)) {
11
+ return { action: 'allow' };
12
+ }
13
+ if ((0, util_1.isChangingDirectory)(command)) {
14
+ return {
15
+ action: 'block',
16
+ reason: `命令包含切换目录操作,为防止目录逃逸,禁止执行。如有需要请手动操作。`,
17
+ };
18
+ }
19
+ const scriptCheck = (0, util_1.isScriptExecution)(command);
20
+ if (scriptCheck.blocked) {
21
+ return {
22
+ action: 'block',
23
+ reason: scriptCheck.reason,
24
+ };
25
+ }
26
+ const dangerCheck = (0, util_1.isDangerousOperation)(command);
27
+ if (dangerCheck.blocked) {
28
+ return {
29
+ action: 'block',
30
+ reason: dangerCheck.reason,
31
+ };
32
+ }
33
+ return { action: 'confirm' };
34
+ }
@@ -0,0 +1 @@
1
+ export declare function isDangerousPath(filepath: string): boolean;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.isDangerousPath = isDangerousPath;
7
+ const path_1 = __importDefault(require("path"));
8
+ const os_1 = __importDefault(require("os"));
9
+ const dangerous_path_json_1 = __importDefault(require("./dangerous-path.json"));
10
+ function expandPath(filepath) {
11
+ let expanded = filepath;
12
+ if (expanded.startsWith('~')) {
13
+ expanded = path_1.default.join(os_1.default.homedir(), expanded.slice(1));
14
+ }
15
+ expanded = expanded.replace(/%USERPROFILE%/gi, os_1.default.homedir());
16
+ expanded = expanded.replace(/%APPDATA%/gi, process.env.APPDATA || path_1.default.join(os_1.default.homedir(), 'AppData', 'Roaming'));
17
+ expanded = expanded.replace(/%LOCALAPPDATA%/gi, process.env.LOCALAPPDATA || path_1.default.join(os_1.default.homedir(), 'AppData', 'Local'));
18
+ if (!path_1.default.isAbsolute(expanded)) {
19
+ expanded = path_1.default.resolve(expanded);
20
+ }
21
+ expanded = path_1.default.normalize(expanded);
22
+ return expanded;
23
+ }
24
+ function globToRegex(pattern) {
25
+ const escaped = pattern
26
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
27
+ .replace(/\*/g, '[^\\\\/]*');
28
+ return new RegExp(`^${escaped}(?:[\\\\/].*)?$`);
29
+ }
30
+ function isDangerousPath(filepath) {
31
+ const platform = process.platform === 'win32'
32
+ ? 'windows'
33
+ : process.platform === 'darwin'
34
+ ? 'macos'
35
+ : 'linux';
36
+ const dangerousList = dangerous_path_json_1.default[platform];
37
+ const expandedInput = expandPath(filepath);
38
+ for (const dangerous of dangerousList) {
39
+ const expandedDangerous = expandPath(dangerous);
40
+ if (dangerous.includes('*')) {
41
+ const regex = globToRegex(expandedDangerous);
42
+ if (regex.test(expandedInput))
43
+ return true;
44
+ }
45
+ else {
46
+ if (expandedInput === expandedDangerous)
47
+ return true;
48
+ if (expandedInput.startsWith(expandedDangerous + path_1.default.sep))
49
+ return true;
50
+ }
51
+ }
52
+ return false;
53
+ }
@@ -0,0 +1 @@
1
+ export declare function isSafeDomain(url: string): boolean;
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isSafeDomain = isSafeDomain;
4
+ const commonDomainsCNForDevelopers = [
5
+ // 搜索 / AI
6
+ 'google.com',
7
+ 'baidu.com',
8
+ 'bing.com',
9
+ 'openai.com',
10
+ 'claude.ai',
11
+ 'anthropic.com',
12
+ 'perplexity.ai',
13
+ 'kimi.moonshot.cn',
14
+ 'doubao.com',
15
+ 'deepseek.com',
16
+ // 代码托管 / 开发平台
17
+ 'github.com',
18
+ 'gitlab.com',
19
+ 'gitee.com',
20
+ 'bitbucket.org',
21
+ // 技术社区
22
+ 'stackoverflow.com',
23
+ 'v2ex.com',
24
+ 'zhihu.com',
25
+ 'juejin.cn',
26
+ 'csdn.net',
27
+ 'oschina.net',
28
+ 'segmentfault.com',
29
+ 'infoq.cn',
30
+ '51cto.com',
31
+ 'cnblogs.com',
32
+ 'linux.do',
33
+ 'reddit.com',
34
+ 'medium.com',
35
+ 'dev.to',
36
+ 'hackernoon.com',
37
+ // 文档 / API / 开源
38
+ 'npmjs.com',
39
+ 'nodejs.org',
40
+ 'python.org',
41
+ 'pypi.org',
42
+ 'rust-lang.org',
43
+ 'golang.org',
44
+ 'docker.com',
45
+ 'kubernetes.io',
46
+ 'mozilla.org',
47
+ 'developer.mozilla.org',
48
+ 'w3.org',
49
+ 'react.dev',
50
+ 'nextjs.org',
51
+ 'vuejs.org',
52
+ 'nuxt.com',
53
+ 'tailwindcss.com',
54
+ 'vercel.com',
55
+ 'supabase.com',
56
+ 'cloudflare.com',
57
+ // 云服务 / DevOps
58
+ 'aliyun.com',
59
+ 'tencent.com',
60
+ 'huaweicloud.com',
61
+ 'aws.amazon.com',
62
+ 'azure.com',
63
+ 'googleapis.com',
64
+ 'firebase.google.com',
65
+ 'netlify.com',
66
+ 'railway.app',
67
+ 'render.com',
68
+ // CI/CD / 工程工具
69
+ 'jenkins.io',
70
+ 'sonarqube.org',
71
+ 'sentry.io',
72
+ 'postman.com',
73
+ 'swagger.io',
74
+ 'openapi.org',
75
+ // 数据库 / 中间件
76
+ 'mysql.com',
77
+ 'postgresql.org',
78
+ 'redis.io',
79
+ 'mongodb.com',
80
+ 'sqlite.org',
81
+ 'apache.org',
82
+ 'elastic.co',
83
+ 'rabbitmq.com',
84
+ 'kafka.apache.org',
85
+ // 办公 / 协作
86
+ 'feishu.cn',
87
+ 'dingtalk.com',
88
+ 'yuque.com',
89
+ 'notion.so',
90
+ 'atlassian.com',
91
+ 'jira.com',
92
+ 'confluence.com',
93
+ 'slack.com',
94
+ 'trello.com',
95
+ // 下载 / 软件
96
+ 'jetbrains.com',
97
+ 'visualstudio.com',
98
+ 'microsoft.com',
99
+ 'apple.com',
100
+ 'homebrew.sh',
101
+ 'iterm2.com',
102
+ // 中国互联网公司
103
+ 'qq.com',
104
+ 'wechat.com',
105
+ 'weibo.com',
106
+ 'bilibili.com',
107
+ 'douyin.com',
108
+ 'xiaohongshu.com',
109
+ 'taobao.com',
110
+ 'tmall.com',
111
+ 'jd.com',
112
+ 'aliyun.com',
113
+ // 学习 / 视频
114
+ 'youtube.com',
115
+ 'coursera.org',
116
+ 'udemy.com',
117
+ 'leetcode.com',
118
+ 'nowcoder.com',
119
+ 'geeksforgeeks.org',
120
+ // AI / Agent / 自动化
121
+ 'langchain.com',
122
+ 'langgraph.dev',
123
+ 'huggingface.co',
124
+ 'replicate.com',
125
+ 'ollama.com',
126
+ 'openrouter.ai',
127
+ 'tavily.com',
128
+ 'smith.langchain.com',
129
+ ];
130
+ function isSafeDomain(url) {
131
+ let hostname;
132
+ try {
133
+ hostname = new URL(url).hostname.toLowerCase();
134
+ }
135
+ catch {
136
+ return false;
137
+ }
138
+ return commonDomainsCNForDevelopers.some((domain) => {
139
+ const d = domain.toLowerCase();
140
+ return hostname === d || hostname.endsWith('.' + d);
141
+ });
142
+ }
@@ -0,0 +1,8 @@
1
+ export declare function checkNetworkPermission(toolCall: {
2
+ name: string;
3
+ args: Record<string, any>;
4
+ }): {
5
+ action: 'allow';
6
+ } | {
7
+ action: 'confirm';
8
+ };
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkNetworkPermission = checkNetworkPermission;
4
+ const is_safe_domains_1 = require("./is-safe-domains");
5
+ function checkNetworkPermission(toolCall) {
6
+ const url = toolCall.args?.url;
7
+ if (typeof url !== 'string') {
8
+ return { action: 'allow' };
9
+ }
10
+ if ((0, is_safe_domains_1.isSafeDomain)(url)) {
11
+ return { action: 'allow' };
12
+ }
13
+ return { action: 'confirm' };
14
+ }
@@ -0,0 +1,9 @@
1
+ export declare function checkReadPermission(toolCall: {
2
+ name: string;
3
+ args: Record<string, any>;
4
+ }): {
5
+ action: 'allow';
6
+ } | {
7
+ action: 'block';
8
+ reason: string;
9
+ };
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkReadPermission = checkReadPermission;
4
+ const is_dangerous_path_1 = require("./is-dangerous-path");
5
+ function checkReadPermission(toolCall) {
6
+ const filepath = toolCall.args?.filepath;
7
+ if (filepath == null) {
8
+ return { action: 'allow' };
9
+ }
10
+ if ((0, is_dangerous_path_1.isDangerousPath)(filepath)) {
11
+ return {
12
+ action: 'block',
13
+ reason: `路径 "${filepath}" 是系统敏感目录,为保护系统安全,禁止访问。如有需要请手动操作。`,
14
+ };
15
+ }
16
+ return { action: 'allow' };
17
+ }
@@ -0,0 +1,11 @@
1
+ export declare function isInProjectDir(filepath: string): boolean;
2
+ export declare function isChangingDirectory(command: string): boolean;
3
+ export declare function isScriptExecution(command: string): {
4
+ blocked: boolean;
5
+ reason?: string;
6
+ };
7
+ export declare function isSafeCommand(command: string): boolean;
8
+ export declare function isDangerousOperation(command: string): {
9
+ blocked: boolean;
10
+ reason?: string;
11
+ };
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.isInProjectDir = isInProjectDir;
7
+ exports.isChangingDirectory = isChangingDirectory;
8
+ exports.isScriptExecution = isScriptExecution;
9
+ exports.isSafeCommand = isSafeCommand;
10
+ exports.isDangerousOperation = isDangerousOperation;
11
+ const path_1 = __importDefault(require("path"));
12
+ const config_1 = require("../config");
13
+ function isInProjectDir(filepath) {
14
+ const resolved = path_1.default.resolve(filepath);
15
+ const cwd = path_1.default.resolve(process.cwd());
16
+ if (resolved === cwd || resolved.startsWith(cwd + path_1.default.sep)) {
17
+ return true;
18
+ }
19
+ const zhitalkDir = config_1.WORKSPACE_DIR;
20
+ return resolved === zhitalkDir || resolved.startsWith(zhitalkDir + path_1.default.sep);
21
+ }
22
+ function isChangingDirectory(command) {
23
+ return /(?:^|[\s;|&])(?:cd|chdir|pushd|popd)(?:\s|$)/i.test(command);
24
+ }
25
+ const PYTHON_TOOLS = ['python', 'python3', 'python2'];
26
+ const JS_TOOLS = ['node', 'nodejs', 'tsx', 'ts-node'];
27
+ const OTHER_LANG_TOOLS = [
28
+ 'java', 'javac', 'dotnet', 'go', 'cargo', 'rustc',
29
+ 'ruby', 'php', 'perl', 'lua', 'rscript',
30
+ ];
31
+ const BLOCKED_EXTENSIONS = [
32
+ '.py', '.js', '.ts', '.mjs', '.cjs',
33
+ '.java', '.cs', '.go', '.rb', '.rs', '.php', '.pl', '.lua',
34
+ ];
35
+ function getFirstToken(command) {
36
+ const trimmed = command.trim();
37
+ const match = trimmed.match(/^([^\s]+)/);
38
+ return match ? match[1] : trimmed;
39
+ }
40
+ function isScriptExecution(command) {
41
+ const subCommands = command.split(/[;|&]+/).filter(Boolean);
42
+ for (const sub of subCommands) {
43
+ const token = getFirstToken(sub);
44
+ const tool = path_1.default.basename(token).toLowerCase();
45
+ const ext = path_1.default.extname(token).toLowerCase();
46
+ if (PYTHON_TOOLS.includes(tool) || ext === '.py') {
47
+ return { blocked: true, reason: '检测到 Python 脚本执行,请使用 run_py tool 执行 Python 代码。' };
48
+ }
49
+ if (JS_TOOLS.includes(tool) || ['.js', '.ts', '.mjs', '.cjs'].includes(ext)) {
50
+ return { blocked: true, reason: '检测到 JavaScript/TypeScript 脚本执行,请使用 run_js tool 执行 JavaScript/TypeScript 代码。' };
51
+ }
52
+ if (OTHER_LANG_TOOLS.includes(tool) || BLOCKED_EXTENSIONS.includes(ext)) {
53
+ return { blocked: true, reason: `检测到 ${tool || ext} 脚本执行,exec tool 仅允许执行 shell/bash/sh 脚本。` };
54
+ }
55
+ }
56
+ return { blocked: false };
57
+ }
58
+ const DANGEROUS_COMMANDS = [
59
+ 'sudo', 'doas',
60
+ 'rm', 'rmdir', 'unlink', 'shred',
61
+ 'del', 'erase', 'rd',
62
+ 'remove-item', 'clear-item',
63
+ 'mv', 'move', 'rename', 'ren',
64
+ 'cp', 'copy', 'xcopy', 'robocopy',
65
+ 'touch', 'dd', 'truncate', 'tee',
66
+ 'mkdir', 'md', 'mkfifo', 'mknod',
67
+ 'new-item',
68
+ 'chmod', 'chown', 'chgrp', 'umask', 'setfacl', 'chflags',
69
+ 'icacls', 'cacls', 'takeown', 'attrib',
70
+ 'kill', 'killall', 'pkill', 'xkill',
71
+ 'systemctl', 'service', 'launchctl',
72
+ 'init', 'shutdown', 'reboot', 'halt', 'poweroff',
73
+ 'crontab', 'at', 'batch',
74
+ 'taskkill',
75
+ 'sc', 'net', 'netsh',
76
+ 'stop-process', 'start-process', 'restart-computer',
77
+ 'useradd', 'usermod', 'userdel',
78
+ 'groupadd', 'groupmod', 'groupdel',
79
+ 'passwd', 'chsh', 'chfn', 'chage',
80
+ 'su', 'runas',
81
+ 'dscl', 'dseditgroup',
82
+ 'env', 'printenv', 'history',
83
+ 'ssh', 'scp', 'sftp', 'ftp', 'telnet',
84
+ 'nc', 'netcat', 'ncat',
85
+ 'curl', 'wget',
86
+ 'nmap', 'masscan', 'zmap',
87
+ 'iptables', 'ufw', 'firewall-cmd', 'nft',
88
+ 'socat', 'proxychains',
89
+ ];
90
+ const SHELL_COMMAND_SWITCH = /(?:bash|sh|zsh|cmd|powershell)\s+(?:-c\s+(".*?"|'.*?'|\S+)|\/c\s+(".*?"|'.*?'|\S+)|-Command\s+(".*?"|'.*?'|\S+))/i;
91
+ function unquote(str) {
92
+ if ((str.startsWith('"') && str.endsWith('"')) || (str.startsWith("'") && str.endsWith("'"))) {
93
+ return str.slice(1, -1);
94
+ }
95
+ return str;
96
+ }
97
+ function extractShellSubCommand(command) {
98
+ const match = command.match(SHELL_COMMAND_SWITCH);
99
+ if (!match)
100
+ return null;
101
+ return unquote(match[1] || match[2] || match[3] || '');
102
+ }
103
+ function hasOutputRedirect(command) {
104
+ return /(^|[\s;|&])\d?>>?\s/.test(command);
105
+ }
106
+ const SAFE_COMMANDS = [
107
+ 'ls', 'pwd', 'cat', 'head', 'tail', 'grep', 'find',
108
+ 'echo', 'date', 'whoami', 'id', 'uname', 'wc', 'sort', 'uniq',
109
+ 'diff', 'which', 'whereis', 'file', 'stat', 'df', 'du',
110
+ 'ps', 'pgrep', 'pstree', 'uptime', 'hostname',
111
+ 'printf', 'readlink', 'realpath', 'tput', 'clear', 'reset',
112
+ 'seq', 'yes', 'true', 'false',
113
+ 'dir', 'type', 'findstr', 'more', 'tree', 'ver', 'vol',
114
+ 'gci', 'gc', 'gl', 'sls', 'write',
115
+ ];
116
+ const SAFE_GIT_SUBCOMMANDS = ['status', 'diff', 'log'];
117
+ function getSecondToken(command) {
118
+ const tokens = command.trim().split(/\s+/);
119
+ return tokens[1] || null;
120
+ }
121
+ function isSafeCommand(command) {
122
+ if (hasOutputRedirect(command))
123
+ return false;
124
+ const subCommands = command.split(/[;|&]+/).filter(Boolean);
125
+ for (const sub of subCommands) {
126
+ const token = getFirstToken(sub);
127
+ const tool = path_1.default.basename(token).toLowerCase();
128
+ if (SAFE_COMMANDS.includes(tool)) {
129
+ continue;
130
+ }
131
+ if (tool === 'git') {
132
+ const subCommand = getSecondToken(sub)?.toLowerCase();
133
+ if (subCommand && SAFE_GIT_SUBCOMMANDS.includes(subCommand)) {
134
+ continue;
135
+ }
136
+ }
137
+ return false;
138
+ }
139
+ return true;
140
+ }
141
+ function isDangerousOperation(command) {
142
+ const subCommand = extractShellSubCommand(command);
143
+ if (subCommand) {
144
+ const result = isDangerousOperation(subCommand);
145
+ if (result.blocked)
146
+ return result;
147
+ }
148
+ const subCommands = command.split(/[;|&]+/).filter(Boolean);
149
+ for (const sub of subCommands) {
150
+ const token = getFirstToken(sub);
151
+ const tool = path_1.default.basename(token).toLowerCase();
152
+ if (DANGEROUS_COMMANDS.includes(tool)) {
153
+ return { blocked: true, reason: `检测到危险操作 "${tool}",exec tool 禁止执行该命令。如有需要请手动操作。` };
154
+ }
155
+ }
156
+ if (hasOutputRedirect(command)) {
157
+ return { blocked: true, reason: '检测到输出重定向,exec tool 禁止修改文件系统。如有需要请手动操作。' };
158
+ }
159
+ return { blocked: false };
160
+ }
@@ -0,0 +1,11 @@
1
+ export declare function checkWritePermission(toolCall: {
2
+ name: string;
3
+ args: Record<string, any>;
4
+ }): {
5
+ action: 'allow';
6
+ } | {
7
+ action: 'block';
8
+ reason: string;
9
+ } | {
10
+ action: 'confirm';
11
+ };
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkWritePermission = checkWritePermission;
4
+ const is_dangerous_path_1 = require("./is-dangerous-path");
5
+ const util_1 = require("./util");
6
+ function checkWritePermission(toolCall) {
7
+ const filepath = toolCall.args?.filepath;
8
+ if (filepath == null) {
9
+ return { action: 'allow' };
10
+ }
11
+ if ((0, is_dangerous_path_1.isDangerousPath)(filepath)) {
12
+ return {
13
+ action: 'block',
14
+ reason: `路径 "${filepath}" 是系统敏感目录,为保护系统安全,禁止访问。如有需要请手动操作。`,
15
+ };
16
+ }
17
+ if ((0, util_1.isInProjectDir)(filepath)) {
18
+ return { action: 'allow' };
19
+ }
20
+ return { action: 'confirm' };
21
+ }
@@ -0,0 +1 @@
1
+ export declare const systemPrompt: string;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.systemPrompt = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const skills_1 = require("./skills");
10
+ const config_1 = require("./config");
11
+ // ── Skills ────────────────────────────────────────────────
12
+ (0, skills_1.discoverSkills)();
13
+ const skillsText = (0, skills_1.getSkillsListText)();
14
+ const basePrompt = 'You are zhitalk, 中文名字叫智语, a personal AI Agent like OpenClaw, including tools, skills, memory, hook, sub-agent, MCP server, etc. Run in the terminal.';
15
+ function readProfile() {
16
+ try {
17
+ const filePath = path_1.default.join(config_1.WORKSPACE_DIR, '.data', 'profile.md');
18
+ const content = fs_1.default.readFileSync(filePath, 'utf-8').trim();
19
+ return `<profile_info>${content}</profile_info>`;
20
+ }
21
+ catch {
22
+ return '<profile_info></profile_info>';
23
+ }
24
+ }
25
+ const profilePrompt = `## User Profile
26
+
27
+ When you learn information about the user that fits the following categories, store it as profile information for future personalization.
28
+
29
+ <profile_template>
30
+ - Basic identity: name, nickname, gender, age, region, language
31
+ - Appearance: height, weight, skin tone, body type
32
+ - Personality and communication preferences
33
+ - Hobbies and interests
34
+ - Skills
35
+ - Work / occupation
36
+ </profile_template>
37
+
38
+ Here is the user's current profile information:
39
+ ${readProfile()}`;
40
+ const memoryPrompt = `## Memory Management Rules
41
+
42
+ - When deleting a memory, first use memory_retrieve to find its id, then call memory_delete with that id. If no matching memory is found, politely inform the user.
43
+ - When updating a memory, first delete the old memory, then create a new one.
44
+ - When information fits the categories in <profile_template>, do not record it as a memory. It will be stored in the profile file instead.`;
45
+ const dateTimePrompt = `## Current DateTime
46
+
47
+ ${new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })}`;
48
+ exports.systemPrompt = skillsText
49
+ ? `${basePrompt}\n\n${profilePrompt}\n\n${memoryPrompt}\n\n## Available Skills\n\nYou have access to the following skills. When a user's request matches a skill's description, you MUST call the \`load_skill\` tool to load that skill's full instructions, then follow them.\n\n${skillsText}\n\n${dateTimePrompt}`
50
+ : `${basePrompt}\n\n${profilePrompt}\n\n${memoryPrompt}\n\n${dateTimePrompt}`;
@@ -0,0 +1,8 @@
1
+ export interface SkillInfo {
2
+ name: string;
3
+ description: string;
4
+ dirPath: string;
5
+ }
6
+ export declare function discoverSkills(): SkillInfo[];
7
+ export declare function loadSkill(name: string): string | null;
8
+ export declare function getSkillsListText(): string;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.discoverSkills = discoverSkills;
4
+ exports.loadSkill = loadSkill;
5
+ exports.getSkillsListText = getSkillsListText;
6
+ const fs_1 = require("fs");
7
+ const path_1 = require("path");
8
+ const os_1 = require("os");
9
+ const config_1 = require("./config");
10
+ const skills = [];
11
+ const skillContentMap = new Map();
12
+ function parseFrontmatter(content) {
13
+ if (!content.startsWith('---')) {
14
+ return { name: '', description: '' };
15
+ }
16
+ const endIdx = content.indexOf('---', 3);
17
+ if (endIdx === -1) {
18
+ return { name: '', description: '' };
19
+ }
20
+ const frontmatter = content.slice(3, endIdx).trim();
21
+ const lines = frontmatter.split('\n');
22
+ const result = {};
23
+ for (const line of lines) {
24
+ const colonIdx = line.indexOf(':');
25
+ if (colonIdx === -1)
26
+ continue;
27
+ const key = line.slice(0, colonIdx).trim();
28
+ const value = line.slice(colonIdx + 1).trim();
29
+ result[key] = value;
30
+ }
31
+ return { name: result.name || '', description: result.description || '' };
32
+ }
33
+ function discoverSkills() {
34
+ skills.length = 0;
35
+ skillContentMap.clear();
36
+ const skillDirs = [
37
+ (0, path_1.join)((0, os_1.homedir)(), '.agents', 'skills'),
38
+ (0, path_1.join)(config_1.WORKSPACE_DIR, '.agents', 'skills'),
39
+ (0, path_1.join)(config_1.WORKSPACE_DIR, 'skills'),
40
+ ];
41
+ for (const skillsDir of skillDirs) {
42
+ let entries;
43
+ try {
44
+ entries = (0, fs_1.readdirSync)(skillsDir);
45
+ }
46
+ catch {
47
+ continue;
48
+ }
49
+ for (const entry of entries) {
50
+ const entryPath = (0, path_1.join)(skillsDir, entry);
51
+ try {
52
+ const entryStat = (0, fs_1.statSync)(entryPath);
53
+ if (!entryStat.isDirectory())
54
+ continue;
55
+ const skillMdPath = (0, path_1.join)(entryPath, 'SKILL.md');
56
+ const content = (0, fs_1.readFileSync)(skillMdPath, 'utf-8');
57
+ const { name, description } = parseFrontmatter(content);
58
+ if (name && description) {
59
+ const existing = skills.find((s) => s.name === name);
60
+ if (existing) {
61
+ existing.description = description;
62
+ existing.dirPath = entryPath;
63
+ }
64
+ else {
65
+ skills.push({ name, description, dirPath: entryPath });
66
+ }
67
+ skillContentMap.set(name, content);
68
+ }
69
+ }
70
+ catch {
71
+ // Ignore directories without SKILL.md or parse errors
72
+ }
73
+ }
74
+ }
75
+ return skills;
76
+ }
77
+ function loadSkill(name) {
78
+ return skillContentMap.get(name) ?? null;
79
+ }
80
+ function getSkillsListText() {
81
+ const lines = skills.map((s) => `- **${s.name}**: ${s.description}`);
82
+ if (skills.length > 0) {
83
+ lines.push('');
84
+ lines.push('skills 的目录:');
85
+ lines.push((0, path_1.join)((0, os_1.homedir)(), '.agents', 'skills'));
86
+ lines.push((0, path_1.join)(config_1.WORKSPACE_DIR, '.agents', 'skills'));
87
+ lines.push((0, path_1.join)(config_1.WORKSPACE_DIR, 'skills'));
88
+ lines.push(`如果增加新 skill,必须放在 ${(0, path_1.join)(config_1.WORKSPACE_DIR, 'skills')} 目录下`);
89
+ }
90
+ return lines.join('\n');
91
+ }
@@ -0,0 +1,3 @@
1
+ export declare function agentTool({ prompt }: {
2
+ prompt: string;
3
+ }): Promise<string>;