bambu-printer-mcp 1.1.26 → 1.1.28

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.
@@ -28,6 +28,7 @@ import fs from "node:fs/promises";
28
28
  import { existsSync, realpathSync } from "node:fs";
29
29
  import path from "node:path";
30
30
  import crypto from "node:crypto";
31
+ import { profileJsonFiles } from './profile-files.js';
31
32
 
32
33
  export type ProfileKind = "machine" | "process" | "filament";
33
34
 
@@ -125,17 +126,7 @@ async function buildNameIndex(
125
126
  ...userProfileRoots.flatMap(root => ['process', 'filament'].map(sub => path.join(root, sub))),
126
127
  ];
127
128
  for (const dir of directories) {
128
- let entries: string[];
129
- try {
130
- entries = await fs.readdir(dir);
131
- } catch {
132
- // Vendor or subdir missing -- skip silently; flatten will fail later
133
- // with a precise "name not found" error.
134
- continue;
135
- }
136
- for (const entry of entries) {
137
- if (!entry.endsWith(".json")) continue;
138
- const filePath = path.join(dir, entry);
129
+ for (const filePath of profileJsonFiles(dir)) {
139
130
  let raw: string;
140
131
  try {
141
132
  raw = await fs.readFile(filePath, "utf8");
@@ -344,6 +335,37 @@ function enforceMatchingNozzles(arr: unknown[]): void {
344
335
  }
345
336
  }
346
337
 
338
+ /**
339
+ * BambuStudio picks each per-variant machine, process, and filament value
340
+ * (e.g. filament_max_volumetric_speed) by "<extruder_type> <nozzle_volume_type>"
341
+ * among the variants each extruder declares in extruder_variant_list. A flow
342
+ * type the preset doesn't declare has no values to pick, so refuse it instead
343
+ * of labelling a job for a nozzle it wasn't sliced for.
344
+ */
345
+ function assertNozzleVariantDeclared(
346
+ flat: Record<string, unknown>,
347
+ volumeType: string,
348
+ machineLeaf: string
349
+ ): void {
350
+ const strings = (key: string): string[] =>
351
+ Array.isArray(flat[key]) ? (flat[key] as unknown[]).map(String) : [];
352
+ const extruderTypes = strings("extruder_type");
353
+ const declaredLists = strings("extruder_variant_list");
354
+ const count = (flat["nozzle_volume_type"] as unknown[]).length;
355
+ for (let i = 0; i < count; i++) {
356
+ const extruderType = extruderTypes[i] ?? extruderTypes[0];
357
+ const declared = (declaredLists[i] ?? declaredLists[0] ?? "").split(",").map((v) => v.trim()).filter(Boolean);
358
+ const matches = (variant: string) =>
359
+ extruderType ? variant === `${extruderType} ${volumeType}` : variant.endsWith(` ${volumeType}`);
360
+ // Presets without variant declarations only have Standard values.
361
+ if (declared.length === 0 ? volumeType === "Standard" : declared.some(matches)) continue;
362
+ throw new Error(
363
+ `Slicing for a ${volumeType} nozzle is refused: "${machineLeaf}" declares no ${volumeType} variant ` +
364
+ `for extruder ${i + 1} (declared: ${declared.join(", ") || "none"}).`
365
+ );
366
+ }
367
+ }
368
+
347
369
  /** Best-effort extruder count for fallback nozzle_volume_type sizing. */
348
370
  /** BambuStudio's built-in filament_colour default. */
349
371
  export const DEFAULT_FILAMENT_COLOUR = "#00AE42";
@@ -696,6 +718,7 @@ export async function flattenForCli(opts: FlattenOptions): Promise<FlattenedProf
696
718
 
697
719
  // CLI-specific post-processing on machine profile only.
698
720
  deriveNozzleVolumeType(machineFlat, opts.nozzleVolumeType);
721
+ if (opts.nozzleVolumeType) assertNozzleVariantDeclared(machineFlat, opts.nozzleVolumeType, opts.machineLeaf);
699
722
  applyMachineModelBedMetadata(machineFlat, machineIndex);
700
723
  // A standalone custom machine can accompany process/filament profiles that
701
724
  // need BBL resolution; do not impose bundled model config on that machine.
@@ -10,6 +10,7 @@ import { EventEmitter } from 'events';
10
10
  import * as crypto from 'crypto';
11
11
  import { execFile } from 'child_process';
12
12
  import { flattenForCli, detectProfilesRoot, resolveBblMachineProfile } from '../slicer/profile-flatten.js';
13
+ import { profileJsonFiles } from '../slicer/profile-files.js';
13
14
 
14
15
  const readFileAsync = promisify(fs.readFile);
15
16
  const writeFileAsync = promisify(fs.writeFile);
@@ -165,6 +166,7 @@ export interface BambuSliceOptions {
165
166
  filamentColours?: string[]; // positional #RRGGBB per loaded filament slot
166
167
  bedType?: string; // Bambu bed type, e.g. textured_plate or cool_plate
167
168
  nozzleType?: string; // installed hotend material written into the machine preset
169
+ nozzleVolumeType?: 'Standard' | 'High Flow'; // installed nozzle flow, the machine preset's nozzle_volume_type
168
170
  enableTimelapse?: boolean; // --enable-timelapse: timelapse-aware slicing
169
171
  allowMixTemp?: boolean; // --allow-mix-temp: allow mixed-temp filaments
170
172
  scale?: number; // --scale factor: uniform scale
@@ -232,10 +234,9 @@ export class STLManipulator extends EventEmitter {
232
234
  }
233
235
 
234
236
  for (const root of roots) {
235
- const candidate = path.join(root, category, `${profileName}.json`);
236
- if (fs.existsSync(candidate)) {
237
- return candidate;
238
- }
237
+ const candidate = profileJsonFiles(path.join(root, category))
238
+ .find(file => path.basename(file) === `${profileName}.json`);
239
+ if (candidate) return candidate;
239
240
  }
240
241
 
241
242
  return undefined;
@@ -250,12 +251,7 @@ export class STLManipulator extends EventEmitter {
250
251
  continue;
251
252
  }
252
253
 
253
- for (const entry of fs.readdirSync(filamentDir)) {
254
- if (!entry.endsWith('.json')) {
255
- continue;
256
- }
257
-
258
- const filePath = path.join(filamentDir, entry);
254
+ for (const filePath of profileJsonFiles(filamentDir)) {
259
255
  try {
260
256
  const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
261
257
  const filamentId = typeof parsed?.filament_id === 'string' ? parsed.filament_id.trim() : '';
@@ -568,6 +564,7 @@ export class STLManipulator extends EventEmitter {
568
564
  userProfileRoots: configuredBambuProfileDirs(),
569
565
  tempDir: this.tempDir,
570
566
  bedType: this.resolveBambuStudioBedType(bambuOptions?.bedType),
567
+ nozzleVolumeType: bambuOptions?.nozzleVolumeType,
571
568
  filamentColours: bambuOptions?.filamentColours ?? bundle.filamentColours,
572
569
  projectTowerPosition: bundle.projectTowerPosition,
573
570
  sourceProfiles: {
@@ -1,33 +0,0 @@
1
- #!/bin/zsh
2
-
3
- # Build the optional macOS adapter that calls Bambu Studio's installed
4
- # networking plug-in at runtime. The plug-in itself is not bundled here.
5
- set -euo pipefail
6
-
7
- if [[ "$(uname -s)" != "Darwin" ]]; then
8
- print -u2 "The Bambu native helper currently supports macOS only."
9
- exit 1
10
- fi
11
-
12
- SCRIPT_DIR="${0:A:h}"
13
- PROJECT_ROOT="${SCRIPT_DIR:h}"
14
- CXX_BIN="${CXX:-clang++}"
15
- OUTPUT="${PROJECT_ROOT}/native/bambu-native-print"
16
- SOURCE="${PROJECT_ROOT}/native/bambu-native-print.cpp"
17
-
18
- if ! command -v "$CXX_BIN" >/dev/null 2>&1; then
19
- print -u2 "C++ compiler not found: $CXX_BIN"
20
- exit 1
21
- fi
22
-
23
- "$CXX_BIN" \
24
- -std=c++17 \
25
- -O2 \
26
- -Wall \
27
- -Wextra \
28
- -o "$OUTPUT" \
29
- "$SOURCE" \
30
- -ldl
31
-
32
- chmod 755 "$OUTPUT"
33
- print "Built $OUTPUT"