From 71a062422ffa252dbd02181eabdbfb94862fd2d6 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 10 Mar 2026 09:16:11 +0000 Subject: [PATCH 1/3] fix: rename package to @malopezr7/jato for npm publish npm rejected "jato" as too similar to existing packages. Scoped name @malopezr7/jato resolves the 403 conflict. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a93d3ee..647b475 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "jato", + "name": "@malopezr7/jato", "version": "0.1.0", "description": "One directory. Every AI tool. Centralized configuration for Claude Code, Codex CLI, Gemini CLI, and OpenCode.", "type": "module", From 023a99e83a4fa39410e8ae4f722e5f0164aa82e8 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 10 Mar 2026 09:27:40 +0000 Subject: [PATCH 2/3] feat: add `jato skill install` command and update README - New `jato skill install` command to quickly install the jato-manager skill directly into provider skills directories (claude, codex, gemini) without needing a full jato init + use flow - Supports --provider flag to target specific providers - Update README with scoped package name @malopezr7/jato - Document quick skill setup in README - Add npm version badge --- README.md | 24 ++++++++-- src/cli/commands/skill.ts | 97 +++++++++++++++++++++++++++++++++++++++ src/cli/index.ts | 2 + tests/cli/skill.test.ts | 60 ++++++++++++++++++++++++ 4 files changed, 180 insertions(+), 3 deletions(-) create mode 100644 src/cli/commands/skill.ts create mode 100644 tests/cli/skill.test.ts diff --git a/README.md b/README.md index 2278c16..eeb5fd5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- version + version license stars node @@ -17,7 +17,7 @@
```bash -npx jato init +npx @malopezr7/jato init ``` --- @@ -34,7 +34,7 @@ The real trick: jato installs a **skill that teaches your LLM to be your config ```bash # Install and create your first jato -npx jato init +npx @malopezr7/jato init # Activate it jato use my-jato @@ -48,6 +48,23 @@ Three init paths: - **Template** — starts from a built-in template (`starter`, `mobile`, `backend`, `fullstack`) - **Wizard** — just ask your AI to build one (the jato-manager skill handles it) +## Quick Skill Setup + +Want the jato-manager skill in your AI tools right now, without setting up a full jato? + +```bash +# Install the skill to all detected providers +npx @malopezr7/jato skill install + +# Install to a specific provider only +npx @malopezr7/jato skill install --provider claude + +# Install to multiple providers +npx @malopezr7/jato skill install --provider claude --provider gemini +``` + +This copies the **jato-manager** skill directly into each provider's skills directory (`~/.claude/skills/`, `~/.gemini/skills/`, etc.), so your LLM can immediately help you manage jato configurations. + ## How It Works A jato is a folder. Everything inside is your AI setup: @@ -96,6 +113,7 @@ jato list Show available jatos jato off Deactivate the current jato jato doctor Health check — schema, env vars, providers, skills jato install Install jatos from a git repository +jato skill install Install the jato-manager skill to your AI providers ``` That's the whole surface. diff --git a/src/cli/commands/skill.ts b/src/cli/commands/skill.ts new file mode 100644 index 0000000..34adcae --- /dev/null +++ b/src/cli/commands/skill.ts @@ -0,0 +1,97 @@ +import type { Command } from "commander"; +import { mkdir, readFile, writeFile } from "node:fs/promises"; +import { join, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import chalk from "chalk"; +import { getSkillsDir } from "../../core/hub.js"; +import { detectInstalledProviders } from "../../providers/detector.js"; +import { getProvider } from "../../providers/registry.js"; + +async function readManagerSkill(home?: string): Promise { + const hubPath = join(getSkillsDir(home), "jato-manager.md"); + try { + return await readFile(hubPath, "utf8"); + } catch { + // Fallback: read from dist/src + const __dirname = dirname(fileURLToPath(import.meta.url)); + const distPath = join(__dirname, "..", "..", "skills", "jato-manager.md"); + try { + return await readFile(distPath, "utf8"); + } catch { + const srcPath = join( + __dirname, + "..", + "..", + "..", + "src", + "skills", + "jato-manager.md", + ); + return await readFile(srcPath, "utf8"); + } + } +} + +export function registerSkillCommand(program: Command): void { + const skill = program + .command("skill") + .description("Manage jato skills"); + + skill + .command("install") + .description( + "Install the jato-manager skill directly into provider skills directories", + ) + .option( + "--provider ", + "Providers to install to (e.g. claude, codex, gemini). Defaults to all detected.", + ) + .action(async (opts: { provider?: string[] }) => { + const content = await readManagerSkill(); + + let targetProviders: string[]; + + if (opts.provider) { + targetProviders = opts.provider; + } else { + const detected = await detectInstalledProviders(); + targetProviders = detected + .filter((d) => d.found) + .map((d) => d.name); + } + + if (targetProviders.length === 0) { + process.stderr.write( + ` ${chalk.red("✗")} No AI providers detected. Use --provider to specify one.\n`, + ); + process.exitCode = 1; + return; + } + + let installed = 0; + + for (const name of targetProviders) { + const provider = getProvider(name); + if (!provider) { + process.stderr.write( + ` ${chalk.yellow("!")} Unknown provider: ${name}\n`, + ); + continue; + } + + const skillDir = join(provider.skillsDir(), "jato-manager"); + await mkdir(skillDir, { recursive: true }); + await writeFile(join(skillDir, "SKILL.md"), content, "utf8"); + process.stdout.write( + ` ${chalk.green("✓")} Installed jato-manager skill → ${name} (${skillDir})\n`, + ); + installed++; + } + + if (installed > 0) { + process.stdout.write( + `\n ${chalk.dim("Your AI tools can now help you manage jatos. Try asking:")} ${chalk.cyan('"Create a jato for my React project"')}\n`, + ); + } + }); +} diff --git a/src/cli/index.ts b/src/cli/index.ts index 73c1482..769d76f 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -7,6 +7,7 @@ import { registerListCommand } from "./commands/list.js"; import { registerOffCommand } from "./commands/off.js"; import { registerDoctorCommand } from "./commands/doctor.js"; import { registerInstallCommand } from "./commands/install.js"; +import { registerSkillCommand } from "./commands/skill.js"; export type CliResult = { exitCode: number; @@ -28,6 +29,7 @@ export function createProgram(): Command { registerOffCommand(program); registerDoctorCommand(program); registerInstallCommand(program); + registerSkillCommand(program); return program; } diff --git a/tests/cli/skill.test.ts b/tests/cli/skill.test.ts new file mode 100644 index 0000000..de0a9f1 --- /dev/null +++ b/tests/cli/skill.test.ts @@ -0,0 +1,60 @@ +import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { mkdtemp, rm, mkdir, readFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { spawnSync } from "node:child_process"; + +let tmpHome: string; +const cliPath = join(process.cwd(), "dist", "cli", "index.js"); + +beforeEach(async () => { + tmpHome = await mkdtemp(join(tmpdir(), "rig-cli-skill-")); +}); + +afterEach(async () => { + await rm(tmpHome, { recursive: true, force: true }); +}); + +function runCli( + args: string, +): { stdout: string; stderr: string; exitCode: number } { + const result = spawnSync("node", [cliPath, ...args.split(" ")], { + env: { ...process.env, HOME: tmpHome }, + encoding: "utf8", + timeout: 10000, + }); + return { + stdout: result.stdout ?? "", + stderr: result.stderr ?? "", + exitCode: result.status ?? 1, + }; +} + +describe("jato skill install", () => { + it("installs skill to a specific provider", async () => { + // Create the provider's skills dir so detection can work + await mkdir(join(tmpHome, ".claude"), { recursive: true }); + + const { stdout } = runCli("skill install --provider claude"); + expect(stdout).toContain("Installed jato-manager skill"); + expect(stdout).toContain("claude"); + + const skillContent = await readFile( + join(tmpHome, ".claude", "skills", "jato-manager", "SKILL.md"), + "utf8", + ); + expect(skillContent).toContain("jato"); + }); + + it("fails when no providers are detected and none specified", async () => { + const { stderr, exitCode } = runCli("skill install"); + expect(exitCode).toBe(1); + expect(stderr).toContain("No AI providers detected"); + }); + + it("warns on unknown provider", async () => { + const { stdout, stderr } = runCli("skill install --provider fakeprovider"); + const output = stdout + stderr; + expect(output).toContain("Unknown provider"); + }); +}); From 26247a6050f81f04da58ff7d1b3de2bdad7c08de Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 10 Mar 2026 09:29:49 +0000 Subject: [PATCH 3/3] docs(site): update install command to scoped package name and add skill install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Hero and CTA: npx jato init → npx @malopezr7/jato init - CLI reference: add jato skill install command, update count to seven --- site/src/components/CLI.astro | 3 ++- site/src/components/CTA.astro | 4 ++-- site/src/components/Hero.astro | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/site/src/components/CLI.astro b/site/src/components/CLI.astro index 6c3d174..b34e99b 100644 --- a/site/src/components/CLI.astro +++ b/site/src/components/CLI.astro @@ -6,6 +6,7 @@ const commands = [ { c: "jato off", d: "Deactivate the current jato" }, { c: "jato doctor", d: "Health check — schema, env vars, providers, skills" }, { c: "jato install ", d: "Install jatos from a git repository" }, + { c: "jato skill install", d: "Quick-install the jato-manager skill into your AI providers" }, ]; --- @@ -15,7 +16,7 @@ const commands = [

- Six commands.
That's the whole surface. + Seven commands.
That's the whole surface.

diff --git a/site/src/components/CTA.astro b/site/src/components/CTA.astro index 5961c7e..c38b6e2 100644 --- a/site/src/components/CTA.astro +++ b/site/src/components/CTA.astro @@ -27,9 +27,9 @@
- npx jato init + npx @malopezr7/jato init