dsh-config-manager 0.1.80 → 0.1.81
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/lib/cli/actions.d.ts +5 -0
- package/lib/cli/actions.js +5 -0
- package/lib/cli/index.js +21 -7
- package/lib/client.js +527 -525
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/routes/sync.js +16 -0
- package/lib/sync/autosync-scheduler.d.ts +8 -3
- package/lib/sync/autosync-scheduler.js +22 -9
- package/lib/sync/sync-engine.d.ts +13 -0
- package/lib/sync/sync-engine.js +9 -1
- package/lib/sync/sync-session.d.ts +5 -0
- package/package.json +1 -1
- package/src/cli/actions.ts +6 -0
- package/src/cli/index-guards.test.ts +62 -0
- package/src/cli/index.ts +19 -9
- package/src/client/sync/merge-view.ts +2 -0
- package/src/index.ts +1 -1
- package/src/routes/sync.ts +16 -0
- package/src/sync/autosync-scheduler.test.ts +62 -0
- package/src/sync/autosync-scheduler.ts +21 -8
- package/src/sync/sync-engine.test.ts +64 -0
- package/src/sync/sync-engine.ts +22 -1
- package/src/sync/sync-session.ts +5 -0
package/lib/cli/actions.d.ts
CHANGED
|
@@ -142,6 +142,11 @@ export interface RescueStatus {
|
|
|
142
142
|
/** 首页聚合:每一项各自 try/catch,缺一项不影响其余(但失败必须在 errors 里可见)。 */
|
|
143
143
|
export declare function readRescueStatus(paths: RescuePaths, now?: () => Date): Promise<RescueStatus>;
|
|
144
144
|
export type WriteRefusalCode = 'safe-mode' | 'stale-lock' | 'dsh-running' | 'nothing-to-do' | 'io-error';
|
|
145
|
+
/**
|
|
146
|
+
* SAFE MODE 拒因码的**单点常量**:`src/cli/index.ts` 的源码守卫(P0-11-07)禁止
|
|
147
|
+
* CLI 自带 `'safe-mode'` 字面量,判据必须复用本常量(否则改一处漏一处)。
|
|
148
|
+
*/
|
|
149
|
+
export declare const SAFE_MODE_REFUSAL_CODE: WriteRefusalCode;
|
|
145
150
|
export interface WriteGateRefusal {
|
|
146
151
|
ok: false;
|
|
147
152
|
code: WriteRefusalCode;
|
package/lib/cli/actions.js
CHANGED
|
@@ -279,6 +279,11 @@ export async function readRescueStatus(paths, now = () => new Date()) {
|
|
|
279
279
|
function errorText(error) {
|
|
280
280
|
return error instanceof Error ? error.message : String(error);
|
|
281
281
|
}
|
|
282
|
+
/**
|
|
283
|
+
* SAFE MODE 拒因码的**单点常量**:`src/cli/index.ts` 的源码守卫(P0-11-07)禁止
|
|
284
|
+
* CLI 自带 `'safe-mode'` 字面量,判据必须复用本常量(否则改一处漏一处)。
|
|
285
|
+
*/
|
|
286
|
+
export const SAFE_MODE_REFUSAL_CODE = 'safe-mode';
|
|
282
287
|
/**
|
|
283
288
|
* 写动作的前置门(与 CLI `sessions repair --fix` 同一判据)。
|
|
284
289
|
*
|
package/lib/cli/index.js
CHANGED
|
@@ -30,7 +30,7 @@ import { runSessionsRepair } from './sessions-repair.js';
|
|
|
30
30
|
import { runSessionsInspect } from './sessions-inspect.js';
|
|
31
31
|
import { runImportSource } from './import-source.js';
|
|
32
32
|
import { renderCommandHelp, renderOverview } from './help.js';
|
|
33
|
-
import { collectVerifyResults, readRunningInstances } from './actions.js';
|
|
33
|
+
import { checkWriteGates, collectVerifyResults, readRunningInstances, SAFE_MODE_REFUSAL_CODE } from './actions.js';
|
|
34
34
|
import { Phase3Recovery, readSafeModeMarkerSync, safeModeMarkerPath } from '../core/phase3-host.js';
|
|
35
35
|
import { verifyBackupZip, } from '../core/backup-verify.js';
|
|
36
36
|
import { collectBackupEntries, buildSectionFlags, parseSectionsArg, OFFLINE_UNAVAILABLE_SECTIONS, } from '../core/backup-plan.js';
|
|
@@ -853,19 +853,33 @@ export async function runCli(argv, io = defaultIo, env = process.env, deps = {})
|
|
|
853
853
|
}, io, env);
|
|
854
854
|
}
|
|
855
855
|
if (options.command === 'sessions') {
|
|
856
|
-
//
|
|
856
|
+
// 离线修复:只读写会话目录,默认 dry-run(零写入)。list/doctor 纯只读,连「DSH 在跑」都不用管。
|
|
857
|
+
// **--fix 走与救急台完全相同的写入门**(actions.ts 的 checkWriteGates,顺序 SAFE MODE → 残留环境锁 → DSH 未运行):
|
|
858
|
+
// 此前这里只查「DSH 在跑」,于是 SAFE MODE 激活 / 残留环境锁时 CLI 仍能改写会话字节 —— 与救急台判据分叉(审计 P1)。
|
|
857
859
|
const home = options.home ?? resolveDshHome(env);
|
|
858
860
|
const action = options.positionals[0] ?? 'repair';
|
|
859
861
|
// T6:list / doctor 是**只读**动作 —— 不检查「DSH 是否在跑」,因为读永远不会伤害运行中的实例。
|
|
860
862
|
if (action === 'list' || action === 'doctor') {
|
|
861
863
|
return runSessionsInspect({ home, action: action === 'doctor' ? 'doctor' : 'list', json: options.json }, io);
|
|
862
864
|
}
|
|
863
|
-
// T6:repair(含 --fix/--apply
|
|
865
|
+
// T6:repair(含 --fix/--apply)先跑安全修复计划;写操作前三道门与救急台逐条同源。
|
|
864
866
|
if (options.fix === true) {
|
|
865
|
-
const
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
867
|
+
const controlOpts = { dataRoot: options.dataRoot, dataDir: options.dataDir };
|
|
868
|
+
const gate = await checkWriteGates(resolveControlRoots(controlOpts, env), {
|
|
869
|
+
needsDshStopped: true,
|
|
870
|
+
locksDir: resolveRecoverLocksDir(controlOpts, env),
|
|
871
|
+
});
|
|
872
|
+
if (!gate.ok) {
|
|
873
|
+
io.error('拒绝执行:' + gate.reason);
|
|
874
|
+
if (gate.code === 'dsh-running') {
|
|
875
|
+
io.error('DSH running: close DSH before repairing session bytes.');
|
|
876
|
+
}
|
|
877
|
+
else if (gate.code === SAFE_MODE_REFUSAL_CODE) {
|
|
878
|
+
io.error('SAFE MODE is active: resolve the pending transaction before writing session bytes.');
|
|
879
|
+
}
|
|
880
|
+
else if (gate.code === 'stale-lock') {
|
|
881
|
+
io.error('A stale environment lock is present: run "dsh-config-manager recover-stale-lock" first.');
|
|
882
|
+
}
|
|
869
883
|
return 1;
|
|
870
884
|
}
|
|
871
885
|
}
|