aawp-ai 1.6.3 → 1.6.5

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.
Files changed (2) hide show
  1. package/bin/install.js +73 -136
  2. package/package.json +1 -1
package/bin/install.js CHANGED
@@ -9,10 +9,8 @@ const { execSync, spawnSync } = require('child_process');
9
9
  const VERSION = require('../package.json').version;
10
10
  const SKILL_NAME = 'aawp';
11
11
  const REPO_URL = 'https://github.com/aawp-ai/aawp.git';
12
- const RAW_BASE = 'https://raw.githubusercontent.com/aawp-ai/aawp/main';
13
- const FALLBACK = 'https://aawp.ai/skill';
14
12
 
15
- // ── ANSI colors ───────────────────────────────────────────────────────────────
13
+ // ── ANSI ──────────────────────────────────────────────────────────────────────
16
14
  const isTTY = process.stdout.isTTY;
17
15
  const c = (code, s) => isTTY ? `\x1b[${code}m${s}\x1b[0m` : s;
18
16
  const bold = s => c('1', s);
@@ -29,167 +27,106 @@ const fail = s => console.log(` ${red('✗')} ${s}`);
29
27
 
30
28
  // ── Helpers ───────────────────────────────────────────────────────────────────
31
29
  const HOME = os.homedir();
32
-
33
30
  function hasCmd(cmd) {
34
31
  try { execSync(`command -v ${cmd}`, { stdio: 'ignore' }); return true; } catch { return false; }
35
32
  }
36
33
  function dirExists(p) {
37
34
  try { return fs.statSync(p).isDirectory(); } catch { return false; }
38
35
  }
39
- function hasGit() { return hasCmd('git'); }
40
36
 
41
- async function fetchBuffer(url) {
42
- if (typeof fetch !== 'undefined') {
43
- const res = await fetch(url);
44
- if (!res.ok) throw new Error(`HTTP ${res.status}`);
45
- return Buffer.from(await res.arrayBuffer());
46
- }
47
- return new Promise((resolve, reject) => {
48
- const proto = url.startsWith('https') ? require('https') : require('http');
49
- proto.get(url, res => {
50
- if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
51
- return fetchBuffer(res.headers.location).then(resolve).catch(reject);
52
- }
53
- if (res.statusCode !== 200) return reject(new Error(`HTTP ${res.status}`));
54
- const chunks = [];
55
- res.on('data', c => chunks.push(c));
56
- res.on('end', () => resolve(Buffer.concat(chunks)));
57
- res.on('error', reject);
58
- }).on('error', reject);
59
- });
60
- }
37
+ // ── Git clone / pull ──────────────────────────────────────────────────────────
38
+ function install(dest) {
39
+ const absDest = path.resolve(dest);
61
40
 
62
- // ── Git clone (full install) ──────────────────────────────────────────────────
63
- function gitClone(dest) {
64
- if (dirExists(dest) && dirExists(path.join(dest, '.git'))) {
65
- info('Existing install found pulling latest...');
66
- const r = spawnSync('git', ['-C', dest, 'pull', '--ff-only'], { stdio: 'inherit' });
67
- return r.status === 0;
68
- }
69
- if (dirExists(dest)) {
70
- // Directory exists but not a git repo remove and re-clone
71
- warn(`${dest} exists but is not a git repo — replacing...`);
72
- fs.rmSync(dest, { recursive: true, force: true });
41
+ if (dirExists(path.join(absDest, '.git'))) {
42
+ info('Updating existing install...');
43
+ const r = spawnSync('git', ['-C', absDest, 'pull', '--ff-only'], { stdio: 'inherit' });
44
+ if (r.status !== 0) { warn('git pull failed'); return false; }
45
+ } else {
46
+ if (dirExists(absDest)) fs.rmSync(absDest, { recursive: true, force: true });
47
+ fs.mkdirSync(path.dirname(absDest), { recursive: true });
48
+ const r = spawnSync('git', ['clone', '--depth', '1', REPO_URL, absDest], { stdio: 'inherit' });
49
+ if (r.status !== 0) { fail('git clone failed'); return false; }
73
50
  }
74
- fs.mkdirSync(path.dirname(dest), { recursive: true });
75
- const r = spawnSync('git', ['clone', '--depth', '1', REPO_URL, dest], { stdio: 'inherit' });
76
- return r.status === 0;
77
- }
78
51
 
79
- // ── Manifest-only fallback (no git) ──────────────────────────────────────────
80
- async function manifestFallback(dest) {
81
- info('git not available — installing SKILL.md manifest only');
82
- warn('Full functionality requires git. Install git and re-run: npx aawp-ai');
83
- fs.mkdirSync(dest, { recursive: true });
84
- try {
85
- const md = await fetchBuffer(`${RAW_BASE}/SKILL.md`);
86
- fs.writeFileSync(path.join(dest, 'SKILL.md'), md);
87
- } catch {
88
- const md = await fetchBuffer(`${FALLBACK}/SKILL.md`);
89
- fs.writeFileSync(path.join(dest, 'SKILL.md'), md);
52
+ // Bootstrap (download binary if missing)
53
+ const bootstrap = path.join(absDest, 'scripts', 'bootstrap.sh');
54
+ if (fs.existsSync(bootstrap)) {
55
+ const r = spawnSync('bash', [bootstrap], { stdio: 'inherit', cwd: absDest });
56
+ if (r.status !== 0) warn('Bootstrap issue binary may need manual download');
90
57
  }
58
+
91
59
  return true;
92
60
  }
93
61
 
94
- // ── Client detection ──────────────────────────────────────────────────────────
95
- const CLIENTS = [
96
- { name: 'OpenClaw', detect: () => hasCmd('clawhub') || hasCmd('openclaw') || dirExists('skills'), skillDir: 'skills' },
97
- { name: 'Cursor', detect: () => hasCmd('cursor') || dirExists(path.join(HOME, '.cursor')), skillDir: path.join(HOME, '.cursor', 'skills') },
98
- { name: 'Claude Code',detect: () => hasCmd('claude') || dirExists(path.join(HOME, '.claude')), skillDir: path.join(HOME, '.claude', 'skills') },
99
- { name: 'Gemini CLI', detect: () => hasCmd('gemini') || dirExists(path.join(HOME, '.gemini')), skillDir: path.join(HOME, '.gemini', 'skills') },
100
- { name: 'OpenCode', detect: () => hasCmd('opencode') || dirExists(path.join(HOME, '.config', 'opencode')), skillDir: path.join(HOME, '.config', 'opencode', 'skills') },
101
- { name: 'Goose', detect: () => hasCmd('goose') || dirExists(path.join(HOME, '.config', 'goose')), skillDir: path.join(HOME, '.config', 'goose', 'skills') },
102
- ];
62
+ // ── Detect install location (same conventions as clawhub / each AI client) ───
63
+ function detectInstallDir() {
64
+ // 1. OpenClaw: ~/.openclaw/workspace/skills/ (new default), or cwd/skills/ (legacy/custom)
65
+ if (hasCmd('openclaw')) {
66
+ const ocSkills = path.join(HOME, '.openclaw', 'workspace', 'skills');
67
+ const cwdSkills = path.join(process.cwd(), 'skills');
68
+ // Prefer ~/.openclaw/workspace/skills if the workspace exists
69
+ if (dirExists(path.join(HOME, '.openclaw', 'workspace'))) {
70
+ return { dir: path.join(ocSkills, SKILL_NAME), client: 'OpenClaw' };
71
+ }
72
+ if (dirExists(cwdSkills)) {
73
+ return { dir: path.join(cwdSkills, SKILL_NAME), client: 'OpenClaw' };
74
+ }
75
+ // OpenClaw detected but no workspace yet — use default
76
+ return { dir: path.join(ocSkills, SKILL_NAME), client: 'OpenClaw' };
77
+ }
78
+
79
+ // 2. Known AI clients — each has a standard skills directory
80
+ const clients = [
81
+ { name: 'Cursor', detect: () => hasCmd('cursor') || dirExists(path.join(HOME, '.cursor')), dirs: [path.join(HOME, '.cursor', 'skills')] },
82
+ { name: 'Claude Code', detect: () => hasCmd('claude') || dirExists(path.join(HOME, '.claude')), dirs: [path.join(HOME, '.claude', 'skills')] },
83
+ { name: 'Gemini CLI', detect: () => hasCmd('gemini') || dirExists(path.join(HOME, '.gemini')), dirs: [path.join(HOME, '.gemini', 'skills')] },
84
+ { name: 'Windsurf', detect: () => hasCmd('windsurf') || dirExists(path.join(HOME, '.windsurf')), dirs: [path.join(HOME, '.windsurf', 'skills')] },
85
+ { name: 'OpenCode', detect: () => hasCmd('opencode') || dirExists(path.join(HOME, '.config', 'opencode')), dirs: [path.join(HOME, '.config', 'opencode', 'skills')] },
86
+ { name: 'Goose', detect: () => hasCmd('goose') || dirExists(path.join(HOME, '.config', 'goose')), dirs: [path.join(HOME, '.config', 'goose', 'skills')] },
87
+ ];
88
+
89
+ for (const c of clients) {
90
+ if (c.detect()) {
91
+ return { dir: path.join(c.dirs[0], SKILL_NAME), client: c.name };
92
+ }
93
+ }
103
94
 
104
- const UNIVERSAL_DIR = path.join(HOME, '.agents', 'skills');
95
+ // 3. Fallback: universal agentskills.io convention
96
+ return { dir: path.join(HOME, '.agents', 'skills', SKILL_NAME), client: null };
97
+ }
105
98
 
106
99
  // ── Main ──────────────────────────────────────────────────────────────────────
107
- async function main() {
100
+ function main() {
108
101
  console.log('');
109
- console.log(` ${bold('AAWP Skill Installer')} ${dim('v' + VERSION)}`);
110
- console.log(` ${dim('AI Agent Wallet Protocol — aawp.ai')}`);
102
+ console.log(` ${bold('AAWP')} ${dim('v' + VERSION)}`);
103
+ console.log(` ${dim('AI Agent Wallet Protocol')}`);
111
104
  console.log('');
112
105
 
113
- const detected = CLIENTS.filter(c => c.detect());
114
- const git = hasGit();
115
-
116
- if (detected.length === 0) {
117
- info('No AI clients detected — installing to universal ~/.agents/skills/');
118
- } else {
119
- info(`Detected: ${detected.map(c => c.name).join(', ')}`);
106
+ if (!hasCmd('git')) {
107
+ fail('git is required. Install git and re-run: npx aawp-ai');
108
+ process.exit(1);
120
109
  }
121
- if (!git) warn('git not found — will install manifest only (limited functionality)');
122
- console.log('');
123
110
 
124
- // Collect unique install dirs
125
- const seenDirs = new Set();
126
- const targets = [];
111
+ const { dir, client } = detectInstallDir();
112
+ const shortDir = dir.replace(HOME, '~');
127
113
 
128
- for (const client of detected) {
129
- if (client.skillDir && !seenDirs.has(client.skillDir)) {
130
- seenDirs.add(client.skillDir);
131
- targets.push({ dir: client.skillDir, label: client.name });
132
- }
133
- }
134
- if (!seenDirs.has(UNIVERSAL_DIR)) {
135
- targets.push({ dir: UNIVERSAL_DIR, label: 'universal' });
136
- }
137
-
138
- let count = 0;
139
-
140
- for (const { dir, label } of targets) {
141
- const dest = path.join(dir, SKILL_NAME);
142
- const shortDest = dest.replace(HOME, '~');
143
- info(`Installing to ${shortDest} ${dim('(' + label + ')')}`);
144
-
145
- try {
146
- let ok = false;
147
- if (git) {
148
- ok = gitClone(dest);
149
- if (!ok) {
150
- warn('git clone failed — falling back to manifest-only');
151
- ok = await manifestFallback(dest);
152
- }
153
- } else {
154
- ok = await manifestFallback(dest);
155
- }
156
-
157
- if (ok) {
158
- // Run bootstrap if full install (downloads binary if missing)
159
- const bootstrap = path.join(dest, 'scripts', 'bootstrap.sh');
160
- if (fs.existsSync(bootstrap)) {
161
- info('Running bootstrap (downloading binary artifacts)...');
162
- const r = spawnSync('bash', [bootstrap], { stdio: 'inherit', cwd: dest });
163
- if (r.status === 0) {
164
- success('Bootstrap complete — binary verified');
165
- } else {
166
- warn('Bootstrap had issues — binary may need manual download');
167
- }
168
- }
169
- success(`Installed → ${shortDest}`);
170
- count++;
171
- }
172
- } catch (e) {
173
- fail(`Failed: ${e.message}`);
174
- }
175
- console.log('');
176
- }
114
+ if (client) info(`Detected ${client}`);
115
+ info(`Installing to ${shortDir}`);
116
+ console.log('');
177
117
 
178
- if (count > 0) {
179
- console.log(` ${bold(green('AAWP skill installed!'))}`);
118
+ if (install(dir)) {
180
119
  console.log('');
181
- console.log(` ${dim('Restart your AI client to load the skill.')}`);
182
- console.log(` ${dim('Then ask your AI: "set up my AAWP wallet"')}`);
120
+ console.log(` ${bold(green('Done!'))} Installed to ${shortDir}`);
183
121
  console.log('');
184
- console.log(` ${dim('Docs: https://aawp.ai · GitHub: https://github.com/aawp-ai/aawp')}`);
122
+ console.log(` ${dim('Ask your AI:')} ${bold('"set up my AAWP wallet"')}`);
123
+ console.log(` ${dim('Docs: https://aawp.ai')}`);
185
124
  } else {
186
- fail('Nothing was installed.');
187
- console.log(` ${dim('Try: git clone https://github.com/aawp-ai/aawp.git ~/.agents/skills/aawp')}`);
125
+ console.log('');
126
+ fail('Installation failed.');
127
+ console.log(` ${dim('Try: git clone ' + REPO_URL + ' ' + shortDir)}`);
188
128
  }
189
129
  console.log('');
190
130
  }
191
131
 
192
- main().catch(e => {
193
- fail(`Unexpected error: ${e.message}`);
194
- process.exit(1);
195
- });
132
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aawp-ai",
3
- "version": "1.6.3",
3
+ "version": "1.6.5",
4
4
  "description": "Install the AAWP skill for any Agent Skills compatible AI client",
5
5
  "keywords": [
6
6
  "aawp",