@almyty/skills 1.0.1 → 1.0.3

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/README.md CHANGED
@@ -1,55 +1,38 @@
1
1
  # @almyty/skills
2
2
 
3
- Install and manage AI skills from [almyty](https://almyty.com) in 30+ coding agents.
3
+ Install and manage almyty skills in 30+ AI coding agents (Claude Code, Cursor, Windsurf, Copilot, Codex, and more).
4
4
 
5
- ## Quick Start
5
+ ## Quick start
6
6
 
7
7
  ```bash
8
- # Install skills from a gateway
9
- npx @almyty/skills install @your-org/your-gateway
10
-
11
- # Keep skills synced (daemon mode)
12
- npx @almyty/skills daemon
13
-
14
- # Run a skill directly
15
- npx @almyty/skills run @your-org/your-gateway/tool-name --param value
8
+ $ npx @almyty/auth login
9
+ $ npx @almyty/skills gateways
10
+ $ npx @almyty/skills install @org/gateway
16
11
  ```
17
12
 
18
- ## What It Does
19
-
20
- almyty turns any API into AI-ready tools. This CLI installs those tools as **SKILL.md files** into your project, where they're automatically picked up by supported agents.
21
-
22
- ## Supported Agents
23
-
24
- | Category | Agents |
25
- |----------|--------|
26
- | **IDE** | Claude Code, Cursor, Windsurf, VS Code Copilot, JetBrains |
27
- | **AI Assistants** | Claude Desktop, ChatGPT, Gemini |
28
- | **Dev Tools** | Aider, Continue, Cody, GitHub Copilot CLI |
29
- | **Frameworks** | LangChain, LlamaIndex, CrewAI, AutoGPT |
30
-
31
13
  ## Commands
32
14
 
33
- ```
34
- npx @almyty/skills login Authenticate with almyty
35
- npx @almyty/skills logout Remove stored credentials
36
- npx @almyty/skills daemon Start skill daemon (syncs all skills)
37
- npx @almyty/skills install <ref> Install skills from a gateway
38
- npx @almyty/skills list [ref] List available skills
39
- npx @almyty/skills search <query> Search for skills
40
- npx @almyty/skills run <ref> Execute a skill
41
- npx @almyty/skills installed Show locally installed skills
42
- npx @almyty/skills remove Remove all installed skills
43
- npx @almyty/skills gateways List your gateways
44
- ```
15
+ | Command | Description |
16
+ |---------|-------------|
17
+ | `gateways` | List your gateways |
18
+ | `list` | List all available skills |
19
+ | `list @org/gateway` | List skills from one gateway |
20
+ | `search <query>` | Search skills by keyword |
21
+ | `install @org/gateway` | Install all skills from a gateway |
22
+ | `install @org/gateway/skill` | Install a single skill |
23
+ | `installed` | Show locally installed skills |
24
+ | `remove` | Remove all installed skills |
25
+ | `run @org/gateway/skill [--key value]` | Execute a skill |
26
+ | `daemon [--interval 60]` | Sync all skills on a schedule |
27
+ | `watch @org/gateway [--interval 60]` | Watch a specific gateway for changes |
45
28
 
46
29
  ## References
47
30
 
48
31
  Skills are referenced as `@org/gateway` or `@org/gateway/skill`:
49
32
 
50
33
  ```bash
51
- npx @almyty/skills install @acme/petstore # All skills from a gateway
52
- npx @almyty/skills run @acme/petstore/get-pet # Run a specific skill
34
+ $ npx @almyty/skills install @acme/petstore
35
+ $ npx @almyty/skills run @acme/petstore/get-pet --id 123
53
36
  ```
54
37
 
55
38
  ## Configuration
@@ -63,7 +46,21 @@ Create `.almytyrc` in your project or home directory:
63
46
  }
64
47
  ```
65
48
 
66
- Or use environment variables: `ALMYTY_URL`, `ALMYTY_TOKEN`.
49
+ ## Environment variables
50
+
51
+ | Variable | Description |
52
+ |----------|-------------|
53
+ | `ALMYTY_TOKEN` | Auth token override |
54
+ | `ALMYTY_URL` | API URL override |
55
+ | `ALMYTY_SKILLS_DIR` | Custom directory for installed skill files |
56
+
57
+ ## Authentication
58
+
59
+ Requires `npx @almyty/auth login` first. Reads credentials from `~/.almyty/credentials.json`.
60
+
61
+ ## Docs
62
+
63
+ https://almyty.com/docs
67
64
 
68
65
  ## License
69
66
 
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,145 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { parseRef } from '../client.js';
3
+ import { generateMetaSkill } from '../meta-skill.js';
4
+ import { loadConfig } from '../config.js';
5
+ // ---------------------------------------------------------------------------
6
+ // parseRef()
7
+ // ---------------------------------------------------------------------------
8
+ describe('parseRef', () => {
9
+ it('parses @org/gateway as a gateway ref', () => {
10
+ const result = parseRef('@org/gateway');
11
+ expect(result).toEqual({
12
+ type: 'gateway',
13
+ orgSlug: 'org',
14
+ gatewaySlug: 'gateway',
15
+ raw: '@org/gateway',
16
+ });
17
+ });
18
+ it('parses @org/gateway/skill as a skill ref', () => {
19
+ const result = parseRef('@org/gateway/skill');
20
+ expect(result).toEqual({
21
+ type: 'skill',
22
+ orgSlug: 'org',
23
+ gatewaySlug: 'gateway',
24
+ skillName: 'skill',
25
+ raw: '@org/gateway/skill',
26
+ });
27
+ });
28
+ it('parses a UUID string as a uuid ref', () => {
29
+ const uuid = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890';
30
+ const result = parseRef(uuid);
31
+ expect(result).toEqual({
32
+ type: 'uuid',
33
+ uuid,
34
+ raw: uuid,
35
+ });
36
+ });
37
+ it('parses uppercase UUID correctly', () => {
38
+ const uuid = 'A1B2C3D4-E5F6-7890-ABCD-EF1234567890';
39
+ const result = parseRef(uuid);
40
+ expect(result.type).toBe('uuid');
41
+ expect(result.uuid).toBe(uuid);
42
+ });
43
+ it('returns search for a random string', () => {
44
+ const result = parseRef('some-random-query');
45
+ expect(result).toEqual({
46
+ type: 'search',
47
+ raw: 'some-random-query',
48
+ });
49
+ });
50
+ it('returns search for an empty string', () => {
51
+ const result = parseRef('');
52
+ expect(result).toEqual({
53
+ type: 'search',
54
+ raw: '',
55
+ });
56
+ });
57
+ it('returns search for @ with only one segment', () => {
58
+ const result = parseRef('@org');
59
+ expect(result).toEqual({
60
+ type: 'search',
61
+ raw: '@org',
62
+ });
63
+ });
64
+ it('returns search for @ with more than three segments', () => {
65
+ const result = parseRef('@org/gw/skill/extra');
66
+ expect(result).toEqual({
67
+ type: 'search',
68
+ raw: '@org/gw/skill/extra',
69
+ });
70
+ });
71
+ });
72
+ // ---------------------------------------------------------------------------
73
+ // generateMetaSkill()
74
+ // ---------------------------------------------------------------------------
75
+ describe('generateMetaSkill', () => {
76
+ it('returns a SkillFile with name "skills" and fileName "almyty-skills"', () => {
77
+ const skill = generateMetaSkill();
78
+ expect(skill.name).toBe('skills');
79
+ expect(skill.fileName).toBe('almyty-skills');
80
+ });
81
+ it('content includes npx @almyty/skills commands', () => {
82
+ const { content } = generateMetaSkill();
83
+ expect(content).toContain('npx @almyty/skills');
84
+ });
85
+ it('content references daemon command', () => {
86
+ const { content } = generateMetaSkill();
87
+ expect(content).toContain('daemon');
88
+ });
89
+ it('content references search command', () => {
90
+ const { content } = generateMetaSkill();
91
+ expect(content).toContain('search');
92
+ });
93
+ it('content references install command', () => {
94
+ const { content } = generateMetaSkill();
95
+ expect(content).toContain('install');
96
+ });
97
+ it('content references run command', () => {
98
+ const { content } = generateMetaSkill();
99
+ expect(content).toContain('run');
100
+ });
101
+ it('content includes SKILL.md front-matter', () => {
102
+ const { content } = generateMetaSkill();
103
+ expect(content).toContain('---');
104
+ expect(content).toContain('name: almyty-skills');
105
+ expect(content).toContain('description:');
106
+ });
107
+ });
108
+ // ---------------------------------------------------------------------------
109
+ // loadConfig()
110
+ // ---------------------------------------------------------------------------
111
+ describe('loadConfig', () => {
112
+ const originalEnv = process.env;
113
+ beforeEach(() => {
114
+ // Reset env between tests
115
+ process.env = { ...originalEnv };
116
+ delete process.env.APIFAI_SKILLS_DIR;
117
+ });
118
+ afterEach(() => {
119
+ process.env = originalEnv;
120
+ vi.restoreAllMocks();
121
+ });
122
+ it('returns empty config when no .almytyrc exists and no env var', () => {
123
+ // Use a temp directory that definitely has no .almytyrc
124
+ const config = loadConfig('/tmp/nonexistent-dir-' + Date.now());
125
+ expect(config).toEqual({});
126
+ });
127
+ it('uses APIFAI_SKILLS_DIR env var when set', () => {
128
+ process.env.APIFAI_SKILLS_DIR = '/custom/skills/dir';
129
+ const config = loadConfig();
130
+ expect(config).toEqual({ skillsDir: '/custom/skills/dir' });
131
+ });
132
+ it('env var takes precedence over .almytyrc files', () => {
133
+ process.env.APIFAI_SKILLS_DIR = '/env/override';
134
+ // Even if we pass a projectDir, env should take priority
135
+ const config = loadConfig('/some/project');
136
+ expect(config.skillsDir).toBe('/env/override');
137
+ });
138
+ it('returns empty config for a directory with no rc file and no home rc', () => {
139
+ // Use a deeply nested temp path that certainly has no .almytyrc anywhere
140
+ // and also won't match ~/.almytyrc (already handled by the missing file)
141
+ const fakePath = `/tmp/almyty-test-${Date.now()}/deeply/nested/project`;
142
+ const config = loadConfig(fakePath);
143
+ expect(config).toEqual({});
144
+ });
145
+ });
package/dist/auth.d.ts CHANGED
@@ -1,41 +1,20 @@
1
1
  /**
2
- * Authentication helpers for the almyty skills CLI.
2
+ * Credential resolver for @almyty/skills.
3
3
  *
4
- * Shares credentials with @almyty/mcp-server via ~/.almyty/credentials.json.
4
+ * Authentication itself lives in the dedicated @almyty/auth package
5
+ * (`npx @almyty/auth login`). This module just READS the shared
6
+ * credentials store and surfaces them to the rest of the skills CLI.
5
7
  *
6
- * Supports:
7
- * 1. Environment variable (APIFAI_TOKEN) — for CI/scripts
8
- * 2. Stored credentials (~/.almyty/credentials.json) — for interactive use
9
- * 3. Interactive login (npx @almyty/skills login) — stores credentials
8
+ * Lookup order:
9
+ * 1. ALMYTY_TOKEN environment variable (CI / scripts)
10
+ * 2. ~/.almyty/credentials.json (interactive use, written
11
+ * by `npx @almyty/auth login`)
10
12
  */
11
- interface StoredCredentials {
12
- url: string;
13
- token: string;
14
- email?: string;
15
- expiresAt?: string;
16
- }
17
- /**
18
- * Load stored credentials from ~/.almyty/credentials.json
19
- */
20
- export declare function loadCredentials(): StoredCredentials | null;
21
- /**
22
- * Save credentials to ~/.almyty/credentials.json
23
- */
24
- export declare function saveCredentials(creds: StoredCredentials): void;
25
- /**
26
- * Remove stored credentials
27
- */
28
- export declare function logout(): void;
29
13
  /**
30
- * Resolve token: env var > stored credentials
14
+ * Resolve token: env var > stored credentials. Exits with a clear hint
15
+ * if no credentials are available.
31
16
  */
32
17
  export declare function resolveAuth(): {
33
18
  url: string;
34
19
  token: string;
35
20
  };
36
- /**
37
- * Interactive login: prompts for email/password, authenticates against
38
- * the almyty backend, and stores the JWT token.
39
- */
40
- export declare function login(baseUrl: string): Promise<void>;
41
- export {};
package/dist/auth.js CHANGED
@@ -1,63 +1,36 @@
1
1
  /**
2
- * Authentication helpers for the almyty skills CLI.
2
+ * Credential resolver for @almyty/skills.
3
3
  *
4
- * Shares credentials with @almyty/mcp-server via ~/.almyty/credentials.json.
4
+ * Authentication itself lives in the dedicated @almyty/auth package
5
+ * (`npx @almyty/auth login`). This module just READS the shared
6
+ * credentials store and surfaces them to the rest of the skills CLI.
5
7
  *
6
- * Supports:
7
- * 1. Environment variable (APIFAI_TOKEN) — for CI/scripts
8
- * 2. Stored credentials (~/.almyty/credentials.json) — for interactive use
9
- * 3. Interactive login (npx @almyty/skills login) — stores credentials
8
+ * Lookup order:
9
+ * 1. ALMYTY_TOKEN environment variable (CI / scripts)
10
+ * 2. ~/.almyty/credentials.json (interactive use, written
11
+ * by `npx @almyty/auth login`)
10
12
  */
11
- import { readFileSync, writeFileSync, mkdirSync, unlinkSync, existsSync } from 'fs';
13
+ import { readFileSync, existsSync } from 'fs';
12
14
  import { homedir } from 'os';
13
15
  import { join } from 'path';
14
- import { createInterface } from 'readline';
15
- const CREDENTIALS_DIR = join(homedir(), '.almyty');
16
- const CREDENTIALS_FILE = join(CREDENTIALS_DIR, 'credentials.json');
17
- /**
18
- * Load stored credentials from ~/.almyty/credentials.json
19
- */
20
- export function loadCredentials() {
16
+ const CREDENTIALS_FILE = join(homedir(), '.almyty', 'credentials.json');
17
+ function loadCredentials() {
21
18
  try {
22
19
  if (!existsSync(CREDENTIALS_FILE))
23
20
  return null;
24
- const data = readFileSync(CREDENTIALS_FILE, 'utf-8');
25
- return JSON.parse(data);
21
+ return JSON.parse(readFileSync(CREDENTIALS_FILE, 'utf-8'));
26
22
  }
27
23
  catch {
28
24
  return null;
29
25
  }
30
26
  }
31
27
  /**
32
- * Save credentials to ~/.almyty/credentials.json
33
- */
34
- export function saveCredentials(creds) {
35
- mkdirSync(CREDENTIALS_DIR, { recursive: true });
36
- writeFileSync(CREDENTIALS_FILE, JSON.stringify(creds, null, 2), { mode: 0o600 });
37
- }
38
- /**
39
- * Remove stored credentials
40
- */
41
- export function logout() {
42
- try {
43
- if (existsSync(CREDENTIALS_FILE)) {
44
- unlinkSync(CREDENTIALS_FILE);
45
- console.log('Logged out. Credentials removed.');
46
- }
47
- else {
48
- console.log('No stored credentials found.');
49
- }
50
- }
51
- catch {
52
- console.error('Failed to remove credentials.');
53
- }
54
- }
55
- /**
56
- * Resolve token: env var > stored credentials
28
+ * Resolve token: env var > stored credentials. Exits with a clear hint
29
+ * if no credentials are available.
57
30
  */
58
31
  export function resolveAuth() {
59
- const envToken = process.env.APIFAI_TOKEN;
60
- const envUrl = process.env.APIFAI_URL || 'https://api.almyty.com';
32
+ const envToken = process.env.ALMYTY_TOKEN;
33
+ const envUrl = process.env.ALMYTY_URL || 'https://api.almyty.com';
61
34
  if (envToken) {
62
35
  return { url: envUrl, token: envToken };
63
36
  }
@@ -66,52 +39,7 @@ export function resolveAuth() {
66
39
  return { url: creds.url, token: creds.token };
67
40
  }
68
41
  console.error('Not authenticated. Run one of:');
69
- console.error(' npx @almyty/skills login');
70
- console.error(' export APIFAI_TOKEN=<your-token>');
42
+ console.error(' npx @almyty/auth login # browser-based login');
43
+ console.error(' export ALMYTY_TOKEN=<token> # for CI');
71
44
  process.exit(1);
72
45
  }
73
- /**
74
- * Interactive login: prompts for email/password, authenticates against
75
- * the almyty backend, and stores the JWT token.
76
- */
77
- export async function login(baseUrl) {
78
- const rl = createInterface({
79
- input: process.stdin,
80
- output: process.stderr,
81
- });
82
- const ask = (question) => new Promise((resolve) => rl.question(question, resolve));
83
- try {
84
- console.error(`Logging in to ${baseUrl}...\n`);
85
- const email = await ask('Email: ');
86
- const password = await ask('Password: ');
87
- console.error('\nAuthenticating...');
88
- const response = await fetch(`${baseUrl}/api/auth/login`, {
89
- method: 'POST',
90
- headers: { 'Content-Type': 'application/json' },
91
- body: JSON.stringify({ email, password }),
92
- });
93
- if (!response.ok) {
94
- const errBody = await response.json().catch(() => ({ message: 'Authentication failed' }));
95
- console.error(`Error: ${errBody.message || 'Authentication failed'}`);
96
- process.exit(1);
97
- }
98
- const data = await response.json();
99
- const token = data.accessToken || data.token;
100
- if (!token) {
101
- console.error('Error: No token received from server');
102
- process.exit(1);
103
- }
104
- saveCredentials({
105
- url: baseUrl,
106
- token,
107
- email,
108
- });
109
- console.error(`\n✓ Logged in as ${email}`);
110
- console.error(` Credentials saved to ${CREDENTIALS_FILE}`);
111
- console.error('\nYou can now install skills:');
112
- console.error(' npx @almyty/skills install --gateway <id>');
113
- }
114
- finally {
115
- rl.close();
116
- }
117
- }
package/dist/client.js CHANGED
@@ -23,7 +23,7 @@ export class AlmytyClient {
23
23
  this.token = token;
24
24
  }
25
25
  async request(path) {
26
- const url = `${this.baseUrl}/api${path}`;
26
+ const url = `${this.baseUrl}${path}`;
27
27
  const response = await fetch(url, {
28
28
  headers: {
29
29
  'Authorization': `Bearer ${this.token}`,
@@ -32,7 +32,7 @@ export class AlmytyClient {
32
32
  });
33
33
  if (!response.ok) {
34
34
  if (response.status === 401) {
35
- throw new Error('Authentication failed. Run: npx @almyty/skills login');
35
+ throw new Error('Authentication failed. Run: npx @almyty/auth login');
36
36
  }
37
37
  const text = await response.text();
38
38
  throw new Error(`API error (${response.status}): ${text}`);
@@ -40,7 +40,7 @@ export class AlmytyClient {
40
40
  return response.json();
41
41
  }
42
42
  async post(path, body) {
43
- const url = `${this.baseUrl}/api${path}`;
43
+ const url = `${this.baseUrl}${path}`;
44
44
  const resp = await fetch(url, {
45
45
  method: 'POST',
46
46
  headers: {
@@ -86,8 +86,8 @@ export class AlmytyClient {
86
86
  }
87
87
  async listGateways() {
88
88
  const data = await this.request('/gateways');
89
- const gateways = data?.data?.data?.gateways || data?.data?.data || data?.data || [];
90
- return gateways.map((gw) => ({
89
+ const gateways = data?.data?.gateways || data?.data?.data || data?.data || [];
90
+ return (Array.isArray(gateways) ? gateways : []).map((gw) => ({
91
91
  id: gw.id,
92
92
  name: gw.name,
93
93
  type: gw.type,
@@ -113,7 +113,24 @@ export class AlmytyClient {
113
113
  return skills;
114
114
  }
115
115
  async executeSkill(gatewayId, toolId, parameters) {
116
- return this.post(`/gateways/${gatewayId}/skills/${toolId}/execute`, { parameters });
116
+ // The execute endpoint expects a UUID. If toolId is a name slug,
117
+ // resolve it by listing the gateway's tools and matching.
118
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
119
+ let resolvedId = toolId;
120
+ if (!uuidRegex.test(toolId)) {
121
+ const tools = await this.request(`/gateways/${gatewayId}/tools`);
122
+ const list = tools?.data?.gatewayTools || tools?.data?.data || tools?.data || [];
123
+ const match = (Array.isArray(list) ? list : []).find((gt) => {
124
+ const t = gt.tool || gt;
125
+ const slug = t.name?.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
126
+ return slug === toolId || t.name === toolId;
127
+ });
128
+ if (!match) {
129
+ throw new Error(`Tool "${toolId}" not found in gateway ${gatewayId}`);
130
+ }
131
+ resolvedId = (match.tool || match).id;
132
+ }
133
+ return this.post(`/gateways/${gatewayId}/skills/${resolvedId}/execute`, { parameters });
117
134
  }
118
135
  async resolveRef(ref) {
119
136
  if (ref.startsWith('@')) {
package/dist/config.js CHANGED
@@ -3,7 +3,7 @@ import { homedir } from 'os';
3
3
  import { join, resolve } from 'path';
4
4
  import { detectAgents, getDefaultTargets, filterAgents } from './agents.js';
5
5
  export function loadConfig(projectDir) {
6
- const envDir = process.env.APIFAI_SKILLS_DIR;
6
+ const envDir = process.env.ALMYTY_SKILLS_DIR;
7
7
  if (envDir) {
8
8
  return { skillsDir: envDir };
9
9
  }
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { login, logout, resolveAuth } from './auth.js';
2
+ import { resolveAuth } from './auth.js';
3
3
  import { AlmytyClient, parseRef } from './client.js';
4
4
  import { getAllTargets } from './agents.js';
5
5
  import { installSkills, removeSkills, listInstalledSkills } from './installer.js';
@@ -14,8 +14,6 @@ Usage:
14
14
  npx @almyty/skills <command> [options]
15
15
 
16
16
  Commands:
17
- login Authenticate with almyty
18
- logout Remove stored credentials
19
17
  daemon Start skill daemon (syncs all skills)
20
18
  install <ref> Install skills
21
19
  list [ref] List available skills
@@ -25,6 +23,10 @@ Commands:
25
23
  remove Remove all installed skills
26
24
  gateways List your gateways
27
25
 
26
+ Authentication:
27
+ Run \`npx @almyty/auth login\` once. Credentials at ~/.almyty/credentials.json
28
+ are shared across every almyty CLI.
29
+
28
30
  References:
29
31
  @org/gateway All skills from a gateway
30
32
  @org/gateway/skill A specific skill
@@ -33,9 +35,9 @@ References:
33
35
 
34
36
  Config:
35
37
  .almytyrc JSON config file (project or home dir)
36
- APIFAI_SKILLS_DIR Override skill installation directory
37
- APIFAI_URL Override API URL
38
- APIFAI_TOKEN Override auth token
38
+ ALMYTY_SKILLS_DIR Override skill installation directory
39
+ ALMYTY_URL Override API URL
40
+ ALMYTY_TOKEN Override auth token
39
41
 
40
42
  Options:
41
43
  --interval, -i <seconds> Daemon poll interval in seconds (default: 60)
@@ -142,14 +144,15 @@ async function main() {
142
144
  const config = loadConfig(projectDir);
143
145
  const urlOverride = args.flags.url || config.url;
144
146
  switch (command) {
145
- case 'login': {
146
- const url = urlOverride || process.env.APIFAI_URL || 'https://api.almyty.com';
147
- await login(url);
148
- break;
149
- }
150
- case 'logout': {
151
- logout();
152
- break;
147
+ case 'login':
148
+ case 'logout':
149
+ case 'whoami': {
150
+ // Auth has moved to its own dedicated package. Redirect rather
151
+ // than silently doing nothing — users typing the old commands
152
+ // should see the new entry point.
153
+ console.error(`Authentication moved to @almyty/auth.`);
154
+ console.error(` npx @almyty/auth ${command}`);
155
+ process.exit(1);
153
156
  }
154
157
  case 'gateways': {
155
158
  const { url, token } = resolveAuth();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almyty/skills",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Install API skills into AI coding agents — Claude Code, Cursor, Windsurf, Copilot, Codex",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",