gangtise-openapi-cli 0.44.0 → 0.45.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 CHANGED
@@ -6,6 +6,8 @@
6
6
 
7
7
  README 仅列最近 5 个版本摘要:
8
8
 
9
+ - **v0.45.0 — 2026-10-07**:① **`vault drive-copy` 可复制整个文件夹**:`--folder-id` + `--target-parent-id`,连同子文件夹与文件复制到另一空间,返回 `{folderId, newFolderId}`;复制文件的写法不变,两组参数二选一。② **下载文件名**:响应同时给出 UTF-8 文件名与普通文件名时用 UTF-8 的那个。③ `GANGTISE_BASE_URL` 指向非本机地址却用 `http://` 时 stderr 提示一次(凭证会明文传输)。④ 文档:`bond daily-quote` / `bond valuation` 的数据可能比账号窗口短,**按年份取长序列时核对首行日期**;`bond announcement` 按日期查询时有代码的行都带后缀;基金只知道名称时怎么换代码;分钟 K 的可查历史是滚动的短窗口。
10
+
9
11
  - **v0.44.0 — 2026-09-30**:**新增 `fund` 公募基金 18 个命令,一律 0.4 积分/次**(按次,与返回行数、基金只数无关):`basic-info` / `nav`(日频净值)/ `fee-rate` / `manager-info`(按姓名精确匹配,同名全返回)/ `manager-history` / `asset-size` / `holder-structure` / `top10-holders` / `asset-allocation` / `stock-portfolio` / `industry-allocation` / `bond-portfolio` / `bond-type-allocation` / `fund-portfolio` / `fund-type-allocation` / `etf-pcf-header` / `etf-pcf-components` / `etf-share-change`。`--security` 用带大写后缀的基金代码(场外 `.OF`,场内 `.SH` / `.SZ`),**代码不存在、不带后缀或后缀小写都返回空结果、不报错**。不分页:单次上限 10000 行,超出整批报 `100006`;日期两端都不传取账号可回溯窗口内的全部,起点早于窗口整批报 `110003`。**整族超时 / 5xx 不自动重发**(避免重复扣费)。取数前注意:各命令单位不同(元 / 万元 / 万份 / 万股);`holder-structure` 的 `holderCount` 是带千分位的字符串;持仓明细只返回证券简称、不返回代码;`fund-type-allocation` 季报期只含重仓基金。逐条见 `gangtise-openapi/references/commands/fund.md`。**另有几处行为变化**:只收一个值的参数重复传直接报错;代码类列表也按顿号 / 分号 / 空格分隔并去重;显式 `--size` 与 `fundamental earning-forecast` 的日期区间估算超过 1000 积分同样要 `--yes`;jsonl / csv 文件一律以换行结尾,csv 不再给 `-3.5%` 这类值加 `'`;全市场分片早于账号窗口的部分跳过而不中止;接口返回下载链接时不带 `--output` 也会下载;A 股公告与 `ai knowledge-batch` 只写日期的 `--end-time` 按当日 23:59:59 换算;`--indicator-param` 里的日期值与 `--date` 同样校验;单次请求另有总时长上限(`GANGTISE_TIMEOUT_MS` 的 2 倍,下载与上传 60 倍);环境变量设成空字符串按未设置处理。完整列表见 CHANGELOG。
10
12
 
11
13
  - **v0.43.1 — 2026-09-27**:① **EDE `fiscalYear` 漏传不报错**:预测类(`frcst_*`)与分红类(`div_cash_yr` 等)漏传时按服务端自定的默认年度取数,数看着正常但未必是你要的年度——**一律显式传 `fiscalYear`**;其余必填参数缺失仍报 `100001`。② **翻页去重**:同一 ID 的任一已出现版本再次出现都按重复去掉(计入 `duplicateRows`),不区分字段顺序。③ **观点 `detail`**:某一批夹有空元素或格式异常的元素时,这一批已返回的正文照常输出;空元素的 ID 列在 `missingIds`,其余没取到的列在 `unfetchedIds`(`unfetchedError` 带 traceId)。④ 文档:`finc_roe_avg_avg` 示例补 `reportDate`;债券三个评级命令的计费说明统一。
@@ -14,8 +16,6 @@ README 仅列最近 5 个版本摘要:
14
16
 
15
17
  - **v0.42.0 — 2026-09-25**:① **数值参数只收十进制写法**:`--size 0x10`、`--size 1e3`、`--limit 5.0` 这类写法发请求前报错并点名参数(此前会被换算成 16 / 1000 / 5 照常发出);数字列表类参数逐项要求整数。**脚本里用了这类写法的,请改成普通整数。** ② **接管道时保留退出码**:`gangtise … | head` 提前关掉读端时,以已判定的退出码(`3` / `4`)结束,此前一律 `0`;脚本用 `set -o pipefail` 即可看到。③ **`GANGTISE_TIMEOUT_MS` 只收整数毫秒**:低于 1 秒回退默认、高于 1 小时按 1 小时,所写数值没有按原样生效时 stderr 提示一次。④ 观点 `detail` 与估值分析的返回结构与约定不符时报错并附 trace,不再按空结果处理。⑤ `fundamental valuation-analysis` 的 `--field` 不含数值列、接口返回 0 行时,stderr 说明原因。⑥ 性能:大批量导出按块写盘;自动翻页时单个慢页对其余页的拖累更小;`GANGTISE_PAGE_CONCURRENCY` 设到 16 以上时并发随之增加。
16
18
 
17
- - **v0.41.1 — 2026-09-24**:① **`quote index-day-kline --security all` 改为直接报错**:该接口对 `all` 返回空结果、不报错,与「当天无数据」无法区分;报错信息写明原因与替代写法。指数日 K 请用 `quote day-kline` 逐个传代码;该接口的返回字段与 `day-kline` 相同、不含指数名称,名称用 `reference securities-search --keyword <指数代码> --category index` 返回的 `gtsName`。② **`fundamental valuation-analysis` 长区间不再被静默截断**:序列逐自然日一行(含周末),默认只取最近 2000 行,区间更长时开头会缺失——现在撞满即标 `partial`、退出码 3,并提示把 `--limit` 设到不小于区间天数(按 366 × 年数估算,如 5 年约 1830 行);首行恰好就是 `--start-date` 时说明没丢,不标。起点早于账号回溯下界时该接口从下界起返回、不报错,CLI 在 stderr 提示首行晚于 `--start-date`。③ **估值分析 `--field` 不再可能错列**:CLI 发请求前对字段去重并去掉 `tradeDate`(它总在第一列返回)。旧版在 `--field` 同时含 `tradeDate`(或重复字段)与不存在的字段名时,会输出整体右移一列的数据且退出 0,**用过这类组合的估值结果请重跑**。④ 依赖 `undici` 升至 7.29.1(安全更新)。⑤ 文档:`fundamental valuation-analysis` 的 `--field` 至少要含一个数值列(`value` 等),只传 `tradeDate` 或只传不存在的名字时接口返回 0 行、不报错;`references/errors.md` 的退出码摘要补上 `4`。⑥ **Skill 安装命令改为可重复执行**:目标目录已存在时直接 `cp -r`,新版会被复制进嵌套的 `gangtise-openapi/gangtise-openapi/`、已安装的副本仍是旧版;这样更新过的,按「AI Agent Skill」段的新命令重新执行一次即可。
18
-
19
19
  ### 历史里程碑
20
20
 
21
21
  - **v0.41.0**:新增债券 12 个命令与云盘管理 9 个命令;观点列表改走 v2(列表只含摘要 1 积分/条,正文按 ID 另取);新增会议线索与联网搜索。
@@ -80,7 +80,7 @@ export GANGTISE_TIMEOUT_MS=30000 # 请求超时,整数毫秒(默认 30
80
80
  export GANGTISE_TOKEN_CACHE_PATH=... # 覆盖 token 缓存路径(默认 ~/.config/gangtise/token.json)
81
81
  ```
82
82
 
83
- 环境变量设成空字符串(如 `GANGTISE_BASE_URL=`)按未设置处理,取默认值。
83
+ 环境变量设成空字符串(如 `GANGTISE_BASE_URL=`)按未设置处理,取默认值。`GANGTISE_BASE_URL` 指向非本机地址却用 `http://` 时,CLI 在 stderr 提示一次:登录与请求里的 AK / SK / token 会明文传输。
84
84
 
85
85
  如果没有 `GANGTISE_TOKEN`,CLI 会自动调用 token 接口并缓存到本地(`~/.config/gangtise/token.json`,权限 0600)。服务端判定 Token 失效时,先用其他进程已刷新并写入缓存的 token,不行再重新登录,然后重发请求;凭证本身错(AK/SK 不匹配)不重试,直接报错让你查环境变量。
86
86
 
@@ -230,7 +230,7 @@ install_skill ~/.hermes/skills # Hermes
230
230
  | | `drive-folder-list` | 云盘目录浏览(某文件夹下的直接子文件夹与文件) |
231
231
  | | `drive-upload` / `drive-create-folder` / `drive-rename` | 上传文件、新建文件夹、重命名(均免费) |
232
232
  | | `drive-move-file` / `drive-move-folder` | 移动文件与文件夹(同一空间内) |
233
- | | `drive-copy` | 把文件复制到另一空间(我的云盘 ↔ 租户云盘;目前只支持文件) |
233
+ | | `drive-copy` | 把文件或整个文件夹复制到另一空间(我的云盘 ↔ 租户云盘) |
234
234
  | | `drive-delete-file` / `drive-delete-folder` | 删除文件 / 文件夹(需 `--yes`;删文件夹连同其中内容一起删除,不可恢复) |
235
235
  | | `record-list` / `record-download` | 录音速记列表与下载 |
236
236
  | | `my-conference-list` / `my-conference-download` | 我的会议列表与下载 |
@@ -686,7 +686,7 @@ gangtise bond announcement --security 019742.SH --page-size 50
686
686
  gangtise bond announcement --start-date 2026-09-18 --end-date 2026-09-19 --page-no 2 --page-size 50
687
687
  ```
688
688
 
689
- > **`bond announcement` 需要手动翻页**:它是本系列唯一分页的接口,且响应**不返回 `total`**,因此不走 CLI 的自动翻页——`--page-no` 从 1 开始逐页递增,翻过末页返回空数组(退出码 0)即停;条件下一条都没有时第 1 页就返回 `130001`(退出码 1)。⚠️ 按日期区间查询时返回的 `securityCode` 不带市场后缀,要接着查其他债券命令,先用该行的 `securityName` 走 `reference securities-search` 换回带后缀的代码。其余债券命令一次返回全部匹配行。
689
+ > **`bond announcement` 需要手动翻页**:它是本系列唯一分页的接口,且响应**不返回 `total`**,因此不走 CLI 的自动翻页——`--page-no` 从 1 开始逐页递增,翻过末页返回空数组(退出码 0)即停;条件下一条都没有时第 1 页就返回 `130001`(退出码 1)。按日期区间查询时,部分行的 `securityCode` 为空(不对应已上市证券的公告等),这类行无法接着查其他债券命令。其余债券命令一次返回全部匹配行。
690
690
 
691
691
  > **`bond issuer-info` 的行业有两套**:`swIndustry` 是申万「一级/二级」(如 `食品饮料/白酒Ⅱ`),`nationalIndustry` 是国民经济行业分类。评级列 `latestIssuerRating` 混合了境内与境外口径,做信用比较前一并取 `ratingAgency` 判断。
692
692
 
@@ -775,6 +775,8 @@ gangtise vault drive-move-file --file-id 49412 --file-id 43319 --target-folder-i
775
775
  gangtise vault drive-move-folder --folder-id 103 --target-parent-id root
776
776
  # 跨空间复制文件:个人云盘的文件复制到租户云盘某文件夹(root = 租户云盘根目录)
777
777
  gangtise vault drive-copy --file-id 49412 --file-id 43319 --target-folder-id 201
778
+ # 跨空间复制整个文件夹(连同子文件夹与文件)到租户云盘根目录
779
+ gangtise vault drive-copy --folder-id 103 --target-parent-id root
778
780
  # 删除(不可恢复,需 --yes;删文件夹会连同其中全部子文件夹与文件一起删除)
779
781
  gangtise vault drive-delete-file --file-id 49412 --yes
780
782
  gangtise vault drive-delete-folder --folder-id 103 --yes
@@ -1,6 +1,7 @@
1
1
  import { Command, Option } from "commander";
2
2
  import { collectList, collectNames } from "../core/args.js";
3
3
  import { uploadDriveFile } from "../core/driveUpload.js";
4
+ import { ValidationError } from "../core/errors.js";
4
5
  import { flagFailedItems } from "../core/normalize.js";
5
6
  import { emit, addDownloadCommand, assertConfirmed, field, value, required, list, numberList, format, output, from, size, startTime, endTime, query, RESEARCH_AREA_CITIC_OR_DIRECTION } from "./shared.js";
6
7
  export const vault = new Command("vault").description("Vault APIs");
@@ -71,15 +72,32 @@ query(vault, "drive-move-folder", {
71
72
  format("json"), output(),
72
73
  ],
73
74
  });
74
- vault.command("drive-copy").description("Copy files to the OTHER space: my drive <-> tenant drive (free; same-space copies are rejected)")
75
- .requiredOption("--file-id <id>", "Source file ID (repeat or comma-separate)", collectList)
76
- .requiredOption("--target-folder-id <id>", "Destination folder ID in the other space, or 'root' for that space's root")
75
+ vault.command("drive-copy").description("Copy files, or one folder with everything inside, to the OTHER space: my drive <-> tenant drive (free; same-space copies are rejected)")
76
+ .option("--file-id <id>", "Source file ID (repeat or comma-separate); use with --target-folder-id", collectList, [])
77
+ .option("--target-folder-id <id>", "Destination folder ID in the other space, or 'root' for that space's root")
78
+ .option("--folder-id <id>", "Source folder ID; use with --target-parent-id")
79
+ .option("--target-parent-id <id>", "Destination parent folder ID in the other space, or 'root' for that space's root")
77
80
  .option("--format <format>", "Output format", "json").option("--output <path>")
78
- .action((options) => emit(options, async (client) => {
79
- const data = await client.call("vault.drive.copy", { copyType: "file", fileIdList: options.fileId, targetFolderId: options.targetFolderId });
80
- flagFailedItems(data, "vault drive-copy");
81
- return data;
82
- }));
81
+ .action((options) => {
82
+ const byFile = options.fileId.length > 0 || options.targetFolderId !== undefined;
83
+ const byFolder = options.folderId !== undefined || options.targetParentId !== undefined;
84
+ if (byFile && byFolder)
85
+ throw new ValidationError("pass either --file-id + --target-folder-id (copy files) or --folder-id + --target-parent-id (copy a folder), not both");
86
+ if (byFile && (!options.fileId.length || options.targetFolderId === undefined))
87
+ throw new ValidationError("copying files needs both --file-id and --target-folder-id");
88
+ if (byFolder && (options.folderId === undefined || options.targetParentId === undefined))
89
+ throw new ValidationError("copying a folder needs both --folder-id and --target-parent-id");
90
+ if (!byFile && !byFolder)
91
+ throw new ValidationError("pass --file-id + --target-folder-id (copy files) or --folder-id + --target-parent-id (copy a folder)");
92
+ const body = byFile
93
+ ? { copyType: "file", fileIdList: options.fileId, targetFolderId: options.targetFolderId }
94
+ : { copyType: "folder", folderId: options.folderId, targetParentId: options.targetParentId };
95
+ return emit(options, async (client) => {
96
+ const data = await client.call("vault.drive.copy", body);
97
+ flagFailedItems(data, "vault drive-copy");
98
+ return data;
99
+ });
100
+ });
83
101
  vault.command("drive-delete-file").description("Delete drive files — irreversible (free)")
84
102
  .requiredOption("--file-id <id>", "File ID to delete (repeat or comma-separate)", collectList)
85
103
  .option("--yes", "Required: confirm the deletion")
@@ -661,12 +661,10 @@ export class GangtiseClient {
661
661
  throw new ApiError('Download failed', undefined, response.statusCode, text, retryAfterMs);
662
662
  }
663
663
  const contentDisposition = response.headers['content-disposition'];
664
- const filenameMatch = Array.isArray(contentDisposition)
665
- ? contentDisposition[0]?.match(/filename\*=UTF-8''([^;]+)|filename="?([^";]+)"?/i)
666
- : contentDisposition?.match(/filename\*=UTF-8''([^;]+)|filename="?([^";]+)"?/i);
664
+ const disposition = Array.isArray(contentDisposition) ? contentDisposition[0] : contentDisposition;
665
+ const raw = disposition?.match(/filename\*=UTF-8''([^;]+)/i)?.[1] ?? disposition?.match(/filename="?([^";]+)"?/i)?.[1];
667
666
  let filename;
668
- if (filenameMatch) {
669
- const raw = filenameMatch[1] || filenameMatch[2];
667
+ if (raw) {
670
668
  try {
671
669
  filename = decodeURIComponent(raw);
672
670
  }
@@ -1,9 +1,11 @@
1
+ import { isIPv4 } from "node:net";
1
2
  import os from "node:os";
2
3
  import path from "node:path";
3
4
  export const DEFAULT_BASE_URL = "https://openapi.gangtise.com";
4
5
  export const DEFAULT_TIMEOUT_MS = 30_000;
5
6
  export const DEFAULT_TOKEN_CACHE_PATH = path.join(os.homedir(), ".config", "gangtise", "token.json");
6
7
  let timeoutWarned = false;
8
+ let plainHttpWarned = false;
7
9
  export function loadConfig() {
8
10
  const rawTimeout = process.env.GANGTISE_TIMEOUT_MS?.trim();
9
11
  const timeoutMs = resolveTimeoutEnv(rawTimeout);
@@ -11,8 +13,10 @@ export function loadConfig() {
11
13
  timeoutWarned = true;
12
14
  process.stderr.write(`[gangtise] warning: GANGTISE_TIMEOUT_MS=${rawTimeout} is not in effect, using ${timeoutMs} ms: expected whole milliseconds from ${MIN_TIMEOUT_MS} to ${MAX_TIMEOUT_MS}\n`);
13
15
  }
16
+ const baseUrl = envValue("GANGTISE_BASE_URL") ?? DEFAULT_BASE_URL;
17
+ warnIfPlainHttp(baseUrl);
14
18
  return {
15
- baseUrl: envValue("GANGTISE_BASE_URL") ?? DEFAULT_BASE_URL,
19
+ baseUrl,
16
20
  timeoutMs,
17
21
  accessKey: envValue("GANGTISE_ACCESS_KEY"),
18
22
  secretKey: envValue("GANGTISE_SECRET_KEY"),
@@ -20,6 +24,24 @@ export function loadConfig() {
20
24
  tokenCachePath: envValue("GANGTISE_TOKEN_CACHE_PATH") ?? DEFAULT_TOKEN_CACHE_PATH,
21
25
  };
22
26
  }
27
+ function warnIfPlainHttp(baseUrl) {
28
+ if (plainHttpWarned)
29
+ return;
30
+ let url;
31
+ try {
32
+ url = new URL(baseUrl);
33
+ }
34
+ catch {
35
+ return;
36
+ }
37
+ if (url.protocol !== "http:")
38
+ return;
39
+ const host = url.hostname.replace(/^\[|\]$/g, "");
40
+ if (host === "localhost" || host === "::1" || (isIPv4(host) && host.startsWith("127.")))
41
+ return;
42
+ plainHttpWarned = true;
43
+ process.stderr.write(`[gangtise] warning: GANGTISE_BASE_URL uses plain http (${url.host}): the access key, secret and token are sent unencrypted. Use https unless this is a trusted local proxy.\n`);
44
+ }
23
45
  function envValue(name) {
24
46
  const value = process.env[name]?.trim();
25
47
  return value ? value : undefined;
@@ -1014,7 +1014,7 @@ const ENDPOINT_DEFS = {
1014
1014
  path: "/application/open-vault/drive/copy",
1015
1015
  kind: "json",
1016
1016
  itemFailures: true,
1017
- description: "Copy drive files to the OTHER space (my drive <-> tenant drive)",
1017
+ description: "Copy drive files or a folder to the OTHER space (my drive <-> tenant drive)",
1018
1018
  retry: "no-replay",
1019
1019
  },
1020
1020
  "vault.record.list": {
@@ -299,9 +299,6 @@ export function csvEscape(value) {
299
299
  return out;
300
300
  }
301
301
  export const LINES_PER_WRITE = 1000;
302
- export function writeLines(stream, lines) {
303
- return lines.length === 0 ? Promise.resolve() : writeLine(stream, lines.join("\n"));
304
- }
305
302
  export function writeLine(stream, line) {
306
303
  return new Promise((resolve, reject) => {
307
304
  const ok = stream.write(line + "\n", (err) => err ? reject(err) : undefined);
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: gangtise-openapi
3
- version: "0.44.0"
3
+ version: "0.45.0"
4
4
  description: |-
5
5
  通过 gangtise CLI 直接调用 Gangtise OpenAPI,拉取投研原始数据、批量导出、下载文件、调用 AI 能力。
6
6
 
@@ -179,7 +179,7 @@ vault.stock-pool.create
179
179
  | 管理层讨论 / A·港·美股公告 / `alternative edb-*` 行业指标 | 前溯 **3 年** |
180
180
  | `insight pamirs-summary` 帕米尔纪要 | **不限**(但需单独购买专家纪要库) |
181
181
 
182
- ⚠️ **实际窗口按账号配**,换接口绕不过去(`indicator` 与 `quote day-kline` 同界)。整段在界外返回 `110003`(不是空结果),把日期移进范围或联系客户经理。🔴 **区间跨过下界时各接口不同**:`quote` 日 K / 分钟 K / 资金流向与 `fundamental valuation-analysis` 从下界起返回、**不报错**(首行明显晚于起始日时 CLI 在 stderr 提示);`indicator`、`bond` 与 `fund` 整批报 `110003`。**例外**:`quote minute-kline` 窗口短得多,整段在窗外返回空结果、不报错(CLI 在 stderr 提示);`ai hot-topic` 超出账号可查范围时也返回空结果、不报错。
182
+ ⚠️ **实际窗口按账号配**,换接口绕不过去(`indicator` 与 `quote day-kline` 同界)。整段在界外返回 `110003`(不是空结果),把日期移进范围或联系客户经理。🔴 **区间跨过下界时各接口不同**:`quote` 日 K / 分钟 K / 资金流向与 `fundamental valuation-analysis` 从下界起返回、**不报错**(首行明显晚于起始日时 CLI 在 stderr 提示);`indicator`、`bond` 与 `fund` 整批报 `110003`;`bond daily-quote` / `bond valuation` 的数据还可能比账号窗口短——区间早于数据起点时返回 `130001`,跨过数据起点时从有数据的那天起返回、不报错,核对首行日期。**例外**:`quote minute-kline` 窗口短得多且随日期滚动,整段在窗外返回空结果、不报错(CLI 在 stderr 提示);`ai hot-topic` 超出账号可查范围时也返回空结果、不报错。
183
183
 
184
184
  ### 下载规则(`--file-type` / `--content-type`)
185
185
 
@@ -255,7 +255,7 @@ vault.stock-pool.create
255
255
  | 评级调整 / 评级变动历史 | `bond rating-change`(债项评级,最多 10 只)、`bond issuer-rating-change`(主体评级,`--security` 或 `--issuer` 二选一) |
256
256
  | 利率债发行计划 / 国债发行安排 | `bond issuance-plan`(**只按日期区间查,不收债券码**) |
257
257
  | 含权债行权 / 回售 / 赎回提示 | `bond exercise-notice` |
258
- | 基金资料 / 基金分类 / 管理人 / 成立日 / 业绩基准 / 跟踪指数 / 风险等级 | `fund basic-info`(`--security` 用 `005827.OF` / `159967.SZ` 这类带后缀代码;`--field` 写错**整批拒绝** `100003`) |
258
+ | 基金资料 / 基金分类 / 管理人 / 成立日 / 业绩基准 / 跟踪指数 / 风险等级 | `fund basic-info`(`--security` 用 `005827.OF` / `159967.SZ` 这类带后缀代码;只知道名称时,场内基金用 `reference securities-search --keyword <场内简称或 6 位代码> --category fund` 换代码(全称常搜不到),场外 `.OF` 搜不到、需自备;`--field` 写错**整批拒绝** `100003`) |
259
259
  | 基金净值 / 复权净值 / 区间收益 / 货币基金七日年化 | `fund nav`(算收益用 `navAdjusted`) |
260
260
  | 基金费率 / 管理费 / 申购赎回费 | `fund fee-rate`(`feeRate` 是字符串) |
261
261
  | 基金经理画像(按人名) | `fund manager-info --manager <姓名>`(精确匹配,同名全返回,用 `currentCompany` 区分) |
@@ -272,7 +272,7 @@ vault.stock-pool.create
272
272
  | 联网搜索 / 查公开信息 / 政策原文 / 传闻核实 | `tool web-search`(1 积分/次;`--site` 定向站点、`--min-tier` 收信源、`--include-content` 取正文〔此时 `--size` ≤5〕) |
273
273
  | 云盘文件 | `vault drive-list / drive-download` |
274
274
  | 云盘目录 / 文件夹里有什么 | `vault drive-folder-list`(`--space-type 1` 我的云盘〔默认〕/ `2` 租户云盘,`--parent-id` 不传即根目录) |
275
- | 云盘上传 / 新建文件夹 / 重命名 / 移动 / 跨空间复制文件 / 删除(会改动账号数据) | `vault drive-upload / drive-create-folder / drive-rename / drive-move-file / drive-move-folder / drive-copy / drive-delete-file / drive-delete-folder`(删除须加 `--yes`;详见 `references/commands/vault.md`) |
275
+ | 云盘上传 / 新建文件夹 / 重命名 / 移动 / 跨空间复制文件或文件夹 / 删除(会改动账号数据) | `vault drive-upload / drive-create-folder / drive-rename / drive-move-file / drive-move-folder / drive-copy / drive-delete-file / drive-delete-folder`(删除须加 `--yes`;详见 `references/commands/vault.md`) |
276
276
  | 录音速记 | `vault record-list / record-download` |
277
277
  | 我的会议(业绩会/策略会/路演内部记录) | `vault my-conference-list / my-conference-download` |
278
278
  | 微信群消息 | `vault wechat-message-list`(先 `vault wechat-chatroom-list` 拿群 ID) |
@@ -18,6 +18,8 @@
18
18
 
19
19
  ⚠️ **`--start-date` 早于可回溯下界时整批返回 `110003`「超出时间范围限制」**(这三个命令都是)——即使 `--end-date` 在窗口内,也不会只返回窗口内那一段。把 `--start-date` 移进窗口再查;实际下界随账号服务等级而定,以返回为准。
20
20
 
21
+ ⚠️ **`bond daily-quote` / `bond valuation` 的数据可能比账号窗口短**:区间在窗口内、但早于数据起点时整段返回 `130001`「数据未找到」;跨过数据起点时从有数据的那天起返回、不报错。按年份取长序列时核对返回的首行日期。
22
+
21
23
  ## `basic-info` 债券基本资料
22
24
 
23
25
  ```bash
@@ -113,7 +115,7 @@ gangtise bond announcement (--security <code>... | --start-date <d> --end-date <
113
115
  - 翻过末页返回**空数组**(`--format json` 输出 `[]`,退出码 0)——到这一页就停
114
116
  - 条件下**一条公告都没有**时,任何页码都返回 `404` / `130001`(退出码 1)——第 1 页收到它就是没有数据,不用再翻
115
117
 
116
- ⚠️ **按日期区间查询时,返回的 `securityCode` 不带市场后缀**(如 `012682337`);按 `--security` 查询时带后缀。要把结果接着传给其他 `bond` 命令(它们只收带后缀的代码,否则 `120001`),用该行的 `securityName` 走 `reference securities-search --keyword <简称>` 换回带后缀的 `gtsCode`,并核对它去掉后缀后与原代码一致。**别拿不带后缀的代码本身去搜**——检索按相似度返回,可能给出相邻的其他代码;部分资产支持证券按简称也检索不到。
118
+ 按日期区间查询时,部分行的 `securityCode` 为空(如不对应已上市证券的公告、部分新发行债券的发行文件),这类行无法接着传给其他 `bond` 命令;有代码的行都带市场后缀,可以直接传。
117
119
 
118
120
  其余债券命令一次返回全部匹配行。
119
121
 
@@ -5,11 +5,12 @@
5
5
  `--security` 收**基金交易代码**,后缀大写:场外 `005827.OF`;场内 `159967.SZ` / `510300.SH`。可重复,也接受逗号分隔;重复代码服务端自动去重。
6
6
 
7
7
  - 🔴 **代码不存在、不带后缀(`005827`)、后缀小写(`.of`)、传成股票代码,都返回空结果、不报错**——拿到空先核对代码与后缀
8
+ - **只知道基金名称时**:场内基金(ETF、LOF 的场内份额)用 `reference securities-search --keyword <场内简称或 6 位代码> --category fund` 换代码(基金全称常搜不到,如「华泰柏瑞沪深300ETF」要搜「沪深300ETF」或 `510300`);场外 `.OF` 代码搜不到,需要自备
8
9
  - LOF / ETF 的场内代码(`161005.SZ`)与场外代码(`161005.OF`)都能查,返回的 `fundCode` 与 `fundName` 跟随传入的代码(场内简称 / 场外简称不同);同一只基金别两种代码混着传,会重复
9
10
  - A / C 等份额各有代码,要合并到同一只基金用 `basic-info` 的 `mainFundCode`
10
11
  - 多只基金的结果**按 `fundCode` 字段对应**,别按请求顺序对位
11
12
 
12
- ⚠️ **超时 / 5xx 不自动重放**(避免重复扣费)。偶发 `999999` 系统错误,同参数重跑即可。
13
+ ⚠️ **超时 / 5xx 不自动重放**(避免重复扣费),偶发失败自行重跑。
13
14
 
14
15
  ---
15
16
 
@@ -26,6 +26,7 @@ gangtise vault drive-rename --type file|folder --id <id> --name <name>
26
26
  gangtise vault drive-move-file --file-id <id>... --target-folder-id <id|root>
27
27
  gangtise vault drive-move-folder --folder-id <id> --target-parent-id <id|root>
28
28
  gangtise vault drive-copy --file-id <id>... --target-folder-id <id|root>
29
+ gangtise vault drive-copy --folder-id <id> --target-parent-id <id|root>
29
30
  gangtise vault drive-delete-file --file-id <id>... --yes
30
31
  gangtise vault drive-delete-folder --folder-id <id> --yes
31
32
  ```
@@ -36,7 +37,7 @@ gangtise vault drive-delete-folder --folder-id <id> --yes
36
37
  - `drive-upload`:单个文件 ≤100MB(CLI 本地先拦);试用账号每天累计上传 ≤500MB(超出 `230008`)。`--title` 不传用本地文件名
37
38
  - 名称(`--name` / `--title`)≤200 个字符,按 UTF-16 计——中文算 1、emoji 算 2;超出 `230004`
38
39
  - **移动只能在同一空间内**:`drive-move-file` 里跨空间的文件进 `failList`(「空间不一致」);`drive-move-folder` 移到其他空间、自身或其子文件夹报 `230005`
39
- - **跨空间用 `drive-copy`**:把文件在「我的云盘 ↔ 租户云盘」之间复制(可批量),源保留不动;`--target-folder-id` 必须在另一空间,`root` 即另一空间的根目录,同空间复制报 `100003`。返回 `successList[]{fileId, newFileId}`。**目前只支持复制文件**,整个文件夹的复制暂未提供
40
+ - **跨空间用 `drive-copy`**:在「我的云盘 ↔ 租户云盘」之间复制,源保留不动,同空间复制报 `100003`。两种用法二选一:复制文件用 `--file-id`(可批量)+ `--target-folder-id`,返回 `successList[]{fileId, newFileId}`;复制整个文件夹用 `--folder-id` + `--target-parent-id`,连同其中的子文件夹与文件一起复制,返回 `{folderId, newFolderId}`。目标 ID 必须在另一空间,`root` 即另一空间的根目录
40
41
  - 🔴 **删除不可恢复,必须 `--yes`**:`drive-delete-file` 可批量;`drive-delete-folder` **连同其中全部子文件夹与文件一起删除**,删前先 `drive-folder-list --parent-id <id>` 看清里面有什么。拒绝后**不要自行补 `--yes` 重跑**,把要删的名称列给用户确认
41
42
  - **批量命令的部分失败**:`drive-delete-file` / `drive-move-file` / `drive-copy` 对单条失败仍返回成功,明细在 `failList`(`fileId` + `failReason`,如「文件不存在」)。CLI 把失败的 ID 写到 stderr、结果标 `partial` 并**退出 3**
42
43
 
@@ -86,7 +86,7 @@ CLI 自动处理 envelope:`{code, msg, data}` 信封会按 `code === "000000"`
86
86
  | vault drive-create-folder | `{folderId, parentId, folderName, spaceType, createTime}` | `folderId` |
87
87
  | vault drive-rename | `{id, name}` | — |
88
88
  | vault drive-move-folder / drive-delete-folder | `{folderId, parentId}` / `{folderId}` | — |
89
- | vault drive-copy | `{successList, failList}` | `successList[]{fileId, newFileId}`(`newFileId` 是另一空间里副本的 ID);`failList[]{fileId, failReason}`,非空时 `partial` + 退出码 3 |
89
+ | vault drive-copy | 复制文件:`{successList, failList}`;复制文件夹:`{folderId, newFolderId}` | `successList[]{fileId, newFileId}`(`newFileId` 是另一空间里副本的 ID);`failList[]{fileId, failReason}`,非空时 `partial` + 退出码 3。复制文件夹时 `newFolderId` 是另一空间里副本文件夹的 ID |
90
90
  | vault drive-move-file / drive-delete-file | `{successList, failList}` | `successList[]` 为文件 ID;`failList[]{fileId, failReason}`,非空时 `partial` + 退出码 3 |
91
91
  | vault record-list | `{list, total}` | `list[].recordId` / `list[].title` / `list[].category` / `list[].createTime` / `list[].recordDuration` |
92
92
  | vault record-download | 文件路径(stdout) | — |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gangtise-openapi-cli",
3
- "version": "0.44.0",
3
+ "version": "0.45.0",
4
4
  "description": "CLI for Gangtise OpenAPI",
5
5
  "license": "MIT",
6
6
  "repository": {