dsh-rewind-plugin 0.4.1 → 0.5.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.
- package/CONTRIBUTING.md +72 -0
- package/README.en.md +174 -0
- package/README.md +105 -101
- package/SECURITY.md +154 -0
- package/docs/README.md +29 -0
- package/docs/architecture.md +128 -0
- package/docs/compat/tracking-boundary.md +103 -0
- package/docs/compat/tracking-boundary.zh.md +55 -0
- package/docs/compat/troubleshooting.md +41 -0
- package/docs/{troubleshooting.zh.md → compat/troubleshooting.zh.md} +15 -0
- package/docs/format.md +150 -0
- package/docs/harness-reference.md +7 -3
- package/docs/release/release.md +69 -0
- package/docs/{release.md → release/release.zh.md} +6 -52
- package/docs/snapshot-auto-cleanup.md +71 -0
- package/docs/snapshot-auto-cleanup.zh.md +42 -0
- package/lib/client.js +1 -1
- package/lib/index.js +982 -50
- package/lib/types/client/candidates.d.ts +5 -4
- package/lib/types/client/index.d.ts +1 -1
- package/lib/types/index.d.ts +3 -1
- package/lib/types/locales.d.ts +17 -0
- package/lib/types/rewind.d.ts +3 -2
- package/lib/types/snapshot-cleanup.d.ts +125 -0
- package/lib/types/snapshot.d.ts +374 -14
- package/package.json +6 -3
- package/README.zh.md +0 -159
- package/docs/troubleshooting.md +0 -44
- /package/docs/{compat-audit.md → compat/audit.md} +0 -0
- /package/docs/{client-contract.md → contract/client-contract.md} +0 -0
- /package/docs/{client-contract.zh.md → contract/client-contract.zh.md} +0 -0
|
@@ -18,11 +18,12 @@ export declare const PREVIEW_CHARS = 80;
|
|
|
18
18
|
/**
|
|
19
19
|
* Default cap on how many user messages the rewind picker lists (newest kept).
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* Matches the snapshot store's MAX_ANCHOR_GROUPS (100), so the picker shows
|
|
22
|
+
* every anchor group that can still restore file backups; 100 stays
|
|
23
|
+
* scrollable/searchable via the popupSelect shell, and callers can still
|
|
24
|
+
* pass an explicit `limit`.
|
|
24
25
|
*/
|
|
25
|
-
export declare const DEFAULT_CANDIDATE_LIMIT =
|
|
26
|
+
export declare const DEFAULT_CANDIDATE_LIMIT = 100;
|
|
26
27
|
/** One selectable rewind target. */
|
|
27
28
|
export interface RewindCandidate {
|
|
28
29
|
/** Absolute log seq of the `user/message` event. */
|
|
@@ -37,6 +37,6 @@ export declare const inject: string[];
|
|
|
37
37
|
export declare function apply(ctx: ClientContext): void;
|
|
38
38
|
/**
|
|
39
39
|
* Public contract — rewind visibility. Stable, semver-protected; the rest of
|
|
40
|
-
* this module is internal. See `docs/client-contract.md`.
|
|
40
|
+
* this module is internal. See `docs/contract/client-contract.md`.
|
|
41
41
|
*/
|
|
42
42
|
export { hiddenSeqsOf, targetSeqOfArgs, type HiddenChat } from './hidden.ts';
|
package/lib/types/index.d.ts
CHANGED
|
@@ -26,13 +26,15 @@
|
|
|
26
26
|
*/
|
|
27
27
|
import type { Context } from '@deepseek-ai/cordis';
|
|
28
28
|
export { SnapshotStore } from './snapshot.ts';
|
|
29
|
-
export type { CheckpointEntry, FileImpact, RestoreOutcome } from './snapshot.ts';
|
|
29
|
+
export type { CheckpointEntry, FileImpact, PruneStaleReport, RestoreOutcome, RestoreJournal, RestoreJournalState, RestoreReconcileReport } from './snapshot.ts';
|
|
30
30
|
export declare const name = "dsh-rewind";
|
|
31
31
|
export declare const inject: string[];
|
|
32
32
|
/** Plugin config: optional override of the checkpoint store root. */
|
|
33
33
|
export interface RewindConfig {
|
|
34
34
|
/** Checkpoint store root (defaults to `~/.dsh/rewind-snapshots`). */
|
|
35
35
|
readonly snapshotDir?: string;
|
|
36
|
+
/** In-place content dedup (identical before-content → link). Default `true`. */
|
|
37
|
+
readonly dedup?: boolean;
|
|
36
38
|
}
|
|
37
39
|
/**
|
|
38
40
|
* Register the `/rewind` command and the checkpoint pipeline (before-capture
|
package/lib/types/locales.d.ts
CHANGED
|
@@ -49,6 +49,23 @@ export declare const en: {
|
|
|
49
49
|
noUserMessages: string;
|
|
50
50
|
chooseMode: string;
|
|
51
51
|
'command.description': string;
|
|
52
|
+
'cleanup.description': string;
|
|
53
|
+
'cleanup.inputHint': string;
|
|
54
|
+
'cleanup.status': string;
|
|
55
|
+
'cleanup.enabled': string;
|
|
56
|
+
'cleanup.disabled': string;
|
|
57
|
+
'cleanup.present': string;
|
|
58
|
+
'cleanup.absent': string;
|
|
59
|
+
'cleanup.onOk': string;
|
|
60
|
+
'cleanup.offOk': string;
|
|
61
|
+
'cleanup.maxAgeOk': string;
|
|
62
|
+
'cleanup.cfgInvalid': string;
|
|
63
|
+
'cleanup.saveFailed': string;
|
|
64
|
+
'cleanup.runDry': string;
|
|
65
|
+
'cleanup.runApply': string;
|
|
66
|
+
'cleanup.runFailed': string;
|
|
67
|
+
'cleanup.skipped': string;
|
|
68
|
+
'cleanup.usage': string;
|
|
52
69
|
};
|
|
53
70
|
/** The host rewind dictionary key union. */
|
|
54
71
|
export type HostKey = keyof typeof en;
|
package/lib/types/rewind.d.ts
CHANGED
|
@@ -80,10 +80,11 @@ export interface RewindPlan {
|
|
|
80
80
|
export declare const CANDIDATE_PREVIEW_CHARS = 80;
|
|
81
81
|
/**
|
|
82
82
|
* Default cap on how many user messages a candidate listing returns (newest
|
|
83
|
-
* kept).
|
|
83
|
+
* kept). Matches the snapshot store's MAX_ANCHOR_GROUPS (100), so every
|
|
84
|
+
* anchor group that still has restorable file backups is listed; callers can
|
|
84
85
|
* still pass an explicit `limit`.
|
|
85
86
|
*/
|
|
86
|
-
export declare const DEFAULT_CANDIDATE_LIMIT =
|
|
87
|
+
export declare const DEFAULT_CANDIDATE_LIMIT = 100;
|
|
87
88
|
/**
|
|
88
89
|
* Turn number for the rewind marker.
|
|
89
90
|
*
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot cleanup policy: the persisted config file, its validation, the
|
|
3
|
+
* `/snapshot-auto-cleanup` command's argument grammar, and the auto-sweep
|
|
4
|
+
* throttle. Kept free of host wiring so the policy and the parser are
|
|
5
|
+
* unit-testable in isolation; `src/index.ts` is the only consumer.
|
|
6
|
+
*
|
|
7
|
+
* Semantics (the "cleanup" vocabulary deliberately avoids "retention"):
|
|
8
|
+
* - `enabled` toggles the AUTOMATIC (24h) sweep. `false` (the default) keeps
|
|
9
|
+
* every snapshot — the pre-feature behavior — and never writes a file.
|
|
10
|
+
* - `maxAgeDays` is the only "keep" knob: a finished session dir whose newest
|
|
11
|
+
* member stamp is older than this many days of idle is removed by a sweep.
|
|
12
|
+
* `0`/negative/non-integer are rejected, so a broken file can never steer
|
|
13
|
+
* the sweep into deleting everything.
|
|
14
|
+
* - The config file is created ONLY by an explicit `/snapshot-auto-cleanup`
|
|
15
|
+
* write. An absent file reads as the safe default (off); an unreadable or
|
|
16
|
+
* invalid file reports `ok:false` so a sweep fail-closes (deletes nothing)
|
|
17
|
+
* instead of guessing.
|
|
18
|
+
*
|
|
19
|
+
* @module dsh-rewind/snapshot-cleanup
|
|
20
|
+
*/
|
|
21
|
+
/** The cleanup policy, as persisted under `~/.dsh/snapshot-cleanup.json`. */
|
|
22
|
+
export interface CleanupConfig {
|
|
23
|
+
readonly enabled: boolean;
|
|
24
|
+
readonly maxAgeDays: number;
|
|
25
|
+
}
|
|
26
|
+
export declare const CLEANUP_CONFIG_FILENAME = "snapshot-cleanup.json";
|
|
27
|
+
/** Environment variable overriding the config file path. */
|
|
28
|
+
export declare const CLEANUP_CONFIG_ENV = "DSH_SNAPSHOT_CLEANUP_CONFIG";
|
|
29
|
+
/** The default keep threshold: finished sessions idle > 30 days are pruned. */
|
|
30
|
+
export declare const DEFAULT_MAX_AGE_DAYS = 30;
|
|
31
|
+
/** The safe default policy (off) — a missing/corrupt file behaves like this. */
|
|
32
|
+
export declare const DEFAULT_CLEANUP_CONFIG: CleanupConfig;
|
|
33
|
+
/** Auto-sweep cadence (the user's hardcoded 24h rhythm — not user-set). */
|
|
34
|
+
export declare const AUTO_SWEEP_INTERVAL_MS: number;
|
|
35
|
+
/** Resolve the config file path: env override, else `~/.dsh/snapshot-cleanup.json`. */
|
|
36
|
+
export declare function resolveCleanupConfigPath(): string;
|
|
37
|
+
/** The state file that records the last automatic-sweep wall-clock time. */
|
|
38
|
+
export declare const STATE_FILENAME = "snapshot-cleanup-last-sweep.json";
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the last-sweep state path. It sits beside the config file so the
|
|
41
|
+
* 24h cadence SURVIVES a host restart (a real deployment is rarely up 24/7,
|
|
42
|
+
* so an in-memory timestamp would reset on every boot and re-sweep too often).
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveCleanupStatePath(): string;
|
|
45
|
+
/**
|
|
46
|
+
* Read the persisted last-sweep time (epoch ms). A missing or corrupt file
|
|
47
|
+
* reads as `0` ("never swept"), so the next activity runs the sweep — which is
|
|
48
|
+
* safe because the sweep is idempotent and never deletes the active session.
|
|
49
|
+
*/
|
|
50
|
+
export declare function loadLastSweepAt(path: string): Promise<number>;
|
|
51
|
+
/** Persist the last-sweep time, atomically (temp + rename). */
|
|
52
|
+
export declare function saveLastSweepAt(path: string, ms: number): Promise<void>;
|
|
53
|
+
/** The slice of a store `runAutoCleanupCheck` needs (pruneStale). */
|
|
54
|
+
export interface AutoCleanupPruner {
|
|
55
|
+
pruneStale(opts: {
|
|
56
|
+
keepActiveId?: string;
|
|
57
|
+
maxAgeDays: number;
|
|
58
|
+
dryRun?: boolean;
|
|
59
|
+
}): Promise<unknown>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The one-shot auto-cleanup check. Loads the policy + persisted last-sweep time
|
|
63
|
+
* and, only when enabled AND >=24h since the last sweep, runs the sweep and
|
|
64
|
+
* re-anchors the window on disk. Dependencies (store, paths, logger) are
|
|
65
|
+
* injected so the composition is unit-testable without a host. Never rejects:
|
|
66
|
+
* a corrupt config fail-closes (no deletion) and logs, a prune failure logs.
|
|
67
|
+
*
|
|
68
|
+
* `sessionId` is the active session directory that must never be pruned.
|
|
69
|
+
*/
|
|
70
|
+
export declare function runAutoCleanupCheck(deps: {
|
|
71
|
+
pruner: AutoCleanupPruner;
|
|
72
|
+
configPath: string;
|
|
73
|
+
statePath: string;
|
|
74
|
+
log: (msg: string) => void;
|
|
75
|
+
}, sessionId: string | undefined): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Validate one parsed JSON value into a {@link CleanupConfig}. Tolerates
|
|
78
|
+
* unknown extra keys; rejects a present-but-wrong-typed known key. Missing
|
|
79
|
+
* known keys fall back to the safe default.
|
|
80
|
+
*/
|
|
81
|
+
export declare function parseCleanupConfig(raw: unknown): {
|
|
82
|
+
ok: true;
|
|
83
|
+
config: CleanupConfig;
|
|
84
|
+
} | {
|
|
85
|
+
ok: false;
|
|
86
|
+
error: string;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Load and validate the config file. A missing file is NOT an error: it reads
|
|
90
|
+
* as the safe default (off, `fromFile:false`). An unreadable, non-JSON, or
|
|
91
|
+
* structurally-invalid file is `ok:false` so a sweep fail-closes.
|
|
92
|
+
*/
|
|
93
|
+
export declare function loadCleanupConfig(path: string): Promise<{
|
|
94
|
+
ok: true;
|
|
95
|
+
config: CleanupConfig;
|
|
96
|
+
fromFile: boolean;
|
|
97
|
+
} | {
|
|
98
|
+
ok: false;
|
|
99
|
+
error: string;
|
|
100
|
+
}>;
|
|
101
|
+
/**
|
|
102
|
+
* Persist a validated {@link CleanupConfig}, atomically (temp + rename). Any
|
|
103
|
+
* invalid value throws before the file is touched, so the command can never
|
|
104
|
+
* write a broken policy.
|
|
105
|
+
*/
|
|
106
|
+
export declare function saveCleanupConfig(path: string, config: CleanupConfig): Promise<void>;
|
|
107
|
+
/** The `/snapshot-auto-cleanup` sub-command the parser can resolve to. */
|
|
108
|
+
export type CleanupCommandAction = 'status' | 'on' | 'off' | 'max-age' | 'run' | 'run-apply';
|
|
109
|
+
/**
|
|
110
|
+
* Parse the free-form text after `/snapshot-auto-cleanup`. Pure so it is
|
|
111
|
+
* unit-testable; `src/index.ts` maps the resolved action onto the store / the
|
|
112
|
+
* config file. `max-age` returns the validated positive day count.
|
|
113
|
+
*/
|
|
114
|
+
export declare function parseCleanupCommand(rawInput: string): {
|
|
115
|
+
action: CleanupCommandAction;
|
|
116
|
+
value?: number;
|
|
117
|
+
} | {
|
|
118
|
+
error: string;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* The 24h auto-sweep throttle. `lastAtMs` of `0` means "never ran" (a fresh
|
|
122
|
+
* process), so the first call always sweeps; after that a call within 24h is
|
|
123
|
+
* a no-op, matching the "every machine at most once per day" model.
|
|
124
|
+
*/
|
|
125
|
+
export declare function shouldRunAutoSweep(lastAtMs: number, nowMs: number): boolean;
|