@hithink-tech/hithink-finance-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/LICENSE +21 -0
  3. package/README.md +161 -0
  4. package/SECURITY.md +3 -0
  5. package/dist/application/config.d.ts +44 -0
  6. package/dist/application/config.js +111 -0
  7. package/dist/application/ports/auth-provider.d.ts +23 -0
  8. package/dist/application/ports/auth-provider.js +2 -0
  9. package/dist/application/source-policy.d.ts +13 -0
  10. package/dist/application/source-policy.js +31 -0
  11. package/dist/application/use-cases/data-clean.d.ts +2 -0
  12. package/dist/application/use-cases/data-clean.js +18 -0
  13. package/dist/application/use-cases/data-init.d.ts +4 -0
  14. package/dist/application/use-cases/data-init.js +9 -0
  15. package/dist/application/use-cases/data-remove.d.ts +2 -0
  16. package/dist/application/use-cases/data-remove.js +27 -0
  17. package/dist/application/use-cases/data-repair.d.ts +5 -0
  18. package/dist/application/use-cases/data-repair.js +5 -0
  19. package/dist/application/use-cases/data-sync.d.ts +25 -0
  20. package/dist/application/use-cases/data-sync.js +55 -0
  21. package/dist/application/use-cases/local-query.d.ts +4 -0
  22. package/dist/application/use-cases/local-query.js +88 -0
  23. package/dist/application/use-cases/market-history.d.ts +8 -0
  24. package/dist/application/use-cases/market-history.js +16 -0
  25. package/dist/application/use-cases/market-panel.d.ts +3 -0
  26. package/dist/application/use-cases/market-panel.js +5 -0
  27. package/dist/application/use-cases/remote-query.d.ts +4 -0
  28. package/dist/application/use-cases/remote-query.js +66 -0
  29. package/dist/cli/context.d.ts +17 -0
  30. package/dist/cli/context.js +52 -0
  31. package/dist/cli/i18n.d.ts +23 -0
  32. package/dist/cli/i18n.js +150 -0
  33. package/dist/cli/main.d.ts +3 -0
  34. package/dist/cli/main.js +80 -0
  35. package/dist/cli/program.d.ts +20 -0
  36. package/dist/cli/program.js +111 -0
  37. package/dist/commands/auth/index.d.ts +10 -0
  38. package/dist/commands/auth/index.js +131 -0
  39. package/dist/commands/config/index.d.ts +13 -0
  40. package/dist/commands/config/index.js +26 -0
  41. package/dist/commands/data/index.d.ts +10 -0
  42. package/dist/commands/data/index.js +185 -0
  43. package/dist/commands/db/index.d.ts +4 -0
  44. package/dist/commands/db/index.js +72 -0
  45. package/dist/commands/financials/index.d.ts +5 -0
  46. package/dist/commands/financials/index.js +6 -0
  47. package/dist/commands/index/index.d.ts +5 -0
  48. package/dist/commands/index/index.js +6 -0
  49. package/dist/commands/market/index.d.ts +5 -0
  50. package/dist/commands/market/index.js +6 -0
  51. package/dist/commands/market/local.d.ts +4 -0
  52. package/dist/commands/market/local.js +97 -0
  53. package/dist/commands/remote.d.ts +11 -0
  54. package/dist/commands/remote.js +195 -0
  55. package/dist/commands/skills/index.d.ts +4 -0
  56. package/dist/commands/skills/index.js +43 -0
  57. package/dist/commands/special/index.d.ts +5 -0
  58. package/dist/commands/special/index.js +6 -0
  59. package/dist/commands/symbol/index.d.ts +5 -0
  60. package/dist/commands/symbol/index.js +6 -0
  61. package/dist/commands/system/capabilities.d.ts +4 -0
  62. package/dist/commands/system/capabilities.js +24 -0
  63. package/dist/commands/system/doctor.d.ts +4 -0
  64. package/dist/commands/system/doctor.js +15 -0
  65. package/dist/commands/system/schema.d.ts +4 -0
  66. package/dist/commands/system/schema.js +47 -0
  67. package/dist/commands/system/uninstall.d.ts +11 -0
  68. package/dist/commands/system/uninstall.js +68 -0
  69. package/dist/commands/system/update.d.ts +11 -0
  70. package/dist/commands/system/update.js +72 -0
  71. package/dist/contracts/envelope.d.ts +37 -0
  72. package/dist/contracts/envelope.js +36 -0
  73. package/dist/contracts/errors.d.ts +23 -0
  74. package/dist/contracts/errors.js +33 -0
  75. package/dist/contracts/local-capabilities.d.ts +13 -0
  76. package/dist/contracts/local-capabilities.js +37 -0
  77. package/dist/contracts/registry.d.ts +9 -0
  78. package/dist/contracts/registry.js +4 -0
  79. package/dist/contracts/remote-capabilities.d.ts +24 -0
  80. package/dist/contracts/remote-capabilities.js +667 -0
  81. package/dist/domains/financials/types.d.ts +6 -0
  82. package/dist/domains/financials/types.js +2 -0
  83. package/dist/domains/index/types.d.ts +6 -0
  84. package/dist/domains/index/types.js +2 -0
  85. package/dist/domains/market/types.d.ts +6 -0
  86. package/dist/domains/market/types.js +2 -0
  87. package/dist/domains/special/types.d.ts +5 -0
  88. package/dist/domains/special/types.js +2 -0
  89. package/dist/domains/symbol/types.d.ts +6 -0
  90. package/dist/domains/symbol/types.js +2 -0
  91. package/dist/infrastructure/credentials/api-key-provider.d.ts +14 -0
  92. package/dist/infrastructure/credentials/api-key-provider.js +102 -0
  93. package/dist/infrastructure/credentials/keyring.d.ts +15 -0
  94. package/dist/infrastructure/credentials/keyring.js +21 -0
  95. package/dist/infrastructure/credentials/redact.d.ts +3 -0
  96. package/dist/infrastructure/credentials/redact.js +26 -0
  97. package/dist/infrastructure/duckdb/connection.d.ts +8 -0
  98. package/dist/infrastructure/duckdb/connection.js +18 -0
  99. package/dist/infrastructure/duckdb/dump-client.d.ts +20 -0
  100. package/dist/infrastructure/duckdb/dump-client.js +66 -0
  101. package/dist/infrastructure/duckdb/factors.d.ts +3 -0
  102. package/dist/infrastructure/duckdb/factors.js +83 -0
  103. package/dist/infrastructure/duckdb/importer.d.ts +11 -0
  104. package/dist/infrastructure/duckdb/importer.js +105 -0
  105. package/dist/infrastructure/duckdb/migrations.d.ts +17 -0
  106. package/dist/infrastructure/duckdb/migrations.js +92 -0
  107. package/dist/infrastructure/duckdb/quality.d.ts +12 -0
  108. package/dist/infrastructure/duckdb/quality.js +56 -0
  109. package/dist/infrastructure/duckdb/schema.d.ts +4 -0
  110. package/dist/infrastructure/duckdb/schema.js +14 -0
  111. package/dist/infrastructure/filesystem/atomic-file.d.ts +2 -0
  112. package/dist/infrastructure/filesystem/atomic-file.js +38 -0
  113. package/dist/infrastructure/filesystem/platform-paths.d.ts +15 -0
  114. package/dist/infrastructure/filesystem/platform-paths.js +42 -0
  115. package/dist/infrastructure/filesystem/process-lock.d.ts +6 -0
  116. package/dist/infrastructure/filesystem/process-lock.js +56 -0
  117. package/dist/infrastructure/filesystem/stdin.d.ts +5 -0
  118. package/dist/infrastructure/filesystem/stdin.js +9 -0
  119. package/dist/infrastructure/fuyao/client.d.ts +31 -0
  120. package/dist/infrastructure/fuyao/client.js +145 -0
  121. package/dist/infrastructure/fuyao/envelope.d.ts +9 -0
  122. package/dist/infrastructure/fuyao/envelope.js +8 -0
  123. package/dist/infrastructure/fuyao/pagination.d.ts +16 -0
  124. package/dist/infrastructure/fuyao/pagination.js +44 -0
  125. package/dist/infrastructure/fuyao/retry.d.ts +5 -0
  126. package/dist/infrastructure/fuyao/retry.js +18 -0
  127. package/dist/infrastructure/fuyao/windowing.d.ts +8 -0
  128. package/dist/infrastructure/fuyao/windowing.js +25 -0
  129. package/dist/infrastructure/skills/drift.d.ts +3 -0
  130. package/dist/infrastructure/skills/drift.js +8 -0
  131. package/dist/infrastructure/skills/installer.d.ts +13 -0
  132. package/dist/infrastructure/skills/installer.js +48 -0
  133. package/dist/infrastructure/skills/manifest.d.ts +11 -0
  134. package/dist/infrastructure/skills/manifest.js +62 -0
  135. package/dist/infrastructure/updater/cache.d.ts +15 -0
  136. package/dist/infrastructure/updater/cache.js +76 -0
  137. package/dist/infrastructure/updater/check.d.ts +13 -0
  138. package/dist/infrastructure/updater/check.js +51 -0
  139. package/dist/infrastructure/updater/install.d.ts +4 -0
  140. package/dist/infrastructure/updater/install.js +39 -0
  141. package/dist/output/json.d.ts +3 -0
  142. package/dist/output/json.js +16 -0
  143. package/dist/output/renderer.d.ts +4 -0
  144. package/dist/output/renderer.js +47 -0
  145. package/dist/output/table.d.ts +2 -0
  146. package/dist/output/table.js +31 -0
  147. package/migrations/001-initial.sql +95 -0
  148. package/migrations/manifest.json +12 -0
  149. package/package.json +66 -0
  150. package/schemas/capabilities.json +290 -0
  151. package/schemas/command-envelope.schema.json +12 -0
  152. package/scripts/postinstall.mjs +27 -0
  153. package/scripts/update-check.mjs +23 -0
  154. package/skills/hithink-finance-data/SKILL.md +74 -0
  155. package/skills/hithink-finance-data/references/data-clean.md +33 -0
  156. package/skills/hithink-finance-data/references/data-init.md +35 -0
  157. package/skills/hithink-finance-data/references/data-migrate.md +33 -0
  158. package/skills/hithink-finance-data/references/data-remove.md +33 -0
  159. package/skills/hithink-finance-data/references/data-repair.md +33 -0
  160. package/skills/hithink-finance-data/references/data-status.md +33 -0
  161. package/skills/hithink-finance-data/references/data-sync.md +34 -0
  162. package/skills/hithink-finance-data/references/data-validate.md +33 -0
  163. package/skills/hithink-finance-data/references/db-describe.md +33 -0
  164. package/skills/hithink-finance-data/references/db-export.md +33 -0
  165. package/skills/hithink-finance-data/references/db-query.md +33 -0
  166. package/skills/hithink-finance-financials/SKILL.md +59 -0
  167. package/skills/hithink-finance-financials/references/financials-balance-sheet.md +40 -0
  168. package/skills/hithink-finance-financials/references/financials-cash-flow.md +40 -0
  169. package/skills/hithink-finance-financials/references/financials-income.md +40 -0
  170. package/skills/hithink-finance-financials/references/financials-indicators.md +37 -0
  171. package/skills/hithink-finance-index/SKILL.md +59 -0
  172. package/skills/hithink-finance-index/references/index-catalog.md +36 -0
  173. package/skills/hithink-finance-index/references/index-constituents.md +36 -0
  174. package/skills/hithink-finance-index/references/index-history.md +38 -0
  175. package/skills/hithink-finance-index/references/index-snapshot.md +37 -0
  176. package/skills/hithink-finance-market/SKILL.md +63 -0
  177. package/skills/hithink-finance-market/references/market-adjustment-factors.md +33 -0
  178. package/skills/hithink-finance-market/references/market-calendar.md +35 -0
  179. package/skills/hithink-finance-market/references/market-corporate-actions.md +38 -0
  180. package/skills/hithink-finance-market/references/market-history.md +39 -0
  181. package/skills/hithink-finance-market/references/market-panel.md +33 -0
  182. package/skills/hithink-finance-market/references/market-snapshot.md +39 -0
  183. package/skills/hithink-finance-research/SKILL.md +58 -0
  184. package/skills/hithink-finance-research/references/research-workflow.md +34 -0
  185. package/skills/hithink-finance-shared/SKILL.md +55 -0
  186. package/skills/hithink-finance-shared/references/auth-and-config.md +31 -0
  187. package/skills/hithink-finance-shared/references/global-rules.md +21 -0
  188. package/skills/hithink-finance-shared/references/lifecycle.md +23 -0
  189. package/skills/hithink-finance-shared/references/skills-management.md +22 -0
  190. package/skills/hithink-finance-special-data/SKILL.md +68 -0
  191. package/skills/hithink-finance-special-data/references/special-anomaly-list.md +36 -0
  192. package/skills/hithink-finance-special-data/references/special-anomaly-stock.md +37 -0
  193. package/skills/hithink-finance-special-data/references/special-dragon-tiger.md +37 -0
  194. package/skills/hithink-finance-special-data/references/special-hot-stock-history.md +36 -0
  195. package/skills/hithink-finance-special-data/references/special-hot-stock-trend.md +38 -0
  196. package/skills/hithink-finance-special-data/references/special-hot-stock.md +36 -0
  197. package/skills/hithink-finance-special-data/references/special-limit-up-ladder.md +35 -0
  198. package/skills/hithink-finance-special-data/references/special-limit-up-pool.md +40 -0
  199. package/skills/hithink-finance-special-data/references/special-skyrocket.md +36 -0
  200. package/skills/hithink-finance-symbol/SKILL.md +56 -0
  201. package/skills/hithink-finance-symbol/references/symbol-list.md +39 -0
  202. package/skills/hithink-finance-symbol/references/symbol-search.md +39 -0
  203. package/skills/manifest.json +55 -0
@@ -0,0 +1,11 @@
1
+ export interface ManagedSkillManifest {
2
+ protocolVersion: '1';
3
+ cliVersion: string;
4
+ files: Record<string, string>;
5
+ }
6
+ export declare function buildSkillManifest(root: string, cliVersion: string): Promise<ManagedSkillManifest>;
7
+ export declare function reconcileManagedSkills(source: string, target: string, next: ManagedSkillManifest, previous?: ManagedSkillManifest): Promise<{
8
+ backups: string[];
9
+ }>;
10
+ export declare function removeManagedSkills(target: string, manifest: ManagedSkillManifest): Promise<void>;
11
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1,62 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { copyFile, mkdir, readdir, readFile, rm, stat } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ async function files(root, current = root) {
5
+ const output = [];
6
+ for (const entry of await readdir(current, { withFileTypes: true })) {
7
+ const absolute = path.join(current, entry.name);
8
+ if (entry.isDirectory())
9
+ output.push(...(await files(root, absolute)));
10
+ else if (entry.isFile())
11
+ output.push(path.relative(root, absolute).replaceAll(path.sep, '/'));
12
+ }
13
+ return output.sort();
14
+ }
15
+ async function hash(file) {
16
+ return createHash('sha256')
17
+ .update(await readFile(file))
18
+ .digest('hex');
19
+ }
20
+ export async function buildSkillManifest(root, cliVersion) {
21
+ const entries = {};
22
+ for (const relative of await files(root))
23
+ entries[relative] = await hash(path.join(root, ...relative.split('/')));
24
+ return { protocolVersion: '1', cliVersion, files: entries };
25
+ }
26
+ async function exists(file) {
27
+ try {
28
+ return (await stat(file)).isFile();
29
+ }
30
+ catch {
31
+ return false;
32
+ }
33
+ }
34
+ export async function reconcileManagedSkills(source, target, next, previous) {
35
+ const backups = [];
36
+ for (const [relative, nextHash] of Object.entries(next.files)) {
37
+ const sourceFile = path.join(source, ...relative.split('/'));
38
+ const targetFile = path.join(target, ...relative.split('/'));
39
+ await mkdir(path.dirname(targetFile), { recursive: true });
40
+ if (await exists(targetFile)) {
41
+ const currentHash = await hash(targetFile);
42
+ const oldHash = previous?.files[relative];
43
+ if (oldHash !== undefined && currentHash !== oldHash && currentHash !== nextHash) {
44
+ const backup = `${targetFile}.backup-${Date.now()}`;
45
+ await copyFile(targetFile, backup);
46
+ backups.push(backup);
47
+ }
48
+ }
49
+ await copyFile(sourceFile, targetFile);
50
+ }
51
+ if (previous !== undefined) {
52
+ for (const relative of Object.keys(previous.files))
53
+ if (!(relative in next.files))
54
+ await rm(path.join(target, ...relative.split('/')), { force: true });
55
+ }
56
+ return { backups };
57
+ }
58
+ export async function removeManagedSkills(target, manifest) {
59
+ for (const relative of Object.keys(manifest.files))
60
+ await rm(path.join(target, ...relative.split('/')), { force: true });
61
+ }
62
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1,15 @@
1
+ export interface UpdateCacheState {
2
+ checkedAt: number;
3
+ status: 'success' | 'failure';
4
+ refreshStartedAt?: number;
5
+ promptedAt?: number;
6
+ promptedCurrentVersion?: string;
7
+ promptedLatestVersion?: string;
8
+ latestVersion?: string;
9
+ }
10
+ export type UpdateCacheDecision = 'disabled' | 'fresh' | 'cooldown' | 'refreshing' | 'refresh';
11
+ export type UpdatePromptDecision = 'none' | 'prompt';
12
+ export declare function updateCacheDecision(state: UpdateCacheState | undefined, now: number, disabled?: boolean): UpdateCacheDecision;
13
+ export declare function compareSemver(leftVersion: string, rightVersion: string): number;
14
+ export declare function updatePromptDecision(state: UpdateCacheState | undefined, currentVersion: string, now: number, disabled?: boolean): UpdatePromptDecision;
15
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1,76 @@
1
+ const PROMPT_TTL_MS = 24 * 3_600_000;
2
+ export function updateCacheDecision(state, now, disabled = false) {
3
+ if (disabled)
4
+ return 'disabled';
5
+ if (state?.refreshStartedAt !== undefined && now - state.refreshStartedAt < 5 * 60_000)
6
+ return 'refreshing';
7
+ if (state === undefined)
8
+ return 'refresh';
9
+ const age = now - state.checkedAt;
10
+ if (state.status === 'success' && age < 24 * 3_600_000)
11
+ return 'fresh';
12
+ if (state.status === 'failure' && age < 6 * 3_600_000)
13
+ return 'cooldown';
14
+ return 'refresh';
15
+ }
16
+ function parseSemver(value) {
17
+ const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/u.exec(value);
18
+ if (match === null)
19
+ return undefined;
20
+ return {
21
+ major: Number(match[1]),
22
+ minor: Number(match[2]),
23
+ patch: Number(match[3]),
24
+ prerelease: match[4]?.split('.') ?? [],
25
+ };
26
+ }
27
+ function comparePrerelease(left, right) {
28
+ if (left.length === 0 && right.length === 0)
29
+ return 0;
30
+ if (left.length === 0)
31
+ return 1;
32
+ if (right.length === 0)
33
+ return -1;
34
+ const length = Math.max(left.length, right.length);
35
+ for (let index = 0; index < length; index += 1) {
36
+ const leftPart = left[index];
37
+ const rightPart = right[index];
38
+ if (leftPart === undefined)
39
+ return -1;
40
+ if (rightPart === undefined)
41
+ return 1;
42
+ if (leftPart === rightPart)
43
+ continue;
44
+ const leftNumeric = /^\d+$/u.test(leftPart);
45
+ const rightNumeric = /^\d+$/u.test(rightPart);
46
+ if (leftNumeric && rightNumeric)
47
+ return Number(leftPart) - Number(rightPart);
48
+ if (leftNumeric)
49
+ return -1;
50
+ if (rightNumeric)
51
+ return 1;
52
+ return leftPart.localeCompare(rightPart);
53
+ }
54
+ return 0;
55
+ }
56
+ export function compareSemver(leftVersion, rightVersion) {
57
+ const left = parseSemver(leftVersion);
58
+ const right = parseSemver(rightVersion);
59
+ if (left === undefined || right === undefined)
60
+ return 0;
61
+ const core = left.major - right.major || left.minor - right.minor || left.patch - right.patch;
62
+ return core === 0 ? comparePrerelease(left.prerelease, right.prerelease) : core;
63
+ }
64
+ export function updatePromptDecision(state, currentVersion, now, disabled = false) {
65
+ if (disabled || state?.status !== 'success' || state.latestVersion === undefined)
66
+ return 'none';
67
+ if (compareSemver(state.latestVersion, currentVersion) <= 0)
68
+ return 'none';
69
+ if (state.promptedAt !== undefined &&
70
+ state.promptedCurrentVersion === currentVersion &&
71
+ state.promptedLatestVersion === state.latestVersion &&
72
+ now - state.promptedAt < PROMPT_TTL_MS)
73
+ return 'none';
74
+ return 'prompt';
75
+ }
76
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1,13 @@
1
+ import type { UpdateCacheState } from './cache.js';
2
+ export declare function readUpdateCache(file: string): Promise<UpdateCacheState | undefined>;
3
+ export declare function scheduleUpdateCheck(packageRoot: string, packageName: string, cacheFile: string): void;
4
+ export interface UpdateNoticeOptions {
5
+ packageRoot: string;
6
+ packageName: string;
7
+ currentVersion: string;
8
+ cacheFile: string;
9
+ stderr: NodeJS.WriteStream;
10
+ disabled?: boolean;
11
+ }
12
+ export declare function maybeEmitCachedUpdateNotice(options: UpdateNoticeOptions): Promise<void>;
13
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1,51 @@
1
+ import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
2
+ import { spawn } from 'node:child_process';
3
+ import path from 'node:path';
4
+ import { updateCacheDecision, updatePromptDecision } from './cache.js';
5
+ export async function readUpdateCache(file) {
6
+ try {
7
+ return JSON.parse(await readFile(file, 'utf8'));
8
+ }
9
+ catch {
10
+ return undefined;
11
+ }
12
+ }
13
+ async function writeUpdateCache(file, state) {
14
+ await mkdir(path.dirname(file), { recursive: true });
15
+ const temporary = `${file}.${process.pid}.tmp`;
16
+ await writeFile(temporary, `${JSON.stringify(state)}\n`, { mode: 0o600 });
17
+ await rename(temporary, file);
18
+ }
19
+ export function scheduleUpdateCheck(packageRoot, packageName, cacheFile) {
20
+ const child = spawn(process.execPath, [path.join(packageRoot, 'scripts', 'update-check.mjs'), packageName, cacheFile], { detached: true, stdio: 'ignore', windowsHide: true, env: process.env });
21
+ child.unref();
22
+ }
23
+ export async function maybeEmitCachedUpdateNotice(options) {
24
+ try {
25
+ const cached = await readUpdateCache(options.cacheFile);
26
+ const now = Date.now();
27
+ const disabled = options.disabled === true;
28
+ const decision = updateCacheDecision(cached, now, disabled);
29
+ if (decision === 'refresh') {
30
+ scheduleUpdateCheck(options.packageRoot, options.packageName, options.cacheFile);
31
+ }
32
+ if (cached === undefined ||
33
+ cached.latestVersion === undefined ||
34
+ updatePromptDecision(cached, options.currentVersion, now, disabled) !== 'prompt')
35
+ return;
36
+ const latestVersion = cached.latestVersion;
37
+ options.stderr.write(`[update] A newer hithink-finance CLI version is available: ${latestVersion} ` +
38
+ `(current ${options.currentVersion}).\n` +
39
+ 'Run `hithink-finance update --check --format json` to inspect it; ' +
40
+ 'run `hithink-finance update --repair` to update after confirmation.\n');
41
+ await writeUpdateCache(options.cacheFile, {
42
+ ...cached,
43
+ promptedAt: now,
44
+ promptedCurrentVersion: options.currentVersion,
45
+ promptedLatestVersion: latestVersion,
46
+ });
47
+ }
48
+ catch {
49
+ }
50
+ }
51
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1,4 @@
1
+ export declare function installGlobalPackage(npmExecutable: string, packageName: string, version: string): Promise<number>;
2
+ export declare function runExecutable(executable: string, executableArgs: string[]): Promise<number>;
3
+ export declare function uninstallGlobalPackage(npmExecutable: string, packageName: string): Promise<number>;
4
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1,39 @@
1
+ import { spawn } from 'node:child_process';
2
+ export async function installGlobalPackage(npmExecutable, packageName, version) {
3
+ return new Promise((resolve, reject) => {
4
+ const npmArgs = ['install', '-g', `${packageName}@${version}`];
5
+ const isWindowsScript = process.platform === 'win32' && /\.(cmd|bat)$/iu.test(npmExecutable);
6
+ const command = isWindowsScript ? (process.env.ComSpec ?? 'cmd.exe') : npmExecutable;
7
+ const args = isWindowsScript
8
+ ?
9
+ ['/d', '/s', '/c', npmExecutable, ...npmArgs]
10
+ : npmArgs;
11
+ const child = spawn(command, args, {
12
+ stdio: 'inherit',
13
+ windowsHide: true,
14
+ env: process.env,
15
+ });
16
+ child.once('error', reject);
17
+ child.once('exit', (code) => resolve(code ?? 1));
18
+ });
19
+ }
20
+ export async function runExecutable(executable, executableArgs) {
21
+ return new Promise((resolve, reject) => {
22
+ const isWindowsScript = process.platform === 'win32' && /\.(cmd|bat)$/iu.test(executable);
23
+ const command = isWindowsScript ? (process.env.ComSpec ?? 'cmd.exe') : executable;
24
+ const args = isWindowsScript
25
+ ? ['/d', '/s', '/c', executable, ...executableArgs]
26
+ : executableArgs;
27
+ const child = spawn(command, args, {
28
+ stdio: 'inherit',
29
+ windowsHide: true,
30
+ env: process.env,
31
+ });
32
+ child.once('error', reject);
33
+ child.once('exit', (code) => resolve(code ?? 1));
34
+ });
35
+ }
36
+ export async function uninstallGlobalPackage(npmExecutable, packageName) {
37
+ return runExecutable(npmExecutable, ['uninstall', '-g', packageName]);
38
+ }
39
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1,3 @@
1
+ export declare function externalize(value: unknown): unknown;
2
+ export declare function renderJson(value: unknown): string;
3
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1,16 @@
1
+ function snakeCase(key) {
2
+ return key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
3
+ }
4
+ export function externalize(value) {
5
+ if (Array.isArray(value)) {
6
+ return value.map(externalize);
7
+ }
8
+ if (value !== null && typeof value === 'object') {
9
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [snakeCase(key), externalize(entry)]));
10
+ }
11
+ return value;
12
+ }
13
+ export function renderJson(value) {
14
+ return `${JSON.stringify(externalize(value))}\n`;
15
+ }
16
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1,4 @@
1
+ import type { CliContext } from '../cli/context.js';
2
+ import type { Envelope } from '../contracts/envelope.js';
3
+ export declare function renderResult(result: Envelope, context: CliContext): Promise<void>;
4
+ //# sourceMappingURL=renderer.d.ts.map
@@ -0,0 +1,47 @@
1
+ import { externalize, renderJson } from './json.js';
2
+ import { renderTable } from './table.js';
3
+ function resolvedFormat(context) {
4
+ if (context.format !== 'auto') {
5
+ return context.format;
6
+ }
7
+ return context.stdout.isTTY === true ? 'table' : 'json';
8
+ }
9
+ function csvEscape(value) {
10
+ if (value === null || value === undefined)
11
+ return '';
12
+ const text = typeof value === 'object' ? JSON.stringify(externalize(value)) : String(externalize(value));
13
+ return /[",\n\r]/u.test(text) ? `"${text.replaceAll('"', '""')}"` : text;
14
+ }
15
+ function renderCsv(value) {
16
+ const external = externalize(value);
17
+ const rows = Array.isArray(external) ? external : [external];
18
+ if (rows.length === 0)
19
+ return '\n';
20
+ if (rows.every((row) => row !== null && typeof row === 'object' && !Array.isArray(row))) {
21
+ const headers = [
22
+ ...new Set(rows.flatMap((row) => Object.keys(row))),
23
+ ];
24
+ return `${headers.join(',')}\n${rows
25
+ .map((row) => headers.map((header) => csvEscape(row[header])).join(','))
26
+ .join('\n')}\n`;
27
+ }
28
+ return `value\n${rows.map(csvEscape).join('\n')}\n`;
29
+ }
30
+ export async function renderResult(result, context) {
31
+ const stream = result.ok ? context.stdout : context.stderr;
32
+ const format = resolvedFormat(context);
33
+ if (format === 'json' || format === 'ndjson') {
34
+ stream.write(renderJson(result));
35
+ return;
36
+ }
37
+ if (format === 'csv' && result.ok) {
38
+ stream.write(renderCsv(result.data));
39
+ return;
40
+ }
41
+ if (!result.ok) {
42
+ stream.write(`hithink-finance v${result.meta.cliVersion} — Error (${result.error.code}): ${result.error.message}\n${result.error.hint}\n`);
43
+ return;
44
+ }
45
+ stream.write(renderTable(result.data));
46
+ }
47
+ //# sourceMappingURL=renderer.js.map
@@ -0,0 +1,2 @@
1
+ export declare function renderTable(value: unknown): string;
2
+ //# sourceMappingURL=table.d.ts.map
@@ -0,0 +1,31 @@
1
+ export function renderTable(value) {
2
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
3
+ return `${String(value)}\n`;
4
+ }
5
+ if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
6
+ return rowsToTable(['key', 'value'], Object.entries(value).map(([key, entry]) => [key, cell(entry)]));
7
+ }
8
+ if (Array.isArray(value)) {
9
+ if (value.length === 0)
10
+ return '(empty)\n';
11
+ if (value.every((entry) => entry !== null && typeof entry === 'object' && !Array.isArray(entry))) {
12
+ const records = value;
13
+ const headers = [...new Set(records.flatMap((record) => Object.keys(record)))];
14
+ return rowsToTable(headers, records.map((record) => headers.map((header) => cell(record[header]))));
15
+ }
16
+ return rowsToTable(['value'], value.map((entry) => [cell(entry)]));
17
+ }
18
+ return `${cell(value)}\n`;
19
+ }
20
+ function cell(value) {
21
+ if (value === null || value === undefined)
22
+ return '';
23
+ return typeof value === 'object' ? JSON.stringify(value) : String(value);
24
+ }
25
+ function rowsToTable(headers, rows) {
26
+ const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => row[index]?.length ?? 0)));
27
+ const renderRow = (row) => `| ${row.map((entry, index) => entry.padEnd(widths[index] ?? 0)).join(' | ')} |`;
28
+ const separator = `| ${widths.map((width) => '-'.repeat(width)).join(' | ')} |`;
29
+ return `${[renderRow(headers), separator, ...rows.map(renderRow)].join('\n')}\n`;
30
+ }
31
+ //# sourceMappingURL=table.js.map
@@ -0,0 +1,95 @@
1
+ CREATE TABLE IF NOT EXISTS _meta (
2
+ key VARCHAR PRIMARY KEY,
3
+ value VARCHAR NOT NULL
4
+ );
5
+
6
+ CREATE TABLE IF NOT EXISTS _import_batches (
7
+ batch_id VARCHAR PRIMARY KEY,
8
+ source VARCHAR NOT NULL,
9
+ started_at TIMESTAMP NOT NULL,
10
+ completed_at TIMESTAMP,
11
+ status VARCHAR NOT NULL,
12
+ row_count BIGINT,
13
+ content_hash VARCHAR,
14
+ error_code VARCHAR
15
+ );
16
+
17
+ CREATE TABLE IF NOT EXISTS raw_kline_daily (
18
+ thscode VARCHAR NOT NULL,
19
+ date DATE NOT NULL,
20
+ open DOUBLE NOT NULL,
21
+ high DOUBLE NOT NULL,
22
+ low DOUBLE NOT NULL,
23
+ close DOUBLE NOT NULL,
24
+ prev_close DOUBLE,
25
+ volume DOUBLE NOT NULL,
26
+ amount DOUBLE NOT NULL,
27
+ batch_id VARCHAR,
28
+ PRIMARY KEY (thscode, date)
29
+ );
30
+
31
+ CREATE TABLE IF NOT EXISTS raw_adjustment_events (
32
+ thscode VARCHAR NOT NULL,
33
+ ex_date DATE NOT NULL,
34
+ dividend_per_share DOUBLE NOT NULL DEFAULT 0,
35
+ per_share_bonus DOUBLE NOT NULL DEFAULT 0,
36
+ rights_ratio DOUBLE NOT NULL DEFAULT 0,
37
+ rights_price DOUBLE,
38
+ batch_id VARCHAR,
39
+ PRIMARY KEY (thscode, ex_date)
40
+ );
41
+
42
+ CREATE TABLE IF NOT EXISTS dim_symbol (
43
+ thscode VARCHAR PRIMARY KEY,
44
+ ticker VARCHAR,
45
+ name VARCHAR,
46
+ exchange VARCHAR,
47
+ asset_type VARCHAR NOT NULL DEFAULT 'a-share',
48
+ updated_at TIMESTAMP
49
+ );
50
+
51
+ CREATE TABLE IF NOT EXISTS calc_adjust_factor_daily (
52
+ thscode VARCHAR NOT NULL,
53
+ date DATE NOT NULL,
54
+ forward_factor DOUBLE NOT NULL,
55
+ backward_factor DOUBLE NOT NULL,
56
+ PRIMARY KEY (thscode, date)
57
+ );
58
+
59
+ CREATE TABLE IF NOT EXISTS stg_kline_daily AS SELECT * FROM raw_kline_daily WHERE FALSE;
60
+ CREATE TABLE IF NOT EXISTS stg_adjustment_events AS SELECT * FROM raw_adjustment_events WHERE FALSE;
61
+ CREATE TABLE IF NOT EXISTS stg_symbol AS SELECT * FROM dim_symbol WHERE FALSE;
62
+
63
+ CREATE OR REPLACE VIEW v_symbol AS
64
+ SELECT thscode, ticker, name, exchange, asset_type, updated_at
65
+ FROM dim_symbol;
66
+
67
+ CREATE OR REPLACE VIEW v_daily AS
68
+ SELECT thscode, date, open, high, low, close, prev_close, volume, amount
69
+ FROM raw_kline_daily;
70
+
71
+ CREATE OR REPLACE VIEW v_daily_qfq AS
72
+ SELECT
73
+ d.thscode,
74
+ d.date,
75
+ d.open * COALESCE(f.forward_factor, 1) AS open,
76
+ d.high * COALESCE(f.forward_factor, 1) AS high,
77
+ d.low * COALESCE(f.forward_factor, 1) AS low,
78
+ d.close * COALESCE(f.forward_factor, 1) AS close,
79
+ d.volume,
80
+ d.amount
81
+ FROM raw_kline_daily d
82
+ LEFT JOIN calc_adjust_factor_daily f USING (thscode, date);
83
+
84
+ CREATE OR REPLACE VIEW v_daily_hfq AS
85
+ SELECT
86
+ d.thscode,
87
+ d.date,
88
+ d.open * COALESCE(f.backward_factor, 1) AS open,
89
+ d.high * COALESCE(f.backward_factor, 1) AS high,
90
+ d.low * COALESCE(f.backward_factor, 1) AS low,
91
+ d.close * COALESCE(f.backward_factor, 1) AS close,
92
+ d.volume,
93
+ d.amount
94
+ FROM raw_kline_daily d
95
+ LEFT JOIN calc_adjust_factor_daily f USING (thscode, date);
@@ -0,0 +1,12 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "migrations": [
4
+ {
5
+ "version": 1,
6
+ "name": "initial",
7
+ "type": "safe",
8
+ "file": "001-initial.sql",
9
+ "checksum": "de348d8053706344413a06d58b3420baa227058a627b727402f98a33458fbab3"
10
+ }
11
+ ]
12
+ }
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@hithink-tech/hithink-finance-cli",
3
+ "version": "0.1.0",
4
+ "description": "hithink finance CLI for humans, automation, and AI agents",
5
+ "type": "module",
6
+ "bin": {
7
+ "hithink-finance": "./dist/cli/main.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "!dist/**/*.map",
12
+ "schemas",
13
+ "migrations",
14
+ "skills",
15
+ "scripts/postinstall.mjs",
16
+ "scripts/update-check.mjs",
17
+ "README.md",
18
+ "CHANGELOG.md",
19
+ "SECURITY.md"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsc -p tsconfig.json",
23
+ "generate:contracts": "npm run build && node scripts/generate-contracts.mjs && prettier --write \"schemas/*.json\" \"skills/**/*.md\"",
24
+ "postinstall": "node scripts/postinstall.mjs",
25
+ "pretest": "npm run build",
26
+ "test": "vitest run",
27
+ "typecheck": "tsc -p tsconfig.json --noEmit",
28
+ "lint": "eslint .",
29
+ "format": "prettier --check .",
30
+ "verify": "npm run format && npm run lint && npm run typecheck && npm run test && npm run build",
31
+ "prepublishOnly": "node scripts/check-license.mjs && npm run verify"
32
+ },
33
+ "engines": {
34
+ "node": ">=22.12.0"
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/HiThink-Tech/Financial-API.git",
39
+ "directory": "hithink-finance-cli"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "license": "MIT",
45
+ "homepage": "https://github.com/HiThink-Tech/Financial-API/tree/main/hithink-finance-cli",
46
+ "bugs": {
47
+ "url": "https://github.com/HiThink-Tech/Financial-API/issues"
48
+ },
49
+ "dependencies": {
50
+ "@duckdb/node-api": "1.5.4-r.1",
51
+ "@napi-rs/keyring": "1.3.0",
52
+ "commander": "15.0.0",
53
+ "skills": "1.5.15",
54
+ "zod": "4.4.3"
55
+ },
56
+ "devDependencies": {
57
+ "@eslint/js": "10.0.1",
58
+ "@types/node": "22.15.1",
59
+ "eslint": "10.6.0",
60
+ "execa": "9.6.1",
61
+ "prettier": "3.9.4",
62
+ "typescript": "6.0.3",
63
+ "typescript-eslint": "8.63.0",
64
+ "vitest": "4.1.10"
65
+ }
66
+ }