@minhpnq1807/contextos 0.5.3 → 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 CHANGED
@@ -1,5 +1,10 @@
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
+
3
8
  ## 0.5.3
4
9
 
5
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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minhpnq1807/contextos",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "Task-aware AGENTS.md context injection and compliance reporting for Codex, Claude Code, and Antigravity.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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(","));