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.
- package/bin/install.js +73 -136
- 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
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
// ──
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
|
|
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
|
-
|
|
100
|
+
function main() {
|
|
108
101
|
console.log('');
|
|
109
|
-
console.log(` ${bold('AAWP
|
|
110
|
-
console.log(` ${dim('AI Agent Wallet Protocol
|
|
102
|
+
console.log(` ${bold('AAWP')} ${dim('v' + VERSION)}`);
|
|
103
|
+
console.log(` ${dim('AI Agent Wallet Protocol')}`);
|
|
111
104
|
console.log('');
|
|
112
105
|
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
125
|
-
const
|
|
126
|
-
const targets = [];
|
|
111
|
+
const { dir, client } = detectInstallDir();
|
|
112
|
+
const shortDir = dir.replace(HOME, '~');
|
|
127
113
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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 (
|
|
179
|
-
console.log(` ${bold(green('AAWP skill installed!'))}`);
|
|
118
|
+
if (install(dir)) {
|
|
180
119
|
console.log('');
|
|
181
|
-
console.log(` ${
|
|
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('
|
|
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
|
-
|
|
187
|
-
|
|
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()
|
|
193
|
-
fail(`Unexpected error: ${e.message}`);
|
|
194
|
-
process.exit(1);
|
|
195
|
-
});
|
|
132
|
+
main();
|