skill-calorie 0.2.6 → 0.3.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.
- package/SKILL.md +17 -13
- package/dist/cli/config.d.ts +24 -1
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +20 -7
- package/dist/cli/config.js.map +1 -1
- package/dist/config.d.ts +10 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +60 -7
- package/dist/config.js.map +1 -1
- package/dist/fetch/audit.d.ts +2 -2
- package/dist/health.d.ts.map +1 -1
- package/dist/health.js +46 -43
- package/dist/health.js.map +1 -1
- package/dist/output.d.ts +4 -3
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +7 -11
- package/dist/output.js.map +1 -1
- package/dist/paths.d.ts +23 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +44 -6
- package/dist/paths.js.map +1 -1
- package/dist/photo/dir.d.ts +1 -1
- package/dist/photo/dir.d.ts.map +1 -1
- package/dist/photo/dir.js +1 -1
- package/dist/photo/dir.js.map +1 -1
- package/dist/photo/photos.d.ts +3 -2
- package/dist/photo/photos.d.ts.map +1 -1
- package/dist/photo/photos.js +7 -8
- package/dist/photo/photos.js.map +1 -1
- package/dist/workout/landBatch.js +2 -2
- package/dist/workout/landRunner.d.ts +1 -1
- package/dist/workout/landRunner.d.ts.map +1 -1
- package/dist/workout/landRunner.js +15 -9
- package/dist/workout/landRunner.js.map +1 -1
- package/dist/workout/xunjiRunner.js +3 -3
- package/dist/xunji/catalog.d.ts +2 -4
- package/dist/xunji/catalog.d.ts.map +1 -1
- package/dist/xunji/catalog.js +7 -11
- package/dist/xunji/catalog.js.map +1 -1
- package/dist/xunji/index.d.ts +1 -1
- package/dist/xunji/index.js +1 -1
- package/dist/xunji/rateLimit.d.ts +4 -4
- package/dist/xunji/rateLimit.d.ts.map +1 -1
- package/dist/xunji/rateLimit.js +6 -6
- package/dist/xunji/rateLimit.js.map +1 -1
- package/dist/xunji/run-sync.d.ts +1 -1
- package/dist/xunji/run-sync.js +1 -1
- package/dist/xunji/run.d.ts +1 -1
- package/dist/xunji/run.d.ts.map +1 -1
- package/package.json +1 -1
package/SKILL.md
CHANGED
|
@@ -25,7 +25,7 @@ calorie-cmd-read calorie.help.lookup --params '{"q":"看今日主页"}'
|
|
|
25
25
|
|
|
26
26
|
## 唯一出口(T11)
|
|
27
27
|
|
|
28
|
-
-
|
|
28
|
+
- 入口=本包 `bin` 声明的那条(`calorie-cmd-read`);**怎么调见下面「唯一出口:怎么跑」节**。纯 CLI 单轨,无面板/定时/外联动。
|
|
29
29
|
- 运维定位(C1 #43):`skill-calorie-fetch`(`dist/fetch/cli.js`)仅运维(import/validate/dedupe/export/history/audit/catalog-verify),不承载业务读写;业务读写唯一出口仍为 `calorie-cmd-read`。
|
|
30
30
|
- 契约:P9 冻结 argv+JSON+exit;缺 key exit 2、未知 key exit 3、取数/缺失 exit 4、envelope/渲染/落盘 exit 5、预检 exit 1。
|
|
31
31
|
- stdout 纯净:成功只打 envelope JSON 一行;进度与错误一律 stderr;HTML 默认落 `<库目录>/<产物目录>/<中文command>_<YYYYMMDD>_<HHMMSS>[_N].html`(同秒冲突自动加 `_2`/`_3`)——`<库目录>`=配置文件 `~/.ilife/calorie.yaml` 的 `db.dir`,空串=数据目录 `~/.ilife/data/`;`<产物目录>`=同文件的 `html.dir`(默认 `calorie_html`)。落点回传在 envelope `data.output`(**恒绝对路径**,相对库目录/`--html` 亦按 cwd 归一后回传);`--html <路径>` 显式覆盖任意路径(**唯一落点参数**:老技能的 `--output` 别名已按 #245 删除,给了即 exit 2,与其余五家同形)。
|
|
@@ -546,17 +546,21 @@ calorie-cmd-read calorie.help.lookup --params '{"q":"看今日主页"}'
|
|
|
546
546
|
|
|
547
547
|
## 环境与出 scope
|
|
548
548
|
|
|
549
|
-
- 路径类取值一律读配置文件 `~/.ilife/calorie.yaml`(**配置文件是唯一真相,环境变量不参与配置**):库目录=`db.dir`(空串=数据目录 `~/.ilife/data/`,首次读时自动建)、库文件名=`db.name`(默认 `calorie_data.db`)、产物目录=`html.dir`(默认 `calorie_html`)、照片目录=`photos.dir`(**空串=这一项还没配**:取数侧跳过「照片文件在不在」的校验、写侧直接阻断,不猜路径)、GIF 子目录=`photos.gifs`(默认 `gifs`)、训记五项=`xunji.*`、落地三项=`land
|
|
549
|
+
- 路径类取值一律读配置文件 `~/.ilife/calorie.yaml`(**配置文件是唯一真相,环境变量不参与配置**):库目录=`db.dir`(空串=数据目录 `~/.ilife/data/`,首次读时自动建)、库文件名=`db.name`(默认 `calorie_data.db`)、产物目录=`html.dir`(默认 `calorie_html`)、照片目录=`photos.dir`(**空串=这一项还没配**:取数侧跳过「照片文件在不在」的校验、写侧直接阻断,不猜路径)、GIF 子目录=`photos.gifs`(默认 `gifs`)、训记五项=`xunji.*`、落地三项=`land.*`。真实 DB 禁迁,测试 tmp 隔离;老家只读对照。取值面与环境项见 docs/env.md。
|
|
550
550
|
- 出 scope(一期外):面板(二期单 MAP)、定时任务、本技能外联动(router+作息/备忘/训记仅只读对照,不落本包)。
|
|
551
551
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
-
|
|
552
|
+
<!-- CALL-FORM-START -->
|
|
553
|
+
|
|
554
|
+
## 唯一出口:怎么跑
|
|
555
|
+
|
|
556
|
+
入口=本技能包 `package.json` 里 `bin` 声明的那条:`dist/cli/cmd_read.js`。
|
|
557
|
+
`<技能基目录>`=加载本技能时给出的 `Base directory for this skill: <路径>` 那一行。
|
|
558
|
+
|
|
559
|
+
1. 命令名解析得到时:`calorie-cmd-read <key> [--params '<json>']`。
|
|
560
|
+
2. 解析不到时(`not recognized`/`command not found`)= PATH 上没有这条命令,下面这行照样跑得起来:
|
|
561
|
+
`node <技能基目录>/dist/cli/cmd_read.js <key> [--params '<json>']`
|
|
562
|
+
3. 本目录里没有编译产物时:`npx -p skill-calorie calorie-cmd-read <key> [--params '<json>']`(上面第 2 行就够,不必再取一份)。
|
|
563
|
+
|
|
564
|
+
换走法的信号只有一个:命令名解析不到。其余报错照 stderr 的报文原样交给用户。
|
|
565
|
+
<!-- CALL-FORM-END -->
|
|
566
|
+
|
package/dist/cli/config.d.ts
CHANGED
|
@@ -9,8 +9,31 @@ export declare function isConfigKey(key: string): boolean;
|
|
|
9
9
|
/**
|
|
10
10
|
* 跑一个配置 key,返回整行 envelope JSON。
|
|
11
11
|
*
|
|
12
|
-
* 三个 key 的载荷:读 → `{path, dataDir, created, values}`;写 → 入参 `{values}`,回执 `{path, values}`;
|
|
12
|
+
* 三个 key 的载荷:读 → `{path, dataDir, created, values, resolved}`;写 → 入参 `{values}`,回执 `{path, values}`;
|
|
13
13
|
* 重置 → `{path, backupPath}`(`backupPath` 为 null 表示本来就没有配置文件)。
|
|
14
|
+
*
|
|
15
|
+
* `resolved`(#757,照记账 #749 样板)=一组**解析后的绝对路径**,给设置页的只读行显示用:
|
|
16
|
+
* 生效数据目录/库文件/产物目录/照片目录/GIF 子目录/训记状态目录/动作库
|
|
17
|
+
* (算式唯一定义地=`src/paths.ts` 纯函数一族 + `src/xunji/catalog.ts` 的预置件,面板不自己拼路径)。
|
|
18
|
+
* 只算路径、不建目录、不写盘(设置页与体检都能随时调)。
|
|
14
19
|
*/
|
|
20
|
+
export interface CalorieResolvedPaths {
|
|
21
|
+
/** 生效数据目录(`db.dir` 非空用它,空=默认落点)——面板上可改项之一的生效值。 */
|
|
22
|
+
readonly dbDir: string;
|
|
23
|
+
/** 库文件绝对路径。 */
|
|
24
|
+
readonly dbFile: string;
|
|
25
|
+
/** HTML 产物目录绝对路径。 */
|
|
26
|
+
readonly htmlDir: string;
|
|
27
|
+
/** 照片目录绝对路径(空串按默认落点,不再是「未配置」)。 */
|
|
28
|
+
readonly photosDir: string;
|
|
29
|
+
/** 照片 GIF 子目录绝对路径。 */
|
|
30
|
+
readonly gifsDir: string;
|
|
31
|
+
/** 训记状态目录绝对路径(空串按默认落点,不再 `~/.mavis`)。 */
|
|
32
|
+
readonly stateDir: string;
|
|
33
|
+
/** 训记动作库绝对路径(空串=包内预置那份)。 */
|
|
34
|
+
readonly catalog: string;
|
|
35
|
+
}
|
|
36
|
+
/** 算那一组解析后的绝对路径。**只算路径、不建目录、不写盘**。 */
|
|
37
|
+
export declare function resolvedCaloriePaths(): CalorieResolvedPaths;
|
|
15
38
|
export declare function runConfigKey(key: string, params: Record<string, unknown>): string;
|
|
16
39
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/cli/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAmBA,wEAAwE;AACxE,eAAO,MAAM,WAAW;;;;CAId,CAAC;AAEX,yBAAyB;AACzB,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEhD;AAiCD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,oBAAoB;IACnC,kDAAkD;IAClD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,eAAe;IACf,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,qBAAqB;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,kCAAkC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,sBAAsB;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,4BAA4B;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,sCAAsC;AACtC,wBAAgB,oBAAoB,IAAI,oBAAoB,CAc3D;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAgBjF"}
|
package/dist/cli/config.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { CALORIE_SKILL, ENVELOPE_VERSION } from './keys.js';
|
|
2
2
|
import { loadCalorieConfig, resetCalorieConfig, saveCalorieConfig } from '../config.js';
|
|
3
|
+
import { dbFileOf, gifsDirOf, htmlDirOf, photosDirOf, resolveDbDir, resolveDbFileName, stateDirOf } from '../paths.js';
|
|
4
|
+
import { XUNJI_CATALOG } from '../xunji/index.js';
|
|
3
5
|
import { fail } from '../shared/params.js';
|
|
4
6
|
/** 三个 key 的唯一定义地(插件侧镜像同值,见 `packages/plugin-calorie/src/bridge.ts`)。 */
|
|
5
7
|
export const CONFIG_KEYS = {
|
|
@@ -42,16 +44,27 @@ function withHumanError(run) {
|
|
|
42
44
|
fail(1, e instanceof Error ? e.message : String(e));
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
/** 算那一组解析后的绝对路径。**只算路径、不建目录、不写盘**。 */
|
|
48
|
+
export function resolvedCaloriePaths() {
|
|
49
|
+
const c = loadCalorieConfig();
|
|
50
|
+
const dbDir = resolveDbDir();
|
|
51
|
+
const photosDir = photosDirOf(dbDir, c.values.photos.dir);
|
|
52
|
+
const catalogConfigured = c.values.xunji.catalog;
|
|
53
|
+
return {
|
|
54
|
+
dbDir,
|
|
55
|
+
dbFile: dbFileOf(dbDir, resolveDbFileName()),
|
|
56
|
+
htmlDir: htmlDirOf(dbDir, c.values.html.dir),
|
|
57
|
+
photosDir,
|
|
58
|
+
gifsDir: gifsDirOf(photosDir, c.values.photos.gifs),
|
|
59
|
+
stateDir: stateDirOf(dbDir, c.values.xunji.stateDir),
|
|
60
|
+
catalog: catalogConfigured !== '' ? catalogConfigured : XUNJI_CATALOG.preset,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
51
63
|
export function runConfigKey(key, params) {
|
|
52
64
|
if (key === CONFIG_KEYS.read) {
|
|
53
65
|
const c = withHumanError(() => loadCalorieConfig());
|
|
54
|
-
|
|
66
|
+
const resolved = withHumanError(() => resolvedCaloriePaths());
|
|
67
|
+
return envelope(key, 'detail', { path: c.path, dataDir: c.dataDir, created: c.created, values: c.values, resolved });
|
|
55
68
|
}
|
|
56
69
|
if (key === CONFIG_KEYS.write) {
|
|
57
70
|
const raw = params['values'];
|
package/dist/cli/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACxF,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE3C,wEAAwE;AACxE,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,IAAI,EAAE,qBAAqB;IAC3B,KAAK,EAAE,sBAAsB;IAC7B,KAAK,EAAE,sBAAsB;CACrB,CAAC;AAEX,yBAAyB;AACzB,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,OAAO,GAAG,KAAK,WAAW,CAAC,IAAI,IAAI,GAAG,KAAK,WAAW,CAAC,KAAK,IAAI,GAAG,KAAK,WAAW,CAAC,KAAK,CAAC;AAC5F,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW,EAAE,KAAoB,EAAE,IAAa;IAChE,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;AAC/F,CAAC;AAED,8CAA8C;AAC9C,SAAS,WAAW,CAAC,OAAqB,EAAE,QAAsB;IAChE,MAAM,GAAG,GAAiB,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACrE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACnF,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,CAAC,GAAG,CAAC,GAAG,KAA6B,CAAC;YACzC,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAA4B,EAAE,GAAG,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAE,IAAgC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACpI,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC;YAAE,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;QACrG,GAAG,CAAC,GAAG,CAAC,GAAG,MAA8B,CAAC;IAC5C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,8DAA8D;AAC9D,SAAS,cAAc,CAAI,GAAY;IACrC,IAAI,CAAC;QACH,OAAO,GAAG,EAAE,CAAC;IACf,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,CAAC,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC;AACH,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -26,12 +26,16 @@ export declare const CALORIE_CONFIG_DEFAULTS: {
|
|
|
26
26
|
backfillDays: number;
|
|
27
27
|
};
|
|
28
28
|
land: {
|
|
29
|
-
scheduleCli: string;
|
|
30
|
-
memoCli: string;
|
|
31
29
|
xunjiSeconds: number;
|
|
32
30
|
landSeconds: number;
|
|
33
31
|
};
|
|
34
32
|
};
|
|
33
|
+
/** **已退休键**(#762 过渡件 + #757 真删):我们自己删过、老配置文件里必然还留着的键的叶子全路径。命中的键跳过校验、
|
|
34
|
+
* 不进取值、也不会被写回(任何一次保存/重置天然抹掉它)。名单**只许写已经删掉的键**——键还在默认值表里
|
|
35
|
+
* 就写进清单=在护栏上开洞,`base-link-core` 收到清单时当场拒。
|
|
36
|
+
* `land.scheduleCli`/`land.memoCli`(#748 定稿)删于本票 #757:两个跨技能出口退回「按包布局推断」,
|
|
37
|
+
* 面板不再显示这两行。退出条件:下一个大版本删掉这张清单。 */
|
|
38
|
+
export declare const CALORIE_CONFIG_RETIRED: readonly string[];
|
|
35
39
|
/** 取值形状由默认值表派生(同一件事只有一个定义地)。 */
|
|
36
40
|
export type CalorieConfigValues = typeof CALORIE_CONFIG_DEFAULTS;
|
|
37
41
|
/** 读回来的一份配置:文件路径(人话报错要指它)+数据目录+取值。 */
|
|
@@ -41,7 +45,10 @@ export interface LoadedCalorieConfig {
|
|
|
41
45
|
readonly created: boolean;
|
|
42
46
|
readonly values: CalorieConfigValues;
|
|
43
47
|
}
|
|
44
|
-
/** 读一份配置(文件不存在即按默认值落一份并把配置目录/数据目录建出来)。
|
|
48
|
+
/** 读一份配置(文件不存在即按默认值落一份并把配置目录/数据目录建出来)。
|
|
49
|
+
*
|
|
50
|
+
* 读回来的 `values` 是**文件里那份 ⊕ 默认值**(文件里写空串则仍是空串=按默认落点);
|
|
51
|
+
* 首次落文件时写下去的是 `writableDefaults()`(可改落点=绝对路径)。 */
|
|
45
52
|
export declare function loadCalorieConfig(): LoadedCalorieConfig;
|
|
46
53
|
/** 写一份配置(写出去的是完整一份:没给的项按默认值补齐)。写完清记忆,同进程后续读也现取。 */
|
|
47
54
|
export declare function saveCalorieConfig(values: ConfigRecord): {
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,qCAAqC;AACrC,eAAO,MAAM,mBAAmB,EAAG,SAAkB,CAAC;AAEtD;;;;wDAIwD;AACxD,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;CAMnC,CAAC;AAEF;;;;mCAImC;AACnC,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAAyC,CAAC;AAE9F,gCAAgC;AAChC,MAAM,MAAM,mBAAmB,GAAG,OAAO,uBAAuB,CAAC;AA0CjE,sCAAsC;AACtC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;CACtC;AAOD;;;mDAGmD;AACnD,wBAAgB,iBAAiB,IAAI,mBAAmB,CAiBvD;AAED,mDAAmD;AACnD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAIxE;AAED,4CAA4C;AAC5C,wBAAgB,kBAAkB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAIhF"}
|
package/dist/config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** 卡路里自己的配置面:那份默认值表 + 读/写/重置三个薄转调。
|
|
2
2
|
*
|
|
3
3
|
* 口径出处(「配置的存与生效口径裁定」#675 的解决评论,本票 #676 落地):
|
|
4
|
-
* · 每个技能一份 YAML 配置文件,默认 `~/.ilife/calorie.yaml
|
|
4
|
+
* · 每个技能一份 YAML 配置文件,默认 `~/.ilife/calorie.yaml`(只此一处,由 `os.homedir()` 派生);
|
|
5
5
|
* · **配置文件是唯一真相**,环境变量不参与配置;
|
|
6
6
|
* · 「重置为默认」先自动备份 `.bak`,备份失败即不写盘、原文件保持不动。
|
|
7
7
|
* 读写实现(受限 YAML 子集解析、键表与类型校验、备份、建目录)住 `base-link-core` 的 `src/config/`
|
|
@@ -10,8 +10,11 @@
|
|
|
10
10
|
* 默认值逐项等于改造前的代码常量(对照读数见 `docs/plugins/plugin-calorie/t676-证据.md`)。
|
|
11
11
|
* 用法上一处约定:**空串=按默认落点**——落点由各取用处按本域常量算(今天写死在哪,默认就是哪里),
|
|
12
12
|
* 所以空串不是「没配」,而是「用老落点」,老数据不会看起来丢了。
|
|
13
|
+
* #757 起这条约定的**两半分头**(照记账 #749 样板):**读**认空串;**写**(首次落文件/保存/重置)把面板上可改的
|
|
14
|
+
* 那两格(`db.dir`/`photos.dir`)落成算出来的绝对路径——见下面 `writableDefaults()` 的注释。
|
|
13
15
|
*/
|
|
14
16
|
import { configPaths, loadConfig, resetConfig, saveConfig } from 'base-link-core';
|
|
17
|
+
import { join } from 'node:path';
|
|
15
18
|
/** 配置文件主体名:`<配置目录>/calorie.yaml`。 */
|
|
16
19
|
export const CALORIE_CONFIG_STEM = 'calorie';
|
|
17
20
|
/** 卡路里那份配置表:键即设置页的行,一层嵌套(子集支持范围见 base-link-core README)。
|
|
@@ -24,17 +27,67 @@ export const CALORIE_CONFIG_DEFAULTS = {
|
|
|
24
27
|
html: { dir: 'calorie_html' },
|
|
25
28
|
photos: { dir: '', gifs: 'gifs' },
|
|
26
29
|
xunji: { key: '', cli: '', stateDir: '', catalog: '', backfillDays: 1 },
|
|
27
|
-
land: {
|
|
30
|
+
land: { xunjiSeconds: 300, landSeconds: 60 },
|
|
28
31
|
};
|
|
29
|
-
/**
|
|
32
|
+
/** **已退休键**(#762 过渡件 + #757 真删):我们自己删过、老配置文件里必然还留着的键的叶子全路径。命中的键跳过校验、
|
|
33
|
+
* 不进取值、也不会被写回(任何一次保存/重置天然抹掉它)。名单**只许写已经删掉的键**——键还在默认值表里
|
|
34
|
+
* 就写进清单=在护栏上开洞,`base-link-core` 收到清单时当场拒。
|
|
35
|
+
* `land.scheduleCli`/`land.memoCli`(#748 定稿)删于本票 #757:两个跨技能出口退回「按包布局推断」,
|
|
36
|
+
* 面板不再显示这两行。退出条件:下一个大版本删掉这张清单。 */
|
|
37
|
+
export const CALORIE_CONFIG_RETIRED = ['land.scheduleCli', 'land.memoCli'];
|
|
38
|
+
/** 写盘那一份用的默认值表:**可改落点**(`db.dir`/`photos.dir`)写成算出来的绝对路径(#746 总口径回灌,本票 #757 落地)。
|
|
39
|
+
*
|
|
40
|
+
* 为什么写绝对路径:面板上「数据目录/照片目录」那两格显示的是从配置文件算出的生效值,而空串的语义是「按默认落点」
|
|
41
|
+
* ——默认落点由 `os.homedir()` 派生,换机器/改用户名就会漂到别处;写死了才是「这一格写的是什么就是什么」。
|
|
42
|
+
* **只读落点保持原样**(`xunji.stateDir` 的空串由落点算式解成 `<数据目录>/xunji`,绝对化=改语义)。
|
|
43
|
+
*
|
|
44
|
+
* 口径的两半:**读**仍认空串(=按默认落点,老文件一份不用动,也不与 #762 的退休键过渡打架);
|
|
45
|
+
* **写**(首次落文件/保存/重置)一律落绝对路径。那两格不自己拼配置目录——`db.dir` 直接用 `configPaths(stem).dataDir`,
|
|
46
|
+
* `photos.dir` 用 `join(dataDir, 'photos')`(今天算照片默认落点只有这一处算法)。 */
|
|
47
|
+
function writableDefaults() {
|
|
48
|
+
const dataDir = configPaths(CALORIE_CONFIG_STEM).dataDir;
|
|
49
|
+
return {
|
|
50
|
+
...CALORIE_CONFIG_DEFAULTS,
|
|
51
|
+
db: { ...CALORIE_CONFIG_DEFAULTS.db, dir: dataDir },
|
|
52
|
+
photos: { ...CALORIE_CONFIG_DEFAULTS.photos, dir: join(dataDir, 'photos') },
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** 写盘前把可改落点那两格的**空白值**去掉:空串=按默认落点,而写的时候那个落点要落成绝对路径
|
|
56
|
+
* (见 `writableDefaults`)——去掉这一格,`base-link-core` 的 `fillDefaults` 自会补上写盘用的默认值。
|
|
57
|
+
* 组里一个子项都不剩时连组一起去掉(空组写出去解析不回来)。 */
|
|
58
|
+
function withoutBlankEditableDirs(values) {
|
|
59
|
+
let out = { ...values };
|
|
60
|
+
for (const groupKey of ['db', 'photos']) {
|
|
61
|
+
const group = out[groupKey];
|
|
62
|
+
if (typeof group !== 'object' || group === null || Array.isArray(group))
|
|
63
|
+
continue;
|
|
64
|
+
const dir = group['dir'];
|
|
65
|
+
if (typeof dir !== 'string' || dir !== '')
|
|
66
|
+
continue;
|
|
67
|
+
const next = { ...group };
|
|
68
|
+
delete next['dir'];
|
|
69
|
+
if (Object.keys(next).length === 0) {
|
|
70
|
+
const { [groupKey]: _dropped, ...rest } = out;
|
|
71
|
+
out = rest;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
out = { ...out, [groupKey]: next };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
/** 每进程按**配置目录**记一份:家目录一变(测试逐用例换临时家目录)即现读,
|
|
30
80
|
* 同一目录里不反复读盘(「保存即生效」由 `saveCalorieConfig`/`resetCalorieConfig` 清记忆保证,
|
|
31
81
|
* 不靠长连接;记忆位不绑「进程」而绑「配置目录」是为了不让换目录后的读落到上一份的缓存上)。 */
|
|
32
82
|
let memo = null;
|
|
33
|
-
/** 读一份配置(文件不存在即按默认值落一份并把配置目录/数据目录建出来)。
|
|
83
|
+
/** 读一份配置(文件不存在即按默认值落一份并把配置目录/数据目录建出来)。
|
|
84
|
+
*
|
|
85
|
+
* 读回来的 `values` 是**文件里那份 ⊕ 默认值**(文件里写空串则仍是空串=按默认落点);
|
|
86
|
+
* 首次落文件时写下去的是 `writableDefaults()`(可改落点=绝对路径)。 */
|
|
34
87
|
export function loadCalorieConfig() {
|
|
35
88
|
const file = configPaths(CALORIE_CONFIG_STEM).configFile;
|
|
36
89
|
if (memo === null || memo.file !== file) {
|
|
37
|
-
const loaded = loadConfig(CALORIE_CONFIG_STEM,
|
|
90
|
+
const loaded = loadConfig(CALORIE_CONFIG_STEM, writableDefaults(), CALORIE_CONFIG_RETIRED);
|
|
38
91
|
// base-link-core 读回来时已经过了「键齐 + 类型对」两道校验(不认识的键、类型不符一律抛),
|
|
39
92
|
// 故这一处从宽松记录到形状记录的转换是有依据的投影,不是猜测。
|
|
40
93
|
memo = {
|
|
@@ -51,13 +104,13 @@ export function loadCalorieConfig() {
|
|
|
51
104
|
}
|
|
52
105
|
/** 写一份配置(写出去的是完整一份:没给的项按默认值补齐)。写完清记忆,同进程后续读也现取。 */
|
|
53
106
|
export function saveCalorieConfig(values) {
|
|
54
|
-
const r = saveConfig(CALORIE_CONFIG_STEM,
|
|
107
|
+
const r = saveConfig(CALORIE_CONFIG_STEM, writableDefaults(), withoutBlankEditableDirs(values), CALORIE_CONFIG_RETIRED);
|
|
55
108
|
memo = null;
|
|
56
109
|
return r;
|
|
57
110
|
}
|
|
58
111
|
/** 重置为默认(先另存 `<配置目录>/calorie.yaml.bak`)。 */
|
|
59
112
|
export function resetCalorieConfig() {
|
|
60
|
-
const r = resetConfig(CALORIE_CONFIG_STEM,
|
|
113
|
+
const r = resetConfig(CALORIE_CONFIG_STEM, writableDefaults(), CALORIE_CONFIG_RETIRED);
|
|
61
114
|
memo = null;
|
|
62
115
|
return r;
|
|
63
116
|
}
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAElF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,qCAAqC;AACrC,MAAM,CAAC,MAAM,mBAAmB,GAAG,SAAkB,CAAC;AAEtD;;;;wDAIwD;AACxD,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE;IACxC,IAAI,EAAE,EAAE,GAAG,EAAE,cAAc,EAAE;IAC7B,MAAM,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;IACjC,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE;IACvE,IAAI,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE;CAC7C,CAAC;AAEF;;;;mCAImC;AACnC,MAAM,CAAC,MAAM,sBAAsB,GAAsB,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC;AAK9F;;;;;;;;iEAQiE;AACjE,SAAS,gBAAgB;IACvB,MAAM,OAAO,GAAG,WAAW,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC;IACzD,OAAO;QACL,GAAG,uBAAuB;QAC1B,EAAE,EAAE,EAAE,GAAG,uBAAuB,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE;QACnD,MAAM,EAAE,EAAE,GAAG,uBAAuB,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE;KAC5E,CAAC;AACJ,CAAC;AAED;;oCAEoC;AACpC,SAAS,wBAAwB,CAAC,MAAoB;IACpD,IAAI,GAAG,GAAiB,EAAE,GAAG,MAAM,EAAE,CAAC;IACtC,KAAK,MAAM,QAAQ,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAU,EAAE,CAAC;QACjD,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,SAAS;QAClF,MAAM,GAAG,GAAI,KAAiC,CAAC,KAAK,CAAC,CAAC;QACtD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,EAAE;YAAE,SAAS;QACpD,MAAM,IAAI,GAA4B,EAAE,GAAI,KAAiC,EAAE,CAAC;QAChF,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,GAAG,CAAC;YAC9C,GAAG,GAAG,IAAI,CAAC;QACb,CAAC;aAAM,CAAC;YACN,GAAG,GAAG,EAAE,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,IAA4B,EAAE,CAAC;QAC7D,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAUD;;oDAEoD;AACpD,IAAI,IAAI,GAAyD,IAAI,CAAC;AAEtE;;;mDAGmD;AACnD,MAAM,UAAU,iBAAiB;IAC/B,MAAM,IAAI,GAAG,WAAW,CAAC,mBAAmB,CAAC,CAAC,UAAU,CAAC;IACzD,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,UAAU,CAAC,mBAAmB,EAAE,gBAAgB,EAAE,EAAE,sBAAsB,CAAC,CAAC;QAC3F,wDAAwD;QACxD,iCAAiC;QACjC,IAAI,GAAG;YACL,IAAI;YACJ,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,MAAM,EAAE,MAAM,CAAC,MAAwC;aACxD;SACF,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC;AACrB,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,iBAAiB,CAAC,MAAoB;IACpD,MAAM,CAAC,GAAG,UAAU,CAAC,mBAAmB,EAAE,gBAAgB,EAAE,EAAE,wBAAwB,CAAC,MAAM,CAAC,EAAE,sBAAsB,CAAC,CAAC;IACxH,IAAI,GAAG,IAAI,CAAC;IACZ,OAAO,CAAC,CAAC;AACX,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,kBAAkB;IAChC,MAAM,CAAC,GAAG,WAAW,CAAC,mBAAmB,EAAE,gBAAgB,EAAE,EAAE,sBAAsB,CAAC,CAAC;IACvF,IAAI,GAAG,IAAI,CAAC;IACZ,OAAO,CAAC,CAAC;AACX,CAAC"}
|
package/dist/fetch/audit.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** T6 #25 · 训练计划动作名审计(老家 audit_plan_names.py 同契约)。
|
|
2
2
|
* 输出统一 { status, data, message } 三段式;exit 映射由 CLI 负责。
|
|
3
|
-
* #606
|
|
4
|
-
*
|
|
3
|
+
* #606:库面与动作名校验搬进训记模块,本件改走它的能力门——**默认读包内预置快照**
|
|
4
|
+
* (#757 起老机器路径已退场:`XUNJI_CATALOG` 只剩 `preset` 一项,不再有第二套口径)。
|
|
5
5
|
*/
|
|
6
6
|
import type { DatabaseSync } from 'node:sqlite';
|
|
7
7
|
export type AuditStatus = 'ok' | 'warn' | 'fail';
|
package/dist/health.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAwBA,0BAA0B;AAC1B,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEtD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;CACvC;AAED,kEAAkE;AAClE,eAAO,MAAM,kBAAkB,EAAG,EAAW,CAAC;AAc9C,oDAAoD;AACpD,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAC5B;IAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CAAE,GACxH;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,IAAI,UAAU,CAYtD;AA6OD,sDAAsD;AACtD,wBAAgB,wBAAwB,IAAI,mBAAmB,CAwN9D"}
|
package/dist/health.js
CHANGED
|
@@ -19,11 +19,11 @@ import { fileURLToPath } from 'node:url';
|
|
|
19
19
|
import { DatabaseSync } from 'node:sqlite';
|
|
20
20
|
import { configPaths } from 'base-link-core';
|
|
21
21
|
import { CALORIE_CONFIG_DEFAULTS, CALORIE_CONFIG_STEM } from './config.js';
|
|
22
|
+
import { dbDirOf, gifsDirOf, htmlDirOf, photosDirOf, stateDirOf } from './paths.js';
|
|
23
|
+
import { XUNJI_CATALOG } from './xunji/index.js';
|
|
22
24
|
/** 库表数门槛:`src/schema.ts` 那 11 张表齐了才算正常(少了报黄:还能用,但缺功能的表要重建或迁移)。 */
|
|
23
25
|
export const DB_TABLE_THRESHOLD = 11;
|
|
24
26
|
const SKILL = 'calorie';
|
|
25
|
-
/** 训记三份状态文件住在同一个目录。 */
|
|
26
|
-
const XUNJI_STATE_DIR = join(homedir(), '.mavis');
|
|
27
27
|
/** 包根:`dist/health.js` 上一级。 */
|
|
28
28
|
function packageRoot() {
|
|
29
29
|
return join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
@@ -296,10 +296,10 @@ export function buildCalorieHealthReport() {
|
|
|
296
296
|
const read = readCalorieConfigReadOnly();
|
|
297
297
|
const values = read.kind === 'ok' ? read.values : projectOnDefaults({});
|
|
298
298
|
const present = read.kind === 'ok' ? read.present : new Set();
|
|
299
|
-
// ①
|
|
299
|
+
// ① 配置文件本身:能不能解析;它落在默认位置还是别处(只陈述,不评价)。
|
|
300
300
|
const defaultConfigFile = join(homedir(), '.ilife', CALORIE_CONFIG_STEM + '.yaml');
|
|
301
301
|
const relocated = paths.configFile !== defaultConfigFile;
|
|
302
|
-
const where = relocated ? '
|
|
302
|
+
const where = relocated ? '位置与默认不同(见配置文件落点)' : '默认位置';
|
|
303
303
|
if (read.kind === 'bad') {
|
|
304
304
|
items.push({
|
|
305
305
|
id: 'config.file', title: '配置文件', status: 'red',
|
|
@@ -324,9 +324,9 @@ export function buildCalorieHealthReport() {
|
|
|
324
324
|
source: '配置文件',
|
|
325
325
|
});
|
|
326
326
|
}
|
|
327
|
-
// ②
|
|
327
|
+
// ② 数据目录:在不在、能不能写(算式唯一定义地=`src/paths.ts` 的 `dbDirOf`,本件只给只读值)。
|
|
328
328
|
const dbDirConfigured = textOf(readValue(values, 'db', 'dir'));
|
|
329
|
-
const dataDir =
|
|
329
|
+
const dataDir = dbDirOf(paths.dataDir, dbDirConfigured);
|
|
330
330
|
const dataDirSource = sourceOf(present, 'db.dir');
|
|
331
331
|
const dataDirVerdict = dirVerdict(dataDir);
|
|
332
332
|
items.push({
|
|
@@ -382,9 +382,9 @@ export function buildCalorieHealthReport() {
|
|
|
382
382
|
});
|
|
383
383
|
}
|
|
384
384
|
}
|
|
385
|
-
// ④
|
|
385
|
+
// ④ 产物目录:在不在、能不能写(还没建=绿:交付页面时才落这里,那时自动建;算式=`htmlDirOf`)。
|
|
386
386
|
const htmlDirName = textOf(readValue(values, 'html', 'dir'));
|
|
387
|
-
const htmlDir =
|
|
387
|
+
const htmlDir = htmlDirOf(dataDir, htmlDirName);
|
|
388
388
|
const htmlVerdict = dirVerdict(htmlDir);
|
|
389
389
|
const htmlSource = sourceOf(present, 'html.dir');
|
|
390
390
|
items.push({
|
|
@@ -395,7 +395,7 @@ export function buildCalorieHealthReport() {
|
|
|
395
395
|
: htmlVerdict.writable
|
|
396
396
|
? '在且能写:' + p(htmlDir) + '。'
|
|
397
397
|
: '在,但写不进去:' + p(htmlDir) + '(交付会转成内联回执,不再落盘)。',
|
|
398
|
-
action: !htmlVerdict.exists || htmlVerdict.writable ? '' : '
|
|
398
|
+
action: !htmlVerdict.exists || htmlVerdict.writable ? '' : '去掉这个目录的只读属性,或编辑配置文件改「HTML 产物目录名」。',
|
|
399
399
|
source: htmlSource,
|
|
400
400
|
});
|
|
401
401
|
// ⑤ 这个值从哪来:只陈述数据目录与库文件名的来源,不判好坏(六家通用最后一条)。
|
|
@@ -405,33 +405,38 @@ export function buildCalorieHealthReport() {
|
|
|
405
405
|
+ (read.kind === 'missing' ? '(配置文件还不存在,落点全按默认值)。' : '。'),
|
|
406
406
|
action: '', source: dataDirSource,
|
|
407
407
|
});
|
|
408
|
-
// ⑥
|
|
409
|
-
|
|
410
|
-
const
|
|
408
|
+
// ⑥ 照片目录(卡路里特有,#757 新口径):空串=按默认落点 `<数据目录>/photos`,「未配置」状态消失。
|
|
409
|
+
// 还没建=绿(首次记身材照时自动建);在但写不进去/同名文件占位=红。算式=`photosDirOf`。
|
|
410
|
+
const photosConfigured = textOf(readValue(values, 'photos', 'dir'));
|
|
411
|
+
const photosDir = photosDirOf(dataDir, photosConfigured);
|
|
412
|
+
const photosVerdict = dirVerdict(photosDir);
|
|
413
|
+
const photosBlocked = !photosVerdict.exists
|
|
414
|
+
? photosVerdict.reason !== ''
|
|
415
|
+
: !photosVerdict.writable;
|
|
411
416
|
items.push({
|
|
412
417
|
id: 'photos.dir', title: '照片目录',
|
|
413
|
-
status:
|
|
414
|
-
message:
|
|
415
|
-
?
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
418
|
+
status: photosBlocked ? 'red' : 'green',
|
|
419
|
+
message: !photosVerdict.exists
|
|
420
|
+
? (photosVerdict.reason !== ''
|
|
421
|
+
? '同名文件占了它的位置:' + p(photosDir) + '(' + photosVerdict.reason + ')。'
|
|
422
|
+
: '还没建:' + p(photosDir) + '(首次记身材照时自动建)。')
|
|
423
|
+
: photosVerdict.writable
|
|
424
|
+
? '在且能写:' + p(photosDir) + '。'
|
|
425
|
+
: '在,但写不进去:' + p(photosDir) + '(' + photosVerdict.reason + ')。',
|
|
426
|
+
action: photosBlocked
|
|
427
|
+
? '建出这个目录(或去掉只读),或在配置页把「照片目录」换一个位置。'
|
|
428
|
+
: '',
|
|
429
|
+
source: sourceOf(present, 'photos.dir'),
|
|
423
430
|
});
|
|
424
|
-
// ⑦ 照片 GIF
|
|
431
|
+
// ⑦ 照片 GIF 子目录:不在=黄(合成 GIF 时自动建;算式=`gifsDirOf`)。
|
|
425
432
|
const gifsSub = textOf(readValue(values, 'photos', 'gifs'));
|
|
426
|
-
const gifsDir =
|
|
427
|
-
const gifsExists =
|
|
433
|
+
const gifsDir = gifsDirOf(photosDir, gifsSub);
|
|
434
|
+
const gifsExists = existsSync(gifsDir);
|
|
428
435
|
items.push({
|
|
429
436
|
id: 'photos.gifs', title: '照片 GIF 子目录',
|
|
430
|
-
status:
|
|
431
|
-
message:
|
|
432
|
-
|
|
433
|
-
: gifsExists ? '在:' + p(gifsDir) + '。' : '还没建:' + p(gifsDir) + '(合成 GIF 时才落这里)。',
|
|
434
|
-
action: photosDir === '' ? '先配「照片目录」。' : gifsExists ? '' : '第一次合成 GIF 时会自动建;想提前建也行。',
|
|
437
|
+
status: gifsExists ? 'green' : 'yellow',
|
|
438
|
+
message: gifsExists ? '在:' + p(gifsDir) + '。' : '还没建:' + p(gifsDir) + '(合成 GIF 时才落这里)。',
|
|
439
|
+
action: gifsExists ? '' : '第一次合成 GIF 时会自动建;想提前建也行。',
|
|
435
440
|
source: sourceOf(present, 'photos.gifs'),
|
|
436
441
|
});
|
|
437
442
|
// ⑧ 训记 KEY:只查「配了没有」,**绝不显示值**。
|
|
@@ -452,9 +457,9 @@ export function buildCalorieHealthReport() {
|
|
|
452
457
|
message: xunjiCliExists ? '在:' + p(xunjiCli) + '。' : '不在:' + p(xunjiCli) + '。',
|
|
453
458
|
action: xunjiCliExists ? '' : '技能包没构建完整:重装这个技能包,或跑一次它的构建。',
|
|
454
459
|
});
|
|
455
|
-
// ⑩
|
|
460
|
+
// ⑩ 训记三份状态文件目录:`<数据目录>/xunji` 能不能写(不可写=黄;算式=`stateDirOf`,#757 起不再 `~/.mavis`)。
|
|
456
461
|
const stateDirConfigured = textOf(readValue(values, 'xunji', 'stateDir'));
|
|
457
|
-
const stateDir =
|
|
462
|
+
const stateDir = stateDirOf(dataDir, stateDirConfigured);
|
|
458
463
|
const stateVerdict = dirVerdict(stateDir);
|
|
459
464
|
items.push({
|
|
460
465
|
id: 'xunji.stateDir', title: '训记状态文件目录',
|
|
@@ -462,15 +467,13 @@ export function buildCalorieHealthReport() {
|
|
|
462
467
|
message: !stateVerdict.exists
|
|
463
468
|
? '还没建:' + p(stateDir) + '(限频与同步游标要记这里,第一次用时自动建)。'
|
|
464
469
|
: stateVerdict.writable ? '在且能写:' + p(stateDir) + '。' : '在,但写不进去:' + p(stateDir) + '。',
|
|
465
|
-
action: !stateVerdict.exists || stateVerdict.writable ? '' : '
|
|
466
|
-
source:
|
|
470
|
+
action: !stateVerdict.exists || stateVerdict.writable ? '' : '去掉只读,或编辑配置文件改「训记状态文件目录」。',
|
|
471
|
+
source: sourceOf(present, 'xunji.stateDir'),
|
|
467
472
|
});
|
|
468
|
-
// ⑪ 跨技能出口(作息/备忘 CLI
|
|
473
|
+
// ⑪ 跨技能出口(作息/备忘 CLI):不在=黄(只在用「落地训练」时才是红;#757 起删键,出口按包布局推断)。
|
|
469
474
|
const siblingRoot = join(packageRoot(), '..');
|
|
470
|
-
const
|
|
471
|
-
const
|
|
472
|
-
const scheduleCli = scheduleConfigured !== '' ? scheduleConfigured : join(siblingRoot, 'skill-schedule', 'dist', 'cli', 'cmd_read.js');
|
|
473
|
-
const memoCli = memoConfigured !== '' ? memoConfigured : join(siblingRoot, 'skill-memo-ilife', 'dist', 'cli', 'cmd_read.js');
|
|
475
|
+
const scheduleCli = join(siblingRoot, 'skill-schedule', 'dist', 'cli', 'cmd_read.js');
|
|
476
|
+
const memoCli = join(siblingRoot, 'skill-memo-ilife', 'dist', 'cli', 'cmd_read.js');
|
|
474
477
|
const missingLand = [];
|
|
475
478
|
if (!existsSync(scheduleCli))
|
|
476
479
|
missingLand.push('作息 ' + p(scheduleCli));
|
|
@@ -483,17 +486,17 @@ export function buildCalorieHealthReport() {
|
|
|
483
486
|
? '两个出口都在。'
|
|
484
487
|
: '不在:' + missingLand.join(';') + '。',
|
|
485
488
|
action: missingLand.length === 0 ? '' : '只有「落地训练」会用到这两个出口;要用就先装上(或构建)那两家技能包。',
|
|
486
|
-
source:
|
|
489
|
+
source: '默认值',
|
|
487
490
|
});
|
|
488
|
-
// ⑫
|
|
491
|
+
// ⑫ 训记动作库包内预置:包内数据件在不在(不在=黄;路径唯一定义地=`XUNJI_CATALOG.preset`)。
|
|
489
492
|
const catalogConfigured = textOf(readValue(values, 'xunji', 'catalog'));
|
|
490
|
-
const catalog = catalogConfigured !== '' ? catalogConfigured :
|
|
493
|
+
const catalog = catalogConfigured !== '' ? catalogConfigured : XUNJI_CATALOG.preset;
|
|
491
494
|
const catalogExists = existsSync(catalog);
|
|
492
495
|
items.push({
|
|
493
496
|
id: 'xunji.catalog', title: '训记动作库包内预置',
|
|
494
497
|
status: catalogExists ? 'green' : 'yellow',
|
|
495
498
|
message: catalogExists ? '在:' + p(catalog) + '。' : '不在:' + p(catalog) + '(动作名判不了)。',
|
|
496
|
-
action: catalogExists ? '' : '
|
|
499
|
+
action: catalogExists ? '' : '技能包装得不完整,或配置里指到了不存在的路径;重装技能包,或编辑配置文件改回包内预置那份。',
|
|
497
500
|
source: sourceOf(present, 'xunji.catalog'),
|
|
498
501
|
});
|
|
499
502
|
return { skill: SKILL, configPath: p(paths.configFile), dataDir: p(dataDir), items };
|