dsh-config-manager 0.2.0 → 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.
@@ -45,10 +45,37 @@
45
45
  * 且文件类分区不进 SecretScanner(与 pluginFiles/skills 同语义)。
46
46
  */
47
47
  import type { HostContext } from '../core/types.ts';
48
+ import type { AutosyncConfig } from '../sync/autosync-config.ts';
49
+ import type { BackupScheduleConfig } from '../sync/backup-schedule-config.ts';
48
50
  import type { RecursiveListing } from '../utils/recursive-walk.ts';
49
51
  import { FileCollectionAdapter } from './file-collection.ts';
50
52
  /** self 分区白名单文件(相对 baseDir,即 $DSH_HOME/dsh-config-manager/)。 */
51
53
  export declare const SELF_CONFIG_FILES: readonly string[];
54
+ /**
55
+ * 调度配置里「运行态字段」的**命名口径**:调度器每轮收尾都会改写的字段名形状
56
+ * (`lastRun*` 一族 + `consecutiveFailures`)。剔除表必须覆盖两个调度配置的并集,
57
+ * 少一个都会让 self 分区的 hashSection 每轮翻新(issue #119)。
58
+ */
59
+ type RunStateKeyOf<T> = {
60
+ [K in keyof T]-?: K extends 'consecutiveFailures' | `lastRun${string}` ? K : never;
61
+ }[keyof T];
62
+ type SchedulerRunStateKey = RunStateKeyOf<AutosyncConfig> | RunStateKeyOf<BackupScheduleConfig>;
63
+ /**
64
+ * 调度配置里的**运行态字段**:每次执行收尾都会被调度器改写,不属于「配置身份」。
65
+ * 仅比对时剔除(见 comparableContent);写盘仍写完整文件。
66
+ *
67
+ * 逐项列全而不是靠前缀过滤:前缀过滤会把**将来**新增的运行态字段静默吞掉(看不见的假 Skip),
68
+ * 漏列则让 hash 每轮翻新(issue #119)。所以列全 + 下面的穷尽断言,让编译器守住漂移。
69
+ */
70
+ declare const VOLATILE_RUN_STATE_KEY_LIST: readonly ["lastRunAt", "lastRunStatus", "lastRunMessage", "lastRunHistoryId", "consecutiveFailures", "lastRunSkipReason", "lastRunSkipCount"];
71
+ /**
72
+ * 编译期穷尽断言(零运行时开销):`AutosyncConfig` / `BackupScheduleConfig` 将来新增任何
73
+ * `lastRun*` 字段而没进上表时,`Exclude` 不再是 `never`,**这一行 typecheck 报错**。
74
+ * 只写 `satisfies keyof T` 挡不住「新增字段忘了加」——那正是 issue #119 的失效模式。
75
+ */
76
+ type AssertExhaustive<T extends never> = T;
77
+ /** 见 AssertExhaustive 的注释;导出只为让断言参与类型检查(无需被引用)。 */
78
+ export type SchedulerRunStateKeysExhaustive = AssertExhaustive<Exclude<SchedulerRunStateKey, (typeof VOLATILE_RUN_STATE_KEY_LIST)[number]>>;
52
79
  export declare class SelfAdapter extends FileCollectionAdapter {
53
80
  readonly id: 'self';
54
81
  readonly displayName: string;
@@ -94,3 +121,4 @@ export declare class SelfAdapter extends FileCollectionAdapter {
94
121
  */
95
122
  protected comparableContent(relativePath: string, data: Uint8Array): Uint8Array;
96
123
  }
124
+ export {};
@@ -15,10 +15,21 @@ export const SELF_CONFIG_FILES = [
15
15
  /**
16
16
  * 调度配置里的**运行态字段**:每次执行收尾都会被调度器改写,不属于「配置身份」。
17
17
  * 仅比对时剔除(见 comparableContent);写盘仍写完整文件。
18
+ *
19
+ * 逐项列全而不是靠前缀过滤:前缀过滤会把**将来**新增的运行态字段静默吞掉(看不见的假 Skip),
20
+ * 漏列则让 hash 每轮翻新(issue #119)。所以列全 + 下面的穷尽断言,让编译器守住漂移。
18
21
  */
19
- const VOLATILE_RUN_STATE_KEYS = new Set([
20
- 'lastRunAt', 'lastRunStatus', 'lastRunMessage', 'lastRunHistoryId', 'consecutiveFailures',
21
- ]);
22
+ const VOLATILE_RUN_STATE_KEY_LIST = [
23
+ 'lastRunAt',
24
+ 'lastRunStatus',
25
+ 'lastRunMessage',
26
+ 'lastRunHistoryId',
27
+ 'consecutiveFailures',
28
+ // issue #119:跳过码每轮在「写入 / 清空」之间翻转,与 lastRunAt 同性质,漏剔即每轮真推快照
29
+ 'lastRunSkipReason',
30
+ 'lastRunSkipCount',
31
+ ];
32
+ const VOLATILE_RUN_STATE_KEYS = new Set(VOLATILE_RUN_STATE_KEY_LIST);
22
33
  /** 含运行态字段的调度配置(相对 baseDir)。 */
23
34
  const SCHEDULER_CONFIG_RELS = new Set([
24
35
  'sync/sync-autosync.json',