openclaw-productboard 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.
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ /**
3
+ * ProductBoard Product Management Tools
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createProductTools = createProductTools;
7
+ function createProductTools(client) {
8
+ return [
9
+ // pb_product_list
10
+ {
11
+ name: 'pb_product_list',
12
+ description: 'List all products in the ProductBoard workspace. Products are top-level containers for organizing features.',
13
+ parameters: {
14
+ type: 'object',
15
+ properties: {
16
+ limit: {
17
+ type: 'number',
18
+ description: 'Maximum number of products to return (default: 50)',
19
+ default: 50,
20
+ },
21
+ },
22
+ },
23
+ handler: async (params) => {
24
+ const products = await client.listProducts({
25
+ limit: params.limit || 50,
26
+ });
27
+ return {
28
+ count: products.length,
29
+ products: products.map((p) => ({
30
+ id: p.id,
31
+ name: p.name,
32
+ description: p.description?.substring(0, 200),
33
+ createdAt: p.createdAt,
34
+ url: p.links?.html,
35
+ })),
36
+ };
37
+ },
38
+ },
39
+ // pb_product_get
40
+ {
41
+ name: 'pb_product_get',
42
+ description: 'Get detailed information about a specific product by ID, including its components.',
43
+ parameters: {
44
+ type: 'object',
45
+ properties: {
46
+ id: {
47
+ type: 'string',
48
+ description: 'Product ID',
49
+ },
50
+ includeComponents: {
51
+ type: 'boolean',
52
+ description: 'Include the list of components under this product',
53
+ default: true,
54
+ },
55
+ },
56
+ required: ['id'],
57
+ },
58
+ handler: async (params) => {
59
+ const product = await client.getProduct(params.id);
60
+ const result = {
61
+ id: product.id,
62
+ name: product.name,
63
+ description: product.description,
64
+ createdAt: product.createdAt,
65
+ updatedAt: product.updatedAt,
66
+ url: product.links?.html,
67
+ };
68
+ // Optionally include components
69
+ if (params.includeComponents !== false) {
70
+ const components = await client.listComponents({
71
+ productId: product.id,
72
+ limit: 100,
73
+ });
74
+ result.components = components.map((c) => ({
75
+ id: c.id,
76
+ name: c.name,
77
+ description: c.description?.substring(0, 200),
78
+ }));
79
+ result.componentCount = components.length;
80
+ }
81
+ return result;
82
+ },
83
+ },
84
+ // pb_product_hierarchy
85
+ {
86
+ name: 'pb_product_hierarchy',
87
+ description: 'Get the complete product hierarchy including all products and their components. Useful for understanding the workspace structure.',
88
+ parameters: {
89
+ type: 'object',
90
+ properties: {},
91
+ },
92
+ handler: async () => {
93
+ const hierarchy = await client.getProductHierarchy();
94
+ // Build tree structure
95
+ const productMap = new Map();
96
+ // Initialize products
97
+ for (const product of hierarchy.products) {
98
+ productMap.set(product.id, {
99
+ id: product.id,
100
+ name: product.name,
101
+ description: product.description?.substring(0, 200),
102
+ components: [],
103
+ });
104
+ }
105
+ // Build component tree (components can be nested)
106
+ const componentMap = new Map();
107
+ for (const component of hierarchy.components) {
108
+ componentMap.set(component.id, {
109
+ ...component,
110
+ subcomponents: [],
111
+ });
112
+ }
113
+ // Assign components to parents
114
+ for (const component of hierarchy.components) {
115
+ const comp = componentMap.get(component.id);
116
+ if (component.parent?.product?.id) {
117
+ // Top-level component under a product
118
+ const product = productMap.get(component.parent.product.id);
119
+ if (product) {
120
+ product.components.push({
121
+ id: comp.id,
122
+ name: comp.name,
123
+ description: comp.description?.substring(0, 200),
124
+ subcomponents: comp.subcomponents,
125
+ });
126
+ }
127
+ }
128
+ else if (component.parent?.component?.id) {
129
+ // Nested component
130
+ const parent = componentMap.get(component.parent.component.id);
131
+ if (parent) {
132
+ parent.subcomponents.push({
133
+ id: comp.id,
134
+ name: comp.name,
135
+ });
136
+ }
137
+ }
138
+ }
139
+ return {
140
+ productCount: hierarchy.products.length,
141
+ componentCount: hierarchy.components.length,
142
+ hierarchy: Array.from(productMap.values()),
143
+ };
144
+ },
145
+ },
146
+ ];
147
+ }
148
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvZHVjdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdG9vbHMvcHJvZHVjdHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOztHQUVHOztBQUtILGdEQW9LQztBQXBLRCxTQUFnQixrQkFBa0IsQ0FBQyxNQUEwQjtJQUMzRCxPQUFPO1FBQ0wsa0JBQWtCO1FBQ2xCO1lBQ0UsSUFBSSxFQUFFLGlCQUFpQjtZQUN2QixXQUFXLEVBQ1QsNkdBQTZHO1lBQy9HLFVBQVUsRUFBRTtnQkFDVixJQUFJLEVBQUUsUUFBUTtnQkFDZCxVQUFVLEVBQUU7b0JBQ1YsS0FBSyxFQUFFO3dCQUNMLElBQUksRUFBRSxRQUFRO3dCQUNkLFdBQVcsRUFBRSxvREFBb0Q7d0JBQ2pFLE9BQU8sRUFBRSxFQUFFO3FCQUNaO2lCQUNGO2FBQ0Y7WUFDRCxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxFQUFFO2dCQUN4QixNQUFNLFFBQVEsR0FBRyxNQUFNLE1BQU0sQ0FBQyxZQUFZLENBQUM7b0JBQ3pDLEtBQUssRUFBRSxNQUFNLENBQUMsS0FBZSxJQUFJLEVBQUU7aUJBQ3BDLENBQUMsQ0FBQztnQkFDSCxPQUFPO29CQUNMLEtBQUssRUFBRSxRQUFRLENBQUMsTUFBTTtvQkFDdEIsUUFBUSxFQUFFLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7d0JBQzdCLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRTt3QkFDUixJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUk7d0JBQ1osV0FBVyxFQUFFLENBQUMsQ0FBQyxXQUFXLEVBQUUsU0FBUyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUM7d0JBQzdDLFNBQVMsRUFBRSxDQUFDLENBQUMsU0FBUzt3QkFDdEIsR0FBRyxFQUFFLENBQUMsQ0FBQyxLQUFLLEVBQUUsSUFBSTtxQkFDbkIsQ0FBQyxDQUFDO2lCQUNKLENBQUM7WUFDSixDQUFDO1NBQ0Y7UUFF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QUMsSUFBSSxDQUFDO2dDQUN4QixFQUFFLEVBQUUsSUFBSSxDQUFDLEVBQUU7Z0NBQ1gsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJOzZCQUNoQixDQUFDLENBQUM7d0JBQ0wsQ0FBQztvQkFDSCxDQUFDO2dCQUNILENBQUM7Z0JBRUQsT0FBTztvQkFDTCxZQUFZLEVBQUUsU0FBUyxDQUFDLFFBQVEsQ0FBQyxNQUFNO29CQUN2QyxjQUFjLEVBQUUsU0FBUyxDQUFDLFVBQVUsQ0FBQyxNQUFNO29CQUMzQyxTQUFTLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLENBQUM7aUJBQzNDLENBQUM7WUFDSixDQUFDO1NBQ0Y7S0FDRixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUHJvZHVjdEJvYXJkIFByb2R1Y3QgTWFuYWdlbWVudCBUb29sc1xuICovXG5cbmltcG9ydCB7IFByb2R1Y3RCb2FyZENsaWVudCB9IGZyb20gJy4uL2NsaWVudC9hcGktY2xpZW50JztcbmltcG9ydCB7IFRvb2xEZWZpbml0aW9uIH0gZnJvbSAnLi4vY2xpZW50L3R5cGVzJztcblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVByb2R1Y3RUb29scyhjbGllbnQ6IFByb2R1Y3RCb2FyZENsaWVudCk6IFRvb2xEZWZpbml0aW9uW10ge1xuICByZXR1cm4gW1xuICAgIC8vIHBiX3Byb2R1Y3RfbGlzdFxuICAgIHtcbiAgICAgIG5hbWU6ICdwYl9wcm9kdWN0X2xpc3QnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdMaXN0IGFsbCBwcm9kdWN0cyBpbiB0aGUgUHJvZHVjdEJvYXJkIHdvcmtzcGFjZS4gUHJvZHVjdHMgYXJlIHRvcC1sZXZlbCBjb250YWluZXJzIGZvciBvcmdhbml6aW5nIGZlYXR1cmVzLicsXG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIHR5cGU6ICdvYmplY3QnLFxuICAgICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgbGltaXQ6IHtcbiAgICAgICAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgICAgICAgZGVzY3JpcHRpb246ICdNYXhpbXVtIG51bWJlciBvZiBwcm9kdWN0cyB0byByZXR1cm4gKGRlZmF1bHQ6IDUwKScsXG4gICAgICAgICAgICBkZWZhdWx0OiA1MCxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICAgIGhhbmRsZXI6IGFzeW5jIChwYXJhbXMpID0+IHtcbiAgICAgICAgY29uc3QgcHJvZHVjdHMgPSBhd2FpdCBjbGllbnQubGlzdFByb2R1Y3RzKHtcbiAgICAgICAgICBsaW1pdDogcGFyYW1zLmxpbWl0IGFzIG51bWJlciB8fCA1MCxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgY291bnQ6IHByb2R1Y3RzLmxlbmd0aCxcbiAgICAgICAgICBwcm9kdWN0czogcHJvZHVjdHMubWFwKChwKSA9PiAoe1xuICAgICAgICAgICAgaWQ6IHAuaWQsXG4gICAgICAgICAgICBuYW1lOiBwLm5hbWUsXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogcC5kZXNjcmlwdGlvbj8uc3Vic3RyaW5nKDAsIDIwMCksXG4gICAgICAgICAgICBjcmVhdGVkQXQ6IHAuY3JlYXRlZEF0LFxuICAgICAgICAgICAgdXJsOiBwLmxpbmtzPy5odG1sLFxuICAgICAgICAgIH0pKSxcbiAgICAgICAgfTtcbiAgICAgIH0sXG4gICAgfSxcblxuICAgIC8vIHBiX3Byb2R1Y3RfZ2V0XG4gICAge1xuICAgICAgbmFtZTogJ3BiX3Byb2R1Y3RfZ2V0JyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnR2V0IGRldGFpbGVkIGluZm9ybWF0aW9uIGFib3V0IGEgc3BlY2lmaWMgcHJvZHVjdCBieSBJRCwgaW5jbHVkaW5nIGl0cyBjb21wb25lbnRzLicsXG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIHR5cGU6ICdvYmplY3QnLFxuICAgICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgaWQ6IHtcbiAgICAgICAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgICAgICAgZGVzY3JpcHRpb246ICdQcm9kdWN0IElEJyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGluY2x1ZGVDb21wb25lbnRzOiB7XG4gICAgICAgICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogJ0luY2x1ZGUgdGhlIGxpc3Qgb2YgY29tcG9uZW50cyB1bmRlciB0aGlzIHByb2R1Y3QnLFxuICAgICAgICAgICAgZGVmYXVsdDogdHJ1ZSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICByZXF1aXJlZDogWydpZCddLFxuICAgICAgfSxcbiAgICAgIGhhbmRsZXI6IGFzeW5jIChwYXJhbXMpID0+IHtcbiAgICAgICAgY29uc3QgcHJvZHVjdCA9IGF3YWl0IGNsaWVudC5nZXRQcm9kdWN0KHBhcmFtcy5pZCBhcyBzdHJpbmcpO1xuXG4gICAgICAgIGNvbnN0IHJlc3VsdDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7XG4gICAgICAgICAgaWQ6IHByb2R1Y3QuaWQsXG4gICAgICAgICAgbmFtZTogcHJvZHVjdC5uYW1lLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBwcm9kdWN0LmRlc2NyaXB0aW9uLFxuICAgICAgICAgIGNyZWF0ZWRBdDogcHJvZHVjdC5jcmVhdGVkQXQsXG4gICAgICAgICAgdXBkYXRlZEF0OiBwcm9kdWN0LnVwZGF0ZWRBdCxcbiAgICAgICAgICB1cmw6IHByb2R1Y3QubGlua3M/Lmh0bWwsXG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gT3B0aW9uYWxseSBpbmNsdWRlIGNvbXBvbmVudHNcbiAgICAgICAgaWYgKHBhcmFtcy5pbmNsdWRlQ29tcG9uZW50cyAhPT0gZmFsc2UpIHtcbiAgICAgICAgICBjb25zdCBjb21wb25lbnRzID0gYXdhaXQgY2xpZW50Lmxpc3RDb21wb25lbnRzKHtcbiAgICAgICAgICAgIHByb2R1Y3RJZDogcHJvZHVjdC5pZCxcbiAgICAgICAgICAgIGxpbWl0OiAxMDAsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmVzdWx0LmNvbXBvbmVudHMgPSBjb21wb25lbnRzLm1hcCgoYykgPT4gKHtcbiAgICAgICAgICAgIGlkOiBjLmlkLFxuICAgICAgICAgICAgbmFtZTogYy5uYW1lLFxuICAgICAgICAgICAgZGVzY3JpcHRpb246IGMuZGVzY3JpcHRpb24/LnN1YnN0cmluZygwLCAyMDApLFxuICAgICAgICAgIH0pKTtcbiAgICAgICAgICByZXN1bHQuY29tcG9uZW50Q291bnQgPSBjb21wb25lbnRzLmxlbmd0aDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICB9LFxuICAgIH0sXG5cbiAgICAvLyBwYl9wcm9kdWN0X2hpZXJhcmNoeVxuICAgIHtcbiAgICAgIG5hbWU6ICdwYl9wcm9kdWN0X2hpZXJhcmNoeScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0dldCB0aGUgY29tcGxldGUgcHJvZHVjdCBoaWVyYXJjaHkgaW5jbHVkaW5nIGFsbCBwcm9kdWN0cyBhbmQgdGhlaXIgY29tcG9uZW50cy4gVXNlZnVsIGZvciB1bmRlcnN0YW5kaW5nIHRoZSB3b3Jrc3BhY2Ugc3RydWN0dXJlLicsXG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIHR5cGU6ICdvYmplY3QnLFxuICAgICAgICBwcm9wZXJ0aWVzOiB7fSxcbiAgICAgIH0sXG4gICAgICBoYW5kbGVyOiBhc3luYyAoKSA9PiB7XG4gICAgICAgIGNvbnN0IGhpZXJhcmNoeSA9IGF3YWl0IGNsaWVudC5nZXRQcm9kdWN0SGllcmFyY2h5KCk7XG5cbiAgICAgICAgLy8gQnVpbGQgdHJlZSBzdHJ1Y3R1cmVcbiAgICAgICAgY29uc3QgcHJvZHVjdE1hcCA9IG5ldyBNYXA8c3RyaW5nLCB7XG4gICAgICAgICAgaWQ6IHN0cmluZztcbiAgICAgICAgICBuYW1lOiBzdHJpbmc7XG4gICAgICAgICAgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG4gICAgICAgICAgY29tcG9uZW50czogQXJyYXk8e1xuICAgICAgICAgICAgaWQ6IHN0cmluZztcbiAgICAgICAgICAgIG5hbWU6IHN0cmluZztcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuICAgICAgICAgICAgc3ViY29tcG9uZW50czogQXJyYXk8eyBpZDogc3RyaW5nOyBuYW1lOiBzdHJpbmcgfT47XG4gICAgICAgICAgfT47XG4gICAgICAgIH0+KCk7XG5cbiAgICAgICAgLy8gSW5pdGlhbGl6ZSBwcm9kdWN0c1xuICAgICAgICBmb3IgKGNvbnN0IHByb2R1Y3Qgb2YgaGllcmFyY2h5LnByb2R1Y3RzKSB7XG4gICAgICAgICAgcHJvZHVjdE1hcC5zZXQocHJvZHVjdC5pZCwge1xuICAgICAgICAgICAgaWQ6IHByb2R1Y3QuaWQsXG4gICAgICAgICAgICBuYW1lOiBwcm9kdWN0Lm5hbWUsXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogcHJvZHVjdC5kZXNjcmlwdGlvbj8uc3Vic3RyaW5nKDAsIDIwMCksXG4gICAgICAgICAgICBjb21wb25lbnRzOiBbXSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEJ1aWxkIGNvbXBvbmVudCB0cmVlIChjb21wb25lbnRzIGNhbiBiZSBuZXN0ZWQpXG4gICAgICAgIGNvbnN0IGNvbXBvbmVudE1hcCA9IG5ldyBNYXA8c3RyaW5nLCB0eXBlb2YgaGllcmFyY2h5LmNvbXBvbmVudHNbMF0gJiB7IHN1YmNvbXBvbmVudHM6IEFycmF5PHsgaWQ6IHN0cmluZzsgbmFtZTogc3RyaW5nIH0+IH0+KCk7XG5cbiAgICAgICAgZm9yIChjb25zdCBjb21wb25lbnQgb2YgaGllcmFyY2h5LmNvbXBvbmVudHMpIHtcbiAgICAgICAgICBjb21wb25lbnRNYXAuc2V0KGNvbXBvbmVudC5pZCwge1xuICAgICAgICAgICAgLi4uY29tcG9uZW50LFxuICAgICAgICAgICAgc3ViY29tcG9uZW50czogW10sXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBc3NpZ24gY29tcG9uZW50cyB0byBwYXJlbnRzXG4gICAgICAgIGZvciAoY29uc3QgY29tcG9uZW50IG9mIGhpZXJhcmNoeS5jb21wb25lbnRzKSB7XG4gICAgICAgICAgY29uc3QgY29tcCA9IGNvbXBvbmVudE1hcC5nZXQoY29tcG9uZW50LmlkKSE7XG5cbiAgICAgICAgICBpZiAoY29tcG9uZW50LnBhcmVudD8ucHJvZHVjdD8uaWQpIHtcbiAgICAgICAgICAgIC8vIFRvcC1sZXZlbCBjb21wb25lbnQgdW5kZXIgYSBwcm9kdWN0XG4gICAgICAgICAgICBjb25zdCBwcm9kdWN0ID0gcHJvZHVjdE1hcC5nZXQoY29tcG9uZW50LnBhcmVudC5wcm9kdWN0LmlkKTtcbiAgICAgICAgICAgIGlmIChwcm9kdWN0KSB7XG4gICAgICAgICAgICAgIHByb2R1Y3QuY29tcG9uZW50cy5wdXNoKHtcbiAgICAgICAgICAgICAgICBpZDogY29tcC5pZCxcbiAgICAgICAgICAgICAgICBuYW1lOiBjb21wLm5hbWUsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IGNvbXAuZGVzY3JpcHRpb24/LnN1YnN0cmluZygwLCAyMDApLFxuICAgICAgICAgICAgICAgIHN1YmNvbXBvbmVudHM6IGNvbXAuc3ViY29tcG9uZW50cyxcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmIChjb21wb25lbnQucGFyZW50Py5jb21wb25lbnQ/LmlkKSB7XG4gICAgICAgICAgICAvLyBOZXN0ZWQgY29tcG9uZW50XG4gICAgICAgICAgICBjb25zdCBwYXJlbnQgPSBjb21wb25lbnRNYXAuZ2V0KGNvbXBvbmVudC5wYXJlbnQuY29tcG9uZW50LmlkKTtcbiAgICAgICAgICAgIGlmIChwYXJlbnQpIHtcbiAgICAgICAgICAgICAgcGFyZW50LnN1YmNvbXBvbmVudHMucHVzaCh7XG4gICAgICAgICAgICAgICAgaWQ6IGNvbXAuaWQsXG4gICAgICAgICAgICAgICAgbmFtZTogY29tcC5uYW1lLFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHByb2R1Y3RDb3VudDogaGllcmFyY2h5LnByb2R1Y3RzLmxlbmd0aCxcbiAgICAgICAgICBjb21wb25lbnRDb3VudDogaGllcmFyY2h5LmNvbXBvbmVudHMubGVuZ3RoLFxuICAgICAgICAgIGhpZXJhcmNoeTogQXJyYXkuZnJvbShwcm9kdWN0TWFwLnZhbHVlcygpKSxcbiAgICAgICAgfTtcbiAgICAgIH0sXG4gICAgfSxcbiAgXTtcbn1cbiJdfQ==
@@ -0,0 +1,6 @@
1
+ /**
2
+ * ProductBoard Search and User Tools
3
+ */
4
+ import { ProductBoardClient } from '../client/api-client';
5
+ import { ToolDefinition } from '../client/types';
6
+ export declare function createSearchTools(client: ProductBoardClient): ToolDefinition[];
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ /**
3
+ * ProductBoard Search and User Tools
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createSearchTools = createSearchTools;
7
+ function createSearchTools(client) {
8
+ return [
9
+ // pb_search
10
+ {
11
+ name: 'pb_search',
12
+ description: 'Global search across ProductBoard. Searches features, products, components, and notes by name, title, or content.',
13
+ parameters: {
14
+ type: 'object',
15
+ properties: {
16
+ query: {
17
+ type: 'string',
18
+ description: 'Search query text',
19
+ },
20
+ type: {
21
+ type: 'string',
22
+ description: 'Limit search to specific type',
23
+ enum: ['feature', 'product', 'component', 'note'],
24
+ },
25
+ limit: {
26
+ type: 'number',
27
+ description: 'Maximum results to return (default: 25)',
28
+ default: 25,
29
+ },
30
+ },
31
+ required: ['query'],
32
+ },
33
+ handler: async (params) => {
34
+ const searchParams = {
35
+ query: params.query,
36
+ type: params.type,
37
+ limit: params.limit || 25,
38
+ };
39
+ const results = await client.search(searchParams);
40
+ // Group results by type
41
+ const grouped = {
42
+ features: [],
43
+ products: [],
44
+ components: [],
45
+ notes: [],
46
+ };
47
+ for (const result of results) {
48
+ const key = result.type + 's';
49
+ if (grouped[key]) {
50
+ grouped[key].push({
51
+ id: result.id,
52
+ name: result.name || result.title,
53
+ description: result.description || result.content,
54
+ url: result.links?.html,
55
+ });
56
+ }
57
+ }
58
+ return {
59
+ totalCount: results.length,
60
+ query: params.query,
61
+ results: grouped,
62
+ };
63
+ },
64
+ },
65
+ // pb_user_current
66
+ {
67
+ name: 'pb_user_current',
68
+ description: 'Get information about the currently authenticated user, including workspace details.',
69
+ parameters: {
70
+ type: 'object',
71
+ properties: {},
72
+ },
73
+ handler: async () => {
74
+ const user = await client.getCurrentUser();
75
+ return {
76
+ id: user.id,
77
+ email: user.email,
78
+ name: user.name,
79
+ role: user.role,
80
+ workspaceId: user.workspaceId,
81
+ workspaceName: user.workspaceName,
82
+ };
83
+ },
84
+ },
85
+ // pb_user_list
86
+ {
87
+ name: 'pb_user_list',
88
+ description: 'List all users in the ProductBoard workspace. Useful for finding user IDs for assigning features.',
89
+ parameters: {
90
+ type: 'object',
91
+ properties: {
92
+ limit: {
93
+ type: 'number',
94
+ description: 'Maximum number of users to return (default: 100)',
95
+ default: 100,
96
+ },
97
+ },
98
+ },
99
+ handler: async (params) => {
100
+ const users = await client.listUsers({
101
+ limit: params.limit || 100,
102
+ });
103
+ return {
104
+ count: users.length,
105
+ users: users.map((u) => ({
106
+ id: u.id,
107
+ email: u.email,
108
+ name: u.name,
109
+ role: u.role,
110
+ })),
111
+ };
112
+ },
113
+ },
114
+ ];
115
+ }
116
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VhcmNoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rvb2xzL3NlYXJjaC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7O0dBRUc7O0FBS0gsOENBcUhDO0FBckhELFNBQWdCLGlCQUFpQixDQUFDLE1BQTBCO0lBQzFELE9BQU87UUFDTCxZQUFZO1FBQ1o7WUFDRSxJQUFJLEVBQUUsV0FBVztZQUNqQixXQUFXLEVBQ1QsbUhBQW1IO1lBQ3JILFVBQVUsRUFBRTtnQkFDVixJQUFJLEVBQUUsUUFBUTtnQkFDZCxVQUFVLEVBQUU7b0JBQ1YsS0FBSyxFQUFFO3dCQUNMLElBQUksRUFBRSxRQUFRO3dCQUNkLFdBQVcsRUFBRSxtQkFBbUI7cUJBQ2pDO29CQUNELElBQUksRUFBRTt3QkFDSixJQUFJLEVBQUUsUUFBUTt3QkFDZCxXQUFXLEVBQUUsK0JBQStCO3dCQUM1QyxJQUFJLEVBQUUsQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxNQUFNLENBQUM7cUJBQ2xEO29CQUNELEtBQUssRUFBRTt3QkFDTCxJQUFJLEVBQUUsUUFBUTt3QkFDZCxXQUFXLEVBQUUseUNBQXlDO3dCQUN0RCxPQUFPLEVBQUUsRUFBRTtxQkFDWjtpQkFDRjtnQkFDRCxRQUFRLEVBQUUsQ0FBQyxPQUFPLENBQUM7YUFDcEI7WUFDRCxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxFQUFFO2dCQUN4QixNQUFNLFlBQVksR0FBaUI7b0JBQ2pDLEtBQUssRUFBRSxNQUFNLENBQUMsS0FBZTtvQkFDN0IsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFnRTtvQkFDN0UsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFlLElBQUksRUFBRTtpQkFDcEMsQ0FBQztnQkFFRixNQUFNLE9BQU8sR0FBRyxNQUFNLE1BQU0sQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUM7Z0JBRWxELHdCQUF3QjtnQkFDeEIsTUFBTSxPQUFPLEdBQThCO29CQUN6QyxRQUFRLEVBQUUsRUFBRTtvQkFDWixRQUFRLEVBQUUsRUFBRTtvQkFDWixVQUFVLEVBQUUsRUFBRTtvQkFDZCxLQUFLLEVBQUUsRUFBRTtpQkFDVixDQUFDO2dCQUVGLEtBQUssTUFBTSxNQUFNLElBQUksT0FBTyxFQUFFLENBQUM7b0JBQzdCLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxJQUFJLEdBQUcsR0FBRyxDQUFDO29CQUM5QixJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO3dCQUNqQixPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDOzRCQUNoQixFQUFFLEVBQUUsTUFBTSxDQUFDLEVBQUU7NEJBQ2IsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLElBQUksTUFBTSxDQUFDLEtBQUs7NEJBQ2pDLFdBQVcsRUFBRSxNQUFNLENBQUMsV0FBVyxJQUFJLE1BQU0sQ0FBQyxPQUFPOzRCQUNqRCxHQUFHLEVBQUUsTUFBTSxDQUFDLEtBQUssRUFBRSxJQUFJO3lCQUN4QixDQUFDLENBQUM7b0JBQ0wsQ0FBQztnQkFDSCxDQUFDO2dCQUVELE9BQU87b0JBQ0wsVUFBVSxFQUFFLE9BQU8sQ0FBQyxNQUFNO29CQUMxQixLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQUs7b0JBQ25CLE9BQU8sRUFBRSxPQUFPO2lCQUNqQixDQUFDO1lBQ0osQ0FBQztTQUNGO1FBRUQsa0JBQWtCO1FBQ2xCO1lBQ0UsSUFBSSxFQUFFLGlCQUFpQjtZQUN2QixXQUFXLEVBQ1Qsc0ZBQXNGO1lBQ3hGLFVBQVUsRUFBRTtnQkFDVixJQUFJLEVBQUUsUUFBUTtnQkFDZCxVQUFVLEVBQUUsRUFBRTthQUNmO1lBQ0QsT0FBTyxFQUFFLEtBQUssSUFBSSxFQUFFO2dCQUNsQixNQUFNLElBQUksR0FBRyxNQUFNLE1BQU0sQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDM0MsT0FBTztvQkFDTCxFQUFFLEVBQUUsSUFBSSxDQUFDLEVBQUU7b0JBQ1gsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLO29CQUNqQixJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUk7b0JBQ2YsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJO29CQUNmLFdBQVcsRUFBRSxJQUFJLENBQUMsV0FBVztvQkFDN0IsYUFBYSxFQUFFLElBQUksQ0FBQyxhQUFhO2lCQUNsQyxDQUFDO1lBQ0osQ0FBQztTQUNGO1FBRUQsZUFBZTtRQUNmO1lBQ0UsSUFBSSxFQUFFLGNBQWM7WUFDcEIsV0FBVyxFQUNULG1HQUFtRztZQUNyRyxVQUFVLEVBQUU7Z0JBQ1YsSUFBSSxFQUFFLFFBQVE7Z0JBQ2QsVUFBVSxFQUFFO29CQUNWLEtBQUssRUFBRTt3QkFDTCxJQUFJLEVBQUUsUUFBUTt3QkFDZCxXQUFXLEVBQUUsa0RBQWtEO3dCQUMvRCxPQUFPLEVBQUUsR0FBRztxQkFDYjtpQkFDRjthQUNGO1lBQ0QsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsRUFBRTtnQkFDeEIsTUFBTSxLQUFLLEdBQUcsTUFBTSxNQUFNLENBQUMsU0FBUyxDQUFDO29CQUNuQyxLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQWUsSUFBSSxHQUFHO2lCQUNyQyxDQUFDLENBQUM7Z0JBQ0gsT0FBTztvQkFDTCxLQUFLLEVBQUUsS0FBSyxDQUFDLE1BQU07b0JBQ25CLEtBQUssRUFBRSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO3dCQUN2QixFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUU7d0JBQ1IsS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLO3dCQUNkLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSTt3QkFDWixJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUk7cUJBQ2IsQ0FBQyxDQUFDO2lCQUNKLENBQUM7WUFDSixDQUFDO1NBQ0Y7S0FDRixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUHJvZHVjdEJvYXJkIFNlYXJjaCBhbmQgVXNlciBUb29sc1xuICovXG5cbmltcG9ydCB7IFByb2R1Y3RCb2FyZENsaWVudCB9IGZyb20gJy4uL2NsaWVudC9hcGktY2xpZW50JztcbmltcG9ydCB7IFRvb2xEZWZpbml0aW9uLCBTZWFyY2hQYXJhbXMgfSBmcm9tICcuLi9jbGllbnQvdHlwZXMnO1xuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlU2VhcmNoVG9vbHMoY2xpZW50OiBQcm9kdWN0Qm9hcmRDbGllbnQpOiBUb29sRGVmaW5pdGlvbltdIHtcbiAgcmV0dXJuIFtcbiAgICAvLyBwYl9zZWFyY2hcbiAgICB7XG4gICAgICBuYW1lOiAncGJfc2VhcmNoJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnR2xvYmFsIHNlYXJjaCBhY3Jvc3MgUHJvZHVjdEJvYXJkLiBTZWFyY2hlcyBmZWF0dXJlcywgcHJvZHVjdHMsIGNvbXBvbmVudHMsIGFuZCBub3RlcyBieSBuYW1lLCB0aXRsZSwgb3IgY29udGVudC4nLFxuICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICB0eXBlOiAnb2JqZWN0JyxcbiAgICAgICAgcHJvcGVydGllczoge1xuICAgICAgICAgIHF1ZXJ5OiB7XG4gICAgICAgICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiAnU2VhcmNoIHF1ZXJ5IHRleHQnLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgdHlwZToge1xuICAgICAgICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogJ0xpbWl0IHNlYXJjaCB0byBzcGVjaWZpYyB0eXBlJyxcbiAgICAgICAgICAgIGVudW06IFsnZmVhdHVyZScsICdwcm9kdWN0JywgJ2NvbXBvbmVudCcsICdub3RlJ10sXG4gICAgICAgICAgfSxcbiAgICAgICAgICBsaW1pdDoge1xuICAgICAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogJ01heGltdW0gcmVzdWx0cyB0byByZXR1cm4gKGRlZmF1bHQ6IDI1KScsXG4gICAgICAgICAgICBkZWZhdWx0OiAyNSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICByZXF1aXJlZDogWydxdWVyeSddLFxuICAgICAgfSxcbiAgICAgIGhhbmRsZXI6IGFzeW5jIChwYXJhbXMpID0+IHtcbiAgICAgICAgY29uc3Qgc2VhcmNoUGFyYW1zOiBTZWFyY2hQYXJhbXMgPSB7XG4gICAgICAgICAgcXVlcnk6IHBhcmFtcy5xdWVyeSBhcyBzdHJpbmcsXG4gICAgICAgICAgdHlwZTogcGFyYW1zLnR5cGUgYXMgJ2ZlYXR1cmUnIHwgJ25vdGUnIHwgJ3Byb2R1Y3QnIHwgJ2NvbXBvbmVudCcgfCB1bmRlZmluZWQsXG4gICAgICAgICAgbGltaXQ6IHBhcmFtcy5saW1pdCBhcyBudW1iZXIgfHwgMjUsXG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IGNsaWVudC5zZWFyY2goc2VhcmNoUGFyYW1zKTtcblxuICAgICAgICAvLyBHcm91cCByZXN1bHRzIGJ5IHR5cGVcbiAgICAgICAgY29uc3QgZ3JvdXBlZDogUmVjb3JkPHN0cmluZywgdW5rbm93bltdPiA9IHtcbiAgICAgICAgICBmZWF0dXJlczogW10sXG4gICAgICAgICAgcHJvZHVjdHM6IFtdLFxuICAgICAgICAgIGNvbXBvbmVudHM6IFtdLFxuICAgICAgICAgIG5vdGVzOiBbXSxcbiAgICAgICAgfTtcblxuICAgICAgICBmb3IgKGNvbnN0IHJlc3VsdCBvZiByZXN1bHRzKSB7XG4gICAgICAgICAgY29uc3Qga2V5ID0gcmVzdWx0LnR5cGUgKyAncyc7XG4gICAgICAgICAgaWYgKGdyb3VwZWRba2V5XSkge1xuICAgICAgICAgICAgZ3JvdXBlZFtrZXldLnB1c2goe1xuICAgICAgICAgICAgICBpZDogcmVzdWx0LmlkLFxuICAgICAgICAgICAgICBuYW1lOiByZXN1bHQubmFtZSB8fCByZXN1bHQudGl0bGUsXG4gICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiByZXN1bHQuZGVzY3JpcHRpb24gfHwgcmVzdWx0LmNvbnRlbnQsXG4gICAgICAgICAgICAgIHVybDogcmVzdWx0LmxpbmtzPy5odG1sLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB0b3RhbENvdW50OiByZXN1bHRzLmxlbmd0aCxcbiAgICAgICAgICBxdWVyeTogcGFyYW1zLnF1ZXJ5LFxuICAgICAgICAgIHJlc3VsdHM6IGdyb3VwZWQsXG4gICAgICAgIH07XG4gICAgICB9LFxuICAgIH0sXG5cbiAgICAvLyBwYl91c2VyX2N1cnJlbnRcbiAgICB7XG4gICAgICBuYW1lOiAncGJfdXNlcl9jdXJyZW50JyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnR2V0IGluZm9ybWF0aW9uIGFib3V0IHRoZSBjdXJyZW50bHkgYXV0aGVudGljYXRlZCB1c2VyLCBpbmNsdWRpbmcgd29ya3NwYWNlIGRldGFpbHMuJyxcbiAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgdHlwZTogJ29iamVjdCcsXG4gICAgICAgIHByb3BlcnRpZXM6IHt9LFxuICAgICAgfSxcbiAgICAgIGhhbmRsZXI6IGFzeW5jICgpID0+IHtcbiAgICAgICAgY29uc3QgdXNlciA9IGF3YWl0IGNsaWVudC5nZXRDdXJyZW50VXNlcigpO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGlkOiB1c2VyLmlkLFxuICAgICAgICAgIGVtYWlsOiB1c2VyLmVtYWlsLFxuICAgICAgICAgIG5hbWU6IHVzZXIubmFtZSxcbiAgICAgICAgICByb2xlOiB1c2VyLnJvbGUsXG4gICAgICAgICAgd29ya3NwYWNlSWQ6IHVzZXIud29ya3NwYWNlSWQsXG4gICAgICAgICAgd29ya3NwYWNlTmFtZTogdXNlci53b3Jrc3BhY2VOYW1lLFxuICAgICAgICB9O1xuICAgICAgfSxcbiAgICB9LFxuXG4gICAgLy8gcGJfdXNlcl9saXN0XG4gICAge1xuICAgICAgbmFtZTogJ3BiX3VzZXJfbGlzdCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0xpc3QgYWxsIHVzZXJzIGluIHRoZSBQcm9kdWN0Qm9hcmQgd29ya3NwYWNlLiBVc2VmdWwgZm9yIGZpbmRpbmcgdXNlciBJRHMgZm9yIGFzc2lnbmluZyBmZWF0dXJlcy4nLFxuICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICB0eXBlOiAnb2JqZWN0JyxcbiAgICAgICAgcHJvcGVydGllczoge1xuICAgICAgICAgIGxpbWl0OiB7XG4gICAgICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiAnTWF4aW11bSBudW1iZXIgb2YgdXNlcnMgdG8gcmV0dXJuIChkZWZhdWx0OiAxMDApJyxcbiAgICAgICAgICAgIGRlZmF1bHQ6IDEwMCxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICAgIGhhbmRsZXI6IGFzeW5jIChwYXJhbXMpID0+IHtcbiAgICAgICAgY29uc3QgdXNlcnMgPSBhd2FpdCBjbGllbnQubGlzdFVzZXJzKHtcbiAgICAgICAgICBsaW1pdDogcGFyYW1zLmxpbWl0IGFzIG51bWJlciB8fCAxMDAsXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGNvdW50OiB1c2Vycy5sZW5ndGgsXG4gICAgICAgICAgdXNlcnM6IHVzZXJzLm1hcCgodSkgPT4gKHtcbiAgICAgICAgICAgIGlkOiB1LmlkLFxuICAgICAgICAgICAgZW1haWw6IHUuZW1haWwsXG4gICAgICAgICAgICBuYW1lOiB1Lm5hbWUsXG4gICAgICAgICAgICByb2xlOiB1LnJvbGUsXG4gICAgICAgICAgfSkpLFxuICAgICAgICB9O1xuICAgICAgfSxcbiAgICB9LFxuICBdO1xufVxuIl19
@@ -0,0 +1,54 @@
1
+ /**
2
+ * LRU Cache for ProductBoard API responses
3
+ */
4
+ export interface CacheOptions {
5
+ /** Time-to-live in milliseconds */
6
+ ttl: number;
7
+ /** Maximum number of items to cache */
8
+ max: number;
9
+ }
10
+ export declare class ApiCache {
11
+ private cache;
12
+ constructor(options?: Partial<CacheOptions>);
13
+ /**
14
+ * Generate a cache key from tool name and parameters
15
+ */
16
+ static generateKey(tool: string, params: Record<string, unknown>): string;
17
+ /**
18
+ * Get a value from the cache
19
+ */
20
+ get<T>(key: string): T | undefined;
21
+ /**
22
+ * Set a value in the cache
23
+ */
24
+ set<T>(key: string, value: T, ttl?: number): void;
25
+ /**
26
+ * Check if a key exists in the cache
27
+ */
28
+ has(key: string): boolean;
29
+ /**
30
+ * Delete a value from the cache
31
+ */
32
+ delete(key: string): boolean;
33
+ /**
34
+ * Clear all values from the cache
35
+ */
36
+ clear(): void;
37
+ /**
38
+ * Invalidate cache entries matching a pattern
39
+ */
40
+ invalidatePattern(pattern: string): number;
41
+ /**
42
+ * Get cache statistics
43
+ */
44
+ stats(): {
45
+ size: number;
46
+ max: number;
47
+ };
48
+ /**
49
+ * Wrap an async function with caching
50
+ */
51
+ wrap<T>(key: string, fn: () => Promise<T>, ttl?: number): Promise<T>;
52
+ }
53
+ export declare function getCache(options?: Partial<CacheOptions>): ApiCache;
54
+ export declare function resetCache(): void;
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ /**
3
+ * LRU Cache for ProductBoard API responses
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ApiCache = void 0;
7
+ exports.getCache = getCache;
8
+ exports.resetCache = resetCache;
9
+ const lru_cache_1 = require("lru-cache");
10
+ const DEFAULT_OPTIONS = {
11
+ ttl: 5 * 60 * 1000, // 5 minutes
12
+ max: 500,
13
+ };
14
+ class ApiCache {
15
+ cache;
16
+ constructor(options = {}) {
17
+ const opts = { ...DEFAULT_OPTIONS, ...options };
18
+ this.cache = new lru_cache_1.LRUCache({
19
+ max: opts.max,
20
+ ttl: opts.ttl,
21
+ });
22
+ }
23
+ /**
24
+ * Generate a cache key from tool name and parameters
25
+ */
26
+ static generateKey(tool, params) {
27
+ const sortedParams = Object.keys(params)
28
+ .sort()
29
+ .reduce((acc, key) => {
30
+ const value = params[key];
31
+ if (value !== undefined && value !== null) {
32
+ acc[key] = value;
33
+ }
34
+ return acc;
35
+ }, {});
36
+ return `${tool}:${JSON.stringify(sortedParams)}`;
37
+ }
38
+ /**
39
+ * Get a value from the cache
40
+ */
41
+ get(key) {
42
+ return this.cache.get(key);
43
+ }
44
+ /**
45
+ * Set a value in the cache
46
+ */
47
+ set(key, value, ttl) {
48
+ if (ttl !== undefined) {
49
+ this.cache.set(key, value, { ttl });
50
+ }
51
+ else {
52
+ this.cache.set(key, value);
53
+ }
54
+ }
55
+ /**
56
+ * Check if a key exists in the cache
57
+ */
58
+ has(key) {
59
+ return this.cache.has(key);
60
+ }
61
+ /**
62
+ * Delete a value from the cache
63
+ */
64
+ delete(key) {
65
+ return this.cache.delete(key);
66
+ }
67
+ /**
68
+ * Clear all values from the cache
69
+ */
70
+ clear() {
71
+ this.cache.clear();
72
+ }
73
+ /**
74
+ * Invalidate cache entries matching a pattern
75
+ */
76
+ invalidatePattern(pattern) {
77
+ let count = 0;
78
+ for (const key of this.cache.keys()) {
79
+ if (key.startsWith(pattern)) {
80
+ this.cache.delete(key);
81
+ count++;
82
+ }
83
+ }
84
+ return count;
85
+ }
86
+ /**
87
+ * Get cache statistics
88
+ */
89
+ stats() {
90
+ return {
91
+ size: this.cache.size,
92
+ max: this.cache.max,
93
+ };
94
+ }
95
+ /**
96
+ * Wrap an async function with caching
97
+ */
98
+ async wrap(key, fn, ttl) {
99
+ const cached = this.get(key);
100
+ if (cached !== undefined) {
101
+ return cached;
102
+ }
103
+ const result = await fn();
104
+ this.set(key, result, ttl);
105
+ return result;
106
+ }
107
+ }
108
+ exports.ApiCache = ApiCache;
109
+ // Singleton instance for the plugin
110
+ let cacheInstance = null;
111
+ function getCache(options) {
112
+ if (!cacheInstance) {
113
+ cacheInstance = new ApiCache(options);
114
+ }
115
+ return cacheInstance;
116
+ }
117
+ function resetCache() {
118
+ if (cacheInstance) {
119
+ cacheInstance.clear();
120
+ }
121
+ cacheInstance = null;
122
+ }
123
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOztHQUVHOzs7QUFvSUgsNEJBS0M7QUFFRCxnQ0FLQztBQTlJRCx5Q0FBcUM7QUFTckMsTUFBTSxlQUFlLEdBQWlCO0lBQ3BDLEdBQUcsRUFBRSxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksRUFBRSxZQUFZO0lBQ2hDLEdBQUcsRUFBRSxHQUFHO0NBQ1QsQ0FBQztBQUtGLE1BQWEsUUFBUTtJQUNYLEtBQUssQ0FBK0I7SUFFNUMsWUFBWSxVQUFpQyxFQUFFO1FBQzdDLE1BQU0sSUFBSSxHQUFHLEVBQUUsR0FBRyxlQUFlLEVBQUUsR0FBRyxPQUFPLEVBQUUsQ0FBQztRQUNoRCxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksb0JBQVEsQ0FBcUI7WUFDNUMsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHO1lBQ2IsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHO1NBQ2QsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLFdBQVcsQ0FBQyxJQUFZLEVBQUUsTUFBK0I7UUFDOUQsTUFBTSxZQUFZLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUM7YUFDckMsSUFBSSxFQUFFO2FBQ04sTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFO1lBQ25CLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUMxQixJQUFJLEtBQUssS0FBSyxTQUFTLElBQUksS0FBSyxLQUFLLElBQUksRUFBRSxDQUFDO2dCQUMxQyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsS0FBSyxDQUFDO1lBQ25CLENBQUM7WUFDRCxPQUFPLEdBQUcsQ0FBQztRQUNiLENBQUMsRUFBRSxFQUE2QixDQUFDLENBQUM7UUFFcEMsT0FBTyxHQUFHLElBQUksSUFB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KiBMUlUgQ2FjaGUgZm9yIFByb2R1Y3RCb2FyZCBBUEkgcmVzcG9uc2VzXG4gKi9cblxuaW1wb3J0IHsgTFJVQ2FjaGUgfSBmcm9tICdscnUtY2FjaGUnO1xuXG5leHBvcnQgaW50ZXJmYWNlIENhY2hlT3B0aW9ucyB7XG4gIC8qKiBUaW1lLXRvLWxpdmUgaW4gbWlsbGlzZWNvbmRzICovXG4gIHR0bDogbnVtYmVyO1xuICAvKiogTWF4aW11bSBudW1iZXIgb2YgaXRlbXMgdG8gY2FjaGUgKi9cbiAgbWF4OiBudW1iZXI7XG59XG5cbmNvbnN0IERFRkFVTFRfT1BUSU9OUzogQ2FjaGVPcHRpb25zID0ge1xuICB0dGw6IDUgKiA2MCAqIDEwMDAsIC8vIDUgbWludXRlc1xuICBtYXg6IDUwMCxcbn07XG5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55XG50eXBlIENhY2hlVmFsdWUgPSBhbnk7XG5cbmV4cG9ydCBjbGFzcyBBcGlDYWNoZSB7XG4gIHByaXZhdGUgY2FjaGU6IExSVUNhY2hlPHN0cmluZywgQ2FjaGVWYWx1ZT47XG5cbiAgY29uc3RydWN0b3Iob3B0aW9uczogUGFydGlhbDxDYWNoZU9wdGlvbnM+ID0ge30pIHtcbiAgICBjb25zdCBvcHRzID0geyAuLi5ERUZBVUxUX09QVElPTlMsIC4uLm9wdGlvbnMgfTtcbiAgICB0aGlzLmNhY2hlID0gbmV3IExSVUNhY2hlPHN0cmluZywgQ2FjaGVWYWx1ZT4oe1xuICAgICAgbWF4OiBvcHRzLm1heCxcbiAgICAgIHR0bDogb3B0cy50dGwsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGUgYSBjYWNoZSBrZXkgZnJvbSB0b29sIG5hbWUgYW5kIHBhcmFtZXRlcnNcbiAgICovXG4gIHN0YXRpYyBnZW5lcmF0ZUtleSh0b29sOiBzdHJpbmcsIHBhcmFtczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBzdHJpbmcge1xuICAgIGNvbnN0IHNvcnRlZFBhcmFtcyA9IE9iamVjdC5rZXlzKHBhcmFtcylcbiAgICAgIC5zb3J0KClcbiAgICAgIC5yZWR1Y2UoKGFjYywga2V5KSA9PiB7XG4gICAgICAgIGNvbnN0IHZhbHVlID0gcGFyYW1zW2tleV07XG4gICAgICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkICYmIHZhbHVlICE9PSBudWxsKSB7XG4gICAgICAgICAgYWNjW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgfSwge30gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pO1xuXG4gICAgcmV0dXJuIGAke3Rvb2x9OiR7SlNPTi5zdHJpbmdpZnkoc29ydGVkUGFyYW1zKX1gO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhIHZhbHVlIGZyb20gdGhlIGNhY2hlXG4gICAqL1xuICBnZXQ8VD4oa2V5OiBzdHJpbmcpOiBUIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5jYWNoZS5nZXQoa2V5KSBhcyBUIHwgdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCBhIHZhbHVlIGluIHRoZSBjYWNoZVxuICAgKi9cbiAgc2V0PFQ+KGtleTogc3RyaW5nLCB2YWx1ZTogVCwgdHRsPzogbnVtYmVyKTogdm9pZCB7XG4gICAgaWYgKHR0bCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLmNhY2hlLnNldChrZXksIHZhbHVlLCB7IHR0bCB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5jYWNoZS5zZXQoa2V5LCB2YWx1ZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIGEga2V5IGV4aXN0cyBpbiB0aGUgY2FjaGVcbiAgICovXG4gIGhhcyhrZXk6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmNhY2hlLmhhcyhrZXkpO1xuICB9XG5cbiAgLyoqXG4gICAqIERlbGV0ZSBhIHZhbHVlIGZyb20gdGhlIGNhY2hlXG4gICAqL1xuICBkZWxldGUoa2V5OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5jYWNoZS5kZWxldGUoa2V5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDbGVhciBhbGwgdmFsdWVzIGZyb20gdGhlIGNhY2hlXG4gICAqL1xuICBjbGVhcigpOiB2b2lkIHtcbiAgICB0aGlzLmNhY2hlLmNsZWFyKCk7XG4gIH1cblxuICAvKipcbiAgICogSW52YWxpZGF0ZSBjYWNoZSBlbnRyaWVzIG1hdGNoaW5nIGEgcGF0dGVyblxuICAgKi9cbiAgaW52YWxpZGF0ZVBhdHRlcm4ocGF0dGVybjogc3RyaW5nKTogbnVtYmVyIHtcbiAgICBsZXQgY291bnQgPSAwO1xuICAgIGZvciAoY29uc3Qga2V5IG9mIHRoaXMuY2FjaGUua2V5cygpKSB7XG4gICAgICBpZiAoa2V5LnN0YXJ0c1dpdGgocGF0dGVybikpIHtcbiAgICAgICAgdGhpcy5jYWNoZS5kZWxldGUoa2V5KTtcbiAgICAgICAgY291bnQrKztcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGNvdW50O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBjYWNoZSBzdGF0aXN0aWNzXG4gICAqL1xuICBzdGF0cygpOiB7IHNpemU6IG51bWJlcjsgbWF4OiBudW1iZXIgfSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHNpemU6IHRoaXMuY2FjaGUuc2l6ZSxcbiAgICAgIG1heDogdGhpcy5jYWNoZS5tYXgsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXcmFwIGFuIGFzeW5jIGZ1bmN0aW9uIHdpdGggY2FjaGluZ1xuICAgKi9cbiAgYXN5bmMgd3JhcDxUPihcbiAgICBrZXk6IHN0cmluZyxcbiAgICBmbjogKCkgPT4gUHJvbWlzZTxUPixcbiAgICB0dGw/OiBudW1iZXJcbiAgKTogUHJvbWlzZTxUPiB7XG4gICAgY29uc3QgY2FjaGVkID0gdGhpcy5nZXQ8VD4oa2V5KTtcbiAgICBpZiAoY2FjaGVkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiBjYWNoZWQ7XG4gICAgfVxuXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZm4oKTtcbiAgICB0aGlzLnNldChrZXksIHJlc3VsdCwgdHRsKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG59XG5cbi8vIFNpbmdsZXRvbiBpbnN0YW5jZSBmb3IgdGhlIHBsdWdpblxubGV0IGNhY2hlSW5zdGFuY2U6IEFwaUNhY2hlIHwgbnVsbCA9IG51bGw7XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRDYWNoZShvcHRpb25zPzogUGFydGlhbDxDYWNoZU9wdGlvbnM+KTogQXBpQ2FjaGUge1xuICBpZiAoIWNhY2hlSW5zdGFuY2UpIHtcbiAgICBjYWNoZUluc3RhbmNlID0gbmV3IEFwaUNhY2hlKG9wdGlvbnMpO1xuICB9XG4gIHJldHVybiBjYWNoZUluc3RhbmNlO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVzZXRDYWNoZSgpOiB2b2lkIHtcbiAgaWYgKGNhY2hlSW5zdGFuY2UpIHtcbiAgICBjYWNoZUluc3RhbmNlLmNsZWFyKCk7XG4gIH1cbiAgY2FjaGVJbnN0YW5jZSA9IG51bGw7XG59XG4iXX0=
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Token Bucket Rate Limiter for ProductBoard API
3
+ */
4
+ export interface RateLimiterOptions {
5
+ /** Maximum tokens in the bucket */
6
+ maxTokens: number;
7
+ /** Tokens added per interval */
8
+ refillRate: number;
9
+ /** Refill interval in milliseconds */
10
+ refillInterval: number;
11
+ }
12
+ export declare class RateLimiter {
13
+ private tokens;
14
+ private lastRefill;
15
+ private readonly options;
16
+ constructor(options?: Partial<RateLimiterOptions>);
17
+ /**
18
+ * Refill tokens based on elapsed time
19
+ */
20
+ private refill;
21
+ /**
22
+ * Try to acquire a token
23
+ * @returns true if token was acquired, false if rate limited
24
+ */
25
+ tryAcquire(): boolean;
26
+ /**
27
+ * Acquire a token, waiting if necessary
28
+ * @returns Promise that resolves when a token is available
29
+ */
30
+ acquire(): Promise<void>;
31
+ /**
32
+ * Get the time in milliseconds until a token is available
33
+ */
34
+ getWaitTime(): number;
35
+ /**
36
+ * Get current token count
37
+ */
38
+ getTokens(): number;
39
+ /**
40
+ * Reset the rate limiter to full capacity
41
+ */
42
+ reset(): void;
43
+ /**
44
+ * Check if rate limited without consuming a token
45
+ */
46
+ isRateLimited(): boolean;
47
+ /**
48
+ * Get rate limiter statistics
49
+ */
50
+ stats(): {
51
+ tokens: number;
52
+ maxTokens: number;
53
+ waitTime: number;
54
+ };
55
+ private sleep;
56
+ }
57
+ export declare function getRateLimiter(options?: Partial<RateLimiterOptions>): RateLimiter;
58
+ export declare function resetRateLimiter(): void;