mcp-3d-printer-server 1.2.12 → 1.2.14
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/CHANGELOG.md +30 -0
- package/CONTRIBUTORS.md +4 -0
- package/README.md +2 -2
- package/dist/fulu-orca.d.ts +8 -0
- package/dist/fulu-orca.js +107 -10
- package/dist/index.js +3 -3
- package/dist/printers/bambu.js +11 -4
- package/dist/safety/confirmation.js +9 -2
- package/dist/safety/printer-state.d.ts +2 -0
- package/dist/safety/printer-state.js +42 -1
- package/dist/slicer/bambu-cli.d.ts +21 -1
- package/dist/slicer/bambu-cli.js +86 -11
- package/dist/slicer/run-slicer.d.ts +2 -0
- package/dist/slicer/run-slicer.js +3 -2
- package/dist/stl/stl-manipulator.d.ts +8 -0
- package/dist/stl/stl-manipulator.js +31 -2
- package/package.json +2 -2
- package/server.json +2 -2
- package/src/fulu-orca.ts +102 -10
- package/src/index.ts +3 -3
- package/src/printers/bambu.ts +11 -3
- package/src/safety/confirmation.ts +8 -2
- package/src/safety/printer-state.ts +42 -1
- package/src/slicer/bambu-cli.ts +92 -7
- package/src/slicer/run-slicer.ts +5 -2
- package/src/stl/stl-manipulator.ts +29 -1
package/src/slicer/run-slicer.ts
CHANGED
|
@@ -11,6 +11,8 @@ export interface SlicerRunOptions {
|
|
|
11
11
|
slicerType: string;
|
|
12
12
|
/** Polled while the slicer runs; returning true kills it. */
|
|
13
13
|
isCancelled?: () => boolean;
|
|
14
|
+
/** The slicer's own reason for a nonzero exit, read before its output directory is removed. */
|
|
15
|
+
failureReason?: (exitCode: number | null) => string | undefined;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export interface SlicerRunResult {
|
|
@@ -51,7 +53,7 @@ function describeOutput(stdoutTail: string, stderrTail: string): string {
|
|
|
51
53
|
* cancellation rejects with a SlicerError that includes the evidence.
|
|
52
54
|
*/
|
|
53
55
|
export function runSlicerProcess(options: SlicerRunOptions): Promise<SlicerRunResult> {
|
|
54
|
-
const { command, args, timeoutMs, slicerType, isCancelled } = options;
|
|
56
|
+
const { command, args, timeoutMs, slicerType, isCancelled, failureReason } = options;
|
|
55
57
|
return new Promise((resolve, reject) => {
|
|
56
58
|
const stdout = new TailBuffer();
|
|
57
59
|
const stderr = new TailBuffer();
|
|
@@ -107,9 +109,10 @@ export function runSlicerProcess(options: SlicerRunOptions): Promise<SlicerRunRe
|
|
|
107
109
|
: signal
|
|
108
110
|
? `Slicer was terminated by signal ${signal}`
|
|
109
111
|
: `Slicer exited with code ${code}`;
|
|
112
|
+
const cliReason = timedOut || cancelled ? undefined : failureReason?.(code);
|
|
110
113
|
settle(() => reject(new SlicerError(
|
|
111
114
|
"execution",
|
|
112
|
-
`${reason} (${slicerType}: ${command}).\n${describeOutput(stdoutTail, stderrTail)}`,
|
|
115
|
+
`${reason} (${slicerType}: ${command})${cliReason ? `: ${cliReason}` : ""}.\n${describeOutput(stdoutTail, stderrTail)}`,
|
|
113
116
|
{
|
|
114
117
|
slicerType,
|
|
115
118
|
slicerPath: command,
|
|
@@ -11,7 +11,9 @@ import { detectProfilesRoot } from '../slicer/profile-flatten.js';
|
|
|
11
11
|
import {
|
|
12
12
|
BambuCliProfilePreparer,
|
|
13
13
|
assertSlicedProjectOutput,
|
|
14
|
+
bambuCliFailureReason,
|
|
14
15
|
buildBambuCliArgs,
|
|
16
|
+
planBambuCliInput,
|
|
15
17
|
type BambuCliSlicerType,
|
|
16
18
|
type BambuSliceOptions,
|
|
17
19
|
} from '../slicer/bambu-cli.js';
|
|
@@ -182,6 +184,27 @@ export class STLManipulator extends EventEmitter {
|
|
|
182
184
|
return timeoutMs;
|
|
183
185
|
}
|
|
184
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Apply slice_stl's scale and rotations to a copy of the mesh as OrcaSlicer's
|
|
189
|
+
* CLI would, about the model's centre. Orca adds each --rotate* to the
|
|
190
|
+
* object's Euler angles (ModelVolume::rotate), so the result rotates about X,
|
|
191
|
+
* then Y, then Z whatever the argument order, after scaling. The slicer then
|
|
192
|
+
* places the result on the plate.
|
|
193
|
+
*/
|
|
194
|
+
private async transformMeshForCli(stlFilePath: string, options: BambuSliceOptions, outputDir: string): Promise<string> {
|
|
195
|
+
const { geometry, boundingBox } = await this.loadSTL(stlFilePath);
|
|
196
|
+
const center = new THREE.Vector3();
|
|
197
|
+
boundingBox.getCenter(center);
|
|
198
|
+
const radians = (degrees: number) => degrees * Math.PI / 180;
|
|
199
|
+
geometry.applyMatrix4(new THREE.Matrix4().makeTranslation(-center.x, -center.y, -center.z));
|
|
200
|
+
if (options.scale !== undefined) geometry.applyMatrix4(new THREE.Matrix4().makeScale(options.scale, options.scale, options.scale));
|
|
201
|
+
if (options.rotateX) geometry.applyMatrix4(new THREE.Matrix4().makeRotationX(radians(options.rotateX)));
|
|
202
|
+
if (options.rotateY) geometry.applyMatrix4(new THREE.Matrix4().makeRotationY(radians(options.rotateY)));
|
|
203
|
+
if (options.rotate) geometry.applyMatrix4(new THREE.Matrix4().makeRotationZ(radians(options.rotate)));
|
|
204
|
+
geometry.applyMatrix4(new THREE.Matrix4().makeTranslation(center.x, center.y, center.z));
|
|
205
|
+
return this.saveSTL(geometry, path.join(outputDir, `${path.basename(stlFilePath, path.extname(stlFilePath))}_transformed.stl`));
|
|
206
|
+
}
|
|
207
|
+
|
|
185
208
|
/**
|
|
186
209
|
* Load STL file and return geometry and bounding box
|
|
187
210
|
*/
|
|
@@ -1060,6 +1083,7 @@ export class STLManipulator extends EventEmitter {
|
|
|
1060
1083
|
}
|
|
1061
1084
|
options.loadFilaments = legacyFilaments;
|
|
1062
1085
|
}
|
|
1086
|
+
const cliInput = planBambuCliInput(cliType, is3mf, options);
|
|
1063
1087
|
const profilesRoot = detectProfilesRoot(slicerPath, cliType);
|
|
1064
1088
|
const preparer = new BambuCliProfilePreparer(path.join(this.tempDir, 'slicer-profiles'));
|
|
1065
1089
|
const bundle = await preparer.prepare(
|
|
@@ -1072,7 +1096,9 @@ export class STLManipulator extends EventEmitter {
|
|
|
1072
1096
|
options
|
|
1073
1097
|
);
|
|
1074
1098
|
bambuOutputDir = fs.mkdtempSync(path.join(this.tempDir, `${operationId}-bambu-output-`));
|
|
1075
|
-
|
|
1099
|
+
// The transformed copy lives in the run's output directory, which is removed afterwards.
|
|
1100
|
+
const inputPath = cliInput.meshTransformed ? await this.transformMeshForCli(stlFilePath, options, bambuOutputDir) : stlFilePath;
|
|
1101
|
+
args = [...buildBambuCliArgs(bundle, bambuOutputDir, exportName, options, cliInput), inputPath];
|
|
1076
1102
|
bambuExport = {
|
|
1077
1103
|
producedPath: path.join(bambuOutputDir, exportName),
|
|
1078
1104
|
// One folder per operation: concurrent slices of same-named inputs
|
|
@@ -1135,12 +1161,14 @@ export class STLManipulator extends EventEmitter {
|
|
|
1135
1161
|
if (progressCallback) progressCallback(20, `Executing slicer: ${slicerPath} ${args.join(' ')}`);
|
|
1136
1162
|
console.error(`Executing: ${slicerPath} ${args.join(' ')}`);
|
|
1137
1163
|
|
|
1164
|
+
const cliOutputDir = bambuOutputDir;
|
|
1138
1165
|
await runSlicerProcess({
|
|
1139
1166
|
command: slicerPath,
|
|
1140
1167
|
args,
|
|
1141
1168
|
timeoutMs: this.resolveSlicerTimeoutMs(),
|
|
1142
1169
|
slicerType,
|
|
1143
1170
|
isCancelled: () => !this.activeOperations.get(operationId),
|
|
1171
|
+
failureReason: cliOutputDir ? (exitCode) => bambuCliFailureReason(exitCode, cliOutputDir) : undefined,
|
|
1144
1172
|
});
|
|
1145
1173
|
|
|
1146
1174
|
if (!this.activeOperations.get(operationId)) {
|