@besile/scm-cli 2026.3.29
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.zh.md +451 -0
- package/bin/scm-cli.js +38 -0
- package/index.d.ts +59 -0
- package/package.json +51 -0
- package/src/cmd/auth/login.js +92 -0
- package/src/cmd/auth/logout.js +39 -0
- package/src/cmd/auth/status.js +29 -0
- package/src/cmd/auth/token.js +118 -0
- package/src/cmd/index.js +40 -0
- package/src/cmd/orders/material-orders.js +123 -0
- package/src/cmd/orders/production-orders.js +143 -0
- package/src/cmd/orders/qc-orders.js +109 -0
- package/src/cmd/root.js +41 -0
- package/src/core/scm-client.js +8 -0
- package/src/core/scm-errors.js +20 -0
- package/src/core/scm-logger.js +18 -0
- package/src/internal/auth/token-store.js +155 -0
- package/src/internal/client/scm-client.js +420 -0
- package/src/internal/config/config.js +62 -0
- package/src/internal/errors/scm-errors.js +140 -0
- package/src/internal/index.js +43 -0
- package/src/internal/output/formatter.js +120 -0
- package/src/internal/output/logger.js +168 -0
- package/src/shortcuts/common/runner.js +145 -0
- package/src/shortcuts/common/types.js +35 -0
- package/src/shortcuts/index.js +23 -0
- package/src/shortcuts/material-orders/index.js +12 -0
- package/src/shortcuts/material-orders/list.js +77 -0
- package/src/shortcuts/production-orders/index.js +13 -0
- package/src/shortcuts/production-orders/list.js +48 -0
- package/src/shortcuts/production-orders/query.js +86 -0
- package/src/shortcuts/qc-orders/index.js +12 -0
- package/src/shortcuts/qc-orders/list.js +79 -0
- package/src/shortcuts/register.js +82 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 WFS
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* Material Orders +list shortcut
|
|
7
|
+
*/
|
|
8
|
+
import { scmClient, ordersLogger } from '../../internal/index.js';
|
|
9
|
+
|
|
10
|
+
export const MaterialOrdersList = {
|
|
11
|
+
service: 'material-orders',
|
|
12
|
+
command: '+list',
|
|
13
|
+
description: '查询物料订单列表',
|
|
14
|
+
risk: 'read',
|
|
15
|
+
scopes: [],
|
|
16
|
+
hasFormat: true,
|
|
17
|
+
flags: [
|
|
18
|
+
{ name: 'open-id', type: 'string', required: true, description: '飞书用户 openId' },
|
|
19
|
+
{ name: 'page-no', type: 'number', default: 1, description: '页码' },
|
|
20
|
+
{ name: 'page-size', type: 'number', default: 20, description: '每页条数' },
|
|
21
|
+
// 订单信息
|
|
22
|
+
{ name: 'order-no', type: 'string', description: '物料订单号' },
|
|
23
|
+
{ name: 'status', type: 'string', description: '物料订单状态: 0-待采购|1-采购中|2-部分到货|3-已到货|4-已取消' },
|
|
24
|
+
{ name: 'cooperation-mode', type: 'string', description: '合作模式: 0-CMT|1-FOB' },
|
|
25
|
+
// 商品信息
|
|
26
|
+
{ name: 'goods-full-code', type: 'string', description: '大货款号' },
|
|
27
|
+
{ name: 'goods-batch', type: 'string', description: '大货批次' },
|
|
28
|
+
{ name: 'goods-type', type: 'string', description: '大货类型: 0-首单|1-加单|2-翻单' },
|
|
29
|
+
// 供应商
|
|
30
|
+
{ name: 'supplier-name', type: 'string', description: '供应商名称' },
|
|
31
|
+
// 人员
|
|
32
|
+
{ name: 'purchaser-id-list', type: 'string', description: '采购员 ID 列表 (逗号分隔)' },
|
|
33
|
+
{ name: 'pd-user-id-list', type: 'string', description: 'PD ID 列表 (逗号分隔)' },
|
|
34
|
+
{ name: 'designer-name', type: 'string', description: '设计师名称' },
|
|
35
|
+
// 时间
|
|
36
|
+
{ name: 'type', type: 'string', description: '时间查询类型: 0-上市|1-下单|2-交期|3-调整|4-关单|5-生产下单|6-工厂接单|7-计划到货|8-实际到货|9-需求到货' },
|
|
37
|
+
{ name: 'start-time', type: 'string', description: '开始时间 (ISO 8601)' },
|
|
38
|
+
{ name: 'end-time', type: 'string', description: '结束时间 (ISO 8601)' },
|
|
39
|
+
],
|
|
40
|
+
|
|
41
|
+
async execute(internal, runtime) {
|
|
42
|
+
const f = runtime.flags;
|
|
43
|
+
const openId = f['open-id'];
|
|
44
|
+
const token = await scmClient.getToken(openId, null, null);
|
|
45
|
+
|
|
46
|
+
const filter = {
|
|
47
|
+
pageNo: parseInt(f['page-no']) || 1,
|
|
48
|
+
pageSize: Math.min(parseInt(f['page-size']) || 20, 100),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// 订单信息
|
|
52
|
+
if (f['order-no']) filter.orderNo = f['order-no'];
|
|
53
|
+
if (f['status'] !== undefined) filter.status = parseInt(f['status']);
|
|
54
|
+
if (f['cooperation-mode'] !== undefined) filter.cooperationMode = parseInt(f['cooperation-mode']);
|
|
55
|
+
// 商品信息
|
|
56
|
+
if (f['goods-full-code']) filter.goodsFullCode = f['goods-full-code'];
|
|
57
|
+
if (f['goods-batch']) filter.goodsBatch = f['goods-batch'];
|
|
58
|
+
if (f['goods-type'] !== undefined) filter.goodsType = parseInt(f['goods-type']);
|
|
59
|
+
// 供应商
|
|
60
|
+
if (f['supplier-name']) filter.supplierName = f['supplier-name'];
|
|
61
|
+
// 人员
|
|
62
|
+
if (f['purchaser-id-list']) filter.purchaserIdList = f['purchaser-id-list'].split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n));
|
|
63
|
+
if (f['pd-user-id-list']) filter.pdUserIdList = f['pd-user-id-list'].split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n));
|
|
64
|
+
if (f['designer-name']) filter.designerName = f['designer-name'];
|
|
65
|
+
// 时间
|
|
66
|
+
if (f['type'] !== undefined) filter.type = parseInt(f['type']);
|
|
67
|
+
if (f['start-time']) filter.startTime = f['start-time'];
|
|
68
|
+
if (f['end-time']) filter.endTime = f['end-time'];
|
|
69
|
+
|
|
70
|
+
const body = { domain: 'goods_material', action: 'query', filter };
|
|
71
|
+
const endpoint = '/admin-api/api/ai-scm/execute';
|
|
72
|
+
const result = await scmClient.invoke(endpoint, { method: 'POST', body }, { token });
|
|
73
|
+
|
|
74
|
+
ordersLogger.info('查询物料订单', { openId, total: result?.total });
|
|
75
|
+
return result || {};
|
|
76
|
+
},
|
|
77
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 WFS
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* Production Orders shortcuts
|
|
7
|
+
*/
|
|
8
|
+
import { ProductionOrdersList } from './list.js';
|
|
9
|
+
import { ProductionOrdersQuery } from './query.js';
|
|
10
|
+
|
|
11
|
+
export function Shortcuts() {
|
|
12
|
+
return [ProductionOrdersList, ProductionOrdersQuery];
|
|
13
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 WFS
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* Production Orders +list shortcut
|
|
7
|
+
*/
|
|
8
|
+
import { scmClient, ordersLogger } from '../../internal/index.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* +list shortcut — list production orders with pagination
|
|
12
|
+
*/
|
|
13
|
+
export const ProductionOrdersList = {
|
|
14
|
+
service: 'production-orders',
|
|
15
|
+
command: '+list',
|
|
16
|
+
description: '查询大货生产订单列表(支持分页)',
|
|
17
|
+
risk: 'read',
|
|
18
|
+
scopes: [],
|
|
19
|
+
hasFormat: true,
|
|
20
|
+
flags: [
|
|
21
|
+
{ name: 'open-id', type: 'string', required: true, description: '飞书用户 openId' },
|
|
22
|
+
{ name: 'page-no', type: 'number', default: 1, description: '页码,从 1 开始' },
|
|
23
|
+
{ name: 'page-size', type: 'number', default: 20, description: '每页条数,最大 100' },
|
|
24
|
+
],
|
|
25
|
+
|
|
26
|
+
async execute(internal, runtime) {
|
|
27
|
+
const { 'open-id': openId, 'page-no': pageNo, 'page-size': pageSize } = runtime.flags;
|
|
28
|
+
const token = await scmClient.getToken(openId, null, null);
|
|
29
|
+
|
|
30
|
+
const body = {
|
|
31
|
+
domain: 'production_order',
|
|
32
|
+
action: 'query',
|
|
33
|
+
filter: {
|
|
34
|
+
pageNo: parseInt(pageNo) || 1,
|
|
35
|
+
pageSize: Math.min(parseInt(pageSize) || 20, 100),
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const endpoint = '/admin-api/api/ai-scm/execute';
|
|
40
|
+
const result = await scmClient.invoke(endpoint, {
|
|
41
|
+
method: 'POST',
|
|
42
|
+
body,
|
|
43
|
+
}, { token });
|
|
44
|
+
|
|
45
|
+
ordersLogger.info('查询生产订单', { openId, total: result?.total });
|
|
46
|
+
return result || {};
|
|
47
|
+
},
|
|
48
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 WFS
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* Production Orders +query shortcut
|
|
7
|
+
*/
|
|
8
|
+
import { scmClient, ordersLogger } from '../../internal/index.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* +query shortcut — full production orders query with all filters
|
|
12
|
+
*/
|
|
13
|
+
export const ProductionOrdersQuery = {
|
|
14
|
+
service: 'production-orders',
|
|
15
|
+
command: '+query',
|
|
16
|
+
description: '查询大货生产订单(支持全部筛选条件)',
|
|
17
|
+
risk: 'read',
|
|
18
|
+
scopes: [],
|
|
19
|
+
hasFormat: true,
|
|
20
|
+
flags: [
|
|
21
|
+
{ name: 'open-id', type: 'string', required: true, description: '飞书用户 openId' },
|
|
22
|
+
{ name: 'page-no', type: 'number', default: 1, description: '页码' },
|
|
23
|
+
{ name: 'page-size', type: 'number', default: 20, description: '每页条数' },
|
|
24
|
+
// 订单状态
|
|
25
|
+
{ name: 'prod-status', type: 'string', description: '生产订单状态: -1-全部|0-待确定|1-待同步|2-在途中|3-已完成|100-已取消' },
|
|
26
|
+
{ name: 'confirm-supplier', type: 'string', description: '确认供应商: 0-未确认|1-已确认' },
|
|
27
|
+
{ name: 'supplier-order-status', type: 'string', description: '供应商订单状态' },
|
|
28
|
+
{ name: 'quotation-status', type: 'string', description: '报价单状态' },
|
|
29
|
+
{ name: 'wash-status', type: 'string', description: '洗唛订单状态' },
|
|
30
|
+
// 商品信息
|
|
31
|
+
{ name: 'goods-full-code', type: 'string', description: '大货款号' },
|
|
32
|
+
{ name: 'goods-batch', type: 'string', description: '大货批次' },
|
|
33
|
+
{ name: 'goods-type', type: 'string', description: '大货类型: 0-首单|1-加单|2-翻单' },
|
|
34
|
+
// 供应商
|
|
35
|
+
{ name: 'supplier-name', type: 'string', description: '供应商名称' },
|
|
36
|
+
{ name: 'cooperation-mode', type: 'string', description: '合作模式: 0-CMT|1-FOB' },
|
|
37
|
+
// 人员
|
|
38
|
+
{ name: 'designer-name', type: 'string', description: '设计师名称' },
|
|
39
|
+
// 时间
|
|
40
|
+
{ name: 'type', type: 'string', description: '时间类型: 0-上市|1-下单|2-交期...' },
|
|
41
|
+
{ name: 'start-time', type: 'string', description: '开始时间 (ISO 8601)' },
|
|
42
|
+
{ name: 'end-time', type: 'string', description: '结束时间 (ISO 8601)' },
|
|
43
|
+
// 状态标识
|
|
44
|
+
{ name: 'qc-inspection', type: 'string', description: 'QC 质检结果' },
|
|
45
|
+
// 分类
|
|
46
|
+
{ name: 'sale-area', type: 'string', description: '销售地区 ID 列表(逗号分隔)' },
|
|
47
|
+
],
|
|
48
|
+
|
|
49
|
+
async execute(internal, runtime) {
|
|
50
|
+
const f = runtime.flags;
|
|
51
|
+
const openId = f['open-id'];
|
|
52
|
+
|
|
53
|
+
const token = await scmClient.getToken(openId, null, null);
|
|
54
|
+
|
|
55
|
+
const filter = {
|
|
56
|
+
pageNo: parseInt(f['page-no']) || 1,
|
|
57
|
+
pageSize: Math.min(parseInt(f['page-size']) || 20, 100),
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Optional filters
|
|
61
|
+
if (f['prod-status'] !== undefined) filter.prodStatus = parseInt(f['prod-status']);
|
|
62
|
+
if (f['confirm-supplier'] !== undefined) filter.confirmSupplier = parseInt(f['confirm-supplier']);
|
|
63
|
+
if (f['supplier-order-status'] !== undefined) filter.supplierOrderStatus = parseInt(f['supplier-order-status']);
|
|
64
|
+
if (f['quotation-status'] !== undefined) filter.quotationStatus = parseInt(f['quotation-status']);
|
|
65
|
+
if (f['wash-status'] !== undefined) filter.washStatus = parseInt(f['wash-status']);
|
|
66
|
+
if (f['goods-full-code']) filter.goodsFullCode = f['goods-full-code'];
|
|
67
|
+
if (f['goods-batch']) filter.goodsBatch = f['goods-batch'];
|
|
68
|
+
if (f['goods-type'] !== undefined) filter.goodsType = parseInt(f['goods-type']);
|
|
69
|
+
if (f['supplier-name']) filter.supplierName = f['supplier-name'];
|
|
70
|
+
if (f['cooperation-mode'] !== undefined) filter.cooperationMode = parseInt(f['cooperation-mode']);
|
|
71
|
+
if (f['designer-name']) filter.designerName = f['designer-name'];
|
|
72
|
+
if (f['type'] !== undefined) filter.type = parseInt(f['type']);
|
|
73
|
+
if (f['start-time']) filter.startTime = f['start-time'];
|
|
74
|
+
if (f['end-time']) filter.endTime = f['end-time'];
|
|
75
|
+
if (f['qc-inspection'] !== undefined) filter.qcInspection = parseInt(f['qc-inspection']);
|
|
76
|
+
if (f['sale-area']) filter.saleArea = f['sale-area'].split(',').map(Number);
|
|
77
|
+
|
|
78
|
+
const body = { domain: 'production_order', action: 'query', filter };
|
|
79
|
+
|
|
80
|
+
const endpoint = '/admin-api/api/ai-scm/execute';
|
|
81
|
+
const result = await scmClient.invoke(endpoint, { method: 'POST', body }, { token });
|
|
82
|
+
|
|
83
|
+
ordersLogger.info('查询生产订单', { openId, total: result?.total });
|
|
84
|
+
return result || {};
|
|
85
|
+
},
|
|
86
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 WFS
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* QC Orders +list shortcut
|
|
7
|
+
*/
|
|
8
|
+
import { scmClient, ordersLogger } from '../../internal/index.js';
|
|
9
|
+
|
|
10
|
+
export const QcOrdersList = {
|
|
11
|
+
service: 'qc-orders',
|
|
12
|
+
command: '+list',
|
|
13
|
+
description: '查询 QC 质检订单列表',
|
|
14
|
+
risk: 'read',
|
|
15
|
+
scopes: [],
|
|
16
|
+
hasFormat: true,
|
|
17
|
+
flags: [
|
|
18
|
+
{ name: 'open-id', type: 'string', required: true, description: '飞书用户 openId' },
|
|
19
|
+
{ name: 'page-no', type: 'number', default: 1, description: '页码' },
|
|
20
|
+
{ name: 'page-size', type: 'number', default: 10, description: '每页条数' },
|
|
21
|
+
// 订单状态
|
|
22
|
+
{ name: 'qc-order-status', type: 'string', description: 'QC 订单状态: -1-全部|0-待分配|1-已分配|2-已完成|3-已取消' },
|
|
23
|
+
// 商品信息
|
|
24
|
+
{ name: 'goods-full-code', type: 'string', description: '大货款号' },
|
|
25
|
+
{ name: 'goods-type', type: 'string', description: '大货类型: 1-大货|2-翻单|3-补料' },
|
|
26
|
+
{ name: 'goods-grade-list', type: 'string', description: '商品分级列表 (逗号分隔)' },
|
|
27
|
+
// 供应商
|
|
28
|
+
{ name: 'supplier-name', type: 'string', description: '供应商名称' },
|
|
29
|
+
// 人员
|
|
30
|
+
{ name: 'mid-manager', type: 'string', description: '中查管理人员' },
|
|
31
|
+
{ name: 'check-goods', type: 'string', description: '查货人员' },
|
|
32
|
+
{ name: 'tail-manager', type: 'string', description: '尾查管理人员' },
|
|
33
|
+
{ name: 'qc-user-id-list', type: 'string', description: 'QC 用户 ID 列表 (逗号分隔)' },
|
|
34
|
+
{ name: 'prod-manager-id-list', type: 'string', description: '生产经理 ID 列表 (逗号分隔)' },
|
|
35
|
+
{ name: 'purchaser-id-list', type: 'string', description: '采购员 ID 列表 (逗号分隔)' },
|
|
36
|
+
// 时间
|
|
37
|
+
{ name: 'time-type', type: 'string', description: '时间类型: 0-预约验货|1-下单|2-接单|3-分配|4-完成|5-交期' },
|
|
38
|
+
{ name: 'start-time', type: 'string', description: '开始时间 (ISO 8601)' },
|
|
39
|
+
{ name: 'end-time', type: 'string', description: '结束时间 (ISO 8601)' },
|
|
40
|
+
],
|
|
41
|
+
|
|
42
|
+
async execute(internal, runtime) {
|
|
43
|
+
const f = runtime.flags;
|
|
44
|
+
const openId = f['open-id'];
|
|
45
|
+
const token = await scmClient.getToken(openId, null, null);
|
|
46
|
+
|
|
47
|
+
const filter = {
|
|
48
|
+
pageNo: parseInt(f['page-no']) || 1,
|
|
49
|
+
pageSize: Math.min(parseInt(f['page-size']) || 10, 100),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// 订单状态
|
|
53
|
+
if (f['qc-order-status'] !== undefined) filter.qcOrderStatus = parseInt(f['qc-order-status']);
|
|
54
|
+
// 商品信息
|
|
55
|
+
if (f['goods-full-code']) filter.goodsFullCode = f['goods-full-code'];
|
|
56
|
+
if (f['goods-type'] !== undefined) filter.goodsType = parseInt(f['goods-type']);
|
|
57
|
+
if (f['goods-grade-list']) filter.goodsGradeList = f['goods-grade-list'].split(',').map(s => s.trim());
|
|
58
|
+
// 供应商
|
|
59
|
+
if (f['supplier-name']) filter.supplierName = f['supplier-name'];
|
|
60
|
+
// 人员
|
|
61
|
+
if (f['mid-manager']) filter.midManager = f['mid-manager'];
|
|
62
|
+
if (f['check-goods']) filter.checkGoods = f['check-goods'];
|
|
63
|
+
if (f['tail-manager']) filter.tailManager = f['tail-manager'];
|
|
64
|
+
if (f['qc-user-id-list']) filter.qcUserIdList = f['qc-user-id-list'].split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n));
|
|
65
|
+
if (f['prod-manager-id-list']) filter.prodManagerIdList = f['prod-manager-id-list'].split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n));
|
|
66
|
+
if (f['purchaser-id-list']) filter.purchaserIdList = f['purchaser-id-list'].split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n));
|
|
67
|
+
// 时间
|
|
68
|
+
if (f['time-type'] !== undefined) filter.timeType = parseInt(f['time-type']);
|
|
69
|
+
if (f['start-time']) filter.startTime = f['start-time'];
|
|
70
|
+
if (f['end-time']) filter.endTime = f['end-time'];
|
|
71
|
+
|
|
72
|
+
const body = { domain: 'qc_order', action: 'query', filter };
|
|
73
|
+
const endpoint = '/admin-api/api/ai-scm/execute';
|
|
74
|
+
const result = await scmClient.invoke(endpoint, { method: 'POST', body }, { token });
|
|
75
|
+
|
|
76
|
+
ordersLogger.info('查询 QC 订单', { openId, total: result?.total });
|
|
77
|
+
return result || {};
|
|
78
|
+
},
|
|
79
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 WFS
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* Shortcuts registration — registers all shortcuts to the command tree
|
|
7
|
+
*
|
|
8
|
+
* Inspired by lark-cli's shortcuts/register.go
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { shortcutAction } from './common/runner.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Register all shortcuts for a domain
|
|
15
|
+
*
|
|
16
|
+
* @param {Object} program - Commander program
|
|
17
|
+
* @param {string} domain - Domain name (e.g., 'production-orders')
|
|
18
|
+
* @param {Array} shortcuts - Array of Shortcut definitions
|
|
19
|
+
* @param {Object} internalCtx - Internal context
|
|
20
|
+
*/
|
|
21
|
+
function registerDomainShortcuts(program, domain, shortcuts, internalCtx) {
|
|
22
|
+
// Find or create domain subcommand
|
|
23
|
+
let domainCmd = program.commands.find(c => c.name() === domain);
|
|
24
|
+
|
|
25
|
+
if (!domainCmd) {
|
|
26
|
+
domainCmd = program
|
|
27
|
+
.command(domain)
|
|
28
|
+
.description(`${domain} commands`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
for (const shortcut of shortcuts) {
|
|
32
|
+
// Build command name without + prefix
|
|
33
|
+
const cmdName = shortcut.command.replace(/^\+/, '');
|
|
34
|
+
|
|
35
|
+
// Create command with description
|
|
36
|
+
const cmd = domainCmd
|
|
37
|
+
.command(cmdName)
|
|
38
|
+
.description(shortcut.description);
|
|
39
|
+
|
|
40
|
+
// Add flags
|
|
41
|
+
for (const flag of (shortcut.flags || [])) {
|
|
42
|
+
let flagSpec = `--${flag.name}`;
|
|
43
|
+
if (flag.type === 'boolean') {
|
|
44
|
+
flagSpec = `--${flag.name}`;
|
|
45
|
+
} else {
|
|
46
|
+
flagSpec += ` <${flag.name}>`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const description = flag.description || '';
|
|
50
|
+
const defaultVal = flag.default !== undefined ? String(flag.default) : undefined;
|
|
51
|
+
|
|
52
|
+
if (flag.type === 'boolean') {
|
|
53
|
+
cmd.option(`--${flag.name}`, description, defaultVal);
|
|
54
|
+
} else if (flag.required) {
|
|
55
|
+
cmd.requiredOption(`${flagSpec} [required]`, description);
|
|
56
|
+
} else {
|
|
57
|
+
cmd.option(`${flagSpec}`, description, defaultVal);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Add --format flag if hasFormat
|
|
62
|
+
if (shortcut.hasFormat !== false) {
|
|
63
|
+
cmd.option('--format <format>', 'Output format: table|json|pretty', 'table');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Register action
|
|
67
|
+
cmd.action(shortcutAction(shortcut, internalCtx));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Register all shortcuts to the commander program
|
|
73
|
+
*
|
|
74
|
+
* @param {Object} program - Root commander program
|
|
75
|
+
* @param {Object} shortcutsMap - Map of domain -> Shortcut[] (from domain/index.js)
|
|
76
|
+
* @param {Object} internalCtx - Internal context
|
|
77
|
+
*/
|
|
78
|
+
export function registerShortcuts(program, shortcutsMap, internalCtx) {
|
|
79
|
+
for (const [domain, shortcuts] of Object.entries(shortcutsMap)) {
|
|
80
|
+
registerDomainShortcuts(program, domain, shortcuts, internalCtx);
|
|
81
|
+
}
|
|
82
|
+
}
|