@youzan-cloud/zan-saas-cli 0.0.0-stage → 0.1.0-beta.3
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/DEPENDENCIES.json +50 -0
- package/INSTALL.md +79 -0
- package/LICENSE +21 -0
- package/NOTICE +1 -0
- package/README.md +151 -2
- package/THIRD_PARTY_NOTICES.txt +162 -0
- package/bin/zan-saas-cli.js +28 -0
- package/internal/registry/index.js +123 -0
- package/internal/registry/manifest.json +424 -0
- package/npm-shrinkwrap.json +86 -0
- package/package.json +33 -4
- package/skills/README.md +30 -0
- package/skills/zan-saas/SKILL.md +54 -0
- package/skills/zan-saas/references/host-entry.md +25 -0
- package/skills/zan-saas-access/SKILL.md +37 -0
- package/skills/zan-saas-access/references/role-list.md +11 -0
- package/skills/zan-saas-access/references/staff-perms-get.md +11 -0
- package/skills/zan-saas-aftersale/SKILL.md +31 -0
- package/skills/zan-saas-aftersale/references/case-list.md +13 -0
- package/skills/zan-saas-aftersale/references/case-scan.md +31 -0
- package/skills/zan-saas-benefit/SKILL.md +46 -0
- package/skills/zan-saas-benefit/references/card-get.md +7 -0
- package/skills/zan-saas-benefit/references/card-grant-list.md +11 -0
- package/skills/zan-saas-benefit/references/card-list.md +7 -0
- package/skills/zan-saas-benefit/references/customer-card-get.md +7 -0
- package/skills/zan-saas-benefit/references/customer-card-list.md +7 -0
- package/skills/zan-saas-coupon/SKILL.md +41 -0
- package/skills/zan-saas-coupon/references/activity-get.md +11 -0
- package/skills/zan-saas-coupon/references/activity-list.md +15 -0
- package/skills/zan-saas-coupon/references/voucher-get.md +13 -0
- package/skills/zan-saas-coupon/references/voucher-list.md +25 -0
- package/skills/zan-saas-customer/SKILL.md +73 -0
- package/skills/zan-saas-customer/references/customer-scan.md +11 -0
- package/skills/zan-saas-customer/references/segment-list.md +22 -0
- package/skills/zan-saas-fulfillment/SKILL.md +36 -0
- package/skills/zan-saas-fulfillment/references/delivery-get.md +11 -0
- package/skills/zan-saas-fulfillment/references/shipment-list.md +11 -0
- package/skills/zan-saas-fulfillment/references/waybill-get.md +9 -0
- package/skills/zan-saas-interaction/SKILL.md +37 -0
- package/skills/zan-saas-interaction/references/lottery-get.md +11 -0
- package/skills/zan-saas-interaction/references/lottery-list.md +19 -0
- package/skills/zan-saas-item/SKILL.md +61 -0
- package/skills/zan-saas-item/references/attribute-list.md +11 -0
- package/skills/zan-saas-item/references/brand-list.md +7 -0
- package/skills/zan-saas-item/references/classification-get.md +7 -0
- package/skills/zan-saas-item/references/classification-list.md +7 -0
- package/skills/zan-saas-item/references/group-list.md +9 -0
- package/skills/zan-saas-item/references/item-content.md +9 -0
- package/skills/zan-saas-item/references/item-get.md +9 -0
- package/skills/zan-saas-item/references/item-search.md +23 -0
- package/skills/zan-saas-item/references/product-identity.md +11 -0
- package/skills/zan-saas-member/SKILL.md +41 -0
- package/skills/zan-saas-member/references/customer-level-get.md +7 -0
- package/skills/zan-saas-member/references/growth-log-list.md +17 -0
- package/skills/zan-saas-member/references/membership-get.md +7 -0
- package/skills/zan-saas-order/SKILL.md +56 -0
- package/skills/zan-saas-order/references/order-get.md +26 -0
- package/skills/zan-saas-order/references/order-list.md +25 -0
- package/skills/zan-saas-order/references/order-scan.md +35 -0
- package/skills/zan-saas-org/SKILL.md +37 -0
- package/skills/zan-saas-org/references/staff-get.md +15 -0
- package/skills/zan-saas-org/references/staff-role-get.md +11 -0
- package/skills/zan-saas-org/references/unit-get.md +11 -0
- package/skills/zan-saas-org/references/unit-list.md +15 -0
- package/skills/zan-saas-points/SKILL.md +42 -0
- package/skills/zan-saas-points/references/account-get.md +7 -0
- package/skills/zan-saas-points/references/log-list.md +17 -0
- package/skills/zan-saas-points/references/rule-list.md +2 -0
- package/skills/zan-saas-privacy/SKILL.md +30 -0
- package/skills/zan-saas-privacy/references/field-decrypt.md +19 -0
- package/skills/zan-saas-shared/SKILL.md +94 -0
- package/skills/zan-saas-shared/references/authentication.md +52 -0
- package/skills/zan-saas-shared/references/value-processing.md +27 -0
- package/skills/zan-saas-stock/SKILL.md +28 -0
- package/skills/zan-saas-stock/references/log-list.md +11 -0
- package/skills/zan-saas-valuecard/SKILL.md +37 -0
- package/skills/zan-saas-valuecard/references/card-get.md +13 -0
- package/skills/zan-saas-valuecard/references/card-list.md +11 -0
- package/src/auth/browser.js +28 -0
- package/src/auth/callback-server.js +99 -0
- package/src/auth/config.js +53 -0
- package/src/auth/credential-store.js +109 -0
- package/src/auth/oauth-client.js +105 -0
- package/src/auth/pkce.js +28 -0
- package/src/auth/session.js +178 -0
- package/src/auth/tool.js +25 -0
- package/src/cli/command-paths.js +126 -0
- package/src/cli/context-help.js +102 -0
- package/src/cli/diagnostic-command.js +57 -0
- package/src/cli/domain-catalog.js +42 -0
- package/src/cli/help-text.js +32 -0
- package/src/cli/native-loader.js +120 -0
- package/src/cli/native-path.js +22 -0
- package/src/cli/parser-policy.js +141 -0
- package/src/cli/program.js +134 -0
- package/src/cli/skill-catalog.js +241 -0
- package/src/commands/native/access/commands.index.json +24 -0
- package/src/commands/native/access/domain.json +3 -0
- package/src/commands/native/access/role/list/command.js +141 -0
- package/src/commands/native/access/role/list/schema.json +393 -0
- package/src/commands/native/access/staff-perms/get/command.js +119 -0
- package/src/commands/native/access/staff-perms/get/schema.json +703 -0
- package/src/commands/native/aftersale/case/get/command.js +104 -0
- package/src/commands/native/aftersale/case/get/exact-json.js +52 -0
- package/src/commands/native/aftersale/case/get/money.js +28 -0
- package/src/commands/native/aftersale/case/get/projection.js +120 -0
- package/src/commands/native/aftersale/case/get/query.js +72 -0
- package/src/commands/native/aftersale/case/get/schema.json +134 -0
- package/src/commands/native/aftersale/case/list/command.js +135 -0
- package/src/commands/native/aftersale/case/list/schema.json +1095 -0
- package/src/commands/native/aftersale/case/scan/command.js +110 -0
- package/src/commands/native/aftersale/case/scan/query.js +62 -0
- package/src/commands/native/aftersale/case/scan/scan.js +78 -0
- package/src/commands/native/aftersale/case/scan/schema.json +964 -0
- package/src/commands/native/aftersale/case/scan/search.js +108 -0
- package/src/commands/native/aftersale/commands.index.json +42 -0
- package/src/commands/native/aftersale/domain.json +3 -0
- package/src/commands/native/aftersale/refund/list/command.js +97 -0
- package/src/commands/native/aftersale/refund/list/money.js +25 -0
- package/src/commands/native/aftersale/refund/list/projection.js +50 -0
- package/src/commands/native/aftersale/refund/list/query.js +73 -0
- package/src/commands/native/aftersale/refund/list/schema.json +130 -0
- package/src/commands/native/aftersale/shared/query.js +58 -0
- package/src/commands/native/aftersale/shared/search.js +128 -0
- package/src/commands/native/benefit/card-definition/get/command.js +110 -0
- package/src/commands/native/benefit/card-definition/get/schema.json +545 -0
- package/src/commands/native/benefit/card-definition/list/command.js +105 -0
- package/src/commands/native/benefit/card-definition/list/schema.json +690 -0
- package/src/commands/native/benefit/card-grant/list/command.js +135 -0
- package/src/commands/native/benefit/card-grant/list/schema.json +758 -0
- package/src/commands/native/benefit/commands.index.json +51 -0
- package/src/commands/native/benefit/customer-card/get/command.js +110 -0
- package/src/commands/native/benefit/customer-card/get/schema.json +340 -0
- package/src/commands/native/benefit/customer-card/list/command.js +102 -0
- package/src/commands/native/benefit/customer-card/list/schema.json +731 -0
- package/src/commands/native/benefit/domain.json +3 -0
- package/src/commands/native/coupon/activity/get/command.js +183 -0
- package/src/commands/native/coupon/activity/get/schema.json +624 -0
- package/src/commands/native/coupon/activity/list/command.js +169 -0
- package/src/commands/native/coupon/activity/list/schema.json +845 -0
- package/src/commands/native/coupon/commands.index.json +42 -0
- package/src/commands/native/coupon/domain.json +3 -0
- package/src/commands/native/coupon/shared/query.js +15 -0
- package/src/commands/native/coupon/voucher/get/command.js +113 -0
- package/src/commands/native/coupon/voucher/get/schema.json +147 -0
- package/src/commands/native/coupon/voucher/list/command.js +155 -0
- package/src/commands/native/coupon/voucher/list/schema.json +772 -0
- package/src/commands/native/customer/commands.index.json +96 -0
- package/src/commands/native/customer/customer/get/adapter.js +82 -0
- package/src/commands/native/customer/customer/get/command.js +106 -0
- package/src/commands/native/customer/customer/get/schema.json +958 -0
- package/src/commands/native/customer/customer/list/command.js +78 -0
- package/src/commands/native/customer/customer/list/input.js +145 -0
- package/src/commands/native/customer/customer/list/query.js +103 -0
- package/src/commands/native/customer/customer/list/schema.json +969 -0
- package/src/commands/native/customer/customer/scan/command.js +80 -0
- package/src/commands/native/customer/customer/scan/scan.js +92 -0
- package/src/commands/native/customer/customer/scan/schema.json +211 -0
- package/src/commands/native/customer/customer-tag/get/command.js +166 -0
- package/src/commands/native/customer/customer-tag/get/schema.json +317 -0
- package/src/commands/native/customer/customer-tag/list/command.js +143 -0
- package/src/commands/native/customer/customer-tag/list/schema.json +259 -0
- package/src/commands/native/customer/domain.json +3 -0
- package/src/commands/native/customer/segment/list/command.js +96 -0
- package/src/commands/native/customer/segment/list/query.js +98 -0
- package/src/commands/native/customer/segment/list/schema.json +135 -0
- package/src/commands/native/customer/segment-customer/list/command.js +171 -0
- package/src/commands/native/customer/segment-customer/list/schema.json +123 -0
- package/src/commands/native/customer/shared/search-input.js +179 -0
- package/src/commands/native/customer/shared/search-page.js +54 -0
- package/src/commands/native/customer/tag/get/command.js +73 -0
- package/src/commands/native/customer/tag/get/schema.json +339 -0
- package/src/commands/native/customer/tagcategory/get/command.js +80 -0
- package/src/commands/native/customer/tagcategory/get/query.js +98 -0
- package/src/commands/native/customer/tagcategory/get/schema.json +339 -0
- package/src/commands/native/customer/tagcategory/list/command.js +127 -0
- package/src/commands/native/customer/tagcategory/list/schema.json +394 -0
- package/src/commands/native/fulfillment/commands.index.json +33 -0
- package/src/commands/native/fulfillment/delivery/get/command.js +107 -0
- package/src/commands/native/fulfillment/delivery/get/projection.js +142 -0
- package/src/commands/native/fulfillment/delivery/get/schema.json +173 -0
- package/src/commands/native/fulfillment/domain.json +3 -0
- package/src/commands/native/fulfillment/shipment/list/command.js +83 -0
- package/src/commands/native/fulfillment/shipment/list/projection.js +130 -0
- package/src/commands/native/fulfillment/shipment/list/schema.json +752 -0
- package/src/commands/native/fulfillment/waybill/get/command.js +193 -0
- package/src/commands/native/fulfillment/waybill/get/response.js +68 -0
- package/src/commands/native/fulfillment/waybill/get/schema.json +190 -0
- package/src/commands/native/interaction/commands.index.json +24 -0
- package/src/commands/native/interaction/domain.json +3 -0
- package/src/commands/native/interaction/lottery/get/command.js +61 -0
- package/src/commands/native/interaction/lottery/get/query.js +152 -0
- package/src/commands/native/interaction/lottery/get/schema.json +1004 -0
- package/src/commands/native/interaction/lottery/list/command.js +176 -0
- package/src/commands/native/interaction/lottery/list/schema.json +898 -0
- package/src/commands/native/item/attribute/list/command.js +122 -0
- package/src/commands/native/item/attribute/list/schema.json +727 -0
- package/src/commands/native/item/brand/list/command.js +114 -0
- package/src/commands/native/item/brand/list/schema.json +725 -0
- package/src/commands/native/item/classification/get/command.js +87 -0
- package/src/commands/native/item/classification/get/schema.json +596 -0
- package/src/commands/native/item/classification/list/command.js +105 -0
- package/src/commands/native/item/classification/list/schema.json +676 -0
- package/src/commands/native/item/commands.index.json +87 -0
- package/src/commands/native/item/domain.json +1 -0
- package/src/commands/native/item/group/list/command.js +122 -0
- package/src/commands/native/item/group/list/schema.json +809 -0
- package/src/commands/native/item/item/get/command.js +122 -0
- package/src/commands/native/item/item/get/schema.json +3799 -0
- package/src/commands/native/item/item/list/command.js +7 -0
- package/src/commands/native/item/item/list/schema.json +1118 -0
- package/src/commands/native/item/item/scan/command.js +7 -0
- package/src/commands/native/item/item/scan/schema.json +1046 -0
- package/src/commands/native/item/item-content/get/command.js +54 -0
- package/src/commands/native/item/item-content/get/schema.json +677 -0
- package/src/commands/native/item/shared/api.js +31 -0
- package/src/commands/native/item/shared/content.js +20 -0
- package/src/commands/native/item/shared/diagnostics.js +61 -0
- package/src/commands/native/item/shared/h5.js +63 -0
- package/src/commands/native/item/shared/identity.js +62 -0
- package/src/commands/native/item/shared/normalize.js +49 -0
- package/src/commands/native/item/shared/scope.js +22 -0
- package/src/commands/native/item/shared/search-command.js +61 -0
- package/src/commands/native/item/shared/search-options.js +150 -0
- package/src/commands/native/item/shared/search.js +158 -0
- package/src/commands/native/member/commands.index.json +60 -0
- package/src/commands/native/member/customer-level/get/command.js +122 -0
- package/src/commands/native/member/customer-level/get/schema.json +300 -0
- package/src/commands/native/member/domain.json +3 -0
- package/src/commands/native/member/growth/get/command.js +64 -0
- package/src/commands/native/member/growth/get/schema.json +283 -0
- package/src/commands/native/member/growth-log/list/command.js +203 -0
- package/src/commands/native/member/growth-log/list/schema.json +695 -0
- package/src/commands/native/member/level/get/command.js +70 -0
- package/src/commands/native/member/level/get/query.js +125 -0
- package/src/commands/native/member/level/get/schema.json +339 -0
- package/src/commands/native/member/level/list/command.js +50 -0
- package/src/commands/native/member/level/list/query.js +109 -0
- package/src/commands/native/member/level/list/schema.json +104 -0
- package/src/commands/native/member/membership/get/command.js +78 -0
- package/src/commands/native/member/membership/get/schema.json +283 -0
- package/src/commands/native/order/commands.index.json +33 -0
- package/src/commands/native/order/domain.json +3 -0
- package/src/commands/native/order/order/get/command.js +155 -0
- package/src/commands/native/order/order/get/schema.json +1167 -0
- package/src/commands/native/order/order/list/command.js +230 -0
- package/src/commands/native/order/order/list/schema.json +1363 -0
- package/src/commands/native/order/order/scan/command.js +148 -0
- package/src/commands/native/order/order/scan/scan.js +89 -0
- package/src/commands/native/order/order/scan/schema.json +1445 -0
- package/src/commands/native/order/shared/projection.js +183 -0
- package/src/commands/native/order/shared/query.js +84 -0
- package/src/commands/native/order/shared/search.js +112 -0
- package/src/commands/native/org/commands.index.json +42 -0
- package/src/commands/native/org/domain.json +3 -0
- package/src/commands/native/org/shared/single-staff.js +115 -0
- package/src/commands/native/org/staff/get/command.js +148 -0
- package/src/commands/native/org/staff/get/schema.json +114 -0
- package/src/commands/native/org/staff-role/get/command.js +45 -0
- package/src/commands/native/org/staff-role/get/schema.json +93 -0
- package/src/commands/native/org/unit/get/command.js +131 -0
- package/src/commands/native/org/unit/get/schema.json +478 -0
- package/src/commands/native/org/unit/list/command.js +187 -0
- package/src/commands/native/org/unit/list/schema.json +828 -0
- package/src/commands/native/points/account/get/command.js +65 -0
- package/src/commands/native/points/account/get/schema.json +303 -0
- package/src/commands/native/points/commands.index.json +33 -0
- package/src/commands/native/points/domain.json +3 -0
- package/src/commands/native/points/log/list/command.js +141 -0
- package/src/commands/native/points/log/list/schema.json +761 -0
- package/src/commands/native/points/rule/list/command.js +82 -0
- package/src/commands/native/points/rule/list/schema.json +294 -0
- package/src/commands/native/privacy/commands.index.json +15 -0
- package/src/commands/native/privacy/domain.json +3 -0
- package/src/commands/native/privacy/field/decrypt/command.js +185 -0
- package/src/commands/native/privacy/field/decrypt/schema.json +656 -0
- package/src/commands/native/privacy/shared/order-source.js +33 -0
- package/src/commands/native/stock/commands.index.json +15 -0
- package/src/commands/native/stock/domain.json +3 -0
- package/src/commands/native/stock/log/list/command.js +207 -0
- package/src/commands/native/stock/log/list/schema.json +922 -0
- package/src/commands/native/valuecard/card/get/command.js +107 -0
- package/src/commands/native/valuecard/card/get/schema.json +683 -0
- package/src/commands/native/valuecard/card/list/command.js +136 -0
- package/src/commands/native/valuecard/card/list/pagination.js +23 -0
- package/src/commands/native/valuecard/card/list/schema.json +780 -0
- package/src/commands/native/valuecard/commands.index.json +24 -0
- package/src/commands/native/valuecard/domain.json +3 -0
- package/src/commands/native/valuecard/shared/projection.js +57 -0
- package/src/commands/system/api.js +47 -0
- package/src/commands/system/auth.js +118 -0
- package/src/commands/system/contracts.js +373 -0
- package/src/commands/system/doctor.js +24 -0
- package/src/commands/system/install.js +41 -0
- package/src/commands/system/printer.js +16 -0
- package/src/commands/system/schema.js +162 -0
- package/src/commands/system/shop-guidance.js +9 -0
- package/src/commands/system/shop.js +237 -0
- package/src/commands/system/skills.js +49 -0
- package/src/execution/beijing-date-time.js +29 -0
- package/src/execution/beijing-time.js +21 -0
- package/src/execution/bounded-input.js +42 -0
- package/src/execution/command-io.js +137 -0
- package/src/execution/command-policy.js +41 -0
- package/src/execution/command-schema.js +131 -0
- package/src/execution/datetime.js +83 -0
- package/src/execution/error-details.js +399 -0
- package/src/execution/error-model.js +82 -0
- package/src/execution/exact-json.js +80 -0
- package/src/execution/list-total.js +10 -0
- package/src/execution/money.js +59 -0
- package/src/execution/parser-error.js +66 -0
- package/src/execution/privacy.js +197 -0
- package/src/execution/public-schema.js +52 -0
- package/src/execution/query-api.js +101 -0
- package/src/execution/range.js +84 -0
- package/src/execution/request-state.js +55 -0
- package/src/execution/schema-completeness.js +116 -0
- package/src/execution/shop-query.js +54 -0
- package/src/execution/target-shop-default.js +23 -0
- package/src/execution/target-shop.js +49 -0
- package/src/identity/context-store.js +54 -0
- package/src/identity/context.js +38 -0
- package/src/installation/install.js +158 -0
- package/src/installation/npm-error.js +93 -0
- package/src/installation/skill.js +113 -0
- package/src/transport/account-api.js +152 -0
- package/src/transport/api.js +199 -0
- package/src/transport/shop-app.js +63 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Command } = require('commander');
|
|
4
|
+
const { InputIssueError, bindError, modelAt, constraints } = require('../execution/error-details');
|
|
5
|
+
|
|
6
|
+
class DiagnosticCommand extends Command {
|
|
7
|
+
constructor(name, { path, schema, optionPaths = {}, parameterCategory = 'validation' }) {
|
|
8
|
+
super(name);
|
|
9
|
+
this.diagnosticContext = { command: this, path, schema, optionPaths, parameterCategory };
|
|
10
|
+
this.exitOverride(error => {
|
|
11
|
+
if (['commander.helpDisplayed', 'commander.version'].includes(error.code)) throw error;
|
|
12
|
+
throw this.issue('constraint');
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
issue(reason, option) {
|
|
17
|
+
const context = this.diagnosticContext;
|
|
18
|
+
const attribute = option?.attributeName();
|
|
19
|
+
const mapped = Object.entries(context.optionPaths).find(([, value]) => value === attribute)?.[0];
|
|
20
|
+
const path = mapped || (attribute && modelAt(context.schema, 'input', `/${attribute}`) ? `/${attribute}` : undefined);
|
|
21
|
+
const expected = option?.argChoices ? { enum: [...option.argChoices] } :
|
|
22
|
+
path ? constraints(modelAt(context.schema, 'input', path)) : undefined;
|
|
23
|
+
return bindError(new InputIssueError([{ source: 'argv', reason,
|
|
24
|
+
...(option ? { option: option.long || option.short } : {}),
|
|
25
|
+
...(path ? { path } : {}), ...(expected ? { expected } : {}) }]), context);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
addOption(option) {
|
|
29
|
+
const parse = option.parseArg;
|
|
30
|
+
if (parse) option.argParser((value, previous) => {
|
|
31
|
+
try { return parse.call(option, value, previous); }
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error.code === 'commander.invalidArgument') throw this.issue('invalid_choice', option);
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
return super.addOption(option);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
missingMandatoryOptionValue(option) { throw this.issue('required', option); }
|
|
41
|
+
optionMissingArgument(option) { throw this.issue('missing_value', option); }
|
|
42
|
+
missingArgument() { throw this.issue('required'); }
|
|
43
|
+
unknownOption() { throw this.issue('unknown_option'); }
|
|
44
|
+
unknownCommand() { throw this.issue('unknown_command'); }
|
|
45
|
+
_excessArguments() {
|
|
46
|
+
if (!this._allowExcessArguments) throw this.issue('excess_arguments');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
action(handler) {
|
|
50
|
+
return super.action(async (...args) => {
|
|
51
|
+
try { return await handler.apply(this, args); }
|
|
52
|
+
catch (error) { throw bindError(error, this.diagnosticContext); }
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = { DiagnosticCommand };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { validateSkillFrontmatter } = require('./skill-catalog');
|
|
6
|
+
|
|
7
|
+
const skillsRoot = path.join(__dirname, '..', '..', 'skills');
|
|
8
|
+
const namePattern = /^[a-z][a-z0-9-]*$/;
|
|
9
|
+
const reservedNames = new Set(['api', 'auth', 'doctor', 'help', 'schema', 'shop', 'skills', 'shared']);
|
|
10
|
+
|
|
11
|
+
function validDomainName(name) {
|
|
12
|
+
return namePattern.test(name) && !reservedNames.has(name);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function domainSkillName(domain) {
|
|
16
|
+
return `zan-saas-${domain}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function regularFile(filename) {
|
|
20
|
+
return fs.lstatSync(filename).isFile();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function loadDomain(root, domain, rootSkills = skillsRoot) {
|
|
24
|
+
if (!validDomainName(domain)) throw new Error(`Invalid native domain: ${domain}`);
|
|
25
|
+
const filename = path.join(root, domain, 'domain.json');
|
|
26
|
+
try {
|
|
27
|
+
if (!regularFile(filename)) throw new Error(`Invalid domain descriptor: ${domain}`);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
if (error.code === 'ENOENT') throw new Error(`Missing domain descriptor: ${domain}/domain.json`);
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
const descriptor = JSON.parse(fs.readFileSync(filename, 'utf8'));
|
|
33
|
+
if (typeof descriptor.description !== 'string' || !descriptor.description.trim() ||
|
|
34
|
+
Object.keys(descriptor).some(key => key !== 'description')) {
|
|
35
|
+
throw new Error(`Invalid domain descriptor: ${domain}`);
|
|
36
|
+
}
|
|
37
|
+
const skill = domainSkillName(domain);
|
|
38
|
+
validateSkillFrontmatter(rootSkills, { name: skill });
|
|
39
|
+
return { name: domain, description: descriptor.description.trim(), skill };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = { skillsRoot, validDomainName, domainSkillName, loadDomain };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Help } = require('commander');
|
|
4
|
+
|
|
5
|
+
const headings = {
|
|
6
|
+
Usage: '用法', Arguments: '参数', Options: '选项',
|
|
7
|
+
'Global Options': '全局选项', Commands: '命令'
|
|
8
|
+
};
|
|
9
|
+
const annotations = { choices: '可选值', default: '默认值', preset: '预设值', env: '环境变量' };
|
|
10
|
+
const positionLabels = { hq: '总部', shop: '店铺', all: '总部、店铺' };
|
|
11
|
+
const riskLabels = { read: '只读', low: '低', medium: '中', high: '高' };
|
|
12
|
+
|
|
13
|
+
function localizeAnnotations(description) {
|
|
14
|
+
return description.replace(/(\(|, )(choices|default|preset|env): /g,
|
|
15
|
+
(_match, separator, name) => `${separator}${annotations[name]}:`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const chineseHelp = {
|
|
19
|
+
formatHelp(command, helper) {
|
|
20
|
+
return Help.prototype.formatHelp.call(this, command, helper)
|
|
21
|
+
.replace(/^(Usage|Arguments|Options|Global Options|Commands):/gm,
|
|
22
|
+
(_match, name) => `${headings[name]}:`);
|
|
23
|
+
},
|
|
24
|
+
optionDescription(option) {
|
|
25
|
+
return localizeAnnotations(Help.prototype.optionDescription.call(this, option));
|
|
26
|
+
},
|
|
27
|
+
argumentDescription(argument) {
|
|
28
|
+
return localizeAnnotations(Help.prototype.argumentDescription.call(this, argument));
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
module.exports = { chineseHelp, positionLabels, riskLabels };
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const {
|
|
6
|
+
addAtomicCommand, addTaskCommand, registerDomain, publishedDomains, validateAvailability
|
|
7
|
+
} = require('./command-paths');
|
|
8
|
+
const { loadDomain, skillsRoot, validDomainName } = require('./domain-catalog');
|
|
9
|
+
const { loadCommandSchema, attachCommandSchema } = require('../execution/command-schema');
|
|
10
|
+
const { nativeCommandLocation } = require('./native-path');
|
|
11
|
+
const { isDeepStrictEqual } = require('node:util');
|
|
12
|
+
|
|
13
|
+
const nativeRoot = path.join(__dirname, '..', 'commands', 'native');
|
|
14
|
+
const namePattern = /^[a-z][a-z0-9-]*$/;
|
|
15
|
+
const taskPattern = /^\+[a-z][a-z0-9-]*$/;
|
|
16
|
+
|
|
17
|
+
function directories(root) {
|
|
18
|
+
return fs.readdirSync(root, { withFileTypes: true })
|
|
19
|
+
.filter(entry => entry.isDirectory())
|
|
20
|
+
.map(entry => entry.name)
|
|
21
|
+
.sort();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function discoverNative(root = nativeRoot) {
|
|
25
|
+
const domains = directories(root);
|
|
26
|
+
const modules = [];
|
|
27
|
+
for (const domain of domains) {
|
|
28
|
+
if (!validDomainName(domain)) {
|
|
29
|
+
throw new Error(`Invalid native domain: ${domain}`);
|
|
30
|
+
}
|
|
31
|
+
const groups = directories(path.join(root, domain));
|
|
32
|
+
for (const group of groups) {
|
|
33
|
+
if (group === 'shared') continue;
|
|
34
|
+
if (taskPattern.test(group)) {
|
|
35
|
+
modules.push(`${domain}/${group}/command.js`);
|
|
36
|
+
} else if (namePattern.test(group)) {
|
|
37
|
+
const actions = directories(path.join(root, domain, group));
|
|
38
|
+
if (!actions.length) throw new Error(`Native resource has no actions: ${domain}/${group}`);
|
|
39
|
+
for (const action of actions) {
|
|
40
|
+
if (!namePattern.test(action)) throw new Error(`Invalid native action: ${action}`);
|
|
41
|
+
modules.push(`${domain}/${group}/${action}/command.js`);
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
throw new Error(`Invalid native command group: ${group}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
for (const modulePath of modules) {
|
|
49
|
+
if (!fs.existsSync(path.join(root, modulePath)) ||
|
|
50
|
+
!fs.statSync(path.join(root, modulePath)).isFile()) {
|
|
51
|
+
throw new Error(`Missing native command entry: ${modulePath}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return { domains, modules };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function registerNativeDomains(program, domains) {
|
|
58
|
+
const registeredDomains = new Set();
|
|
59
|
+
for (const entry of domains) {
|
|
60
|
+
if (!validDomainName(entry.name) || registeredDomains.has(entry.name)) {
|
|
61
|
+
throw new Error(`Invalid native domain manifest entry: ${entry.name}`);
|
|
62
|
+
}
|
|
63
|
+
registerDomain(program, entry);
|
|
64
|
+
registeredDomains.add(entry.name);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return registeredDomains;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function registerNativeDomain(program, domain, businessCommands, root = nativeRoot,
|
|
71
|
+
rootSkills = skillsRoot, context) {
|
|
72
|
+
const definition = loadDomain(root, domain.name, rootSkills);
|
|
73
|
+
if (definition.description !== domain.description || definition.skill !== domain.skill) {
|
|
74
|
+
throw new Error(`Native domain differs from manifest: ${domain.name}`);
|
|
75
|
+
}
|
|
76
|
+
if (!publishedDomains(program).some(entry => entry.name === domain.name)) {
|
|
77
|
+
throw new Error(`Native command has no registered domain: ${domain.name}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const seen = new Set();
|
|
81
|
+
for (const entry of businessCommands) {
|
|
82
|
+
const parts = entry.module.split('/');
|
|
83
|
+
const location = nativeCommandLocation(entry.module, entry.resourcePath);
|
|
84
|
+
// A generated manifest is still validated before loading any module.
|
|
85
|
+
if (!location || entry.path !== location.path || entry.kind !== location.kind || seen.has(entry.path)) {
|
|
86
|
+
throw new Error(`Invalid native command manifest entry: ${entry.path}`);
|
|
87
|
+
}
|
|
88
|
+
seen.add(entry.path);
|
|
89
|
+
if (parts[0] !== domain.name) {
|
|
90
|
+
throw new Error(`Native command is in the wrong domain index: ${entry.path}`);
|
|
91
|
+
}
|
|
92
|
+
const definition = require(path.join(root, entry.module));
|
|
93
|
+
const { kind } = location;
|
|
94
|
+
if (Object.hasOwn(definition, 'mutationRisk') ||
|
|
95
|
+
!isDeepStrictEqual(definition.resourcePath, entry.resourcePath) ||
|
|
96
|
+
definition.kind !== kind || definition.risk !== entry.risk ||
|
|
97
|
+
definition.at !== entry.at ||
|
|
98
|
+
validateAvailability(definition.availability) !== validateAvailability(entry.availability) ||
|
|
99
|
+
typeof definition.createCommand !== 'function') {
|
|
100
|
+
throw new Error(`Native command contract differs from manifest: ${entry.path}`);
|
|
101
|
+
}
|
|
102
|
+
const command = definition.createCommand({ context });
|
|
103
|
+
if (command.name() !== parts[kind === 'task' ? 1 : 2]) {
|
|
104
|
+
throw new Error(`Native command name differs from directory: ${entry.path}`);
|
|
105
|
+
}
|
|
106
|
+
if (!command.description().trim()) {
|
|
107
|
+
throw new Error(`Native command needs a help description: ${entry.path}`);
|
|
108
|
+
}
|
|
109
|
+
attachCommandSchema(command, loadCommandSchema(
|
|
110
|
+
path.join(root, ...parts.slice(0, -1), 'schema.json')
|
|
111
|
+
));
|
|
112
|
+
if (kind === 'task') {
|
|
113
|
+
addTaskCommand(program, parts[0], command, entry.risk, entry.at, entry.availability);
|
|
114
|
+
} else {
|
|
115
|
+
addAtomicCommand(program, parts[0], location.resources, command, entry.risk, entry.at, entry.availability);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
module.exports = { nativeRoot, discoverNative, registerNativeDomains, registerNativeDomain };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const namePattern = /^[a-z][a-z0-9-]*$/;
|
|
4
|
+
const taskPattern = /^\+[a-z][a-z0-9-]*$/;
|
|
5
|
+
|
|
6
|
+
function nativeCommandLocation(modulePath, resourcePath) {
|
|
7
|
+
if (typeof modulePath !== 'string') return null;
|
|
8
|
+
const parts = modulePath.split('/');
|
|
9
|
+
if (!namePattern.test(parts[0]) || parts.at(-1) !== 'command.js') return null;
|
|
10
|
+
if (parts.length === 3 && taskPattern.test(parts[1]) && resourcePath === undefined) {
|
|
11
|
+
return { domain: parts[0], kind: 'task', action: parts[1], path: `${parts[0]}.${parts[1]}` };
|
|
12
|
+
}
|
|
13
|
+
if (parts.length !== 4 || !namePattern.test(parts[1]) || !namePattern.test(parts[2])) return null;
|
|
14
|
+
const resources = resourcePath === undefined ? [parts[1]] : resourcePath;
|
|
15
|
+
if (!Array.isArray(resources) || !resources.length ||
|
|
16
|
+
!resources.every(value => typeof value === 'string' && namePattern.test(value)) ||
|
|
17
|
+
resources.join('-') !== parts[1]) return null;
|
|
18
|
+
return { domain: parts[0], kind: 'atomic', action: parts[2], resources,
|
|
19
|
+
path: [parts[0], ...resources, parts[2]].join('.') };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = { nativeCommandLocation };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Command } = require('commander');
|
|
4
|
+
const { commandPath } = require('./command-paths');
|
|
5
|
+
const { commandSchema } = require('../execution/command-schema');
|
|
6
|
+
const { modelAt, constraints } = require('../execution/error-details');
|
|
7
|
+
const { ParserError } = require('../execution/parser-error');
|
|
8
|
+
|
|
9
|
+
const parserReasons = {
|
|
10
|
+
'commander.unknownCommand': 'unknown_command',
|
|
11
|
+
'commander.unknownOption': 'unknown_option',
|
|
12
|
+
'commander.missingArgument': 'required',
|
|
13
|
+
'commander.missingMandatoryOptionValue': 'required',
|
|
14
|
+
'commander.optionMissingArgument': 'missing_value',
|
|
15
|
+
'commander.invalidArgument': 'invalid_choice',
|
|
16
|
+
'commander.excessArguments': 'excess_arguments',
|
|
17
|
+
'commander.conflictingOption': 'constraint'
|
|
18
|
+
};
|
|
19
|
+
const messages = {
|
|
20
|
+
unknown_command: '未知命令,请查看帮助或候选命令',
|
|
21
|
+
unknown_option: '命令中有不支持的选项,请查看此命令 --help',
|
|
22
|
+
excess_arguments: '命令中有多余的位置参数,请查看此命令 --help',
|
|
23
|
+
required: '缺少必填参数,请查看此命令 --help',
|
|
24
|
+
missing_value: '请为参数提供值',
|
|
25
|
+
invalid_choice: '参数值不在允许范围内,请查看此命令 --help',
|
|
26
|
+
constraint: '参数组合不符合要求,请查看此命令 --help'
|
|
27
|
+
};
|
|
28
|
+
const safeName = /^(?:[a-z][a-z0-9-]*|\+[a-z][a-z0-9-]*)$/;
|
|
29
|
+
|
|
30
|
+
function distance(left, right) {
|
|
31
|
+
let previous = Array.from({ length: right.length + 1 }, (_, index) => index);
|
|
32
|
+
for (let i = 0; i < left.length; i++) {
|
|
33
|
+
const row = [i + 1];
|
|
34
|
+
for (let j = 0; j < right.length; j++) {
|
|
35
|
+
row.push(Math.min(row[j] + 1, previous[j + 1] + 1,
|
|
36
|
+
previous[j] + (left[i] === right[j] ? 0 : 1)));
|
|
37
|
+
}
|
|
38
|
+
previous = row;
|
|
39
|
+
}
|
|
40
|
+
return previous[right.length];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function suggestedArgv(command, token) {
|
|
44
|
+
if (typeof token !== 'string' || token.length < 3 || token.length > 64 || !safeName.test(token)) return [];
|
|
45
|
+
const prefix = commandPath(command).split('.').filter(Boolean);
|
|
46
|
+
const names = command.createHelp().visibleCommands(command)
|
|
47
|
+
.flatMap(child => [child.name(), ...child.aliases()]).filter(name => safeName.test(name));
|
|
48
|
+
const candidates = [...new Set(names)].map(name => ({ name, distance: distance(token, name) }))
|
|
49
|
+
.filter(candidate => candidate.distance <= (token.length > 5 ? 2 : 1))
|
|
50
|
+
.sort((left, right) => left.distance - right.distance || left.name.localeCompare(right.name, 'en'));
|
|
51
|
+
return candidates.filter(candidate => candidate.distance === candidates[0].distance)
|
|
52
|
+
.slice(0, 3).map(candidate => [...prefix, candidate.name]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function parserFailure(command, reason, { option, argument, token } = {}) {
|
|
56
|
+
const path = commandPath(command);
|
|
57
|
+
const helpArgv = [...path.split('.').filter(Boolean), '--help'];
|
|
58
|
+
const issue = { source: 'argv', reason };
|
|
59
|
+
const schema = commandSchema(command);
|
|
60
|
+
const attribute = option?.attributeName() || argument?.name();
|
|
61
|
+
const modelPath = attribute && `/${attribute}`;
|
|
62
|
+
const model = schema && modelPath && modelAt(schema, 'input', modelPath);
|
|
63
|
+
if (option) issue.option = option.long || option.short;
|
|
64
|
+
if (model) issue.path = modelPath;
|
|
65
|
+
if (option?.argChoices) issue.expected = { enum: [...option.argChoices] };
|
|
66
|
+
else if (model && Object.keys(constraints(model)).length) issue.expected = constraints(model);
|
|
67
|
+
const suggestions = reason === 'unknown_command' ? suggestedArgv(command, token) : [];
|
|
68
|
+
const message = option && reason === 'required' ? `请提供 ${issue.option}` :
|
|
69
|
+
option && reason === 'missing_value' ? `请为 ${issue.option} 提供值` :
|
|
70
|
+
option?.argChoices && reason === 'invalid_choice' ?
|
|
71
|
+
`${issue.option} 只能使用:${option.argChoices.join('、')}` :
|
|
72
|
+
argument && reason === 'required' ? `请提供参数 <${argument.name()}>` : messages[reason];
|
|
73
|
+
return new ParserError(message, {
|
|
74
|
+
command: path, issues: [issue], helpArgv,
|
|
75
|
+
...(suggestions.length ? { suggestions } : {}),
|
|
76
|
+
nextStep: `${suggestions.length ? `你可能想执行 zan-saas ${suggestions[0].join(' ')};` : ''}` +
|
|
77
|
+
`查看帮助:zan-saas ${helpArgv.join(' ')}`
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function configureParserPolicy(prepareHelp) {
|
|
82
|
+
const installed = new WeakSet();
|
|
83
|
+
const options = new WeakSet();
|
|
84
|
+
function install(command) {
|
|
85
|
+
if (!installed.has(command)) {
|
|
86
|
+
installed.add(command);
|
|
87
|
+
const help = command.help;
|
|
88
|
+
command.help = function(context) {
|
|
89
|
+
const navigation = context?.error && !this._actionHandler &&
|
|
90
|
+
!this._defaultCommandName && this.args.length === 0;
|
|
91
|
+
return help.call(this, navigation ? { error: false } : context);
|
|
92
|
+
};
|
|
93
|
+
const error = command.error;
|
|
94
|
+
command.error = function(message, settings) {
|
|
95
|
+
const reason = parserReasons[settings?.code];
|
|
96
|
+
if (reason) throw parserFailure(this, reason);
|
|
97
|
+
return error.call(this, message, settings);
|
|
98
|
+
};
|
|
99
|
+
const methods = {
|
|
100
|
+
missingMandatoryOptionValue(option) { throw parserFailure(this, 'required', { option }); },
|
|
101
|
+
optionMissingArgument(option) { throw parserFailure(this, 'missing_value', { option }); },
|
|
102
|
+
missingArgument(name) {
|
|
103
|
+
throw parserFailure(this, 'required', {
|
|
104
|
+
argument: this.registeredArguments.find(argument => argument.name() === name)
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
unknownOption() {
|
|
108
|
+
if (!this._allowUnknownOption) throw parserFailure(this, 'unknown_option');
|
|
109
|
+
},
|
|
110
|
+
unknownCommand() {
|
|
111
|
+
prepareHelp(this);
|
|
112
|
+
throw parserFailure(this, 'unknown_command', { token: this.args[0] });
|
|
113
|
+
},
|
|
114
|
+
_excessArguments() {
|
|
115
|
+
if (!this._allowExcessArguments) throw parserFailure(this, 'excess_arguments');
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
for (const [name, handler] of Object.entries(methods)) {
|
|
119
|
+
if (command[name] === Command.prototype[name]) command[name] = handler;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
for (const option of command.options) {
|
|
123
|
+
if (options.has(option)) continue;
|
|
124
|
+
options.add(option);
|
|
125
|
+
const parse = option.parseArg;
|
|
126
|
+
if (parse) option.argParser(function(...args) {
|
|
127
|
+
try { return parse.apply(this, args); }
|
|
128
|
+
catch (error) {
|
|
129
|
+
if (error.code === 'commander.invalidArgument') {
|
|
130
|
+
throw parserFailure(command, 'invalid_choice', { option });
|
|
131
|
+
}
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
for (const child of command.commands) install(child);
|
|
137
|
+
}
|
|
138
|
+
return install;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
module.exports = { configureParserPolicy, parserFailure };
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Command } = require('commander');
|
|
4
|
+
const { version } = require('../../package.json');
|
|
5
|
+
const { createSchemaCommand } = require('../commands/system/schema');
|
|
6
|
+
const { createDoctorCommand } = require('../commands/system/doctor');
|
|
7
|
+
const { createApiCommand } = require('../commands/system/api');
|
|
8
|
+
const { createSkillsCommand } = require('../commands/system/skills');
|
|
9
|
+
const { createInstallCommand } = require('../commands/system/install');
|
|
10
|
+
const { createAuthCommand } = require('../commands/system/auth');
|
|
11
|
+
const { createShopCommand } = require('../commands/system/shop');
|
|
12
|
+
const {
|
|
13
|
+
registerNativeDomains, registerNativeDomain, nativeRoot
|
|
14
|
+
} = require('./native-loader');
|
|
15
|
+
const { skillsRoot } = require('./domain-catalog');
|
|
16
|
+
const { validateSkillCatalog } = require('./skill-catalog');
|
|
17
|
+
const { openRegistry } = require('../../internal/registry');
|
|
18
|
+
const { readContext } = require('../identity/context');
|
|
19
|
+
const { contextInput } = require('../identity/context-store');
|
|
20
|
+
const { assertAvailable } = require('../execution/command-policy');
|
|
21
|
+
const { commandSchema } = require('../execution/command-schema');
|
|
22
|
+
const { commandContract, commandPath } = require('./command-paths');
|
|
23
|
+
const { configureContextHelp, isContextHelp } = require('./context-help');
|
|
24
|
+
const { configureParserPolicy } = require('./parser-policy');
|
|
25
|
+
|
|
26
|
+
function createProgram({ catalog = openRegistry(), root = nativeRoot, rootSkills = skillsRoot,
|
|
27
|
+
eagerDomains = false, context = contextInput(process.env) } = {}) {
|
|
28
|
+
const { domains, skills, businessCommandCount } = catalog.manifest;
|
|
29
|
+
const domainNames = new Set(domains.map(domain => domain.name));
|
|
30
|
+
const loadedDomains = new Set();
|
|
31
|
+
const program = new Command();
|
|
32
|
+
const contextState = readContext(context);
|
|
33
|
+
const installParsing = configureParserPolicy(prepareHelp);
|
|
34
|
+
const installHelp = configureContextHelp(program, contextState, loadDomain);
|
|
35
|
+
|
|
36
|
+
function loadDomain(name) {
|
|
37
|
+
if (loadedDomains.has(name)) return;
|
|
38
|
+
const domain = domains.find(entry => entry.name === name);
|
|
39
|
+
if (!domain) return;
|
|
40
|
+
const index = catalog.loadDomain(name);
|
|
41
|
+
registerNativeDomain(program, domain, index.businessCommands, root, rootSkills,
|
|
42
|
+
contextState.context);
|
|
43
|
+
loadedDomains.add(name);
|
|
44
|
+
installHelp();
|
|
45
|
+
installParsing(program);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
program.name('zan-saas')
|
|
49
|
+
.description('有赞 SaaS 命令行工具')
|
|
50
|
+
.version(version, '-V, --version', '显示版本号')
|
|
51
|
+
.exitOverride()
|
|
52
|
+
.configureOutput({ writeErr: () => {} });
|
|
53
|
+
|
|
54
|
+
program.addCommand(createSchemaCommand(() => program, path => {
|
|
55
|
+
if (!path) {
|
|
56
|
+
for (const domain of domains) loadDomain(domain.name);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const name = path.split('.')[0];
|
|
60
|
+
if (domainNames.has(name)) loadDomain(name);
|
|
61
|
+
}));
|
|
62
|
+
program.addCommand(createDoctorCommand(businessCommandCount));
|
|
63
|
+
program.addCommand(createApiCommand());
|
|
64
|
+
program.addCommand(createAuthCommand());
|
|
65
|
+
program.addCommand(createShopCommand());
|
|
66
|
+
program.addCommand(createSkillsCommand(skills, rootSkills));
|
|
67
|
+
program.addCommand(createInstallCommand());
|
|
68
|
+
function configureSystemErrors(command) {
|
|
69
|
+
command.exitOverride().configureOutput({ writeErr: program.configureOutput().writeErr });
|
|
70
|
+
for (const child of command.commands) configureSystemErrors(child);
|
|
71
|
+
}
|
|
72
|
+
for (const command of program.commands) configureSystemErrors(command);
|
|
73
|
+
registerNativeDomains(program, domains);
|
|
74
|
+
validateSkillCatalog(skills, domains);
|
|
75
|
+
installHelp();
|
|
76
|
+
installParsing(program);
|
|
77
|
+
|
|
78
|
+
program.hook('preSubcommand', (parent, command) => {
|
|
79
|
+
if (parent === program && domainNames.has(command.name())) loadDomain(command.name());
|
|
80
|
+
installHelp(command);
|
|
81
|
+
installParsing(command);
|
|
82
|
+
});
|
|
83
|
+
program.hook('preAction', (_parent, command) => {
|
|
84
|
+
if (isContextHelp(command)) return;
|
|
85
|
+
const contract = commandContract(commandPath(command), command);
|
|
86
|
+
if (['atomic', 'task'].includes(contract.kind)) {
|
|
87
|
+
const details = commandSchema(command)?.error?.properties?.details;
|
|
88
|
+
const stages = details?.properties?.stage?.enum;
|
|
89
|
+
assertAvailable(contract.at, contextState, {
|
|
90
|
+
dryRun: command.opts().dryRun === true, command: commandPath(command),
|
|
91
|
+
includeDetails: Boolean(details),
|
|
92
|
+
contextStage: stages?.includes('configuration') && !stages.includes('context')
|
|
93
|
+
? 'configuration' : 'context'
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
function prepareHelp(target) {
|
|
98
|
+
if (target === program) {
|
|
99
|
+
for (const domain of domains) loadDomain(domain.name);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
let command = target;
|
|
103
|
+
while (command.parent && command.parent !== program) command = command.parent;
|
|
104
|
+
if (command.parent === program && domainNames.has(command.name())) {
|
|
105
|
+
loadDomain(command.name());
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
program.on('beforeAllHelp', helpContext => prepareHelp(helpContext.command));
|
|
109
|
+
|
|
110
|
+
if (skills.some(skill => skill.type === 'entry')) {
|
|
111
|
+
program.addHelpText('after', `
|
|
112
|
+
快速开始:
|
|
113
|
+
1. 登录:zan-saas auth login,按提示在浏览器完成授权
|
|
114
|
+
2. 查看当前店铺:zan-saas shop current;已有有效上下文时沿用
|
|
115
|
+
3. 需要选店时:zan-saas shop list,按用户指定的店名或选择执行 zan-saas shop use <kdtId>
|
|
116
|
+
4. 阅读使用指引:zan-saas skills read zan-saas
|
|
117
|
+
|
|
118
|
+
查询命令:
|
|
119
|
+
zan-saas help auth login
|
|
120
|
+
zan-saas help <domain> <resource> <action>
|
|
121
|
+
zan-saas schema <path>
|
|
122
|
+
命令路径中的各部分须分别传参;也可使用各层命令的 --help。
|
|
123
|
+
|
|
124
|
+
领域业务命令需要登录凭证和店铺上下文;--dry-run 仅预览,不访问业务接口。
|
|
125
|
+
当前领域业务命令均为只读查询;api 为独立的原始接口入口,调用前查看 zan-saas help api。
|
|
126
|
+
使用指引解释操作方式,可执行命令以当前安装版的 help 和 schema 为准。`);
|
|
127
|
+
}
|
|
128
|
+
if (eagerDomains) {
|
|
129
|
+
for (const domain of domains) loadDomain(domain.name);
|
|
130
|
+
}
|
|
131
|
+
return program;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
module.exports = { createProgram };
|