cicy-desktop 1.0.8

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 (66) hide show
  1. package/.github/workflows/build.yml +85 -0
  2. package/.kiro/steering/dev-workflow.md +166 -0
  3. package/AGENTS.md +247 -0
  4. package/CLAUDE.md +162 -0
  5. package/DOCKER.md +85 -0
  6. package/Dockerfile +46 -0
  7. package/README.md +720 -0
  8. package/TODO-anti-detection.md +326 -0
  9. package/bin/cicy +176 -0
  10. package/bin/preinstall.sh +32 -0
  11. package/copy-to-desktop.sh +26 -0
  12. package/docs/AUTOMATION-API.md +342 -0
  13. package/docs/REQUEST_MONITORING.md +435 -0
  14. package/docs/REST-API-FEATURE.md +155 -0
  15. package/docs/REST-API.md +319 -0
  16. package/docs/feature-distributed-multi-agent.md +555 -0
  17. package/docs/yaml.md +255 -0
  18. package/electron-mcp-fixed.command +134 -0
  19. package/electron-mcp-simple.command +135 -0
  20. package/electron-mcp.command +92 -0
  21. package/generate-openapi.js +158 -0
  22. package/jest.config.js +10 -0
  23. package/jest.setup.global.js +13 -0
  24. package/jest.teardown.global.js +7 -0
  25. package/package.json +75 -0
  26. package/service.sh +164 -0
  27. package/src/config.js +8 -0
  28. package/src/extension/inject.js +135 -0
  29. package/src/main-old.js +837 -0
  30. package/src/main.js +403 -0
  31. package/src/preload-rpc.js +4 -0
  32. package/src/server/args-parser.js +37 -0
  33. package/src/server/electron-setup.js +33 -0
  34. package/src/server/express-app.js +166 -0
  35. package/src/server/logging.js +58 -0
  36. package/src/server/mcp-server.js +53 -0
  37. package/src/server/tool-registry.js +77 -0
  38. package/src/server/ui-routes.js +81 -0
  39. package/src/swagger-ui.html +41 -0
  40. package/src/tools/account-tools.js +194 -0
  41. package/src/tools/automation-tools.js +297 -0
  42. package/src/tools/cdp-tools.js +444 -0
  43. package/src/tools/clipboard-tools.js +180 -0
  44. package/src/tools/download-tools.js +57 -0
  45. package/src/tools/exec-js.js +297 -0
  46. package/src/tools/exec-tools.js +139 -0
  47. package/src/tools/file-tools.js +212 -0
  48. package/src/tools/hook-chatgpt.js +489 -0
  49. package/src/tools/hook-gemini.js +454 -0
  50. package/src/tools/index.js +19 -0
  51. package/src/tools/ipc-bridge.js +31 -0
  52. package/src/tools/ping.js +60 -0
  53. package/src/tools/r-reset.js +28 -0
  54. package/src/tools/screenshot-tools.js +28 -0
  55. package/src/tools/system-tools.js +531 -0
  56. package/src/tools/window-tools.js +882 -0
  57. package/src/ui.html +914 -0
  58. package/src/utils/auth.js +81 -0
  59. package/src/utils/cdp-utils.js +8 -0
  60. package/src/utils/download-manager.js +41 -0
  61. package/src/utils/process-utils.js +185 -0
  62. package/src/utils/snapshot-utils.js +56 -0
  63. package/src/utils/window-monitor.js +605 -0
  64. package/src/utils/window-state.js +137 -0
  65. package/src/utils/window-utils.js +336 -0
  66. package/update-desktop.sh +33 -0
package/docs/yaml.md ADDED
@@ -0,0 +1,255 @@
1
+ # YAML 支持文档
2
+
3
+ ## 概述
4
+
5
+ Electron MCP Server 支持 YAML 和 JSON 双格式,**默认使用 YAML** 以节省 token 消耗。
6
+
7
+ ## 为什么选择 YAML?
8
+
9
+ ### Token 节省对比
10
+
11
+ **JSON 格式(~100 字符):**
12
+ ```json
13
+ {"name":"open_window","arguments":{"url":"https://google.com","reuseWindow":false}}
14
+ ```
15
+
16
+ **YAML 格式(~70 字符):**
17
+ ```yaml
18
+ name: open_window
19
+ arguments:
20
+ url: https://google.com
21
+ reuseWindow: false
22
+ ```
23
+
24
+ **节省约 30-45% token!**
25
+
26
+ ### 其他优势
27
+
28
+ - ✅ 更易读易写
29
+ - ✅ 无需大量引号和逗号
30
+ - ✅ 支持注释(虽然在 API 调用中不常用)
31
+ - ✅ 更自然的缩进结构
32
+
33
+ ## 服务器端支持
34
+
35
+ ### Accept 头控制
36
+
37
+ 服务器根据 `Accept` 头返回相应格式:
38
+
39
+ ```bash
40
+ # 请求 YAML 响应
41
+ curl -H "Accept: application/yaml" http://localhost:8101/rpc
42
+
43
+ # 请求 JSON 响应(默认)
44
+ curl -H "Accept: application/json" http://localhost:8101/rpc
45
+ ```
46
+
47
+ ### 响应格式对比
48
+
49
+ **YAML 响应(~50 字符):**
50
+ ```yaml
51
+ jsonrpc: '2.0'
52
+ id: 1
53
+ result:
54
+ content:
55
+ - type: text
56
+ text: Pong
57
+ ```
58
+
59
+ **JSON 响应(~90 字符):**
60
+ ```json
61
+ {"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"Pong"}]}}
62
+ ```
63
+
64
+ ## cicy-rpc 工具
65
+
66
+ ### 默认行为
67
+
68
+ `cicy-rpc` 默认使用 YAML 格式:
69
+
70
+ ```bash
71
+ # YAML(默认,无需标志)
72
+ cicy-rpc "
73
+ name: ping
74
+ arguments: {}
75
+ "
76
+
77
+ # JSON(需要 --json 或 -j)
78
+ cicy-rpc --json '{"name":"ping","arguments":{}}'
79
+ ```
80
+
81
+ ### 自动处理
82
+
83
+ 工具自动处理格式转换:
84
+
85
+ 1. **输入处理**:
86
+ - YAML 输入 → 使用 `yq` 转换为 JSON
87
+ - JSON 输入 → 直接使用
88
+
89
+ 2. **Accept 头**:
90
+ - YAML 模式 → `Accept: application/yaml`
91
+ - JSON 模式 → `Accept: application/json`
92
+
93
+ 3. **输出解析**:
94
+ - YAML 响应 → 使用 `yq` 解析
95
+ - JSON 响应 → 使用 `jq` 解析
96
+
97
+ ## 依赖安装
98
+
99
+ ### 服务器端
100
+
101
+ ```bash
102
+ npm install js-yaml
103
+ ```
104
+
105
+ ### 客户端
106
+
107
+ ```bash
108
+ pip install yq --break-system-packages
109
+ ```
110
+
111
+ ## 实际使用示例
112
+
113
+ ### 打开窗口
114
+
115
+ ```bash
116
+ cicy-rpc "
117
+ name: open_window
118
+ arguments:
119
+ url: https://gemini.google.com
120
+ "
121
+ ```
122
+
123
+ ### 设置窗口位置
124
+
125
+ ```bash
126
+ cicy-rpc "
127
+ name: set_window_bounds
128
+ arguments:
129
+ win_id: 1
130
+ x: 1320
131
+ y: 0
132
+ width: 360
133
+ height: 720
134
+ "
135
+ ```
136
+
137
+ ### 执行 JavaScript
138
+
139
+ ```bash
140
+ cicy-rpc "
141
+ name: exec_js
142
+ arguments:
143
+ win_id: 1
144
+ code: document.title
145
+ "
146
+ ```
147
+
148
+ ### 复杂参数
149
+
150
+ ```bash
151
+ cicy-rpc "
152
+ name: open_window
153
+ arguments:
154
+ url: https://example.com
155
+ accountIdx: 1
156
+ reuseWindow: false
157
+ options:
158
+ width: 1280
159
+ height: 720
160
+ "
161
+ ```
162
+
163
+ ## 性能影响
164
+
165
+ ### Token 消耗
166
+
167
+ - **YAML**: 平均节省 30-45% 字符
168
+ - **网络传输**: 响应体积减少约 40%
169
+ - **解析速度**: YAML 略慢,但差异可忽略
170
+
171
+ ### 推荐使用场景
172
+
173
+ - ✅ **AI 对话**: 使用 YAML(节省 token)
174
+ - ✅ **命令行工具**: 使用 YAML(易读易写)
175
+ - ⚠️ **程序化调用**: JSON 或 YAML 均可
176
+ - ⚠️ **性能关键**: JSON(解析更快)
177
+
178
+ ## 故障排除
179
+
180
+ ### yq 未安装
181
+
182
+ ```bash
183
+ ❌ Error: yq not found. Install with: pip install yq --break-system-packages
184
+ ```
185
+
186
+ **解决方案:**
187
+ ```bash
188
+ pip install yq --break-system-packages
189
+ ```
190
+
191
+ ### YAML 语法错误
192
+
193
+ ```bash
194
+ ❌ Error: yaml.scanner.ScannerError: mapping values are not allowed here
195
+ ```
196
+
197
+ **解决方案:**
198
+ - 检查缩进(使用空格,不要用 Tab)
199
+ - 确保冒号后有空格
200
+ - 检查特殊字符是否需要引号
201
+
202
+ ### 服务器不支持 YAML
203
+
204
+ 如果服务器版本较旧,使用 JSON 格式:
205
+
206
+ ```bash
207
+ cicy-rpc --json '{"name":"ping","arguments":{}}'
208
+ ```
209
+
210
+ ## 技术实现
211
+
212
+ ### 服务器端 (Node.js)
213
+
214
+ ```javascript
215
+ const yaml = require('js-yaml');
216
+
217
+ app.post("/rpc", async (req, res) => {
218
+ const acceptHeader = req.get('Accept') || 'application/json';
219
+ const useYaml = acceptHeader.includes('application/yaml');
220
+
221
+ const response = { /* ... */ };
222
+
223
+ if (useYaml) {
224
+ res.type('application/yaml').send(yaml.dump(response));
225
+ } else {
226
+ res.json(response);
227
+ }
228
+ });
229
+ ```
230
+
231
+ ### 客户端 (Bash)
232
+
233
+ ```bash
234
+ # YAML 转 JSON
235
+ PARAMS=$(echo "$PARAMS_INPUT" | yq -c .)
236
+
237
+ # 设置 Accept 头
238
+ ACCEPT_HEADER="application/yaml"
239
+
240
+ # 解析 YAML 响应
241
+ curl ... | yq -r '.result.content[].text'
242
+ ```
243
+
244
+ ## 最佳实践
245
+
246
+ 1. **默认使用 YAML** - 节省 token 和带宽
247
+ 2. **复杂嵌套使用 JSON** - 避免 YAML 缩进问题
248
+ 3. **程序化调用优先 JSON** - 更好的库支持
249
+ 4. **命令行优先 YAML** - 更易读易写
250
+
251
+ ## 参考资源
252
+
253
+ - [YAML 规范](https://yaml.org/)
254
+ - [js-yaml 文档](https://github.com/nodeca/js-yaml)
255
+ - [yq 文档](https://github.com/kislyuk/yq)
@@ -0,0 +1,134 @@
1
+ #!/bin/bash
2
+
3
+ # Electron MCP 启动脚本 - 修复版本
4
+ # 用于在 macOS 上双击启动 Electron MCP 服务
5
+
6
+ # 设置错误处理
7
+ set -e
8
+
9
+ # 获取脚本所在目录
10
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
11
+
12
+ # 检查是否在项目目录中
13
+ if [ -f "$SCRIPT_DIR/package.json" ]; then
14
+ PROJECT_DIR="$SCRIPT_DIR"
15
+ elif [ -f "$SCRIPT_DIR/electron-mcp/package.json" ]; then
16
+ PROJECT_DIR="$SCRIPT_DIR/electron-mcp"
17
+ else
18
+ # 如果脚本在桌面,尝试找到项目目录
19
+ if [ -f "/Users/ton/Desktop/electron-mcp/package.json" ]; then
20
+ PROJECT_DIR="/Users/ton/Desktop/electron-mcp"
21
+ elif [ -f "$HOME/Desktop/electron-mcp/package.json" ]; then
22
+ PROJECT_DIR="$HOME/Desktop/electron-mcp"
23
+ else
24
+ echo "❌ 错误: 找不到 electron-mcp 项目目录"
25
+ echo "请确保项目在以下位置之一:"
26
+ echo "- $SCRIPT_DIR/electron-mcp/"
27
+ echo "- $HOME/Desktop/electron-mcp/"
28
+ echo ""
29
+ echo "按任意键退出..."
30
+ read -n 1
31
+ exit 1
32
+ fi
33
+ fi
34
+
35
+ # 输出启动信息
36
+ clear
37
+ echo "========================================="
38
+ echo " 🚀 Electron MCP 启动脚本"
39
+ echo " 📁 项目目录: $PROJECT_DIR"
40
+ echo " 📅 时间: $(date '+%Y-%m-%d %H:%M:%S')"
41
+ echo "========================================="
42
+
43
+ # 切换到项目目录
44
+ cd "$PROJECT_DIR"
45
+
46
+ # 检查 Node.js 是否安装
47
+ if ! command -v node &> /dev/null; then
48
+ echo "❌ 错误: 未找到 Node.js"
49
+ echo "请先安装 Node.js: https://nodejs.org/"
50
+ echo ""
51
+ echo "按任意键退出..."
52
+ read -n 1
53
+ exit 1
54
+ fi
55
+
56
+ echo "✅ Node.js 版本: $(node --version)"
57
+
58
+ # 检查 npm 是否安装
59
+ if ! command -v npm &> /dev/null; then
60
+ echo "❌ 错误: 未找到 npm"
61
+ echo "请先安装 npm"
62
+ echo ""
63
+ echo "按任意键退出..."
64
+ read -n 1
65
+ exit 1
66
+ fi
67
+
68
+ echo "✅ npm 版本: $(npm --version)"
69
+
70
+ # 检查依赖是否安装
71
+ if [ ! -d "node_modules" ]; then
72
+ echo ""
73
+ echo "📦 正在安装依赖..."
74
+ npm install
75
+ if [ $? -ne 0 ]; then
76
+ echo "❌ 依赖安装失败"
77
+ echo ""
78
+ echo "按任意键退出..."
79
+ read -n 1
80
+ exit 1
81
+ fi
82
+ echo "✅ 依赖安装完成"
83
+ fi
84
+
85
+ # 检查 Electron 是否可用
86
+ if ! command -v electron &> /dev/null && [ ! -f "node_modules/.bin/electron" ]; then
87
+ echo ""
88
+ echo "📦 正在安装 Electron..."
89
+ npm install electron --save-dev
90
+ if [ $? -ne 0 ]; then
91
+ echo "❌ Electron 安装失败"
92
+ echo ""
93
+ echo "按任意键退出..."
94
+ read -n 1
95
+ exit 1
96
+ fi
97
+ echo "✅ Electron 安装完成"
98
+ fi
99
+
100
+ # 设置环境变量
101
+ export NODE_ENV=development
102
+
103
+ # 显示启动信息
104
+ echo ""
105
+ echo "========================================="
106
+ echo "🚀 正在启动 Electron MCP 服务..."
107
+ echo "📋 端口: 8101"
108
+ echo "📋 调试端口: 9221"
109
+ echo ""
110
+ echo "服务启动后可以访问:"
111
+ echo "- MCP 服务: http://localhost:8101/mcp"
112
+ echo "- API 文档: http://localhost:8101/docs"
113
+ echo "- 远程调试: http://localhost:9221"
114
+ echo ""
115
+ echo "⚠️ 关闭此窗口将停止服务"
116
+ echo " 按 Ctrl+C 可以优雅停止服务"
117
+ echo "========================================="
118
+ echo ""
119
+
120
+ # 启动应用(不使用 exit,让进程保持运行)
121
+ npm start
122
+
123
+ # 如果 npm start 退出,显示信息
124
+ echo ""
125
+ echo "========================================="
126
+ if [ $? -eq 0 ]; then
127
+ echo "✅ 服务已正常停止"
128
+ else
129
+ echo "❌ 服务异常退出"
130
+ echo "请检查上面的错误信息"
131
+ fi
132
+ echo ""
133
+ echo "按任意键关闭窗口..."
134
+ read -n 1
@@ -0,0 +1,135 @@
1
+ #!/bin/bash
2
+
3
+ # 简化版 Electron MCP 启动脚本
4
+ # 避免复杂的路径检测,直接使用固定路径
5
+
6
+ # 强制保持终端打开
7
+ exec 2>&1
8
+
9
+ echo "========================================="
10
+ echo " 🚀 Electron MCP 启动脚本 (简化版)"
11
+ echo " 📅 $(date '+%Y-%m-%d %H:%M:%S')"
12
+ echo "========================================="
13
+
14
+ # 尝试多个可能的项目路径
15
+ PROJECT_PATHS=(
16
+ "/Users/ton/Desktop/electron-mcp"
17
+ "$HOME/Desktop/electron-mcp"
18
+ "$HOME/Documents/electron-mcp"
19
+ "$HOME/Projects/electron-mcp"
20
+ )
21
+
22
+ PROJECT_DIR=""
23
+
24
+ echo "🔍 正在查找项目目录..."
25
+
26
+ for path in "${PROJECT_PATHS[@]}"; do
27
+ echo "检查: $path"
28
+ if [ -f "$path/package.json" ]; then
29
+ PROJECT_DIR="$path"
30
+ echo "✅ 找到项目: $PROJECT_DIR"
31
+ break
32
+ fi
33
+ done
34
+
35
+ if [ -z "$PROJECT_DIR" ]; then
36
+ echo ""
37
+ echo "❌ 错误: 找不到 electron-mcp 项目"
38
+ echo ""
39
+ echo "请确保项目在以下位置之一:"
40
+ for path in "${PROJECT_PATHS[@]}"; do
41
+ echo " - $path"
42
+ done
43
+ echo ""
44
+ echo "或者手动输入项目路径:"
45
+ read -p "项目路径: " USER_PATH
46
+ if [ -f "$USER_PATH/package.json" ]; then
47
+ PROJECT_DIR="$USER_PATH"
48
+ echo "✅ 使用用户指定路径: $PROJECT_DIR"
49
+ else
50
+ echo "❌ 指定路径无效"
51
+ echo "按回车键退出..."
52
+ read
53
+ exit 1
54
+ fi
55
+ fi
56
+
57
+ echo ""
58
+ echo "📁 项目目录: $PROJECT_DIR"
59
+ echo "📁 切换到项目目录..."
60
+
61
+ cd "$PROJECT_DIR" || {
62
+ echo "❌ 无法切换到项目目录"
63
+ echo "按回车键退出..."
64
+ read
65
+ exit 1
66
+ }
67
+
68
+ echo "✅ 当前目录: $(pwd)"
69
+
70
+ # 检查 Node.js
71
+ echo ""
72
+ echo "🔍 检查 Node.js..."
73
+ if command -v node >/dev/null 2>&1; then
74
+ echo "✅ Node.js: $(node --version)"
75
+ else
76
+ echo "❌ 未找到 Node.js"
77
+ echo "请安装 Node.js: https://nodejs.org/"
78
+ echo "按回车键退出..."
79
+ read
80
+ exit 1
81
+ fi
82
+
83
+ # 检查 npm
84
+ echo "🔍 检查 npm..."
85
+ if command -v npm >/dev/null 2>&1; then
86
+ echo "✅ npm: $(npm --version)"
87
+ else
88
+ echo "❌ 未找到 npm"
89
+ echo "按回车键退出..."
90
+ read
91
+ exit 1
92
+ fi
93
+
94
+ # 检查依赖
95
+ echo ""
96
+ echo "🔍 检查项目依赖..."
97
+ if [ ! -d "node_modules" ]; then
98
+ echo "📦 安装依赖中..."
99
+ npm install
100
+ if [ $? -ne 0 ]; then
101
+ echo "❌ 依赖安装失败"
102
+ echo "按回车键退出..."
103
+ read
104
+ exit 1
105
+ fi
106
+ else
107
+ echo "✅ 依赖已安装"
108
+ fi
109
+
110
+ # 启动服务
111
+ echo ""
112
+ echo "========================================="
113
+ echo "🚀 启动 Electron MCP 服务"
114
+ echo "📋 端口: 8101"
115
+ echo "📋 API: http://localhost:8101/docs"
116
+ echo ""
117
+ echo "⚠️ 关闭此窗口将停止服务"
118
+ echo " 按 Ctrl+C 停止服务"
119
+ echo "========================================="
120
+ echo ""
121
+
122
+ # 启动并保持运行
123
+ npm start
124
+
125
+ # 服务停止后的处理
126
+ echo ""
127
+ echo "========================================="
128
+ if [ $? -eq 0 ]; then
129
+ echo "✅ 服务正常停止"
130
+ else
131
+ echo "❌ 服务异常退出 (退出码: $?)"
132
+ fi
133
+ echo ""
134
+ echo "按回车键关闭窗口..."
135
+ read
@@ -0,0 +1,92 @@
1
+ #!/bin/bash
2
+
3
+ # Electron MCP 启动脚本
4
+ # 用于在 macOS 上双击启动 Electron MCP 服务
5
+
6
+ # 设置脚本目录
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ PROJECT_DIR="$SCRIPT_DIR"
9
+
10
+ # 输出启动信息
11
+ echo "========================================="
12
+ echo " Electron MCP 启动脚本"
13
+ echo " 项目目录: $PROJECT_DIR"
14
+ echo "========================================="
15
+
16
+ # 检查是否在正确的项目目录
17
+ if [ ! -f "$PROJECT_DIR/package.json" ]; then
18
+ echo "❌ 错误: 未找到 package.json 文件"
19
+ echo "请确保脚本在 electron-mcp 项目根目录中"
20
+ read -p "按任意键退出..."
21
+ exit 1
22
+ fi
23
+
24
+ # 切换到项目目录
25
+ cd "$PROJECT_DIR"
26
+
27
+ # 检查 Node.js 是否安装
28
+ if ! command -v node &> /dev/null; then
29
+ echo "❌ 错误: 未找到 Node.js"
30
+ echo "请先安装 Node.js: https://nodejs.org/"
31
+ read -p "按任意键退出..."
32
+ exit 1
33
+ fi
34
+
35
+ # 检查 npm 是否安装
36
+ if ! command -v npm &> /dev/null; then
37
+ echo "❌ 错误: 未找到 npm"
38
+ echo "请先安装 npm"
39
+ read -p "按任意键退出..."
40
+ exit 1
41
+ fi
42
+
43
+ # 检查依赖是否安装
44
+ if [ ! -d "node_modules" ]; then
45
+ echo "📦 正在安装依赖..."
46
+ npm install
47
+ if [ $? -ne 0 ]; then
48
+ echo "❌ 依赖安装失败"
49
+ read -p "按任意键退出..."
50
+ exit 1
51
+ fi
52
+ fi
53
+
54
+ # 检查 Electron 是否安装
55
+ if ! command -v electron &> /dev/null && [ ! -f "node_modules/.bin/electron" ]; then
56
+ echo "❌ 错误: 未找到 Electron"
57
+ echo "正在安装 Electron..."
58
+ npm install electron --save-dev
59
+ if [ $? -ne 0 ]; then
60
+ echo "❌ Electron 安装失败"
61
+ read -p "按任意键退出..."
62
+ exit 1
63
+ fi
64
+ fi
65
+
66
+ # 设置环境变量
67
+ export NODE_ENV=development
68
+
69
+ # 启动服务
70
+ echo "🚀 正在启动 Electron MCP 服务..."
71
+ echo "端口: 8101"
72
+ echo "调试端口: 9221"
73
+ echo ""
74
+ echo "服务启动后可以访问:"
75
+ echo "- MCP 服务: http://localhost:8101/mcp"
76
+ echo "- API 文档: http://localhost:8101/docs"
77
+ echo "- 远程调试: http://localhost:9221"
78
+ echo ""
79
+ echo "按 Ctrl+C 停止服务"
80
+ echo "========================================="
81
+
82
+ # 启动应用
83
+ npm start
84
+
85
+ # 如果启动失败,显示错误信息
86
+ if [ $? -ne 0 ]; then
87
+ echo ""
88
+ echo "❌ 服务启动失败"
89
+ echo "请检查错误信息并重试"
90
+ read -p "按任意键退出..."
91
+ exit 1
92
+ fi