shawnxixi-cli 0.3.0 → 1.1.0
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/.env.example +8 -2
- package/.github/workflows/ci.yml +9 -22
- package/.github/workflows/release.yml +30 -0
- package/CLAUDE.md +167 -63
- package/README.md +345 -65
- package/commitlint.config.js +10 -0
- package/dist/commands/biz/calendar.d.ts +17 -2
- package/dist/commands/biz/calendar.d.ts.map +1 -1
- package/dist/commands/biz/calendar.js +47 -9
- package/dist/commands/biz/calendar.js.map +1 -1
- package/dist/commands/biz/finance.d.ts +32 -1
- package/dist/commands/biz/finance.d.ts.map +1 -1
- package/dist/commands/biz/finance.js +99 -12
- package/dist/commands/biz/finance.js.map +1 -1
- package/dist/commands/biz/health.d.ts +32 -0
- package/dist/commands/biz/health.d.ts.map +1 -0
- package/dist/commands/biz/health.js +92 -0
- package/dist/commands/biz/health.js.map +1 -0
- package/dist/commands/biz/item.d.ts +41 -0
- package/dist/commands/biz/item.d.ts.map +1 -1
- package/dist/commands/biz/item.js +89 -5
- package/dist/commands/biz/item.js.map +1 -1
- package/dist/commands/biz/record.d.ts +0 -8
- package/dist/commands/biz/record.d.ts.map +1 -1
- package/dist/commands/biz/record.js +29 -8
- package/dist/commands/biz/record.js.map +1 -1
- package/dist/commands/biz/task.d.ts +38 -0
- package/dist/commands/biz/task.d.ts.map +1 -0
- package/dist/commands/biz/task.js +110 -0
- package/dist/commands/biz/task.js.map +1 -0
- package/dist/commands/biz/todo.d.ts +52 -8
- package/dist/commands/biz/todo.d.ts.map +1 -1
- package/dist/commands/biz/todo.js +167 -17
- package/dist/commands/biz/todo.js.map +1 -1
- package/dist/commands/sys/health.d.ts.map +1 -1
- package/dist/commands/sys/health.js +20 -3
- package/dist/commands/sys/health.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +281 -42
- package/dist/index.js.map +1 -1
- package/dist/services/api.d.ts +22 -8
- package/dist/services/api.d.ts.map +1 -1
- package/dist/services/api.js +108 -28
- package/dist/services/api.js.map +1 -1
- package/dist/utils/env.d.ts +16 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +78 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/finance.model.d.ts +80 -0
- package/dist/utils/finance.model.d.ts.map +1 -0
- package/dist/utils/finance.model.js +150 -0
- package/dist/utils/finance.model.js.map +1 -0
- package/dist/utils/output.d.ts +42 -0
- package/dist/utils/output.d.ts.map +1 -0
- package/dist/utils/output.js +124 -0
- package/dist/utils/output.js.map +1 -0
- package/dist/utils/todo.model.d.ts +55 -0
- package/dist/utils/todo.model.d.ts.map +1 -0
- package/dist/utils/todo.model.js +135 -0
- package/dist/utils/todo.model.js.map +1 -0
- package/package.json +18 -2
- package/src/commands/biz/calendar.ts +61 -10
- package/src/commands/biz/finance.ts +112 -13
- package/src/commands/biz/health.ts +96 -0
- package/src/commands/biz/item.ts +113 -6
- package/src/commands/biz/record.ts +32 -8
- package/src/commands/biz/task.ts +115 -0
- package/src/commands/biz/todo.ts +193 -21
- package/src/commands/sys/health.ts +23 -3
- package/src/index.ts +311 -54
- package/src/services/api.ts +111 -30
- package/src/utils/env.ts +85 -0
- package/src/utils/finance.model.ts +182 -0
- package/src/utils/output.ts +126 -0
- package/src/utils/todo.model.ts +167 -0
- package/tests/commands/finance.test.ts +281 -0
- package/tests/commands/item.test.ts +215 -0
- package/tests/commands/todo.test.ts +292 -9
- package/tests/services/api.test.ts +292 -20
- package/tests/utils/finance.model.test.ts +319 -0
- package/tests/utils/todo.model.test.ts +315 -0
|
@@ -4,20 +4,40 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { apiService } from '../../services/api';
|
|
7
|
+
import { output, outputError, createLoading, isDryRun, dryRunLog } from '../../utils/output';
|
|
7
8
|
|
|
8
9
|
export const syncHealth = async (dataType?: string, options: { startDate?: string; endDate?: string } = {}) => {
|
|
10
|
+
const loading = createLoading('处理健康数据...');
|
|
11
|
+
|
|
9
12
|
try {
|
|
10
13
|
if (dataType || options.startDate || options.endDate) {
|
|
11
14
|
// 查询模式
|
|
15
|
+
if (isDryRun()) {
|
|
16
|
+
loading.stop();
|
|
17
|
+
dryRunLog('查询健康数据', { dataType, ...options });
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
loading.start();
|
|
12
22
|
const result = await apiService.queryHealthData(dataType, options.startDate, options.endDate);
|
|
13
|
-
|
|
23
|
+
loading.succeed('健康数据加载成功');
|
|
24
|
+
output(result);
|
|
14
25
|
} else {
|
|
15
26
|
// 同步模式
|
|
27
|
+
if (isDryRun()) {
|
|
28
|
+
loading.stop();
|
|
29
|
+
dryRunLog('同步健康数据', {});
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
loading.start();
|
|
16
34
|
const result = await apiService.syncHealthData();
|
|
17
|
-
|
|
35
|
+
loading.succeed('健康数据同步成功');
|
|
36
|
+
output(result);
|
|
18
37
|
}
|
|
19
38
|
} catch (error: any) {
|
|
20
|
-
|
|
39
|
+
loading.fail('健康数据操作失败');
|
|
40
|
+
outputError(error.message);
|
|
21
41
|
process.exit(1);
|
|
22
42
|
}
|
|
23
43
|
};
|
package/src/index.ts
CHANGED
|
@@ -4,45 +4,110 @@
|
|
|
4
4
|
* shawnxixi-cli
|
|
5
5
|
* 肖嘻 CLI 工具入口
|
|
6
6
|
* 命令命名空间:biz:*(日常业务)、sys:*(系统操作)
|
|
7
|
+
*
|
|
8
|
+
* 全局参数:
|
|
9
|
+
* --json 输出 JSON 格式
|
|
10
|
+
* --quiet 静默模式(只输出关键信息)
|
|
11
|
+
* --dry-run 预览模式(不实际调用 API)
|
|
7
12
|
*/
|
|
8
13
|
|
|
9
14
|
import { Command } from 'commander';
|
|
15
|
+
import { version } from '../package.json';
|
|
10
16
|
import { todoCommands } from './commands/biz/todo';
|
|
11
17
|
import { recordCommands } from './commands/biz/record';
|
|
12
18
|
import { financeCommands } from './commands/biz/finance';
|
|
13
19
|
import { itemCommands } from './commands/biz/item';
|
|
14
20
|
import { calendarCommands } from './commands/biz/calendar';
|
|
15
|
-
import {
|
|
21
|
+
import { taskCommands } from './commands/biz/task';
|
|
22
|
+
import { healthCommands } from './commands/biz/health';
|
|
23
|
+
import { setGlobalFlags, output } from './utils/output';
|
|
24
|
+
|
|
25
|
+
// 预解析全局参数(在 Commander 解析之前)
|
|
26
|
+
const rawArgs = process.argv.slice(2);
|
|
27
|
+
const globalFlags = {
|
|
28
|
+
json: rawArgs.includes('--json'),
|
|
29
|
+
quiet: rawArgs.includes('--quiet'),
|
|
30
|
+
dryRun: rawArgs.includes('--dry-run'),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// 设置全局标志
|
|
34
|
+
setGlobalFlags(globalFlags);
|
|
35
|
+
|
|
36
|
+
// 过滤掉全局参数,避免干扰 commander 解析
|
|
37
|
+
const filteredArgs = rawArgs.filter(arg => !['--json', '--quiet', '--dry-run'].includes(arg));
|
|
16
38
|
|
|
17
39
|
const program = new Command();
|
|
18
40
|
|
|
19
41
|
program
|
|
20
42
|
.name('shawnxixi')
|
|
21
|
-
.description('肖嘻 CLI 工具')
|
|
22
|
-
.version(
|
|
43
|
+
.description('肖嘻 CLI 工具 - 日常业务与系统管理')
|
|
44
|
+
.version(version);
|
|
23
45
|
|
|
24
46
|
// ============ biz ============
|
|
25
47
|
|
|
26
48
|
const biz = program.command('biz').description('日常业务命令');
|
|
27
49
|
|
|
28
|
-
// biz todo
|
|
29
|
-
|
|
50
|
+
// -------- biz todo --------
|
|
51
|
+
// biz todo create 创建待办
|
|
52
|
+
// biz todo list 列出待办
|
|
53
|
+
// biz todo edit 编辑待办
|
|
54
|
+
// biz todo done 标记完成
|
|
55
|
+
// biz todo delete 删除待办
|
|
56
|
+
// biz todo repeat 完成并生成下次 occurrence
|
|
57
|
+
// biz todo subtask 创建子待办
|
|
58
|
+
// biz todo subtasks 列出子待办
|
|
59
|
+
const todo = biz.command('todo').description('待办管理(对标滴答清单)');
|
|
30
60
|
|
|
31
61
|
todo
|
|
32
62
|
.command('create <title>')
|
|
33
63
|
.description('创建待办')
|
|
34
64
|
.option('--due <date>', '截止日期 YYYY-MM-DD')
|
|
35
65
|
.option('--priority <level>', '优先级 low|medium|high', 'medium')
|
|
36
|
-
.
|
|
37
|
-
|
|
66
|
+
.option('--tags <tags>', '标签,逗号分隔')
|
|
67
|
+
.option('--repeat <rule>', '重复规则 daily|weekly|monthly')
|
|
68
|
+
.option('--end-date <date>', '重复结束日期 YYYY-MM-DD')
|
|
69
|
+
.option('--parent-id <id>', '父待办 ID(创建子待办)')
|
|
70
|
+
.action(async (title: string, options: Record<string, string>) => {
|
|
71
|
+
await todoCommands.create(title, {
|
|
72
|
+
due: options.due,
|
|
73
|
+
priority: options.priority,
|
|
74
|
+
tags: options.tags,
|
|
75
|
+
repeat: options.repeat,
|
|
76
|
+
endDate: options.endDate,
|
|
77
|
+
parentId: options.parentId,
|
|
78
|
+
});
|
|
38
79
|
});
|
|
39
80
|
|
|
40
81
|
todo
|
|
41
82
|
.command('list')
|
|
42
83
|
.description('列出待办')
|
|
43
|
-
.option('--status <status>', '状态过滤')
|
|
44
|
-
.
|
|
45
|
-
|
|
84
|
+
.option('--status <status>', '状态过滤 pending|done')
|
|
85
|
+
.option('--priority <level>', '优先级过滤 low|medium|high')
|
|
86
|
+
.option('--tags <tags>', '标签过滤,逗号分隔')
|
|
87
|
+
.action(async (options: Record<string, string>) => {
|
|
88
|
+
await todoCommands.list({
|
|
89
|
+
status: options.status,
|
|
90
|
+
priority: options.priority,
|
|
91
|
+
tags: options.tags,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
todo
|
|
96
|
+
.command('edit <id>')
|
|
97
|
+
.description('编辑待办')
|
|
98
|
+
.option('--title <title>', '新标题')
|
|
99
|
+
.option('--status <status>', '新状态 pending|done')
|
|
100
|
+
.option('--priority <level>', '新优先级 low|medium|high')
|
|
101
|
+
.option('--due <date>', '新截止日期 YYYY-MM-DD')
|
|
102
|
+
.option('--tags <tags>', '新标签,逗号分隔')
|
|
103
|
+
.action(async (id: string, options: Record<string, string>) => {
|
|
104
|
+
await todoCommands.update(parseInt(id, 10), {
|
|
105
|
+
title: options.title,
|
|
106
|
+
status: options.status,
|
|
107
|
+
priority: options.priority,
|
|
108
|
+
due: options.due,
|
|
109
|
+
tags: options.tags,
|
|
110
|
+
});
|
|
46
111
|
});
|
|
47
112
|
|
|
48
113
|
todo
|
|
@@ -59,8 +124,81 @@ todo
|
|
|
59
124
|
await todoCommands.delete(parseInt(id, 10));
|
|
60
125
|
});
|
|
61
126
|
|
|
62
|
-
|
|
63
|
-
|
|
127
|
+
todo
|
|
128
|
+
.command('repeat <id>')
|
|
129
|
+
.description('完成待办并生成下次 occurrence(适用于重复待办)')
|
|
130
|
+
.action(async (id: string) => {
|
|
131
|
+
await todoCommands.repeat(parseInt(id, 10));
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
todo
|
|
135
|
+
.command('subtask <parent-id>')
|
|
136
|
+
.description('创建子待办')
|
|
137
|
+
.requiredOption('--title <title>', '子待办标题(必需)')
|
|
138
|
+
.action(async (parentId: string, options: Record<string, string>) => {
|
|
139
|
+
await todoCommands.subtask(parseInt(parentId, 10), { title: options.title });
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
todo
|
|
143
|
+
.command('subtasks <parent-id>')
|
|
144
|
+
.description('列出子待办')
|
|
145
|
+
.action(async (parentId: string) => {
|
|
146
|
+
await todoCommands.subtasks(parseInt(parentId, 10));
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// -------- biz task --------
|
|
150
|
+
// biz task create 创建任务
|
|
151
|
+
// biz task list 列出任务
|
|
152
|
+
// biz task update 更新任务
|
|
153
|
+
// biz task delete 删除任务
|
|
154
|
+
const task = biz.command('task').description('任务管理(对标系统任务)');
|
|
155
|
+
|
|
156
|
+
task
|
|
157
|
+
.command('list')
|
|
158
|
+
.description('列出任务')
|
|
159
|
+
.option('--status <status>', '状态过滤 pending|running|done')
|
|
160
|
+
.option('--source <source>', '来源过滤 openclaw|cli')
|
|
161
|
+
.action(async (options: Record<string, string>) => {
|
|
162
|
+
await taskCommands.list({ status: options.status, source: options.source });
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
task
|
|
166
|
+
.command('create <title>')
|
|
167
|
+
.description('创建任务')
|
|
168
|
+
.option('--source <source>', '来源 openclaw|cli', 'cli')
|
|
169
|
+
.option('--openclaw-id <id>', 'OpenClaw ID')
|
|
170
|
+
.option('--priority <level>', '优先级 low|medium|high', 'medium')
|
|
171
|
+
.action(async (title: string, options: Record<string, string>) => {
|
|
172
|
+
await taskCommands.create(title, {
|
|
173
|
+
source: options.source,
|
|
174
|
+
openclawId: options.openclawId,
|
|
175
|
+
priority: options.priority,
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
task
|
|
180
|
+
.command('update <id>')
|
|
181
|
+
.description('更新任务')
|
|
182
|
+
.option('--status <status>', '新状态 pending|running|done')
|
|
183
|
+
.option('--priority <level>', '新优先级 low|medium|high')
|
|
184
|
+
.action(async (id: string, options: Record<string, string>) => {
|
|
185
|
+
await taskCommands.update(parseInt(id, 10), {
|
|
186
|
+
status: options.status,
|
|
187
|
+
priority: options.priority,
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
task
|
|
192
|
+
.command('delete <id>')
|
|
193
|
+
.description('删除任务')
|
|
194
|
+
.action(async (id: string) => {
|
|
195
|
+
await taskCommands.delete(parseInt(id, 10));
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// -------- biz record --------
|
|
199
|
+
// biz record create 创建记录
|
|
200
|
+
// biz record list 列出记录
|
|
201
|
+
const record = biz.command('record').description('记录管理(日记/宠物/笔记/想法)');
|
|
64
202
|
|
|
65
203
|
record
|
|
66
204
|
.command('create <title>')
|
|
@@ -68,29 +206,47 @@ record
|
|
|
68
206
|
.option('--content <text>', '内容')
|
|
69
207
|
.option('--type <type>', '类型 diary|pet|note|idea', 'diary')
|
|
70
208
|
.option('--tags <tags>', '标签,逗号分隔')
|
|
71
|
-
.action(async (title: string, options:
|
|
72
|
-
await recordCommands.create(title, options.content || '',
|
|
209
|
+
.action(async (title: string, options: Record<string, string>) => {
|
|
210
|
+
await recordCommands.create(title, options.content || '', {
|
|
211
|
+
type: options.type,
|
|
212
|
+
tags: options.tags,
|
|
213
|
+
});
|
|
73
214
|
});
|
|
74
215
|
|
|
75
216
|
record
|
|
76
217
|
.command('list')
|
|
77
218
|
.description('列出记录')
|
|
78
|
-
.option('--type <type>', '类型过滤')
|
|
79
|
-
.
|
|
80
|
-
|
|
219
|
+
.option('--type <type>', '类型过滤 diary|pet|note|idea')
|
|
220
|
+
.option('--tags <tags>', '标签过滤,逗号分隔')
|
|
221
|
+
.action(async (options: Record<string, string>) => {
|
|
222
|
+
await recordCommands.list({ type: options.type, tags: options.tags });
|
|
81
223
|
});
|
|
82
224
|
|
|
83
|
-
// biz finance
|
|
84
|
-
|
|
225
|
+
// -------- biz finance --------
|
|
226
|
+
// biz finance create 新增账单
|
|
227
|
+
// biz finance list 列出账单
|
|
228
|
+
// biz finance stats 账单统计
|
|
229
|
+
// biz finance report 月度报表
|
|
230
|
+
const finance = biz.command('finance').description('财务管理(对标记账类 App)');
|
|
85
231
|
|
|
86
232
|
finance
|
|
87
233
|
.command('create <amount>')
|
|
88
234
|
.description('记一笔账')
|
|
89
235
|
.option('--type <type>', '类型 income|expense', 'expense')
|
|
90
|
-
.option('--category <cat>', '分类'
|
|
91
|
-
.option('--
|
|
92
|
-
.
|
|
93
|
-
|
|
236
|
+
.option('--category <cat>', '分类')
|
|
237
|
+
.option('--note <text>', '备注')
|
|
238
|
+
.option('--account <account>', '账户 cash|card|alipay|wechat', 'cash')
|
|
239
|
+
.option('--date <date>', '日期 YYYY-MM-DD')
|
|
240
|
+
.option('--tags <tags>', '标签,逗号分隔')
|
|
241
|
+
.action(async (amount: string, options: Record<string, string>) => {
|
|
242
|
+
await financeCommands.create(amount, {
|
|
243
|
+
type: options.type,
|
|
244
|
+
category: options.category,
|
|
245
|
+
note: options.note,
|
|
246
|
+
account: options.account,
|
|
247
|
+
date: options.date,
|
|
248
|
+
tags: options.tags,
|
|
249
|
+
});
|
|
94
250
|
});
|
|
95
251
|
|
|
96
252
|
finance
|
|
@@ -98,12 +254,37 @@ finance
|
|
|
98
254
|
.description('列出账单')
|
|
99
255
|
.option('--type <type>', '类型过滤 income|expense')
|
|
100
256
|
.option('--category <cat>', '分类过滤')
|
|
101
|
-
.
|
|
102
|
-
|
|
257
|
+
.option('--month <month>', '月份过滤 YYYY-MM')
|
|
258
|
+
.action(async (options: Record<string, string>) => {
|
|
259
|
+
await financeCommands.list({
|
|
260
|
+
type: options.type,
|
|
261
|
+
category: options.category,
|
|
262
|
+
month: options.month,
|
|
263
|
+
});
|
|
103
264
|
});
|
|
104
265
|
|
|
105
|
-
|
|
106
|
-
|
|
266
|
+
finance
|
|
267
|
+
.command('stats')
|
|
268
|
+
.description('账单统计')
|
|
269
|
+
.option('--month <month>', '月份 YYYY-MM', new Date().toISOString().slice(0, 7))
|
|
270
|
+
.action(async (options: Record<string, string>) => {
|
|
271
|
+
await financeCommands.stats({ month: options.month });
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
finance
|
|
275
|
+
.command('report')
|
|
276
|
+
.description('月度报表')
|
|
277
|
+
.option('--month <month>', '月份 YYYY-MM', new Date().toISOString().slice(0, 7))
|
|
278
|
+
.action(async (options: Record<string, string>) => {
|
|
279
|
+
await financeCommands.report({ month: options.month });
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// -------- biz item --------
|
|
283
|
+
// biz item create 添加物品
|
|
284
|
+
// biz item list 列出物品
|
|
285
|
+
// biz item expiring 即将过期物品
|
|
286
|
+
// biz item stats 库存统计
|
|
287
|
+
const item = biz.command('item').description('物品管理(对标物品清单 App)');
|
|
107
288
|
|
|
108
289
|
item
|
|
109
290
|
.command('create <name>')
|
|
@@ -111,63 +292,139 @@ item
|
|
|
111
292
|
.option('--location <loc>', '存放位置')
|
|
112
293
|
.option('--expire <date>', '过期日期 YYYY-MM-DD')
|
|
113
294
|
.option('--category <cat>', '分类')
|
|
114
|
-
.
|
|
115
|
-
|
|
295
|
+
.option('--quantity <n>', '数量', parseInt)
|
|
296
|
+
.option('--unit <unit>', '单位 个|瓶|盒|kg|g|ml|l')
|
|
297
|
+
.option('--brand <brand>', '品牌')
|
|
298
|
+
.option('--barcode <code>', '条码')
|
|
299
|
+
.option('--price <price>', '价格')
|
|
300
|
+
.option('--supplier <supplier>', '供应商')
|
|
301
|
+
.option('--purchase-date <date>', '购买日期 YYYY-MM-DD')
|
|
302
|
+
.action(async (name: string, options: Record<string, string>) => {
|
|
303
|
+
await itemCommands.create(name, {
|
|
304
|
+
location: options.location,
|
|
305
|
+
expire: options.expire,
|
|
306
|
+
category: options.category,
|
|
307
|
+
quantity: options.quantity ? parseInt(options.quantity) : undefined,
|
|
308
|
+
unit: options.unit,
|
|
309
|
+
brand: options.brand,
|
|
310
|
+
barcode: options.barcode,
|
|
311
|
+
price: options.price ? parseFloat(options.price) : undefined,
|
|
312
|
+
supplier: options.supplier,
|
|
313
|
+
purchaseDate: options.purchaseDate,
|
|
314
|
+
});
|
|
116
315
|
});
|
|
117
316
|
|
|
118
317
|
item
|
|
119
318
|
.command('list')
|
|
120
319
|
.description('列出物品')
|
|
121
320
|
.option('--category <cat>', '分类过滤')
|
|
122
|
-
.action(async (options:
|
|
123
|
-
await itemCommands.list(options);
|
|
321
|
+
.action(async (options: Record<string, string>) => {
|
|
322
|
+
await itemCommands.list({ category: options.category });
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
item
|
|
326
|
+
.command('expiring')
|
|
327
|
+
.description('即将过期的物品')
|
|
328
|
+
.option('--days <n>', '提前多少天提醒', '7')
|
|
329
|
+
.action(async (options: Record<string, string>) => {
|
|
330
|
+
await itemCommands.expiring({ days: options.days ? parseInt(options.days) : 7 });
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
item
|
|
334
|
+
.command('stats')
|
|
335
|
+
.description('物品库存统计')
|
|
336
|
+
.action(async () => {
|
|
337
|
+
await itemCommands.stats();
|
|
124
338
|
});
|
|
125
339
|
|
|
126
|
-
// biz calendar
|
|
127
|
-
|
|
340
|
+
// -------- biz calendar --------
|
|
341
|
+
// biz calendar create 创建日程
|
|
342
|
+
// biz calendar list 列出日程
|
|
343
|
+
const calendar = biz.command('calendar').description('日程管理(对标日历 App)');
|
|
128
344
|
|
|
129
345
|
calendar
|
|
130
346
|
.command('create <title>')
|
|
131
347
|
.description('创建日程')
|
|
132
|
-
.requiredOption('--
|
|
133
|
-
.requiredOption('--
|
|
348
|
+
.requiredOption('--from <datetime>', '开始时间 YYYY-MM-DD 或 YYYY-MM-DD HH:MM')
|
|
349
|
+
.requiredOption('--to <datetime>', '结束时间 YYYY-MM-DD 或 YYYY-MM-DD HH:MM')
|
|
350
|
+
.option('--location <loc>', '地点')
|
|
351
|
+
.option('--color <color>', '颜色 HEX 如 #ff0000')
|
|
134
352
|
.option('--desc <text>', '描述')
|
|
135
|
-
.action(async (title: string, options:
|
|
136
|
-
await calendarCommands.create(title,
|
|
353
|
+
.action(async (title: string, options: Record<string, string>) => {
|
|
354
|
+
await calendarCommands.create(title, {
|
|
355
|
+
from: options.from,
|
|
356
|
+
to: options.to,
|
|
357
|
+
location: options.location,
|
|
358
|
+
color: options.color,
|
|
359
|
+
desc: options.desc,
|
|
360
|
+
});
|
|
137
361
|
});
|
|
138
362
|
|
|
139
363
|
calendar
|
|
140
364
|
.command('list')
|
|
141
365
|
.description('列出日程')
|
|
142
|
-
.option('--from <datetime>', '开始时间')
|
|
143
|
-
.option('--to <datetime>', '结束时间')
|
|
144
|
-
.action(async (options:
|
|
145
|
-
await calendarCommands.list(options);
|
|
366
|
+
.option('--from <datetime>', '开始时间 YYYY-MM-DD')
|
|
367
|
+
.option('--to <datetime>', '结束时间 YYYY-MM-DD')
|
|
368
|
+
.action(async (options: Record<string, string>) => {
|
|
369
|
+
await calendarCommands.list({ from: options.from, to: options.to });
|
|
146
370
|
});
|
|
147
371
|
|
|
148
|
-
//
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const health =
|
|
372
|
+
// -------- biz health --------
|
|
373
|
+
// biz health log 记录健康数据
|
|
374
|
+
// biz health list 查询健康数据
|
|
375
|
+
// biz health sync 同步健康数据
|
|
376
|
+
const health = biz.command('health').description('健康数据管理(对标 Apple Health)');
|
|
153
377
|
|
|
154
378
|
health
|
|
155
|
-
.command('
|
|
156
|
-
.description('
|
|
157
|
-
.
|
|
158
|
-
|
|
379
|
+
.command('log')
|
|
380
|
+
.description('记录健康数据')
|
|
381
|
+
.requiredOption('--type <type>', '数据类型 heart_rate|steps|weight|sleep|blood_pressure|oxygen|body_temp')
|
|
382
|
+
.requiredOption('--value <value>', '数值')
|
|
383
|
+
.option('--unit <unit>', '单位 bpm|kg|steps|hours|mmHg|%|°C')
|
|
384
|
+
.option('--date <date>', '日期 YYYY-MM-DD', new Date().toISOString().slice(0, 10))
|
|
385
|
+
.action(async (options: Record<string, string>) => {
|
|
386
|
+
await healthCommands.log({
|
|
387
|
+
type: options.type,
|
|
388
|
+
value: options.value,
|
|
389
|
+
unit: options.unit,
|
|
390
|
+
date: options.date,
|
|
391
|
+
});
|
|
159
392
|
});
|
|
160
393
|
|
|
161
394
|
health
|
|
162
|
-
.command('
|
|
395
|
+
.command('list')
|
|
163
396
|
.description('查询健康数据')
|
|
397
|
+
.option('--type <type>', '数据类型过滤')
|
|
164
398
|
.option('--from <date>', '开始日期 YYYY-MM-DD')
|
|
165
399
|
.option('--to <date>', '结束日期 YYYY-MM-DD')
|
|
166
|
-
.action(async (
|
|
167
|
-
await
|
|
400
|
+
.action(async (options: Record<string, string>) => {
|
|
401
|
+
await healthCommands.list({
|
|
402
|
+
type: options.type,
|
|
403
|
+
from: options.from,
|
|
404
|
+
to: options.to,
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
health
|
|
409
|
+
.command('sync')
|
|
410
|
+
.description('同步健康数据(保留兼容)')
|
|
411
|
+
.action(async () => {
|
|
412
|
+
await healthCommands.sync();
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
// ============ sys ============
|
|
416
|
+
|
|
417
|
+
const sys = program.command('sys').description('系统命令');
|
|
418
|
+
|
|
419
|
+
sys
|
|
420
|
+
.command('health')
|
|
421
|
+
.description('健康检查')
|
|
422
|
+
.action(async () => {
|
|
423
|
+
output({ status: 'ok', timestamp: new Date().toISOString() });
|
|
168
424
|
});
|
|
169
425
|
|
|
170
|
-
|
|
426
|
+
// 解析过滤后的参数
|
|
427
|
+
program.parseAsync(['node', 'shawnxixi', ...filteredArgs]).catch((error) => {
|
|
171
428
|
console.error('Command failed:', error);
|
|
172
429
|
process.exit(1);
|
|
173
430
|
});
|