gangtise-openapi-cli 0.15.0 → 0.16.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/README.md +58 -9
- package/dist/src/cli.js +63 -79
- package/dist/src/core/client.js +0 -6
- package/dist/src/core/endpoints.js +35 -42
- package/dist/src/core/errors.js +7 -0
- package/dist/src/core/lookupData/index.js +0 -6
- package/dist/src/core/normalize.js +5 -0
- package/dist/src/version.js +1 -1
- package/package.json +5 -2
- package/dist/src/core/lookupData/announcement-categories.js +0 -554
- package/dist/src/core/lookupData/industries.js +0 -157
- package/dist/src/core/lookupData/industry-codes.js +0 -126
- package/dist/src/core/lookupData/regions.js +0 -78
- package/dist/src/core/lookupData/research-areas.js +0 -266
- package/dist/src/core/lookupData/theme-ids.js +0 -1614
package/README.md
CHANGED
|
@@ -4,6 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
## Changelog
|
|
6
6
|
|
|
7
|
+
### v0.16.0 — 2026-06-12
|
|
8
|
+
|
|
9
|
+
**新增接口(参考数据 · 常量查询,均免积分)**
|
|
10
|
+
- `reference constant-category` — 查询常量分类:全量导出常量分类及各分类适用于哪些接口的哪些参数(7 个分类:中信/申万/Gangtise 行业、国内城市、A股/港股公告分类、区域)
|
|
11
|
+
- `reference constant-list --category <code>` — 查询常量值:按分类导出全量常量(`constantId` / `constantName`,树形分类含 `children` 嵌套)
|
|
12
|
+
- `reference concept-search --keyword <kw>` — 查询题材 ID:按名称/拼音/分组名搜索,返回 `conceptId`(供 `alternative concept-info / concept-securities`、`ai theme-tracking` 使用)
|
|
13
|
+
- `reference sector-search --keyword <kw>` — 查询板块 ID:返回 `sectorId` + `hierarchy` 层级路径
|
|
14
|
+
- `reference sector-constituents --sector-id <id>` — 查询板块成分股:返回该板块全量成分股(`gtsCode` / `gtsName`);注意 sectorId 必须来自 sector-search,题材 conceptId 查不到成分
|
|
15
|
+
|
|
16
|
+
**接口变更(Breaking)**
|
|
17
|
+
- 移除已被新 API 覆盖的 6 个本地 lookup 子命令及静态数据:`lookup research-area / industry / region / announcement-category / theme-id / industry-code list`,请改用 `reference constant-list` / `reference concept-search` / `reference sector-constituents`(申万行业代码 `821xxx.SWI` 全量:`sector-constituents --sector-id 2000000014`,即申万一级行业指数板块)
|
|
18
|
+
- `lookup` 仅保留 2 个 API 未覆盖的本地表:`broker-org` / `meeting-org`
|
|
19
|
+
- 路演/调研/策略会/论坛 list 新增 `--location <id>` 按城市过滤(domesticCity 常量 ID;实测 2026-06-12 服务端过滤暂未生效)
|
|
20
|
+
|
|
7
21
|
### v0.15.0 — 2026-05-29
|
|
8
22
|
|
|
9
23
|
**新增接口**
|
|
@@ -125,6 +139,22 @@ cd gangtise-openapi-cli
|
|
|
125
139
|
npm install
|
|
126
140
|
npm run dev -- --help
|
|
127
141
|
```
|
|
142
|
+
|
|
143
|
+
## 发布
|
|
144
|
+
|
|
145
|
+
npm 发版通过 GitHub Actions Trusted Publishing 完成,不需要 `NPM_TOKEN`。npm 包设置里的 Trusted Publisher 需要匹配本仓库和 workflow 文件名 `publish.yml`。
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
npm version patch --no-git-tag-version
|
|
149
|
+
npm run prepare
|
|
150
|
+
VERSION=$(node -p "require('./package.json').version")
|
|
151
|
+
git commit -am "chore: release v$VERSION"
|
|
152
|
+
git tag -a "v$VERSION" -m "v$VERSION" # 必须 annotated:--follow-tags 不推 lightweight tag
|
|
153
|
+
git push --follow-tags
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
推送 `v*` tag 后,`.github/workflows/publish.yml` 会在 GitHub-hosted runner 上使用 OIDC 发布到 `https://registry.npmjs.org/`。也可以从 GitHub Actions 页面手动运行该 workflow。
|
|
157
|
+
|
|
128
158
|
## 版本更新
|
|
129
159
|
|
|
130
160
|
查看当前版本(自动与线上版本比对):
|
|
@@ -219,7 +249,7 @@ cp -r gangtise-openapi ~/.hermes/skills/gangtise-openapi
|
|
|
219
249
|
| 模块 | 子命令 | 说明 |
|
|
220
250
|
|------|--------|------|
|
|
221
251
|
| **Auth** | `login` / `status` | 认证登录、状态查询 |
|
|
222
|
-
| **Lookup** | `
|
|
252
|
+
| **Lookup** | `broker-org list` / `meeting-org list` | 本地枚举表(API 未覆盖的部分;行业/区域/公告分类/题材/申万行业代码改用 Reference 接口) |
|
|
223
253
|
| **Insight** | `opinion list` | 内资机构观点 |
|
|
224
254
|
| | `summary list` / `download` | 纪要(含下载,支持 `--file-type` 选原始/HTML) |
|
|
225
255
|
| | `roadshow list` | 路演 |
|
|
@@ -233,6 +263,11 @@ cp -r gangtise-openapi ~/.hermes/skills/gangtise-openapi
|
|
|
233
263
|
| | `foreign-opinion list` | 外资机构观点 |
|
|
234
264
|
| | `independent-opinion list` / `download` | 外资独立分析师观点(含原文/翻译HTML下载) |
|
|
235
265
|
| **Reference** | `securities-search` | GTS Code 搜索(按名称/代码/拼音匹配) |
|
|
266
|
+
| | `constant-category` | 常量分类列表(含各分类适用的接口与参数) |
|
|
267
|
+
| | `constant-list` | 按分类导出常量值全量列表(行业/城市/公告分类/区域等) |
|
|
268
|
+
| | `concept-search` | 题材 ID 搜索(名称/拼音/分组名匹配) |
|
|
269
|
+
| | `sector-search` | 板块 ID 搜索(返回层级路径) |
|
|
270
|
+
| | `sector-constituents` | 板块成分股查询 |
|
|
236
271
|
| **Quote** | `day-kline` / `day-kline-hk` / `day-kline-us` | A股/港股/美股历史日K线 |
|
|
237
272
|
| | `index-day-kline` | 沪深京指数日K线 |
|
|
238
273
|
| | `minute-kline` | A股分钟K线 |
|
|
@@ -286,13 +321,14 @@ cp -r gangtise-openapi ~/.hermes/skills/gangtise-openapi
|
|
|
286
321
|
先查枚举/参数:
|
|
287
322
|
|
|
288
323
|
```bash
|
|
289
|
-
gangtise
|
|
290
|
-
gangtise
|
|
291
|
-
gangtise
|
|
292
|
-
gangtise
|
|
293
|
-
gangtise
|
|
294
|
-
gangtise
|
|
295
|
-
gangtise lookup
|
|
324
|
+
gangtise reference constant-category # 有哪些常量分类、各用于哪些参数
|
|
325
|
+
gangtise reference constant-list --category citicIndustry # 中信行业(--industry / --research-area)
|
|
326
|
+
gangtise reference constant-list --category swIndustry # 申万行业
|
|
327
|
+
gangtise reference constant-list --category regionCategory # 外资研报区域
|
|
328
|
+
gangtise reference constant-list --category aShareAnnouncementCategory # A股公告分类(树形)
|
|
329
|
+
gangtise reference sector-constituents --sector-id 2000000014 # 申万行业代码 821xxx.SWI 全量(security-clue --gts-code 用)
|
|
330
|
+
gangtise lookup broker-org list # 券商机构(本地表)
|
|
331
|
+
gangtise lookup meeting-org list # 会议机构(本地表)
|
|
296
332
|
```
|
|
297
333
|
|
|
298
334
|
再调用业务命令:
|
|
@@ -420,6 +456,19 @@ gangtise reference securities-search --keyword "贵州茅台" --category stock
|
|
|
420
456
|
gangtise reference securities-search --keyword "600519" --category stock
|
|
421
457
|
gangtise reference securities-search --keyword gzmt --top 5
|
|
422
458
|
gangtise reference securities-search --keyword "银行" --category stock --category index
|
|
459
|
+
|
|
460
|
+
# 常量查询:先看分类,再按分类导出全量常量值
|
|
461
|
+
gangtise reference constant-category --format json
|
|
462
|
+
gangtise reference constant-list --category citicIndustry --format json
|
|
463
|
+
gangtise reference constant-list --category aShareAnnouncementCategory --format json # 树形,含 children
|
|
464
|
+
|
|
465
|
+
# 题材 ID 搜索(供 concept-info / concept-securities / theme-tracking 使用)
|
|
466
|
+
gangtise reference concept-search --keyword 机器人 --top 3 --format json
|
|
467
|
+
gangtise reference concept-search --keyword jqr # 拼音首字母
|
|
468
|
+
|
|
469
|
+
# 板块:先搜板块 ID,再查成分股(sectorId 必须来自 sector-search)
|
|
470
|
+
gangtise reference sector-search --keyword 半导体设备 --format json
|
|
471
|
+
gangtise reference sector-constituents --sector-id 1000001005 --format json
|
|
423
472
|
```
|
|
424
473
|
|
|
425
474
|
### Quote
|
|
@@ -577,7 +626,7 @@ gangtise alternative edb-data \
|
|
|
577
626
|
--output ./indicator.csv
|
|
578
627
|
|
|
579
628
|
# 题材指数:先查 conceptId(与 theme-id 共用 ID 体系),再拉画像 / 成分股
|
|
580
|
-
gangtise
|
|
629
|
+
gangtise reference concept-search --keyword 机器人 --format json # → 121000130
|
|
581
630
|
gangtise alternative concept-info --concept-id 121000130 --format json
|
|
582
631
|
# 题材成分股(题材深度 F8,按分组返回,标记重点个股)
|
|
583
632
|
gangtise alternative concept-securities --concept-id 121000130 --format json
|
package/dist/src/cli.js
CHANGED
|
@@ -46,6 +46,35 @@ async function runDownload(client, endpointKey, query, options) {
|
|
|
46
46
|
const resolved = options.resolveOutputPath ? await options.resolveOutputPath(result) : undefined;
|
|
47
47
|
await saveDownloadResult(result, options.fallbackName, resolved);
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Register a download subcommand. All download commands share one shape: a
|
|
51
|
+
* required id option, optionally --file-type / --content-type, then --output.
|
|
52
|
+
* `idField` doubles as the commander option key and the query/title-cache
|
|
53
|
+
* field, so it must stay the camelCase twin of `idOption`.
|
|
54
|
+
*/
|
|
55
|
+
function addDownloadCommand(parent, spec) {
|
|
56
|
+
const cmd = parent.command(spec.name ?? "download").requiredOption(`${spec.idOption} <id>`);
|
|
57
|
+
if (spec.fileType?.required)
|
|
58
|
+
cmd.requiredOption("--file-type <number>", spec.fileType.description);
|
|
59
|
+
else if (spec.fileType)
|
|
60
|
+
cmd.option("--file-type <number>", spec.fileType.description, spec.fileType.default);
|
|
61
|
+
if (spec.contentTypeDescription)
|
|
62
|
+
cmd.requiredOption("--content-type <type>", spec.contentTypeDescription);
|
|
63
|
+
cmd.option("--output <path>").action((options) => withClient(async (client) => {
|
|
64
|
+
const id = options[spec.idField];
|
|
65
|
+
const qp = { [spec.idField]: id };
|
|
66
|
+
if (spec.fileType && options.fileType)
|
|
67
|
+
qp.fileType = parseNumberOption(options.fileType, "--file-type", { integer: true, min: 1 });
|
|
68
|
+
if (spec.contentTypeDescription)
|
|
69
|
+
qp.contentType = options.contentType;
|
|
70
|
+
const titleList = spec.titleListEndpoint;
|
|
71
|
+
await runDownload(client, spec.endpointKey, qp, {
|
|
72
|
+
output: options.output,
|
|
73
|
+
fallbackName: `${spec.fallbackPrefix}-${id}`,
|
|
74
|
+
resolveOutputPath: titleList ? (result) => resolveTitle(client, result, titleList, spec.idField, id) : undefined,
|
|
75
|
+
});
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
49
78
|
function addTimeFilters(command) {
|
|
50
79
|
return command
|
|
51
80
|
.option("--from <number>", "Starting offset", "0")
|
|
@@ -79,16 +108,15 @@ program
|
|
|
79
108
|
const cache = await readTokenCache(config.tokenCachePath);
|
|
80
109
|
await printData({ hasEnvToken: Boolean(config.token), hasCachedToken: Boolean(cache?.accessToken), cache }, parseOutputFormat(options.format));
|
|
81
110
|
}));
|
|
82
|
-
const lookup = new Command("lookup").description("
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
.addCommand(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
.addCommand(new Command("theme-id").description("Theme IDs for theme-tracking --theme-id").addCommand(new Command("list").option("--format <format>", "Output format", "table").action((options) => emit(options, (client) => client.call("lookup.theme-ids.list")))));
|
|
111
|
+
const lookup = new Command("lookup").description("Local lookup tables (IDs not covered by 'reference constant-list')");
|
|
112
|
+
const addLookupList = (name, endpointKey, description) => {
|
|
113
|
+
const cmd = new Command(name);
|
|
114
|
+
if (description)
|
|
115
|
+
cmd.description(description);
|
|
116
|
+
lookup.addCommand(cmd.addCommand(new Command("list").option("--format <format>", "Output format", "table").action((options) => emit(options, (client) => client.call(endpointKey)))));
|
|
117
|
+
};
|
|
118
|
+
addLookupList("broker-org", "lookup.broker-orgs.list");
|
|
119
|
+
addLookupList("meeting-org", "lookup.meeting-orgs.list");
|
|
92
120
|
program.addCommand(lookup);
|
|
93
121
|
const insight = new Command("insight").description("Insight APIs");
|
|
94
122
|
const opinion = new Command("opinion");
|
|
@@ -115,21 +143,13 @@ addTimeFilters(summary.command("list").option("--search-type <number>", "Search
|
|
|
115
143
|
researchAreaList: maybeArray(options.researchArea), securityList: maybeArray(options.security), institutionList: maybeArray(options.institution),
|
|
116
144
|
categoryList: maybeArray(options.category), marketList: maybeArray(options.market), participantRoleList: maybeArray(options.participantRole),
|
|
117
145
|
}), { endpointKey: "insight.summary.list", idField: "summaryId" }));
|
|
118
|
-
summary.
|
|
119
|
-
|
|
120
|
-
if (options.fileType)
|
|
121
|
-
qp.fileType = parseNumberOption(options.fileType, "--file-type", { integer: true, min: 1 });
|
|
122
|
-
await runDownload(client, "insight.summary.download", qp, {
|
|
123
|
-
output: options.output,
|
|
124
|
-
fallbackName: `summary-${options.summaryId}`,
|
|
125
|
-
resolveOutputPath: (result) => resolveTitle(client, result, "insight.summary.list", "summaryId", options.summaryId),
|
|
126
|
-
});
|
|
127
|
-
}));
|
|
128
|
-
const addScheduleList = (command, endpointKey) => addTimeFilters(command.command("list").option("--research-area <id>", "Research area", collectList, []).option("--institution <id>", "Institution ID", collectList, []).option("--security <code>", "Security code", collectList, []).option("--category <name>", "Category", collectList, []).option("--market <name>", "Market", collectList, []).option("--participant-role <name>", "Participant role", collectList, []).option("--broker-type <name>", "Broker type", collectList, []).option("--object <type>", "Object type: company/industry", collectList, []).option("--permission <number>", "Permission", collectNumberList, []).option("--format <format>", "Output format", "table").option("--output <path>", "Output path")).action((options) => emit(options, (client) => client.call(endpointKey, {
|
|
146
|
+
addDownloadCommand(summary, { endpointKey: "insight.summary.download", idOption: "--summary-id", idField: "summaryId", fallbackPrefix: "summary", fileType: { description: "File type: 1=original(default) 2=HTML; only affects meeting platform summaries" }, titleListEndpoint: "insight.summary.list" });
|
|
147
|
+
const addScheduleList = (command, endpointKey) => addTimeFilters(command.command("list").option("--research-area <id>", "Research area", collectList, []).option("--institution <id>", "Institution ID", collectList, []).option("--security <code>", "Security code", collectList, []).option("--category <name>", "Category", collectList, []).option("--market <name>", "Market", collectList, []).option("--participant-role <name>", "Participant role", collectList, []).option("--broker-type <name>", "Broker type", collectList, []).option("--object <type>", "Object type: company/industry", collectList, []).option("--permission <number>", "Permission", collectNumberList, []).option("--location <id>", "Location ID (domesticCity constant, via 'reference constant-list')", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>", "Output path")).action((options) => emit(options, (client) => client.call(endpointKey, {
|
|
129
148
|
from: parseFrom(options.from), size: parseSize(options.size), startTime: options.startTime, endTime: options.endTime, keyword: options.keyword,
|
|
130
149
|
researchAreaList: maybeArray(options.researchArea), institutionList: maybeArray(options.institution), securityList: maybeArray(options.security),
|
|
131
150
|
categoryList: maybeArray(options.category), marketList: maybeArray(options.market), participantRoleList: maybeArray(options.participantRole),
|
|
132
151
|
brokerTypeList: maybeArray(options.brokerType), objectList: maybeArray(options.object), permission: options.permission.length ? options.permission : undefined,
|
|
152
|
+
locationList: maybeArray(options.location),
|
|
133
153
|
})));
|
|
134
154
|
addScheduleList(roadshow, "insight.roadshow.list");
|
|
135
155
|
addScheduleList(siteVisit, "insight.site-visit.list");
|
|
@@ -143,13 +163,7 @@ addTimeFilters(research.command("list").option("--search-type <number>", "Search
|
|
|
143
163
|
ratingChangeList: maybeArray(options.ratingChange), minReportPages: parseOptionalNumberOption(options.minPages, "--min-pages", { integer: true, min: 0 }),
|
|
144
164
|
maxReportPages: parseOptionalNumberOption(options.maxPages, "--max-pages", { integer: true, min: 0 }), sourceList: maybeArray(options.source),
|
|
145
165
|
}), { endpointKey: "insight.research.list", idField: "reportId" }));
|
|
146
|
-
research.
|
|
147
|
-
await runDownload(client, "insight.research.download", { reportId: options.reportId, fileType: parseNumberOption(options.fileType, "--file-type", { integer: true, min: 1 }) }, {
|
|
148
|
-
output: options.output,
|
|
149
|
-
fallbackName: `research-${options.reportId}`,
|
|
150
|
-
resolveOutputPath: (result) => resolveTitle(client, result, "insight.research.list", "reportId", options.reportId),
|
|
151
|
-
});
|
|
152
|
-
}));
|
|
166
|
+
addDownloadCommand(research, { endpointKey: "insight.research.download", idOption: "--report-id", idField: "reportId", fallbackPrefix: "research", fileType: { description: "File type: 1=PDF 2=Markdown", default: "1" }, titleListEndpoint: "insight.research.list" });
|
|
153
167
|
addTimeFilters(foreignReport.command("list").option("--search-type <number>", "Search type: 1=title 2=fulltext", "1").option("--rank-type <number>", "Rank type: 1=composite 2=time desc", "1").option("--security <code>", "Security code", collectList, []).option("--region <id>", "Region ID", collectList, []).option("--category <name>", "Report category", collectList, []).option("--industry <id>", "Industry ID", collectList, []).option("--broker <id>", "Broker ID", collectList, []).option("--llm-tag <tag>", "Semantic tag", collectList, []).option("--rating <name>", "Rating", collectList, []).option("--rating-change <name>", "Rating change", collectList, []).option("--min-pages <number>", "Min report pages").option("--max-pages <number>", "Max report pages").option("--format <format>", "Output format", "table").option("--output <path>", "Output path")).action((options) => emit(options, (client) => client.call("insight.foreign-report.list", {
|
|
154
168
|
from: parseFrom(options.from), size: parseSize(options.size), startTime: options.startTime, endTime: options.endTime, keyword: options.keyword,
|
|
155
169
|
searchType: parseNumberOption(options.searchType, "--search-type", { integer: true, min: 1 }), rankType: parseNumberOption(options.rankType, "--rank-type", { integer: true, min: 1 }),
|
|
@@ -158,26 +172,14 @@ addTimeFilters(foreignReport.command("list").option("--search-type <number>", "S
|
|
|
158
172
|
ratingList: maybeArray(options.rating), ratingChangeList: maybeArray(options.ratingChange),
|
|
159
173
|
minReportPages: parseOptionalNumberOption(options.minPages, "--min-pages", { integer: true, min: 0 }), maxReportPages: parseOptionalNumberOption(options.maxPages, "--max-pages", { integer: true, min: 0 }),
|
|
160
174
|
}), { endpointKey: "insight.foreign-report.list", idField: "reportId" }));
|
|
161
|
-
foreignReport.
|
|
162
|
-
await runDownload(client, "insight.foreign-report.download", { reportId: options.reportId, fileType: parseNumberOption(options.fileType, "--file-type", { integer: true, min: 1 }) }, {
|
|
163
|
-
output: options.output,
|
|
164
|
-
fallbackName: `foreign-report-${options.reportId}`,
|
|
165
|
-
resolveOutputPath: (result) => resolveTitle(client, result, "insight.foreign-report.list", "reportId", options.reportId),
|
|
166
|
-
});
|
|
167
|
-
}));
|
|
175
|
+
addDownloadCommand(foreignReport, { endpointKey: "insight.foreign-report.download", idOption: "--report-id", idField: "reportId", fallbackPrefix: "foreign-report", fileType: { description: "File type: 1=PDF 2=Markdown 3=CN-PDF 4=CN-Markdown", default: "1" }, titleListEndpoint: "insight.foreign-report.list" });
|
|
168
176
|
addTimeFilters(announcement.command("list").option("--search-type <number>", "Search type: 1=title 2=fulltext", "1").option("--rank-type <number>", "Rank type: 1=composite 2=time desc", "1").option("--security <code>", "Security code", collectList, []).option("--announcement-type <type>", "Announcement type", collectList, []).option("--category <id>", "Category ID", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>", "Output path")).action((options) => emit(options, (client) => client.call("insight.announcement.list", {
|
|
169
177
|
from: parseFrom(options.from), size: parseSize(options.size),
|
|
170
178
|
startTime: parseTimestamp13(options.startTime, "--start-time"), endTime: parseTimestamp13(options.endTime, "--end-time"),
|
|
171
179
|
searchType: parseNumberOption(options.searchType, "--search-type", { integer: true, min: 1 }), rankType: parseNumberOption(options.rankType, "--rank-type", { integer: true, min: 1 }), keyword: options.keyword,
|
|
172
180
|
securityList: maybeArray(options.security), announcementTypeList: maybeArray(options.announcementType), categoryList: maybeArray(options.category),
|
|
173
181
|
}), { endpointKey: "insight.announcement.list", idField: "announcementId" }));
|
|
174
|
-
announcement.
|
|
175
|
-
await runDownload(client, "insight.announcement.download", { announcementId: options.announcementId, fileType: parseNumberOption(options.fileType, "--file-type", { integer: true, min: 1 }) }, {
|
|
176
|
-
output: options.output,
|
|
177
|
-
fallbackName: `announcement-${options.announcementId}`,
|
|
178
|
-
resolveOutputPath: (result) => resolveTitle(client, result, "insight.announcement.list", "announcementId", options.announcementId),
|
|
179
|
-
});
|
|
180
|
-
}));
|
|
182
|
+
addDownloadCommand(announcement, { endpointKey: "insight.announcement.download", idOption: "--announcement-id", idField: "announcementId", fallbackPrefix: "announcement", fileType: { description: "File type: 1=PDF 2=Markdown", default: "1" }, titleListEndpoint: "insight.announcement.list" });
|
|
181
183
|
addTimeFilters(announcementHk.command("list").option("--search-type <number>", "Search type: 1=title 2=fulltext", "1").option("--rank-type <number>", "Rank type: 1=composite 2=time desc", "1").option("--security <code>", "Security code (e.g. 01913.HK)", collectList, []).option("--category <id>", "Category ID", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>", "Output path")).action((options) => emit(options, (client) => client.call("insight.announcement-hk.list", {
|
|
182
184
|
from: parseFrom(options.from), size: parseSize(options.size),
|
|
183
185
|
startTime: options.startTime, endTime: options.endTime,
|
|
@@ -186,13 +188,7 @@ addTimeFilters(announcementHk.command("list").option("--search-type <number>", "
|
|
|
186
188
|
keyword: options.keyword,
|
|
187
189
|
securityList: maybeArray(options.security), categoryList: maybeArray(options.category),
|
|
188
190
|
}), { endpointKey: "insight.announcement-hk.list", idField: "announcementId" }));
|
|
189
|
-
announcementHk.
|
|
190
|
-
await runDownload(client, "insight.announcement-hk.download", { announcementId: options.announcementId }, {
|
|
191
|
-
output: options.output,
|
|
192
|
-
fallbackName: `announcement-hk-${options.announcementId}`,
|
|
193
|
-
resolveOutputPath: (result) => resolveTitle(client, result, "insight.announcement-hk.list", "announcementId", options.announcementId),
|
|
194
|
-
});
|
|
195
|
-
}));
|
|
191
|
+
addDownloadCommand(announcementHk, { endpointKey: "insight.announcement-hk.download", idOption: "--announcement-id", idField: "announcementId", fallbackPrefix: "announcement-hk", titleListEndpoint: "insight.announcement-hk.list" });
|
|
196
192
|
addTimeFilters(foreignOpinion.command("list").option("--rank-type <number>", "Rank type: 1=composite 2=time desc", "1").option("--security <code>", "Security code (e.g. UBER.N)", collectList, []).option("--region <code>", "Region code", collectList, []).option("--industry <id>", "Industry ID", collectList, []).option("--broker <id>", "Broker ID", collectList, []).option("--rating <name>", "Rating", collectList, []).option("--rating-change <name>", "Rating change", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>", "Output path")).action((options) => emit(options, (client) => client.call("insight.foreign-opinion.list", {
|
|
197
193
|
from: parseFrom(options.from), size: parseSize(options.size),
|
|
198
194
|
startTime: options.startTime, endTime: options.endTime,
|
|
@@ -210,12 +206,7 @@ addTimeFilters(independentOpinion.command("list").option("--rank-type <number>",
|
|
|
210
206
|
industryList: maybeArray(options.industry), securityList: maybeArray(options.security),
|
|
211
207
|
ratingList: maybeArray(options.rating), ratingChangeList: maybeArray(options.ratingChange),
|
|
212
208
|
})));
|
|
213
|
-
independentOpinion.
|
|
214
|
-
await runDownload(client, "insight.independent-opinion.download", { independentOpinionId: options.independentOpinionId, fileType: parseNumberOption(options.fileType, "--file-type", { integer: true, min: 1 }) }, {
|
|
215
|
-
output: options.output,
|
|
216
|
-
fallbackName: `independent-opinion-${options.independentOpinionId}`,
|
|
217
|
-
});
|
|
218
|
-
}));
|
|
209
|
+
addDownloadCommand(independentOpinion, { endpointKey: "insight.independent-opinion.download", idOption: "--independent-opinion-id", idField: "independentOpinionId", fallbackPrefix: "independent-opinion", fileType: { description: "File type: 1=original HTML 2=CN-translated HTML", required: true } });
|
|
219
210
|
insight.addCommand(opinion);
|
|
220
211
|
insight.addCommand(summary);
|
|
221
212
|
insight.addCommand(roadshow);
|
|
@@ -306,7 +297,7 @@ ai.command("earnings-review").requiredOption("--security-code <code>").requiredO
|
|
|
306
297
|
}
|
|
307
298
|
}));
|
|
308
299
|
ai.command("earnings-review-check").requiredOption("--data-id <id>", "dataId from earnings-review").option("--format <format>", "Output format", "json").option("--output <path>").action((options) => withClient((client) => checkAsyncContent(client, "ai.earnings-review.get-content", options.dataId, parseOutputFormat(options.format), options.output)));
|
|
309
|
-
ai.command("theme-tracking").requiredOption("--theme-id <id>", "Theme ID (use
|
|
300
|
+
ai.command("theme-tracking").requiredOption("--theme-id <id>", "Theme ID (use 'reference concept-search')").requiredOption("--date <date>", "Date (yyyy-MM-dd)").option("--type <name>", "Report type: morning/night", collectList, []).option("--format <format>", "Output format", "json").option("--output <path>").action((options) => emit(options, (client) => {
|
|
310
301
|
const typeList = options.type.length ? options.type : undefined;
|
|
311
302
|
return client.call("ai.theme-tracking", { themeId: options.themeId, date: options.date, type: typeList });
|
|
312
303
|
}));
|
|
@@ -359,32 +350,25 @@ reference.command("securities-search").requiredOption("--keyword <text>", "Searc
|
|
|
359
350
|
category: options.category.length ? options.category : undefined,
|
|
360
351
|
top: parseNumberOption(options.top, "--top", { integer: true, min: 1 }),
|
|
361
352
|
})));
|
|
353
|
+
reference.command("constant-category").description("List constant categories and which API params accept them").option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => client.call("reference.constant-category")));
|
|
354
|
+
reference.command("constant-list").requiredOption("--category <code>", "Category code from 'reference constant-category' (e.g. citicIndustry/swIndustry/regionCategory)").option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => client.call("reference.constant-list", { category: options.category })));
|
|
355
|
+
reference.command("concept-search").requiredOption("--keyword <text>", "Search keyword (name/pinyin/group name)").option("--top <number>", "Max results (default: 10, max: 10)", "10").option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => client.call("reference.concept-search", {
|
|
356
|
+
keyword: options.keyword,
|
|
357
|
+
top: parseNumberOption(options.top, "--top", { integer: true, min: 1 }),
|
|
358
|
+
})));
|
|
359
|
+
reference.command("sector-search").option("--keyword <text>", "Search keyword (name/pinyin)").option("--top <number>", "Max results (default: 10, max: 10)", "10").option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => client.call("reference.sector-search", {
|
|
360
|
+
keyword: options.keyword,
|
|
361
|
+
top: parseNumberOption(options.top, "--top", { integer: true, min: 1 }),
|
|
362
|
+
})));
|
|
363
|
+
reference.command("sector-constituents").requiredOption("--sector-id <id>", "Sector ID from 'reference sector-search'").option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => client.call("reference.sector-constituents", { sectorId: options.sectorId })));
|
|
362
364
|
program.addCommand(reference);
|
|
363
365
|
const vault = new Command("vault").description("Vault APIs");
|
|
364
366
|
vault.command("drive-list").option("--from <number>", "Starting offset", "0").option("--size <number>", "Total rows to return; omit to fetch all").option("--start-time <datetime>").option("--end-time <datetime>").option("--keyword <text>").option("--file-type <number>", "File type", collectNumberList, []).option("--space-type <number>", "Space type", collectNumberList, []).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => client.call("vault.drive.list", { from: parseFrom(options.from), size: parseSize(options.size), startTime: options.startTime, endTime: options.endTime, keyword: options.keyword, fileTypeList: options.fileType.length ? options.fileType : undefined, spaceTypeList: options.spaceType.length ? options.spaceType : undefined }), { endpointKey: "vault.drive.list", idField: "fileId" }));
|
|
365
|
-
vault.
|
|
366
|
-
await runDownload(client, "vault.drive.download", { fileId: options.fileId }, {
|
|
367
|
-
output: options.output,
|
|
368
|
-
fallbackName: `file-${options.fileId}`,
|
|
369
|
-
resolveOutputPath: (result) => resolveTitle(client, result, "vault.drive.list", "fileId", options.fileId),
|
|
370
|
-
});
|
|
371
|
-
}));
|
|
367
|
+
addDownloadCommand(vault, { endpointKey: "vault.drive.download", name: "drive-download", idOption: "--file-id", idField: "fileId", fallbackPrefix: "file", titleListEndpoint: "vault.drive.list" });
|
|
372
368
|
vault.command("record-list").option("--from <number>", "Starting offset", "0").option("--size <number>", "Total rows to return; omit to fetch all").option("--start-time <datetime>").option("--end-time <datetime>").option("--keyword <text>").option("--category <name>", "Recording type: upload/link/mobile/gtNote/pc/share", collectList, []).option("--space-type <number>", "Space type: 1=my records / 2=tenant records", collectNumberList, []).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => client.call("vault.record.list", { from: parseFrom(options.from), size: parseSize(options.size), startTime: options.startTime, endTime: options.endTime, keyword: options.keyword, categoryList: maybeArray(options.category), spaceTypeList: options.spaceType.length ? options.spaceType : undefined }), { endpointKey: "vault.record.list", idField: "recordId" }));
|
|
373
|
-
vault.
|
|
374
|
-
await runDownload(client, "vault.record.download", { recordId: options.recordId, contentType: options.contentType }, {
|
|
375
|
-
output: options.output,
|
|
376
|
-
fallbackName: `record-${options.recordId}`,
|
|
377
|
-
resolveOutputPath: (result) => resolveTitle(client, result, "vault.record.list", "recordId", options.recordId),
|
|
378
|
-
});
|
|
379
|
-
}));
|
|
369
|
+
addDownloadCommand(vault, { endpointKey: "vault.record.download", name: "record-download", idOption: "--record-id", idField: "recordId", fallbackPrefix: "record", contentTypeDescription: "Content type: original/asr/summary", titleListEndpoint: "vault.record.list" });
|
|
380
370
|
vault.command("my-conference-list").option("--from <number>", "Starting offset", "0").option("--size <number>", "Total rows to return; omit to fetch all").option("--start-time <datetime>").option("--end-time <datetime>").option("--keyword <text>").option("--research-area <id>", "Research area ID", collectList, []).option("--security <code>", "Security code", collectList, []).option("--institution <id>", "Institution ID", collectList, []).option("--category <name>", "Conference category: earningsCall/strategyMeeting/fundRoadshow/shareholdersMeeting/maMeeting/specialMeeting/companyAnalysis/industryAnalysis/other", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => client.call("vault.my-conference.list", { from: parseFrom(options.from), size: parseSize(options.size), startTime: options.startTime, endTime: options.endTime, keyword: options.keyword, researchAreaList: maybeArray(options.researchArea), securityList: maybeArray(options.security), institutionList: maybeArray(options.institution), categoryList: maybeArray(options.category) }), { endpointKey: "vault.my-conference.list", idField: "conferenceId" }));
|
|
381
|
-
vault.
|
|
382
|
-
await runDownload(client, "vault.my-conference.download", { conferenceId: options.conferenceId, contentType: options.contentType }, {
|
|
383
|
-
output: options.output,
|
|
384
|
-
fallbackName: `conference-${options.conferenceId}`,
|
|
385
|
-
resolveOutputPath: (result) => resolveTitle(client, result, "vault.my-conference.list", "conferenceId", options.conferenceId),
|
|
386
|
-
});
|
|
387
|
-
}));
|
|
371
|
+
addDownloadCommand(vault, { endpointKey: "vault.my-conference.download", name: "my-conference-download", idOption: "--conference-id", idField: "conferenceId", fallbackPrefix: "conference", contentTypeDescription: "Content type: asr/summary", titleListEndpoint: "vault.my-conference.list" });
|
|
388
372
|
vault.command("wechat-message-list").option("--from <number>", "Starting offset", "0").option("--size <number>", "Total rows to return; omit to fetch all").option("--start-time <datetime>").option("--end-time <datetime>").option("--keyword <text>").option("--security <code>", "Security code (e.g. 000001.SZ)", collectList, []).option("--wechat-group-id <id>", "WeChat group ID", collectList, []).option("--industry <id>", "Industry ID", collectList, []).option("--category <name>", "Message type: text/image/documents/url", collectList, []).option("--tag <name>", "Tag: roadShow/research/strategyMeeting/meetingSummary/industryComment/companyComment/earningsReview", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => client.call("vault.wechat-message.list", buildWechatMessageListBody(options))));
|
|
389
373
|
vault.command("wechat-chatroom-list").option("--from <number>", "Starting offset", "0").option("--size <number>", "Rows to return", "20").option("--room-name <name>", "WeChat group name; repeat or comma-separate for multiple names", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => client.call("vault.wechat-chatroom.list", buildWechatChatroomListBody(options))));
|
|
390
374
|
vault.command("stock-pool-list").option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => client.call("vault.stock-pool.list", {})));
|
|
@@ -412,8 +396,8 @@ alternative.command("edb-data").option("--indicator-id <id>", "Indicator ID (rep
|
|
|
412
396
|
}
|
|
413
397
|
await printData(data, parseOutputFormat(options.format), options.output);
|
|
414
398
|
}));
|
|
415
|
-
alternative.command("concept-info").requiredOption("--concept-id <id>", "Concept (theme index) ID, e.g. 121000130 机器人; discover via 'gangtise
|
|
416
|
-
alternative.command("concept-securities").requiredOption("--concept-id <id>", "Concept (theme index) ID, e.g. 121000130 机器人; discover via 'gangtise
|
|
399
|
+
alternative.command("concept-info").requiredOption("--concept-id <id>", "Concept (theme index) ID, e.g. 121000130 机器人; discover via 'gangtise reference concept-search'").option("--format <format>", "Output format", "json").option("--output <path>").action((options) => emit(options, (client) => client.call("alternative.concept-info", { conceptId: options.conceptId })));
|
|
400
|
+
alternative.command("concept-securities").requiredOption("--concept-id <id>", "Concept (theme index) ID, e.g. 121000130 机器人; discover via 'gangtise reference concept-search'").option("--format <format>", "Output format", "json").option("--output <path>").action((options) => emit(options, (client) => client.call("alternative.concept-securities", { conceptId: options.conceptId })));
|
|
417
401
|
program.addCommand(alternative);
|
|
418
402
|
program.command("raw").description("Raw API calls").addCommand(new Command("call").argument("<endpointKey>").option("--body <json>").option("--query <key=value>", "Query string pair", collectKeyValue, {}).option("--format <format>", "Output format", "json").option("--output <path>").action(async (endpointKey, options) => {
|
|
419
403
|
const endpoint = ENDPOINTS[endpointKey];
|
package/dist/src/core/client.js
CHANGED
|
@@ -101,14 +101,8 @@ export class GangtiseClient {
|
|
|
101
101
|
}
|
|
102
102
|
async readLocalLookup(endpoint) {
|
|
103
103
|
const keyMapping = {
|
|
104
|
-
"lookup.research-areas.list": "research-areas",
|
|
105
104
|
"lookup.broker-orgs.list": "broker-orgs",
|
|
106
105
|
"lookup.meeting-orgs.list": "meeting-orgs",
|
|
107
|
-
"lookup.industries.list": "industries",
|
|
108
|
-
"lookup.regions.list": "regions",
|
|
109
|
-
"lookup.announcement-categories.list": "announcement-categories",
|
|
110
|
-
"lookup.industry-codes.list": "industry-codes",
|
|
111
|
-
"lookup.theme-ids.list": "theme-ids",
|
|
112
106
|
};
|
|
113
107
|
const lookupKey = keyMapping[endpoint.key];
|
|
114
108
|
if (lookupKey) {
|
|
@@ -8,13 +8,6 @@ export const ENDPOINTS = {
|
|
|
8
8
|
description: "Get access token",
|
|
9
9
|
},
|
|
10
10
|
// ─── lookup (served from local data, not HTTP) ───
|
|
11
|
-
"lookup.research-areas.list": {
|
|
12
|
-
key: "lookup.research-areas.list",
|
|
13
|
-
method: "GET",
|
|
14
|
-
path: "/guide/research-area-local",
|
|
15
|
-
kind: "json",
|
|
16
|
-
description: "List research areas from local docs",
|
|
17
|
-
},
|
|
18
11
|
"lookup.broker-orgs.list": {
|
|
19
12
|
key: "lookup.broker-orgs.list",
|
|
20
13
|
method: "GET",
|
|
@@ -29,41 +22,6 @@ export const ENDPOINTS = {
|
|
|
29
22
|
kind: "json",
|
|
30
23
|
description: "List meeting orgs from local docs",
|
|
31
24
|
},
|
|
32
|
-
"lookup.industries.list": {
|
|
33
|
-
key: "lookup.industries.list",
|
|
34
|
-
method: "GET",
|
|
35
|
-
path: "/guide/industries-local",
|
|
36
|
-
kind: "json",
|
|
37
|
-
description: "List industries from local docs",
|
|
38
|
-
},
|
|
39
|
-
"lookup.regions.list": {
|
|
40
|
-
key: "lookup.regions.list",
|
|
41
|
-
method: "GET",
|
|
42
|
-
path: "/guide/regions-local",
|
|
43
|
-
kind: "json",
|
|
44
|
-
description: "List regions from local docs",
|
|
45
|
-
},
|
|
46
|
-
"lookup.announcement-categories.list": {
|
|
47
|
-
key: "lookup.announcement-categories.list",
|
|
48
|
-
method: "GET",
|
|
49
|
-
path: "/guide/announcement-categories-local",
|
|
50
|
-
kind: "json",
|
|
51
|
-
description: "List announcement categories from local docs",
|
|
52
|
-
},
|
|
53
|
-
"lookup.industry-codes.list": {
|
|
54
|
-
key: "lookup.industry-codes.list",
|
|
55
|
-
method: "GET",
|
|
56
|
-
path: "/guide/industry-codes-local",
|
|
57
|
-
kind: "json",
|
|
58
|
-
description: "List Shenwan industry codes from local docs",
|
|
59
|
-
},
|
|
60
|
-
"lookup.theme-ids.list": {
|
|
61
|
-
key: "lookup.theme-ids.list",
|
|
62
|
-
method: "GET",
|
|
63
|
-
path: "/guide/theme-ids-local",
|
|
64
|
-
kind: "json",
|
|
65
|
-
description: "List theme IDs from local docs",
|
|
66
|
-
},
|
|
67
25
|
// ─── insight ───
|
|
68
26
|
"insight.opinion.list": {
|
|
69
27
|
key: "insight.opinion.list",
|
|
@@ -211,6 +169,41 @@ export const ENDPOINTS = {
|
|
|
211
169
|
kind: "json",
|
|
212
170
|
description: "Search GTS codes (securities)",
|
|
213
171
|
},
|
|
172
|
+
"reference.constant-category": {
|
|
173
|
+
key: "reference.constant-category",
|
|
174
|
+
method: "GET",
|
|
175
|
+
path: "/application/open-reference/constants/category",
|
|
176
|
+
kind: "json",
|
|
177
|
+
description: "List constant categories and their API usage scopes",
|
|
178
|
+
},
|
|
179
|
+
"reference.constant-list": {
|
|
180
|
+
key: "reference.constant-list",
|
|
181
|
+
method: "POST",
|
|
182
|
+
path: "/application/open-reference/constants/getList",
|
|
183
|
+
kind: "json",
|
|
184
|
+
description: "List all constant values of a category",
|
|
185
|
+
},
|
|
186
|
+
"reference.concept-search": {
|
|
187
|
+
key: "reference.concept-search",
|
|
188
|
+
method: "POST",
|
|
189
|
+
path: "/application/open-reference/concepts/search",
|
|
190
|
+
kind: "json",
|
|
191
|
+
description: "Search concept (theme) IDs by keyword",
|
|
192
|
+
},
|
|
193
|
+
"reference.sector-search": {
|
|
194
|
+
key: "reference.sector-search",
|
|
195
|
+
method: "POST",
|
|
196
|
+
path: "/application/open-reference/sectors/search",
|
|
197
|
+
kind: "json",
|
|
198
|
+
description: "Search sector IDs by keyword",
|
|
199
|
+
},
|
|
200
|
+
"reference.sector-constituents": {
|
|
201
|
+
key: "reference.sector-constituents",
|
|
202
|
+
method: "POST",
|
|
203
|
+
path: "/application/open-reference/sectors/constituents",
|
|
204
|
+
kind: "json",
|
|
205
|
+
description: "List constituent securities of a sector",
|
|
206
|
+
},
|
|
214
207
|
// ─── quote ───
|
|
215
208
|
"quote.day-kline": {
|
|
216
209
|
key: "quote.day-kline",
|
package/dist/src/core/errors.js
CHANGED
|
@@ -21,6 +21,13 @@ const ERROR_HINTS = {
|
|
|
21
21
|
"8000016": "开发账号状态异常。",
|
|
22
22
|
"8000018": "开发账号已到期。",
|
|
23
23
|
"903301": "今日调用次数已达上限。",
|
|
24
|
+
"410110": "异步内容生成中,稍后用对应 *-check 命令查询。",
|
|
25
|
+
"410111": "异步内容生成失败(终态),请更换参数后重新提交。",
|
|
26
|
+
"410004": "数据未找到,请检查查询条件。",
|
|
27
|
+
"430004": "下载失败(官方未文档化错误码),请确认 reportId 有效或更换 --file-type 重试。",
|
|
28
|
+
"430007": "行情查询超出限制,请缩短日期范围。",
|
|
29
|
+
"433007": "数据源不匹配,请检查 resourceType 与 sourceId 组合。",
|
|
30
|
+
"10011401": "白名单未开通,请联系管理员。",
|
|
24
31
|
};
|
|
25
32
|
export class ApiError extends CliError {
|
|
26
33
|
code;
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
const cache = new Map();
|
|
2
2
|
const loaders = {
|
|
3
|
-
"research-areas": () => import("./research-areas.js"),
|
|
4
3
|
"broker-orgs": () => import("./broker-orgs.js"),
|
|
5
4
|
"meeting-orgs": () => import("./meeting-orgs.js"),
|
|
6
|
-
"industries": () => import("./industries.js"),
|
|
7
|
-
"regions": () => import("./regions.js"),
|
|
8
|
-
"announcement-categories": () => import("./announcement-categories.js"),
|
|
9
|
-
"industry-codes": () => import("./industry-codes.js"),
|
|
10
|
-
"theme-ids": () => import("./theme-ids.js"),
|
|
11
5
|
};
|
|
12
6
|
export async function getLookupData(key) {
|
|
13
7
|
if (cache.has(key))
|
|
@@ -29,5 +29,10 @@ export function normalizeRows(value) {
|
|
|
29
29
|
const hasMeta = Object.keys(meta).length > 0;
|
|
30
30
|
return hasMeta ? { ...meta, list: chatRoomList } : chatRoomList;
|
|
31
31
|
}
|
|
32
|
+
if (Array.isArray(record.constants)) {
|
|
33
|
+
const { constants, ...meta } = record;
|
|
34
|
+
const hasMeta = Object.keys(meta).length > 0;
|
|
35
|
+
return hasMeta ? { ...meta, list: constants } : constants;
|
|
36
|
+
}
|
|
32
37
|
return value;
|
|
33
38
|
}
|
package/dist/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated — DO NOT EDIT
|
|
2
|
-
export const CLI_VERSION = "0.
|
|
2
|
+
export const CLI_VERSION = "0.16.0";
|
package/package.json
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gangtise-openapi-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "CLI for Gangtise OpenAPI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "git+
|
|
8
|
+
"url": "git+https://github.com/gangtiser/gangtise-openapi-cli.git"
|
|
9
9
|
},
|
|
10
10
|
"bugs": {
|
|
11
11
|
"url": "https://github.com/gangtiser/gangtise-openapi-cli/issues"
|
|
12
12
|
},
|
|
13
13
|
"homepage": "https://github.com/gangtiser/gangtise-openapi-cli#readme",
|
|
14
14
|
"type": "module",
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"registry": "https://registry.npmjs.org/"
|
|
17
|
+
},
|
|
15
18
|
"bin": {
|
|
16
19
|
"gangtise": "dist/src/cli.js"
|
|
17
20
|
},
|