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.
Files changed (43) hide show
  1. package/dist/bin/wangchuan.js +29 -1
  2. package/dist/bin/wangchuan.js.map +1 -1
  3. package/dist/src/commands/doctor.d.ts.map +1 -1
  4. package/dist/src/commands/doctor.js +10 -0
  5. package/dist/src/commands/doctor.js.map +1 -1
  6. package/dist/src/commands/history.d.ts +11 -0
  7. package/dist/src/commands/history.d.ts.map +1 -0
  8. package/dist/src/commands/history.js +40 -0
  9. package/dist/src/commands/history.js.map +1 -0
  10. package/dist/src/commands/pull.d.ts +1 -1
  11. package/dist/src/commands/pull.d.ts.map +1 -1
  12. package/dist/src/commands/pull.js +20 -4
  13. package/dist/src/commands/pull.js.map +1 -1
  14. package/dist/src/commands/push.d.ts +1 -1
  15. package/dist/src/commands/push.d.ts.map +1 -1
  16. package/dist/src/commands/push.js +25 -5
  17. package/dist/src/commands/push.js.map +1 -1
  18. package/dist/src/commands/snapshot.d.ts +16 -0
  19. package/dist/src/commands/snapshot.d.ts.map +1 -0
  20. package/dist/src/commands/snapshot.js +193 -0
  21. package/dist/src/commands/snapshot.js.map +1 -0
  22. package/dist/src/commands/sync.d.ts +1 -1
  23. package/dist/src/commands/sync.d.ts.map +1 -1
  24. package/dist/src/commands/sync.js +28 -6
  25. package/dist/src/commands/sync.js.map +1 -1
  26. package/dist/src/core/sync-history.d.ts +20 -0
  27. package/dist/src/core/sync-history.d.ts.map +1 -0
  28. package/dist/src/core/sync-history.js +39 -0
  29. package/dist/src/core/sync-history.js.map +1 -0
  30. package/dist/src/core/sync.d.ts +25 -9
  31. package/dist/src/core/sync.d.ts.map +1 -1
  32. package/dist/src/core/sync.js +156 -17
  33. package/dist/src/core/sync.js.map +1 -1
  34. package/dist/src/i18n.d.ts.map +1 -1
  35. package/dist/src/i18n.js +31 -0
  36. package/dist/src/i18n.js.map +1 -1
  37. package/dist/src/types.d.ts +11 -4
  38. package/dist/src/types.d.ts.map +1 -1
  39. package/dist/test/sync-history.test.d.ts +5 -0
  40. package/dist/test/sync-history.test.d.ts.map +1 -0
  41. package/dist/test/sync-history.test.js +111 -0
  42. package/dist/test/sync-history.test.js.map +1 -0
  43. package/package.json +2 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-history.test.d.ts","sourceRoot":"","sources":["../../test/sync-history.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * sync-history.test.ts — Tests for sync-history and ignore patterns
3
+ */
4
+ import { describe, it, after } from 'node:test';
5
+ import assert from 'node:assert/strict';
6
+ import fs from 'fs';
7
+ import os from 'os';
8
+ import path from 'path';
9
+ import { readSyncHistory, appendSyncEvent } from '../src/core/sync-history.js';
10
+ import { matchesIgnore } from '../src/core/sync.js';
11
+ // ── Test fixtures ────────────────────────────────────────────────────
12
+ const TMP = fs.mkdtempSync(path.join(os.tmpdir(), 'wc-history-'));
13
+ after(() => {
14
+ fs.rmSync(TMP, { recursive: true, force: true });
15
+ });
16
+ function mkEvent(overrides) {
17
+ return {
18
+ timestamp: new Date().toISOString(),
19
+ action: 'push',
20
+ environment: 'default',
21
+ fileCount: 5,
22
+ encrypted: 2,
23
+ hostname: 'test-host',
24
+ ...overrides,
25
+ };
26
+ }
27
+ // ── sync-history tests ───────────────────────────────────────────────
28
+ describe('sync-history', () => {
29
+ it('appendSyncEvent + readSyncHistory round-trip', () => {
30
+ const historyPath = path.join(TMP, 'history-roundtrip.json');
31
+ const event = mkEvent({ action: 'pull', fileCount: 10 });
32
+ appendSyncEvent(event, historyPath);
33
+ const events = readSyncHistory(historyPath);
34
+ assert.equal(events.length, 1);
35
+ assert.equal(events[0].action, 'pull');
36
+ assert.equal(events[0].fileCount, 10);
37
+ assert.equal(events[0].hostname, 'test-host');
38
+ });
39
+ it('multiple appends accumulate in order', () => {
40
+ const historyPath = path.join(TMP, 'history-multi.json');
41
+ appendSyncEvent(mkEvent({ action: 'push', fileCount: 1 }), historyPath);
42
+ appendSyncEvent(mkEvent({ action: 'pull', fileCount: 2 }), historyPath);
43
+ appendSyncEvent(mkEvent({ action: 'sync', fileCount: 3 }), historyPath);
44
+ const events = readSyncHistory(historyPath);
45
+ assert.equal(events.length, 3);
46
+ assert.equal(events[0].action, 'push');
47
+ assert.equal(events[1].action, 'pull');
48
+ assert.equal(events[2].action, 'sync');
49
+ });
50
+ it('FIFO rotation: 105 events → only 100 remain', () => {
51
+ const historyPath = path.join(TMP, 'history-fifo.json');
52
+ for (let i = 0; i < 105; i++) {
53
+ appendSyncEvent(mkEvent({ fileCount: i }), historyPath);
54
+ }
55
+ const events = readSyncHistory(historyPath);
56
+ assert.equal(events.length, 100);
57
+ // First event should be the 6th one (index 5), since first 5 were evicted
58
+ assert.equal(events[0].fileCount, 5);
59
+ // Last event should be index 104
60
+ assert.equal(events[99].fileCount, 104);
61
+ });
62
+ it('readSyncHistory returns empty array for missing file', () => {
63
+ const events = readSyncHistory(path.join(TMP, 'nonexistent.json'));
64
+ assert.deepStrictEqual(events, []);
65
+ });
66
+ it('readSyncHistory returns empty array for corrupted file', () => {
67
+ const historyPath = path.join(TMP, 'history-corrupt.json');
68
+ fs.writeFileSync(historyPath, '{ not valid json array!!!', 'utf-8');
69
+ const events = readSyncHistory(historyPath);
70
+ assert.deepStrictEqual(events, []);
71
+ });
72
+ it('optional fields (agent, sha) round-trip correctly', () => {
73
+ const historyPath = path.join(TMP, 'history-optional.json');
74
+ appendSyncEvent(mkEvent({ agent: 'claude', sha: 'abc123' }), historyPath);
75
+ const events = readSyncHistory(historyPath);
76
+ assert.equal(events[0].agent, 'claude');
77
+ assert.equal(events[0].sha, 'abc123');
78
+ });
79
+ });
80
+ // ── matchesIgnore tests ──────────────────────────────────────────────
81
+ describe('matchesIgnore', () => {
82
+ it('matches simple wildcard pattern against basename', () => {
83
+ assert.ok(matchesIgnore('some/dir/file.tmp', ['*.tmp']));
84
+ assert.ok(matchesIgnore('file.log', ['*.log']));
85
+ assert.ok(!matchesIgnore('file.md', ['*.tmp']));
86
+ });
87
+ it('matches exact filename pattern', () => {
88
+ assert.ok(matchesIgnore('some/path/.DS_Store', ['.DS_Store']));
89
+ assert.ok(!matchesIgnore('some/path/file.txt', ['.DS_Store']));
90
+ });
91
+ it('matches ** patterns against full relative path', () => {
92
+ assert.ok(matchesIgnore('a/node_modules/pkg/index.js', ['**/node_modules/**']));
93
+ assert.ok(matchesIgnore('node_modules/pkg/index.js', ['**/node_modules/**']));
94
+ assert.ok(!matchesIgnore('a/other/pkg/index.js', ['**/node_modules/**']));
95
+ });
96
+ it('matches path patterns with /', () => {
97
+ assert.ok(matchesIgnore('build/output.js', ['build/*.js']));
98
+ assert.ok(!matchesIgnore('src/output.js', ['build/*.js']));
99
+ });
100
+ it('returns false for empty patterns list', () => {
101
+ assert.ok(!matchesIgnore('anything.txt', []));
102
+ });
103
+ it('matches multiple patterns (any match → true)', () => {
104
+ const patterns = ['*.tmp', '*.log', '.DS_Store'];
105
+ assert.ok(matchesIgnore('debug.log', patterns));
106
+ assert.ok(matchesIgnore('cache.tmp', patterns));
107
+ assert.ok(matchesIgnore('.DS_Store', patterns));
108
+ assert.ok(!matchesIgnore('readme.md', patterns));
109
+ });
110
+ });
111
+ //# sourceMappingURL=sync-history.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-history.test.js","sourceRoot":"","sources":["../../test/sync-history.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wangchuan",
3
- "version": "2.11.0",
3
+ "version": "2.13.0",
4
4
  "description": "忘川 · AI 记忆同步系统 — 智能体记忆永不遗失",
5
5
  "bin": {
6
6
  "wangchuan": "./dist/bin/wangchuan.js"
@@ -17,7 +17,7 @@
17
17
  "postbuild": "chmod +x dist/bin/wangchuan.js",
18
18
  "prepublishOnly": "npm run build",
19
19
  "dev": "tsx bin/wangchuan.ts",
20
- "test": "node --import tsx/esm --test test/crypto.test.ts test/json-field.test.ts test/sync.test.ts",
20
+ "test": "node --import tsx/esm --test test/crypto.test.ts test/json-field.test.ts test/sync.test.ts test/sync-history.test.ts",
21
21
  "typecheck": "tsc --noEmit"
22
22
  },
23
23
  "keywords": [