Skip to content

Commit 2ed771c

Browse files
authored
Merge pull request #323 from syncable-dev/remove-agent-chat
feat: autoupdater
2 parents 3d121ba + ed4f790 commit 2ed771c

5 files changed

Lines changed: 103 additions & 24 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,30 @@
66
},
77
"metadata": {
88
"description": "Syncable CLI skills for AI coding agents — project analysis, security, vulnerabilities, dependencies, IaC validation, and cloud deployment.",
9-
"version": "0.1.0"
9+
"version": "0.1.11"
1010
},
1111
"plugins": [
1212
{
1313
"name": "syncable-cli-skills",
1414
"source": "./installer/plugins/syncable-cli-skills",
1515
"description": "Syncable CLI skills for project analysis, security scanning, vulnerability detection, dependency auditing, IaC validation, Kubernetes optimization, and cloud deployment.",
16-
"version": "0.1.0",
16+
"version": "0.1.11",
1717
"author": {
1818
"name": "Syncable",
1919
"email": "support@syncable.dev"
2020
},
2121
"homepage": "https://syncable.dev",
2222
"repository": "https://github.com/syncable-dev/syncable-cli",
2323
"license": "MIT",
24-
"keywords": ["syncable", "devops", "security", "deployment", "kubernetes", "docker", "iac"]
24+
"keywords": [
25+
"syncable",
26+
"devops",
27+
"security",
28+
"deployment",
29+
"kubernetes",
30+
"docker",
31+
"iac"
32+
]
2533
}
2634
]
2735
}

installer/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "syncable-cli-skills",
3-
"version": "0.1.9",
3+
"version": "0.1.11",
44
"type": "module",
55
"description": "Install Syncable CLI skills for AI coding agents (Claude Code, Cursor, Windsurf, Codex, Gemini CLI)",
66
"license": "GPL-3.0",
Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
{
22
"name": "syncable-cli-skills",
33
"description": "Syncable CLI skills for project analysis, security scanning, vulnerability detection, dependency auditing, IaC validation, Kubernetes optimization, and cloud deployment.",
4-
"version": "0.1.0",
4+
"version": "0.1.11",
55
"author": {
66
"name": "Syncable",
77
"email": "support@syncable.dev"
88
},
99
"homepage": "https://syncable.dev",
1010
"license": "MIT",
11-
"keywords": ["syncable", "devops", "security", "deployment", "kubernetes", "docker", "iac"]
11+
"keywords": [
12+
"syncable",
13+
"devops",
14+
"security",
15+
"deployment",
16+
"kubernetes",
17+
"docker",
18+
"iac"
19+
]
1220
}

installer/scripts/copy-skills.js

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
77
const source = resolve(__dirname, '..', '..', 'skills');
88
const dest = resolve(__dirname, '..', 'skills');
99

10+
// Read the canonical version from package.json
11+
const packageJson = JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json'), 'utf-8'));
12+
const version = packageJson.version;
13+
1014
if (!existsSync(source)) {
1115
console.error('Error: skills/ directory not found at', source);
1216
process.exit(1);
@@ -17,21 +21,58 @@ removeSync(dest);
1721
copySync(source, dest);
1822
console.log(`Copied skills from ${source} to ${dest}`);
1923

20-
// Also regenerate installer/plugins/syncable-cli-skills/skills/
21-
// so the Claude Code marketplace plugin stays in sync with the source skills.
24+
// ── Sync version across all files that reference it ─────────────────
25+
26+
// 1. installer/plugins/syncable-cli-skills/.claude-plugin/plugin.json
27+
const pluginJsonPath = resolve(__dirname, '..', 'plugins', 'syncable-cli-skills', '.claude-plugin', 'plugin.json');
28+
if (existsSync(pluginJsonPath)) {
29+
const pluginJson = JSON.parse(readFileSync(pluginJsonPath, 'utf-8'));
30+
pluginJson.version = version;
31+
writeFileSync(pluginJsonPath, JSON.stringify(pluginJson, null, 2) + '\n');
32+
console.log(`Synced plugin.json version to ${version}`);
33+
}
34+
35+
// 2. .claude-plugin/marketplace.json (repo root)
36+
const marketplacePath = resolve(__dirname, '..', '..', '.claude-plugin', 'marketplace.json');
37+
if (existsSync(marketplacePath)) {
38+
const marketplace = JSON.parse(readFileSync(marketplacePath, 'utf-8'));
39+
if (marketplace.metadata) marketplace.metadata.version = version;
40+
if (marketplace.plugins) {
41+
for (const plugin of marketplace.plugins) {
42+
if (plugin.name === 'syncable-cli-skills') {
43+
plugin.version = version;
44+
}
45+
}
46+
}
47+
writeFileSync(marketplacePath, JSON.stringify(marketplace, null, 2) + '\n');
48+
console.log(`Synced marketplace.json version to ${version}`);
49+
}
50+
51+
// 3. PLUGIN_VERSION constant in src/transformers/claude.ts
52+
const claudeTsPath = resolve(__dirname, '..', 'src', 'transformers', 'claude.ts');
53+
if (existsSync(claudeTsPath)) {
54+
let claudeTs = readFileSync(claudeTsPath, 'utf-8');
55+
claudeTs = claudeTs.replace(
56+
/const PLUGIN_VERSION = '[^']+';/,
57+
`const PLUGIN_VERSION = '${version}';`
58+
);
59+
writeFileSync(claudeTsPath, claudeTs);
60+
console.log(`Synced PLUGIN_VERSION to ${version}`);
61+
}
62+
63+
// ── Regenerate plugin skills ────────────────────────────────────────
64+
2265
const pluginSkillsDir = resolve(__dirname, '..', 'plugins', 'syncable-cli-skills', 'skills');
2366
removeSync(pluginSkillsDir);
2467

2568
function transformSkillFile(filePath) {
2669
const raw = readFileSync(filePath, 'utf-8');
27-
// Parse YAML frontmatter (---\n...\n---\n)
2870
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
2971
if (!match) return null;
3072

3173
const frontmatterRaw = match[1];
3274
const body = match[2];
3375

34-
// Extract description value (handles multi-line descriptions with quotes)
3576
const descMatch = frontmatterRaw.match(/^description:\s*(.+)$/m);
3677
if (!descMatch) return null;
3778

installer/src/transformers/claude.ts

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { TransformResult } from './types.js';
66
import { execCommand, commandExists } from '../utils.js';
77

88
const PLUGIN_NAME = 'syncable-cli-skills';
9-
const PLUGIN_VERSION = '0.1.0';
9+
const PLUGIN_VERSION = '0.1.11';
1010
const MARKETPLACE_NAME = 'syncable';
1111
const MARKETPLACE_REPO = 'syncable-dev/syncable-cli';
1212

@@ -202,9 +202,32 @@ export async function installClaudePlugin(skills: Skill[]): Promise<{ cacheDir:
202202
writePluginManifest(cacheDir);
203203
enablePluginInSettings();
204204

205+
// Also write skills to ~/.claude/skills/ for SDK-based integrations
206+
// (e.g. Zed's ACP adapter) that don't read from the plugin cache.
207+
// The SDK loads user-level skills from this directory when configured
208+
// with settingSources: ["user"].
209+
writeUserLevelSkills(skills);
210+
205211
return { cacheDir, skillCount: skills.length };
206212
}
207213

214+
/**
215+
* Write skills to ~/.claude/skills/ so they're available to SDK-based
216+
* integrations (Zed, etc.) that don't read the plugin cache.
217+
*/
218+
function writeUserLevelSkills(skills: Skill[]): void {
219+
const userSkillsDir = path.join(os.homedir(), '.claude', 'skills');
220+
221+
for (const skill of skills) {
222+
const results = transformForClaude(skill);
223+
for (const { relativePath, content } of results) {
224+
const fullPath = path.join(userSkillsDir, relativePath);
225+
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
226+
fs.writeFileSync(fullPath, content);
227+
}
228+
}
229+
}
230+
208231
/**
209232
* Remove the Claude Code plugin.
210233
*/
@@ -254,19 +277,18 @@ export async function uninstallClaudePlugin(): Promise<void> {
254277
}
255278
}
256279

257-
// Clean up old flat-file skills
258-
const oldDirs = [
259-
path.join(os.homedir(), '.claude', 'skills', 'syncable'),
260-
];
261-
for (const dir of oldDirs) {
262-
if (fs.existsSync(dir)) fs.rmSync(dir, { recursive: true });
263-
}
264-
265-
const flatSkillsDir = path.join(os.homedir(), '.claude', 'skills');
266-
if (fs.existsSync(flatSkillsDir)) {
267-
for (const file of fs.readdirSync(flatSkillsDir)) {
268-
if (file.startsWith('syncable-') && file.endsWith('.md')) {
269-
fs.unlinkSync(path.join(flatSkillsDir, file));
280+
// Clean up user-level skills (both old flat files and new directory format)
281+
const userSkillsDir = path.join(os.homedir(), '.claude', 'skills');
282+
if (fs.existsSync(userSkillsDir)) {
283+
for (const entry of fs.readdirSync(userSkillsDir)) {
284+
if (entry.startsWith('syncable-')) {
285+
const entryPath = path.join(userSkillsDir, entry);
286+
const stat = fs.statSync(entryPath);
287+
if (stat.isDirectory()) {
288+
fs.rmSync(entryPath, { recursive: true });
289+
} else if (entry.endsWith('.md')) {
290+
fs.unlinkSync(entryPath);
291+
}
270292
}
271293
}
272294
}

0 commit comments

Comments
 (0)