@adcp/client 3.14.1 → 3.16.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/adcp-registry.js +736 -0
- package/bin/adcp.js +38 -2
- package/dist/lib/core/SingleAgentClient.d.ts +0 -1
- package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.js +1 -2
- package/dist/lib/core/SingleAgentClient.js.map +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/protocols/mcp.d.ts.map +1 -1
- package/dist/lib/protocols/mcp.js +49 -20
- package/dist/lib/protocols/mcp.js.map +1 -1
- package/dist/lib/registry/index.d.ts +97 -31
- package/dist/lib/registry/index.d.ts.map +1 -1
- package/dist/lib/registry/index.js +228 -61
- package/dist/lib/registry/index.js.map +1 -1
- package/dist/lib/registry/types.d.ts +41 -57
- package/dist/lib/registry/types.d.ts.map +1 -1
- package/dist/lib/registry/types.generated.d.ts +1860 -0
- package/dist/lib/registry/types.generated.d.ts.map +1 -0
- package/dist/lib/registry/types.generated.js +8 -0
- package/dist/lib/registry/types.generated.js.map +1 -0
- package/dist/lib/registry/types.js +6 -0
- package/dist/lib/registry/types.js.map +1 -1
- package/dist/lib/types/core.generated.d.ts +91 -64
- package/dist/lib/types/core.generated.d.ts.map +1 -1
- package/dist/lib/types/core.generated.js +2 -2
- package/dist/lib/types/core.generated.js.map +1 -1
- package/dist/lib/types/schemas.generated.d.ts +334 -42
- package/dist/lib/types/schemas.generated.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.js +65 -29
- package/dist/lib/types/schemas.generated.js.map +1 -1
- package/dist/lib/types/tools.generated.d.ts +178 -67
- package/dist/lib/types/tools.generated.d.ts.map +1 -1
- package/dist/lib/version.d.ts +5 -5
- package/dist/lib/version.d.ts.map +1 -1
- package/dist/lib/version.js +5 -5
- package/dist/lib/version.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,736 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AdCP CLI Registry Commands
|
|
3
|
+
*
|
|
4
|
+
* Look up, save, and manage brands, properties, agents, and publishers
|
|
5
|
+
* in the AdCP registry.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { readFileSync } = require('fs');
|
|
9
|
+
const { RegistryClient } = require('../dist/lib/registry/index.js');
|
|
10
|
+
|
|
11
|
+
const VALID_COMMANDS = [
|
|
12
|
+
// Lookup
|
|
13
|
+
'brand',
|
|
14
|
+
'brands',
|
|
15
|
+
'brand-json',
|
|
16
|
+
'enrich-brand',
|
|
17
|
+
'property',
|
|
18
|
+
'properties',
|
|
19
|
+
// Save
|
|
20
|
+
'save-brand',
|
|
21
|
+
'save-property',
|
|
22
|
+
// List & Search
|
|
23
|
+
'list-brands',
|
|
24
|
+
'list-properties',
|
|
25
|
+
'search',
|
|
26
|
+
'agents',
|
|
27
|
+
'publishers',
|
|
28
|
+
'stats',
|
|
29
|
+
// Validation
|
|
30
|
+
'validate',
|
|
31
|
+
'validate-publisher',
|
|
32
|
+
// Discovery
|
|
33
|
+
'lookup',
|
|
34
|
+
'discover',
|
|
35
|
+
'agent-formats',
|
|
36
|
+
'agent-products',
|
|
37
|
+
// Authorization
|
|
38
|
+
'check-auth',
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Parse flags and their values out of an args array.
|
|
43
|
+
* Returns { flags, positional }.
|
|
44
|
+
*/
|
|
45
|
+
function parseArgs(args) {
|
|
46
|
+
const flags = {
|
|
47
|
+
auth: undefined,
|
|
48
|
+
registryUrl: undefined,
|
|
49
|
+
json: false,
|
|
50
|
+
search: undefined,
|
|
51
|
+
type: undefined,
|
|
52
|
+
health: false,
|
|
53
|
+
capabilities: false,
|
|
54
|
+
properties: false,
|
|
55
|
+
limit: undefined,
|
|
56
|
+
offset: undefined,
|
|
57
|
+
};
|
|
58
|
+
const positional = [];
|
|
59
|
+
|
|
60
|
+
for (let i = 0; i < args.length; i++) {
|
|
61
|
+
const arg = args[i];
|
|
62
|
+
if (arg === '--auth' && i + 1 < args.length) {
|
|
63
|
+
flags.auth = args[++i];
|
|
64
|
+
} else if (arg === '--registry-url' && i + 1 < args.length) {
|
|
65
|
+
flags.registryUrl = args[++i];
|
|
66
|
+
} else if (arg === '--search' && i + 1 < args.length) {
|
|
67
|
+
flags.search = args[++i];
|
|
68
|
+
} else if (arg === '--type' && i + 1 < args.length) {
|
|
69
|
+
flags.type = args[++i];
|
|
70
|
+
} else if (arg === '--limit' && i + 1 < args.length) {
|
|
71
|
+
flags.limit = parseInt(args[++i], 10);
|
|
72
|
+
} else if (arg === '--offset' && i + 1 < args.length) {
|
|
73
|
+
flags.offset = parseInt(args[++i], 10);
|
|
74
|
+
} else if (arg === '--json') {
|
|
75
|
+
flags.json = true;
|
|
76
|
+
} else if (arg === '--health') {
|
|
77
|
+
flags.health = true;
|
|
78
|
+
} else if (arg === '--capabilities') {
|
|
79
|
+
flags.capabilities = true;
|
|
80
|
+
} else if (arg === '--properties') {
|
|
81
|
+
flags.properties = true;
|
|
82
|
+
} else if (arg.startsWith('--')) {
|
|
83
|
+
// Unknown flag — skip
|
|
84
|
+
} else {
|
|
85
|
+
positional.push(arg);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return { flags, positional };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Parse a JSON payload from a positional arg.
|
|
94
|
+
* Supports inline JSON strings and @file references.
|
|
95
|
+
*/
|
|
96
|
+
function parsePayload(arg) {
|
|
97
|
+
if (!arg) return undefined;
|
|
98
|
+
try {
|
|
99
|
+
if (arg.startsWith('@')) {
|
|
100
|
+
const filePath = arg.substring(1);
|
|
101
|
+
return JSON.parse(readFileSync(filePath, 'utf-8'));
|
|
102
|
+
}
|
|
103
|
+
return JSON.parse(arg);
|
|
104
|
+
} catch (err) {
|
|
105
|
+
throw new Error(`Failed to parse payload: ${err.message}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function prettyPrintBrand(brand, domain) {
|
|
110
|
+
if (!brand) {
|
|
111
|
+
console.log(`No brand found for '${domain}'`);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
console.log(`Brand: ${brand.brand_name}`);
|
|
116
|
+
console.log(` Domain: ${brand.canonical_domain}`);
|
|
117
|
+
console.log(` Canonical ID: ${brand.canonical_id}`);
|
|
118
|
+
if (brand.keller_type) {
|
|
119
|
+
console.log(` Keller Type: ${brand.keller_type}`);
|
|
120
|
+
}
|
|
121
|
+
console.log(` Source: ${brand.source}`);
|
|
122
|
+
if (brand.parent_brand) {
|
|
123
|
+
console.log(` Parent: ${brand.parent_brand}`);
|
|
124
|
+
}
|
|
125
|
+
if (brand.house_name || brand.house_domain) {
|
|
126
|
+
console.log(` House: ${brand.house_name || ''}${brand.house_domain ? ' (' + brand.house_domain + ')' : ''}`);
|
|
127
|
+
}
|
|
128
|
+
if (brand.brand_agent_url) {
|
|
129
|
+
console.log(` Agent URL: ${brand.brand_agent_url}`);
|
|
130
|
+
}
|
|
131
|
+
if (brand.brand_manifest) {
|
|
132
|
+
const m = brand.brand_manifest;
|
|
133
|
+
if (m.description) {
|
|
134
|
+
console.log(` Description: ${String(m.description).slice(0, 120)}`);
|
|
135
|
+
}
|
|
136
|
+
if (m.colors) {
|
|
137
|
+
const colorParts = Object.entries(m.colors).map(([k, v]) => `${k}: ${v}`);
|
|
138
|
+
console.log(` Colors: ${colorParts.join(', ')}`);
|
|
139
|
+
}
|
|
140
|
+
if (m.logos) {
|
|
141
|
+
console.log(` Logos: ${m.logos.length}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function prettyPrintProperty(property, domain) {
|
|
147
|
+
if (!property) {
|
|
148
|
+
console.log(`No property found for '${domain}'`);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
console.log(`Property: ${property.publisher_domain}`);
|
|
153
|
+
console.log(` Verified: ${property.verified ? 'Yes' : 'No'}`);
|
|
154
|
+
console.log(` Source: ${property.source}`);
|
|
155
|
+
|
|
156
|
+
if (property.authorized_agents && property.authorized_agents.length > 0) {
|
|
157
|
+
console.log(` Authorized Agents: ${property.authorized_agents.length}`);
|
|
158
|
+
for (const agent of property.authorized_agents) {
|
|
159
|
+
console.log(` - ${agent.url}`);
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
console.log(` Authorized Agents: 0`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (property.properties && property.properties.length > 0) {
|
|
166
|
+
console.log(` Properties: ${property.properties.length}`);
|
|
167
|
+
for (const prop of property.properties.slice(0, 10)) {
|
|
168
|
+
const ids = prop.identifiers.map(id => id.value).join(', ');
|
|
169
|
+
const propType = prop.property_type || prop.type || '';
|
|
170
|
+
console.log(` - ${prop.name} (${propType}) [${ids}]`);
|
|
171
|
+
}
|
|
172
|
+
if (property.properties.length > 10) {
|
|
173
|
+
console.log(` ... and ${property.properties.length - 10} more`);
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
console.log(` Properties: 0`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function prettyPrintSaveResult(result) {
|
|
181
|
+
console.log(`Saved successfully`);
|
|
182
|
+
if (result.message) console.log(` Message: ${result.message}`);
|
|
183
|
+
if (result.domain) console.log(` Domain: ${result.domain}`);
|
|
184
|
+
if (result.id) console.log(` ID: ${result.id}`);
|
|
185
|
+
if (result.revision_number != null) console.log(` Revision: ${result.revision_number}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function prettyPrintAgent(agent) {
|
|
189
|
+
const name = agent.name || agent.agent_url || 'Unknown';
|
|
190
|
+
const url = agent.agent_url || '';
|
|
191
|
+
const type = agent.type || '';
|
|
192
|
+
console.log(` ${name}${type ? ' (' + type + ')' : ''}`);
|
|
193
|
+
if (url) console.log(` URL: ${url}`);
|
|
194
|
+
if (agent.health) {
|
|
195
|
+
console.log(` Health: ${agent.health.status || 'unknown'}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function printRegistryUsage() {
|
|
200
|
+
console.log(`AdCP Registry - Brand, Property & Agent Management
|
|
201
|
+
|
|
202
|
+
USAGE:
|
|
203
|
+
adcp registry <command> <args> [options]
|
|
204
|
+
|
|
205
|
+
LOOKUP COMMANDS:
|
|
206
|
+
brand <domain> Look up a brand by domain
|
|
207
|
+
brands <domain> [domain...] Bulk brand lookup (max 100)
|
|
208
|
+
brand-json <domain> Get raw brand.json data for a domain
|
|
209
|
+
enrich-brand <domain> Enrich brand data via Brandfetch
|
|
210
|
+
property <domain> Look up a property by domain
|
|
211
|
+
properties <domain> [d...] Bulk property lookup (max 100)
|
|
212
|
+
|
|
213
|
+
SAVE COMMANDS (requires --auth):
|
|
214
|
+
save-brand <domain> <name> [manifest-json]
|
|
215
|
+
Save or update a community brand
|
|
216
|
+
save-brand <domain> <name> @manifest.json
|
|
217
|
+
Save brand with manifest from file
|
|
218
|
+
save-property <domain> <agent-url> [payload-json]
|
|
219
|
+
Save or update a hosted property
|
|
220
|
+
save-property <domain> <agent-url> @property.json
|
|
221
|
+
Save property with full payload from file
|
|
222
|
+
|
|
223
|
+
LIST & SEARCH:
|
|
224
|
+
list-brands [--search term] List/search brands in the registry
|
|
225
|
+
list-properties [--search t] List/search properties in the registry
|
|
226
|
+
search <query> Search brands, publishers, and properties
|
|
227
|
+
agents [--type sales] List registered agents
|
|
228
|
+
publishers List publishers
|
|
229
|
+
stats Registry statistics
|
|
230
|
+
|
|
231
|
+
VALIDATION:
|
|
232
|
+
validate <domain> Validate domain's adagents.json
|
|
233
|
+
validate-publisher <domain> Validate publisher configuration
|
|
234
|
+
|
|
235
|
+
DISCOVERY:
|
|
236
|
+
lookup <domain> Look up authorized agents for domain
|
|
237
|
+
discover <agent-url> Probe a live agent endpoint
|
|
238
|
+
agent-formats <agent-url> List agent's creative formats
|
|
239
|
+
agent-products <agent-url> List agent's products
|
|
240
|
+
|
|
241
|
+
AUTHORIZATION:
|
|
242
|
+
check-auth <agent-url> <type> <value>
|
|
243
|
+
Check if agent is authorized for property
|
|
244
|
+
|
|
245
|
+
OPTIONS:
|
|
246
|
+
--auth TOKEN API key for authenticated access (required for save)
|
|
247
|
+
--registry-url URL Custom registry URL (default: https://adcontextprotocol.org)
|
|
248
|
+
--json Output raw JSON
|
|
249
|
+
--search TERM Search filter for list commands
|
|
250
|
+
--type TYPE Agent type filter (creative, signals, sales, governance, si)
|
|
251
|
+
--health Include agent health data
|
|
252
|
+
--capabilities Include agent capabilities data
|
|
253
|
+
--properties Include agent property data
|
|
254
|
+
--limit N Limit number of results
|
|
255
|
+
--offset N Offset for pagination
|
|
256
|
+
|
|
257
|
+
ENVIRONMENT VARIABLES:
|
|
258
|
+
ADCP_REGISTRY_API_KEY Default API key for registry operations
|
|
259
|
+
|
|
260
|
+
EXAMPLES:
|
|
261
|
+
# Lookups
|
|
262
|
+
adcp registry brand nike.com
|
|
263
|
+
adcp registry brands nike.com adidas.com --json
|
|
264
|
+
adcp registry brand-json nike.com
|
|
265
|
+
adcp registry enrich-brand nike.com --json
|
|
266
|
+
adcp registry property nytimes.com
|
|
267
|
+
|
|
268
|
+
# List & Search
|
|
269
|
+
adcp registry list-brands --search nike
|
|
270
|
+
adcp registry search nike --json
|
|
271
|
+
adcp registry agents --type sales --health
|
|
272
|
+
adcp registry publishers
|
|
273
|
+
adcp registry stats
|
|
274
|
+
|
|
275
|
+
# Validation
|
|
276
|
+
adcp registry validate nytimes.com
|
|
277
|
+
adcp registry validate-publisher nytimes.com
|
|
278
|
+
|
|
279
|
+
# Discovery
|
|
280
|
+
adcp registry lookup nytimes.com
|
|
281
|
+
adcp registry discover https://test-agent.adcontextprotocol.org
|
|
282
|
+
adcp registry agent-formats https://test-agent.adcontextprotocol.org
|
|
283
|
+
adcp registry agent-products https://test-agent.adcontextprotocol.org
|
|
284
|
+
|
|
285
|
+
# Authorization
|
|
286
|
+
adcp registry check-auth https://agent.example.com domain nytimes.com
|
|
287
|
+
|
|
288
|
+
# Save a brand
|
|
289
|
+
adcp registry save-brand acme.com "Acme Corp" --auth sk_your_key
|
|
290
|
+
adcp registry save-brand acme.com "Acme Corp" '{"colors":{"primary":"#FF0000"}}' --auth sk_your_key
|
|
291
|
+
|
|
292
|
+
# Save a property
|
|
293
|
+
adcp registry save-property example.com https://agent.example.com --auth sk_your_key`);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Handle the 'registry' subcommand.
|
|
298
|
+
* @param {string[]} args - Arguments after 'registry'
|
|
299
|
+
* @returns {Promise<number>} Exit code (0 = success, 1 = error, 2 = usage error)
|
|
300
|
+
*/
|
|
301
|
+
async function handleRegistryCommand(args) {
|
|
302
|
+
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
|
|
303
|
+
printRegistryUsage();
|
|
304
|
+
return 2;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const { flags, positional } = parseArgs(args);
|
|
308
|
+
const subcommand = positional[0];
|
|
309
|
+
|
|
310
|
+
if (!VALID_COMMANDS.includes(subcommand)) {
|
|
311
|
+
console.error(`Unknown registry command: '${subcommand}'\n`);
|
|
312
|
+
printRegistryUsage();
|
|
313
|
+
return 2;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const apiKey = flags.auth || process.env.ADCP_REGISTRY_API_KEY;
|
|
317
|
+
const client = new RegistryClient({
|
|
318
|
+
...(flags.registryUrl && { baseUrl: flags.registryUrl }),
|
|
319
|
+
...(apiKey && { apiKey }),
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
try {
|
|
323
|
+
switch (subcommand) {
|
|
324
|
+
case 'brand': {
|
|
325
|
+
const domain = positional[1];
|
|
326
|
+
if (!domain) {
|
|
327
|
+
console.error('Error: domain is required\n');
|
|
328
|
+
return 2;
|
|
329
|
+
}
|
|
330
|
+
const result = await client.lookupBrand(domain);
|
|
331
|
+
if (flags.json) {
|
|
332
|
+
console.log(JSON.stringify(result, null, 2));
|
|
333
|
+
} else {
|
|
334
|
+
prettyPrintBrand(result, domain);
|
|
335
|
+
}
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
case 'brands': {
|
|
339
|
+
const domains = positional.slice(1);
|
|
340
|
+
if (domains.length === 0) {
|
|
341
|
+
console.error('Error: at least one domain is required\n');
|
|
342
|
+
return 2;
|
|
343
|
+
}
|
|
344
|
+
const results = await client.lookupBrands(domains);
|
|
345
|
+
if (flags.json) {
|
|
346
|
+
console.log(JSON.stringify(results, null, 2));
|
|
347
|
+
} else {
|
|
348
|
+
const entries = Object.entries(results);
|
|
349
|
+
for (let i = 0; i < entries.length; i++) {
|
|
350
|
+
const [domain, brand] = entries[i];
|
|
351
|
+
prettyPrintBrand(brand, domain);
|
|
352
|
+
if (i < entries.length - 1) console.log('');
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
case 'brand-json': {
|
|
358
|
+
const domain = positional[1];
|
|
359
|
+
if (!domain) {
|
|
360
|
+
console.error('Error: domain is required\n');
|
|
361
|
+
return 2;
|
|
362
|
+
}
|
|
363
|
+
const result = await client.getBrandJson(domain);
|
|
364
|
+
if (flags.json) {
|
|
365
|
+
console.log(JSON.stringify(result, null, 2));
|
|
366
|
+
} else if (!result) {
|
|
367
|
+
console.log(`No brand.json found for '${domain}'`);
|
|
368
|
+
} else {
|
|
369
|
+
console.log(`Brand JSON: ${domain}`);
|
|
370
|
+
for (const [key, value] of Object.entries(result)) {
|
|
371
|
+
console.log(` ${key}: ${JSON.stringify(value)}`);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
case 'enrich-brand': {
|
|
377
|
+
const domain = positional[1];
|
|
378
|
+
if (!domain) {
|
|
379
|
+
console.error('Error: domain is required\n');
|
|
380
|
+
return 2;
|
|
381
|
+
}
|
|
382
|
+
const result = await client.enrichBrand(domain);
|
|
383
|
+
if (flags.json) {
|
|
384
|
+
console.log(JSON.stringify(result, null, 2));
|
|
385
|
+
} else {
|
|
386
|
+
console.log(`Enriched brand: ${domain}`);
|
|
387
|
+
for (const [key, value] of Object.entries(result)) {
|
|
388
|
+
console.log(` ${key}: ${JSON.stringify(value)}`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
case 'property': {
|
|
394
|
+
const domain = positional[1];
|
|
395
|
+
if (!domain) {
|
|
396
|
+
console.error('Error: domain is required\n');
|
|
397
|
+
return 2;
|
|
398
|
+
}
|
|
399
|
+
const result = await client.lookupProperty(domain);
|
|
400
|
+
if (flags.json) {
|
|
401
|
+
console.log(JSON.stringify(result, null, 2));
|
|
402
|
+
} else {
|
|
403
|
+
prettyPrintProperty(result, domain);
|
|
404
|
+
}
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
case 'properties': {
|
|
408
|
+
const domains = positional.slice(1);
|
|
409
|
+
if (domains.length === 0) {
|
|
410
|
+
console.error('Error: at least one domain is required\n');
|
|
411
|
+
return 2;
|
|
412
|
+
}
|
|
413
|
+
const results = await client.lookupProperties(domains);
|
|
414
|
+
if (flags.json) {
|
|
415
|
+
console.log(JSON.stringify(results, null, 2));
|
|
416
|
+
} else {
|
|
417
|
+
const entries = Object.entries(results);
|
|
418
|
+
for (let i = 0; i < entries.length; i++) {
|
|
419
|
+
const [domain, prop] = entries[i];
|
|
420
|
+
prettyPrintProperty(prop, domain);
|
|
421
|
+
if (i < entries.length - 1) console.log('');
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
426
|
+
case 'save-brand': {
|
|
427
|
+
const domain = positional[1];
|
|
428
|
+
const brandName = positional[2];
|
|
429
|
+
if (!domain || !brandName) {
|
|
430
|
+
console.error('Error: domain and brand name are required\n');
|
|
431
|
+
console.error('Usage: adcp registry save-brand <domain> <brand-name> [manifest-json]\n');
|
|
432
|
+
return 2;
|
|
433
|
+
}
|
|
434
|
+
const payload = { domain, brand_name: brandName };
|
|
435
|
+
const manifestArg = positional[3];
|
|
436
|
+
if (manifestArg) {
|
|
437
|
+
payload.brand_manifest = parsePayload(manifestArg);
|
|
438
|
+
}
|
|
439
|
+
const result = await client.saveBrand(payload);
|
|
440
|
+
if (flags.json) {
|
|
441
|
+
console.log(JSON.stringify(result, null, 2));
|
|
442
|
+
} else {
|
|
443
|
+
prettyPrintSaveResult(result);
|
|
444
|
+
}
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
case 'save-property': {
|
|
448
|
+
const domain = positional[1];
|
|
449
|
+
const agentUrl = positional[2];
|
|
450
|
+
if (!domain || !agentUrl) {
|
|
451
|
+
console.error('Error: domain and agent URL are required\n');
|
|
452
|
+
console.error('Usage: adcp registry save-property <domain> <agent-url> [payload-json]\n');
|
|
453
|
+
return 2;
|
|
454
|
+
}
|
|
455
|
+
const extraArg = positional[3];
|
|
456
|
+
let payload;
|
|
457
|
+
if (extraArg) {
|
|
458
|
+
const extra = parsePayload(extraArg);
|
|
459
|
+
payload = {
|
|
460
|
+
publisher_domain: domain,
|
|
461
|
+
authorized_agents: [{ url: agentUrl }],
|
|
462
|
+
...extra,
|
|
463
|
+
};
|
|
464
|
+
} else {
|
|
465
|
+
payload = {
|
|
466
|
+
publisher_domain: domain,
|
|
467
|
+
authorized_agents: [{ url: agentUrl }],
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
const result = await client.saveProperty(payload);
|
|
471
|
+
if (flags.json) {
|
|
472
|
+
console.log(JSON.stringify(result, null, 2));
|
|
473
|
+
} else {
|
|
474
|
+
prettyPrintSaveResult(result);
|
|
475
|
+
}
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// ====== List & Search ======
|
|
480
|
+
|
|
481
|
+
case 'list-brands': {
|
|
482
|
+
const options = {};
|
|
483
|
+
if (flags.search) options.search = flags.search;
|
|
484
|
+
if (flags.limit != null) options.limit = flags.limit;
|
|
485
|
+
if (flags.offset != null) options.offset = flags.offset;
|
|
486
|
+
const result = await client.listBrands(Object.keys(options).length ? options : undefined);
|
|
487
|
+
if (flags.json) {
|
|
488
|
+
console.log(JSON.stringify(result, null, 2));
|
|
489
|
+
} else {
|
|
490
|
+
const brands = result.brands || [];
|
|
491
|
+
console.log(`Brands: ${brands.length} results`);
|
|
492
|
+
for (const b of brands) {
|
|
493
|
+
console.log(` ${b.brand_name || b.canonical_domain || b.domain} (${b.canonical_domain || b.domain})`);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
case 'list-properties': {
|
|
499
|
+
const options = {};
|
|
500
|
+
if (flags.search) options.search = flags.search;
|
|
501
|
+
if (flags.limit != null) options.limit = flags.limit;
|
|
502
|
+
if (flags.offset != null) options.offset = flags.offset;
|
|
503
|
+
const result = await client.listProperties(Object.keys(options).length ? options : undefined);
|
|
504
|
+
if (flags.json) {
|
|
505
|
+
console.log(JSON.stringify(result, null, 2));
|
|
506
|
+
} else {
|
|
507
|
+
const props = result.properties || [];
|
|
508
|
+
console.log(`Properties: ${props.length} results`);
|
|
509
|
+
for (const p of props) {
|
|
510
|
+
console.log(` ${p.publisher_domain || p.domain} (${p.source || 'unknown'})`);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
break;
|
|
514
|
+
}
|
|
515
|
+
case 'search': {
|
|
516
|
+
const query = positional[1];
|
|
517
|
+
if (!query) {
|
|
518
|
+
console.error('Error: query is required\n');
|
|
519
|
+
return 2;
|
|
520
|
+
}
|
|
521
|
+
const result = await client.search(query);
|
|
522
|
+
if (flags.json) {
|
|
523
|
+
console.log(JSON.stringify(result, null, 2));
|
|
524
|
+
} else {
|
|
525
|
+
const brandCount = (result.brands || []).length;
|
|
526
|
+
const pubCount = (result.publishers || []).length;
|
|
527
|
+
const propCount = (result.properties || []).length;
|
|
528
|
+
console.log(`Search results for '${query}':`);
|
|
529
|
+
console.log(` Brands: ${brandCount}`);
|
|
530
|
+
console.log(` Publishers: ${pubCount}`);
|
|
531
|
+
console.log(` Properties: ${propCount}`);
|
|
532
|
+
}
|
|
533
|
+
break;
|
|
534
|
+
}
|
|
535
|
+
case 'agents': {
|
|
536
|
+
const options = {};
|
|
537
|
+
if (flags.type) options.type = flags.type;
|
|
538
|
+
if (flags.health) options.health = true;
|
|
539
|
+
if (flags.capabilities) options.capabilities = true;
|
|
540
|
+
if (flags.properties) options.properties = true;
|
|
541
|
+
const result = await client.listAgents(Object.keys(options).length ? options : undefined);
|
|
542
|
+
if (flags.json) {
|
|
543
|
+
console.log(JSON.stringify(result, null, 2));
|
|
544
|
+
} else {
|
|
545
|
+
const agents = result.agents || [];
|
|
546
|
+
console.log(`Agents: ${result.count || agents.length} registered`);
|
|
547
|
+
for (const agent of agents) {
|
|
548
|
+
prettyPrintAgent(agent);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
break;
|
|
552
|
+
}
|
|
553
|
+
case 'publishers': {
|
|
554
|
+
const result = await client.listPublishers();
|
|
555
|
+
if (flags.json) {
|
|
556
|
+
console.log(JSON.stringify(result, null, 2));
|
|
557
|
+
} else {
|
|
558
|
+
const pubs = result.publishers || [];
|
|
559
|
+
console.log(`Publishers: ${result.count || pubs.length} registered`);
|
|
560
|
+
for (const pub of pubs) {
|
|
561
|
+
console.log(` ${pub.domain || pub.publisher_domain || 'unknown'}`);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
break;
|
|
565
|
+
}
|
|
566
|
+
case 'stats': {
|
|
567
|
+
const result = await client.getRegistryStats();
|
|
568
|
+
if (flags.json) {
|
|
569
|
+
console.log(JSON.stringify(result, null, 2));
|
|
570
|
+
} else {
|
|
571
|
+
console.log('Registry Statistics:');
|
|
572
|
+
for (const [key, value] of Object.entries(result)) {
|
|
573
|
+
console.log(` ${key}: ${JSON.stringify(value)}`);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// ====== Validation ======
|
|
580
|
+
|
|
581
|
+
case 'validate': {
|
|
582
|
+
const domain = positional[1];
|
|
583
|
+
if (!domain) {
|
|
584
|
+
console.error('Error: domain is required\n');
|
|
585
|
+
return 2;
|
|
586
|
+
}
|
|
587
|
+
const result = await client.validateAdagents(domain);
|
|
588
|
+
if (flags.json) {
|
|
589
|
+
console.log(JSON.stringify(result, null, 2));
|
|
590
|
+
} else {
|
|
591
|
+
const valid = result.valid !== false;
|
|
592
|
+
console.log(`Validation: ${valid ? 'PASS' : 'FAIL'}`);
|
|
593
|
+
console.log(` Domain: ${domain}`);
|
|
594
|
+
if (result.errors && result.errors.length > 0) {
|
|
595
|
+
console.log(` Errors: ${result.errors.length}`);
|
|
596
|
+
for (const err of result.errors) {
|
|
597
|
+
console.log(` - ${typeof err === 'string' ? err : err.message || JSON.stringify(err)}`);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
if (result.warnings && result.warnings.length > 0) {
|
|
601
|
+
console.log(` Warnings: ${result.warnings.length}`);
|
|
602
|
+
for (const w of result.warnings) {
|
|
603
|
+
console.log(` - ${typeof w === 'string' ? w : w.message || JSON.stringify(w)}`);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
break;
|
|
608
|
+
}
|
|
609
|
+
case 'validate-publisher': {
|
|
610
|
+
const domain = positional[1];
|
|
611
|
+
if (!domain) {
|
|
612
|
+
console.error('Error: domain is required\n');
|
|
613
|
+
return 2;
|
|
614
|
+
}
|
|
615
|
+
const result = await client.validatePublisher(domain);
|
|
616
|
+
if (flags.json) {
|
|
617
|
+
console.log(JSON.stringify(result, null, 2));
|
|
618
|
+
} else {
|
|
619
|
+
console.log(`Publisher validation: ${domain}`);
|
|
620
|
+
for (const [key, value] of Object.entries(result)) {
|
|
621
|
+
console.log(` ${key}: ${JSON.stringify(value)}`);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
break;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// ====== Discovery ======
|
|
628
|
+
|
|
629
|
+
case 'lookup': {
|
|
630
|
+
const domain = positional[1];
|
|
631
|
+
if (!domain) {
|
|
632
|
+
console.error('Error: domain is required\n');
|
|
633
|
+
return 2;
|
|
634
|
+
}
|
|
635
|
+
const result = await client.lookupDomain(domain);
|
|
636
|
+
if (flags.json) {
|
|
637
|
+
console.log(JSON.stringify(result, null, 2));
|
|
638
|
+
} else {
|
|
639
|
+
console.log(`Domain lookup: ${domain}`);
|
|
640
|
+
const agents = result.authorized_agents || [];
|
|
641
|
+
console.log(` Authorized agents: ${agents.length}`);
|
|
642
|
+
for (const agent of agents) {
|
|
643
|
+
console.log(` - ${agent.url || agent.agent_url || JSON.stringify(agent)}`);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
break;
|
|
647
|
+
}
|
|
648
|
+
case 'discover': {
|
|
649
|
+
const url = positional[1];
|
|
650
|
+
if (!url) {
|
|
651
|
+
console.error('Error: agent URL is required\n');
|
|
652
|
+
return 2;
|
|
653
|
+
}
|
|
654
|
+
const result = await client.discoverAgent(url);
|
|
655
|
+
if (flags.json) {
|
|
656
|
+
console.log(JSON.stringify(result, null, 2));
|
|
657
|
+
} else {
|
|
658
|
+
console.log(`Agent discovery: ${url}`);
|
|
659
|
+
for (const [key, value] of Object.entries(result)) {
|
|
660
|
+
console.log(` ${key}: ${JSON.stringify(value)}`);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
break;
|
|
664
|
+
}
|
|
665
|
+
case 'agent-formats': {
|
|
666
|
+
const url = positional[1];
|
|
667
|
+
if (!url) {
|
|
668
|
+
console.error('Error: agent URL is required\n');
|
|
669
|
+
return 2;
|
|
670
|
+
}
|
|
671
|
+
const result = await client.getAgentFormats(url);
|
|
672
|
+
if (flags.json) {
|
|
673
|
+
console.log(JSON.stringify(result, null, 2));
|
|
674
|
+
} else {
|
|
675
|
+
console.log(`Agent formats: ${url}`);
|
|
676
|
+
const formats = result.formats || [];
|
|
677
|
+
console.log(` Formats: ${formats.length}`);
|
|
678
|
+
for (const f of formats) {
|
|
679
|
+
console.log(` - ${f.name || f.format_id || JSON.stringify(f)}`);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
case 'agent-products': {
|
|
685
|
+
const url = positional[1];
|
|
686
|
+
if (!url) {
|
|
687
|
+
console.error('Error: agent URL is required\n');
|
|
688
|
+
return 2;
|
|
689
|
+
}
|
|
690
|
+
const result = await client.getAgentProducts(url);
|
|
691
|
+
if (flags.json) {
|
|
692
|
+
console.log(JSON.stringify(result, null, 2));
|
|
693
|
+
} else {
|
|
694
|
+
console.log(`Agent products: ${url}`);
|
|
695
|
+
const products = result.products || [];
|
|
696
|
+
console.log(` Products: ${products.length}`);
|
|
697
|
+
for (const p of products) {
|
|
698
|
+
console.log(` - ${p.name || p.product_id || JSON.stringify(p)}`);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
break;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// ====== Authorization ======
|
|
705
|
+
|
|
706
|
+
case 'check-auth': {
|
|
707
|
+
const agentUrl = positional[1];
|
|
708
|
+
const identifierType = positional[2];
|
|
709
|
+
const identifierValue = positional[3];
|
|
710
|
+
if (!agentUrl || !identifierType || !identifierValue) {
|
|
711
|
+
console.error('Error: agent URL, identifier type, and identifier value are required\n');
|
|
712
|
+
console.error('Usage: adcp registry check-auth <agent-url> <type> <value>\n');
|
|
713
|
+
return 2;
|
|
714
|
+
}
|
|
715
|
+
const result = await client.validatePropertyAuthorization(agentUrl, identifierType, identifierValue);
|
|
716
|
+
if (flags.json) {
|
|
717
|
+
console.log(JSON.stringify(result, null, 2));
|
|
718
|
+
} else {
|
|
719
|
+
console.log(`Authorization check:`);
|
|
720
|
+
console.log(` Agent: ${result.agent_url}`);
|
|
721
|
+
console.log(` Type: ${result.identifier_type}`);
|
|
722
|
+
console.log(` Value: ${result.identifier_value}`);
|
|
723
|
+
console.log(` Authorized: ${result.authorized ? 'Yes' : 'No'}`);
|
|
724
|
+
console.log(` Checked at: ${result.checked_at}`);
|
|
725
|
+
}
|
|
726
|
+
break;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return 0;
|
|
730
|
+
} catch (err) {
|
|
731
|
+
console.error(`Error: ${err.message}`);
|
|
732
|
+
return 1;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
module.exports = { handleRegistryCommand, printRegistryUsage };
|