@any-sync/cli 0.2.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.
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { describe, it } = require('node:test');
5
+ const assert = require('node:assert');
6
+ const { globMatch, matchesAny } = require('../lib/glob');
7
+
8
+ describe('globMatch', () => {
9
+ it('matches simple extension pattern', () => {
10
+ assert.ok(globMatch('*.md', 'readme.md'));
11
+ assert.ok(globMatch('*.md', 'CHANGELOG.md'));
12
+ assert.ok(!globMatch('*.md', 'readme.txt'));
13
+ assert.ok(!globMatch('*.md', 'dir/readme.md')); // * does not cross /
14
+ });
15
+
16
+ it('matches ** for any depth', () => {
17
+ assert.ok(globMatch('**/*.md', 'readme.md'));
18
+ assert.ok(globMatch('**/*.md', 'dir/readme.md'));
19
+ assert.ok(globMatch('**/*.md', 'a/b/c/readme.md'));
20
+ assert.ok(!globMatch('**/*.md', 'readme.txt'));
21
+ });
22
+
23
+ it('matches ** at end', () => {
24
+ assert.ok(globMatch('dir/**', 'dir/file.md'));
25
+ assert.ok(globMatch('dir/**', 'dir/sub/file.md'));
26
+ });
27
+
28
+ it('matches exact file name', () => {
29
+ assert.ok(globMatch('settings.json', 'settings.json'));
30
+ assert.ok(!globMatch('settings.json', 'other.json'));
31
+ assert.ok(!globMatch('settings.json', 'dir/settings.json'));
32
+ });
33
+
34
+ it('matches ? for single character', () => {
35
+ assert.ok(globMatch('file?.md', 'file1.md'));
36
+ assert.ok(globMatch('file?.md', 'fileA.md'));
37
+ assert.ok(!globMatch('file?.md', 'file12.md'));
38
+ assert.ok(!globMatch('file?.md', 'file.md'));
39
+ });
40
+
41
+ it('matches **/drafts/**', () => {
42
+ assert.ok(globMatch('**/drafts/**', 'drafts/file.md'));
43
+ assert.ok(globMatch('**/drafts/**', 'a/drafts/file.md'));
44
+ assert.ok(globMatch('**/drafts/**', 'a/drafts/b/file.md'));
45
+ assert.ok(!globMatch('**/drafts/**', 'nodrafts/file.md'));
46
+ });
47
+
48
+ it('handles patterns with dots correctly', () => {
49
+ assert.ok(globMatch('*.json', 'package.json'));
50
+ assert.ok(!globMatch('*.json', 'packageXjson'));
51
+ });
52
+ });
53
+
54
+ describe('matchesAny', () => {
55
+ it('returns true if any pattern matches', () => {
56
+ assert.ok(matchesAny(['*.md', '*.txt'], 'readme.md'));
57
+ assert.ok(matchesAny(['*.md', '*.txt'], 'notes.txt'));
58
+ assert.ok(!matchesAny(['*.md', '*.txt'], 'file.json'));
59
+ });
60
+
61
+ it('returns false for empty patterns', () => {
62
+ assert.ok(!matchesAny([], 'anything'));
63
+ });
64
+ });
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ const { describe, it } = require('node:test');
4
+ const assert = require('node:assert/strict');
5
+ const { getPresetMappings } = require('../lib/init');
6
+
7
+ describe('getPresetMappings', () => {
8
+ it('returns 3 mappings for claude preset', () => {
9
+ const mappings = getPresetMappings('claude');
10
+ assert.ok(Array.isArray(mappings));
11
+ assert.equal(mappings.length, 3);
12
+ assert.equal(mappings[0].name, 'claude-skills');
13
+ assert.equal(mappings[1].name, 'claude-memory');
14
+ assert.equal(mappings[2].name, 'claude-settings');
15
+ assert.equal(mappings[0].destPath, '~/.claude/skills');
16
+ });
17
+
18
+ it('returns 3 mappings for openclaw preset', () => {
19
+ const mappings = getPresetMappings('openclaw');
20
+ assert.ok(Array.isArray(mappings));
21
+ assert.equal(mappings.length, 3);
22
+ assert.equal(mappings[0].name, 'workspace-skills');
23
+ assert.equal(mappings[1].name, 'workspace-memory');
24
+ assert.equal(mappings[2].name, 'workspace-config');
25
+ });
26
+
27
+ it('returns null for unknown preset', () => {
28
+ const mappings = getPresetMappings('unknown');
29
+ assert.equal(mappings, null);
30
+ });
31
+ });
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { describe, it, beforeEach, afterEach } = require('node:test');
5
+ const assert = require('node:assert');
6
+ const fs = require('fs');
7
+ const os = require('os');
8
+ const path = require('path');
9
+ const { Lockfile, makeKey, hashFile } = require('../lib/lockfile');
10
+
11
+ describe('Lockfile', () => {
12
+ let tmpFile;
13
+
14
+ beforeEach(() => {
15
+ tmpFile = path.join(os.tmpdir(), 'test-lockfile-' + Date.now() + '.json');
16
+ });
17
+
18
+ afterEach(() => {
19
+ try { fs.unlinkSync(tmpFile); } catch {}
20
+ });
21
+
22
+ it('initializes with empty data when file does not exist', () => {
23
+ const lf = Lockfile.load(tmpFile);
24
+ assert.strictEqual(lf.getEntry('foo'), null);
25
+ });
26
+
27
+ it('sets and gets entries', () => {
28
+ const lf = Lockfile.load(tmpFile);
29
+ lf.setEntry('mymap::file.md', 'abc123', 'def456');
30
+ const entry = lf.getEntry('mymap::file.md');
31
+ assert.strictEqual(entry.remoteSha, 'abc123');
32
+ assert.strictEqual(entry.localHash, 'def456');
33
+ assert.ok(entry.syncedAt);
34
+ });
35
+
36
+ it('saves and reloads', () => {
37
+ const lf = Lockfile.load(tmpFile);
38
+ lf.setEntry('mymap::file.md', 'abc123', 'def456');
39
+ lf.save();
40
+
41
+ const lf2 = Lockfile.load(tmpFile);
42
+ const entry = lf2.getEntry('mymap::file.md');
43
+ assert.strictEqual(entry.remoteSha, 'abc123');
44
+ assert.strictEqual(entry.localHash, 'def456');
45
+ });
46
+
47
+ it('sets and gets lastSync', () => {
48
+ const lf = Lockfile.load(tmpFile);
49
+ lf.setLastSync('mymap');
50
+ const ts = lf.getLastSync('mymap');
51
+ assert.ok(ts);
52
+ assert.match(ts, /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.000Z$/);
53
+ });
54
+
55
+ it('returns null for unknown lastSync', () => {
56
+ const lf = Lockfile.load(tmpFile);
57
+ assert.strictEqual(lf.getLastSync('nonexistent'), null);
58
+ });
59
+
60
+ it('gets entries for mapping', () => {
61
+ const lf = Lockfile.load(tmpFile);
62
+ lf.setEntry('mymap::file1.md', 'sha1', 'hash1');
63
+ lf.setEntry('mymap::file2.md', 'sha2', 'hash2');
64
+ lf.setEntry('other::file3.md', 'sha3', 'hash3');
65
+
66
+ const entries = lf.getEntriesForMapping('mymap');
67
+ assert.strictEqual(Object.keys(entries).length, 2);
68
+ assert.ok(entries['file1.md']);
69
+ assert.ok(entries['file2.md']);
70
+ assert.strictEqual(entries['file3.md'], undefined);
71
+ });
72
+ });
73
+
74
+ describe('makeKey', () => {
75
+ it('creates mapping::relpath key', () => {
76
+ assert.strictEqual(makeKey('mymap', 'path/to/file.md'), 'mymap::path/to/file.md');
77
+ });
78
+ });
79
+
80
+ describe('hashFile', () => {
81
+ it('computes SHA-256 hash', () => {
82
+ const tmpFile = path.join(os.tmpdir(), 'test-hash-' + Date.now());
83
+ fs.writeFileSync(tmpFile, 'hello');
84
+ try {
85
+ const hash = hashFile(tmpFile);
86
+ assert.strictEqual(hash, '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824');
87
+ } finally {
88
+ fs.unlinkSync(tmpFile);
89
+ }
90
+ });
91
+ });