diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index faaf4e7..fe4b928 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -6,14 +6,14 @@ }, "metadata": { "description": "Syncable CLI skills for AI coding agents — project analysis, security, vulnerabilities, dependencies, IaC validation, and cloud deployment.", - "version": "0.1.11" + "version": "0.1.13" }, "plugins": [ { "name": "syncable-cli-skills", "source": "./installer/plugins/syncable-cli-skills", "description": "Syncable CLI skills for project analysis, security scanning, vulnerability detection, dependency auditing, IaC validation, Kubernetes optimization, and cloud deployment.", - "version": "0.1.11", + "version": "0.1.13", "author": { "name": "Syncable", "email": "support@syncable.dev" diff --git a/installer/.gitignore b/installer/.gitignore index df97807..cba50e6 100644 --- a/installer/.gitignore +++ b/installer/.gitignore @@ -1,3 +1,4 @@ node_modules/ dist/ skills/ +!plugins/syncable-cli-skills/skills/ diff --git a/installer/package.json b/installer/package.json index ce24a2b..b148204 100644 --- a/installer/package.json +++ b/installer/package.json @@ -1,6 +1,6 @@ { "name": "syncable-cli-skills", - "version": "0.1.11", + "version": "0.1.13", "type": "module", "description": "Install Syncable CLI skills for AI coding agents (Claude Code, Cursor, Windsurf, Codex, Gemini CLI)", "license": "GPL-3.0", diff --git a/installer/plugins/syncable-cli-skills/.claude-plugin/plugin.json b/installer/plugins/syncable-cli-skills/.claude-plugin/plugin.json index f6e4a48..9f1a6fb 100644 --- a/installer/plugins/syncable-cli-skills/.claude-plugin/plugin.json +++ b/installer/plugins/syncable-cli-skills/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "syncable-cli-skills", "description": "Syncable CLI skills for project analysis, security scanning, vulnerability detection, dependency auditing, IaC validation, Kubernetes optimization, and cloud deployment.", - "version": "0.1.11", + "version": "0.1.13", "author": { "name": "Syncable", "email": "support@syncable.dev" diff --git a/installer/plugins/syncable-cli-skills/skills/syncable-analyze/SKILL.md b/installer/plugins/syncable-cli-skills/skills/syncable-analyze/SKILL.md new file mode 100644 index 0000000..e1678d1 --- /dev/null +++ b/installer/plugins/syncable-cli-skills/skills/syncable-analyze/SKILL.md @@ -0,0 +1,103 @@ +--- +description: "Analyze a project's tech stack including languages, frameworks, runtimes, package managers, and dependencies using the Syncable CLI sync-ctl tool" +--- + +## Purpose + +Analyze a project directory to detect its tech stack: programming languages, frameworks, runtimes, package managers, dependencies, Docker presence, and monorepo structure. This is the foundation skill — most workflows start here to understand what they're working with. + +## Prerequisites + +- `sync-ctl` binary installed and on PATH +- Agent has access to the project directory + +## Commands + +### Basic analysis (agent output) + +```bash +sync-ctl analyze --agent +``` + +### Human-readable matrix view + +```bash +sync-ctl analyze --display matrix +``` + +### Filtered analysis (only specific aspects) + +```bash +sync-ctl analyze --agent --only languages,frameworks +sync-ctl analyze --agent --only dependencies +``` + +### Key Flags + +| Flag | Purpose | +|------|---------| +| `--agent` | Compressed output for agent consumption (always use when processing results) | +| `--detailed` | Show detailed analysis (legacy vertical format) | +| `--display {matrix\|detailed\|summary}` | Display format for human-readable output | +| `--only ` | Comma-separated: `languages`, `frameworks`, `dependencies` | + +## Output Interpretation + +When reporting to the user, prioritize: primary language, main framework, runtime version, and whether Docker/K8s infrastructure exists. + +## Reading Results + +When you use `--agent`, the output is a compressed summary — not the full analysis. Act on it directly for most decisions. + +The output JSON includes: +- `summary` — project count, languages, frameworks detected +- `full_data_ref` — reference ID for retrieving full data +- `retrieval_hint` — exact command to get more details + +To drill into specifics: +```bash +# Get framework details +sync-ctl retrieve --query "section:frameworks" + +# Get language breakdown +sync-ctl retrieve --query "section:languages" + +# Get specific project details (monorepos) +sync-ctl retrieve --query "project:" + +# Get specific language details +sync-ctl retrieve --query "language:Go" + +# Get specific framework details +sync-ctl retrieve --query "framework:React" + +# List all stored outputs +sync-ctl retrieve --list +``` + +**Available query filters:** `section:summary`, `section:frameworks`, `section:languages`, `language:`, `framework:`, `project:`, `compact:true` + +## Error Handling + +| Error | Cause | Action | +|-------|-------|--------| +| `No such file or directory` | Invalid path | Ask user to verify the project path | +| Empty output | No recognizable project files | Tell user the directory may not contain a supported project. Run `sync-ctl support` to show supported technologies | +| Timeout | Very large monorepo | Try `--only languages` for a faster partial scan | + +## Examples + +**Analyze current directory:** +```bash +sync-ctl analyze . --agent +``` + +**Analyze a specific project:** +```bash +sync-ctl analyze /path/to/project --agent +``` + +**Quick language-only check:** +```bash +sync-ctl analyze . --agent --only languages +``` diff --git a/installer/plugins/syncable-cli-skills/skills/syncable-dependencies/SKILL.md b/installer/plugins/syncable-cli-skills/skills/syncable-dependencies/SKILL.md new file mode 100644 index 0000000..db2aa15 --- /dev/null +++ b/installer/plugins/syncable-cli-skills/skills/syncable-dependencies/SKILL.md @@ -0,0 +1,93 @@ +--- +description: "Audit project dependencies for licenses, production vs development split, and detailed package analysis using the Syncable CLI sync-ctl tool" +--- + +## Purpose + +Analyze project dependencies in detail: list all packages, check license types, separate production from development dependencies, and optionally flag vulnerabilities inline. Use this for license compliance and dependency inventory. + +## Prerequisites + +- `sync-ctl` binary installed and on PATH +- Agent has access to the project directory + +## Commands + +### Full dependency analysis with licenses + +```bash +sync-ctl dependencies --licenses --agent +``` + +### Production dependencies only + +```bash +sync-ctl dependencies --licenses --prod-only --agent +``` + +### Key Flags + +| Flag | Purpose | +|------|---------| +| `--agent` | Compressed output for agent consumption (always use) | +| `--licenses` | Include license information for each dependency | +| `--vulnerabilities` | Quick inline vulnerability check (for thorough CVE scanning, use the standalone `sync-ctl vulnerabilities` command instead) | +| `--prod-only` | Show only production dependencies | +| `--dev-only` | Show only development dependencies | + +## Output Interpretation + +**Priority for reporting to user:** +1. License concerns (copyleft in commercial projects, unknown licenses) +2. Dependency counts (prod vs dev) +3. Specific packages only if asked + +**When to use `--vulnerabilities` vs standalone `vulnerabilities` command:** +- Use `--vulnerabilities` here for a quick inline check alongside license info +- Use `sync-ctl vulnerabilities` for a dedicated, thorough CVE scan + +## Reading Results + +When you use `--agent`, the output is a **compressed summary** with counts, license distribution, and source breakdown. Individual package details are NOT in the compressed output — use `sync-ctl retrieve` to get them. + +**What's in the compressed output:** +- `total` — total dependency count +- `production` / `development` — prod vs dev split +- `by_source` — counts per ecosystem (npm, crates.io, pypi, etc.) +- `by_license` — license distribution +- `full_data_ref` — reference ID for the full data + +**To get individual package details, use retrieve:** +```bash +# Get the full dependency list +sync-ctl retrieve + +# Search for a specific package +sync-ctl retrieve --query "file:package.json" +``` + +Results are paginated (default 20). Use `--limit N --offset M` for more. + +## Error Handling + +| Error | Cause | Action | +|-------|-------|--------| +| `No dependencies found` | No package manager files | Verify project path, run `sync-ctl analyze` to check for supported package managers | +| Incomplete results | Some package managers not fully parsed | Note which ecosystems were scanned and which may be missing | + +## Examples + +**Full audit with licenses:** +```bash +sync-ctl dependencies . --licenses --agent +``` + +**Production-only for license compliance:** +```bash +sync-ctl dependencies . --licenses --prod-only --agent +``` + +**Quick vulnerability check alongside deps:** +```bash +sync-ctl dependencies . --licenses --vulnerabilities --agent +``` diff --git a/installer/plugins/syncable-cli-skills/skills/syncable-deploy-pipeline/SKILL.md b/installer/plugins/syncable-cli-skills/skills/syncable-deploy-pipeline/SKILL.md new file mode 100644 index 0000000..1b96fac --- /dev/null +++ b/installer/plugins/syncable-cli-skills/skills/syncable-deploy-pipeline/SKILL.md @@ -0,0 +1,139 @@ +--- +description: "Deploy a project through Syncable by orchestrating authentication, project analysis, security gating, and cloud deployment using the Syncable CLI sync-ctl tool" +--- + +## Purpose + +Orchestrate a full deployment pipeline through the Syncable platform: authenticate, analyze the project, run a security audit as a gate, then deploy. Ensures no deployment happens without authentication and security review. + +## Prerequisites + +- `sync-ctl` binary installed and on PATH +- Internet access for Syncable API +- Agent has access to the project directory + +## Workflow Steps + +### Step 1: Check authentication and platform context + +```bash +sync-ctl auth status +``` + +**Decision point:** If not authenticated: +```bash +sync-ctl auth login +``` + +Then verify project/environment context: +```bash +sync-ctl project current +``` + +**Decision point:** If no project selected: +```bash +sync-ctl org list +# Ask user which org +sync-ctl org select +sync-ctl project list +# Ask user which project +sync-ctl project select +sync-ctl env list +# Ask user which environment +sync-ctl env select +``` + +### Step 2: Analyze the project + +```bash +sync-ctl analyze --agent +``` + +Save the `full_data_ref` from the analyze output — do not re-run analyze in later steps; use `sync-ctl retrieve` with this ref_id instead. + +### Step 3: Pre-deploy security audit + +Execute the `syncable-security-audit` workflow inline (all its steps and decision logic). **Note:** Step 2's analyze output is reused here — do not re-run analyze. + +1. `sync-ctl security --mode paranoid --agent` +2. `sync-ctl vulnerabilities --agent` +3. `sync-ctl validate ` (if IaC files exist per Step 2's analysis) + +**CRITICAL GATE:** Check the security output's `status` field: +- If `status` is "CRITICAL_ISSUES_FOUND": present findings to user, warn, require confirmation +- If `status` is "HIGH_ISSUES_FOUND": warn but allow deployment +- If `status` is "CLEAN": proceed to deploy + +All critical findings are in the `critical_issues` array of the compressed output — no retrieval needed for the gate decision. + +### Step 4: Deploy + +**4a. Get deployment recommendation:** +```bash +sync-ctl deploy preview +``` + +This returns JSON with: provider recommendation (with reasoning), region, machine type, detected port, health check endpoint, alternatives, discovered .env files, and already-deployed service endpoints. + +**4b. Present recommendation to user and confirm.** Show: +- Recommended provider, region, machine type +- Detected port and whether public/internal +- Any .env files found — ask if they should be injected +- Any service endpoints that could be referenced (e.g., `BACKEND_URL`) + +**4c. Deploy with confirmed settings:** +```bash +sync-ctl deploy run --provider --region --port +``` + +Add `--public` if user wants a public URL. Add `--env KEY=VALUE` for env vars and `--secret KEY` for secrets (user prompted in terminal). Add `--env-file .env` to inject from file. + +**4d. Monitor:** +```bash +sync-ctl deploy status --watch +``` + +**Example with user overrides:** +```bash +# User said "deploy to GCP in us-central1, make it public, use the .env file" +sync-ctl deploy run ./services/api \ + --provider gcp --region us-central1 --port 8080 --public \ + --env-file .env \ + --secret "STRIPE_KEY" +``` + +## Decision Points Summary + +| Condition | Action | +|-----------|--------| +| Not authenticated | Run `sync-ctl auth login` first | +| No project/env selected | Guide user through selection | +| Critical security findings | Warn user, require explicit confirmation to proceed | +| High security findings (no critical) | Warn user but allow deployment | +| Clean security audit | Proceed to deploy | + +## Safety + +- **Never deploy without the security gate.** Even if the user says "just deploy", run at least a fast security scan. +- **Always confirm with the user before triggering deployment.** Show them what will be deployed, to which environment. +- **Monitor deployment status** after triggering — don't fire-and-forget. + +## Cross-Step Retrieval + +Each step produces a `full_data_ref` in its output. You can retrieve details from any previous step at any time: + +```bash +# Check what data is available from all steps +sync-ctl retrieve --list + +# Get framework details from Step 2 (analyze) +sync-ctl retrieve --query "section:frameworks" + +# Get critical security findings from Step 3 +sync-ctl retrieve --query "severity:critical" + +# Get vulnerability details from Step 3 +sync-ctl retrieve --query "severity:high" +``` + +Do NOT re-run a command just to get more detail — use `sync-ctl retrieve` instead. diff --git a/installer/plugins/syncable-cli-skills/skills/syncable-iac-pipeline/SKILL.md b/installer/plugins/syncable-cli-skills/skills/syncable-iac-pipeline/SKILL.md new file mode 100644 index 0000000..62f250e --- /dev/null +++ b/installer/plugins/syncable-cli-skills/skills/syncable-iac-pipeline/SKILL.md @@ -0,0 +1,85 @@ +--- +description: "Validate all infrastructure-as-code files by combining Dockerfile linting, Docker Compose validation, Kubernetes manifest checking, and Helm chart analysis using the Syncable CLI sync-ctl tool" +--- + +## Purpose + +Validate all infrastructure-as-code files in a project by chaining IaC linting with Kubernetes optimization and security checks. Covers Dockerfiles, Docker Compose, Terraform, K8s manifests, and Helm charts. + +## Prerequisites + +- `sync-ctl` binary installed and on PATH +- Agent has access to the project directory +- Project must contain IaC files + +## Workflow Steps + +### Step 1: Analyze the project + +```bash +sync-ctl analyze --agent +``` + +Parse the output to determine: +- Which IaC types exist (Dockerfile, Compose, Terraform, K8s manifests) +- Whether K8s manifests are present — needed for step 3 + +Save the `full_data_ref` from the analyze output — the ref_id from this step can be reused in later steps to retrieve IaC file details without re-running analyze. + +### Step 2: Validate IaC files + +```bash +sync-ctl validate +``` + +If step 1 revealed specific types, you can filter: +```bash +sync-ctl validate --types dockerfile,compose,terraform +``` + +### Step 3: Kubernetes optimization (conditional) + +**Decision point:** Only run if step 1 detected Kubernetes manifests or Helm charts. + +```bash +sync-ctl optimize --full --agent +``` + +The `--full` flag includes kubelint security checks and helmlint validation on top of resource optimization. + +## Decision Points Summary + +| Condition | Action | +|-----------|--------| +| No K8s manifests or Helm charts in step 1 | Skip step 3 | +| No IaC files at all in step 1 | Abort workflow, tell user no IaC files found | + +## Report Synthesis + +Produce an IaC validation report: + +1. **Dockerfile Issues** — hadolint violations by severity +2. **Docker Compose Issues** — dclint violations +3. **Terraform Issues** — validation errors +4. **Kubernetes Issues** — kubelint security findings and resource optimization recommendations (if step 3 ran) +5. **Actionable Fixes** — which issues can be auto-fixed with `--fix` + +## Cross-Step Retrieval + +Each step produces a `full_data_ref` in its output. You can retrieve details from any previous step at any time: + +```bash +# Check what data is available from all steps +sync-ctl retrieve --list + +# Get framework details from Step 1 (analyze) +sync-ctl retrieve --query "section:frameworks" + +# Get critical security findings from Step 2 +sync-ctl retrieve --query "severity:critical" + +# Get vulnerability details from Step 3 +sync-ctl retrieve --query "severity:high" +``` + +Do NOT re-run a command just to get more detail — use `sync-ctl retrieve` instead. diff --git a/installer/plugins/syncable-cli-skills/skills/syncable-optimize/SKILL.md b/installer/plugins/syncable-cli-skills/skills/syncable-optimize/SKILL.md new file mode 100644 index 0000000..5b6aafa --- /dev/null +++ b/installer/plugins/syncable-cli-skills/skills/syncable-optimize/SKILL.md @@ -0,0 +1,128 @@ +--- +description: "Optimize Kubernetes resource requests and limits, analyze costs, detect over-provisioned containers, and right-size pods using the Syncable CLI sync-ctl tool" +--- + +## Purpose + +Analyze Kubernetes manifests and optionally live cluster metrics to recommend resource right-sizing, estimate costs, and detect configuration drift. Can also run kubelint security checks and helmlint validation with `--full` flag. + +## Prerequisites + +- `sync-ctl` binary installed and on PATH +- For static analysis: K8s manifest files (YAML) in the project +- For live cluster analysis: valid kubeconfig with cluster access +- For cost estimation: `--cloud-provider` flag + +## Commands + +### Static manifest analysis + +```bash +sync-ctl optimize --agent +``` + +### Live cluster analysis + +```bash +sync-ctl optimize --cluster --agent +sync-ctl optimize --cluster my-context --namespace default --agent +``` + +### With Prometheus metrics + +```bash +sync-ctl optimize --cluster --prometheus http://localhost:9090 --period 30d --agent +``` + +### Full analysis (includes kubelint + helmlint) + +```bash +sync-ctl optimize --full --agent +``` + +### Cost estimation + +```bash +sync-ctl optimize --cluster --cloud-provider aws --region us-east-1 --agent +``` + +### Key Flags + +| Flag | Purpose | +|------|---------| +| `--agent` | Compressed output for agent consumption (always use) | +| `--cluster [CONTEXT]` | Connect to live K8s cluster (uses current context if no name given) | +| `--prometheus ` | Prometheus URL for historical metrics | +| `--namespace ` | Target namespace (or `*` for all) | +| `--period ` | Analysis period for metrics (e.g., `7d`, `30d`) | +| `--full` | Include kubelint security checks + helmlint validation | +| `--cloud-provider {aws\|gcp\|azure\|onprem}` | Cloud provider for cost estimation | +| `--region ` | Region for pricing (default: `us-east-1`) | +| `--fix` | Generate fix suggestions | +| `--apply` | **DANGEROUS:** Apply fixes to manifest files. Requires `--fix`. Never use without explicit user confirmation. | +| `--dry-run` | Preview changes without applying | +| `--severity ` | Minimum severity to report | +| `--threshold <0-100>` | Minimum waste percentage threshold | + +## Output Interpretation + +**Priority for reporting to user:** +1. High-confidence right-sizing recommendations with cost savings +2. Critical security findings (from `--full`) +3. Drift detection issues +4. Cost breakdown summary + +## Reading Results + +When you use `--agent`, the output is a compressed summary. High-confidence right-sizing recommendations are included in full. Cost summary and drift findings are always present when applicable. + +The output JSON includes: +- `summary` — total recommendations, estimated savings, containers analyzed +- `top_recommendations` — highest-impact right-sizing suggestions +- `costs` — cost attribution summary (if `--cloud-provider` set) +- `drift` — configuration drift issues (if `--cluster` set) +- `full_data_ref` — reference ID for retrieving full data +- `retrieval_hint` — exact command for drill-down + +To drill into specifics: +```bash +# Get high-severity findings +sync-ctl retrieve --query "severity:high" + +# Get recommendations for a specific container +sync-ctl retrieve --query "container:my-app" +``` + +**Available query filters:** `severity:`, `container:` + +## Safety + +- `--fix` only generates suggestions — it does NOT modify files +- `--apply` (requires `--fix`) writes changes to files — always confirm with user first +- `--dry-run` previews what `--apply` would do — use this to show the user before applying +- Recommend: always run `--fix --dry-run` first, show output, then `--fix --apply` only after user approval + +## Error Handling + +| Error | Cause | Action | +|-------|-------|--------| +| `No Kubernetes manifests found` | No YAML with K8s resources | Run `sync-ctl analyze --agent` to check for K8s presence | +| `Cannot connect to cluster` | Invalid kubeconfig or cluster unreachable | Check `kubectl cluster-info` works, verify context name | +| `Prometheus unreachable` | Wrong URL or Prometheus not running | Verify URL, fall back to static analysis without `--prometheus` | + +## Examples + +**Quick static analysis:** +```bash +sync-ctl optimize . --agent +``` + +**Full analysis with live cluster and cost estimation:** +```bash +sync-ctl optimize . --cluster --cloud-provider aws --full --agent +``` + +**Preview fixes before applying:** +```bash +sync-ctl optimize . --fix --dry-run --agent +``` diff --git a/installer/plugins/syncable-cli-skills/skills/syncable-platform/SKILL.md b/installer/plugins/syncable-cli-skills/skills/syncable-platform/SKILL.md new file mode 100644 index 0000000..cdf8a12 --- /dev/null +++ b/installer/plugins/syncable-cli-skills/skills/syncable-platform/SKILL.md @@ -0,0 +1,270 @@ +--- +description: "Authenticate, login, sign in to Syncable platform. Switch organizations, projects, and environments. Deploy services to cloud providers. Check current context and manage platform settings using sync-ctl" +--- + +## Purpose + +Manage Syncable platform operations: authenticate, switch organizations/projects/environments by name, check current context, and trigger deployments. This skill handles the full platform lifecycle. + +## Prerequisites + +- `sync-ctl` binary installed and on PATH +- Internet access for Syncable API + +## Auth-First Rule + +**Always check auth before any platform operation:** + +```bash +sync-ctl auth status +``` + +If the response says "Not logged in" or "Session expired": + +```bash +sync-ctl auth login +``` + +This opens a browser for OAuth device flow. Tell the user: "A browser window will open for you to authorize. If it doesn't open automatically, visit the URL shown and enter the code." Then wait — the command blocks until the user authorizes. + +## Switching Context + +### Switch project by name + +When user says "change project to my-app" or "use project my-app": + +1. List projects to find the ID: +```bash +sync-ctl project list +``` + +2. Parse the table output to find the row where NAME matches the user's request (case-insensitive, partial match OK). + +3. Select by ID: +```bash +sync-ctl project select +``` + +**If multiple matches:** show the user the matching projects and ask which one. +**If no matches:** tell the user no project with that name was found, and show available projects. + +### Switch organization by name + +When user says "switch org to acme" or "use organization acme": + +1. List organizations: +```bash +sync-ctl org list +``` + +2. Parse output to find matching org name → ID. + +3. Select: +```bash +sync-ctl org select +``` + +**Note:** Switching org clears the current project and environment selection. After switching org, you'll need to select a project too. + +### Switch environment by name + +When user says "use staging" or "switch to production": + +```bash +sync-ctl env select +``` + +Environment select accepts **names directly** (not just IDs). No need to list first. + +### Combined switches + +When user says "switch to my-app on staging": + +1. Find and select the project (list → match → select) +2. Then select the environment by name: +```bash +sync-ctl env select staging +``` + +When user says "switch to acme org, project my-app, staging env": + +1. `sync-ctl org list` → find acme → `sync-ctl org select ` +2. `sync-ctl project list` → find my-app → `sync-ctl project select ` +3. `sync-ctl env select staging` + +## Checking Current Context + +When user says "what project am I on" or "show current context": + +```bash +sync-ctl project current +``` + +Shows: organization, project, environment, and last updated timestamp. + +## Commands Reference + +### Authentication + +```bash +sync-ctl auth status # Check if authenticated +sync-ctl auth login # Log in (opens browser) +sync-ctl auth login --no-browser # Log in without auto-opening browser +sync-ctl auth logout # Log out and clear credentials +sync-ctl auth token --raw # Print raw access token +``` + +### Organizations + +```bash +sync-ctl org list # List all organizations +sync-ctl org select # Select organization (requires UUID) +``` + +### Projects + +```bash +sync-ctl project list # List projects in current org +sync-ctl project list --org-id # List projects in specific org +sync-ctl project select # Select project (requires UUID) +sync-ctl project current # Show current context +sync-ctl project info # Show current project details +sync-ctl project info # Show specific project details +``` + +### Environments + +```bash +sync-ctl env list # List environments in current project +sync-ctl env select # Select environment (accepts name or ID) +``` + +### Deployment (non-interactive — use these as an agent) + +```bash +# Preview deployment recommendation (returns JSON) +sync-ctl deploy preview +sync-ctl deploy preview --provider hetzner --region nbg1 + +# Deploy with settings (triggers actual deployment) +sync-ctl deploy run --provider hetzner --region nbg1 --port 8080 --public +sync-ctl deploy run --env "NODE_ENV=production" --secret "DATABASE_URL" --env-file .env + +# Monitor deployment +sync-ctl deploy status +sync-ctl deploy status --watch + +# Interactive wizard (for humans, NOT usable by agents) +sync-ctl deploy wizard + +# Create a new environment +sync-ctl deploy new-env +``` + +### Deploy Flow for Agents + +**Step 1: Preview** — get a recommendation as JSON: +```bash +sync-ctl deploy preview . --service-name my-service +``` + +The output includes: +- `recommendation` — provider, region, machine type, port, health check, with reasoning +- `connected_providers` — all available providers +- `alternatives` — other options the user could choose +- `parsed_env_files` — discovered .env files and non-secret keys +- `deployed_service_endpoints` — URLs of already-deployed services (public and private) + +**Step 2: Show user the preview and get explicit confirmation.** Present: +- Service name, provider, region, machine type +- Port and whether public or internal +- If .env files found, list the keys and ask user which ones to include +- If deployed service endpoints exist, list them and ask which to wire up + +**CRITICAL RULES:** +- NEVER deploy without showing the preview first and getting user confirmation +- ONLY include env vars the user explicitly asked for or confirmed — do NOT auto-include discovered env vars or service endpoints +- If the user says "deploy with API_BASE=..." then ONLY set API_BASE, nothing else +- If the user wants additional env vars, they need to say so explicitly +- Always use `--service-name` to set the name the user wants, not the directory name + +**Step 3: Deploy** — with ONLY the settings the user confirmed: +```bash +sync-ctl deploy run . --service-name frontend-v2 --provider hetzner --region nbg1 --port 8080 --env "API_BASE=https://..." +``` + +Returns JSON with `config_id` and `task_id`. + +**Step 4: Monitor** — watch until complete: +```bash +sync-ctl deploy status --watch +``` + +### Deploy Run Flags + +| Flag | Purpose | +|------|---------| +| `--service-name ` | Service name (ALWAYS set this — defaults to directory name otherwise) | +| `--provider ` | Cloud provider | +| `--region ` | Deployment region (e.g., `nbg1`, `us-central1`) | +| `--machine-type ` | Machine type (e.g., `cx22`, `e2-small`) | +| `--port ` | Port to expose | +| `--public` | Make service publicly accessible (default: internal-only) | +| `--cpu ` | CPU allocation for GCP/Azure (e.g., `1000m`) | +| `--memory ` | Memory allocation for GCP/Azure (e.g., `512Mi`) | +| `--env ` | Non-secret env var (repeatable) | +| `--secret ` | Secret key — user prompted in terminal for value (repeatable) | +| `--env-file ` | Load env vars from .env file (secrets auto-detected by key name) | +| `--min-instances ` | Minimum replicas | +| `--max-instances ` | Maximum replicas | + +## Output Format + +All platform commands output human-readable text (no `--agent` mode). Parse the table output to extract IDs and names. Table format is typically: + +``` +ID NAME DESCRIPTION +------... +abc123-def456-... my-project My project description +``` + +## Error Handling + +| Error | Cause | Action | +|-------|-------|--------| +| `Not authenticated` | No valid session | Run `sync-ctl auth login` | +| `Token expired` | Session timed out | Run `sync-ctl auth login` | +| `No organization selected` | Org not set | Run `sync-ctl org list` then `sync-ctl org select ` | +| `No project selected` | Project not set | Run `sync-ctl project list` then `sync-ctl project select ` | +| `No environment selected` | Env not set | Run `sync-ctl env list` then `sync-ctl env select ` | +| `Project not found` | Wrong ID | Run `sync-ctl project list` to see available projects | +| `Deployment failed` | Build or infra error | Check `sync-ctl deploy status ` for details | + +## Examples + +**User: "change project to my-app"** +```bash +sync-ctl auth status # Check auth first +sync-ctl project list # Find my-app's ID +sync-ctl project select # Select it +``` + +**User: "switch to staging"** +```bash +sync-ctl env select staging +``` + +**User: "switch to acme org and select the api-gateway project on production"** +```bash +sync-ctl auth status +sync-ctl org list # Find acme's ID +sync-ctl org select +sync-ctl project list # Find api-gateway's ID +sync-ctl project select +sync-ctl env select production +``` + +**User: "what am I connected to?"** +```bash +sync-ctl project current +``` diff --git a/installer/plugins/syncable-cli-skills/skills/syncable-project-assessment/SKILL.md b/installer/plugins/syncable-cli-skills/skills/syncable-project-assessment/SKILL.md new file mode 100644 index 0000000..ab34e1c --- /dev/null +++ b/installer/plugins/syncable-cli-skills/skills/syncable-project-assessment/SKILL.md @@ -0,0 +1,104 @@ +--- +description: "Run a comprehensive project health check combining stack analysis, security scanning, vulnerability detection, and dependency auditing using the Syncable CLI sync-ctl tool" +--- + +## Purpose + +Run a comprehensive project health check by chaining multiple Syncable CLI commands. Produces a unified report covering tech stack, security posture, vulnerability status, and dependency health. + +## Prerequisites + +- `sync-ctl` binary installed and on PATH +- Agent has access to the project directory + +## Workflow Steps + +### Step 1: Analyze the project stack + +```bash +sync-ctl analyze --agent +``` + +Parse the output to understand: +- What languages and frameworks are present +- Whether dependencies exist (needed for steps 3 and 4) +- Whether secrets-capable files exist (affects step 2 mode) + +Save the `full_data_ref` from the analyze output — you'll use it to retrieve details without re-running analyze. + +### Step 2: Security scan + +```bash +sync-ctl security --mode balanced --agent +``` + +**Decision point:** If step 1 shows no config files, secrets files, or environment files, use `--mode lightning` instead of `--mode balanced` to save time. + +### Step 3: Vulnerability scan + +```bash +sync-ctl vulnerabilities --agent +``` + +**Decision point:** If step 1 detected no dependencies (no package.json, requirements.txt, Cargo.toml, go.mod, etc.), **skip this step entirely** and note "No dependencies detected" in the report. + +### Step 4: Dependency audit + +```bash +sync-ctl dependencies --licenses --agent +``` + +**Decision point:** Same as step 3 — skip if no dependencies detected. + +## Decision Points Summary + +| Condition | Action | +|-----------|--------| +| No dependencies detected in step 1 | Skip steps 3 and 4 | +| No secrets-capable files in step 1 | Use `--mode lightning` in step 2 | +| Vulnerability scanner missing | Run `sync-ctl tools install --yes`, then retry step 3 | + +## Report Synthesis + +After all steps complete, synthesize a unified report for the user: + +1. **Tech Stack** — primary language, frameworks, runtimes +2. **Security Score** — score from security scan, critical/high finding count +3. **Vulnerabilities** — critical/high CVE count, packages with available fixes +4. **Dependencies** — total count, license concerns (copyleft, unknown) +5. **Recommendations** — top 3-5 actionable items prioritized by severity + +## Examples + +**Assess current directory:** + +The agent runs these commands in sequence, skipping steps based on decision points: + +```bash +sync-ctl analyze . --agent +sync-ctl security . --mode balanced --agent +sync-ctl vulnerabilities . --agent +sync-ctl dependencies . --licenses --agent +``` + +Then synthesizes the results into a single report for the user. + +## Cross-Step Retrieval + +Each step produces a `full_data_ref` in its output. You can retrieve details from any previous step at any time: + +```bash +# Check what data is available from all steps +sync-ctl retrieve --list + +# Get framework details from Step 1 (analyze) +sync-ctl retrieve --query "section:frameworks" + +# Get critical security findings from Step 2 +sync-ctl retrieve --query "severity:critical" + +# Get vulnerability details from Step 3 +sync-ctl retrieve --query "severity:high" +``` + +Do NOT re-run a command just to get more detail — use `sync-ctl retrieve` instead. diff --git a/installer/plugins/syncable-cli-skills/skills/syncable-security-audit/SKILL.md b/installer/plugins/syncable-cli-skills/skills/syncable-security-audit/SKILL.md new file mode 100644 index 0000000..ac6df1b --- /dev/null +++ b/installer/plugins/syncable-cli-skills/skills/syncable-security-audit/SKILL.md @@ -0,0 +1,100 @@ +--- +description: "Perform a thorough pre-deployment or compliance security review combining deep security scan, CVE checks, and IaC validation using the Syncable CLI sync-ctl tool" +--- + +## Purpose + +Perform a deep, multi-layered security review suitable for pre-deployment gates or compliance audits. Goes deeper than the project assessment by using thorough/paranoid scan modes and including IaC validation. + +## Prerequisites + +- `sync-ctl` binary installed and on PATH +- Agent has access to the project directory + +## Workflow Steps + +### Step 1: Analyze the project + +```bash +sync-ctl analyze --agent +``` + +Parse the output to determine: +- What IaC files exist (Dockerfiles, Compose, Terraform, K8s manifests) — needed for step 4 +- What dependencies exist — needed for step 3 + +Save the `full_data_ref` from the analyze output — you'll use it to retrieve details without re-running analyze. + +### Step 2: Deep security scan + +Choose mode based on context: + +**For PR reviews / pre-merge:** +```bash +sync-ctl security --mode thorough --agent +``` + +**For production deployment / compliance:** +```bash +sync-ctl security --mode paranoid --agent +``` + +### Step 3: Vulnerability scan + +```bash +sync-ctl vulnerabilities --agent +``` + +### Step 4: IaC validation + +**Decision point:** Only run if step 1 detected Docker, Compose, Terraform, or K8s files. + +```bash +sync-ctl validate +``` + +If specific types are known from step 1, filter: +```bash +sync-ctl validate --types dockerfile,compose +``` + +## Decision Points Summary + +| Condition | Action | +|-----------|--------| +| PR review context | Use `--mode thorough` in step 2 | +| Pre-deploy / compliance context | Use `--mode paranoid` in step 2 | +| No IaC files detected in step 1 | Skip step 4 | +| No dependencies detected in step 1 | Skip step 3 | + +## Report Synthesis + +Produce a security audit report: + +1. **Security Findings** — all Critical and High findings with file locations and remediation +2. **Vulnerability Status** — CVEs by severity, packages needing updates +3. **IaC Compliance** — lint violations in Dockerfiles, Compose, Terraform +4. **Overall Verdict** — PASS (no critical/high findings), WARN (high findings but no critical), FAIL (critical findings present) +5. **Remediation Priority** — ordered list of actions to resolve findings + +**If critical findings exist:** Explicitly warn the user. If this audit is part of a deploy pipeline, recommend blocking deployment until critical issues are resolved. + +## Cross-Step Retrieval + +Each step produces a `full_data_ref` in its output. You can retrieve details from any previous step at any time: + +```bash +# Check what data is available from all steps +sync-ctl retrieve --list + +# Get framework details from Step 1 (analyze) +sync-ctl retrieve --query "section:frameworks" + +# Get critical security findings from Step 2 +sync-ctl retrieve --query "severity:critical" + +# Get vulnerability details from Step 3 +sync-ctl retrieve --query "severity:high" +``` + +Do NOT re-run a command just to get more detail — use `sync-ctl retrieve` instead. diff --git a/installer/plugins/syncable-cli-skills/skills/syncable-security/SKILL.md b/installer/plugins/syncable-cli-skills/skills/syncable-security/SKILL.md new file mode 100644 index 0000000..e67a79e --- /dev/null +++ b/installer/plugins/syncable-cli-skills/skills/syncable-security/SKILL.md @@ -0,0 +1,110 @@ +--- +description: "Scan code for leaked secrets, credentials, API keys, hardcoded passwords, and insecure code patterns using the Syncable CLI sync-ctl security scanner" +--- + +## Purpose + +Perform security analysis on a codebase: detect leaked secrets (API keys, tokens, passwords, private keys), identify insecure code patterns, and analyze configuration security. Returns findings with severity levels, file locations, and remediation guidance. + +## Prerequisites + +- `sync-ctl` binary installed and on PATH +- Agent has access to the project directory + +## Commands + +### Standard security scan + +```bash +sync-ctl security --mode balanced --agent +``` + +### Mode Selection Guide + +Always pass `--mode` explicitly. Choose based on context: + +| Mode | When to use | Speed | +|------|------------|-------| +| `lightning` | Quick check, only critical files (.env, configs) | Fastest | +| `fast` | Smart sampling, good for large repos during development | Fast | +| `balanced` | **Default choice.** Good coverage with optimizations | Medium | +| `thorough` | Pre-deployment reviews, PR security checks | Slow | +| `paranoid` | Compliance audits, production security reviews | Slowest | + +### Key Flags + +| Flag | Purpose | +|------|---------| +| `--mode {lightning\|fast\|balanced\|thorough\|paranoid}` | Scan depth (always specify) | +| `--agent` | Compressed output for agent consumption (always use when processing results) | +| `--include-low` | Include low-severity findings (off by default) | +| `--no-secrets` | Skip secrets detection (only code patterns) | +| `--no-code-patterns` | Skip code pattern analysis (only secrets) | +| `--fail-on-findings` | Exit with error code if findings exist (for CI) | +| `--output ` | Write report to file | + +## Output Interpretation + +**Priority for reporting to user:** +1. Critical findings first (leaked secrets, hardcoded credentials) +2. High findings (insecure patterns) +3. Summary with score +4. Remediation steps for top findings + +## Reading Results + +When you use `--agent`, the output is a **compressed summary** — NOT the full data. Only critical and high findings are inline. To get medium/low details, you MUST use `sync-ctl retrieve`. + +**What's in the compressed output:** +- `summary` — counts by severity +- `critical_issues` — full details for every critical finding +- `high_issues` — first 10 high-severity findings +- `patterns` — deduplicated medium/low findings as counts only (NO individual details) +- `full_data_ref` — reference ID for the full stored data + +**IMPORTANT: Do NOT try to extract medium/low details from the compressed output. Use retrieve instead.** + +```bash +# Get medium-severity findings +sync-ctl retrieve --query "severity:medium" + +# Get findings for a specific file +sync-ctl retrieve --query "file:src/auth.rs" + +# Get findings by rule code +sync-ctl retrieve --query "code:hardcoded-secret" +``` + +Results are paginated (default 20). Use `--limit N --offset M` for more. + +**Available query filters:** `severity:critical|high|medium|low|info`, `file:`, `code:` + +## Error Handling + +| Error | Cause | Action | +|-------|-------|--------| +| `No such file or directory` | Invalid path | Ask user to verify the project path | +| Very slow scan | Large repo with `thorough`/`paranoid` mode | Suggest trying `balanced` or `fast` mode first | +| No findings | Clean project or scan mode too light | If `lightning`/`fast`, suggest re-running with `balanced` for deeper coverage | + +## Examples + +**Quick secrets check on current directory:** +```bash +sync-ctl security . --mode balanced --agent +``` + +**Deep pre-deploy audit:** +```bash +sync-ctl security . --mode paranoid --agent +``` + +**Secrets-only scan (skip code patterns):** +```bash +sync-ctl security . --mode thorough --no-code-patterns --agent +``` + +**Save report to file:** +```bash +sync-ctl security . --mode thorough --agent --output security-report.json +``` diff --git a/installer/plugins/syncable-cli-skills/skills/syncable-validate/SKILL.md b/installer/plugins/syncable-cli-skills/skills/syncable-validate/SKILL.md new file mode 100644 index 0000000..9e226e6 --- /dev/null +++ b/installer/plugins/syncable-cli-skills/skills/syncable-validate/SKILL.md @@ -0,0 +1,119 @@ +--- +description: "Lint and validate Dockerfiles, Docker Compose files, Kubernetes manifests, Helm charts, and Terraform configs using the Syncable CLI sync-ctl tool" +--- + +## Purpose + +Validate Infrastructure-as-Code files against best practices. Covers Dockerfiles (via native hadolint), Docker Compose files (via native dclint), and Terraform configurations. Reports violations with severity, file locations, and auto-fix suggestions. + +## Prerequisites + +- `sync-ctl` binary installed and on PATH +- Agent has access to the project directory +- Project must contain IaC files (Dockerfiles, docker-compose.yml, *.tf files) + +## Commands + +### Validate all IaC files in a directory + +```bash +sync-ctl validate --agent +``` + +### Validate specific types only + +```bash +sync-ctl validate --types dockerfile --agent +sync-ctl validate --types dockerfile,compose --agent +sync-ctl validate --types terraform --agent +``` + +### Auto-fix issues where possible + +```bash +sync-ctl validate --fix +``` + +### Key Flags + +| Flag | Purpose | +|------|---------| +| `--agent` | Compressed output for agent consumption (always use when processing results) | +| `--types ` | Filter to specific IaC types: `dockerfile`, `compose`, `terraform` | +| `--fix` | Automatically fix issues where possible | + +**Note:** The `--agent` flag is available for structured output. When `--agent` is not used, output is terminal text with structured lint violations. + +## Output Interpretation + +Output contains lint violations, each with: + +- **file** — path to the IaC file +- **line** — line number of the violation +- **rule** — rule ID (e.g., DL3006 for hadolint, DCL001 for dclint) +- **severity** — Error, Warning, Info +- **message** — description of the issue +- **fix** — suggested fix (if available) + +**What gets checked:** + +| Type | Linter | Example checks | +|------|--------|---------------| +| Dockerfile | hadolint (native Rust) | Pin versions, avoid `latest` tag, use COPY not ADD, multi-stage best practices | +| Docker Compose | dclint (native Rust) | Service naming, volume declarations, network configuration, 15 configurable rules | +| Terraform | Terraform validator | Syntax validation, provider configuration, resource definitions | + +**Priority for reporting to user:** +1. Errors first — these will cause build/deploy failures +2. Warnings — best practice violations +3. Info — suggestions for improvement + +## Reading Results + +When you use `--agent`, the output is a compressed summary. All **error**-severity violations are included in full detail. Warnings are deduplicated into patterns. + +The output JSON includes: +- `status` — e.g., "ERRORS_FOUND", "WARNINGS_ONLY", "CLEAN" +- `summary` — counts by severity +- `errors` — full details for every error-severity finding +- `patterns` — deduplicated warning/info findings with counts +- `full_data_ref` — reference ID for retrieving full data +- `retrieval_hint` — exact command for drill-down + +To drill into specifics: +```bash +# Get all error-severity findings +sync-ctl retrieve --query "severity:high" + +# Get findings for a specific file +sync-ctl retrieve --query "file:Dockerfile" + +# Get findings by rule code +sync-ctl retrieve --query "code:DL3006" +``` + +**Available query filters:** `severity:`, `file:`, `code:` + +## Error Handling + +| Error | Cause | Action | +|-------|-------|--------| +| `No IaC files found` | Directory has no Dockerfiles, Compose, or Terraform files | Run `sync-ctl analyze --agent` to verify what IaC exists | +| `Unknown type` | Invalid `--types` value | Valid types are: `dockerfile`, `compose`, `terraform` | + +## Examples + +**Lint all IaC in current directory:** +```bash +sync-ctl validate . --agent +``` + +**Lint only Dockerfiles:** +```bash +sync-ctl validate . --types dockerfile --agent +``` + +**Auto-fix Docker Compose issues:** +```bash +sync-ctl validate . --types compose --fix +``` diff --git a/installer/plugins/syncable-cli-skills/skills/syncable-vulnerabilities/SKILL.md b/installer/plugins/syncable-cli-skills/skills/syncable-vulnerabilities/SKILL.md new file mode 100644 index 0000000..6d09038 --- /dev/null +++ b/installer/plugins/syncable-cli-skills/skills/syncable-vulnerabilities/SKILL.md @@ -0,0 +1,106 @@ +--- +description: "Check project dependencies for known CVEs and security vulnerabilities across npm, pip, cargo, and go ecosystems using the Syncable CLI sync-ctl tool" +--- + +## Purpose + +Scan project dependencies for known CVEs (Common Vulnerabilities and Exposures) across npm, pip, cargo, go, and java ecosystems. Returns vulnerable packages with severity, affected versions, and available fixes. + +## Prerequisites + +- `sync-ctl` binary installed and on PATH +- Agent has access to the project directory +- Language-specific scanning tools should be installed. If a scan fails with "tool not found", run `sync-ctl tools install` to install missing scanners. + +## Commands + +### Scan for vulnerabilities + +```bash +sync-ctl vulnerabilities --agent +``` + +### Filter by severity + +```bash +sync-ctl vulnerabilities --severity high --agent +``` + +### Key Flags + +| Flag | Purpose | +|------|---------| +| `--agent` | Compressed output for agent consumption (always use) | +| `--severity {low\|medium\|high\|critical}` | Only show findings at or above this severity | +| `--output ` | Write report to file | + +## Output Interpretation + +**Priority for reporting to user:** +1. Critical/High CVEs with available fixes — actionable immediately +2. Critical/High CVEs without fixes — flag as risk +3. Medium/Low — mention count, don't enumerate unless asked + +## Reading Results + +When you use `--agent`, the output is a **compressed summary** — NOT the full data. Only critical and high findings are inline. To get medium/low details, you MUST use `sync-ctl retrieve`. + +**What's in the compressed output:** +- `summary` — counts by severity (total, critical, high, medium, low) +- `critical_issues` — full details for every critical finding +- `high_issues` — first 10 high-severity findings (full detail) +- `patterns` — deduplicated medium/low findings as counts only (NO individual details) +- `full_data_ref` — reference ID for the full stored data +- `retrieval_hint` — exact command for drill-down + +**IMPORTANT: Do NOT try to extract medium/low details from the compressed output. They are only available via retrieve.** + +To get individual findings by severity: +```bash +# Get medium-severity findings (NOT in compressed output — must use retrieve) +sync-ctl retrieve --query "severity:medium" + +# Get low-severity findings +sync-ctl retrieve --query "severity:low" + +# Get high-severity findings (also in compressed output, but retrieve gives all of them) +sync-ctl retrieve --query "severity:high" + +# Get findings for a specific source directory +sync-ctl retrieve --query "file:services/api" +``` + +Results are paginated (default 20). Use `--limit N --offset M` for more. + +**Available query filters:** `severity:`, `file:` + +## Error Handling + +| Error | Cause | Action | +|-------|-------|--------| +| `tool not found` or scanner missing | Language-specific audit tool not installed | Run `sync-ctl tools install` to install missing scanners, then retry | +| `No dependencies found` | No package manager files detected | Run `sync-ctl analyze --agent` first to verify the project has dependencies | +| Timeout | Very large dependency tree | Try scanning specific subdirectories in a monorepo | + +## Examples + +**Scan current project:** +```bash +sync-ctl vulnerabilities . --agent +``` + +**Only critical and high severity:** +```bash +sync-ctl vulnerabilities . --severity high --agent +``` + +**Save report:** +```bash +sync-ctl vulnerabilities . --agent --output vuln-report.json +``` + +**Install missing scanners first:** +```bash +sync-ctl tools install --yes +sync-ctl vulnerabilities . --agent +``` diff --git a/installer/scripts/copy-skills.js b/installer/scripts/copy-skills.js index 0605586..2847a51 100644 --- a/installer/scripts/copy-skills.js +++ b/installer/scripts/copy-skills.js @@ -48,17 +48,9 @@ if (existsSync(marketplacePath)) { console.log(`Synced marketplace.json version to ${version}`); } -// 3. PLUGIN_VERSION constant in src/transformers/claude.ts -const claudeTsPath = resolve(__dirname, '..', 'src', 'transformers', 'claude.ts'); -if (existsSync(claudeTsPath)) { - let claudeTs = readFileSync(claudeTsPath, 'utf-8'); - claudeTs = claudeTs.replace( - /const PLUGIN_VERSION = '[^']+';/, - `const PLUGIN_VERSION = '${version}';` - ); - writeFileSync(claudeTsPath, claudeTs); - console.log(`Synced PLUGIN_VERSION to ${version}`); -} +// NOTE: We do NOT sync PLUGIN_VERSION in claude.ts — the installer no longer +// uses a hardcoded version. It piggybacks on whatever version Claude Code's +// CLI cached from the GitHub marketplace, avoiding version mismatches. // ── Regenerate plugin skills ──────────────────────────────────────── diff --git a/installer/src/transformers/claude.ts b/installer/src/transformers/claude.ts index 300c4e8..176633a 100644 --- a/installer/src/transformers/claude.ts +++ b/installer/src/transformers/claude.ts @@ -6,7 +6,6 @@ import { TransformResult } from './types.js'; import { execCommand, commandExists } from '../utils.js'; const PLUGIN_NAME = 'syncable-cli-skills'; -const PLUGIN_VERSION = '0.1.11'; const MARKETPLACE_NAME = 'syncable'; const MARKETPLACE_REPO = 'syncable-dev/syncable-cli'; @@ -27,18 +26,36 @@ export function transformForClaude(skill: Skill): TransformResult[] { } /** - * Get the plugin cache directory for Claude Code. + * Root directory for all cached versions of this plugin. + */ +function getPluginCacheRoot(): string { + return path.join(os.homedir(), '.claude', 'plugins', 'cache', MARKETPLACE_NAME, PLUGIN_NAME); +} + +/** + * Find the cache directory that Claude Code's CLI created (from `claude plugin install`). + * This version is guaranteed to match the GitHub marketplace, so we piggyback on it + * to avoid creating a version that Claude Code would later orphan. + */ +function findCliInstalledCacheDir(): string | null { + const root = getPluginCacheRoot(); + if (!fs.existsSync(root)) return null; + + for (const entry of fs.readdirSync(root)) { + const dir = path.join(root, entry); + if (!fs.statSync(dir).isDirectory()) continue; + // Return any version dir (there should be at most one after CLI install) + return dir; + } + return null; +} + +/** + * Fallback cache directory when the CLI install didn't create one. + * Uses "0.0.0" as a sentinel — the real version comes from the CLI. */ export function getClaudePluginCacheDir(): string { - return path.join( - os.homedir(), - '.claude', - 'plugins', - 'cache', - MARKETPLACE_NAME, - PLUGIN_NAME, - PLUGIN_VERSION - ); + return path.join(getPluginCacheRoot(), '0.0.0'); } // ──────────────────────────────────────────────────────────────────────────── @@ -101,11 +118,14 @@ function writePluginManifest(cacheDir: string): void { const manifestDir = path.join(cacheDir, '.claude-plugin'); fs.mkdirSync(manifestDir, { recursive: true }); + // Derive version from the cache directory name (e.g. ".../0.1.0" → "0.1.0") + const version = path.basename(cacheDir); + const manifest = { name: PLUGIN_NAME, description: 'Syncable CLI skills for project analysis, security scanning, vulnerability detection, dependency auditing, IaC validation, Kubernetes optimization, and cloud deployment.', - version: PLUGIN_VERSION, + version, author: { name: 'Syncable', email: 'support@syncable.dev', @@ -173,23 +193,32 @@ function enablePluginInSettings(): void { * 2. Fall back to manual: write cache files + update settings.json */ export async function installClaudePlugin(skills: Skill[]): Promise<{ cacheDir: string; skillCount: number }> { - // Try the official CLI first — this registers the marketplace and plugin - // in Claude Code's settings. We still do a manual write afterwards because - // the CLI-cached version may be stale or missing skills. + // Step 1: Run the official CLI — this fetches marketplace.json from GitHub, + // determines the correct version, caches the plugin, and registers it in + // settings.json. The version it creates MATCHES what GitHub advertises, + // so Claude Code will never orphan it. await tryClaudeCliInstall(); - const cacheDir = getClaudePluginCacheDir(); - const pluginRootDir = path.dirname(cacheDir); // .../syncable-cli-skills/ - - // Nuke the ENTIRE plugin cache (all versions) and recreate fresh. - // This prevents version mismatches, stale caches, and — critically — - // removes any .orphaned_at marker that Claude Code writes when a cached - // version doesn't match the marketplace catalog. - if (fs.existsSync(pluginRootDir)) { - fs.rmSync(pluginRootDir, { recursive: true, force: true }); + // Step 2: Find the directory the CLI created. We write our skills INTO it + // rather than creating a new version directory, because any version we + // invent might not match the GitHub marketplace and get orphaned. + let cacheDir = findCliInstalledCacheDir(); + + if (cacheDir) { + // Remove .orphaned_at if present (stale from a previous bad install) + const orphanedFile = path.join(cacheDir, '.orphaned_at'); + if (fs.existsSync(orphanedFile)) fs.unlinkSync(orphanedFile); + } else { + // CLI install failed or claude isn't installed — use fallback path + cacheDir = getClaudePluginCacheDir(); + } + + // Step 3: Clear and rewrite skills so the cache is always fresh. + const skillsDir = path.join(cacheDir, 'skills'); + if (fs.existsSync(skillsDir)) { + fs.rmSync(skillsDir, { recursive: true }); } - // Write every skill into a clean cache directory. for (const skill of skills) { const results = transformForClaude(skill); for (const { relativePath, content } of results) { @@ -202,29 +231,30 @@ export async function installClaudePlugin(skills: Skill[]): Promise<{ cacheDir: writePluginManifest(cacheDir); enablePluginInSettings(); - // Also write skills to ~/.claude/skills/ for SDK-based integrations - // (e.g. Zed's ACP adapter) that don't read from the plugin cache. - // The SDK loads user-level skills from this directory when configured - // with settingSources: ["user"]. + // Step 4: Also write skills to ~/.claude/skills/ for SDK-based integrations + // (Zed ACP, etc.) that don't read the plugin cache. writeUserLevelSkills(skills); return { cacheDir, skillCount: skills.length }; } /** - * Write skills to ~/.claude/skills/ so they're available to SDK-based - * integrations (Zed, etc.) that don't read the plugin cache. + * Write skills to ~/.claude/skills/ for SDK-based integrations. + * transformForClaude returns paths like "skills/name/SKILL.md", but + * user-level skills live at ~/.claude/skills/name/SKILL.md, so we + * strip the leading "skills/" prefix. */ function writeUserLevelSkills(skills: Skill[]): void { const userSkillsDir = path.join(os.homedir(), '.claude', 'skills'); for (const skill of skills) { - const results = transformForClaude(skill); - for (const { relativePath, content } of results) { - const fullPath = path.join(userSkillsDir, relativePath); - fs.mkdirSync(path.dirname(fullPath), { recursive: true }); - fs.writeFileSync(fullPath, content); - } + const skillName = skill.filename.replace(/\.md$/, ''); + const safeDesc = skill.frontmatter.description.replace(/"/g, '\\"').trim(); + const content = `---\ndescription: "${safeDesc}"\n---\n\n${skill.body}`; + + const outDir = path.join(userSkillsDir, skillName); + fs.mkdirSync(outDir, { recursive: true }); + fs.writeFileSync(path.join(outDir, 'SKILL.md'), content); } }