wangchuan 2.11.0 → 2.13.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/dist/bin/wangchuan.js +29 -1
- package/dist/bin/wangchuan.js.map +1 -1
- package/dist/src/commands/doctor.d.ts.map +1 -1
- package/dist/src/commands/doctor.js +10 -0
- package/dist/src/commands/doctor.js.map +1 -1
- package/dist/src/commands/history.d.ts +11 -0
- package/dist/src/commands/history.d.ts.map +1 -0
- package/dist/src/commands/history.js +40 -0
- package/dist/src/commands/history.js.map +1 -0
- package/dist/src/commands/pull.d.ts +1 -1
- package/dist/src/commands/pull.d.ts.map +1 -1
- package/dist/src/commands/pull.js +20 -4
- package/dist/src/commands/pull.js.map +1 -1
- package/dist/src/commands/push.d.ts +1 -1
- package/dist/src/commands/push.d.ts.map +1 -1
- package/dist/src/commands/push.js +25 -5
- package/dist/src/commands/push.js.map +1 -1
- package/dist/src/commands/snapshot.d.ts +16 -0
- package/dist/src/commands/snapshot.d.ts.map +1 -0
- package/dist/src/commands/snapshot.js +193 -0
- package/dist/src/commands/snapshot.js.map +1 -0
- package/dist/src/commands/sync.d.ts +1 -1
- package/dist/src/commands/sync.d.ts.map +1 -1
- package/dist/src/commands/sync.js +28 -6
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/core/sync-history.d.ts +20 -0
- package/dist/src/core/sync-history.d.ts.map +1 -0
- package/dist/src/core/sync-history.js +39 -0
- package/dist/src/core/sync-history.js.map +1 -0
- package/dist/src/core/sync.d.ts +25 -9
- package/dist/src/core/sync.d.ts.map +1 -1
- package/dist/src/core/sync.js +156 -17
- package/dist/src/core/sync.js.map +1 -1
- package/dist/src/i18n.d.ts.map +1 -1
- package/dist/src/i18n.js +31 -0
- package/dist/src/i18n.js.map +1 -1
- package/dist/src/types.d.ts +11 -4
- package/dist/src/types.d.ts.map +1 -1
- package/dist/test/sync-history.test.d.ts +5 -0
- package/dist/test/sync-history.test.d.ts.map +1 -0
- package/dist/test/sync-history.test.js +111 -0
- package/dist/test/sync-history.test.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* snapshot.ts — wangchuan snapshot command
|
|
3
|
+
*
|
|
4
|
+
* Manage named snapshots of the current repo state for lightweight version history.
|
|
5
|
+
* snapshot save [name] — copy repo state to ~/.wangchuan/snapshots/{name|timestamp}
|
|
6
|
+
* snapshot list — show all snapshots with metadata
|
|
7
|
+
* snapshot restore <name> — restore snapshot to repo dir, then run restoreFromRepo
|
|
8
|
+
* snapshot delete <name> — remove a snapshot
|
|
9
|
+
*/
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import os from 'os';
|
|
13
|
+
import { config } from '../core/config.js';
|
|
14
|
+
import { ensureMigrated } from '../core/migrate.js';
|
|
15
|
+
import { syncEngine } from '../core/sync.js';
|
|
16
|
+
import { validator } from '../utils/validator.js';
|
|
17
|
+
import { logger } from '../utils/logger.js';
|
|
18
|
+
import { t } from '../i18n.js';
|
|
19
|
+
import chalk from 'chalk';
|
|
20
|
+
const WANGCHUAN_DIR = path.join(os.homedir(), '.wangchuan');
|
|
21
|
+
const SNAPSHOTS_DIR = path.join(WANGCHUAN_DIR, 'snapshots');
|
|
22
|
+
const DEFAULT_MAX = 10;
|
|
23
|
+
// ── Helpers ──────────────────────────────────────────────────────
|
|
24
|
+
function ensureSnapshotsDir() {
|
|
25
|
+
fs.mkdirSync(SNAPSHOTS_DIR, { recursive: true });
|
|
26
|
+
}
|
|
27
|
+
/** Recursively copy a directory */
|
|
28
|
+
function copyDirSync(src, dest) {
|
|
29
|
+
let count = 0;
|
|
30
|
+
if (!fs.existsSync(src))
|
|
31
|
+
return count;
|
|
32
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
33
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
34
|
+
const srcPath = path.join(src, entry.name);
|
|
35
|
+
const destPath = path.join(dest, entry.name);
|
|
36
|
+
if (entry.isDirectory()) {
|
|
37
|
+
count += copyDirSync(srcPath, destPath);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
fs.copyFileSync(srcPath, destPath);
|
|
41
|
+
count++;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return count;
|
|
45
|
+
}
|
|
46
|
+
/** Calculate total size of a directory in bytes */
|
|
47
|
+
function dirSize(dirPath) {
|
|
48
|
+
let total = 0;
|
|
49
|
+
if (!fs.existsSync(dirPath))
|
|
50
|
+
return total;
|
|
51
|
+
for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) {
|
|
52
|
+
const full = path.join(dirPath, entry.name);
|
|
53
|
+
if (entry.isDirectory()) {
|
|
54
|
+
total += dirSize(full);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
total += fs.statSync(full).size;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return total;
|
|
61
|
+
}
|
|
62
|
+
function formatBytes(bytes) {
|
|
63
|
+
if (bytes < 1024)
|
|
64
|
+
return `${bytes}B`;
|
|
65
|
+
if (bytes < 1024 * 1024)
|
|
66
|
+
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
67
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
68
|
+
}
|
|
69
|
+
/** Prune oldest snapshots when count exceeds max */
|
|
70
|
+
function pruneSnapshots(max) {
|
|
71
|
+
if (!fs.existsSync(SNAPSHOTS_DIR))
|
|
72
|
+
return 0;
|
|
73
|
+
const dirs = fs.readdirSync(SNAPSHOTS_DIR)
|
|
74
|
+
.filter(d => fs.statSync(path.join(SNAPSHOTS_DIR, d)).isDirectory())
|
|
75
|
+
.sort();
|
|
76
|
+
if (dirs.length <= max)
|
|
77
|
+
return 0;
|
|
78
|
+
const toRemove = dirs.slice(0, dirs.length - max);
|
|
79
|
+
for (const dir of toRemove) {
|
|
80
|
+
fs.rmSync(path.join(SNAPSHOTS_DIR, dir), { recursive: true, force: true });
|
|
81
|
+
}
|
|
82
|
+
return toRemove.length;
|
|
83
|
+
}
|
|
84
|
+
// ── Actions ─────────────────────────────────────────────────────
|
|
85
|
+
function snapshotSave(repoPath, name, maxSnapshots) {
|
|
86
|
+
ensureSnapshotsDir();
|
|
87
|
+
const snapshotName = name ?? new Date().toISOString().replace(/[:.]/g, '-');
|
|
88
|
+
const snapshotDir = path.join(SNAPSHOTS_DIR, snapshotName);
|
|
89
|
+
if (fs.existsSync(snapshotDir)) {
|
|
90
|
+
fs.rmSync(snapshotDir, { recursive: true, force: true });
|
|
91
|
+
}
|
|
92
|
+
const fileCount = copyDirSync(repoPath, snapshotDir);
|
|
93
|
+
const totalBytes = dirSize(snapshotDir);
|
|
94
|
+
// Write metadata
|
|
95
|
+
const meta = {
|
|
96
|
+
createdAt: new Date().toISOString(),
|
|
97
|
+
fileCount,
|
|
98
|
+
totalBytes,
|
|
99
|
+
};
|
|
100
|
+
fs.writeFileSync(path.join(snapshotDir, '.snapshot-meta.json'), JSON.stringify(meta, null, 2), 'utf-8');
|
|
101
|
+
logger.ok(t('snapshot.saved', { name: snapshotName, count: fileCount }));
|
|
102
|
+
// Auto-prune
|
|
103
|
+
const pruned = pruneSnapshots(maxSnapshots);
|
|
104
|
+
if (pruned > 0) {
|
|
105
|
+
logger.info(t('snapshot.pruned', { count: pruned, max: maxSnapshots }));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function snapshotList() {
|
|
109
|
+
ensureSnapshotsDir();
|
|
110
|
+
const dirs = fs.readdirSync(SNAPSHOTS_DIR)
|
|
111
|
+
.filter(d => fs.statSync(path.join(SNAPSHOTS_DIR, d)).isDirectory())
|
|
112
|
+
.sort()
|
|
113
|
+
.reverse();
|
|
114
|
+
if (dirs.length === 0) {
|
|
115
|
+
logger.info(t('snapshot.listEmpty'));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
logger.info(t('snapshot.listHeader'));
|
|
119
|
+
for (const dir of dirs) {
|
|
120
|
+
const snapshotDir = path.join(SNAPSHOTS_DIR, dir);
|
|
121
|
+
const metaPath = path.join(snapshotDir, '.snapshot-meta.json');
|
|
122
|
+
let meta;
|
|
123
|
+
try {
|
|
124
|
+
meta = JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
|
|
125
|
+
}
|
|
126
|
+
catch { /* no metadata */ }
|
|
127
|
+
const time = meta?.createdAt ?? '—';
|
|
128
|
+
const count = meta?.fileCount ?? 0;
|
|
129
|
+
const size = meta ? formatBytes(meta.totalBytes) : '—';
|
|
130
|
+
logger.info(` ${chalk.cyan(dir)} ${chalk.gray(time)} ${count} files ${chalk.gray(size)}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async function snapshotRestore(repoPath, name) {
|
|
134
|
+
const snapshotDir = path.join(SNAPSHOTS_DIR, name);
|
|
135
|
+
if (!fs.existsSync(snapshotDir)) {
|
|
136
|
+
throw new Error(t('snapshot.notFound', { name }));
|
|
137
|
+
}
|
|
138
|
+
// Copy snapshot content back to repo dir (skip metadata file)
|
|
139
|
+
for (const entry of fs.readdirSync(snapshotDir, { withFileTypes: true })) {
|
|
140
|
+
if (entry.name === '.snapshot-meta.json')
|
|
141
|
+
continue;
|
|
142
|
+
const src = path.join(snapshotDir, entry.name);
|
|
143
|
+
const dest = path.join(repoPath, entry.name);
|
|
144
|
+
if (entry.isDirectory()) {
|
|
145
|
+
copyDirSync(src, dest);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
149
|
+
fs.copyFileSync(src, dest);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
logger.ok(t('snapshot.restored', { name }));
|
|
153
|
+
}
|
|
154
|
+
function snapshotDelete(name) {
|
|
155
|
+
const snapshotDir = path.join(SNAPSHOTS_DIR, name);
|
|
156
|
+
if (!fs.existsSync(snapshotDir)) {
|
|
157
|
+
throw new Error(t('snapshot.notFound', { name }));
|
|
158
|
+
}
|
|
159
|
+
fs.rmSync(snapshotDir, { recursive: true, force: true });
|
|
160
|
+
logger.ok(t('snapshot.deleted', { name }));
|
|
161
|
+
}
|
|
162
|
+
// ── Command entry ───────────────────────────────────────────────
|
|
163
|
+
export async function cmdSnapshot({ action, name, maxSnapshots }) {
|
|
164
|
+
logger.banner(t('snapshot.banner'));
|
|
165
|
+
let cfg = config.load();
|
|
166
|
+
validator.requireInit(cfg);
|
|
167
|
+
cfg = ensureMigrated(cfg);
|
|
168
|
+
const repoPath = syncEngine.expandHome(cfg.localRepoPath);
|
|
169
|
+
const max = maxSnapshots ?? DEFAULT_MAX;
|
|
170
|
+
switch (action) {
|
|
171
|
+
case 'save':
|
|
172
|
+
snapshotSave(repoPath, name, max);
|
|
173
|
+
break;
|
|
174
|
+
case 'list':
|
|
175
|
+
snapshotList();
|
|
176
|
+
break;
|
|
177
|
+
case 'restore':
|
|
178
|
+
if (!name)
|
|
179
|
+
throw new Error(t('snapshot.nameRequired'));
|
|
180
|
+
await snapshotRestore(repoPath, name);
|
|
181
|
+
// After restoring snapshot to repo, also restore files to workspace
|
|
182
|
+
await syncEngine.restoreFromRepo(cfg);
|
|
183
|
+
break;
|
|
184
|
+
case 'delete':
|
|
185
|
+
if (!name)
|
|
186
|
+
throw new Error(t('snapshot.nameRequired'));
|
|
187
|
+
snapshotDelete(name);
|
|
188
|
+
break;
|
|
189
|
+
default:
|
|
190
|
+
throw new Error(t('snapshot.unknownAction', { action }));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../../src/commands/snapshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,5 +14,5 @@ export interface SyncCommandResult {
|
|
|
14
14
|
readonly stageResult?: StageResult | undefined;
|
|
15
15
|
}) | undefined;
|
|
16
16
|
}
|
|
17
|
-
export declare function cmdSync({ agent, dryRun }?: SyncOptions): Promise<SyncCommandResult>;
|
|
17
|
+
export declare function cmdSync({ agent, dryRun, only, exclude }?: SyncOptions): Promise<SyncCommandResult>;
|
|
18
18
|
//# sourceMappingURL=sync.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/commands/sync.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/commands/sync.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAiB,MAAM,aAAa,CAAC;AAIxG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,YAAY,GAAG;QAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;KAAE,CAAC,GAAG,SAAS,CAAC;CACvG;AAED,wBAAsB,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAE,WAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuB5G"}
|
|
@@ -12,12 +12,13 @@ import { ensureMigrated } from '../core/migrate.js';
|
|
|
12
12
|
import { gitEngine } from '../core/git.js';
|
|
13
13
|
import { syncEngine } from '../core/sync.js';
|
|
14
14
|
import { syncLock } from '../core/sync-lock.js';
|
|
15
|
+
import { appendSyncEvent } from '../core/sync-history.js';
|
|
15
16
|
import { validator } from '../utils/validator.js';
|
|
16
17
|
import { logger } from '../utils/logger.js';
|
|
17
18
|
import { t } from '../i18n.js';
|
|
18
19
|
import chalk from 'chalk';
|
|
19
20
|
import ora from 'ora';
|
|
20
|
-
export async function cmdSync({ agent, dryRun } = {}) {
|
|
21
|
+
export async function cmdSync({ agent, dryRun, only, exclude } = {}) {
|
|
21
22
|
logger.banner(t('sync.banner'));
|
|
22
23
|
let cfg = config.load();
|
|
23
24
|
validator.requireInit(cfg);
|
|
@@ -26,18 +27,23 @@ export async function cmdSync({ agent, dryRun } = {}) {
|
|
|
26
27
|
const hostname = cfg.hostname || os.hostname();
|
|
27
28
|
if (agent)
|
|
28
29
|
logger.info(t('sync.filterAgent', { agent: chalk.cyan(agent) }));
|
|
30
|
+
if (only?.length)
|
|
31
|
+
logger.info(t('filter.only', { patterns: only.join(', ') }));
|
|
32
|
+
if (exclude?.length)
|
|
33
|
+
logger.info(t('filter.exclude', { patterns: exclude.join(', ') }));
|
|
29
34
|
if (dryRun)
|
|
30
35
|
logger.info(chalk.yellow(t('dryRun.enabled')));
|
|
36
|
+
const filter = (only?.length || exclude?.length) ? { only, exclude } : undefined;
|
|
31
37
|
// ── Acquire sync lock ─────────────────────────────────────────
|
|
32
38
|
await syncLock.acquire(repoPath);
|
|
33
39
|
try {
|
|
34
|
-
return await runSync(cfg, repoPath, hostname, agent, dryRun);
|
|
40
|
+
return await runSync(cfg, repoPath, hostname, agent, dryRun, filter);
|
|
35
41
|
}
|
|
36
42
|
finally {
|
|
37
43
|
syncLock.release();
|
|
38
44
|
}
|
|
39
45
|
}
|
|
40
|
-
async function runSync(cfg, repoPath, hostname, agent, dryRun) {
|
|
46
|
+
async function runSync(cfg, repoPath, hostname, agent, dryRun, filter) {
|
|
41
47
|
let spinner = ora(t('sync.fetching')).start();
|
|
42
48
|
let remoteAhead = 0;
|
|
43
49
|
try {
|
|
@@ -67,7 +73,7 @@ async function runSync(cfg, repoPath, hostname, agent, dryRun) {
|
|
|
67
73
|
throw new Error(t('sync.pullFailedDetail', { error: err.message }));
|
|
68
74
|
}
|
|
69
75
|
try {
|
|
70
|
-
pullResult = await syncEngine.restoreFromRepo(cfg, agent);
|
|
76
|
+
pullResult = await syncEngine.restoreFromRepo(cfg, agent, filter);
|
|
71
77
|
pulled = true;
|
|
72
78
|
if (pullResult.synced.length > 0) {
|
|
73
79
|
logger.ok(t('sync.pullSummary', {
|
|
@@ -84,8 +90,9 @@ async function runSync(cfg, repoPath, hostname, agent, dryRun) {
|
|
|
84
90
|
spinner = ora(t('sync.staging')).start();
|
|
85
91
|
let stageResult;
|
|
86
92
|
try {
|
|
87
|
-
stageResult = await syncEngine.stageToRepo(cfg, agent);
|
|
88
|
-
spinner.succeed(t('sync.staged', { count: stageResult.synced.length })
|
|
93
|
+
stageResult = await syncEngine.stageToRepo(cfg, agent, filter);
|
|
94
|
+
spinner.succeed(t('sync.staged', { count: stageResult.synced.length }) +
|
|
95
|
+
(stageResult.unchanged.length > 0 ? ' ' + t('push.unchangedSummary', { count: stageResult.unchanged.length }) : ''));
|
|
89
96
|
}
|
|
90
97
|
catch (err) {
|
|
91
98
|
spinner.fail(t('sync.stagingFailed'));
|
|
@@ -155,6 +162,21 @@ async function runSync(cfg, repoPath, hostname, agent, dryRun) {
|
|
|
155
162
|
if (!pulled && !pushResult.committed) {
|
|
156
163
|
logger.ok(t('sync.alreadyInSync'));
|
|
157
164
|
}
|
|
165
|
+
// Record sync history
|
|
166
|
+
const totalFiles = (pullResult?.synced.length ?? 0) + (pushResult.stageResult?.synced.length ?? 0);
|
|
167
|
+
const totalEncrypted = (pullResult?.decrypted.length ?? 0) + (pushResult.stageResult?.encrypted.length ?? 0);
|
|
168
|
+
if (pulled || pushResult.committed) {
|
|
169
|
+
appendSyncEvent({
|
|
170
|
+
timestamp: new Date().toISOString(),
|
|
171
|
+
action: 'sync',
|
|
172
|
+
environment: cfg.environment ?? 'default',
|
|
173
|
+
agent: agent,
|
|
174
|
+
fileCount: totalFiles,
|
|
175
|
+
encrypted: totalEncrypted,
|
|
176
|
+
sha: pushResult.sha,
|
|
177
|
+
hostname,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
158
180
|
return { pulled, pullResult, pushed: pushResult.committed, pushResult };
|
|
159
181
|
}
|
|
160
182
|
//# sourceMappingURL=sync.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../../src/commands/sync.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,MAAM,EAAE,MAAe,mBAAmB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAO,oBAAoB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAY,gBAAgB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAW,iBAAiB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAa,sBAAsB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAY,uBAAuB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAe,oBAAoB,CAAC;AACrD,OAAO,EAAE,CAAC,EAAE,MAAoB,YAAY,CAAC;AAE7C,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAQ,KAAK,CAAC;AASxB,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,KAAkB,EAAE;
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../../src/commands/sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sync-history.ts — Append-only sync event log
|
|
3
|
+
*
|
|
4
|
+
* Stores sync events in ~/.wangchuan/sync-history.json (max 100 entries, FIFO).
|
|
5
|
+
*/
|
|
6
|
+
export interface SyncEvent {
|
|
7
|
+
readonly timestamp: string;
|
|
8
|
+
readonly action: 'push' | 'pull' | 'sync';
|
|
9
|
+
readonly environment: string;
|
|
10
|
+
readonly agent?: string | undefined;
|
|
11
|
+
readonly fileCount: number;
|
|
12
|
+
readonly encrypted: number;
|
|
13
|
+
readonly sha?: string | undefined;
|
|
14
|
+
readonly hostname: string;
|
|
15
|
+
}
|
|
16
|
+
/** Read all sync events from history file */
|
|
17
|
+
export declare function readSyncHistory(historyPath?: string): SyncEvent[];
|
|
18
|
+
/** Append a sync event, keeping at most MAX_ENTRIES (FIFO) */
|
|
19
|
+
export declare function appendSyncEvent(event: SyncEvent, historyPath?: string): void;
|
|
20
|
+
//# sourceMappingURL=sync-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-history.d.ts","sourceRoot":"","sources":["../../../src/core/sync-history.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAC1C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,6CAA6C;AAC7C,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,CAWjE;AAED,8DAA8D;AAC9D,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAY5E"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sync-history.ts — Append-only sync event log
|
|
3
|
+
*
|
|
4
|
+
* Stores sync events in ~/.wangchuan/sync-history.json (max 100 entries, FIFO).
|
|
5
|
+
*/
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import os from 'os';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
const HISTORY_PATH = path.join(os.homedir(), '.wangchuan', 'sync-history.json');
|
|
10
|
+
const MAX_ENTRIES = 100;
|
|
11
|
+
/** Read all sync events from history file */
|
|
12
|
+
export function readSyncHistory(historyPath) {
|
|
13
|
+
const p = historyPath ?? HISTORY_PATH;
|
|
14
|
+
if (!fs.existsSync(p))
|
|
15
|
+
return [];
|
|
16
|
+
try {
|
|
17
|
+
const raw = fs.readFileSync(p, 'utf-8');
|
|
18
|
+
const parsed = JSON.parse(raw);
|
|
19
|
+
if (!Array.isArray(parsed))
|
|
20
|
+
return [];
|
|
21
|
+
return parsed;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** Append a sync event, keeping at most MAX_ENTRIES (FIFO) */
|
|
28
|
+
export function appendSyncEvent(event, historyPath) {
|
|
29
|
+
const p = historyPath ?? HISTORY_PATH;
|
|
30
|
+
const events = readSyncHistory(p);
|
|
31
|
+
events.push(event);
|
|
32
|
+
// FIFO: keep only the last MAX_ENTRIES
|
|
33
|
+
const trimmed = events.length > MAX_ENTRIES
|
|
34
|
+
? events.slice(events.length - MAX_ENTRIES)
|
|
35
|
+
: events;
|
|
36
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
37
|
+
fs.writeFileSync(p, JSON.stringify(trimmed, null, 2), 'utf-8');
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=sync-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-history.js","sourceRoot":"","sources":["../../../src/core/sync-history.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAQ,IAAI,CAAC;AACtB,OAAO,EAAE,MAAQ,IAAI,CAAC;AACtB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,mBAAmB,CAAC,CAAC;AAChF,MAAM,WAAW,GAAI,GAAG,CAAC;AAazB,6CAA6C;AAC7C,MAAM,UAAU,eAAe,CAAC,WAAoB;IAClD,MAAM,CAAC,GAAG,WAAW,IAAI,YAAY,CAAC;IACtC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,CAAC;QACtC,OAAO,MAAqB,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,eAAe,CAAC,KAAgB,EAAE,WAAoB;IACpE,MAAM,CAAC,GAAG,WAAW,IAAI,YAAY,CAAC;IACtC,MAAM,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAEnB,uCAAuC;IACvC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,GAAG,WAAW;QACzC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,WAAW,CAAC;QAC3C,CAAC,CAAC,MAAM,CAAC;IAEX,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AACjE,CAAC"}
|
package/dist/src/core/sync.d.ts
CHANGED
|
@@ -12,15 +12,31 @@
|
|
|
12
12
|
*
|
|
13
13
|
* 所有方法支持可选的 agent 过滤参数,只操作指定智能体的文件。
|
|
14
14
|
*/
|
|
15
|
-
import type { WangchuanConfig, FileEntry, StageResult, RestoreResult, DiffResult, AgentName } from '../types.js';
|
|
15
|
+
import type { WangchuanConfig, FileEntry, StageResult, RestoreResult, DiffResult, AgentName, FilterOptions } from '../types.js';
|
|
16
16
|
export declare function expandHome(p: string): string;
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* Load ignore patterns from ~/.wangchuan/.wangchuanignore.
|
|
19
|
+
* One glob per line, '#' comments and empty lines are skipped.
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadIgnorePatterns(): string[];
|
|
22
|
+
/** Reset the cached ignore patterns (for testing) */
|
|
23
|
+
export declare function resetIgnoreCache(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Check if a relative path matches any ignore pattern.
|
|
26
|
+
* Supports:
|
|
27
|
+
* - Simple globs with `*` (matches anything except `/`)
|
|
28
|
+
* - `**` matches any number of path segments (including zero)
|
|
29
|
+
* - Basename-only patterns (no `/`) match against the filename
|
|
30
|
+
*/
|
|
31
|
+
export declare function matchesIgnore(relPath: string, patterns: readonly string[]): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Build the list of file entries to sync (single source of truth for all sync directions).
|
|
19
34
|
*
|
|
20
|
-
* @param repoDirBase
|
|
21
|
-
* @param agent
|
|
35
|
+
* @param repoDirBase Pass local repo root to scan syncDirs from repo side (pull direction)
|
|
36
|
+
* @param agent Only return entries for specified agent, undefined = all
|
|
37
|
+
* @param filter Optional --only / --exclude filtering
|
|
22
38
|
*/
|
|
23
|
-
export declare function buildFileEntries(cfg: WangchuanConfig, repoDirBase?: string, agent?: AgentName): FileEntry[];
|
|
39
|
+
export declare function buildFileEntries(cfg: WangchuanConfig, repoDirBase?: string, agent?: AgentName, filter?: FilterOptions): FileEntry[];
|
|
24
40
|
/** Sync metadata stored in repo root */
|
|
25
41
|
export interface SyncMeta {
|
|
26
42
|
readonly lastSyncAt: string;
|
|
@@ -33,11 +49,11 @@ export declare const syncEngine: {
|
|
|
33
49
|
readonly buildFileEntries: typeof buildFileEntries;
|
|
34
50
|
readonly readSyncMeta: typeof readSyncMeta;
|
|
35
51
|
/**
|
|
36
|
-
*
|
|
52
|
+
* Push: distribute shared content to all agents, then collect files to repo.
|
|
37
53
|
*/
|
|
38
|
-
readonly stageToRepo: (cfg: WangchuanConfig, agent?: AgentName) => Promise<StageResult>;
|
|
39
|
-
readonly restoreFromRepo: (cfg: WangchuanConfig, agent?: AgentName) => Promise<RestoreResult>;
|
|
40
|
-
readonly diff: (cfg: WangchuanConfig, agent?: AgentName) => Promise<DiffResult>;
|
|
54
|
+
readonly stageToRepo: (cfg: WangchuanConfig, agent?: AgentName, filter?: FilterOptions) => Promise<StageResult>;
|
|
55
|
+
readonly restoreFromRepo: (cfg: WangchuanConfig, agent?: AgentName, filter?: FilterOptions) => Promise<RestoreResult>;
|
|
56
|
+
readonly diff: (cfg: WangchuanConfig, agent?: AgentName, filter?: FilterOptions) => Promise<DiffResult>;
|
|
41
57
|
};
|
|
42
58
|
export {};
|
|
43
59
|
//# sourceMappingURL=sync.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/core/sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAaH,OAAO,KAAK,EACV,eAAe,EACf,SAAS,EACT,WAAW,EACX,aAAa,EACb,UAAU,EACV,SAAS,
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/core/sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAaH,OAAO,KAAK,EACV,eAAe,EACf,SAAS,EACT,WAAW,EACX,aAAa,EACb,UAAU,EACV,SAAS,EAET,aAAa,EACd,MAAM,aAAa,CAAC;AAGrB,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG5C;AAQD;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAW7C;AAED,qDAAqD;AACrD,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAenF;AA0OD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,eAAe,EACpB,WAAW,CAAC,EAAE,MAAM,EACpB,KAAK,CAAC,EAAE,SAAS,EACjB,MAAM,CAAC,EAAE,aAAa,GACrB,SAAS,EAAE,CAiBb;AAuID,wCAAwC;AACxC,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAiBD,iBAAS,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAQvD;AAyJD,eAAO,MAAM,UAAU;;;;IAKrB;;OAEG;gCACoB,eAAe,UAAU,SAAS,WAAW,aAAa,KAAG,OAAO,CAAC,WAAW,CAAC;oCAsG7E,eAAe,UAAU,SAAS,WAAW,aAAa,KAAG,OAAO,CAAC,aAAa,CAAC;yBA4K9F,eAAe,UAAU,SAAS,WAAW,aAAa,KAAG,OAAO,CAAC,UAAU,CAAC;CAwDxF,CAAC"}
|