yuangs 1.3.22 → 1.3.25

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.
@@ -3,7 +3,7 @@ name: Auto Bump & Publish
3
3
  on:
4
4
  push:
5
5
  branches:
6
- - main # 如果你的默认分支不是 main,记得改成对应名字
6
+ - main # 如果你的默认分支不是 main,记得改成对应名字
7
7
 
8
8
  jobs:
9
9
  publish:
@@ -19,13 +19,13 @@ jobs:
19
19
  uses: actions/checkout@v4
20
20
  with:
21
21
  token: ${{ secrets.GITHUB_TOKEN }}
22
- fetch-depth: 0 # 完整历史,方便推 tag
22
+ fetch-depth: 0 # 完整历史,方便推 tag
23
23
 
24
24
  - name: Set up Node.js
25
25
  uses: actions/setup-node@v4
26
26
  with:
27
- node-version: '18'
28
- registry-url: 'https://registry.npmjs.org/'
27
+ node-version: "18"
28
+ registry-url: "https://registry.npmjs.org/"
29
29
 
30
30
  - name: Configure Git
31
31
  run: |
@@ -36,7 +36,7 @@ jobs:
36
36
  # [skip ci] 防止这个 commit 再次触发 workflow 形成死循环
37
37
  - name: Bump version
38
38
  run: |
39
- npm version patch -m "苑广山注:自动发布,升版本号:bump version to %s [skip ci]"
39
+ npm version patch -m "苑广山注:自动升版本号%s[skip ci]"
40
40
 
41
41
  # 推送 commit + tag 回 GitHub
42
42
  - name: Push changes
@@ -51,4 +51,4 @@ jobs:
51
51
  - name: Publish to npm
52
52
  run: npm publish --provenance
53
53
  env:
54
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
54
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/README.md CHANGED
@@ -63,8 +63,65 @@ yuangs ai
63
63
 
64
64
  Pong 游戏: https://wealth.want.biz/pages/pong.html
65
65
 
66
+ ## 配置自定义应用 (v1.3.24)
67
+
68
+ 从 v1.3.24 版本开始,您可以自定义应用列表,而无需修改源代码。
69
+
70
+ ### 配置文件格式
71
+
72
+ 创建一个 JSON 或 YAML 配置文件,支持以下格式之一:
73
+
74
+ 1. `yuangs.config.json` - 项目级别的 JSON 配置文件
75
+ 2. `.yuangs.json` - 项目级或用户主目录的 JSON 隐藏配置文件
76
+ 3. `yuangs.config.yaml` - 项目级别的 YAML 配置文件
77
+ 4. `yuangs.config.yml` - 项目级别的 YAML 配置文件
78
+ 5. `.yuangs.yaml` - 项目级或用户主目录的 YAML 隐藏配置文件
79
+ 6. `.yuangs.yml` - 项目级或用户主目录的 YAML 隐藏配置文件
80
+ 7. `~/.yuangs.json` - 全局用户 JSON 配置文件
81
+ 8. `~/.yuangs.yaml` - 全局用户 YAML 配置文件
82
+ 9. `~/.yuangs.yml` - 全局用户 YAML 配置文件
83
+
84
+ 配置文件示例:
85
+
86
+ ```json
87
+ {
88
+ "shici": "https://wealth.want.biz/shici/index.html",
89
+ "dict": "https://wealth.want.biz/pages/dict.html",
90
+ "pong": "https://wealth.want.biz/pages/pong.html",
91
+ "github": "https://github.com",
92
+ "calendar": "https://calendar.google.com",
93
+ "mail": "https://mail.google.com"
94
+ }
95
+ ```
96
+
97
+ ### 配置文件优先级
98
+
99
+ 配置文件按以下优先级顺序查找(高到低):
100
+
101
+ 1. 当前工作目录下的 `yuangs.config.json`
102
+ 2. 当前工作目录下的 `.yuangs.json`
103
+ 3. 用户主目录下的 `.yuangs.json`
104
+ 4. 项目目录下的 `yuangs.config.json`
105
+ 5. 项目目录下的 `.yuangs.json`
106
+ 6. 如果没有配置文件,则使用默认应用列表
107
+
108
+ ### 使用自定义应用
109
+
110
+ 创建配置文件后,您可以使用任何定义的应用名称作为命令:
111
+
112
+ ```bash
113
+ yuangs github # 打开 GitHub
114
+ yuangs calendar # 打开日历
115
+ yuangs mail # 打开邮箱
116
+ ```
117
+
118
+ 使用 `yuangs list` 命令查看当前加载的所有应用。
119
+
66
120
  ## 近期主要更新日志
67
121
 
122
+ ### v1.3.22 (2025-11-30)
123
+ - **新增** AI 命令支持 `-p` `-f` `-l` 简写,快速选择gemini默认模型
124
+
68
125
  ### v1.3.6 (2025-11-29)
69
126
 
70
127
  - **新增** AI 命令交互模式:直接输入 `yuangs ai` 即可进入一问一答模式,无需每次输入问题,quit 或 exit 可退出。
package/cli.js CHANGED
@@ -13,10 +13,24 @@ function printHelp() {
13
13
  console.log(chalk.gray('仓库地址: https://www.npmjs.com/package/yuangs?activeTab=readme\n'));
14
14
  console.log(chalk.white('使用方法:') + chalk.gray(' yuangs <命令> [参数]\n'));
15
15
  console.log(chalk.bold('命令列表:'));
16
+
17
+ // Show default commands
16
18
  console.log(` ${chalk.green('shici')} 打开古诗词 PWA`);
17
19
  console.log(` ${chalk.green('dict')} 打开英语词典`);
18
20
  console.log(` ${chalk.green('pong')} 打开 Pong 游戏`);
19
21
  console.log(` ${chalk.green('list')} 列出所有应用链接`);
22
+
23
+ // Show dynamically configured apps
24
+ const dynamicApps = Object.keys(yuangs.urls).filter(key =>
25
+ !['shici', 'dict', 'pong'].includes(key)
26
+ );
27
+ if (dynamicApps.length > 0) {
28
+ console.log(chalk.bold('\n自定义应用:'));
29
+ dynamicApps.forEach(app => {
30
+ console.log(` ${chalk.green(app)} 打开 ${app} 应用`);
31
+ });
32
+ }
33
+
20
34
  console.log(` ${chalk.green('ai')} "<问题>" 向 AI 提问(不写问题进入交互模式)`);
21
35
  console.log(` ${chalk.gray('--model, -m <模型名称>')} 指定 AI 模型 (可选)`);
22
36
  console.log(` ${chalk.gray('-p -f -l')} 指定 pro,flash,lite 模型 (可选)`);
@@ -26,6 +40,7 @@ function printHelp() {
26
40
  console.log(` ${chalk.gray('/history')} 查看对话历史\n`);
27
41
  console.log(chalk.gray('AI 示例: yuangs ai "你好" --model gemini-pro-latest'));
28
42
  console.log(chalk.gray('普通示例: yuangs shici\n'));
43
+ console.log(chalk.gray('配置文件: 您可以通过创建 yuangs.config.json 或 ~/.yuangs.json 来自定义应用列表\n'));
29
44
  }
30
45
 
31
46
  function printSuccess(app, url) {
@@ -185,17 +200,20 @@ async function handleAICommand() {
185
200
  await askOnce(question, model);
186
201
  }
187
202
 
203
+ // Check if the command matches one of the configured apps
204
+ const isAppCommand = Object.keys(yuangs.urls).includes(command);
205
+
188
206
  switch (command) {
189
207
  case 'shici':
190
- printSuccess('古诗词应用', yuangs.urls.shici);
208
+ printSuccess('古诗词应用', yuangs.urls.shici || 'N/A');
191
209
  yuangs.openShici();
192
210
  break;
193
211
  case 'dict':
194
- printSuccess('英语词典', yuangs.urls.dict);
212
+ printSuccess('英语词典', yuangs.urls.dict || 'N/A');
195
213
  yuangs.openDict();
196
214
  break;
197
215
  case 'pong':
198
- printSuccess('Pong 游戏', yuangs.urls.pong);
216
+ printSuccess('Pong 游戏', yuangs.urls.pong || 'N/A');
199
217
  yuangs.openPong();
200
218
  break;
201
219
  case 'list':
@@ -212,7 +230,18 @@ switch (command) {
212
230
  case 'help':
213
231
  case '--help':
214
232
  case '-h':
215
- default:
216
233
  printHelp();
217
234
  break;
235
+ default:
236
+ // If it's an app command but not one of the named ones, handle it with the dynamic function
237
+ if (isAppCommand) {
238
+ printSuccess(command, yuangs.urls[command]);
239
+ yuangs.openApp(command);
240
+ } else if (command) {
241
+ console.log(chalk.red(`\n错误: 未知命令 '${command}'\n`));
242
+ printHelp();
243
+ } else {
244
+ printHelp();
245
+ }
246
+ break;
218
247
  }
package/index.js CHANGED
@@ -1,15 +1,74 @@
1
1
  const { exec } = require('child_process');
2
2
  const axios = require('axios');
3
+ const fs = require('fs');
4
+ const path = require('path');
3
5
 
4
6
  // Store conversation history
5
7
  let conversationHistory = [];
6
8
 
7
- const APPS = {
9
+ // Default apps (fallback if no config file exists)
10
+ const DEFAULT_APPS = {
8
11
  shici: 'https://wealth.want.biz/shici/index.html',
9
12
  dict: 'https://wealth.want.biz/pages/dict.html',
10
13
  pong: 'https://wealth.want.biz/pages/pong.html'
11
14
  };
12
15
 
16
+ // Load apps from configuration file
17
+ function loadAppsConfig() {
18
+ // Define possible config file locations (JSON and YAML)
19
+ const configPaths = [
20
+ path.join(process.cwd(), 'yuangs.config.json'), // Current working directory
21
+ path.join(process.cwd(), '.yuangs.json'), // Current working directory dot file
22
+ path.join(process.cwd(), 'yuangs.config.yaml'), // Current working directory YAML
23
+ path.join(process.cwd(), 'yuangs.config.yml'), // Current working directory YAML
24
+ path.join(process.cwd(), '.yuangs.yaml'), // Current working directory dot YAML
25
+ path.join(process.cwd(), '.yuangs.yml'), // Current working directory dot YAML
26
+ path.join(require('os').homedir(), '.yuangs.json'), // User home directory
27
+ path.join(require('os').homedir(), '.yuangs.yaml'), // User home directory YAML
28
+ path.join(require('os').homedir(), '.yuangs.yml'), // User home directory YAML
29
+ path.join(__dirname, 'yuangs.config.json'), // Project directory
30
+ path.join(__dirname, '.yuangs.json'), // Project directory dot file
31
+ path.join(__dirname, 'yuangs.config.yaml'), // Project directory YAML
32
+ path.join(__dirname, 'yuangs.config.yml') // Project directory YAML
33
+ ];
34
+
35
+ for (const configPath of configPaths) {
36
+ if (fs.existsSync(configPath)) {
37
+ try {
38
+ const configContent = fs.readFileSync(configPath, 'utf8');
39
+
40
+ // Determine if it's JSON or YAML based on file extension
41
+ let config;
42
+ if (configPath.endsWith('.json')) {
43
+ config = JSON.parse(configContent);
44
+ } else {
45
+ // For YAML files, we need to require the yaml parser
46
+ let yaml;
47
+ try {
48
+ yaml = require('js-yaml');
49
+ } catch (yamlError) {
50
+ console.warn(`Warning: js-yaml not installed, skipping YAML file ${configPath}`);
51
+ console.warn('Install js-yaml with: npm install js-yaml');
52
+ continue; // Skip this file and try the next config file
53
+ }
54
+ config = yaml.load(configContent);
55
+ }
56
+
57
+ // If config has an 'apps' property, use it, otherwise use the whole config as apps
58
+ return config.apps || config;
59
+ } catch (error) {
60
+ console.warn(`Warning: Could not parse config file at ${configPath}:`, error.message);
61
+ // Continue to next config file
62
+ }
63
+ }
64
+ }
65
+
66
+ // If no config file is found, use default apps
67
+ return DEFAULT_APPS;
68
+ }
69
+
70
+ const APPS = loadAppsConfig();
71
+
13
72
  function openUrl(url) {
14
73
  let command;
15
74
  switch (process.platform) {
@@ -91,9 +150,20 @@ async function getAIAnswer(question, model, includeHistory = true) {
91
150
 
92
151
  module.exports = {
93
152
  urls: APPS,
94
- openShici: () => openUrl(APPS.shici),
95
- openDict: () => openUrl(APPS.dict),
96
- openPong: () => openUrl(APPS.pong),
153
+ // Dynamic function to open any app by key
154
+ openApp: (appKey) => {
155
+ const url = APPS[appKey];
156
+ if (url) {
157
+ openUrl(url);
158
+ return true;
159
+ }
160
+ console.error(`App '${appKey}' not found`);
161
+ return false;
162
+ },
163
+ // Specific functions for default apps (for backward compatibility)
164
+ openShici: () => openUrl(APPS.shici || DEFAULT_APPS.shici),
165
+ openDict: () => openUrl(APPS.dict || DEFAULT_APPS.dict),
166
+ openPong: () => openUrl(APPS.pong || DEFAULT_APPS.pong),
97
167
  listApps: () => {
98
168
  console.log('--- YGS Apps ---');
99
169
  Object.entries(APPS).forEach(([key, url]) => console.log(`${key}: ${url}`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yuangs",
3
- "version": "1.3.22",
3
+ "version": "1.3.25",
4
4
  "description": "苑广山的个人应用集合 CLI(彩色版)",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -15,7 +15,7 @@
15
15
  "tools",
16
16
  "colorful"
17
17
  ],
18
- "homepage": "https://github.com/yuanguangshan/npm_yuangs#readme",
18
+ "homepage": "https://github.com/yauangshan/npm_yuangs#readme",
19
19
  "repository": {
20
20
  "type": "git",
21
21
  "url": "git+https://github.com/yuanguangshan/npm_yuangs.git"
@@ -27,7 +27,8 @@
27
27
  "license": "ISC",
28
28
  "dependencies": {
29
29
  "axios": "^1.13.2",
30
- "chalk": "^4.1.2"
30
+ "chalk": "^4.1.2",
31
+ "js-yaml": "^4.1.0"
31
32
  },
32
33
  "devDependencies": {
33
34
  "jest": "^29.7.0"
@@ -14,6 +14,16 @@ describe('Module: index.js', () => {
14
14
  expect(yuangs.urls.shici).toContain('shici/index.html');
15
15
  });
16
16
 
17
+ test('should have openApp function', () => {
18
+ expect(typeof yuangs.openApp).toBe('function');
19
+ });
20
+
21
+ test('should have backward compatibility functions', () => {
22
+ expect(typeof yuangs.openShici).toBe('function');
23
+ expect(typeof yuangs.openDict).toBe('function');
24
+ expect(typeof yuangs.openPong).toBe('function');
25
+ });
26
+
17
27
  test('should manage conversation history correctly', () => {
18
28
  yuangs.addToConversationHistory('user', 'hello');
19
29
  let history = yuangs.getConversationHistory();
@@ -0,0 +1,8 @@
1
+ {
2
+ "shici": "https://wealth.want.biz/shici/index.html",
3
+ "dict": "https://wealth.want.biz/pages/dict.html",
4
+ "pong": "https://wealth.want.biz/pages/pong.html",
5
+ "github": "https://github.com",
6
+ "calendar": "https://calendar.google.com",
7
+ "mail": "https://mail.google.com"
8
+ }
@@ -0,0 +1,18 @@
1
+ # Example configuration file for yuangs CLI
2
+ # Add your custom applications here
3
+
4
+ shici: "https://wealth.want.biz/shici/index.html"
5
+ dict: "https://wealth.want.biz/pages/dict.html"
6
+ pong: "https://wealth.want.biz/pages/pong.html"
7
+ github: "https://github.com"
8
+ calendar: "https://calendar.google.com"
9
+ mail: "https://mail.google.com"
10
+
11
+ # You can also use the apps property if you prefer to group them
12
+ # apps:
13
+ # shici: "https://wealth.want.biz/shici/index.html"
14
+ # dict: "https://wealth.want.biz/pages/dict.html"
15
+ # pong: "https://wealth.want.biz/pages/pong.html"
16
+ # github: "https://github.com"
17
+ # calendar: "https://calendar.google.com"
18
+ # mail: "https://mail.google.com"