@polypad/mcp 0.1.1 → 0.1.6
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 +9 -5
- package/dist/THIRD_PARTY_NOTICES.txt +260 -0
- package/dist/index.js +127 -64
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -6,15 +6,15 @@ The server runs on your own computer. Nothing is uploaded and there is no accoun
|
|
|
6
6
|
|
|
7
7
|
## Set up
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
**Claude Desktop, one click (no Node.js or terminal needed):** download [polypad.mcpb](https://polypad.ink/downloads/polypad.mcpb) (also behind **Connect AI** on polypad.ink) and open it; Claude Desktop shows an Install button. It runs this same server with Claude Desktop's built-in Node.
|
|
10
10
|
|
|
11
|
-
**Claude Code
|
|
11
|
+
**Claude Code and Cursor:** you need Node.js 22 or newer. `npx` downloads the server on first use.
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
14
|
claude mcp add polypad -- npx -y @polypad/mcp
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
**
|
|
17
|
+
**Cursor** (`.cursor/mcp.json` in a project, or `~/.cursor/mcp.json` for all projects):
|
|
18
18
|
|
|
19
19
|
```json
|
|
20
20
|
{
|
|
@@ -27,7 +27,7 @@ claude mcp add polypad -- npx -y @polypad/mcp
|
|
|
27
27
|
}
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
The same block works in Claude Desktop's `claude_desktop_config.json` (Settings, Developer, Edit Config, then restart) if you prefer it to the extension.
|
|
31
31
|
|
|
32
32
|
## Connect
|
|
33
33
|
|
|
@@ -44,7 +44,7 @@ You can add Polypad to Claude Code and Claude Desktop (or Cursor) and use them a
|
|
|
44
44
|
|
|
45
45
|
## Troubleshooting
|
|
46
46
|
|
|
47
|
-
- **"Server not running"** in the dialog: your AI client has not started the server yet. Ask it something about Polypad, and check `npx -y @polypad/mcp --help` works (Node 22 or newer).
|
|
47
|
+
- **"Server not running"** in the dialog: your AI client has not started the server yet. Ask it something about Polypad, and check `npx -y @polypad/mcp --help` works (Node 22 or newer; the Claude Desktop extension needs neither).
|
|
48
48
|
- **"Wrong code"**: enter the code from the latest start. It changes whenever the connection's owner restarts.
|
|
49
49
|
- **"Port 41720 is already in use"** (the tools say so): a program that is not a Polypad MCP server (or an old 0.1.0 one) holds the port. Close it, or use `--port 41721` here and in the dialog's Advanced section. The server checks again every 2 seconds.
|
|
50
50
|
|
|
@@ -72,4 +72,8 @@ Lengths are in mm and angles in degrees. Sizes can be numbers or formulas over y
|
|
|
72
72
|
- The assistant sees and edits only the project you have open. Disconnect in the dialog cuts it off at any time.
|
|
73
73
|
- Polypad sends nothing to a server. What leaves your machine is what your AI client sends to its model provider: your prompts and the tool results.
|
|
74
74
|
|
|
75
|
+
## Licenses
|
|
76
|
+
|
|
77
|
+
Polypad MCP is MIT licensed. `dist/index.js` bundles a few open-source packages (the MCP SDK, ws, zod and their dependencies); their names, versions and full license texts are in `THIRD_PARTY_NOTICES.txt`, shipped next to it in this package.
|
|
78
|
+
|
|
75
79
|
More: [polypad.ink](https://polypad.ink). License: MIT.
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
THIRD-PARTY NOTICES for @polypad/mcp
|
|
2
|
+
|
|
3
|
+
dist/index.js bundles the open-source packages listed below. Each one is under its own license; the license
|
|
4
|
+
texts are reproduced in full as the packages ship them.
|
|
5
|
+
|
|
6
|
+
@modelcontextprotocol/sdk@1.32.1 (MIT)
|
|
7
|
+
ajv@8.20.0 (MIT)
|
|
8
|
+
ajv-formats@3.0.1 (MIT)
|
|
9
|
+
fast-deep-equal@3.1.3 (MIT)
|
|
10
|
+
fast-uri@3.1.8 (BSD-3-Clause)
|
|
11
|
+
json-schema-traverse@1.0.0 (MIT)
|
|
12
|
+
ws@8.22.0 (MIT)
|
|
13
|
+
zod@4.6.5 (MIT)
|
|
14
|
+
zod-to-json-schema@3.25.2 (ISC)
|
|
15
|
+
|
|
16
|
+
==============================================================================
|
|
17
|
+
@modelcontextprotocol/sdk@1.32.1
|
|
18
|
+
License: MIT
|
|
19
|
+
Source: https://modelcontextprotocol.io
|
|
20
|
+
|
|
21
|
+
MIT License
|
|
22
|
+
|
|
23
|
+
Copyright (c) 2024 Anthropic, PBC
|
|
24
|
+
|
|
25
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
26
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
27
|
+
in the Software without restriction, including without limitation the rights
|
|
28
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
29
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
30
|
+
furnished to do so, subject to the following conditions:
|
|
31
|
+
|
|
32
|
+
The above copyright notice and this permission notice shall be included in all
|
|
33
|
+
copies or substantial portions of the Software.
|
|
34
|
+
|
|
35
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
36
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
37
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
38
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
39
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
40
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
41
|
+
SOFTWARE.
|
|
42
|
+
|
|
43
|
+
==============================================================================
|
|
44
|
+
ajv@8.20.0
|
|
45
|
+
License: MIT
|
|
46
|
+
Source: https://ajv.js.org
|
|
47
|
+
|
|
48
|
+
The MIT License (MIT)
|
|
49
|
+
|
|
50
|
+
Copyright (c) 2015-2021 Evgeny Poberezkin
|
|
51
|
+
|
|
52
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
53
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
54
|
+
in the Software without restriction, including without limitation the rights
|
|
55
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
56
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
57
|
+
furnished to do so, subject to the following conditions:
|
|
58
|
+
|
|
59
|
+
The above copyright notice and this permission notice shall be included in all
|
|
60
|
+
copies or substantial portions of the Software.
|
|
61
|
+
|
|
62
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
63
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
64
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
65
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
66
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
67
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
68
|
+
SOFTWARE.
|
|
69
|
+
|
|
70
|
+
==============================================================================
|
|
71
|
+
ajv-formats@3.0.1
|
|
72
|
+
License: MIT
|
|
73
|
+
Source: https://github.com/ajv-validator/ajv-formats#readme
|
|
74
|
+
|
|
75
|
+
MIT License
|
|
76
|
+
|
|
77
|
+
Copyright (c) 2020 Evgeny Poberezkin
|
|
78
|
+
|
|
79
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
80
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
81
|
+
in the Software without restriction, including without limitation the rights
|
|
82
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
83
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
84
|
+
furnished to do so, subject to the following conditions:
|
|
85
|
+
|
|
86
|
+
The above copyright notice and this permission notice shall be included in all
|
|
87
|
+
copies or substantial portions of the Software.
|
|
88
|
+
|
|
89
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
90
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
91
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
92
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
93
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
94
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
95
|
+
SOFTWARE.
|
|
96
|
+
|
|
97
|
+
==============================================================================
|
|
98
|
+
fast-deep-equal@3.1.3
|
|
99
|
+
License: MIT
|
|
100
|
+
Source: https://github.com/epoberezkin/fast-deep-equal#readme
|
|
101
|
+
|
|
102
|
+
MIT License
|
|
103
|
+
|
|
104
|
+
Copyright (c) 2017 Evgeny Poberezkin
|
|
105
|
+
|
|
106
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
107
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
108
|
+
in the Software without restriction, including without limitation the rights
|
|
109
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
110
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
111
|
+
furnished to do so, subject to the following conditions:
|
|
112
|
+
|
|
113
|
+
The above copyright notice and this permission notice shall be included in all
|
|
114
|
+
copies or substantial portions of the Software.
|
|
115
|
+
|
|
116
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
117
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
118
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
119
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
120
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
121
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
122
|
+
SOFTWARE.
|
|
123
|
+
|
|
124
|
+
==============================================================================
|
|
125
|
+
fast-uri@3.1.8
|
|
126
|
+
License: BSD-3-Clause
|
|
127
|
+
Source: https://github.com/fastify/fast-uri
|
|
128
|
+
|
|
129
|
+
Copyright (c) 2011-2021, Gary Court until https://github.com/garycourt/uri-js/commit/a1acf730b4bba3f1097c9f52e7d9d3aba8cdcaae
|
|
130
|
+
Copyright (c) 2021-present The Fastify team <https://github.com/fastify/fastify#team>
|
|
131
|
+
All rights reserved.
|
|
132
|
+
|
|
133
|
+
Redistribution and use in source and binary forms, with or without
|
|
134
|
+
modification, are permitted provided that the following conditions are met:
|
|
135
|
+
* Redistributions of source code must retain the above copyright
|
|
136
|
+
notice, this list of conditions and the following disclaimer.
|
|
137
|
+
* Redistributions in binary form must reproduce the above copyright
|
|
138
|
+
notice, this list of conditions and the following disclaimer in the
|
|
139
|
+
documentation and/or other materials provided with the distribution.
|
|
140
|
+
* The names of any contributors may not be used to endorse or promote
|
|
141
|
+
products derived from this software without specific prior written
|
|
142
|
+
permission.
|
|
143
|
+
|
|
144
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
145
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
146
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
147
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
|
|
148
|
+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
149
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
150
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
151
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
152
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
153
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
154
|
+
|
|
155
|
+
* * *
|
|
156
|
+
|
|
157
|
+
The complete list of contributors can be found at:
|
|
158
|
+
- https://github.com/garycourt/uri-js/graphs/contributors
|
|
159
|
+
|
|
160
|
+
==============================================================================
|
|
161
|
+
json-schema-traverse@1.0.0
|
|
162
|
+
License: MIT
|
|
163
|
+
Source: https://github.com/epoberezkin/json-schema-traverse#readme
|
|
164
|
+
|
|
165
|
+
MIT License
|
|
166
|
+
|
|
167
|
+
Copyright (c) 2017 Evgeny Poberezkin
|
|
168
|
+
|
|
169
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
170
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
171
|
+
in the Software without restriction, including without limitation the rights
|
|
172
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
173
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
174
|
+
furnished to do so, subject to the following conditions:
|
|
175
|
+
|
|
176
|
+
The above copyright notice and this permission notice shall be included in all
|
|
177
|
+
copies or substantial portions of the Software.
|
|
178
|
+
|
|
179
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
180
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
181
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
182
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
183
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
184
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
185
|
+
SOFTWARE.
|
|
186
|
+
|
|
187
|
+
==============================================================================
|
|
188
|
+
ws@8.22.0
|
|
189
|
+
License: MIT
|
|
190
|
+
Source: https://github.com/websockets/ws
|
|
191
|
+
|
|
192
|
+
Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
|
193
|
+
Copyright (c) 2013 Arnout Kazemier and contributors
|
|
194
|
+
Copyright (c) 2016 Luigi Pinca and contributors
|
|
195
|
+
|
|
196
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
197
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
198
|
+
the Software without restriction, including without limitation the rights to
|
|
199
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
200
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
201
|
+
subject to the following conditions:
|
|
202
|
+
|
|
203
|
+
The above copyright notice and this permission notice shall be included in all
|
|
204
|
+
copies or substantial portions of the Software.
|
|
205
|
+
|
|
206
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
207
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
208
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
209
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
210
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
211
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
212
|
+
|
|
213
|
+
==============================================================================
|
|
214
|
+
zod@4.6.5
|
|
215
|
+
License: MIT
|
|
216
|
+
Source: https://zod.dev
|
|
217
|
+
|
|
218
|
+
MIT License
|
|
219
|
+
|
|
220
|
+
Copyright (c) 2025 Colin McDonnell
|
|
221
|
+
|
|
222
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
223
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
224
|
+
in the Software without restriction, including without limitation the rights
|
|
225
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
226
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
227
|
+
furnished to do so, subject to the following conditions:
|
|
228
|
+
|
|
229
|
+
The above copyright notice and this permission notice shall be included in all
|
|
230
|
+
copies or substantial portions of the Software.
|
|
231
|
+
|
|
232
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
233
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
234
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
235
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
236
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
237
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
238
|
+
SOFTWARE.
|
|
239
|
+
|
|
240
|
+
==============================================================================
|
|
241
|
+
zod-to-json-schema@3.25.2
|
|
242
|
+
License: ISC
|
|
243
|
+
Source: https://github.com/StefanTerdell/zod-to-json-schema
|
|
244
|
+
|
|
245
|
+
ISC License
|
|
246
|
+
|
|
247
|
+
Copyright (c) 2020, Stefan Terdell
|
|
248
|
+
|
|
249
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
250
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
251
|
+
copyright notice and this permission notice appear in all copies.
|
|
252
|
+
|
|
253
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
254
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
255
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
256
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
257
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
258
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
259
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
260
|
+
|
package/dist/index.js
CHANGED
|
@@ -34241,7 +34241,7 @@ var rawSketchShape = { ...sketchShape, constraints: external_exports.array(RawSk
|
|
|
34241
34241
|
var SketchSchema = external_exports.object(sketchShape).superRefine(validateSketch);
|
|
34242
34242
|
|
|
34243
34243
|
// ../../packages/document/src/project.ts
|
|
34244
|
-
var SCHEMA_VERSION =
|
|
34244
|
+
var SCHEMA_VERSION = 18;
|
|
34245
34245
|
var MAX_SNAPSHOT_NAME = 80;
|
|
34246
34246
|
var MAX_PATTERN_COUNT = 100;
|
|
34247
34247
|
var MAX_PATTERN_COPIES = 400;
|
|
@@ -34269,7 +34269,10 @@ function makeSchemas(v, constraint) {
|
|
|
34269
34269
|
external_exports.object({ kind: external_exports.literal("box"), width: pos, depth: pos, height: pos }),
|
|
34270
34270
|
external_exports.object({ kind: external_exports.literal("cylinder"), radius: pos, height: pos }),
|
|
34271
34271
|
external_exports.object({ kind: external_exports.literal("sphere"), radius: pos }),
|
|
34272
|
-
external_exports.object({ kind: external_exports.literal("cone"), radius: pos, topRadius: nonneg, height: pos })
|
|
34272
|
+
external_exports.object({ kind: external_exports.literal("cone"), radius: pos, topRadius: nonneg, height: pos }),
|
|
34273
|
+
external_exports.object({ kind: external_exports.literal("torus"), radius: pos, tubeRadius: pos }),
|
|
34274
|
+
external_exports.object({ kind: external_exports.literal("tube"), radius: pos, innerRadius: pos, height: pos }),
|
|
34275
|
+
external_exports.object({ kind: external_exports.literal("wedge"), width: pos, depth: pos, height: pos, topWidth: nonneg })
|
|
34273
34276
|
]);
|
|
34274
34277
|
const PrimitiveFeatureSchema = external_exports.object({
|
|
34275
34278
|
...featureBase,
|
|
@@ -34333,37 +34336,43 @@ function makeSchemas(v, constraint) {
|
|
|
34333
34336
|
});
|
|
34334
34337
|
const direction = external_exports.object({ axis: external_exports.enum(["x", "y", "z"]), flip: external_exports.boolean().default(false) });
|
|
34335
34338
|
const count = v(external_exports.number().int().min(2).max(MAX_PATTERN_COUNT));
|
|
34339
|
+
const LayoutSchema = external_exports.discriminatedUnion("kind", [
|
|
34340
|
+
external_exports.object({
|
|
34341
|
+
kind: external_exports.literal("linear"),
|
|
34342
|
+
direction,
|
|
34343
|
+
count,
|
|
34344
|
+
spacing: pos,
|
|
34345
|
+
second: external_exports.object({ direction, count, spacing: pos }).optional()
|
|
34346
|
+
}),
|
|
34347
|
+
external_exports.object({
|
|
34348
|
+
kind: external_exports.literal("circular"),
|
|
34349
|
+
axis: external_exports.enum(["x", "y", "z"]),
|
|
34350
|
+
centre: vec32,
|
|
34351
|
+
count,
|
|
34352
|
+
// 360 spreads the copies evenly around; less puts the last copy at this angle.
|
|
34353
|
+
angle: v(external_exports.number().gt(0).max(360)).default(360)
|
|
34354
|
+
})
|
|
34355
|
+
]);
|
|
34356
|
+
const gridWithinLimit = (f) => {
|
|
34357
|
+
const layout = f.layout;
|
|
34358
|
+
if (layout.kind !== "linear" || !layout.second) return true;
|
|
34359
|
+
const [a, b] = [layout.count, layout.second.count];
|
|
34360
|
+
return typeof a !== "number" || typeof b !== "number" || a * b <= MAX_PATTERN_COPIES;
|
|
34361
|
+
};
|
|
34362
|
+
const gridIssue = { path: ["layout", "second", "count"], message: `A grid can have at most ${MAX_PATTERN_COPIES} copies (count x second count)` };
|
|
34336
34363
|
const PatternFeatureSchema = external_exports.object({
|
|
34337
34364
|
...featureBase,
|
|
34338
34365
|
type: external_exports.literal("pattern"),
|
|
34339
34366
|
body: external_exports.string(),
|
|
34340
34367
|
result: external_exports.enum(["join", "separate"]).default("join"),
|
|
34341
|
-
layout:
|
|
34342
|
-
|
|
34343
|
-
|
|
34344
|
-
|
|
34345
|
-
|
|
34346
|
-
|
|
34347
|
-
|
|
34348
|
-
|
|
34349
|
-
external_exports.object({
|
|
34350
|
-
kind: external_exports.literal("circular"),
|
|
34351
|
-
axis: external_exports.enum(["x", "y", "z"]),
|
|
34352
|
-
centre: vec32,
|
|
34353
|
-
count,
|
|
34354
|
-
// 360 spreads the copies evenly around; less puts the last copy at this angle.
|
|
34355
|
-
angle: v(external_exports.number().gt(0).max(360)).default(360)
|
|
34356
|
-
})
|
|
34357
|
-
])
|
|
34358
|
-
}).refine(
|
|
34359
|
-
(f) => {
|
|
34360
|
-
const layout = f.layout;
|
|
34361
|
-
if (layout.kind !== "linear" || !layout.second) return true;
|
|
34362
|
-
const [a, b] = [layout.count, layout.second.count];
|
|
34363
|
-
return typeof a !== "number" || typeof b !== "number" || a * b <= MAX_PATTERN_COPIES;
|
|
34364
|
-
},
|
|
34365
|
-
{ path: ["layout", "second", "count"], message: `A grid can have at most ${MAX_PATTERN_COPIES} copies (count x second count)` }
|
|
34366
|
-
);
|
|
34368
|
+
layout: LayoutSchema
|
|
34369
|
+
}).refine(gridWithinLimit, gridIssue);
|
|
34370
|
+
const FeaturePatternSchema = external_exports.object({
|
|
34371
|
+
...featureBase,
|
|
34372
|
+
type: external_exports.literal("featurePattern"),
|
|
34373
|
+
feature: external_exports.string(),
|
|
34374
|
+
layout: LayoutSchema
|
|
34375
|
+
}).refine(gridWithinLimit, gridIssue);
|
|
34367
34376
|
const MirrorFeatureSchema = external_exports.object({
|
|
34368
34377
|
...featureBase,
|
|
34369
34378
|
type: external_exports.literal("mirror"),
|
|
@@ -34429,6 +34438,7 @@ function makeSchemas(v, constraint) {
|
|
|
34429
34438
|
HoleFeatureSchema,
|
|
34430
34439
|
TransformFeatureSchema,
|
|
34431
34440
|
PatternFeatureSchema,
|
|
34441
|
+
FeaturePatternSchema,
|
|
34432
34442
|
MirrorFeatureSchema,
|
|
34433
34443
|
CopyFeatureSchema,
|
|
34434
34444
|
ImportFeatureSchema,
|
|
@@ -34449,6 +34459,15 @@ var modelShape = {
|
|
|
34449
34459
|
features: external_exports.record(external_exports.string(), FeatureSchema),
|
|
34450
34460
|
order: external_exports.array(external_exports.string())
|
|
34451
34461
|
};
|
|
34462
|
+
function holePatternProblem(model, feature) {
|
|
34463
|
+
const source = model.features[feature.feature];
|
|
34464
|
+
if (!source) return "The hole this pattern repeats was deleted";
|
|
34465
|
+
if (source.type !== "hole") return `${source.name} is not a hole; a hole pattern repeats a hole`;
|
|
34466
|
+
const at = model.order.indexOf(feature.id);
|
|
34467
|
+
const from = model.order.indexOf(source.id);
|
|
34468
|
+
if (from < 0 || at >= 0 && from > at) return `${source.name} comes after this pattern; a hole pattern repeats an earlier hole`;
|
|
34469
|
+
return null;
|
|
34470
|
+
}
|
|
34452
34471
|
function checkModel(model, ctx) {
|
|
34453
34472
|
const ids = Object.keys(model.features);
|
|
34454
34473
|
if (new Set(model.order).size !== model.order.length) {
|
|
@@ -34461,6 +34480,11 @@ function checkModel(model, ctx) {
|
|
|
34461
34480
|
if (model.features[id].id !== id) {
|
|
34462
34481
|
ctx.addIssue({ code: "custom", path: ["features", id], message: "Feature id mismatch" });
|
|
34463
34482
|
}
|
|
34483
|
+
const feature = model.features[id];
|
|
34484
|
+
if (feature.type === "featurePattern") {
|
|
34485
|
+
const problem = holePatternProblem(model, feature);
|
|
34486
|
+
if (problem) ctx.addIssue({ code: "custom", path: ["features", id, "feature"], message: problem });
|
|
34487
|
+
}
|
|
34464
34488
|
}
|
|
34465
34489
|
}
|
|
34466
34490
|
var SnapshotSchema = external_exports.object({
|
|
@@ -34654,6 +34678,26 @@ var patternDirection = external_exports.object({
|
|
|
34654
34678
|
axis: external_exports.enum(["x", "y", "z"]).describe("World axis the copies step along"),
|
|
34655
34679
|
flip: external_exports.boolean().default(false).describe("True steps along the negative axis")
|
|
34656
34680
|
});
|
|
34681
|
+
var patternLayout = external_exports.discriminatedUnion("kind", [
|
|
34682
|
+
external_exports.object({
|
|
34683
|
+
kind: external_exports.literal("linear"),
|
|
34684
|
+
direction: patternDirection,
|
|
34685
|
+
count: external_exports.union([external_exports.number().int().min(2).max(100), external_exports.string().min(1)]).describe("Number of copies in a row, including the original (2 to 100)"),
|
|
34686
|
+
spacing: size("Distance between copies"),
|
|
34687
|
+
second: external_exports.object({
|
|
34688
|
+
direction: patternDirection,
|
|
34689
|
+
count: external_exports.union([external_exports.number().int().min(2).max(100), external_exports.string().min(1)]).describe("Rows in the second direction, including the original"),
|
|
34690
|
+
spacing: size("Distance between rows")
|
|
34691
|
+
}).optional().describe("A second direction makes a grid (at most 400 copies in all)")
|
|
34692
|
+
}),
|
|
34693
|
+
external_exports.object({
|
|
34694
|
+
kind: external_exports.literal("circular"),
|
|
34695
|
+
axis: external_exports.enum(["x", "y", "z"]).describe("World axis (through `centre`) the copies turn about"),
|
|
34696
|
+
centre: vec3("A point on the axis"),
|
|
34697
|
+
count: external_exports.union([external_exports.number().int().min(2).max(100), external_exports.string().min(1)]).describe("Number of copies including the original"),
|
|
34698
|
+
angle: external_exports.union([external_exports.number().gt(0).max(360), external_exports.string().min(1)]).default(360).describe("360 spreads the copies evenly around the full circle; less puts the last copy at this angle (degrees)")
|
|
34699
|
+
})
|
|
34700
|
+
]).describe("How the copies are laid out. Counts include the original");
|
|
34657
34701
|
var inputs = {
|
|
34658
34702
|
new_project: external_exports.object({
|
|
34659
34703
|
name: external_exports.string().trim().min(1).max(120).default("Untitled").describe("Name of the new project"),
|
|
@@ -34673,8 +34717,28 @@ var inputs = {
|
|
|
34673
34717
|
radius: size("Radius of the base"),
|
|
34674
34718
|
topRadius: external_exports.union([external_exports.number().nonnegative(), external_exports.string().min(1)]).describe(`Radius of the top in mm, 0 for a point${EXPR}`),
|
|
34675
34719
|
height: size("Height along Z")
|
|
34720
|
+
}),
|
|
34721
|
+
external_exports.object({
|
|
34722
|
+
kind: external_exports.literal("tube"),
|
|
34723
|
+
radius: size("Outer radius"),
|
|
34724
|
+
innerRadius: size("Inner radius, smaller than the outer radius"),
|
|
34725
|
+
height: size("Height along Z")
|
|
34726
|
+
}),
|
|
34727
|
+
external_exports.object({
|
|
34728
|
+
kind: external_exports.literal("torus"),
|
|
34729
|
+
radius: size("Distance from the centre to the middle of the ring's tube"),
|
|
34730
|
+
tubeRadius: size("Radius of the tube, smaller than the ring radius")
|
|
34731
|
+
}),
|
|
34732
|
+
external_exports.object({
|
|
34733
|
+
kind: external_exports.literal("wedge"),
|
|
34734
|
+
width: size("Size of the base along X"),
|
|
34735
|
+
depth: size("Size along Y"),
|
|
34736
|
+
height: size("Height along Z, at the tall side"),
|
|
34737
|
+
topWidth: external_exports.union([external_exports.number().nonnegative(), external_exports.string().min(1)]).describe(`Width of the flat top in mm, 0 for a sharp ramp edge, the width for a box${EXPR}`)
|
|
34676
34738
|
})
|
|
34677
|
-
]).describe(
|
|
34739
|
+
]).describe(
|
|
34740
|
+
"The solid to add. A primitive stands on the XY plane: its base is centred on `position` and it grows upwards along Z. A torus stands on the XY plane too (it spans z 0 to twice its tube radius). A wedge is tallest at its -X side and slopes down to +X; its top is `topWidth` wide."
|
|
34741
|
+
),
|
|
34678
34742
|
position: vec3("Where the centre of the base goes").default([0, 0, 0]),
|
|
34679
34743
|
rotation: vec3("Rotation about X, then Y, then Z, around the base centre", "degrees").default([0, 0, 0])
|
|
34680
34744
|
}),
|
|
@@ -34739,26 +34803,11 @@ var inputs = {
|
|
|
34739
34803
|
pattern: external_exports.object({
|
|
34740
34804
|
body: bodyId,
|
|
34741
34805
|
result: external_exports.enum(["join", "separate"]).default("join").describe("join fuses the copies into the body; separate makes each copy its own body"),
|
|
34742
|
-
layout:
|
|
34743
|
-
|
|
34744
|
-
|
|
34745
|
-
|
|
34746
|
-
|
|
34747
|
-
spacing: size("Distance between copies"),
|
|
34748
|
-
second: external_exports.object({
|
|
34749
|
-
direction: patternDirection,
|
|
34750
|
-
count: external_exports.union([external_exports.number().int().min(2).max(100), external_exports.string().min(1)]).describe("Rows in the second direction, including the original"),
|
|
34751
|
-
spacing: size("Distance between rows")
|
|
34752
|
-
}).optional().describe("A second direction makes a grid (at most 400 copies in all)")
|
|
34753
|
-
}),
|
|
34754
|
-
external_exports.object({
|
|
34755
|
-
kind: external_exports.literal("circular"),
|
|
34756
|
-
axis: external_exports.enum(["x", "y", "z"]).describe("World axis (through `centre`) the copies turn about"),
|
|
34757
|
-
centre: vec3("A point on the axis"),
|
|
34758
|
-
count: external_exports.union([external_exports.number().int().min(2).max(100), external_exports.string().min(1)]).describe("Number of copies including the original"),
|
|
34759
|
-
angle: external_exports.union([external_exports.number().gt(0).max(360), external_exports.string().min(1)]).default(360).describe("360 spreads the copies evenly around the full circle; less puts the last copy at this angle (degrees)")
|
|
34760
|
-
})
|
|
34761
|
-
]).describe("How the copies are laid out")
|
|
34806
|
+
layout: patternLayout
|
|
34807
|
+
}),
|
|
34808
|
+
pattern_hole: external_exports.object({
|
|
34809
|
+
hole: featureId.describe("Id of the hole to repeat (returned by hole, or listed by get_project). Its copies are cut into the same body"),
|
|
34810
|
+
layout: patternLayout
|
|
34762
34811
|
}),
|
|
34763
34812
|
mirror: external_exports.object({
|
|
34764
34813
|
body: bodyId,
|
|
@@ -34809,25 +34858,26 @@ var inputs = {
|
|
|
34809
34858
|
};
|
|
34810
34859
|
var descriptions = {
|
|
34811
34860
|
new_project: "Start a new, empty Polypad project (optionally from a template), replacing the open one. All lengths in Polypad are millimetres and angles are degrees; Z is up.",
|
|
34812
|
-
set_parameter: "Create or change a named parameter (a number or an expression). Any length field of any feature can use the name, so one change resizes everything bound to it. Reports features that no longer build.",
|
|
34813
|
-
add_primitive: "Add a solid box, cylinder, sphere or
|
|
34861
|
+
set_parameter: "Create or change a named parameter (a number or an expression). Any length field of any feature can use the name, so one change resizes everything bound to it. Reports features that no longer build. Set the sizes up front, then use the names in fields.",
|
|
34862
|
+
add_primitive: "Add a solid box, cylinder, tube, sphere, cone, torus or wedge as a new body. Returns the new feature's id, which is also the body id for later commands. Sizes in mm.",
|
|
34814
34863
|
add_sketch: "Add a 2D sketch on a base plane or on a flat face and draw shapes in it (rectangle, circle, line, polyline, arc, slot, polygon). The sketch is solved and its remaining degrees of freedom reported. Use extrude or revolve to turn closed shapes into a solid.",
|
|
34815
34864
|
extrude: "Extrude the closed shapes of a sketch into a solid: as a new body, or cut from / joined to an existing body. Returns the feature id (the new body's id when mode is new).",
|
|
34816
|
-
revolve: "Revolve the closed shapes of a sketch about an axis in the sketch plane to make a solid of revolution: new body, or cut / join with an existing body.",
|
|
34817
|
-
combine: "Boolean-combine bodies: union, subtract (remove the tools from the target) or intersect. The target keeps its id; the tools are consumed.",
|
|
34818
|
-
hole: "Drill a screw hole (M2 to M10, with clearance, tap or heat-set insert fit and optional counterbore / countersink) into a flat face. Call list_faces first and pass the face index and its rebuildId.",
|
|
34819
|
-
fillet: "Round the given edges of a body with a radius. Call list_edges first and pass the edge indices and their rebuildId.",
|
|
34820
|
-
chamfer: "Bevel the given edges of a body. Call list_edges first and pass the edge indices and their rebuildId.",
|
|
34821
|
-
shell: "Hollow out a body, leaving the given faces open, with walls of a given thickness. Call list_faces first and pass the face indices and their rebuildId.",
|
|
34822
|
-
pattern: "Repeat a body in a row or grid, or around an axis, either fusing the copies into the body or making each copy a body of its own.",
|
|
34823
|
-
|
|
34865
|
+
revolve: "Revolve the closed shapes of a sketch about an axis in the sketch plane to make a solid of revolution: new body, or cut / join with an existing body. Use it for round parts: draw half the outline beside the axis.",
|
|
34866
|
+
combine: "Boolean-combine bodies: union, subtract (remove the tools from the target) or intersect. The target keeps its id; the tools are consumed. To hollow a body use shell, not a subtracted box; to check a collision, intersect two bodies, measure the result, then undo.",
|
|
34867
|
+
hole: "Drill a screw hole (M2 to M10, with clearance, tap or heat-set insert fit and optional counterbore / countersink) into a flat face. Call list_faces first and pass the face index and its rebuildId. Use this for every screw, standoff or insert hole instead of cutting circles.",
|
|
34868
|
+
fillet: "Round the given edges of a body with a radius. Call list_edges first (narrow it with its filter) and pass the edge indices and their rebuildId. If it fails, try a smaller radius or fewer edges.",
|
|
34869
|
+
chamfer: "Bevel the given edges of a body. Call list_edges first (narrow it with its filter) and pass the edge indices and their rebuildId. If it fails, try a smaller distance or fewer edges.",
|
|
34870
|
+
shell: "Hollow out a body, leaving the given faces open, with walls of a given thickness. Call list_faces first and pass the face indices and their rebuildId. Use this for enclosures and cups instead of subtracting a smaller box; list_faces with filter normal finds the face to open.",
|
|
34871
|
+
pattern: "Repeat a body in a row or grid, or around an axis, either fusing the copies into the body or making each copy a body of its own. Model one copy (or one cutter) and pattern it instead of adding copies by hand. To repeat a screw hole use pattern_hole instead.",
|
|
34872
|
+
pattern_hole: "Repeat a hole you already made: in a row or grid, or around an axis (a bolt circle, for example 6 holes around a flange). The copies are cut into the hole's body in one go with the hole's size, fit, head and depth, and follow later edits to the hole. The layout works in world axes: for a bolt circle on a top face use kind circular, axis z, centre a point on the axis (the middle of the circle) and the count; the hole itself is one of the copies, so place it on the bolt circle. A copy that lands off the face is skipped and reported.",
|
|
34873
|
+
mirror: "Mirror a whole body across a plane (yz, xz or xy, optionally moved along its normal), joining the copy into the body or making it a separate body. Model one side of a symmetric part, then mirror it.",
|
|
34824
34874
|
move: "Move, rotate and/or scale a whole body (translate in mm, rotate in degrees about X, Y, Z around a pivot).",
|
|
34825
|
-
update_feature: "Change fields of an existing feature (for example an extrude's distance or a box's width); everything after it rebuilds. The change is refused, and the project left as it was, if the result is not a valid model.",
|
|
34875
|
+
update_feature: "Change fields of an existing feature (for example an extrude's distance or a box's width); everything after it rebuilds. The change is refused, and the project left as it was, if the result is not a valid model. Prefer this over deleting and rebuilding a feature.",
|
|
34826
34876
|
delete_feature: "Delete a feature. Refused while other features still use it; delete those first.",
|
|
34827
34877
|
undo: "Undo the last change made to the project. Can be repeated.",
|
|
34828
34878
|
get_project: "Describe the whole project: parameters, every feature in order (id, name, type, main values, whether it built or the error), and every body (volume, area, bounding box). Start here, and call it again after changes to check the result.",
|
|
34829
|
-
list_faces: "List the faces of a body: index, flat or curved, normal, centre, area, and for flat faces the sketch frame (origin, x and y axes) with the face's bounds in it. The indices go into hole, shell and add_sketch (face). Returns a rebuildId those commands require.",
|
|
34830
|
-
list_edges: "List the edges of a body: index, convex / concave / smooth, length, straight or curved, direction, midpoint, and the faces they border. The indices go into fillet and chamfer. Returns a rebuildId those commands require.",
|
|
34879
|
+
list_faces: "List the faces of a body: index, flat or curved, normal, centre, area, and for flat faces the sketch frame (origin, x and y axes) with the face's bounds in it. The indices go into hole, shell and add_sketch (face). Returns a rebuildId those commands require. A body can have hundreds of faces: use the filter (normal, kind).",
|
|
34880
|
+
list_edges: "List the edges of a body: index, convex / concave / smooth, length, straight or curved, direction, midpoint, and the faces they border. The indices go into fillet and chamfer. Returns a rebuildId those commands require. A body can have hundreds of edges: use the filter (face, direction, kind).",
|
|
34831
34881
|
measure: "Measure bodies: volume (mm3), surface area (mm2), bounding box (mm) and its centre.",
|
|
34832
34882
|
render_view: "Render the model to a PNG image from a standard view, to look at the result. Needs the Polypad browser tab."
|
|
34833
34883
|
};
|
|
@@ -35451,12 +35501,25 @@ var SERVER_INSTRUCTIONS = `Polypad is a parametric CAD editor. These tools build
|
|
|
35451
35501
|
Units and axes: lengths are millimetres, angles degrees, Z is up. Any length field accepts a number or an expression over the project's parameters ("width / 2"); prefer set_parameter for sizes that belong together.
|
|
35452
35502
|
|
|
35453
35503
|
Workflow:
|
|
35454
|
-
1. Start with get_project to see what is already there (the user may have work open). new_project replaces the open project,
|
|
35504
|
+
1. Start with get_project to see what is already there (the user may have work open). new_project replaces the open project: if it has features, ask the user first and never call it over their work; use it freely only when the project is empty.
|
|
35455
35505
|
2. Build with add_primitive, or add_sketch then extrude / revolve. Ids returned by a command are the feature and body ids for later calls.
|
|
35456
35506
|
3. For hole, shell, fillet, chamfer and for sketching on a face, call list_faces or list_edges first. Pass the indices they return together with the same rebuildId. The rebuildId changes whenever the model changes, so after any change list again; a stale one is refused ("Call list_edges again").
|
|
35457
35507
|
4. A feature that does not build stays in the project with its error: fix it with update_feature, or remove it with delete_feature or undo.
|
|
35458
35508
|
5. Check your work: measure gives volume and bounding box, and render_view returns a PNG (iso, top, front, right) so you can look at the result. Compare the numbers with what was asked before you finish.
|
|
35459
35509
|
|
|
35510
|
+
Pick the tool by task:
|
|
35511
|
+
- Hollow part (enclosure, box, cup): shell the solid with the open face(s) removed (list_faces with filter normal "+z" finds the top); don't subtract a smaller box.
|
|
35512
|
+
- Screw holes, standoffs, inserts: hole (size, fit close/normal/loose/tap/insert, counterbore or countersink, blind depth), not cut circles.
|
|
35513
|
+
- Several of the same hole (a bolt circle on a flange, a row or grid of mounting holes): make one hole with hole, then pattern_hole with its id. For a bolt circle use layout kind circular, axis = the face normal axis (z for a top face), centre = a point on the circle's axis, count = number of holes; place the first hole on the circle itself (list_faces gives the face's frame and bounds). Copies that land off the face are skipped and reported.
|
|
35514
|
+
- Repeated parts (rows, grids, around a circle, lattices): model one body, or one cutter body, then pattern it (then combine subtract for a cutter). Symmetric parts: model one side, then mirror.
|
|
35515
|
+
- Round parts (knobs, turrets, finials, domes): add_sketch on XZ (sketch x = world X, sketch y = world Z), draw half the outline at x >= 0, then revolve with axis "y" (the world Z axis).
|
|
35516
|
+
- Pipes, spacers and rings: the tube primitive (a torus for an O-ring), not two subtracted cylinders.
|
|
35517
|
+
- Sizes that belong together or may change: set_parameter first, then use the names in fields.
|
|
35518
|
+
- Changing or fixing a feature: update_feature (or undo the last step); don't delete and rebuild.
|
|
35519
|
+
- Picking edges: use the list_edges filter (face, direction, kind) and the list_faces filter (normal, kind) instead of reading every edge. For the rim of the top: list_faces normal "+z", then list_edges face <index>.
|
|
35520
|
+
- Fillet fails: try a smaller radius or fewer edges at once, or use chamfer.
|
|
35521
|
+
- Clearances and collisions: measure gives bounding boxes; combine intersect on two bodies, then measure, shows an overlap; then undo.
|
|
35522
|
+
|
|
35460
35523
|
Results: a result with isError set was refused or something in the model did not build; the text says what and how to fix it. Nothing is changed by a refused call.`;
|
|
35461
35524
|
function toToolResult(result) {
|
|
35462
35525
|
const content = [{ type: "text", text: result.text }];
|
|
@@ -35485,7 +35548,7 @@ function createPolypadMcp(options = {}) {
|
|
|
35485
35548
|
}
|
|
35486
35549
|
|
|
35487
35550
|
// src/index.ts
|
|
35488
|
-
var VERSION = true ? "0.1.
|
|
35551
|
+
var VERSION = true ? "0.1.6" : "0.0.0-dev";
|
|
35489
35552
|
var err = (line2) => process.stderr.write(`${line2}
|
|
35490
35553
|
`);
|
|
35491
35554
|
async function main() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polypad/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP server that lets Claude, Cursor or another AI assistant build and inspect 3D models in your open Polypad tab (polypad.ink). Runs locally, nothing is uploaded.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
20
|
"dist/index.js",
|
|
21
|
+
"dist/THIRD_PARTY_NOTICES.txt",
|
|
21
22
|
"README.md",
|
|
22
23
|
"LICENSE"
|
|
23
24
|
],
|
|
@@ -32,9 +33,11 @@
|
|
|
32
33
|
"prepublishOnly": "tsup",
|
|
33
34
|
"typecheck": "tsc --noEmit",
|
|
34
35
|
"test": "vitest run",
|
|
35
|
-
"lint": "eslint ."
|
|
36
|
+
"lint": "eslint .",
|
|
37
|
+
"build:mcpb": "node mcpb/build.mjs"
|
|
36
38
|
},
|
|
37
39
|
"devDependencies": {
|
|
40
|
+
"@anthropic-ai/mcpb": "2.1.2",
|
|
38
41
|
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
39
42
|
"@polypad/core": "workspace:*",
|
|
40
43
|
"@polypad/document": "workspace:*",
|