@almyty/skills 1.0.0 → 1.0.1

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 ADDED
@@ -0,0 +1,70 @@
1
+ # @almyty/skills
2
+
3
+ Install and manage AI skills from [almyty](https://almyty.com) in 30+ coding agents.
4
+
5
+ ## Quick Start
6
+
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
16
+ ```
17
+
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
+ ## Commands
32
+
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
+ ```
45
+
46
+ ## References
47
+
48
+ Skills are referenced as `@org/gateway` or `@org/gateway/skill`:
49
+
50
+ ```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
53
+ ```
54
+
55
+ ## Configuration
56
+
57
+ Create `.almytyrc` in your project or home directory:
58
+
59
+ ```json
60
+ {
61
+ "url": "https://api.almyty.com",
62
+ "token": "your-token"
63
+ }
64
+ ```
65
+
66
+ Or use environment variables: `ALMYTY_URL`, `ALMYTY_TOKEN`.
67
+
68
+ ## License
69
+
70
+ BSL-1.1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almyty/skills",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
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",
@@ -1 +0,0 @@
1
- export {};
@@ -1,145 +0,0 @@
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
- });