r3plica 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +173 -0
- package/dist/cli/commands/brand.d.ts +2 -0
- package/dist/cli/commands/brand.js +53 -0
- package/dist/cli/commands/brand.js.map +1 -0
- package/dist/cli/commands/config.d.ts +2 -0
- package/dist/cli/commands/config.js +34 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/finish-collection.d.ts +2 -0
- package/dist/cli/commands/finish-collection.js +71 -0
- package/dist/cli/commands/finish-collection.js.map +1 -0
- package/dist/cli/commands/product-collection.d.ts +2 -0
- package/dist/cli/commands/product-collection.js +59 -0
- package/dist/cli/commands/product-collection.js.map +1 -0
- package/dist/cli/commands/product.d.ts +2 -0
- package/dist/cli/commands/product.js +81 -0
- package/dist/cli/commands/product.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +22 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/api.d.ts +38 -0
- package/dist/core/api.js +158 -0
- package/dist/core/api.js.map +1 -0
- package/dist/core/config.d.ts +3 -0
- package/dist/core/config.js +50 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/errors.d.ts +1 -0
- package/dist/core/errors.js +11 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/formatter.d.ts +18 -0
- package/dist/core/formatter.js +96 -0
- package/dist/core/formatter.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.js +192 -0
- package/dist/mcp/server.js.map +1 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# r3 — R3PLICA CLI
|
|
2
|
+
|
|
3
|
+
Query the R3PLICA digital replicas catalog from your terminal. Search products, brands, collections, and finishes — built for AI agents, developers, and scripts.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g r3plica
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node.js 20+.
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Search products
|
|
17
|
+
r3 product search "dining table"
|
|
18
|
+
|
|
19
|
+
# List brands
|
|
20
|
+
r3 brand list
|
|
21
|
+
|
|
22
|
+
# Filter by brand and category
|
|
23
|
+
r3 product list --brand "Cattelan Italia" --category table
|
|
24
|
+
|
|
25
|
+
# Get product details
|
|
26
|
+
r3 product get <mongo_id>
|
|
27
|
+
|
|
28
|
+
# Pipe to jq
|
|
29
|
+
r3 product list --limit 5 --json | jq '.[].name'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Commands
|
|
33
|
+
|
|
34
|
+
### Products
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
r3 product list [--brand X] [--category X] [--collection X] [--limit N] [--page N]
|
|
38
|
+
r3 product search <query> [--brand X] [--category X] [--limit N]
|
|
39
|
+
r3 product get <mongo_id>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Brands
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
r3 brand list [--country X] [--limit N]
|
|
46
|
+
r3 brand search <query>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Product Collections
|
|
50
|
+
|
|
51
|
+
Product collections are furniture lines from a brand (e.g., "Tudor" by Cattelan Italia).
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
r3 product-collection list [--brand X] [--limit N] [--page N] [--sort X] [--order asc|desc]
|
|
55
|
+
r3 product-collection search <query>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Finish Collections
|
|
59
|
+
|
|
60
|
+
Finish collections are sets of material finishes (shaders) — wood types, fabrics, metals, leathers — that can be applied to product parts.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
r3 finish-collection list [--brand X] [--category X] [--limit N] [--page N]
|
|
64
|
+
r3 finish-collection search <query>
|
|
65
|
+
r3 finish-collection get <mongo_id>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Configuration
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
r3 config show
|
|
72
|
+
r3 config set api-url <url>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Default API URL: `https://api.r3plica.space/api/r3vault`. Override with `R3_API_URL` environment variable or `r3 config set`.
|
|
76
|
+
|
|
77
|
+
## Output
|
|
78
|
+
|
|
79
|
+
- **Terminal**: formatted table with headers and result count
|
|
80
|
+
- **Piped**: JSON (automatic detection)
|
|
81
|
+
- `--json`: force JSON output
|
|
82
|
+
- `--pretty`: force table output
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Table output (terminal)
|
|
86
|
+
$ r3 brand list --limit 3
|
|
87
|
+
|
|
88
|
+
ID Name Country Products
|
|
89
|
+
0a497f00-cc6f-4 Driade Italy 29
|
|
90
|
+
22b4a540-bcf2-4 We Are IB Italy 37
|
|
91
|
+
ab368a13-6038-4 Emu Italy 26
|
|
92
|
+
|
|
93
|
+
3 brands found
|
|
94
|
+
|
|
95
|
+
# JSON output (piped or --json)
|
|
96
|
+
$ r3 brand list --limit 1 --json | jq '.[0].name'
|
|
97
|
+
"Driade"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Use with AI Agents
|
|
101
|
+
|
|
102
|
+
### Claude Code / CLAUDE.md
|
|
103
|
+
|
|
104
|
+
Add to your project's `CLAUDE.md`:
|
|
105
|
+
|
|
106
|
+
```markdown
|
|
107
|
+
## R3PLICA Catalog
|
|
108
|
+
|
|
109
|
+
The `r3` CLI queries the R3PLICA 3D furniture catalog. Use it when the user
|
|
110
|
+
asks about furniture, materials, brands, or design products.
|
|
111
|
+
|
|
112
|
+
- `r3 product search "query"` — search products by text
|
|
113
|
+
- `r3 product list --brand X --category X` — filter products
|
|
114
|
+
- `r3 product get <id>` — product details with finish options
|
|
115
|
+
- `r3 brand list` — all available brands
|
|
116
|
+
- `r3 finish-collection list --brand X` — available finish collections
|
|
117
|
+
- Always use `--json` when processing results programmatically
|
|
118
|
+
- Run `r3 --help` for full command reference
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### MCP Server
|
|
122
|
+
|
|
123
|
+
The package also includes an MCP server for auto-discovery in Claude Desktop, Cursor, and similar IDEs.
|
|
124
|
+
|
|
125
|
+
Add to your Claude Desktop config (`claude_desktop_config.json`):
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"mcpServers": {
|
|
130
|
+
"r3plica": {
|
|
131
|
+
"command": "r3-mcp"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The MCP server exposes the same data through 10 tools: `product_list`, `product_search`, `product_get`, `brand_list`, `brand_search`, `product_collection_list`, `product_collection_search`, `finish_collection_list`, `finish_collection_search`, `finish_collection_get`.
|
|
138
|
+
|
|
139
|
+
## Examples
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# Find Italian brands
|
|
143
|
+
r3 brand list --country Italy
|
|
144
|
+
|
|
145
|
+
# Search chairs, limit to 5 results
|
|
146
|
+
r3 product search "chair" --limit 5
|
|
147
|
+
|
|
148
|
+
# Get all products from a brand
|
|
149
|
+
r3 product list --brand "Driade"
|
|
150
|
+
|
|
151
|
+
# Explore a product collection
|
|
152
|
+
r3 product-collection search "Tudor"
|
|
153
|
+
|
|
154
|
+
# Find wood finishes
|
|
155
|
+
r3 finish-collection list --category wood
|
|
156
|
+
|
|
157
|
+
# Script: get all brand names
|
|
158
|
+
r3 brand list --json | jq -r '.[].name'
|
|
159
|
+
|
|
160
|
+
# Script: count products per brand
|
|
161
|
+
r3 brand list --json | jq -r '.[].name' | while read brand; do
|
|
162
|
+
count=$(r3 product list --brand "$brand" --json 2>/dev/null | jq length)
|
|
163
|
+
echo "$brand: $count"
|
|
164
|
+
done
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## About R3PLICA
|
|
168
|
+
|
|
169
|
+
[R3PLICA](https://r3plica.io) provides high-quality 3D digital replicas of branded furniture to architects, interior designers, and visualization professionals. The catalog includes 60+ premium brands including Cattelan Italia, Driade, Poliform, and more.
|
|
170
|
+
|
|
171
|
+
## License
|
|
172
|
+
|
|
173
|
+
Proprietary - R3PLICA S.r.l.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { listBrands, searchBrands } from "../../core/api.js";
|
|
2
|
+
import { output } from "../../core/formatter.js";
|
|
3
|
+
import { handleError } from "../../core/errors.js";
|
|
4
|
+
const BRAND_COLUMNS = [
|
|
5
|
+
{ key: "mongo_id", header: "ID", width: 16 },
|
|
6
|
+
{ key: "name", header: "Name", width: 25 },
|
|
7
|
+
{ key: "contact.country", header: "Country", width: 15 },
|
|
8
|
+
{ key: "products_count", header: "Products", width: 10 },
|
|
9
|
+
];
|
|
10
|
+
export function registerBrandCommands(program) {
|
|
11
|
+
const brand = program.command("brand").description("Browse and search brands");
|
|
12
|
+
brand
|
|
13
|
+
.command("list")
|
|
14
|
+
.description("List all public brands")
|
|
15
|
+
.option("--country <country>", "Filter by country")
|
|
16
|
+
.option("--limit <n>", "Max results", "50")
|
|
17
|
+
.action(async (opts) => {
|
|
18
|
+
try {
|
|
19
|
+
const results = await listBrands({
|
|
20
|
+
country: opts.country,
|
|
21
|
+
limit: parseInt(opts.limit),
|
|
22
|
+
});
|
|
23
|
+
output(results, {
|
|
24
|
+
json: program.opts().json,
|
|
25
|
+
pretty: program.opts().pretty,
|
|
26
|
+
label: "brand",
|
|
27
|
+
columns: BRAND_COLUMNS,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
handleError(error);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
brand
|
|
35
|
+
.command("search <query>")
|
|
36
|
+
.description("Search brands by name")
|
|
37
|
+
.action(async (query) => {
|
|
38
|
+
try {
|
|
39
|
+
const results = await searchBrands(query);
|
|
40
|
+
output(results, {
|
|
41
|
+
json: program.opts().json,
|
|
42
|
+
pretty: program.opts().pretty,
|
|
43
|
+
label: "brand",
|
|
44
|
+
query,
|
|
45
|
+
columns: BRAND_COLUMNS,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
handleError(error);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=brand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brand.js","sourceRoot":"","sources":["../../../src/cli/commands/brand.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,MAAM,aAAa,GAAG;IACpB,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;IAC5C,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;IAC1C,EAAE,GAAG,EAAE,iBAAiB,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE;IACxD,EAAE,GAAG,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE;CACzD,CAAC;AAEF,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC;IAE/E,KAAK;SACF,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,wBAAwB,CAAC;SACrC,MAAM,CAAC,qBAAqB,EAAE,mBAAmB,CAAC;SAClD,MAAM,CAAC,aAAa,EAAE,aAAa,EAAE,IAAI,CAAC;SAC1C,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC;gBAC/B,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;aAC5B,CAAC,CAAC;YACH,MAAM,CAAC,OAAO,EAAE;gBACd,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI;gBACzB,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM;gBAC7B,KAAK,EAAE,OAAO;gBACd,OAAO,EAAE,aAAa;aACvB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,KAAK;SACF,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,uBAAuB,CAAC;SACpC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QACtB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,CAAC;YAC1C,MAAM,CAAC,OAAO,EAAE;gBACd,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI;gBACzB,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM;gBAC7B,KAAK,EAAE,OAAO;gBACd,KAAK;gBACL,OAAO,EAAE,aAAa;aACvB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { setConfigValue, getFullConfig } from "../../core/config.js";
|
|
2
|
+
export function registerConfigCommands(program) {
|
|
3
|
+
const config = program.command("config").description("Manage CLI configuration");
|
|
4
|
+
config
|
|
5
|
+
.command("set <key> <value>")
|
|
6
|
+
.description("Set a config value (available keys: api-url)")
|
|
7
|
+
.action((key, value) => {
|
|
8
|
+
try {
|
|
9
|
+
setConfigValue(key, value);
|
|
10
|
+
process.stdout.write(`Set ${key} = ${value}\n`);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
process.stderr.write(`Error: ${error instanceof Error ? error.message : error}\n`);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
config
|
|
18
|
+
.command("show")
|
|
19
|
+
.description("Show current configuration")
|
|
20
|
+
.action(() => {
|
|
21
|
+
const cfg = getFullConfig();
|
|
22
|
+
if (program.opts().json) {
|
|
23
|
+
process.stdout.write(JSON.stringify(cfg, null, 2) + "\n");
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
process.stdout.write("\n");
|
|
27
|
+
for (const [key, value] of Object.entries(cfg)) {
|
|
28
|
+
process.stdout.write(` ${key}: ${value}\n`);
|
|
29
|
+
}
|
|
30
|
+
process.stdout.write("\n");
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/cli/commands/config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErE,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACrD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC;IAEjF,MAAM;SACH,OAAO,CAAC,mBAAmB,CAAC;SAC5B,WAAW,CAAC,8CAA8C,CAAC;SAC3D,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;YACnF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,MAAM;SACH,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,4BAA4B,CAAC;SACzC,MAAM,CAAC,GAAG,EAAE;QACX,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;YACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC5D,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC3B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC;YAC/C,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { listFinishCollections, searchFinishCollections, getFinishCollection, } from "../../core/api.js";
|
|
2
|
+
import { output, outputDetail } from "../../core/formatter.js";
|
|
3
|
+
import { handleError } from "../../core/errors.js";
|
|
4
|
+
const FINISH_COLLECTION_COLUMNS = [
|
|
5
|
+
{ key: "mongo_id", header: "ID", width: 16 },
|
|
6
|
+
{ key: "name", header: "Name", width: 30 },
|
|
7
|
+
{ key: "brand.name", header: "Brand", width: 20 },
|
|
8
|
+
{ key: "category.name", header: "Category", width: 12 },
|
|
9
|
+
];
|
|
10
|
+
export function registerFinishCollectionCommands(program) {
|
|
11
|
+
const fc = program
|
|
12
|
+
.command("finish-collection")
|
|
13
|
+
.description("Browse finish collections (material finishes/shaders)");
|
|
14
|
+
fc.command("list")
|
|
15
|
+
.description("List finish collections")
|
|
16
|
+
.option("--brand <name>", "Filter by brand name")
|
|
17
|
+
.option("--category <category>", "Filter by category (Wood, Fabric, Metal, etc.)")
|
|
18
|
+
.option("--limit <n>", "Max results", "20")
|
|
19
|
+
.option("--page <n>", "Page number", "1")
|
|
20
|
+
.action(async (opts) => {
|
|
21
|
+
try {
|
|
22
|
+
const results = await listFinishCollections({
|
|
23
|
+
brand: opts.brand,
|
|
24
|
+
category: opts.category,
|
|
25
|
+
limit: parseInt(opts.limit),
|
|
26
|
+
page: parseInt(opts.page),
|
|
27
|
+
});
|
|
28
|
+
output(results, {
|
|
29
|
+
json: program.opts().json,
|
|
30
|
+
pretty: program.opts().pretty,
|
|
31
|
+
label: "finish collection",
|
|
32
|
+
columns: FINISH_COLLECTION_COLUMNS,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
handleError(error);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
fc.command("search <query>")
|
|
40
|
+
.description("Search finish collections by name")
|
|
41
|
+
.action(async (query) => {
|
|
42
|
+
try {
|
|
43
|
+
const results = await searchFinishCollections(query);
|
|
44
|
+
output(results, {
|
|
45
|
+
json: program.opts().json,
|
|
46
|
+
pretty: program.opts().pretty,
|
|
47
|
+
label: "finish collection",
|
|
48
|
+
query,
|
|
49
|
+
columns: FINISH_COLLECTION_COLUMNS,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
handleError(error);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
fc.command("get <id>")
|
|
57
|
+
.description("Get finish collection details with all finishes")
|
|
58
|
+
.action(async (id) => {
|
|
59
|
+
try {
|
|
60
|
+
const result = await getFinishCollection(id);
|
|
61
|
+
outputDetail(result, {
|
|
62
|
+
json: program.opts().json,
|
|
63
|
+
pretty: program.opts().pretty,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
handleError(error);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=finish-collection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finish-collection.js","sourceRoot":"","sources":["../../../src/cli/commands/finish-collection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { listProductCollections, searchProductCollections } from "../../core/api.js";
|
|
2
|
+
import { output } from "../../core/formatter.js";
|
|
3
|
+
import { handleError } from "../../core/errors.js";
|
|
4
|
+
const COLLECTION_COLUMNS = [
|
|
5
|
+
{ key: "mongo_id", header: "ID", width: 16 },
|
|
6
|
+
{ key: "name", header: "Name", width: 30 },
|
|
7
|
+
{ key: "brand.name", header: "Brand", width: 20 },
|
|
8
|
+
{ key: "products_count", header: "Products", width: 10 },
|
|
9
|
+
];
|
|
10
|
+
export function registerProductCollectionCommands(program) {
|
|
11
|
+
const pc = program
|
|
12
|
+
.command("product-collection")
|
|
13
|
+
.description("Browse product collections (furniture lines)");
|
|
14
|
+
pc.command("list")
|
|
15
|
+
.description("List product collections")
|
|
16
|
+
.option("--brand <name>", "Filter by brand name")
|
|
17
|
+
.option("--limit <n>", "Max results", "20")
|
|
18
|
+
.option("--page <n>", "Page number", "1")
|
|
19
|
+
.option("--sort <field>", "Sort by field")
|
|
20
|
+
.option("--order <dir>", "Sort direction (asc|desc)", "asc")
|
|
21
|
+
.action(async (opts) => {
|
|
22
|
+
try {
|
|
23
|
+
const results = await listProductCollections({
|
|
24
|
+
brand: opts.brand,
|
|
25
|
+
limit: parseInt(opts.limit),
|
|
26
|
+
page: parseInt(opts.page),
|
|
27
|
+
sort: opts.sort,
|
|
28
|
+
order: opts.sort ? opts.order : undefined,
|
|
29
|
+
});
|
|
30
|
+
output(results, {
|
|
31
|
+
json: program.opts().json,
|
|
32
|
+
pretty: program.opts().pretty,
|
|
33
|
+
label: "collection",
|
|
34
|
+
columns: COLLECTION_COLUMNS,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
handleError(error);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
pc.command("search <query>")
|
|
42
|
+
.description("Search product collections by name")
|
|
43
|
+
.action(async (query) => {
|
|
44
|
+
try {
|
|
45
|
+
const results = await searchProductCollections(query);
|
|
46
|
+
output(results, {
|
|
47
|
+
json: program.opts().json,
|
|
48
|
+
pretty: program.opts().pretty,
|
|
49
|
+
label: "collection",
|
|
50
|
+
query,
|
|
51
|
+
columns: COLLECTION_COLUMNS,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
handleError(error);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=product-collection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-collection.js","sourceRoot":"","sources":["../../../src/cli/commands/product-collection.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,MAAM,kBAAkB,GAAG;IACzB,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;IAC5C,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;IAC1C,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE;IACjD,EAAE,GAAG,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE;CACzD,CAAC;AAEF,MAAM,UAAU,iCAAiC,CAAC,OAAgB;IAChE,MAAM,EAAE,GAAG,OAAO;SACf,OAAO,CAAC,oBAAoB,CAAC;SAC7B,WAAW,CAAC,8CAA8C,CAAC,CAAC;IAE/D,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,0BAA0B,CAAC;SACvC,MAAM,CAAC,gBAAgB,EAAE,sBAAsB,CAAC;SAChD,MAAM,CAAC,aAAa,EAAE,aAAa,EAAE,IAAI,CAAC;SAC1C,MAAM,CAAC,YAAY,EAAE,aAAa,EAAE,GAAG,CAAC;SACxC,MAAM,CAAC,gBAAgB,EAAE,eAAe,CAAC;SACzC,MAAM,CAAC,eAAe,EAAE,2BAA2B,EAAE,KAAK,CAAC;SAC3D,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,sBAAsB,CAAC;gBAC3C,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;gBAC3B,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;gBACzB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;aAC1C,CAAC,CAAC;YACH,MAAM,CAAC,OAAO,EAAE;gBACd,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI;gBACzB,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM;gBAC7B,KAAK,EAAE,YAAY;gBACnB,OAAO,EAAE,kBAAkB;aAC5B,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,oCAAoC,CAAC;SACjD,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QACtB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,wBAAwB,CAAC,KAAK,CAAC,CAAC;YACtD,MAAM,CAAC,OAAO,EAAE;gBACd,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI;gBACzB,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM;gBAC7B,KAAK,EAAE,YAAY;gBACnB,KAAK;gBACL,OAAO,EAAE,kBAAkB;aAC5B,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { listProducts, searchProducts, getProduct } from "../../core/api.js";
|
|
2
|
+
import { output, outputDetail } from "../../core/formatter.js";
|
|
3
|
+
import { handleError } from "../../core/errors.js";
|
|
4
|
+
const PRODUCT_COLUMNS = [
|
|
5
|
+
{ key: "mongo_id", header: "ID", width: 16 },
|
|
6
|
+
{ key: "name", header: "Name", width: 30 },
|
|
7
|
+
{ key: "brand.name", header: "Brand", width: 20 },
|
|
8
|
+
{ key: "category", header: "Category", width: 15 },
|
|
9
|
+
];
|
|
10
|
+
export function registerProductCommands(program) {
|
|
11
|
+
const product = program.command("product").description("Browse and search products");
|
|
12
|
+
product
|
|
13
|
+
.command("list")
|
|
14
|
+
.description("List products with optional filters")
|
|
15
|
+
.option("--brand <name>", "Filter by brand name")
|
|
16
|
+
.option("--category <category>", "Filter by product category")
|
|
17
|
+
.option("--collection <name>", "Filter by collection name")
|
|
18
|
+
.option("--limit <n>", "Max results", "20")
|
|
19
|
+
.option("--page <n>", "Page number", "1")
|
|
20
|
+
.action(async (opts) => {
|
|
21
|
+
try {
|
|
22
|
+
const results = await listProducts({
|
|
23
|
+
brand: opts.brand,
|
|
24
|
+
category: opts.category,
|
|
25
|
+
collection: opts.collection,
|
|
26
|
+
limit: parseInt(opts.limit),
|
|
27
|
+
page: parseInt(opts.page),
|
|
28
|
+
});
|
|
29
|
+
output(results, {
|
|
30
|
+
json: program.opts().json,
|
|
31
|
+
pretty: program.opts().pretty,
|
|
32
|
+
label: "product",
|
|
33
|
+
columns: PRODUCT_COLUMNS,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
handleError(error);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
product
|
|
41
|
+
.command("search <query>")
|
|
42
|
+
.description("Search products by text")
|
|
43
|
+
.option("--brand <name>", "Filter by brand name")
|
|
44
|
+
.option("--category <category>", "Filter by product category")
|
|
45
|
+
.option("--limit <n>", "Max results", "20")
|
|
46
|
+
.action(async (query, opts) => {
|
|
47
|
+
try {
|
|
48
|
+
const results = await searchProducts(query, {
|
|
49
|
+
brand: opts.brand,
|
|
50
|
+
category: opts.category,
|
|
51
|
+
limit: parseInt(opts.limit),
|
|
52
|
+
});
|
|
53
|
+
output(results, {
|
|
54
|
+
json: program.opts().json,
|
|
55
|
+
pretty: program.opts().pretty,
|
|
56
|
+
label: "product",
|
|
57
|
+
query,
|
|
58
|
+
columns: PRODUCT_COLUMNS,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
handleError(error);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
product
|
|
66
|
+
.command("get <id>")
|
|
67
|
+
.description("Get detailed product information")
|
|
68
|
+
.action(async (id) => {
|
|
69
|
+
try {
|
|
70
|
+
const result = await getProduct(id);
|
|
71
|
+
outputDetail(result, {
|
|
72
|
+
json: program.opts().json,
|
|
73
|
+
pretty: program.opts().pretty,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
handleError(error);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=product.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product.js","sourceRoot":"","sources":["../../../src/cli/commands/product.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { registerProductCommands } from "./commands/product.js";
|
|
4
|
+
import { registerBrandCommands } from "./commands/brand.js";
|
|
5
|
+
import { registerProductCollectionCommands } from "./commands/product-collection.js";
|
|
6
|
+
import { registerFinishCollectionCommands } from "./commands/finish-collection.js";
|
|
7
|
+
import { registerConfigCommands } from "./commands/config.js";
|
|
8
|
+
const program = new Command();
|
|
9
|
+
program
|
|
10
|
+
.name("r3")
|
|
11
|
+
.description("R3PLICA CLI — Query the R3PLICA 3D furniture catalog")
|
|
12
|
+
.version("1.0.0")
|
|
13
|
+
.option("--json", "Force JSON output")
|
|
14
|
+
.option("--pretty", "Force formatted table output")
|
|
15
|
+
.option("--verbose", "Show debug info on stderr");
|
|
16
|
+
registerProductCommands(program);
|
|
17
|
+
registerBrandCommands(program);
|
|
18
|
+
registerProductCollectionCommands(program);
|
|
19
|
+
registerFinishCollectionCommands(program);
|
|
20
|
+
registerConfigCommands(program);
|
|
21
|
+
program.parse();
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,iCAAiC,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,EAAE,gCAAgC,EAAE,MAAM,iCAAiC,CAAC;AACnF,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,IAAI,CAAC;KACV,WAAW,CAAC,sDAAsD,CAAC;KACnE,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,QAAQ,EAAE,mBAAmB,CAAC;KACrC,MAAM,CAAC,UAAU,EAAE,8BAA8B,CAAC;KAClD,MAAM,CAAC,WAAW,EAAE,2BAA2B,CAAC,CAAC;AAEpD,uBAAuB,CAAC,OAAO,CAAC,CAAC;AACjC,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,iCAAiC,CAAC,OAAO,CAAC,CAAC;AAC3C,gCAAgC,CAAC,OAAO,CAAC,CAAC;AAC1C,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAEhC,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export declare class ApiError extends Error {
|
|
2
|
+
statusCode?: number | undefined;
|
|
3
|
+
constructor(message: string, statusCode?: number | undefined);
|
|
4
|
+
}
|
|
5
|
+
export declare function listProducts(opts: {
|
|
6
|
+
brand?: string;
|
|
7
|
+
category?: string;
|
|
8
|
+
collection?: string;
|
|
9
|
+
limit?: number;
|
|
10
|
+
page?: number;
|
|
11
|
+
}): Promise<any[]>;
|
|
12
|
+
export declare function searchProducts(query: string, opts: {
|
|
13
|
+
brand?: string;
|
|
14
|
+
category?: string;
|
|
15
|
+
limit?: number;
|
|
16
|
+
}): Promise<any[]>;
|
|
17
|
+
export declare function getProduct(mongoId: string): Promise<any>;
|
|
18
|
+
export declare function listBrands(opts: {
|
|
19
|
+
country?: string;
|
|
20
|
+
limit?: number;
|
|
21
|
+
}): Promise<any[]>;
|
|
22
|
+
export declare function searchBrands(query: string): Promise<any[]>;
|
|
23
|
+
export declare function listProductCollections(opts: {
|
|
24
|
+
brand?: string;
|
|
25
|
+
limit?: number;
|
|
26
|
+
page?: number;
|
|
27
|
+
sort?: string;
|
|
28
|
+
order?: string;
|
|
29
|
+
}): Promise<any[]>;
|
|
30
|
+
export declare function searchProductCollections(query: string): Promise<any[]>;
|
|
31
|
+
export declare function listFinishCollections(opts: {
|
|
32
|
+
brand?: string;
|
|
33
|
+
category?: string;
|
|
34
|
+
limit?: number;
|
|
35
|
+
page?: number;
|
|
36
|
+
}): Promise<any[]>;
|
|
37
|
+
export declare function searchFinishCollections(query: string): Promise<any[]>;
|
|
38
|
+
export declare function getFinishCollection(mongoId: string): Promise<any>;
|
package/dist/core/api.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { getApiUrl } from "./config.js";
|
|
2
|
+
const TIMEOUT_MS = 10_000;
|
|
3
|
+
export class ApiError extends Error {
|
|
4
|
+
statusCode;
|
|
5
|
+
constructor(message, statusCode) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.statusCode = statusCode;
|
|
8
|
+
this.name = "ApiError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
async function request(path, params = {}) {
|
|
12
|
+
const baseUrl = getApiUrl();
|
|
13
|
+
const url = new URL(path, baseUrl.endsWith("/") ? baseUrl : baseUrl + "/");
|
|
14
|
+
for (const [key, value] of Object.entries(params)) {
|
|
15
|
+
if (value)
|
|
16
|
+
url.searchParams.set(key, value);
|
|
17
|
+
}
|
|
18
|
+
const controller = new AbortController();
|
|
19
|
+
const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
20
|
+
try {
|
|
21
|
+
const response = await fetch(url.toString(), {
|
|
22
|
+
signal: controller.signal,
|
|
23
|
+
headers: { "Accept": "application/json" },
|
|
24
|
+
});
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw new ApiError(`API returned ${response.status}: ${response.statusText}`, response.status);
|
|
27
|
+
}
|
|
28
|
+
const data = await response.json();
|
|
29
|
+
if (data.status === false) {
|
|
30
|
+
throw new ApiError(data.message || "API returned an error");
|
|
31
|
+
}
|
|
32
|
+
return data;
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (error instanceof ApiError)
|
|
36
|
+
throw error;
|
|
37
|
+
if (error instanceof Error) {
|
|
38
|
+
if (error.name === "AbortError") {
|
|
39
|
+
throw new ApiError("Request timed out after 10s");
|
|
40
|
+
}
|
|
41
|
+
if (error.message.includes("fetch failed") || error.message.includes("ECONNREFUSED")) {
|
|
42
|
+
throw new ApiError(`Cannot connect to R3PLICA API (${baseUrl})\n Check your connection or run: r3 config set api-url <url>`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
throw new ApiError(`Unexpected error: ${error}`);
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
clearTimeout(timeout);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Build the q= filter string from key-value pairs */
|
|
52
|
+
function buildQuery(filters) {
|
|
53
|
+
return Object.entries(filters)
|
|
54
|
+
.filter(([, v]) => v !== undefined && v !== "")
|
|
55
|
+
.map(([k, v]) => `${k}:${v}`)
|
|
56
|
+
.join(";");
|
|
57
|
+
}
|
|
58
|
+
// ── Products ──────────────────────────────────────────────
|
|
59
|
+
export async function listProducts(opts) {
|
|
60
|
+
const q = buildQuery({
|
|
61
|
+
brand: opts.brand,
|
|
62
|
+
category: opts.category,
|
|
63
|
+
collection: opts.collection,
|
|
64
|
+
});
|
|
65
|
+
const data = await request("products", {
|
|
66
|
+
...(q && { q }),
|
|
67
|
+
page: String(opts.page || 1),
|
|
68
|
+
limit: String(opts.limit || 20),
|
|
69
|
+
});
|
|
70
|
+
return data.products || [];
|
|
71
|
+
}
|
|
72
|
+
export async function searchProducts(query, opts) {
|
|
73
|
+
const q = buildQuery({
|
|
74
|
+
name: query,
|
|
75
|
+
brand: opts.brand,
|
|
76
|
+
category: opts.category,
|
|
77
|
+
});
|
|
78
|
+
const data = await request("products", {
|
|
79
|
+
q,
|
|
80
|
+
limit: String(opts.limit || 20),
|
|
81
|
+
});
|
|
82
|
+
return data.products || [];
|
|
83
|
+
}
|
|
84
|
+
export async function getProduct(mongoId) {
|
|
85
|
+
const data = await request("products", {
|
|
86
|
+
q: `mongo_id:${mongoId}`,
|
|
87
|
+
limit: "1",
|
|
88
|
+
});
|
|
89
|
+
const products = data.products || [];
|
|
90
|
+
if (products.length === 0) {
|
|
91
|
+
throw new ApiError(`Product "${mongoId}" not found`);
|
|
92
|
+
}
|
|
93
|
+
return products[0];
|
|
94
|
+
}
|
|
95
|
+
// ── Brands ────────────────────────────────────────────────
|
|
96
|
+
export async function listBrands(opts) {
|
|
97
|
+
const data = await request("brands", {
|
|
98
|
+
limit: String(opts.limit || 50),
|
|
99
|
+
});
|
|
100
|
+
let brands = data.brands || [];
|
|
101
|
+
// Client-side filtering (brands endpoint has no q= support)
|
|
102
|
+
if (opts.country) {
|
|
103
|
+
const country = opts.country.toLowerCase();
|
|
104
|
+
brands = brands.filter((b) => b.contact?.country?.toLowerCase().includes(country));
|
|
105
|
+
}
|
|
106
|
+
return brands;
|
|
107
|
+
}
|
|
108
|
+
export async function searchBrands(query) {
|
|
109
|
+
const data = await request("brands", { limit: "9999" });
|
|
110
|
+
const brands = data.brands || [];
|
|
111
|
+
const q = query.toLowerCase();
|
|
112
|
+
return brands.filter((b) => b.name?.toLowerCase().includes(q) ||
|
|
113
|
+
b.description?.toLowerCase().includes(q));
|
|
114
|
+
}
|
|
115
|
+
// ── Product Collections ───────────────────────────────────
|
|
116
|
+
export async function listProductCollections(opts) {
|
|
117
|
+
const q = buildQuery({ brand: opts.brand });
|
|
118
|
+
const data = await request("product-collections", {
|
|
119
|
+
...(q && { q }),
|
|
120
|
+
page: String(opts.page || 1),
|
|
121
|
+
limit: String(opts.limit || 20),
|
|
122
|
+
...(opts.sort && { sort: opts.sort }),
|
|
123
|
+
...(opts.order && { order: opts.order }),
|
|
124
|
+
});
|
|
125
|
+
return data.product_collections || [];
|
|
126
|
+
}
|
|
127
|
+
export async function searchProductCollections(query) {
|
|
128
|
+
const q = buildQuery({ name: query });
|
|
129
|
+
const data = await request("product-collections", { q, limit: "100" });
|
|
130
|
+
return data.product_collections || [];
|
|
131
|
+
}
|
|
132
|
+
// ── Finish Collections ────────────────────────────────────
|
|
133
|
+
export async function listFinishCollections(opts) {
|
|
134
|
+
const q = buildQuery({ brand: opts.brand, category: opts.category });
|
|
135
|
+
const data = await request("finish-collections", {
|
|
136
|
+
q,
|
|
137
|
+
page: String(opts.page || 1),
|
|
138
|
+
limit: String(opts.limit || 20),
|
|
139
|
+
});
|
|
140
|
+
return data.finish_collections || [];
|
|
141
|
+
}
|
|
142
|
+
export async function searchFinishCollections(query) {
|
|
143
|
+
const q = buildQuery({ name: query });
|
|
144
|
+
const data = await request("finish-collections", { q, limit: "100" });
|
|
145
|
+
return data.finish_collections || [];
|
|
146
|
+
}
|
|
147
|
+
export async function getFinishCollection(mongoId) {
|
|
148
|
+
const data = await request("finish-collections", {
|
|
149
|
+
q: `mongo_id:${mongoId}`,
|
|
150
|
+
limit: "1",
|
|
151
|
+
});
|
|
152
|
+
const collections = data.finish_collections || [];
|
|
153
|
+
if (collections.length === 0) {
|
|
154
|
+
throw new ApiError(`Finish collection "${mongoId}" not found`);
|
|
155
|
+
}
|
|
156
|
+
return collections[0];
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/core/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
const CONFIG_DIR = join(homedir(), ".config", "r3");
|
|
5
|
+
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
6
|
+
const DEFAULT_API_URL = "https://api.r3plica.space/api/r3vault";
|
|
7
|
+
function loadConfig() {
|
|
8
|
+
try {
|
|
9
|
+
if (existsSync(CONFIG_FILE)) {
|
|
10
|
+
const raw = readFileSync(CONFIG_FILE, "utf-8");
|
|
11
|
+
return JSON.parse(raw);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// Ignore corrupt config
|
|
16
|
+
}
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
function saveConfig(config) {
|
|
20
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
21
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n");
|
|
22
|
+
}
|
|
23
|
+
export function getApiUrl() {
|
|
24
|
+
if (process.env.R3_API_URL) {
|
|
25
|
+
return process.env.R3_API_URL;
|
|
26
|
+
}
|
|
27
|
+
const config = loadConfig();
|
|
28
|
+
return config.apiUrl || DEFAULT_API_URL;
|
|
29
|
+
}
|
|
30
|
+
export function setConfigValue(key, value) {
|
|
31
|
+
if (key !== "api-url") {
|
|
32
|
+
throw new Error(`Unknown config key: "${key}". Available keys: api-url`);
|
|
33
|
+
}
|
|
34
|
+
const config = loadConfig();
|
|
35
|
+
config.apiUrl = value;
|
|
36
|
+
saveConfig(config);
|
|
37
|
+
}
|
|
38
|
+
export function getFullConfig() {
|
|
39
|
+
const config = loadConfig();
|
|
40
|
+
return {
|
|
41
|
+
"api-url": getApiUrl(),
|
|
42
|
+
"source": process.env.R3_API_URL
|
|
43
|
+
? "environment (R3_API_URL)"
|
|
44
|
+
: config.apiUrl
|
|
45
|
+
? "config file"
|
|
46
|
+
: "default",
|
|
47
|
+
"config-path": CONFIG_FILE,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAE7B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;AACpD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AACpD,MAAM,eAAe,GAAG,uCAAuC,CAAC;AAMhE,SAAS,UAAU;IACjB,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5B,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,wBAAwB;IAC1B,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,UAAU,CAAC,MAAgB;IAClC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;QAC3B,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IAChC,CAAC;IACD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,MAAM,CAAC,MAAM,IAAI,eAAe,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,KAAa;IACvD,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,4BAA4B,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,UAAU,CAAC,MAAM,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO;QACL,SAAS,EAAE,SAAS,EAAE;QACtB,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;YAC9B,CAAC,CAAC,0BAA0B;YAC5B,CAAC,CAAC,MAAM,CAAC,MAAM;gBACb,CAAC,CAAC,aAAa;gBACf,CAAC,CAAC,SAAS;QACf,aAAa,EAAE,WAAW;KAC3B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function handleError(error: unknown): never;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ApiError } from "./api.js";
|
|
2
|
+
export function handleError(error) {
|
|
3
|
+
if (error instanceof ApiError) {
|
|
4
|
+
process.stderr.write(`Error: ${error.message}\n`);
|
|
5
|
+
}
|
|
6
|
+
else {
|
|
7
|
+
process.stderr.write(`Error: ${error}\n`);
|
|
8
|
+
}
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;IACpD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface Column {
|
|
2
|
+
key: string;
|
|
3
|
+
header: string;
|
|
4
|
+
width?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare function output(data: any, opts: {
|
|
7
|
+
json?: boolean;
|
|
8
|
+
pretty?: boolean;
|
|
9
|
+
columns?: Column[];
|
|
10
|
+
label?: string;
|
|
11
|
+
query?: string;
|
|
12
|
+
}): void;
|
|
13
|
+
/** Output a single item detail (for `get` commands) */
|
|
14
|
+
export declare function outputDetail(data: any, opts: {
|
|
15
|
+
json?: boolean;
|
|
16
|
+
pretty?: boolean;
|
|
17
|
+
}): void;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
function isTTY() {
|
|
2
|
+
return process.stdout.isTTY === true;
|
|
3
|
+
}
|
|
4
|
+
export function output(data, opts) {
|
|
5
|
+
const forceJson = opts.json === true;
|
|
6
|
+
const forcePretty = opts.pretty === true;
|
|
7
|
+
const useTable = forcePretty || (!forceJson && isTTY());
|
|
8
|
+
if (!useTable || !opts.columns) {
|
|
9
|
+
process.stdout.write(JSON.stringify(data, null, 2) + "\n");
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const items = Array.isArray(data) ? data : [data];
|
|
13
|
+
if (items.length === 0) {
|
|
14
|
+
const label = opts.label || "items";
|
|
15
|
+
const suffix = opts.query ? ` matching "${opts.query}"` : "";
|
|
16
|
+
process.stderr.write(`No ${label}s found${suffix}\n`);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const columns = opts.columns;
|
|
20
|
+
// Calculate column widths
|
|
21
|
+
const widths = columns.map((col) => {
|
|
22
|
+
const headerLen = col.header.length;
|
|
23
|
+
const maxDataLen = items.reduce((max, item) => {
|
|
24
|
+
const val = String(resolveValue(item, col.key) ?? "");
|
|
25
|
+
return Math.max(max, val.length);
|
|
26
|
+
}, 0);
|
|
27
|
+
return col.width || Math.min(Math.max(headerLen, maxDataLen) + 2, 40);
|
|
28
|
+
});
|
|
29
|
+
// Header
|
|
30
|
+
const header = columns.map((col, i) => col.header.padEnd(widths[i])).join("");
|
|
31
|
+
process.stdout.write("\n " + header + "\n");
|
|
32
|
+
// Rows
|
|
33
|
+
for (const item of items) {
|
|
34
|
+
const row = columns
|
|
35
|
+
.map((col, i) => {
|
|
36
|
+
const val = String(resolveValue(item, col.key) ?? "");
|
|
37
|
+
return val.substring(0, widths[i] - 1).padEnd(widths[i]);
|
|
38
|
+
})
|
|
39
|
+
.join("");
|
|
40
|
+
process.stdout.write(" " + row + "\n");
|
|
41
|
+
}
|
|
42
|
+
// Footer
|
|
43
|
+
const label = opts.label || "item";
|
|
44
|
+
const count = items.length;
|
|
45
|
+
process.stdout.write(`\n ${count} ${label}${count !== 1 ? "s" : ""} found\n\n`);
|
|
46
|
+
}
|
|
47
|
+
/** Resolve a dot-path key like "brand.name" from an object.
|
|
48
|
+
* If a value along the path is an array, uses the first element. */
|
|
49
|
+
function resolveValue(obj, key) {
|
|
50
|
+
return key.split(".").reduce((acc, part) => {
|
|
51
|
+
if (acc === null || acc === undefined)
|
|
52
|
+
return undefined;
|
|
53
|
+
const val = acc[part];
|
|
54
|
+
return Array.isArray(val) ? val[0] : val;
|
|
55
|
+
}, obj);
|
|
56
|
+
}
|
|
57
|
+
/** Output a single item detail (for `get` commands) */
|
|
58
|
+
export function outputDetail(data, opts) {
|
|
59
|
+
const forceJson = opts.json === true;
|
|
60
|
+
const forcePretty = opts.pretty === true;
|
|
61
|
+
const useFormatted = forcePretty || (!forceJson && isTTY());
|
|
62
|
+
if (!useFormatted) {
|
|
63
|
+
process.stdout.write(JSON.stringify(data, null, 2) + "\n");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
process.stdout.write("\n");
|
|
67
|
+
printObject(data, 0);
|
|
68
|
+
process.stdout.write("\n");
|
|
69
|
+
}
|
|
70
|
+
function printObject(obj, indent) {
|
|
71
|
+
const pad = " ".repeat(indent + 1);
|
|
72
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
73
|
+
if (value === null || value === undefined)
|
|
74
|
+
continue;
|
|
75
|
+
if (Array.isArray(value)) {
|
|
76
|
+
process.stdout.write(`${pad}${key}:\n`);
|
|
77
|
+
for (const item of value) {
|
|
78
|
+
if (typeof item === "object" && item !== null) {
|
|
79
|
+
process.stdout.write(`${pad} -\n`);
|
|
80
|
+
printObject(item, indent + 2);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
process.stdout.write(`${pad} - ${item}\n`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else if (typeof value === "object") {
|
|
88
|
+
process.stdout.write(`${pad}${key}:\n`);
|
|
89
|
+
printObject(value, indent + 1);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
process.stdout.write(`${pad}${key}: ${value}\n`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../src/core/formatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import * as api from "../core/api.js";
|
|
6
|
+
const server = new Server({ name: "r3plica-mcp", version: "1.0.0" }, { capabilities: { tools: {} } });
|
|
7
|
+
const tools = [
|
|
8
|
+
{
|
|
9
|
+
name: "product_list",
|
|
10
|
+
description: "List R3PLICA products with optional filters (brand, category, collection)",
|
|
11
|
+
inputSchema: {
|
|
12
|
+
type: "object",
|
|
13
|
+
properties: {
|
|
14
|
+
brand: { type: "string", description: "Filter by brand name" },
|
|
15
|
+
category: { type: "string", description: "Filter by product category" },
|
|
16
|
+
collection: { type: "string", description: "Filter by collection name" },
|
|
17
|
+
limit: { type: "number", description: "Max results (default: 20)" },
|
|
18
|
+
page: { type: "number", description: "Page number (default: 1)" },
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "product_search",
|
|
24
|
+
description: "Search R3PLICA products by text query",
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
query: { type: "string", description: "Text search query" },
|
|
29
|
+
brand: { type: "string", description: "Filter by brand name" },
|
|
30
|
+
category: { type: "string", description: "Filter by product category" },
|
|
31
|
+
limit: { type: "number", description: "Max results (default: 20)" },
|
|
32
|
+
},
|
|
33
|
+
required: ["query"],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "product_get",
|
|
38
|
+
description: "Get detailed information about a specific product including parts and finish options",
|
|
39
|
+
inputSchema: {
|
|
40
|
+
type: "object",
|
|
41
|
+
properties: {
|
|
42
|
+
id: { type: "string", description: "Product mongo_id" },
|
|
43
|
+
},
|
|
44
|
+
required: ["id"],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "brand_list",
|
|
49
|
+
description: "List all public R3PLICA brands",
|
|
50
|
+
inputSchema: {
|
|
51
|
+
type: "object",
|
|
52
|
+
properties: {
|
|
53
|
+
country: { type: "string", description: "Filter by country" },
|
|
54
|
+
limit: { type: "number", description: "Max results (default: 50)" },
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "brand_search",
|
|
60
|
+
description: "Search R3PLICA brands by name",
|
|
61
|
+
inputSchema: {
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: {
|
|
64
|
+
query: { type: "string", description: "Brand name search query" },
|
|
65
|
+
},
|
|
66
|
+
required: ["query"],
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "product_collection_list",
|
|
71
|
+
description: "List product collections (furniture lines)",
|
|
72
|
+
inputSchema: {
|
|
73
|
+
type: "object",
|
|
74
|
+
properties: {
|
|
75
|
+
brand: { type: "string", description: "Filter by brand name" },
|
|
76
|
+
limit: { type: "number", description: "Max results (default: 20)" },
|
|
77
|
+
page: { type: "number", description: "Page number (default: 1)" },
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: "product_collection_search",
|
|
83
|
+
description: "Search product collections by name",
|
|
84
|
+
inputSchema: {
|
|
85
|
+
type: "object",
|
|
86
|
+
properties: {
|
|
87
|
+
query: { type: "string", description: "Collection name search query" },
|
|
88
|
+
},
|
|
89
|
+
required: ["query"],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "finish_collection_list",
|
|
94
|
+
description: "List finish collections (material finishes/shaders)",
|
|
95
|
+
inputSchema: {
|
|
96
|
+
type: "object",
|
|
97
|
+
properties: {
|
|
98
|
+
brand: { type: "string", description: "Filter by brand name" },
|
|
99
|
+
category: { type: "string", description: "Filter by category (Wood, Fabric, Metal, etc.)" },
|
|
100
|
+
limit: { type: "number", description: "Max results (default: 20)" },
|
|
101
|
+
page: { type: "number", description: "Page number (default: 1)" },
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "finish_collection_search",
|
|
107
|
+
description: "Search finish collections by name",
|
|
108
|
+
inputSchema: {
|
|
109
|
+
type: "object",
|
|
110
|
+
properties: {
|
|
111
|
+
query: { type: "string", description: "Finish collection name search query" },
|
|
112
|
+
},
|
|
113
|
+
required: ["query"],
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: "finish_collection_get",
|
|
118
|
+
description: "Get finish collection details with all individual finishes",
|
|
119
|
+
inputSchema: {
|
|
120
|
+
type: "object",
|
|
121
|
+
properties: {
|
|
122
|
+
id: { type: "string", description: "Finish collection mongo_id" },
|
|
123
|
+
},
|
|
124
|
+
required: ["id"],
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
|
|
129
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
130
|
+
const { name, arguments: args } = request.params;
|
|
131
|
+
try {
|
|
132
|
+
let result;
|
|
133
|
+
switch (name) {
|
|
134
|
+
case "product_list":
|
|
135
|
+
result = await api.listProducts(args);
|
|
136
|
+
break;
|
|
137
|
+
case "product_search":
|
|
138
|
+
result = await api.searchProducts(args.query, args);
|
|
139
|
+
break;
|
|
140
|
+
case "product_get":
|
|
141
|
+
result = await api.getProduct(args.id);
|
|
142
|
+
break;
|
|
143
|
+
case "brand_list":
|
|
144
|
+
result = await api.listBrands(args);
|
|
145
|
+
break;
|
|
146
|
+
case "brand_search":
|
|
147
|
+
result = await api.searchBrands(args.query);
|
|
148
|
+
break;
|
|
149
|
+
case "product_collection_list":
|
|
150
|
+
result = await api.listProductCollections(args);
|
|
151
|
+
break;
|
|
152
|
+
case "product_collection_search":
|
|
153
|
+
result = await api.searchProductCollections(args.query);
|
|
154
|
+
break;
|
|
155
|
+
case "finish_collection_list":
|
|
156
|
+
result = await api.listFinishCollections(args);
|
|
157
|
+
break;
|
|
158
|
+
case "finish_collection_search":
|
|
159
|
+
result = await api.searchFinishCollections(args.query);
|
|
160
|
+
break;
|
|
161
|
+
case "finish_collection_get":
|
|
162
|
+
result = await api.getFinishCollection(args.id);
|
|
163
|
+
break;
|
|
164
|
+
default:
|
|
165
|
+
return {
|
|
166
|
+
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
167
|
+
isError: true,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
return {
|
|
176
|
+
content: [{
|
|
177
|
+
type: "text",
|
|
178
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
179
|
+
}],
|
|
180
|
+
isError: true,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
async function main() {
|
|
185
|
+
const transport = new StdioServerTransport();
|
|
186
|
+
await server.connect(transport);
|
|
187
|
+
}
|
|
188
|
+
main().catch((error) => {
|
|
189
|
+
console.error(`MCP server failed: ${error}`);
|
|
190
|
+
process.exit(1);
|
|
191
|
+
});
|
|
192
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "r3plica",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "R3PLICA CLI — Query the R3PLICA 3D furniture catalog",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"r3": "dist/cli/index.js",
|
|
8
|
+
"r3-mcp": "dist/mcp/server.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsc --watch",
|
|
13
|
+
"start": "node dist/cli/index.js",
|
|
14
|
+
"start:mcp": "node dist/mcp/server.js",
|
|
15
|
+
"clean": "rm -rf dist",
|
|
16
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
17
|
+
},
|
|
18
|
+
"keywords": ["r3plica", "cli", "furniture", "3d", "design", "architecture", "mcp"],
|
|
19
|
+
"author": "R3PLICA S.r.l.",
|
|
20
|
+
"license": "Proprietary",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/R3PLICAsrl/r3-cli.git"
|
|
24
|
+
},
|
|
25
|
+
"files": ["dist/**/*", "README.md", "package.json"],
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"commander": "^13.1.0",
|
|
28
|
+
"@modelcontextprotocol/sdk": "^1.12.1"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"typescript": "^5.8.3",
|
|
32
|
+
"@types/node": "^22.15.24"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=20.0.0"
|
|
36
|
+
}
|
|
37
|
+
}
|