44reports-mcp 1.3.0 → 1.5.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/dist/api-client.d.ts +40 -3
- package/dist/api-client.js +48 -8
- package/dist/index.js +47 -4
- package/dist/tools/products.d.ts +74 -6
- package/dist/tools/products.js +65 -3
- package/dist/tools/upload-directory.d.ts +2 -2
- package/package.json +1 -1
package/dist/api-client.d.ts
CHANGED
|
@@ -151,7 +151,7 @@ export declare class ApiClient {
|
|
|
151
151
|
}>;
|
|
152
152
|
total: number;
|
|
153
153
|
}>;
|
|
154
|
-
getProduct(slug: string, domain?: string): Promise<{
|
|
154
|
+
getProduct(slug: string, domain?: string | string[]): Promise<{
|
|
155
155
|
product: {
|
|
156
156
|
id: string;
|
|
157
157
|
slug: string;
|
|
@@ -173,11 +173,20 @@ export declare class ApiClient {
|
|
|
173
173
|
domain: string;
|
|
174
174
|
}>;
|
|
175
175
|
}>;
|
|
176
|
-
getProductFile(slug: string, filepath: string
|
|
176
|
+
getProductFile(slug: string, filepath: string, options?: {
|
|
177
|
+
format?: 'inline' | 'signed-url';
|
|
178
|
+
ttl?: number;
|
|
179
|
+
}): Promise<{
|
|
177
180
|
path: string;
|
|
178
181
|
content: unknown;
|
|
179
182
|
content_type: string;
|
|
180
183
|
size?: number;
|
|
184
|
+
} | {
|
|
185
|
+
path: string;
|
|
186
|
+
url: string;
|
|
187
|
+
expires_at: string;
|
|
188
|
+
content_type: string;
|
|
189
|
+
size: number;
|
|
181
190
|
}>;
|
|
182
191
|
updateProductFile(slug: string, filepath: string, body: {
|
|
183
192
|
content: unknown;
|
|
@@ -233,7 +242,7 @@ export declare class ApiClient {
|
|
|
233
242
|
deleteProductFile(slug: string, filepath: string): Promise<{
|
|
234
243
|
success: boolean;
|
|
235
244
|
}>;
|
|
236
|
-
getProductIndex(slug: string, domain?: string): Promise<{
|
|
245
|
+
getProductIndex(slug: string, domain?: string | string[]): Promise<{
|
|
237
246
|
product_slug: string;
|
|
238
247
|
updated_at: string;
|
|
239
248
|
files: Array<{
|
|
@@ -253,6 +262,34 @@ export declare class ApiClient {
|
|
|
253
262
|
}): Promise<{
|
|
254
263
|
files: PulledFile[];
|
|
255
264
|
}>;
|
|
265
|
+
findAssets(slug: string, options?: {
|
|
266
|
+
query?: string;
|
|
267
|
+
asset_type?: string;
|
|
268
|
+
surfaces?: string[];
|
|
269
|
+
orientation?: string | null;
|
|
270
|
+
background?: string | null;
|
|
271
|
+
color_mode?: string | null;
|
|
272
|
+
platform?: string | null;
|
|
273
|
+
locale?: string | null;
|
|
274
|
+
include_drafts?: boolean;
|
|
275
|
+
limit?: number;
|
|
276
|
+
ttl?: number;
|
|
277
|
+
}): Promise<{
|
|
278
|
+
query: string | null;
|
|
279
|
+
filters: Record<string, unknown>;
|
|
280
|
+
total_inventory: number;
|
|
281
|
+
matched: number;
|
|
282
|
+
results: Array<{
|
|
283
|
+
path: string;
|
|
284
|
+
score: number;
|
|
285
|
+
matched_terms: string[];
|
|
286
|
+
content_type: string;
|
|
287
|
+
size: number;
|
|
288
|
+
entry: Record<string, unknown>;
|
|
289
|
+
url: string;
|
|
290
|
+
expires_at: string;
|
|
291
|
+
}>;
|
|
292
|
+
}>;
|
|
256
293
|
addBacklogEntry(data: {
|
|
257
294
|
content: string;
|
|
258
295
|
product_slug?: string;
|
package/dist/api-client.js
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
function withQuery(path, params) {
|
|
2
|
+
const qs = params.toString();
|
|
3
|
+
return qs ? `${path}?${qs}` : path;
|
|
4
|
+
}
|
|
5
|
+
function appendDomains(params, domain) {
|
|
6
|
+
if (!domain)
|
|
7
|
+
return;
|
|
8
|
+
for (const d of Array.isArray(domain) ? domain : [domain])
|
|
9
|
+
params.append('domain', d);
|
|
10
|
+
}
|
|
1
11
|
export class ApiClient {
|
|
2
12
|
config;
|
|
3
13
|
constructor(config) {
|
|
@@ -102,15 +112,20 @@ export class ApiClient {
|
|
|
102
112
|
params.set(key, String(value));
|
|
103
113
|
}
|
|
104
114
|
}
|
|
105
|
-
|
|
106
|
-
return this.request(`/api/products${query ? `?${query}` : ''}`);
|
|
115
|
+
return this.request(withQuery('/api/products', params));
|
|
107
116
|
}
|
|
108
117
|
async getProduct(slug, domain) {
|
|
109
|
-
const
|
|
110
|
-
|
|
118
|
+
const params = new URLSearchParams();
|
|
119
|
+
appendDomains(params, domain);
|
|
120
|
+
return this.request(withQuery(`/api/products/${slug}`, params));
|
|
111
121
|
}
|
|
112
|
-
async getProductFile(slug, filepath) {
|
|
113
|
-
|
|
122
|
+
async getProductFile(slug, filepath, options) {
|
|
123
|
+
const params = new URLSearchParams();
|
|
124
|
+
if (options?.format && options.format !== 'inline')
|
|
125
|
+
params.set('format', options.format);
|
|
126
|
+
if (options?.ttl !== undefined)
|
|
127
|
+
params.set('ttl', String(options.ttl));
|
|
128
|
+
return this.request(withQuery(`/api/products/${slug}/files/${filepath}`, params));
|
|
114
129
|
}
|
|
115
130
|
async updateProductFile(slug, filepath, body) {
|
|
116
131
|
return this.request(`/api/products/${slug}/files/${filepath}`, {
|
|
@@ -147,8 +162,9 @@ export class ApiClient {
|
|
|
147
162
|
});
|
|
148
163
|
}
|
|
149
164
|
async getProductIndex(slug, domain) {
|
|
150
|
-
const
|
|
151
|
-
|
|
165
|
+
const params = new URLSearchParams();
|
|
166
|
+
appendDomains(params, domain);
|
|
167
|
+
return this.request(withQuery(`/api/products/${slug}/index`, params));
|
|
152
168
|
}
|
|
153
169
|
async pullProductFiles(slug, options) {
|
|
154
170
|
return this.request(`/api/products/${slug}/pull`, {
|
|
@@ -156,6 +172,30 @@ export class ApiClient {
|
|
|
156
172
|
body: JSON.stringify(options ?? {}),
|
|
157
173
|
});
|
|
158
174
|
}
|
|
175
|
+
async findAssets(slug, options = {}) {
|
|
176
|
+
const params = new URLSearchParams();
|
|
177
|
+
if (options.query)
|
|
178
|
+
params.set('q', options.query);
|
|
179
|
+
if (options.asset_type)
|
|
180
|
+
params.set('asset_type', options.asset_type);
|
|
181
|
+
if (options.surfaces?.length)
|
|
182
|
+
params.set('surfaces', options.surfaces.join(','));
|
|
183
|
+
// For variant fields, undefined = no filter; null = require null on the entry; string = exact match.
|
|
184
|
+
for (const k of ['orientation', 'background', 'color_mode', 'platform', 'locale']) {
|
|
185
|
+
const v = options[k];
|
|
186
|
+
if (v === null)
|
|
187
|
+
params.set(k, '');
|
|
188
|
+
else if (typeof v === 'string')
|
|
189
|
+
params.set(k, v);
|
|
190
|
+
}
|
|
191
|
+
if (options.include_drafts === false)
|
|
192
|
+
params.set('include_drafts', 'false');
|
|
193
|
+
if (options.limit !== undefined)
|
|
194
|
+
params.set('limit', String(options.limit));
|
|
195
|
+
if (options.ttl !== undefined)
|
|
196
|
+
params.set('ttl', String(options.ttl));
|
|
197
|
+
return this.request(withQuery(`/api/products/${slug}/find-assets`, params));
|
|
198
|
+
}
|
|
159
199
|
// --- Agent Backlog ---
|
|
160
200
|
async addBacklogEntry(data) {
|
|
161
201
|
return this.request('/api/backlog', {
|
package/dist/index.js
CHANGED
|
@@ -8,11 +8,18 @@ import { deployReportSchema, updateReportSchema, createDeployTool, createUpdateT
|
|
|
8
8
|
import { listReportsSchema, getReportSchema, deleteReportSchema, createListTool, createGetTool, createDeleteTool, } from './tools/reports.js';
|
|
9
9
|
import { pullContextSchema, createPullTool, } from './tools/pull.js';
|
|
10
10
|
import { manageFoldersSchema, createManageFoldersTool, } from './tools/folders.js';
|
|
11
|
-
import { listProductsSchema, getProductSchema, readProductFileSchema, updateProductKnowledgeSchema, uploadProductFilesSchema, pullProductFilesSchema, createProductSchema, deleteProductSchema, deleteProductFileSchema, getProductHealthSchema, getProductIndexSchema, createListProductsTool, createGetProductTool, createReadProductFileTool, createUpdateProductKnowledgeTool, createUploadProductFilesTool, createPullProductFilesTool, createGetProductHealthTool, createGetProductIndexTool, createCreateProductTool, createDeleteProductTool, createDeleteProductFileTool, } from './tools/products.js';
|
|
11
|
+
import { listProductsSchema, getProductSchema, readProductFileSchema, updateProductKnowledgeSchema, uploadProductFilesSchema, pullProductFilesSchema, createProductSchema, deleteProductSchema, deleteProductFileSchema, getProductHealthSchema, getProductIndexSchema, createListProductsTool, createGetProductTool, createReadProductFileTool, createUpdateProductKnowledgeTool, createUploadProductFilesTool, createPullProductFilesTool, createGetProductHealthTool, createGetProductIndexTool, createCreateProductTool, createDeleteProductTool, createDeleteProductFileTool, createFindAssetsTool, findAssetsSchema, } from './tools/products.js';
|
|
12
12
|
import { createUploadProductDirectoryTool, uploadProductDirectorySchema, UPLOAD_DIRECTORY_DESCRIPTION, } from './tools/upload-directory.js';
|
|
13
13
|
import { addToBacklogSchema, listBacklogSchema, processBacklogSchema, createAddToBacklogTool, createListBacklogTool, createProcessBacklogTool, } from './tools/backlog.js';
|
|
14
|
+
import { DOMAIN_VALUES } from './tools/domains.js';
|
|
14
15
|
const config = loadConfig();
|
|
15
16
|
const client = new ApiClient(config);
|
|
17
|
+
const DOMAIN_FILTER_SCHEMA = {
|
|
18
|
+
oneOf: [
|
|
19
|
+
{ type: 'string', enum: DOMAIN_VALUES },
|
|
20
|
+
{ type: 'array', items: { type: 'string', enum: DOMAIN_VALUES } },
|
|
21
|
+
],
|
|
22
|
+
};
|
|
16
23
|
function prop(type, description, extra = {}) {
|
|
17
24
|
return { type, description, ...extra };
|
|
18
25
|
}
|
|
@@ -158,7 +165,7 @@ const toolDefinitions = [
|
|
|
158
165
|
type: 'object',
|
|
159
166
|
properties: {
|
|
160
167
|
slug: prop('string', 'Product slug'),
|
|
161
|
-
domain:
|
|
168
|
+
domain: { ...DOMAIN_FILTER_SCHEMA, description: 'Filter files by domain. Single domain or array — pass an array (e.g. ["brand", "advertising"]) to combine domains in one request.' },
|
|
162
169
|
},
|
|
163
170
|
required: ['slug'],
|
|
164
171
|
},
|
|
@@ -167,12 +174,14 @@ const toolDefinitions = [
|
|
|
167
174
|
},
|
|
168
175
|
{
|
|
169
176
|
name: 'read_product_file',
|
|
170
|
-
description: 'Read a single file from a product by path. Use get_product to read all knowledge files at once (more efficient). Use read_product_file only when you need one specific file — works for markdown docs, JSON configs, and binary files (logos, PDFs
|
|
177
|
+
description: 'Read a single file from a product by path. Use get_product to read all knowledge files at once (more efficient). Use read_product_file only when you need one specific file — works for markdown docs, JSON configs, and binary files.\n\nFor binary files (logos, screenshots, PDFs): pass `format: "signed-url"` to get a short-lived download URL instead of inline base64. Base64 inflates LLM context by ~33% and round-trips through your prompt; signed URLs let you `curl -o <path> <url>` directly to disk.\n\nTypical workflow: get_product_index → find the file you need → read_product_file (use signed-url for binaries).',
|
|
171
178
|
inputSchema: {
|
|
172
179
|
type: 'object',
|
|
173
180
|
properties: {
|
|
174
181
|
slug: prop('string', 'Product slug'),
|
|
175
182
|
filepath: prop('string', 'File path within the product (e.g., "docs/research/user-research.md", "meta-ads.json", "brand-assets/logo.png")'),
|
|
183
|
+
format: { type: 'string', enum: ['inline', 'signed-url'], description: 'Response format. Default "inline" returns content directly. Use "signed-url" for binaries to avoid base64 context bloat — response will include a `url` field instead of `content`.' },
|
|
184
|
+
ttl: { type: 'number', description: 'Signed URL lifetime in seconds (default 600, max 3600). Ignored unless format="signed-url".' },
|
|
176
185
|
},
|
|
177
186
|
required: ['slug', 'filepath'],
|
|
178
187
|
},
|
|
@@ -284,7 +293,7 @@ const toolDefinitions = [
|
|
|
284
293
|
type: 'object',
|
|
285
294
|
properties: {
|
|
286
295
|
slug: prop('string', 'Product slug'),
|
|
287
|
-
domain:
|
|
296
|
+
domain: { ...DOMAIN_FILTER_SCHEMA, description: 'Filter index entries by domain. Single domain or array.' },
|
|
288
297
|
},
|
|
289
298
|
required: ['slug'],
|
|
290
299
|
},
|
|
@@ -333,6 +342,40 @@ const toolDefinitions = [
|
|
|
333
342
|
schema: deleteProductFileSchema,
|
|
334
343
|
handler: createDeleteProductFileTool(client),
|
|
335
344
|
},
|
|
345
|
+
{
|
|
346
|
+
name: 'find_assets',
|
|
347
|
+
description: 'Search a product\'s asset inventory by free-text query and structured filters. Returns ranked entries with descriptions, taxonomy fields, and short-lived signed download URLs.\n\n' +
|
|
348
|
+
'Prefer this over scanning binary_files from get_product when you know what kind of asset you want — agents reading 30+ paths and guessing from filenames is the failure mode this tool exists to fix.\n\n' +
|
|
349
|
+
'Examples:\n' +
|
|
350
|
+
' • { slug: "clara", query: "horizontal logo for landing page", asset_type: "logo", surfaces: ["landing"], background: "transparent" }\n' +
|
|
351
|
+
' • { slug: "clara", asset_type: "app-icon", platform: "ios" } — pure filter query, no text\n' +
|
|
352
|
+
' • { slug: "clara", query: "device mockup with hand holding phone" } — semantic, no filters\n\n' +
|
|
353
|
+
'Empty string for orientation/background/color_mode/platform/locale means "the entry has this variant set to null". Drafts (auto-described, unverified) are included by default; pass include_drafts=false to exclude them.',
|
|
354
|
+
inputSchema: {
|
|
355
|
+
type: 'object',
|
|
356
|
+
properties: {
|
|
357
|
+
slug: prop('string', 'Product slug'),
|
|
358
|
+
query: prop('string', 'Free-text query against description, usage, file path, asset_type, and surfaces.'),
|
|
359
|
+
asset_type: prop('string', 'Restrict to one asset_type.', {
|
|
360
|
+
enum: ['logo', 'app-icon', 'screenshot-ui', 'screenshot-marketing', 'mockup', 'photo-lifestyle', 'photo-product', 'illustration', 'color-swatch', 'typography-sample', 'brand-guide-page', 'video', 'animation', 'document', 'other'],
|
|
361
|
+
}),
|
|
362
|
+
surfaces: prop('array', 'ANY-of match against the entry\'s surfaces array.', {
|
|
363
|
+
items: { type: 'string', enum: ['ad-creative', 'app-store', 'landing', 'email', 'social-organic', 'brand-guide', 'internal-doc'] },
|
|
364
|
+
}),
|
|
365
|
+
orientation: prop('string', 'Variant filter.', { enum: ['horizontal', 'vertical', 'square'] }),
|
|
366
|
+
background: prop('string', 'Variant filter.', { enum: ['transparent', 'solid-light', 'solid-dark', 'photographic'] }),
|
|
367
|
+
color_mode: prop('string', 'Variant filter.', { enum: ['light', 'dark', 'neutral'] }),
|
|
368
|
+
platform: prop('string', 'Variant filter.', { enum: ['ios', 'android', 'web'] }),
|
|
369
|
+
locale: prop('string', 'Filter by exact locale string (BCP-47, e.g. "en-US").'),
|
|
370
|
+
include_drafts: prop('boolean', 'Include auto-described draft entries (default true).'),
|
|
371
|
+
limit: prop('number', 'Maximum number of results. Default 20, max 100.'),
|
|
372
|
+
ttl: prop('number', 'Lifetime in seconds for the signed download URLs (default 600, max 3600).'),
|
|
373
|
+
},
|
|
374
|
+
required: ['slug'],
|
|
375
|
+
},
|
|
376
|
+
schema: findAssetsSchema,
|
|
377
|
+
handler: createFindAssetsTool(client),
|
|
378
|
+
},
|
|
336
379
|
{
|
|
337
380
|
name: 'add_to_backlog',
|
|
338
381
|
description: 'Add an unstructured observation to the agent backlog for later processing. Low-friction way for any agent to contribute signals — competitor insights, user feedback, research findings, or any data that should eventually enrich product knowledge. Only content is required; everything else is optional.\n\nIf you know which product this relates to, pass product_slug. Otherwise, omit it — the backlog processor will auto-route it to the right product (or reject it as noise).',
|
package/dist/tools/products.d.ts
CHANGED
|
@@ -9,23 +9,29 @@ export declare const listProductsSchema: z.ZodObject<{
|
|
|
9
9
|
}>;
|
|
10
10
|
export declare const getProductSchema: z.ZodObject<{
|
|
11
11
|
slug: z.ZodString;
|
|
12
|
-
domain: z.ZodOptional<z.ZodEnum<["product-research", "brand", "copy", "advertising", "app-store"]>>;
|
|
12
|
+
domain: z.ZodOptional<z.ZodUnion<[z.ZodEnum<["product-research", "brand", "copy", "advertising", "app-store"]>, z.ZodArray<z.ZodEnum<["product-research", "brand", "copy", "advertising", "app-store"]>, "many">]>>;
|
|
13
13
|
}, "strip", z.ZodTypeAny, {
|
|
14
14
|
slug: string;
|
|
15
|
-
domain?: "product-research" | "brand" | "copy" | "advertising" | "app-store" | undefined;
|
|
15
|
+
domain?: "product-research" | "brand" | "copy" | "advertising" | "app-store" | ("product-research" | "brand" | "copy" | "advertising" | "app-store")[] | undefined;
|
|
16
16
|
}, {
|
|
17
17
|
slug: string;
|
|
18
|
-
domain?: "product-research" | "brand" | "copy" | "advertising" | "app-store" | undefined;
|
|
18
|
+
domain?: "product-research" | "brand" | "copy" | "advertising" | "app-store" | ("product-research" | "brand" | "copy" | "advertising" | "app-store")[] | undefined;
|
|
19
19
|
}>;
|
|
20
20
|
export declare const readProductFileSchema: z.ZodObject<{
|
|
21
21
|
slug: z.ZodString;
|
|
22
22
|
filepath: z.ZodString;
|
|
23
|
+
format: z.ZodOptional<z.ZodEnum<["inline", "signed-url"]>>;
|
|
24
|
+
ttl: z.ZodOptional<z.ZodNumber>;
|
|
23
25
|
}, "strip", z.ZodTypeAny, {
|
|
24
26
|
slug: string;
|
|
25
27
|
filepath: string;
|
|
28
|
+
format?: "inline" | "signed-url" | undefined;
|
|
29
|
+
ttl?: number | undefined;
|
|
26
30
|
}, {
|
|
27
31
|
slug: string;
|
|
28
32
|
filepath: string;
|
|
33
|
+
format?: "inline" | "signed-url" | undefined;
|
|
34
|
+
ttl?: number | undefined;
|
|
29
35
|
}>;
|
|
30
36
|
export declare const updateProductKnowledgeSchema: z.ZodObject<{
|
|
31
37
|
slug: z.ZodString;
|
|
@@ -91,13 +97,13 @@ export declare const pullProductFilesSchema: z.ZodObject<{
|
|
|
91
97
|
}>;
|
|
92
98
|
export declare const getProductIndexSchema: z.ZodObject<{
|
|
93
99
|
slug: z.ZodString;
|
|
94
|
-
domain: z.ZodOptional<z.ZodEnum<["product-research", "brand", "copy", "advertising", "app-store"]>>;
|
|
100
|
+
domain: z.ZodOptional<z.ZodUnion<[z.ZodEnum<["product-research", "brand", "copy", "advertising", "app-store"]>, z.ZodArray<z.ZodEnum<["product-research", "brand", "copy", "advertising", "app-store"]>, "many">]>>;
|
|
95
101
|
}, "strip", z.ZodTypeAny, {
|
|
96
102
|
slug: string;
|
|
97
|
-
domain?: "product-research" | "brand" | "copy" | "advertising" | "app-store" | undefined;
|
|
103
|
+
domain?: "product-research" | "brand" | "copy" | "advertising" | "app-store" | ("product-research" | "brand" | "copy" | "advertising" | "app-store")[] | undefined;
|
|
98
104
|
}, {
|
|
99
105
|
slug: string;
|
|
100
|
-
domain?: "product-research" | "brand" | "copy" | "advertising" | "app-store" | undefined;
|
|
106
|
+
domain?: "product-research" | "brand" | "copy" | "advertising" | "app-store" | ("product-research" | "brand" | "copy" | "advertising" | "app-store")[] | undefined;
|
|
101
107
|
}>;
|
|
102
108
|
export declare const getProductHealthSchema: z.ZodObject<{
|
|
103
109
|
slug: z.ZodOptional<z.ZodString>;
|
|
@@ -136,6 +142,46 @@ export declare const deleteProductFileSchema: z.ZodObject<{
|
|
|
136
142
|
slug: string;
|
|
137
143
|
filepath: string;
|
|
138
144
|
}>;
|
|
145
|
+
export declare const findAssetsSchema: z.ZodObject<{
|
|
146
|
+
slug: z.ZodString;
|
|
147
|
+
query: z.ZodOptional<z.ZodString>;
|
|
148
|
+
asset_type: z.ZodOptional<z.ZodEnum<["logo", "app-icon", "screenshot-ui", "screenshot-marketing", "mockup", "photo-lifestyle", "photo-product", "illustration", "color-swatch", "typography-sample", "brand-guide-page", "video", "animation", "document", "other"]>>;
|
|
149
|
+
surfaces: z.ZodOptional<z.ZodArray<z.ZodEnum<["ad-creative", "app-store", "landing", "email", "social-organic", "brand-guide", "internal-doc"]>, "many">>;
|
|
150
|
+
orientation: z.ZodOptional<z.ZodEnum<["horizontal", "vertical", "square"]>>;
|
|
151
|
+
background: z.ZodOptional<z.ZodEnum<["transparent", "solid-light", "solid-dark", "photographic"]>>;
|
|
152
|
+
color_mode: z.ZodOptional<z.ZodEnum<["light", "dark", "neutral"]>>;
|
|
153
|
+
platform: z.ZodOptional<z.ZodEnum<["ios", "android", "web"]>>;
|
|
154
|
+
locale: z.ZodOptional<z.ZodString>;
|
|
155
|
+
include_drafts: z.ZodOptional<z.ZodBoolean>;
|
|
156
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
157
|
+
ttl: z.ZodOptional<z.ZodNumber>;
|
|
158
|
+
}, "strip", z.ZodTypeAny, {
|
|
159
|
+
slug: string;
|
|
160
|
+
limit?: number | undefined;
|
|
161
|
+
ttl?: number | undefined;
|
|
162
|
+
asset_type?: "logo" | "app-icon" | "screenshot-ui" | "screenshot-marketing" | "mockup" | "photo-lifestyle" | "photo-product" | "illustration" | "color-swatch" | "typography-sample" | "brand-guide-page" | "video" | "animation" | "document" | "other" | undefined;
|
|
163
|
+
surfaces?: ("app-store" | "ad-creative" | "landing" | "email" | "social-organic" | "brand-guide" | "internal-doc")[] | undefined;
|
|
164
|
+
orientation?: "horizontal" | "vertical" | "square" | undefined;
|
|
165
|
+
background?: "transparent" | "solid-light" | "solid-dark" | "photographic" | undefined;
|
|
166
|
+
color_mode?: "light" | "dark" | "neutral" | undefined;
|
|
167
|
+
platform?: "ios" | "android" | "web" | undefined;
|
|
168
|
+
locale?: string | undefined;
|
|
169
|
+
include_drafts?: boolean | undefined;
|
|
170
|
+
query?: string | undefined;
|
|
171
|
+
}, {
|
|
172
|
+
slug: string;
|
|
173
|
+
limit?: number | undefined;
|
|
174
|
+
ttl?: number | undefined;
|
|
175
|
+
asset_type?: "logo" | "app-icon" | "screenshot-ui" | "screenshot-marketing" | "mockup" | "photo-lifestyle" | "photo-product" | "illustration" | "color-swatch" | "typography-sample" | "brand-guide-page" | "video" | "animation" | "document" | "other" | undefined;
|
|
176
|
+
surfaces?: ("app-store" | "ad-creative" | "landing" | "email" | "social-organic" | "brand-guide" | "internal-doc")[] | undefined;
|
|
177
|
+
orientation?: "horizontal" | "vertical" | "square" | undefined;
|
|
178
|
+
background?: "transparent" | "solid-light" | "solid-dark" | "photographic" | undefined;
|
|
179
|
+
color_mode?: "light" | "dark" | "neutral" | undefined;
|
|
180
|
+
platform?: "ios" | "android" | "web" | undefined;
|
|
181
|
+
locale?: string | undefined;
|
|
182
|
+
include_drafts?: boolean | undefined;
|
|
183
|
+
query?: string | undefined;
|
|
184
|
+
}>;
|
|
139
185
|
export declare function createListProductsTool(client: ApiClient): (input: z.infer<typeof listProductsSchema>) => Promise<{
|
|
140
186
|
products: Array<{
|
|
141
187
|
id: string;
|
|
@@ -174,6 +220,12 @@ export declare function createReadProductFileTool(client: ApiClient): (input: z.
|
|
|
174
220
|
content: unknown;
|
|
175
221
|
content_type: string;
|
|
176
222
|
size?: number;
|
|
223
|
+
} | {
|
|
224
|
+
path: string;
|
|
225
|
+
url: string;
|
|
226
|
+
expires_at: string;
|
|
227
|
+
content_type: string;
|
|
228
|
+
size: number;
|
|
177
229
|
}>;
|
|
178
230
|
export declare function createUpdateProductKnowledgeTool(client: ApiClient): (input: z.infer<typeof updateProductKnowledgeSchema>) => Promise<{
|
|
179
231
|
success: boolean;
|
|
@@ -239,3 +291,19 @@ export declare function createDeleteProductTool(client: ApiClient): (input: z.in
|
|
|
239
291
|
export declare function createDeleteProductFileTool(client: ApiClient): (input: z.infer<typeof deleteProductFileSchema>) => Promise<{
|
|
240
292
|
success: boolean;
|
|
241
293
|
}>;
|
|
294
|
+
export declare function createFindAssetsTool(client: ApiClient): (input: z.infer<typeof findAssetsSchema>) => Promise<{
|
|
295
|
+
query: string | null;
|
|
296
|
+
filters: Record<string, unknown>;
|
|
297
|
+
total_inventory: number;
|
|
298
|
+
matched: number;
|
|
299
|
+
results: Array<{
|
|
300
|
+
path: string;
|
|
301
|
+
score: number;
|
|
302
|
+
matched_terms: string[];
|
|
303
|
+
content_type: string;
|
|
304
|
+
size: number;
|
|
305
|
+
entry: Record<string, unknown>;
|
|
306
|
+
url: string;
|
|
307
|
+
expires_at: string;
|
|
308
|
+
}>;
|
|
309
|
+
}>;
|
package/dist/tools/products.js
CHANGED
|
@@ -9,11 +9,25 @@ export const listProductsSchema = z.object({
|
|
|
9
9
|
});
|
|
10
10
|
export const getProductSchema = z.object({
|
|
11
11
|
slug: z.string().describe('Product slug'),
|
|
12
|
-
domain: z
|
|
12
|
+
domain: z
|
|
13
|
+
.union([z.enum(DOMAIN_VALUES), z.array(z.enum(DOMAIN_VALUES))])
|
|
14
|
+
.optional()
|
|
15
|
+
.describe('Filter files by domain. Pass a single domain ("brand") or an array (["brand", "advertising"]) to combine domains in one request — useful for creative pipelines that need brand assets plus advertising references without round-tripping operational config.'),
|
|
13
16
|
});
|
|
14
17
|
export const readProductFileSchema = z.object({
|
|
15
18
|
slug: z.string().describe('Product slug'),
|
|
16
19
|
filepath: z.string().describe('File path within the product (e.g., "docs/research/user-research.md", "meta-ads.json", "brand-assets/logo.png")'),
|
|
20
|
+
format: z
|
|
21
|
+
.enum(['inline', 'signed-url'])
|
|
22
|
+
.optional()
|
|
23
|
+
.describe('Response format. "inline" (default) returns the file content (text or base64 data URI for binary). "signed-url" returns a short-lived download URL — strongly preferred for binaries (logos, screenshots, PDFs) since base64 inflates LLM context by ~33%. Fetch with `curl -o <path> <url>`.'),
|
|
24
|
+
ttl: z
|
|
25
|
+
.number()
|
|
26
|
+
.int()
|
|
27
|
+
.positive()
|
|
28
|
+
.max(3600)
|
|
29
|
+
.optional()
|
|
30
|
+
.describe('Lifetime in seconds for the signed URL (default 600, max 3600). Ignored unless format="signed-url".'),
|
|
17
31
|
});
|
|
18
32
|
export const updateProductKnowledgeSchema = z.object({
|
|
19
33
|
slug: z.string().describe('Product slug'),
|
|
@@ -43,7 +57,10 @@ export const pullProductFilesSchema = z.object({
|
|
|
43
57
|
});
|
|
44
58
|
export const getProductIndexSchema = z.object({
|
|
45
59
|
slug: z.string().describe('Product slug'),
|
|
46
|
-
domain: z
|
|
60
|
+
domain: z
|
|
61
|
+
.union([z.enum(DOMAIN_VALUES), z.array(z.enum(DOMAIN_VALUES))])
|
|
62
|
+
.optional()
|
|
63
|
+
.describe('Filter index entries by domain. Pass a single domain or array of domains.'),
|
|
47
64
|
});
|
|
48
65
|
export const getProductHealthSchema = z.object({
|
|
49
66
|
slug: z.string().optional().describe('Product slug. If omitted, returns health for all products.'),
|
|
@@ -60,6 +77,31 @@ export const deleteProductFileSchema = z.object({
|
|
|
60
77
|
slug: z.string().describe('Product slug'),
|
|
61
78
|
filepath: z.string().describe('File path within the product to delete (e.g., "docs/copy/old-brief.md", "brand-assets/old-logo.png")'),
|
|
62
79
|
});
|
|
80
|
+
const ASSET_TYPE_VALUES = [
|
|
81
|
+
'logo', 'app-icon', 'screenshot-ui', 'screenshot-marketing', 'mockup',
|
|
82
|
+
'photo-lifestyle', 'photo-product', 'illustration', 'color-swatch',
|
|
83
|
+
'typography-sample', 'brand-guide-page', 'video', 'animation', 'document', 'other',
|
|
84
|
+
];
|
|
85
|
+
const SURFACE_VALUES = [
|
|
86
|
+
'ad-creative', 'app-store', 'landing', 'email', 'social-organic', 'brand-guide', 'internal-doc',
|
|
87
|
+
];
|
|
88
|
+
export const findAssetsSchema = z.object({
|
|
89
|
+
slug: z.string().describe('Product slug'),
|
|
90
|
+
query: z
|
|
91
|
+
.string()
|
|
92
|
+
.optional()
|
|
93
|
+
.describe('Free-text query — matched against asset description, usage notes, file path, asset_type, and surfaces. Use this for "what" you want ("phone illustration", "horizontal wordmark", "iOS launch icon"). Combine with structured filters for "where" the asset belongs.'),
|
|
94
|
+
asset_type: z.enum(ASSET_TYPE_VALUES).optional().describe('Restrict to one asset_type.'),
|
|
95
|
+
surfaces: z.array(z.enum(SURFACE_VALUES)).optional().describe('ANY-of match against the entry\'s surfaces array. e.g. ["ad-creative","landing"] returns assets used on either.'),
|
|
96
|
+
orientation: z.enum(['horizontal', 'vertical', 'square']).optional().describe('Filter by orientation variant.'),
|
|
97
|
+
background: z.enum(['transparent', 'solid-light', 'solid-dark', 'photographic']).optional().describe('Filter by background variant.'),
|
|
98
|
+
color_mode: z.enum(['light', 'dark', 'neutral']).optional().describe('Filter by color_mode variant.'),
|
|
99
|
+
platform: z.enum(['ios', 'android', 'web']).optional().describe('Filter by platform variant.'),
|
|
100
|
+
locale: z.string().optional().describe('Filter by exact locale string (BCP-47, e.g. "en-US").'),
|
|
101
|
+
include_drafts: z.boolean().optional().describe('Include auto-described draft entries (unverified by a curator). Default true. Drafts are real entries with descriptions; the flag is a confidence marker.'),
|
|
102
|
+
limit: z.number().int().positive().max(100).optional().describe('Maximum number of results. Default 20, max 100.'),
|
|
103
|
+
ttl: z.number().int().positive().max(3600).optional().describe('Lifetime in seconds for the signed download URLs returned with each result. Default 600, max 3600.'),
|
|
104
|
+
});
|
|
63
105
|
// --- Tool factories ---
|
|
64
106
|
export function createListProductsTool(client) {
|
|
65
107
|
return async (input) => {
|
|
@@ -75,7 +117,10 @@ export function createGetProductTool(client) {
|
|
|
75
117
|
}
|
|
76
118
|
export function createReadProductFileTool(client) {
|
|
77
119
|
return async (input) => {
|
|
78
|
-
const result = await client.getProductFile(input.slug, input.filepath
|
|
120
|
+
const result = await client.getProductFile(input.slug, input.filepath, {
|
|
121
|
+
format: input.format,
|
|
122
|
+
ttl: input.ttl,
|
|
123
|
+
});
|
|
79
124
|
return result;
|
|
80
125
|
};
|
|
81
126
|
}
|
|
@@ -173,3 +218,20 @@ export function createDeleteProductFileTool(client) {
|
|
|
173
218
|
return client.deleteProductFile(input.slug, input.filepath);
|
|
174
219
|
};
|
|
175
220
|
}
|
|
221
|
+
export function createFindAssetsTool(client) {
|
|
222
|
+
return async (input) => {
|
|
223
|
+
return client.findAssets(input.slug, {
|
|
224
|
+
query: input.query,
|
|
225
|
+
asset_type: input.asset_type,
|
|
226
|
+
surfaces: input.surfaces,
|
|
227
|
+
orientation: input.orientation,
|
|
228
|
+
background: input.background,
|
|
229
|
+
color_mode: input.color_mode,
|
|
230
|
+
platform: input.platform,
|
|
231
|
+
locale: input.locale,
|
|
232
|
+
include_drafts: input.include_drafts,
|
|
233
|
+
limit: input.limit,
|
|
234
|
+
ttl: input.ttl,
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
}
|
|
@@ -9,16 +9,16 @@ export declare const uploadProductDirectorySchema: z.ZodObject<{
|
|
|
9
9
|
exclude: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
10
10
|
dry_run: z.ZodOptional<z.ZodBoolean>;
|
|
11
11
|
}, "strip", z.ZodTypeAny, {
|
|
12
|
-
slug: string;
|
|
13
12
|
domain: "product-research" | "brand" | "copy" | "advertising" | "app-store";
|
|
13
|
+
slug: string;
|
|
14
14
|
local_dir: string;
|
|
15
15
|
dry_run?: boolean | undefined;
|
|
16
16
|
dest_prefix?: string | undefined;
|
|
17
17
|
glob?: string | undefined;
|
|
18
18
|
exclude?: string[] | undefined;
|
|
19
19
|
}, {
|
|
20
|
-
slug: string;
|
|
21
20
|
domain: "product-research" | "brand" | "copy" | "advertising" | "app-store";
|
|
21
|
+
slug: string;
|
|
22
22
|
local_dir: string;
|
|
23
23
|
dry_run?: boolean | undefined;
|
|
24
24
|
dest_prefix?: string | undefined;
|