netlibrary-cli 1.0.0
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/netlibrary.js +33 -0
- package/commands/agents.js +173 -0
- package/commands/archive.js +40 -0
- package/commands/comments.js +49 -0
- package/commands/config.js +71 -0
- package/commands/embeds.js +120 -0
- package/commands/info.js +57 -0
- package/commands/library.js +158 -0
- package/commands/member.js +211 -0
- package/commands/search.js +63 -0
- package/commands/stacks.js +210 -0
- package/commands/stats.js +36 -0
- package/commands/tasks.js +78 -0
- package/lib/api.js +58 -0
- package/lib/config.js +39 -0
- package/lib/output.js +66 -0
- package/lib/payment.js +114 -0
- package/package.json +28 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const output = require('../lib/output');
|
|
5
|
+
|
|
6
|
+
program
|
|
7
|
+
.name('netlibrary')
|
|
8
|
+
.description('Net Library CLI — interact with the decentralized digital library on Base')
|
|
9
|
+
.version('1.0.0')
|
|
10
|
+
.option('--json', 'Output raw JSON (for programmatic/agent use)')
|
|
11
|
+
.option('--api-key <key>', 'Override API key')
|
|
12
|
+
.option('--base-url <url>', 'Override base URL')
|
|
13
|
+
.hook('preAction', (thisCommand) => {
|
|
14
|
+
const opts = thisCommand.optsWithGlobals();
|
|
15
|
+
if (opts.json) output.setJsonMode(true);
|
|
16
|
+
if (opts.apiKey) process.env.NETLIB_API_KEY = opts.apiKey;
|
|
17
|
+
if (opts.baseUrl) process.env.NETLIB_BASE_URL = opts.baseUrl;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
require('../commands/config')(program);
|
|
21
|
+
require('../commands/library')(program);
|
|
22
|
+
require('../commands/search')(program);
|
|
23
|
+
require('../commands/stacks')(program);
|
|
24
|
+
require('../commands/member')(program);
|
|
25
|
+
require('../commands/agents')(program);
|
|
26
|
+
require('../commands/tasks')(program);
|
|
27
|
+
require('../commands/archive')(program);
|
|
28
|
+
require('../commands/stats')(program);
|
|
29
|
+
require('../commands/embeds')(program);
|
|
30
|
+
require('../commands/info')(program);
|
|
31
|
+
require('../commands/comments')(program);
|
|
32
|
+
|
|
33
|
+
program.parse();
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
const api = require('../lib/api');
|
|
2
|
+
const output = require('../lib/output');
|
|
3
|
+
const config = require('../lib/config');
|
|
4
|
+
|
|
5
|
+
module.exports = function (program) {
|
|
6
|
+
const cmd = program.command('agents').description('Agent management');
|
|
7
|
+
|
|
8
|
+
cmd
|
|
9
|
+
.command('me')
|
|
10
|
+
.description('View your agent profile and widgets')
|
|
11
|
+
.action(async () => {
|
|
12
|
+
try {
|
|
13
|
+
const data = await api.get('/agents/me');
|
|
14
|
+
if (output.isJsonMode()) {
|
|
15
|
+
output.json(data);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const agent = data.agent || {};
|
|
19
|
+
const profile = agent.profile || {};
|
|
20
|
+
const membership = data.membership || {};
|
|
21
|
+
output.item({}, [
|
|
22
|
+
['ID', () => agent.id],
|
|
23
|
+
['Name', () => profile.name || agent.name],
|
|
24
|
+
['Address', () => agent.address],
|
|
25
|
+
['FID', () => agent.fid],
|
|
26
|
+
['Permissions', () => (agent.permissions || []).join(', ')],
|
|
27
|
+
['Created', () => agent.createdAt ? new Date(agent.createdAt).toLocaleString() : null],
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
if (membership.memberId) {
|
|
31
|
+
console.log('\nMembership:');
|
|
32
|
+
output.item(membership, [
|
|
33
|
+
['Member ID', 'memberId'],
|
|
34
|
+
['ENS', 'ensSubname'],
|
|
35
|
+
['Since', 'memberSince', v => v ? new Date(v).toLocaleDateString() : null],
|
|
36
|
+
]);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (data.widgets) {
|
|
40
|
+
console.log('\nWidgets:');
|
|
41
|
+
const w = data.widgets;
|
|
42
|
+
if (w.libraryCard) console.log(` Library Card: ${w.libraryCard.url}`);
|
|
43
|
+
if (w.profile) console.log(` Profile: ${w.profile.url}`);
|
|
44
|
+
if (w.stacks && w.stacks.length > 0) {
|
|
45
|
+
w.stacks.forEach(s => console.log(` Stack: ${s.url} (${s.name})`));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
} catch (err) {
|
|
49
|
+
output.error(err.message);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
cmd
|
|
55
|
+
.command('register')
|
|
56
|
+
.description('Register a new agent (admin only)')
|
|
57
|
+
.requiredOption('--id <id>', 'Agent ID (lowercase, alphanumeric + hyphens)')
|
|
58
|
+
.requiredOption('--name <name>', 'Agent display name')
|
|
59
|
+
.option('--permissions <perms...>', 'Permissions', ['library:write', 'stacks:create', 'stacks:write'])
|
|
60
|
+
.option('--address <addr>', 'Wallet address')
|
|
61
|
+
.option('--description <desc>', 'Description')
|
|
62
|
+
.option('--fid <n>', 'Farcaster FID')
|
|
63
|
+
.option('--pfp-url <url>', 'Profile picture URL')
|
|
64
|
+
.option('--webhook-url <url>', 'Webhook URL')
|
|
65
|
+
.action(async (opts) => {
|
|
66
|
+
try {
|
|
67
|
+
const cfg = config.load();
|
|
68
|
+
const adminKey = process.env.NETLIB_ADMIN_KEY || cfg.adminKey;
|
|
69
|
+
if (!adminKey) {
|
|
70
|
+
output.error('Admin key required. Set with: netlibrary config set admin-key <key>');
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const body = {
|
|
75
|
+
id: opts.id,
|
|
76
|
+
name: opts.name,
|
|
77
|
+
permissions: opts.permissions,
|
|
78
|
+
};
|
|
79
|
+
if (opts.address) body.address = opts.address;
|
|
80
|
+
if (opts.description) body.description = opts.description;
|
|
81
|
+
if (opts.fid) body.fid = parseInt(opts.fid);
|
|
82
|
+
if (opts.pfpUrl) body.pfpUrl = opts.pfpUrl;
|
|
83
|
+
if (opts.webhookUrl) body.webhookUrl = opts.webhookUrl;
|
|
84
|
+
|
|
85
|
+
const data = await api.post('/agents', body, {
|
|
86
|
+
headers: { 'Authorization': `Bearer ${adminKey}` },
|
|
87
|
+
auth: false,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
output.success(`Agent "${opts.id}" registered!`);
|
|
91
|
+
if (data.agent?.apiKey) {
|
|
92
|
+
console.log(`\nAPI Key: ${data.agent.apiKey}`);
|
|
93
|
+
console.log('Save this key — it cannot be retrieved again!');
|
|
94
|
+
}
|
|
95
|
+
if (output.isJsonMode()) output.json(data);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
output.error(err.message);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
cmd
|
|
103
|
+
.command('list')
|
|
104
|
+
.description('List all agents (admin only)')
|
|
105
|
+
.action(async () => {
|
|
106
|
+
try {
|
|
107
|
+
const data = await api.get('/agents');
|
|
108
|
+
output.table(
|
|
109
|
+
['ID', 'Name', 'Address', 'Permissions', 'Active'],
|
|
110
|
+
(data.agents || []).map(a => [
|
|
111
|
+
a.id,
|
|
112
|
+
a.name || '—',
|
|
113
|
+
a.address ? a.address.slice(0, 10) + '...' : '—',
|
|
114
|
+
(a.permissions || []).join(', '),
|
|
115
|
+
a.isActive ? 'Yes' : 'No',
|
|
116
|
+
])
|
|
117
|
+
);
|
|
118
|
+
} catch (err) {
|
|
119
|
+
output.error(err.message);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
cmd
|
|
125
|
+
.command('update')
|
|
126
|
+
.description('Update your agent profile')
|
|
127
|
+
.option('--name <name>', 'Display name')
|
|
128
|
+
.option('--description <desc>', 'Description')
|
|
129
|
+
.option('--address <addr>', 'Wallet address')
|
|
130
|
+
.option('--pfp-url <url>', 'Profile picture URL')
|
|
131
|
+
.option('--webhook-url <url>', 'Webhook URL')
|
|
132
|
+
.option('--fid <n>', 'Farcaster FID')
|
|
133
|
+
.option('--8004-token-id <n>', 'ERC-8004 token ID')
|
|
134
|
+
.option('--id <agentId>', 'Target agent ID (admin only)')
|
|
135
|
+
.action(async (opts) => {
|
|
136
|
+
try {
|
|
137
|
+
const body = {};
|
|
138
|
+
if (opts.id) body.id = opts.id;
|
|
139
|
+
if (opts.name) body.name = opts.name;
|
|
140
|
+
if (opts.description) body.description = opts.description;
|
|
141
|
+
if (opts.address) body.address = opts.address;
|
|
142
|
+
if (opts.pfpUrl) body.pfpUrl = opts.pfpUrl;
|
|
143
|
+
if (opts.webhookUrl) body.webhookUrl = opts.webhookUrl;
|
|
144
|
+
if (opts.fid) body.fid = parseInt(opts.fid);
|
|
145
|
+
if (opts['8004TokenId']) body.erc8004TokenId = parseInt(opts['8004TokenId']);
|
|
146
|
+
|
|
147
|
+
const data = await api.put('/agents', body);
|
|
148
|
+
output.success('Agent updated');
|
|
149
|
+
if (data.erc8004Verification) {
|
|
150
|
+
if (data.erc8004Verification.verified) {
|
|
151
|
+
output.success(`ERC-8004 verified! Token ID: ${data.erc8004Verification.tokenId}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (output.isJsonMode()) output.json(data);
|
|
155
|
+
} catch (err) {
|
|
156
|
+
output.error(err.message);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
cmd
|
|
162
|
+
.command('deactivate <agentId>')
|
|
163
|
+
.description('Deactivate an agent (admin only)')
|
|
164
|
+
.action(async (agentId) => {
|
|
165
|
+
try {
|
|
166
|
+
const data = await api.del('/agents', { id: agentId });
|
|
167
|
+
output.success(`Agent "${agentId}" deactivated`);
|
|
168
|
+
} catch (err) {
|
|
169
|
+
output.error(err.message);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const api = require('../lib/api');
|
|
2
|
+
const output = require('../lib/output');
|
|
3
|
+
|
|
4
|
+
module.exports = function (program) {
|
|
5
|
+
program
|
|
6
|
+
.command('archive [castHash]')
|
|
7
|
+
.description('Archive a Farcaster cast as a library item')
|
|
8
|
+
.option('--cast-url <url>', 'Warpcast URL (alternative to castHash)')
|
|
9
|
+
.option('--text <text>', 'Cast text content')
|
|
10
|
+
.option('--title <title>', 'Custom title')
|
|
11
|
+
.option('-c, --category <cat...>', 'Additional categories')
|
|
12
|
+
.option('--author-fid <n>', 'Author FID')
|
|
13
|
+
.option('--author-username <name>', 'Author username')
|
|
14
|
+
.option('--add-to-stack <stackId>', 'Add to stack after archiving')
|
|
15
|
+
.action(async (castHash, opts) => {
|
|
16
|
+
try {
|
|
17
|
+
if (!castHash && !opts.castUrl) {
|
|
18
|
+
output.error('Provide a cast hash or --cast-url');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const body = {};
|
|
23
|
+
if (castHash) body.castHash = castHash;
|
|
24
|
+
if (opts.castUrl) body.castUrl = opts.castUrl;
|
|
25
|
+
if (opts.text) body.text = opts.text;
|
|
26
|
+
if (opts.title) body.title = opts.title;
|
|
27
|
+
if (opts.category) body.categories = opts.category;
|
|
28
|
+
if (opts.authorFid) body.authorFid = parseInt(opts.authorFid);
|
|
29
|
+
if (opts.authorUsername) body.authorUsername = opts.authorUsername;
|
|
30
|
+
if (opts.addToStack) body.addToStack = opts.addToStack;
|
|
31
|
+
|
|
32
|
+
const data = await api.post('/archive', body);
|
|
33
|
+
output.success(`Archived: ${data.contentKey}`);
|
|
34
|
+
if (output.isJsonMode()) output.json(data);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
output.error(err.message);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const api = require('../lib/api');
|
|
2
|
+
const output = require('../lib/output');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
|
|
5
|
+
module.exports = function (program) {
|
|
6
|
+
program
|
|
7
|
+
.command('comments <contentKey>')
|
|
8
|
+
.description('View comments for a library item')
|
|
9
|
+
.option('--parent-id <id>', 'Get replies to a specific comment')
|
|
10
|
+
.action(async (contentKey, opts) => {
|
|
11
|
+
try {
|
|
12
|
+
const data = await api.get(`/comments/${encodeURIComponent(contentKey)}`, {
|
|
13
|
+
query: { parentId: opts.parentId },
|
|
14
|
+
auth: false,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
if (output.isJsonMode()) {
|
|
18
|
+
output.json(data);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (data.item) {
|
|
23
|
+
console.log(`Comments for: ${chalk.cyan(data.item.title || contentKey)}\n`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const comments = data.comments || [];
|
|
27
|
+
if (comments.length === 0) {
|
|
28
|
+
console.log(chalk.dim('No comments.'));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
comments.forEach(c => {
|
|
33
|
+
const author = c.author?.username || c.author?.address?.slice(0, 10) || 'unknown';
|
|
34
|
+
const date = c.createdAt ? new Date(c.createdAt).toLocaleDateString() : '';
|
|
35
|
+
const edited = c.isEdited ? chalk.dim(' (edited)') : '';
|
|
36
|
+
console.log(`${chalk.cyan(author)} ${chalk.dim(date)}${edited}`);
|
|
37
|
+
console.log(` ${c.text}`);
|
|
38
|
+
if (c.likes > 0) console.log(` ${chalk.dim(`♥ ${c.likes}`)}`);
|
|
39
|
+
if (c.replyCount > 0) console.log(` ${chalk.dim(`↳ ${c.replyCount} replies`)}`);
|
|
40
|
+
console.log('');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
console.log(`${data.totalCount || comments.length} total comments`);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
output.error(err.message);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const config = require('../lib/config');
|
|
3
|
+
const output = require('../lib/output');
|
|
4
|
+
|
|
5
|
+
module.exports = function (program) {
|
|
6
|
+
const cmd = program.command('config').description('Manage CLI configuration');
|
|
7
|
+
|
|
8
|
+
cmd
|
|
9
|
+
.command('set <key> <value>')
|
|
10
|
+
.description(`Set a config value. Keys: ${config.VALID_KEYS.join(', ')}`)
|
|
11
|
+
.action((key, value) => {
|
|
12
|
+
// Accept kebab-case and convert to camelCase
|
|
13
|
+
const keyMap = {
|
|
14
|
+
'api-key': 'apiKey',
|
|
15
|
+
'base-url': 'baseUrl',
|
|
16
|
+
'rpc-url': 'rpcUrl',
|
|
17
|
+
'admin-key': 'adminKey',
|
|
18
|
+
'wallet': 'wallet',
|
|
19
|
+
};
|
|
20
|
+
const resolved = keyMap[key] || key;
|
|
21
|
+
|
|
22
|
+
if (!config.VALID_KEYS.includes(resolved)) {
|
|
23
|
+
output.error(`Invalid key "${key}". Valid keys: ${config.VALID_KEYS.join(', ')}`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
config.set(resolved, value);
|
|
27
|
+
output.success(`Set ${resolved} = ${key === 'api-key' || key === 'apiKey' ? value.slice(0, 8) + '...' : value}`);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
cmd
|
|
31
|
+
.command('get <key>')
|
|
32
|
+
.description('Get a config value')
|
|
33
|
+
.action((key) => {
|
|
34
|
+
const keyMap = {
|
|
35
|
+
'api-key': 'apiKey',
|
|
36
|
+
'base-url': 'baseUrl',
|
|
37
|
+
'rpc-url': 'rpcUrl',
|
|
38
|
+
'admin-key': 'adminKey',
|
|
39
|
+
'wallet': 'wallet',
|
|
40
|
+
};
|
|
41
|
+
const resolved = keyMap[key] || key;
|
|
42
|
+
const val = config.get(resolved);
|
|
43
|
+
if (output.isJsonMode()) {
|
|
44
|
+
output.json({ [resolved]: val || null });
|
|
45
|
+
} else {
|
|
46
|
+
console.log(val || chalk.dim('(not set)'));
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
cmd
|
|
51
|
+
.command('show')
|
|
52
|
+
.description('Show all config values')
|
|
53
|
+
.action(() => {
|
|
54
|
+
const cfg = config.load();
|
|
55
|
+
if (output.isJsonMode()) {
|
|
56
|
+
output.json(cfg);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const masked = { ...cfg };
|
|
60
|
+
if (masked.apiKey) masked.apiKey = masked.apiKey.slice(0, 8) + '...';
|
|
61
|
+
if (masked.adminKey) masked.adminKey = masked.adminKey.slice(0, 8) + '...';
|
|
62
|
+
output.item(masked, [
|
|
63
|
+
['API Key', 'apiKey'],
|
|
64
|
+
['Base URL', 'baseUrl'],
|
|
65
|
+
['Wallet', 'wallet'],
|
|
66
|
+
['RPC URL', 'rpcUrl'],
|
|
67
|
+
['Admin Key', 'adminKey'],
|
|
68
|
+
]);
|
|
69
|
+
console.log(chalk.dim(`\nConfig file: ${config.CONFIG_FILE}`));
|
|
70
|
+
});
|
|
71
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
const api = require('../lib/api');
|
|
2
|
+
const output = require('../lib/output');
|
|
3
|
+
|
|
4
|
+
module.exports = function (program) {
|
|
5
|
+
const cmd = program.command('embeds').description('Embed data API');
|
|
6
|
+
|
|
7
|
+
cmd
|
|
8
|
+
.command('card <address>')
|
|
9
|
+
.description('Get library card data for a member')
|
|
10
|
+
.action(async (address) => {
|
|
11
|
+
try {
|
|
12
|
+
const data = await api.get(`/embeds/card/${address}`, { auth: false });
|
|
13
|
+
if (output.isJsonMode()) {
|
|
14
|
+
output.json(data);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (!data.member) {
|
|
18
|
+
console.log('No member found for this address.');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const m = data.member || {};
|
|
22
|
+
output.item(data, [
|
|
23
|
+
['Display Name', 'displayName'],
|
|
24
|
+
['Member ID', () => m.memberId],
|
|
25
|
+
['ENS', () => m.ensSubname],
|
|
26
|
+
['Joined', () => m.joinedAt ? new Date(m.joinedAt).toLocaleDateString() : null],
|
|
27
|
+
['Uploads', () => `${data.uploads?.count || 0} (${((data.uploads?.totalBytes || 0) / 1024 / 1024).toFixed(2)} MB)`],
|
|
28
|
+
['Stacks', 'stackCount'],
|
|
29
|
+
['Grids', 'gridCount'],
|
|
30
|
+
['Rank', 'rank'],
|
|
31
|
+
['Storage Pass', () => m.hasUnlimitedStoragePass ? 'Yes' : 'No'],
|
|
32
|
+
['ERC-8004', () => m.erc8004Verified ? (m.erc8004TokenId ? `Verified (#${m.erc8004TokenId})` : 'Verified') : 'No'],
|
|
33
|
+
]);
|
|
34
|
+
} catch (err) {
|
|
35
|
+
output.error(err.message);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
cmd
|
|
41
|
+
.command('grid <gridId>')
|
|
42
|
+
.description('Get grid embed data')
|
|
43
|
+
.action(async (gridId) => {
|
|
44
|
+
try {
|
|
45
|
+
const data = await api.get(`/embeds/grid/${gridId}`, { auth: false });
|
|
46
|
+
if (output.isJsonMode()) {
|
|
47
|
+
output.json(data);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const g = data.grid || {};
|
|
51
|
+
output.item(g, [
|
|
52
|
+
['Name', 'name'],
|
|
53
|
+
['ID', 'id'],
|
|
54
|
+
['Owner', 'owner'],
|
|
55
|
+
['Columns', 'columns'],
|
|
56
|
+
['Created', 'createdAt', v => v ? new Date(v).toLocaleString() : null],
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
if (data.cells && data.cells.length > 0) {
|
|
60
|
+
console.log('\nCells:');
|
|
61
|
+
output.table(
|
|
62
|
+
['Pos', 'Title', 'Type', 'Key'],
|
|
63
|
+
data.cells.map(c => [
|
|
64
|
+
c.position,
|
|
65
|
+
c.title || '—',
|
|
66
|
+
c.mediaType || '—',
|
|
67
|
+
c.contentKey,
|
|
68
|
+
])
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
} catch (err) {
|
|
72
|
+
output.error(err.message);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
cmd
|
|
78
|
+
.command('user <address>')
|
|
79
|
+
.description('Get user profile embed data')
|
|
80
|
+
.option('-p, --page <n>', 'Page number', '1')
|
|
81
|
+
.option('-l, --limit <n>', 'Items per page (max 50)', '20')
|
|
82
|
+
.action(async (address, opts) => {
|
|
83
|
+
try {
|
|
84
|
+
const data = await api.get(`/embeds/user/${address}`, {
|
|
85
|
+
query: { page: opts.page, limit: opts.limit },
|
|
86
|
+
auth: false,
|
|
87
|
+
});
|
|
88
|
+
if (output.isJsonMode()) {
|
|
89
|
+
output.json(data);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const m = data.member || {};
|
|
93
|
+
output.item(data, [
|
|
94
|
+
['Display Name', 'displayName'],
|
|
95
|
+
['Address', 'address'],
|
|
96
|
+
['Member ID', () => m.memberId],
|
|
97
|
+
['ENS', () => m.ensSubname],
|
|
98
|
+
['Uploads', 'uploadCount'],
|
|
99
|
+
['Total Size', 'totalBytes', v => v ? `${(v / 1024 / 1024).toFixed(2)} MB` : null],
|
|
100
|
+
]);
|
|
101
|
+
|
|
102
|
+
if (data.uploads && data.uploads.length > 0) {
|
|
103
|
+
console.log('\nUploads:');
|
|
104
|
+
output.table(
|
|
105
|
+
['Title', 'Type', 'Added', 'Key'],
|
|
106
|
+
data.uploads.map(u => [
|
|
107
|
+
u.title || '—',
|
|
108
|
+
u.mediaType || '—',
|
|
109
|
+
u.addedAt ? new Date(u.addedAt).toLocaleDateString() : '—',
|
|
110
|
+
u.contentKey,
|
|
111
|
+
])
|
|
112
|
+
);
|
|
113
|
+
output.pagination(data.pagination);
|
|
114
|
+
}
|
|
115
|
+
} catch (err) {
|
|
116
|
+
output.error(err.message);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
};
|
package/commands/info.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const api = require('../lib/api');
|
|
2
|
+
const output = require('../lib/output');
|
|
3
|
+
|
|
4
|
+
module.exports = function (program) {
|
|
5
|
+
const cmd = program.command('info').description('API information');
|
|
6
|
+
|
|
7
|
+
cmd
|
|
8
|
+
.command('capabilities')
|
|
9
|
+
.description('View the API capabilities manifest')
|
|
10
|
+
.action(async () => {
|
|
11
|
+
try {
|
|
12
|
+
const data = await api.get('/capabilities', { auth: false });
|
|
13
|
+
if (output.isJsonMode()) {
|
|
14
|
+
output.json(data);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
output.item(data, [
|
|
18
|
+
['Name', 'name'],
|
|
19
|
+
['Version', 'version'],
|
|
20
|
+
['URL', 'url'],
|
|
21
|
+
['Chain', () => `${data.chain?.name} (${data.chain?.id})`],
|
|
22
|
+
['CDN', 'cdn'],
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
if (data.pricing) {
|
|
26
|
+
console.log('\nPricing:');
|
|
27
|
+
output.table(
|
|
28
|
+
['Item', 'Price'],
|
|
29
|
+
Object.entries(data.pricing)
|
|
30
|
+
.filter(([k]) => !['treasury', 'usdc', 'chain'].includes(k))
|
|
31
|
+
.map(([k, v]) => [k, v])
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (data.supportedMediaTypes) {
|
|
36
|
+
console.log(`\nMedia types: ${data.supportedMediaTypes.join(', ')}`);
|
|
37
|
+
}
|
|
38
|
+
} catch (err) {
|
|
39
|
+
output.error(err.message);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
cmd
|
|
45
|
+
.command('skill')
|
|
46
|
+
.description('View the full agent skill document')
|
|
47
|
+
.action(async () => {
|
|
48
|
+
try {
|
|
49
|
+
const data = await api.get('/agent-skill', { auth: false });
|
|
50
|
+
// Agent skill is a large JSON doc — always output as JSON
|
|
51
|
+
output.json(data);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
output.error(err.message);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
};
|