@minhpnq1807/contextos 0.5.2 → 0.5.4
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/CHANGELOG.md +10 -0
- package/package.json +1 -1
- package/plugins/ctx/lib/ruler-sync.js +18 -3
- package/plugins/ctx/lib/skillshare-sync.js +86 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.4
|
|
4
|
+
|
|
5
|
+
- Bridges legacy Antigravity skill directories (`~/.gemini/antigravity/skills` and `~/.gemini/antigravity-cli/skills`) into the skillshare source before `ctx sync --skills`.
|
|
6
|
+
- Reads custom `sources.skills` from `~/.config/skillshare/config.yaml` so ContextOS writes to the actual skillshare source path.
|
|
7
|
+
|
|
8
|
+
## 0.5.3
|
|
9
|
+
|
|
10
|
+
- Skips project MCP imports whose command is an absolute path that does not exist, preventing placeholder paths such as `/home/user/.cargo/bin/mcp-rtk` from reaching Antigravity.
|
|
11
|
+
- Sanitizes Antigravity MCP config files during `ctx sync --rules` by removing existing MCP entries with missing absolute command paths.
|
|
12
|
+
|
|
3
13
|
## 0.5.2
|
|
4
14
|
|
|
5
15
|
- Recovers automatically from malformed `embeddings.db` files by moving the corrupt cache aside and recreating it.
|
package/package.json
CHANGED
|
@@ -196,6 +196,7 @@ export function readProjectMcpJsonServers({ cwd = process.cwd(), configPath = pa
|
|
|
196
196
|
const mcpServers = config.mcpServers && typeof config.mcpServers === "object" ? config.mcpServers : {};
|
|
197
197
|
return Object.entries(mcpServers)
|
|
198
198
|
.filter(([, server]) => server && typeof server.command === "string")
|
|
199
|
+
.filter(([, server]) => isRunnableMcpCommand(server.command))
|
|
199
200
|
.map(([name, server]) => ({
|
|
200
201
|
name,
|
|
201
202
|
command: server.command,
|
|
@@ -203,6 +204,11 @@ export function readProjectMcpJsonServers({ cwd = process.cwd(), configPath = pa
|
|
|
203
204
|
}));
|
|
204
205
|
}
|
|
205
206
|
|
|
207
|
+
function isRunnableMcpCommand(command) {
|
|
208
|
+
if (!path.isAbsolute(command)) return true;
|
|
209
|
+
return fs.existsSync(command);
|
|
210
|
+
}
|
|
211
|
+
|
|
206
212
|
function mergeMcpServers(...groups) {
|
|
207
213
|
const merged = new Map();
|
|
208
214
|
for (const group of groups) {
|
|
@@ -253,12 +259,21 @@ function writeJsonFile(filePath, value) {
|
|
|
253
259
|
}
|
|
254
260
|
|
|
255
261
|
export function syncAntigravityMcpFromRuler({ tomlPath, configPaths = antigravityMcpConfigPaths(), dryRun = false } = {}) {
|
|
256
|
-
const
|
|
257
|
-
|
|
262
|
+
const allServers = readRulerMcpServers({ tomlPath });
|
|
263
|
+
const servers = allServers.filter((server) => isRunnableMcpCommand(server.command));
|
|
264
|
+
const skipped = allServers.filter((server) => !isRunnableMcpCommand(server.command)).map((server) => server.name);
|
|
265
|
+
if (!servers.length && !skipped.length) return { changed: false, servers: [], skipped, removed: [], configPaths };
|
|
258
266
|
|
|
267
|
+
const removed = [];
|
|
259
268
|
for (const configPath of configPaths) {
|
|
260
269
|
const config = readJsonFile(configPath, {});
|
|
261
270
|
if (!config.mcpServers || typeof config.mcpServers !== "object") config.mcpServers = {};
|
|
271
|
+
for (const [name, server] of Object.entries(config.mcpServers)) {
|
|
272
|
+
if (server?.command && !isRunnableMcpCommand(server.command)) {
|
|
273
|
+
delete config.mcpServers[name];
|
|
274
|
+
removed.push(name);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
262
277
|
for (const server of servers) {
|
|
263
278
|
config.mcpServers[server.name] = {
|
|
264
279
|
command: server.command,
|
|
@@ -268,7 +283,7 @@ export function syncAntigravityMcpFromRuler({ tomlPath, configPaths = antigravit
|
|
|
268
283
|
if (!dryRun) writeJsonFile(configPath, config);
|
|
269
284
|
}
|
|
270
285
|
|
|
271
|
-
return { changed: true, servers: servers.map((server) => server.name), configPaths };
|
|
286
|
+
return { changed: true, servers: servers.map((server) => server.name), skipped, removed: [...new Set(removed)], configPaths };
|
|
272
287
|
}
|
|
273
288
|
|
|
274
289
|
export function buildCtxMcpToml({ mcpServerPath, agents = DEFAULT_AGENTS } = {}) {
|
|
@@ -50,7 +50,22 @@ export function skillshareConfigDir({ home = os.homedir() } = {}) {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
export function skillshareSourceDir({ home = os.homedir() } = {}) {
|
|
53
|
-
return path.join(skillshareConfigDir({ home }), "skills");
|
|
53
|
+
return readSkillshareSourceDir({ home }) || path.join(skillshareConfigDir({ home }), "skills");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function readSkillshareSourceDir({ home = os.homedir() } = {}) {
|
|
57
|
+
const configPath = path.join(skillshareConfigDir({ home }), "config.yaml");
|
|
58
|
+
if (!fs.existsSync(configPath)) return null;
|
|
59
|
+
const content = fs.readFileSync(configPath, "utf8");
|
|
60
|
+
const match = content.match(/^\s{2}skills:\s*(.+?)\s*$/m);
|
|
61
|
+
if (!match) return null;
|
|
62
|
+
return expandHome(match[1].replace(/^["']|["']$/g, ""), home);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function expandHome(value, home) {
|
|
66
|
+
if (value === "~") return home;
|
|
67
|
+
if (value.startsWith("~/")) return path.join(home, value.slice(2));
|
|
68
|
+
return value;
|
|
54
69
|
}
|
|
55
70
|
|
|
56
71
|
export function checkSkillshareInstalled({ run = runCommand } = {}) {
|
|
@@ -119,6 +134,15 @@ function skillRoots({ cwd, home }) {
|
|
|
119
134
|
];
|
|
120
135
|
}
|
|
121
136
|
|
|
137
|
+
function antigravityLegacyRoots({ cwd, home }) {
|
|
138
|
+
return [
|
|
139
|
+
path.join(home, ".gemini", "antigravity", "skills"),
|
|
140
|
+
path.join(home, ".gemini", "antigravity-cli", "skills"),
|
|
141
|
+
path.join(cwd, ".gemini", "antigravity", "skills"),
|
|
142
|
+
path.join(cwd, ".gemini", "antigravity-cli", "skills")
|
|
143
|
+
];
|
|
144
|
+
}
|
|
145
|
+
|
|
122
146
|
function countSkillFiles(root) {
|
|
123
147
|
return findSkillFiles(root).length;
|
|
124
148
|
}
|
|
@@ -158,6 +182,57 @@ function safeStat(filePath) {
|
|
|
158
182
|
}
|
|
159
183
|
}
|
|
160
184
|
|
|
185
|
+
function safeRealpath(filePath) {
|
|
186
|
+
try {
|
|
187
|
+
return fs.realpathSync(filePath);
|
|
188
|
+
} catch {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function copyDirectory(sourceDir, targetDir) {
|
|
194
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
195
|
+
for (const entry of fs.readdirSync(sourceDir, { withFileTypes: true })) {
|
|
196
|
+
const source = path.join(sourceDir, entry.name);
|
|
197
|
+
const target = path.join(targetDir, entry.name);
|
|
198
|
+
if (entry.isDirectory()) {
|
|
199
|
+
copyDirectory(source, target);
|
|
200
|
+
} else if (entry.isSymbolicLink()) {
|
|
201
|
+
const link = fs.readlinkSync(source);
|
|
202
|
+
fs.symlinkSync(link, target);
|
|
203
|
+
} else if (entry.isFile()) {
|
|
204
|
+
fs.copyFileSync(source, target);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function collectAntigravityLegacySkills({
|
|
210
|
+
cwd = process.cwd(),
|
|
211
|
+
home = os.homedir(),
|
|
212
|
+
sourceDir = skillshareSourceDir({ home }),
|
|
213
|
+
dryRun = false
|
|
214
|
+
} = {}) {
|
|
215
|
+
const sourceReal = safeRealpath(sourceDir);
|
|
216
|
+
const copied = [];
|
|
217
|
+
const skipped = [];
|
|
218
|
+
for (const root of antigravityLegacyRoots({ cwd, home })) {
|
|
219
|
+
const rootReal = safeRealpath(root);
|
|
220
|
+
if (!rootReal || rootReal === sourceReal) continue;
|
|
221
|
+
for (const skillFile of findSkillFiles(root)) {
|
|
222
|
+
const skillDir = path.dirname(skillFile);
|
|
223
|
+
const name = path.basename(skillDir);
|
|
224
|
+
const targetDir = path.join(sourceDir, name);
|
|
225
|
+
if (fs.existsSync(targetDir)) {
|
|
226
|
+
skipped.push(name);
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (!dryRun) copyDirectory(skillDir, targetDir);
|
|
230
|
+
copied.push(name);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return { copied: [...new Set(copied)], skipped: [...new Set(skipped)], sourceDir };
|
|
234
|
+
}
|
|
235
|
+
|
|
161
236
|
export function isSkillshareInitialized({ home = os.homedir() } = {}) {
|
|
162
237
|
return fs.existsSync(skillshareConfigDir({ home }));
|
|
163
238
|
}
|
|
@@ -215,6 +290,16 @@ export async function syncSkills({
|
|
|
215
290
|
}
|
|
216
291
|
}
|
|
217
292
|
|
|
293
|
+
if (!options.noCollect) {
|
|
294
|
+
const legacy = collectAntigravityLegacySkills({ cwd, home, dryRun: options.dryRun });
|
|
295
|
+
if (legacy.copied.length || legacy.skipped.length) {
|
|
296
|
+
const value = options.dryRun
|
|
297
|
+
? `dry-run (${legacy.copied.length} would copy, ${legacy.skipped.length} already present)`
|
|
298
|
+
: `✓ ${legacy.copied.length} copied, ${legacy.skipped.length} already present`;
|
|
299
|
+
logger(statusLine("Collecting Antigravity legacy skills...", value));
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
218
303
|
const syncArgs = ["sync"];
|
|
219
304
|
if (options.dryRun) syncArgs.push("--dry-run");
|
|
220
305
|
if (options.agents.length) syncArgs.push("--agents", options.agents.join(","));
|