@dezkareid/ai-context-sync 1.3.0 → 1.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/README.md +51 -4
- package/dist/constants.js +2 -5
- package/dist/engine.js +45 -47
- package/dist/index.js +252 -113
- package/dist/strategies/claude.js +2 -6
- package/dist/strategies/gemini-md.js +2 -6
- package/dist/strategies/gemini.js +14 -21
- package/dist/strategies/index.js +2 -5
- package/dist/strategies/other.js +2 -6
- package/dist/strategies/symlink.js +13 -20
- package/package.json +8 -2
- package/dist/engine.test.js +0 -225
- package/dist/strategies/claude.test.js +0 -31
- package/dist/strategies/gemini-md.test.js +0 -31
- package/dist/strategies/gemini.test.js +0 -110
- package/dist/strategies/other.test.js +0 -58
- package/dist/strategies/symlink.test.js +0 -101
package/dist/strategies/index.js
CHANGED
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.AGENTS_FILE = void 0;
|
|
4
|
-
const constants_js_1 = require("../constants.js");
|
|
5
|
-
exports.AGENTS_FILE = constants_js_1.AGENTS_FILENAME;
|
|
1
|
+
import { AGENTS_FILENAME } from '../constants.js';
|
|
2
|
+
export const AGENTS_FILE = AGENTS_FILENAME;
|
package/dist/strategies/other.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.OtherStrategy = void 0;
|
|
4
|
-
const symlink_js_1 = require("./symlink.js");
|
|
5
|
-
class OtherStrategy extends symlink_js_1.SymlinkStrategy {
|
|
1
|
+
import { SymlinkStrategy } from './symlink.js';
|
|
2
|
+
export class OtherStrategy extends SymlinkStrategy {
|
|
6
3
|
name = 'other';
|
|
7
4
|
targetFilename;
|
|
8
5
|
constructor(targetFilename, fromFile) {
|
|
@@ -10,4 +7,3 @@ class OtherStrategy extends symlink_js_1.SymlinkStrategy {
|
|
|
10
7
|
this.targetFilename = targetFilename;
|
|
11
8
|
}
|
|
12
9
|
}
|
|
13
|
-
exports.OtherStrategy = OtherStrategy;
|
|
@@ -1,38 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.SymlinkStrategy = void 0;
|
|
7
|
-
const index_js_1 = require("./index.js");
|
|
8
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
-
const path_1 = __importDefault(require("path"));
|
|
10
|
-
class SymlinkStrategy {
|
|
1
|
+
import { AGENTS_FILE } from './index.js';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
export class SymlinkStrategy {
|
|
11
5
|
fromFile;
|
|
12
|
-
constructor(fromFile =
|
|
6
|
+
constructor(fromFile = AGENTS_FILE) {
|
|
13
7
|
this.fromFile = fromFile;
|
|
14
8
|
}
|
|
15
9
|
async sync(_context, projectRoot, targetDir) {
|
|
16
10
|
const outputDir = targetDir ?? projectRoot;
|
|
17
|
-
const targetPath =
|
|
11
|
+
const targetPath = path.join(outputDir, this.targetFilename);
|
|
18
12
|
// Compute the symlink value: relative path from outputDir to the source file in projectRoot
|
|
19
|
-
const agentsAbsPath =
|
|
20
|
-
const symlinkTarget =
|
|
13
|
+
const agentsAbsPath = path.join(projectRoot, this.fromFile);
|
|
14
|
+
const symlinkTarget = path.relative(outputDir, agentsAbsPath);
|
|
21
15
|
// Check if it exists and what type it is
|
|
22
|
-
if (await
|
|
23
|
-
const stats = await
|
|
16
|
+
if (await fs.pathExists(targetPath)) {
|
|
17
|
+
const stats = await fs.lstat(targetPath);
|
|
24
18
|
if (stats.isSymbolicLink()) {
|
|
25
|
-
const existingTarget = await
|
|
19
|
+
const existingTarget = await fs.readlink(targetPath);
|
|
26
20
|
if (existingTarget === symlinkTarget) {
|
|
27
21
|
// Already points to the correct location, nothing to do
|
|
28
22
|
return;
|
|
29
23
|
}
|
|
30
24
|
}
|
|
31
25
|
// If it's a file or a link to somewhere else, remove it
|
|
32
|
-
await
|
|
26
|
+
await fs.remove(targetPath);
|
|
33
27
|
}
|
|
34
28
|
// Create symlink pointing to the source file
|
|
35
|
-
await
|
|
29
|
+
await fs.ensureSymlink(symlinkTarget, targetPath);
|
|
36
30
|
}
|
|
37
31
|
}
|
|
38
|
-
exports.SymlinkStrategy = SymlinkStrategy;
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dezkareid/ai-context-sync",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "CLI utility to synchronize AI agent context files from AGENTS.md",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
7
|
"bin": {
|
|
7
8
|
"ai-context-sync": "./dist/index.js"
|
|
@@ -40,17 +41,22 @@
|
|
|
40
41
|
"inquirer": "9.2.12"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
44
|
+
"@eslint/js": "9.39.2",
|
|
43
45
|
"@types/fs-extra": "11.0.4",
|
|
44
46
|
"@types/inquirer": "9.0.7",
|
|
45
47
|
"@types/node": "25.0.10",
|
|
46
48
|
"@vitest/coverage-v8": "4.0.18",
|
|
49
|
+
"eslint": "9.39.2",
|
|
47
50
|
"typescript": "5.9.3",
|
|
48
|
-
"
|
|
51
|
+
"typescript-eslint": "8.57.0",
|
|
52
|
+
"vitest": "4.0.18",
|
|
53
|
+
"@dezkareid/eslint-config-ts-base": "^0.0.0"
|
|
49
54
|
},
|
|
50
55
|
"scripts": {
|
|
51
56
|
"build": "tsc",
|
|
52
57
|
"start": "node dist/index.js",
|
|
53
58
|
"dev": "tsc -w",
|
|
59
|
+
"lint": "eslint .",
|
|
54
60
|
"test": "vitest run --coverage"
|
|
55
61
|
}
|
|
56
62
|
}
|
package/dist/engine.test.js
DELETED
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const vitest_1 = require("vitest");
|
|
7
|
-
const engine_js_1 = require("./engine.js");
|
|
8
|
-
const constants_js_1 = require("./constants.js");
|
|
9
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
-
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const os_1 = __importDefault(require("os"));
|
|
12
|
-
(0, vitest_1.describe)('SyncEngine', () => {
|
|
13
|
-
let tempDir;
|
|
14
|
-
(0, vitest_1.beforeEach)(async () => {
|
|
15
|
-
tempDir = await fs_extra_1.default.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'sync-engine-test-'));
|
|
16
|
-
});
|
|
17
|
-
(0, vitest_1.afterEach)(async () => {
|
|
18
|
-
await fs_extra_1.default.remove(tempDir);
|
|
19
|
-
});
|
|
20
|
-
(0, vitest_1.it)('should throw error if AGENTS.md is missing', async () => {
|
|
21
|
-
const engine = new engine_js_1.SyncEngine();
|
|
22
|
-
await (0, vitest_1.expect)(engine.sync(tempDir)).rejects.toThrow(`${constants_js_1.AGENTS_FILENAME} not found`);
|
|
23
|
-
});
|
|
24
|
-
(0, vitest_1.it)('should run all strategies when AGENTS.md exists', async () => {
|
|
25
|
-
const engine = new engine_js_1.SyncEngine();
|
|
26
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
27
|
-
const context = '# Agent Context';
|
|
28
|
-
await fs_extra_1.default.writeFile(agentsPath, context);
|
|
29
|
-
await engine.sync(tempDir);
|
|
30
|
-
// Verify Claude
|
|
31
|
-
const claudePath = path_1.default.join(tempDir, 'CLAUDE.md');
|
|
32
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(claudePath)).toBe(true);
|
|
33
|
-
(0, vitest_1.expect)(await fs_extra_1.default.readFile(claudePath, 'utf-8')).toBe(context);
|
|
34
|
-
// Verify Gemini
|
|
35
|
-
const settingsPath = path_1.default.join(tempDir, '.gemini', 'settings.json');
|
|
36
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(settingsPath)).toBe(true);
|
|
37
|
-
const settings = await fs_extra_1.default.readJson(settingsPath);
|
|
38
|
-
(0, vitest_1.expect)(settings.context.fileName).toContain(constants_js_1.AGENTS_FILENAME);
|
|
39
|
-
});
|
|
40
|
-
(0, vitest_1.it)('should run only Claude strategy when selected', async () => {
|
|
41
|
-
const engine = new engine_js_1.SyncEngine();
|
|
42
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
43
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agent Context');
|
|
44
|
-
await engine.sync(tempDir, 'claude');
|
|
45
|
-
const claudePath = path_1.default.join(tempDir, 'CLAUDE.md');
|
|
46
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(claudePath)).toBe(true);
|
|
47
|
-
const geminiDir = path_1.default.join(tempDir, '.gemini');
|
|
48
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(geminiDir)).toBe(false);
|
|
49
|
-
});
|
|
50
|
-
(0, vitest_1.it)('should run only Gemini strategy when selected', async () => {
|
|
51
|
-
const engine = new engine_js_1.SyncEngine();
|
|
52
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
53
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agent Context');
|
|
54
|
-
await engine.sync(tempDir, 'gemini');
|
|
55
|
-
const claudePath = path_1.default.join(tempDir, 'CLAUDE.md');
|
|
56
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(claudePath)).toBe(false);
|
|
57
|
-
const settingsPath = path_1.default.join(tempDir, '.gemini', 'settings.json');
|
|
58
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(settingsPath)).toBe(true);
|
|
59
|
-
});
|
|
60
|
-
(0, vitest_1.it)('should run Gemini Markdown strategy when selected', async () => {
|
|
61
|
-
const engine = new engine_js_1.SyncEngine();
|
|
62
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
63
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agent Context');
|
|
64
|
-
await engine.sync(tempDir, 'gemini-md');
|
|
65
|
-
const geminiMdPath = path_1.default.join(tempDir, 'GEMINI.md');
|
|
66
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(geminiMdPath)).toBe(true);
|
|
67
|
-
const stats = await fs_extra_1.default.lstat(geminiMdPath);
|
|
68
|
-
(0, vitest_1.expect)(stats.isSymbolicLink()).toBe(true);
|
|
69
|
-
});
|
|
70
|
-
(0, vitest_1.it)('should run multiple selected strategies from array', async () => {
|
|
71
|
-
const engine = new engine_js_1.SyncEngine();
|
|
72
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
73
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agent Context');
|
|
74
|
-
await engine.sync(tempDir, ['claude', 'gemini']);
|
|
75
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(path_1.default.join(tempDir, 'CLAUDE.md'))).toBe(true);
|
|
76
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(path_1.default.join(tempDir, '.gemini', 'settings.json'))).toBe(true);
|
|
77
|
-
});
|
|
78
|
-
(0, vitest_1.it)('should run all strategies when "all" is selected', async () => {
|
|
79
|
-
const engine = new engine_js_1.SyncEngine();
|
|
80
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
81
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agent Context');
|
|
82
|
-
await engine.sync(tempDir, 'all');
|
|
83
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(path_1.default.join(tempDir, 'CLAUDE.md'))).toBe(true);
|
|
84
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(path_1.default.join(tempDir, '.gemini', 'settings.json'))).toBe(true);
|
|
85
|
-
});
|
|
86
|
-
(0, vitest_1.it)('should throw error for invalid strategy', async () => {
|
|
87
|
-
const engine = new engine_js_1.SyncEngine();
|
|
88
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
89
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agent Context');
|
|
90
|
-
await (0, vitest_1.expect)(engine.sync(tempDir, 'invalid')).rejects.toThrow('No valid strategies found for: invalid. Available strategies: claude, gemini, gemini-md, other');
|
|
91
|
-
});
|
|
92
|
-
(0, vitest_1.describe)('otherFiles option', () => {
|
|
93
|
-
(0, vitest_1.it)('should create a symlink for a single otherFile', async () => {
|
|
94
|
-
const engine = new engine_js_1.SyncEngine();
|
|
95
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
96
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agent Context');
|
|
97
|
-
await engine.sync(tempDir, 'other', undefined, undefined, ['CURSOR.md']);
|
|
98
|
-
const cursorPath = path_1.default.join(tempDir, 'CURSOR.md');
|
|
99
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(cursorPath)).toBe(true);
|
|
100
|
-
const stats = await fs_extra_1.default.lstat(cursorPath);
|
|
101
|
-
(0, vitest_1.expect)(stats.isSymbolicLink()).toBe(true);
|
|
102
|
-
});
|
|
103
|
-
(0, vitest_1.it)('should create symlinks for multiple otherFiles', async () => {
|
|
104
|
-
const engine = new engine_js_1.SyncEngine();
|
|
105
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
106
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agent Context');
|
|
107
|
-
await engine.sync(tempDir, ['other'], undefined, undefined, ['CURSOR.md', 'COPILOT.md']);
|
|
108
|
-
const cursorPath = path_1.default.join(tempDir, 'CURSOR.md');
|
|
109
|
-
const copilotPath = path_1.default.join(tempDir, 'COPILOT.md');
|
|
110
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(cursorPath)).toBe(true);
|
|
111
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(copilotPath)).toBe(true);
|
|
112
|
-
});
|
|
113
|
-
(0, vitest_1.it)('should throw descriptive error when strategy is "other" but otherFiles is not provided', async () => {
|
|
114
|
-
const engine = new engine_js_1.SyncEngine();
|
|
115
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
116
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agent Context');
|
|
117
|
-
await (0, vitest_1.expect)(engine.sync(tempDir, 'other')).rejects.toThrow('Strategy "other" requires otherFiles to be specified.');
|
|
118
|
-
});
|
|
119
|
-
(0, vitest_1.it)('should throw descriptive error when strategy is "other" but otherFiles is empty', async () => {
|
|
120
|
-
const engine = new engine_js_1.SyncEngine();
|
|
121
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
122
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agent Context');
|
|
123
|
-
await (0, vitest_1.expect)(engine.sync(tempDir, 'other', undefined, undefined, [])).rejects.toThrow('Strategy "other" requires otherFiles to be specified.');
|
|
124
|
-
});
|
|
125
|
-
(0, vitest_1.it)('should run both built-in and custom strategies when combined', async () => {
|
|
126
|
-
const engine = new engine_js_1.SyncEngine();
|
|
127
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
128
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agent Context');
|
|
129
|
-
await engine.sync(tempDir, ['claude', 'other'], undefined, undefined, ['CURSOR.md']);
|
|
130
|
-
const claudePath = path_1.default.join(tempDir, 'CLAUDE.md');
|
|
131
|
-
const cursorPath = path_1.default.join(tempDir, 'CURSOR.md');
|
|
132
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(claudePath)).toBe(true);
|
|
133
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(cursorPath)).toBe(true);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
(0, vitest_1.describe)('fromFile option', () => {
|
|
137
|
-
(0, vitest_1.it)('should use a custom source file when fromFile is provided', async () => {
|
|
138
|
-
const engine = new engine_js_1.SyncEngine();
|
|
139
|
-
const customSource = 'MY_AGENTS.md';
|
|
140
|
-
const customSourcePath = path_1.default.join(tempDir, customSource);
|
|
141
|
-
await fs_extra_1.default.writeFile(customSourcePath, '# Custom Agent Context');
|
|
142
|
-
await engine.sync(tempDir, 'claude', undefined, customSource);
|
|
143
|
-
const claudePath = path_1.default.join(tempDir, 'CLAUDE.md');
|
|
144
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(claudePath)).toBe(true);
|
|
145
|
-
const stats = await fs_extra_1.default.lstat(claudePath);
|
|
146
|
-
(0, vitest_1.expect)(stats.isSymbolicLink()).toBe(true);
|
|
147
|
-
// Symlink should resolve to the custom source file
|
|
148
|
-
const resolvedPath = await fs_extra_1.default.realpath(claudePath);
|
|
149
|
-
const expectedPath = await fs_extra_1.default.realpath(customSourcePath);
|
|
150
|
-
(0, vitest_1.expect)(resolvedPath).toBe(expectedPath);
|
|
151
|
-
});
|
|
152
|
-
(0, vitest_1.it)('should throw error when custom fromFile does not exist', async () => {
|
|
153
|
-
const engine = new engine_js_1.SyncEngine();
|
|
154
|
-
await (0, vitest_1.expect)(engine.sync(tempDir, 'claude', undefined, 'MISSING.md')).rejects.toThrow('MISSING.md not found in');
|
|
155
|
-
});
|
|
156
|
-
(0, vitest_1.it)('should use custom fromFile with other strategy', async () => {
|
|
157
|
-
const engine = new engine_js_1.SyncEngine();
|
|
158
|
-
const customSource = 'MY_AGENTS.md';
|
|
159
|
-
await fs_extra_1.default.writeFile(path_1.default.join(tempDir, customSource), '# Custom Agent Context');
|
|
160
|
-
await engine.sync(tempDir, 'other', undefined, customSource, ['CURSOR.md']);
|
|
161
|
-
const cursorPath = path_1.default.join(tempDir, 'CURSOR.md');
|
|
162
|
-
const resolvedPath = await fs_extra_1.default.realpath(cursorPath);
|
|
163
|
-
const expectedPath = await fs_extra_1.default.realpath(path_1.default.join(tempDir, customSource));
|
|
164
|
-
(0, vitest_1.expect)(resolvedPath).toBe(expectedPath);
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
(0, vitest_1.describe)('targetDir option', () => {
|
|
168
|
-
let targetDir;
|
|
169
|
-
(0, vitest_1.beforeEach)(async () => {
|
|
170
|
-
targetDir = await fs_extra_1.default.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'sync-engine-target-'));
|
|
171
|
-
});
|
|
172
|
-
(0, vitest_1.afterEach)(async () => {
|
|
173
|
-
await fs_extra_1.default.remove(targetDir);
|
|
174
|
-
});
|
|
175
|
-
(0, vitest_1.it)('should write synced files to targetDir instead of projectRoot', async () => {
|
|
176
|
-
const engine = new engine_js_1.SyncEngine();
|
|
177
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
178
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agent Context');
|
|
179
|
-
await engine.sync(tempDir, 'claude', targetDir);
|
|
180
|
-
// File should be in targetDir
|
|
181
|
-
const claudeInTarget = path_1.default.join(targetDir, 'CLAUDE.md');
|
|
182
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(claudeInTarget)).toBe(true);
|
|
183
|
-
// File should NOT be in projectRoot (tempDir)
|
|
184
|
-
const claudeInSource = path_1.default.join(tempDir, 'CLAUDE.md');
|
|
185
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(claudeInSource)).toBe(false);
|
|
186
|
-
});
|
|
187
|
-
(0, vitest_1.it)('should create symlink in targetDir pointing back to projectRoot AGENTS.md', async () => {
|
|
188
|
-
const engine = new engine_js_1.SyncEngine();
|
|
189
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
190
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agent Context');
|
|
191
|
-
await engine.sync(tempDir, 'claude', targetDir);
|
|
192
|
-
const claudePath = path_1.default.join(targetDir, 'CLAUDE.md');
|
|
193
|
-
const stats = await fs_extra_1.default.lstat(claudePath);
|
|
194
|
-
(0, vitest_1.expect)(stats.isSymbolicLink()).toBe(true);
|
|
195
|
-
// The symlink should resolve to the AGENTS.md in projectRoot
|
|
196
|
-
const resolvedPath = await fs_extra_1.default.realpath(claudePath);
|
|
197
|
-
const expectedPath = await fs_extra_1.default.realpath(agentsPath);
|
|
198
|
-
(0, vitest_1.expect)(resolvedPath).toBe(expectedPath);
|
|
199
|
-
});
|
|
200
|
-
(0, vitest_1.it)('should write .gemini/settings.json to targetDir when targetDir is specified', async () => {
|
|
201
|
-
const engine = new engine_js_1.SyncEngine();
|
|
202
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
203
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agent Context');
|
|
204
|
-
await engine.sync(tempDir, 'gemini', targetDir);
|
|
205
|
-
// Settings should be in targetDir
|
|
206
|
-
const settingsInTarget = path_1.default.join(targetDir, '.gemini', 'settings.json');
|
|
207
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(settingsInTarget)).toBe(true);
|
|
208
|
-
// Settings should NOT be in projectRoot
|
|
209
|
-
const settingsInSource = path_1.default.join(tempDir, '.gemini', 'settings.json');
|
|
210
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(settingsInSource)).toBe(false);
|
|
211
|
-
// The stored path should be relative from targetDir to AGENTS.md
|
|
212
|
-
const settings = await fs_extra_1.default.readJson(settingsInTarget);
|
|
213
|
-
const expectedRelPath = path_1.default.relative(targetDir, agentsPath);
|
|
214
|
-
(0, vitest_1.expect)(settings.context.fileName).toContain(expectedRelPath);
|
|
215
|
-
});
|
|
216
|
-
(0, vitest_1.it)('should use projectRoot as targetDir when targetDir is not specified', async () => {
|
|
217
|
-
const engine = new engine_js_1.SyncEngine();
|
|
218
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
219
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agent Context');
|
|
220
|
-
await engine.sync(tempDir, 'claude');
|
|
221
|
-
const claudeInSource = path_1.default.join(tempDir, 'CLAUDE.md');
|
|
222
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(claudeInSource)).toBe(true);
|
|
223
|
-
});
|
|
224
|
-
});
|
|
225
|
-
});
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const vitest_1 = require("vitest");
|
|
7
|
-
const claude_js_1 = require("./claude.js");
|
|
8
|
-
const constants_js_1 = require("../constants.js");
|
|
9
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
-
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const os_1 = __importDefault(require("os"));
|
|
12
|
-
(0, vitest_1.describe)('ClaudeStrategy', () => {
|
|
13
|
-
let tempDir;
|
|
14
|
-
(0, vitest_1.beforeEach)(async () => {
|
|
15
|
-
tempDir = await fs_extra_1.default.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'claude-strategy-test-'));
|
|
16
|
-
});
|
|
17
|
-
(0, vitest_1.afterEach)(async () => {
|
|
18
|
-
await fs_extra_1.default.remove(tempDir);
|
|
19
|
-
});
|
|
20
|
-
(0, vitest_1.it)('should create a symbolic link CLAUDE.md pointing to AGENTS.md', async () => {
|
|
21
|
-
const strategy = new claude_js_1.ClaudeStrategy();
|
|
22
|
-
const agentsPath = path_1.default.join(tempDir, constants_js_1.AGENTS_FILENAME);
|
|
23
|
-
await fs_extra_1.default.writeFile(agentsPath, '# Agents');
|
|
24
|
-
await strategy.sync('# Agents', tempDir);
|
|
25
|
-
const claudePath = path_1.default.join(tempDir, 'CLAUDE.md');
|
|
26
|
-
const stats = await fs_extra_1.default.lstat(claudePath);
|
|
27
|
-
(0, vitest_1.expect)(stats.isSymbolicLink()).toBe(true);
|
|
28
|
-
const target = await fs_extra_1.default.readlink(claudePath);
|
|
29
|
-
(0, vitest_1.expect)(target).toBe(constants_js_1.AGENTS_FILENAME);
|
|
30
|
-
});
|
|
31
|
-
});
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const vitest_1 = require("vitest");
|
|
7
|
-
const gemini_md_js_1 = require("./gemini-md.js");
|
|
8
|
-
const index_js_1 = require("./index.js");
|
|
9
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
-
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const os_1 = __importDefault(require("os"));
|
|
12
|
-
(0, vitest_1.describe)('GeminiMdStrategy', () => {
|
|
13
|
-
let tempDir;
|
|
14
|
-
let strategy;
|
|
15
|
-
(0, vitest_1.beforeEach)(async () => {
|
|
16
|
-
tempDir = await fs_extra_1.default.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'gemini-md-strategy-test-'));
|
|
17
|
-
await fs_extra_1.default.writeFile(path_1.default.join(tempDir, index_js_1.AGENTS_FILE), '# Agents');
|
|
18
|
-
strategy = new gemini_md_js_1.GeminiMdStrategy();
|
|
19
|
-
});
|
|
20
|
-
(0, vitest_1.afterEach)(async () => {
|
|
21
|
-
await fs_extra_1.default.remove(tempDir);
|
|
22
|
-
});
|
|
23
|
-
(0, vitest_1.it)('should create a symbolic link GEMINI.md pointing to AGENTS.md', async () => {
|
|
24
|
-
await strategy.sync('', tempDir);
|
|
25
|
-
const targetPath = path_1.default.join(tempDir, 'GEMINI.md');
|
|
26
|
-
const stats = await fs_extra_1.default.lstat(targetPath);
|
|
27
|
-
(0, vitest_1.expect)(stats.isSymbolicLink()).toBe(true);
|
|
28
|
-
const target = await fs_extra_1.default.readlink(targetPath);
|
|
29
|
-
(0, vitest_1.expect)(target).toBe(index_js_1.AGENTS_FILE);
|
|
30
|
-
});
|
|
31
|
-
});
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const vitest_1 = require("vitest");
|
|
7
|
-
const gemini_js_1 = require("./gemini.js");
|
|
8
|
-
const constants_js_1 = require("../constants.js");
|
|
9
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
-
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const os_1 = __importDefault(require("os"));
|
|
12
|
-
(0, vitest_1.describe)('GeminiStrategy', () => {
|
|
13
|
-
let tempDir;
|
|
14
|
-
(0, vitest_1.beforeEach)(async () => {
|
|
15
|
-
tempDir = await fs_extra_1.default.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'gemini-strategy-test-'));
|
|
16
|
-
});
|
|
17
|
-
(0, vitest_1.afterEach)(async () => {
|
|
18
|
-
await fs_extra_1.default.remove(tempDir);
|
|
19
|
-
});
|
|
20
|
-
(0, vitest_1.it)('should create .gemini/settings.json if it does not exist', async () => {
|
|
21
|
-
const strategy = new gemini_js_1.GeminiStrategy();
|
|
22
|
-
await strategy.sync('context', tempDir);
|
|
23
|
-
const settingsPath = path_1.default.join(tempDir, '.gemini', 'settings.json');
|
|
24
|
-
(0, vitest_1.expect)(await fs_extra_1.default.pathExists(settingsPath)).toBe(true);
|
|
25
|
-
const settings = await fs_extra_1.default.readJson(settingsPath);
|
|
26
|
-
(0, vitest_1.expect)(settings.context.fileName).toContain(constants_js_1.AGENTS_FILENAME);
|
|
27
|
-
});
|
|
28
|
-
(0, vitest_1.it)('should update existing context.fileName array', async () => {
|
|
29
|
-
const strategy = new gemini_js_1.GeminiStrategy();
|
|
30
|
-
const settingsPath = path_1.default.join(tempDir, '.gemini', 'settings.json');
|
|
31
|
-
await fs_extra_1.default.ensureDir(path_1.default.dirname(settingsPath));
|
|
32
|
-
await fs_extra_1.default.writeJson(settingsPath, {
|
|
33
|
-
context: {
|
|
34
|
-
fileName: ['OTHER.md']
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
await strategy.sync('context', tempDir);
|
|
38
|
-
const settings = await fs_extra_1.default.readJson(settingsPath);
|
|
39
|
-
(0, vitest_1.expect)(settings.context.fileName).toContain('OTHER.md');
|
|
40
|
-
(0, vitest_1.expect)(settings.context.fileName).toContain(constants_js_1.AGENTS_FILENAME);
|
|
41
|
-
});
|
|
42
|
-
(0, vitest_1.it)('should convert string fileName to array and add AGENTS.md', async () => {
|
|
43
|
-
const strategy = new gemini_js_1.GeminiStrategy();
|
|
44
|
-
const settingsPath = path_1.default.join(tempDir, '.gemini', 'settings.json');
|
|
45
|
-
await fs_extra_1.default.ensureDir(path_1.default.dirname(settingsPath));
|
|
46
|
-
await fs_extra_1.default.writeJson(settingsPath, {
|
|
47
|
-
context: {
|
|
48
|
-
fileName: 'OTHER.md'
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
await strategy.sync('context', tempDir);
|
|
52
|
-
const settings = await fs_extra_1.default.readJson(settingsPath);
|
|
53
|
-
(0, vitest_1.expect)(Array.isArray(settings.context.fileName)).toBe(true);
|
|
54
|
-
(0, vitest_1.expect)(settings.context.fileName).toContain('OTHER.md');
|
|
55
|
-
(0, vitest_1.expect)(settings.context.fileName).toContain(constants_js_1.AGENTS_FILENAME);
|
|
56
|
-
});
|
|
57
|
-
(0, vitest_1.it)('should not add AGENTS.md twice', async () => {
|
|
58
|
-
const strategy = new gemini_js_1.GeminiStrategy();
|
|
59
|
-
const settingsPath = path_1.default.join(tempDir, '.gemini', 'settings.json');
|
|
60
|
-
await fs_extra_1.default.ensureDir(path_1.default.dirname(settingsPath));
|
|
61
|
-
await fs_extra_1.default.writeJson(settingsPath, {
|
|
62
|
-
context: {
|
|
63
|
-
fileName: [constants_js_1.AGENTS_FILENAME]
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
await strategy.sync('context', tempDir);
|
|
67
|
-
const settings = await fs_extra_1.default.readJson(settingsPath);
|
|
68
|
-
(0, vitest_1.expect)(settings.context.fileName.filter((f) => f === constants_js_1.AGENTS_FILENAME).length).toBe(1);
|
|
69
|
-
});
|
|
70
|
-
(0, vitest_1.it)('should not write to settings.json if AGENTS.md is already present', async () => {
|
|
71
|
-
const strategy = new gemini_js_1.GeminiStrategy();
|
|
72
|
-
const settingsPath = path_1.default.join(tempDir, '.gemini', 'settings.json');
|
|
73
|
-
await fs_extra_1.default.ensureDir(path_1.default.dirname(settingsPath));
|
|
74
|
-
await fs_extra_1.default.writeJson(settingsPath, {
|
|
75
|
-
context: {
|
|
76
|
-
fileName: [constants_js_1.AGENTS_FILENAME]
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
const mtimeBefore = (await fs_extra_1.default.stat(settingsPath)).mtimeMs;
|
|
80
|
-
// Wait a bit to ensure mtime would change if written
|
|
81
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
82
|
-
await strategy.sync('context', tempDir);
|
|
83
|
-
const mtimeAfter = (await fs_extra_1.default.stat(settingsPath)).mtimeMs;
|
|
84
|
-
(0, vitest_1.expect)(mtimeAfter).toBe(mtimeBefore);
|
|
85
|
-
});
|
|
86
|
-
(0, vitest_1.it)('should not write to settings.json if fileName is already AGENTS.md as a string', async () => {
|
|
87
|
-
const strategy = new gemini_js_1.GeminiStrategy();
|
|
88
|
-
const settingsPath = path_1.default.join(tempDir, '.gemini', 'settings.json');
|
|
89
|
-
await fs_extra_1.default.ensureDir(path_1.default.dirname(settingsPath));
|
|
90
|
-
await fs_extra_1.default.writeJson(settingsPath, {
|
|
91
|
-
context: {
|
|
92
|
-
fileName: constants_js_1.AGENTS_FILENAME
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
const mtimeBefore = (await fs_extra_1.default.stat(settingsPath)).mtimeMs;
|
|
96
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
97
|
-
await strategy.sync('context', tempDir);
|
|
98
|
-
const mtimeAfter = (await fs_extra_1.default.stat(settingsPath)).mtimeMs;
|
|
99
|
-
(0, vitest_1.expect)(mtimeAfter).toBe(mtimeBefore);
|
|
100
|
-
});
|
|
101
|
-
(0, vitest_1.it)('should handle invalid JSON in settings.json by starting fresh', async () => {
|
|
102
|
-
const strategy = new gemini_js_1.GeminiStrategy();
|
|
103
|
-
const settingsPath = path_1.default.join(tempDir, '.gemini', 'settings.json');
|
|
104
|
-
await fs_extra_1.default.ensureDir(path_1.default.dirname(settingsPath));
|
|
105
|
-
await fs_extra_1.default.writeFile(settingsPath, 'not a json');
|
|
106
|
-
await strategy.sync('context', tempDir);
|
|
107
|
-
const settings = await fs_extra_1.default.readJson(settingsPath);
|
|
108
|
-
(0, vitest_1.expect)(settings.context.fileName).toContain(constants_js_1.AGENTS_FILENAME);
|
|
109
|
-
});
|
|
110
|
-
});
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const vitest_1 = require("vitest");
|
|
7
|
-
const other_js_1 = require("./other.js");
|
|
8
|
-
const index_js_1 = require("./index.js");
|
|
9
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
-
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const os_1 = __importDefault(require("os"));
|
|
12
|
-
(0, vitest_1.describe)('OtherStrategy', () => {
|
|
13
|
-
let tempDir;
|
|
14
|
-
(0, vitest_1.beforeEach)(async () => {
|
|
15
|
-
tempDir = await fs_extra_1.default.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'other-strategy-test-'));
|
|
16
|
-
await fs_extra_1.default.writeFile(path_1.default.join(tempDir, index_js_1.AGENTS_FILE), '# Agents');
|
|
17
|
-
});
|
|
18
|
-
(0, vitest_1.afterEach)(async () => {
|
|
19
|
-
await fs_extra_1.default.remove(tempDir);
|
|
20
|
-
});
|
|
21
|
-
(0, vitest_1.it)('should create a symlink with the correct targetFilename', async () => {
|
|
22
|
-
const strategy = new other_js_1.OtherStrategy('CURSOR.md');
|
|
23
|
-
await strategy.sync('', tempDir);
|
|
24
|
-
const targetPath = path_1.default.join(tempDir, 'CURSOR.md');
|
|
25
|
-
const stats = await fs_extra_1.default.lstat(targetPath);
|
|
26
|
-
(0, vitest_1.expect)(stats.isSymbolicLink()).toBe(true);
|
|
27
|
-
const target = await fs_extra_1.default.readlink(targetPath);
|
|
28
|
-
(0, vitest_1.expect)(target).toContain(index_js_1.AGENTS_FILE);
|
|
29
|
-
});
|
|
30
|
-
(0, vitest_1.it)('should use default AGENTS.md as source when fromFile is not provided', async () => {
|
|
31
|
-
const strategy = new other_js_1.OtherStrategy('COPILOT.md');
|
|
32
|
-
await strategy.sync('', tempDir);
|
|
33
|
-
const targetPath = path_1.default.join(tempDir, 'COPILOT.md');
|
|
34
|
-
const resolvedPath = await fs_extra_1.default.realpath(targetPath);
|
|
35
|
-
const expectedPath = await fs_extra_1.default.realpath(path_1.default.join(tempDir, index_js_1.AGENTS_FILE));
|
|
36
|
-
(0, vitest_1.expect)(resolvedPath).toBe(expectedPath);
|
|
37
|
-
});
|
|
38
|
-
(0, vitest_1.it)('should use custom fromFile when provided', async () => {
|
|
39
|
-
const customSource = 'MY_AGENTS.md';
|
|
40
|
-
await fs_extra_1.default.writeFile(path_1.default.join(tempDir, customSource), '# Custom Agents');
|
|
41
|
-
const strategy = new other_js_1.OtherStrategy('CURSOR.md', customSource);
|
|
42
|
-
await strategy.sync('', tempDir);
|
|
43
|
-
const targetPath = path_1.default.join(tempDir, 'CURSOR.md');
|
|
44
|
-
const stats = await fs_extra_1.default.lstat(targetPath);
|
|
45
|
-
(0, vitest_1.expect)(stats.isSymbolicLink()).toBe(true);
|
|
46
|
-
const resolvedPath = await fs_extra_1.default.realpath(targetPath);
|
|
47
|
-
const expectedPath = await fs_extra_1.default.realpath(path_1.default.join(tempDir, customSource));
|
|
48
|
-
(0, vitest_1.expect)(resolvedPath).toBe(expectedPath);
|
|
49
|
-
});
|
|
50
|
-
(0, vitest_1.it)('should have name "other"', () => {
|
|
51
|
-
const strategy = new other_js_1.OtherStrategy('CURSOR.md');
|
|
52
|
-
(0, vitest_1.expect)(strategy.name).toBe('other');
|
|
53
|
-
});
|
|
54
|
-
(0, vitest_1.it)('should expose the targetFilename', () => {
|
|
55
|
-
const strategy = new other_js_1.OtherStrategy('CUSTOM_FILE.md');
|
|
56
|
-
(0, vitest_1.expect)(strategy.targetFilename).toBe('CUSTOM_FILE.md');
|
|
57
|
-
});
|
|
58
|
-
});
|