deepfish-ai 1.0.8 → 1.0.12

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.
package/README.md CHANGED
@@ -1,6 +1,5 @@
1
1
  <div align="center" style="display:flex;align-items: center;justify-content: center;">
2
- <img src="./images/logo2.png" alt="DeepFish" style="width:55px;" />
3
- <span style="font-size: 30px;font-weight: bold;color:#3386FE">DeepFish</span>
2
+ <img src="./images/title-img.png" alt="DeepFish" width="300" />
4
3
  </div>
5
4
 
6
5
  ---
@@ -25,13 +24,44 @@
25
24
  />
26
25
  </div>
27
26
 
28
- <img src="./images/banner.png" alt="AI Command Line Tool Screenshot" style="width:100%;text-align:center;" />
27
+ <img src="./images/banner.png" alt="banner" style="width:100%;text-align:center;" />
29
28
 
30
29
 
31
30
 
32
31
  - [English](README.md) | [中文](README_CN.md)
33
32
 
34
- [TOC]
33
+ ## Table of Contents
34
+
35
+ - [Table of Contents](#table-of-contents)
36
+ - [1. Introduction](#1-introduction)
37
+ - [2. Installation](#2-installation)
38
+ - [Prerequisites](#prerequisites)
39
+ - [Installation via npm](#installation-via-npm)
40
+ - [Installation from Source](#installation-from-source)
41
+ - [3. Quick Start](#3-quick-start)
42
+ - [4. Configuration](#4-configuration)
43
+ - [Initial Setup](#initial-setup)
44
+ - [Configuration Commands](#configuration-commands)
45
+ - [Configuration File Structure](#configuration-file-structure)
46
+ - [5. Usage](#5-usage)
47
+ - [Interactive Mode](#interactive-mode)
48
+ - [Direct Command Mode](#direct-command-mode)
49
+ - [Usage Examples](#usage-examples)
50
+ - [6. Extension Development](#6-extension-development)
51
+ - [Creating an Extension](#creating-an-extension)
52
+ - [Registering Extensions](#registering-extensions)
53
+ - [7. Recommendations](#7-recommendations)
54
+ - [AI Service Selection](#ai-service-selection)
55
+ - [8. Usage Notes](#8-usage-notes)
56
+ - [Using Relative Paths](#using-relative-paths)
57
+ - [9. Troubleshooting](#9-troubleshooting)
58
+ - [Configuration Issues](#configuration-issues)
59
+ - [AI Service Connection](#ai-service-connection)
60
+ - [Extension Not Loading](#extension-not-loading)
61
+ - [10. Contributing](#10-contributing)
62
+ - [11. License](#11-license)
63
+ - [12. Support](#12-support)
64
+
35
65
 
36
66
 
37
67
  ## 1. Introduction
@@ -66,7 +96,7 @@ npm install -g deepfish-ai
66
96
  ### Installation from Source
67
97
 
68
98
  ```bash
69
- git clone https://github.com/qq306863030/deepfish.git
99
+ git clone https://github.com/qq306863030/deepfish-ai.git
70
100
  cd deepfish
71
101
  npm install
72
102
  npm link
@@ -259,7 +289,7 @@ module.exports = {
259
289
  };
260
290
  ```
261
291
 
262
- #### Registering Extensions
292
+ ### Registering Extensions
263
293
 
264
294
  **Method 1: Using Command Line**
265
295
 
@@ -284,11 +314,18 @@ module.exports = {
284
314
 
285
315
  **Method 3: Automatic Scanning**
286
316
 
287
- The program automatically scans the following directories for directories starting with "deepfish-" on startup.
288
- 1. The npm global node_modules directory (extensions can be installed via `npm install -g deepfish-xxx`)
289
- 2. The node_modules directory in the current working directory
290
- 3. The current working directory
317
+ Rules for automatic scanning of extension modules upon program startup:
318
+
319
+ 1. Scanning locations:
320
+ - node_modules in the root directory
321
+ - node_modules in the command execution directory
322
+ - the command execution directory itself
291
323
 
324
+ 2. Scanned files:
325
+ - Extension packages under the @deepfish-ai directory
326
+ - Extension packages starting with "deepfish-"
327
+ - JavaScript extension files in the command execution directory, which are automatically loaded if they contain the strings 'module.exports', 'descriptions', and 'functions'
328
+
292
329
  ## 7. Recommendations
293
330
 
294
331
  ### AI Service Selection
package/README_CN.md CHANGED
@@ -1,6 +1,5 @@
1
1
  <div align="center" style="display:flex;align-items: center;justify-content: center;">
2
- <img src="./images/logo2.png" alt="DeepFish" style="width:55px;" />
3
- <span style="font-size: 30px;font-weight: bold;color:#3386FE">DeepFish</span>
2
+ <img src="./images/title-img.png" alt="DeepFish" width="300" />
4
3
  </div>
5
4
 
6
5
  ---
@@ -25,15 +24,44 @@
25
24
  />
26
25
  </div>
27
26
 
28
- <img src="./images/banner.png" alt="AI 命令行工具截图" style="width:100%;text-align:center;" />
27
+ <img src="./images/banner.png" alt="banner" style="width:100%;text-align:center;" />
29
28
 
30
29
 
31
30
 
32
31
 
33
32
  - [English](README.md) | [中文](README_CN.md)
34
33
 
35
- [TOC]
36
-
34
+ ## 目录
35
+
36
+ - [目录](#目录)
37
+ - [1. 介绍](#1-介绍)
38
+ - [2. 安装](#2-安装)
39
+ - [前置要求](#前置要求)
40
+ - [通过npm安装](#通过npm安装)
41
+ - [从源码安装](#从源码安装)
42
+ - [3. 快速使用](#3-快速使用)
43
+ - [4. 配置](#4-配置)
44
+ - [初始设置](#初始设置)
45
+ - [配置命令](#配置命令)
46
+ - [配置文件结构](#配置文件结构)
47
+ - [5. 使用方法](#5-使用方法)
48
+ - [交互模式](#交互模式)
49
+ - [直接命令模式](#直接命令模式)
50
+ - [使用示例](#使用示例)
51
+ - [6. 扩展开发](#6-扩展开发)
52
+ - [创建扩展](#创建扩展)
53
+ - [注册扩展](#注册扩展)
54
+ - [7. 建议](#7-建议)
55
+ - [AI服务选择](#ai服务选择)
56
+ - [8. 使用说明](#8-使用说明)
57
+ - [使用相对路径](#使用相对路径)
58
+ - [9. 故障排除](#9-故障排除)
59
+ - [配置问题](#配置问题)
60
+ - [AI服务连接](#ai服务连接)
61
+ - [扩展未加载](#扩展未加载)
62
+ - [10. 贡献](#10-贡献)
63
+ - [11. 许可证](#11-许可证)
64
+ - [12. 支持](#12-支持)
37
65
 
38
66
  ## 1. 介绍
39
67
 
@@ -66,7 +94,7 @@ npm install -g deepfish-ai
66
94
  ### 从源码安装
67
95
 
68
96
  ```bash
69
- git clone https://github.com/qq306863030/deepfish.git
97
+ git clone https://github.com/qq306863030/deepfish-ai.git
70
98
  cd deepfish
71
99
  npm install
72
100
  npm link
@@ -259,7 +287,7 @@ module.exports = {
259
287
  };
260
288
  ```
261
289
 
262
- #### 注册扩展
290
+ ### 注册扩展
263
291
 
264
292
  **方法1:使用命令行**
265
293
 
@@ -284,10 +312,15 @@ module.exports = {
284
312
 
285
313
  **方法3:自动扫描**
286
314
 
287
- 程序启动时会自动扫描以下目录中以“deepfish-”开头的目录。
288
- 1.程序npm全局node_modules目录(扩展可通过"npm install -g deepfish-xxx" 安装)
289
- 2.当前工作目录中的node_modules目录
290
- 3.当前工作目录
315
+ 程序启动时自动扫描扩展模块的规则:
316
+ 1. 扫描位置:
317
+ - 根目录的node_modules
318
+ - 命令执行目录的node_modules
319
+ - 命令执行目录
320
+ 2. 扫描文件:
321
+ - @deepfish-ai目录下的扩展包
322
+ - deepfish-开头的扩展包
323
+ - 命令执行目录的js扩展文件,js文件内包含'module.exports'、'descriptions'和'functions'字符串则视为扩展文件自动加载
291
324
 
292
325
  ## 7. 建议
293
326
 
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "deepfish-ai",
3
- "version": "1.0.8",
4
- "description": "An AI command-line tool that converts natural language instructions into operating system commands and file operations, supporting Ollama, DeepSeek, and other models compatible with the OpenAI API specification.",
3
+ "version": "1.0.12",
4
+ "description": "This is an AI-driven command-line tool built on Node.js, equipped with AI agent and workflow capabilities. It is compatible with a wide range of AI models, can convert natural language into cross-system terminal and file operation commands, and features high extensibility. It supports complex tasks such as translation, content creation, and format conversion, while allowing custom extensions to be automatically generated via AI.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
7
- "ai": "src/cli.js"
7
+ "ai": "src/cli/index.js"
8
8
  },
9
9
  "scripts": {
10
10
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -12,6 +12,8 @@
12
12
  "keywords": [
13
13
  "ai",
14
14
  "deepseek",
15
+ "agent",
16
+ "assistant",
15
17
  "cli",
16
18
  "command-line",
17
19
  "cmd",
@@ -23,12 +25,12 @@
23
25
  "license": "MIT",
24
26
  "repository": {
25
27
  "type": "git",
26
- "url": "https://github.com/qq306863030/deepfish.git"
28
+ "url": "https://github.com/qq306863030/deepfish-ai.git"
27
29
  },
28
30
  "bugs": {
29
- "url": "https://github.com/qq306863030/deepfish/issues"
31
+ "url": "https://github.com/qq306863030/deepfish-ai/issues"
30
32
  },
31
- "homepage": "https://github.com/qq306863030/deepfish#readme",
33
+ "homepage": "https://github.com/qq306863030/deepfish-ai#readme",
32
34
  "dependencies": {
33
35
  "axios": "^1.13.5",
34
36
  "chalk": "^4.1.0",
@@ -53,4 +55,4 @@
53
55
  "README_CN.md",
54
56
  "LICENSE"
55
57
  ]
56
- }
58
+ }
@@ -0,0 +1,231 @@
1
+ const path = require('path')
2
+ const os = require('os')
3
+ const fs = require('fs-extra')
4
+ const { defaultConfig } = require('./configTools')
5
+ const { logSuccess, logError, logInfo } = require('../core/utils/log')
6
+ const { GlobalVariable } = require('../core/globalVariable')
7
+
8
+ class ConfigManager {
9
+ config = null
10
+ configDir = path.join(os.homedir(), './.deepfish-ai')
11
+ configPath = path.join(this.configDir, './config.js')
12
+ constructor() {
13
+ this.initConfig()
14
+ GlobalVariable.configManager = this
15
+ }
16
+ // 初始化config
17
+ initConfig() {
18
+ fs.ensureDirSync(this.configDir)
19
+ // 判断之前版本的配置文件是否存在,如果存在则迁移到新目录
20
+ const isConfigExists = this.checkConfigExists()
21
+ if (
22
+ !isConfigExists &&
23
+ fs.pathExistsSync(path.join(os.homedir(), '.ai-cmd.config.js'))
24
+ ) {
25
+ fs.moveSync(path.join(os.homedir(), '.ai-cmd.config.js'), this.configPath)
26
+ } else if (!isConfigExists) {
27
+ this._writeConfig()
28
+ }
29
+ this.config = this._getConfig()
30
+ }
31
+
32
+ edit() {
33
+ const { exec } = require('child_process')
34
+ const platform = process.platform
35
+
36
+ let openCommand
37
+ if (process.env.EDITOR) {
38
+ openCommand = `${process.env.EDITOR} "${this.configPath}"`
39
+ } else if (platform === 'darwin') {
40
+ openCommand = `open -e "${this.configPath}"`
41
+ } else if (platform === 'win32') {
42
+ openCommand = `notepad "${this.configPath}"`
43
+ } else {
44
+ openCommand = `xdg-open "${this.configPath}"`
45
+ }
46
+ exec(openCommand, (error) => {
47
+ if (error) {
48
+ logError('Error opening configuration file:', error.message)
49
+ }
50
+ })
51
+ }
52
+
53
+ // 判断config是否存在
54
+ checkConfigExists() {
55
+ return fs.pathExistsSync(this.configPath)
56
+ }
57
+
58
+ // 重名验证
59
+ checkName(aiName) {
60
+ const existingIndex = this.config.ai.findIndex(
61
+ (item) => item.name === aiName,
62
+ )
63
+ return existingIndex !== -1
64
+ }
65
+
66
+ isAiListEmpty() {
67
+ return this.config.ai && this.config.ai.length === 0
68
+ }
69
+
70
+ // 添加一个aiConfig
71
+ addAiConfig(aiConfig) {
72
+ this.config.ai.push(aiConfig)
73
+ this._writeConfig(this.config)
74
+ logSuccess(`AI configuration "${aiConfig.name}" added successfully!`)
75
+ }
76
+
77
+ // 删除一个aiConfig
78
+ delAiConfig(aiName) {
79
+ const existingIndex = this.config.ai.findIndex(
80
+ (item) => item.name === aiName,
81
+ )
82
+ if (existingIndex === -1) {
83
+ logError(`Configuration with name "${aiName}" not found.`)
84
+ return
85
+ }
86
+ const currentAi = this.config.currentAi
87
+ // Check if it's the current configuration
88
+ if (currentAi === aiName) {
89
+ logError(`Cannot delete current configuration "${aiName}".`)
90
+ return
91
+ }
92
+ // Remove the configuration
93
+ this.config.ai.splice(existingIndex, 1)
94
+ this._writeConfig(this.config)
95
+ logSuccess(`AI configuration "${aiName}" deleted successfully!`)
96
+ }
97
+
98
+ // 设置当前Ai
99
+ setCurrentAi(aiName) {
100
+ // 查看列表中是否存在
101
+ const existingIndex = this.config.ai.findIndex(
102
+ (item) => item.name === aiName,
103
+ )
104
+ if (existingIndex === -1) {
105
+ logError(`Configuration with name "${aiName}" not found.`)
106
+ return
107
+ }
108
+ this.config.currentAi = aiName
109
+ this._writeConfig(this.config)
110
+ logSuccess(`Current AI configuration set to "${aiName}" successfully!`)
111
+ }
112
+
113
+ getCurrentAiConfig() {
114
+ return this.config.ai.find((item) => item.name === this.config.currentAi)
115
+ }
116
+
117
+ getCurrentAi() {
118
+ return this.config.currentAi
119
+ }
120
+
121
+ _getAiConfig(aiName) {
122
+ return this.config.ai.find((item) => item.name === aiName)
123
+ }
124
+
125
+ // 获取Ai列表
126
+ getAiList() {
127
+ console.log('AI Configurations')
128
+ console.log('='.repeat(50))
129
+ if (this.config.ai && Array.isArray(this.config.ai)) {
130
+ if (this.config.ai.length === 0) {
131
+ logError('No AI configurations found.')
132
+ } else {
133
+ this.config.ai.forEach((config, index) => {
134
+ const isCurrent = this.config.currentAi === config.name
135
+ logInfo(`${config.name} ${isCurrent ? '(current)' : ''}`)
136
+ })
137
+ }
138
+ } else {
139
+ logError('No AI configurations found.')
140
+ }
141
+ console.log('='.repeat(50))
142
+ }
143
+
144
+ // 重置config
145
+ resetConfig() {
146
+ console.log('Resetting configuration file:', this.configPath)
147
+ this._writeConfig()
148
+ this.config = this._getConfig()
149
+ logError('Configuration file has been reset to default settings.')
150
+ }
151
+
152
+ // 查看ai详情
153
+ viewAiConfigDetail(aiName) {
154
+ if (this.isAiListEmpty()) {
155
+ logError('No AI configurations found. Please add an AI configuration first.')
156
+ return
157
+ }
158
+ if (!aiName) {
159
+ aiName = this.config.currentAi
160
+ if (!aiName) {
161
+ logError('No current AI configuration set. Please input "ai config use <name>" to set a current configuration.')
162
+ return
163
+ }
164
+ }
165
+ const aiConfig = this._getAiConfig(aiName)
166
+ if (!aiConfig) {
167
+ logError('AI configuration not found. Please check the name and try again.')
168
+ return
169
+ }
170
+ logSuccess('AI Configuration Details')
171
+ logSuccess('='.repeat(50))
172
+ logInfo(`Name: ${aiConfig.name}`)
173
+ logInfo(`Type: ${aiConfig.type}`)
174
+ logInfo(`API Base URL: ${aiConfig.baseUrl}`)
175
+ logInfo(`Model: ${aiConfig.model}`)
176
+ if (aiConfig.apiKey) {
177
+ logInfo(`API Key: ${aiConfig.apiKey}`)
178
+ }
179
+ logInfo(`Temperature: ${aiConfig.temperature}`)
180
+ logInfo(`Max Tokens: ${aiConfig.maxTokens}`)
181
+ logInfo(`Streaming Output: ${aiConfig.stream ? 'Enabled' : 'Disabled'}`)
182
+ logInfo(
183
+ `Is Current: ${this.config.currentAi === aiConfig.name ? 'Yes' : 'No'}`,
184
+ )
185
+ logInfo(`File Path: ${this.configPath}`)
186
+ logSuccess('='.repeat(50))
187
+ }
188
+
189
+ // 更新扩展
190
+ updateExtensions(extensions) {
191
+ this.config.extensions = extensions
192
+ this._writeConfig(this.config)
193
+ logSuccess('Extensions updated successfully!')
194
+ }
195
+
196
+ // 删除扩展
197
+ removeExtensionByIndex(extIndex) {
198
+ const filePath = this.config.extensions.splice(extIndex, 1)
199
+ this._writeConfig(this.config)
200
+ logSuccess(
201
+ `Extension removed from config: ${filePath}.You can run 'ai ext ls' to view the changes.`,
202
+ )
203
+ }
204
+
205
+ removeExtensionByPath(filePath) {
206
+ this.config.extensions = this.config.extensions.filter(
207
+ (ext) => ext !== filePath,
208
+ )
209
+ this._writeConfig(this.config)
210
+ logSuccess(
211
+ `Extension removed from config: ${filePath}.You can run 'ai ext ls' to view the changes.`,
212
+ )
213
+ }
214
+
215
+ _getConfig() {
216
+ return require(this.configPath)
217
+ }
218
+
219
+ // 写入配置
220
+ _writeConfig(config) {
221
+ if (!config) {
222
+ config = defaultConfig
223
+ }
224
+ fs.writeFileSync(
225
+ this.configPath,
226
+ `module.exports = ${JSON.stringify(config, null, 2)}`,
227
+ )
228
+ }
229
+ }
230
+
231
+ module.exports = ConfigManager
@@ -0,0 +1,90 @@
1
+ const path = require("path");
2
+ const fs = require("fs-extra");
3
+ const { GlobalVariable } = require('../core/globalVariable')
4
+ const { logError, logSuccess } = require('../core/utils/log');
5
+ const { traverseFiles } = require("./configTools");
6
+
7
+ class ExtConfigManager {
8
+ constructor() {
9
+ this.configManager = GlobalVariable.configManager
10
+ }
11
+
12
+ // 添加
13
+ add(fileName) {
14
+ // 检查 fileName 是否为空
15
+ if (!fileName) {
16
+ logError('Extension file name is required.')
17
+ return
18
+ }
19
+ const filePath = path.resolve(process.cwd(), fileName)
20
+ // 判断是否路径是文件还是目录
21
+ if (fs.statSync(filePath).isDirectory()) {
22
+ // 扫描目录和子目录下所有js、cjs文件
23
+ const files = traverseFiles()
24
+ const jsFiles = files.filter(
25
+ (file) => file.endsWith('.js') || file.endsWith('.cjs'),
26
+ )
27
+ jsFiles.forEach((jsFile) => {
28
+ // 读取文件,查询文件内是否存在‘descriptions’和‘functions’
29
+ const fileContent = fs.readFileSync(jsFile, 'utf-8')
30
+ if (
31
+ fileContent.includes('module.exports') &&
32
+ fileContent.includes('descriptions') &&
33
+ fileContent.includes('functions')
34
+ ) {
35
+ this.add(jsFile)
36
+ }
37
+ })
38
+ return
39
+ }
40
+ // 判断文件是否存在
41
+ if (!fs.existsSync(filePath)) {
42
+ logError(`File not found: ${filePath}`)
43
+ return
44
+ }
45
+ const userConfig = this.configManager.config
46
+ userConfig.extensions.push(filePath)
47
+ // 数组去重
48
+ this.configManager.updateExtensions([...new Set(userConfig.extensions)])
49
+ }
50
+
51
+ // 删除
52
+ remove(fileName) {
53
+ const userConfig = this.configManager.config
54
+ // 增加对数字索引的支持
55
+ if (!isNaN(Number(fileName))) {
56
+ const extIndex = Number(fileName)
57
+ if (extIndex < 0 || extIndex >= userConfig.extensions.length) {
58
+ logError(`Invalid extension index: ${extIndex}`)
59
+ return
60
+ }
61
+ this.configManager.removeExtensionByIndex(extIndex)
62
+ return
63
+ }
64
+ const filePath = path.resolve(process.cwd(), fileName)
65
+ this.configManager.removeExtensionByPath(filePath)
66
+ }
67
+
68
+ // 查看列表
69
+ viewList() {
70
+ const extensions = this.configManager.config.extensions
71
+ if (extensions && Array.isArray(extensions)) {
72
+ console.log('='.repeat(50))
73
+ // 打印扩展列表,并加上索引
74
+ if (extensions.length === 0) {
75
+ console.log(`No extensions in config.`)
76
+ } else {
77
+ console.log('Extensions in config:')
78
+ extensions.forEach((ext, index) => {
79
+ console.log(`[${index}] ${ext}`)
80
+ })
81
+ }
82
+ console.log('='.repeat(50))
83
+ } else {
84
+ logSuccess(`No extensions in config.`)
85
+ }
86
+ }
87
+
88
+ }
89
+
90
+ module.exports = ExtConfigManager