@dshtrading/dsh-home 0.1.6 → 0.2.1

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.
@@ -0,0 +1,4 @@
1
+ //#region src/fs-atomic.d.ts
2
+ declare function writeJsonAtomic(filePath: string, data: unknown, logPrefix: string): Promise<void>;
3
+ //#endregion
4
+ export { writeJsonAtomic };
@@ -0,0 +1,37 @@
1
+ import { dirname } from "node:path";
2
+ import { mkdir, rename, unlink, writeFile } from "node:fs/promises";
3
+ //#region src/fs-atomic.ts
4
+ /**
5
+ * home 数据文件原子写单一实现(2026-09-09 收敛,原为 7 个包的 9+ 处同体副本):
6
+ * tmp(唯一名)+ rename,EPERM/EBUSY(Windows 目标占用)25ms 退避重试 3 次;
7
+ * 重试耗尽或任何失败保留旧文件、清理 tmp、log + throw——目标文件永远只被
8
+ * 原子 rename 触碰,绝不非原子直写(半截写会损坏 JSON 导致 load 静默重置)。
9
+ *
10
+ * logPrefix 是失败日志在文件路径之前的完整前缀,逐字保留各调用方既有日志
11
+ * (如 '[dsh-trading/knowledge] failed to atomic flush knowledge cards to')。
12
+ */
13
+ async function writeJsonAtomic(filePath, data, logPrefix) {
14
+ const dir = dirname(filePath);
15
+ const tmpPath = `${filePath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2, 8)}`;
16
+ const text = JSON.stringify(data, null, 2);
17
+ try {
18
+ await mkdir(dir, { recursive: true });
19
+ await writeFile(tmpPath, text, "utf8");
20
+ let lastError;
21
+ for (let attempt = 0; attempt < 3; attempt++) try {
22
+ await rename(tmpPath, filePath);
23
+ return;
24
+ } catch (err) {
25
+ if (err?.code !== "EPERM" && err?.code !== "EBUSY") throw err;
26
+ lastError = err;
27
+ await new Promise((resolve) => setTimeout(resolve, 25 * (attempt + 1)));
28
+ }
29
+ throw lastError;
30
+ } catch (error) {
31
+ console.error(`${logPrefix} ${filePath}:`, error);
32
+ await unlink(tmpPath).catch(() => {});
33
+ throw error;
34
+ }
35
+ }
36
+ //#endregion
37
+ export { writeJsonAtomic };
package/lib/index.d.ts CHANGED
@@ -1,14 +1,5 @@
1
+ import { writeJsonAtomic } from "./fs-atomic.js";
1
2
  //#region src/index.d.ts
2
- /**
3
- * dsh home 根目录解析,与宿主 @deepseek-ai/dsh-home-paths 同语义:
4
- * 优先级 显式传入 > `$DSH_HOME`(空白视为未设,支持 `~` 展开)> `~/.dsh`,
5
- * 相对路径按 CWD 解析。
6
- *
7
- * dsh-trading 各包的 home 数据文件(watchlists.json、knowledge/cards.json、
8
- * trading-tasks/ledger 等)一律经此解析,使整套 trading 实例可以通过
9
- * `DSH_HOME=~/.dsh-trading` 迁到独立 home,与 dsh web 宿主 home 彻底分开
10
- * (2026-09-08 DSH_HOME 分离,note: implemented/process/2026-09-08-separate-dsh-home.md)。
11
- */
12
3
  /**
13
4
  * 解析 dsh home 根目录。
14
5
  * @param env 环境变量映射,缺省读 `process.env`;空白 `$DSH_HOME` 视为未设。
@@ -60,4 +51,4 @@ interface LegacyHomeMigrationResult {
60
51
  */
61
52
  declare function migrateLegacyTradingHome(options?: LegacyHomeMigrationOptions): LegacyHomeMigrationResult | null;
62
53
  //#endregion
63
- export { HOME_MIGRATION_MARKER, LegacyHomeMigrationOptions, LegacyHomeMigrationResult, TRADING_HOME_ENTRIES, defaultDshHome, dshHomeDir, migrateLegacyTradingHome };
54
+ export { HOME_MIGRATION_MARKER, LegacyHomeMigrationOptions, LegacyHomeMigrationResult, TRADING_HOME_ENTRIES, defaultDshHome, dshHomeDir, migrateLegacyTradingHome, writeJsonAtomic };
package/lib/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { writeJsonAtomic } from "./fs-atomic.js";
1
2
  import { cpSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
2
3
  import { homedir } from "node:os";
3
4
  import { join, resolve } from "node:path";
@@ -120,4 +121,4 @@ function migrateLegacyTradingHome(options = {}) {
120
121
  };
121
122
  }
122
123
  //#endregion
123
- export { HOME_MIGRATION_MARKER, TRADING_HOME_ENTRIES, defaultDshHome, dshHomeDir, migrateLegacyTradingHome };
124
+ export { HOME_MIGRATION_MARKER, TRADING_HOME_ENTRIES, defaultDshHome, dshHomeDir, migrateLegacyTradingHome, writeJsonAtomic };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dshtrading/dsh-home",
3
3
  "description": "dsh home 根目录解析($DSH_HOME 环境变量感知,缺省 ~/.dsh,对齐宿主 dsh-home-paths 语义)——dsh-trading 各包 home 数据文件的唯一路径来源",
4
- "version": "0.1.6",
4
+ "version": "0.2.1",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "./lib/index.d.ts",