@toolpath/plan 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1868 @@
1
+ export { MM_PER_INCH } from '@toolpath/tool-support';
2
+
3
+ type CoverageKind = 'pinned' | 'ignored' | 'open' | 'machined' | 'notMachined';
4
+ /**
5
+ * In the order the coverage bar draws them, and a feature is said to be where its faces differ
6
+ * (`stateOf`). A face itself is weighed by `classifyFaces`, ignored first.
7
+ */
8
+ declare const COVERAGE_KINDS: ReadonlyArray<CoverageKind>;
9
+ /** Each kind in the glossary's words: what the bar, the lists and the Pin features notes say. */
10
+ declare const COVERAGE_LABELS: Record<CoverageKind, string>;
11
+ /** A face: its region, its area (mm²), and the features that include it. */
12
+ interface Face {
13
+ region: number;
14
+ area: number;
15
+ owners: Array<string>;
16
+ }
17
+ /** A part's faces by kind, each largest first, and its whole surface (mm²). */
18
+ interface Coverage {
19
+ total: number;
20
+ faces: Record<CoverageKind, Array<Face>>;
21
+ }
22
+ /** Each face of a coverage by region, and who machines it. */
23
+ declare const facesByRegion: (coverage: Coverage | null) => Map<number, {
24
+ face: Face;
25
+ kind: CoverageKind;
26
+ }>;
27
+ /** A feature as the part's analysis reads it. */
28
+ interface CoverageFeature {
29
+ tag: string;
30
+ featureType: string;
31
+ regionIdxs?: ReadonlyArray<number> | null;
32
+ }
33
+ /** A tag as compared: Toolpath and the analysis spell a tag differently, so in lower case. */
34
+ declare const tagKey: (tag: string) => string;
35
+ /** Tags in lower case: Toolpath and the analysis spell a tag differently. */
36
+ declare const tagSet: (tags: Iterable<string>) => Set<string>;
37
+ /** What every action of a plan cuts, by tag (lower case). */
38
+ declare const planTags: (setups: ReadonlyArray<{
39
+ actions: ReadonlyArray<{
40
+ featureTags?: ReadonlyArray<string> | null;
41
+ }>;
42
+ }>) => Set<string>;
43
+ declare const areaOf: (faces: ReadonlyArray<Pick<Face, "area">>) => number;
44
+ /** What `classifyFaces` reads of the part: its faces, its features, and the faces ignored. */
45
+ interface ClassifiedPart {
46
+ regions: ReadonlyArray<{
47
+ idx: number;
48
+ area: number;
49
+ }>;
50
+ features: ReadonlyArray<CoverageFeature>;
51
+ ignored?: ReadonlyArray<number>;
52
+ }
53
+ /** The constraints view: the person's pins, by tag (lower case). The rest is open. */
54
+ interface ConstraintsCoverage extends ClassifiedPart {
55
+ pinned: ReadonlySet<string>;
56
+ /** One view at a time: never Toolpath's plan beside the pins. */
57
+ machined?: never;
58
+ }
59
+ /** The results view: what Toolpath's plan cuts, by tag (lower case). The rest is not machined. */
60
+ interface ResultsCoverage extends ClassifiedPart {
61
+ machined: ReadonlySet<string>;
62
+ /** One view at a time: never the pins beside Toolpath's plan. */
63
+ pinned?: never;
64
+ }
65
+ /**
66
+ * Each face in exactly one kind: ignored first, then — constraints — pinned or open, or — results —
67
+ * machined or not machined. Every tag set is lower case. The other view's kinds are empty.
68
+ */
69
+ declare const classifyFaces: (input: ConstraintsCoverage | ResultsCoverage) => Coverage;
70
+ /** Faces gathered under the one feature that would machine them all: a row of a Not machined list. */
71
+ interface FaceGroup {
72
+ /** The feature, or null for a face no feature includes: listed alone. */
73
+ tag: string | null;
74
+ /** Its faces, largest first. */
75
+ faces: Array<Face>;
76
+ area: number;
77
+ }
78
+ /** A type that includes most of a direction's faces by its nature, so it never speaks for one. */
79
+ declare const isFallback: (type: string) => boolean;
80
+ /**
81
+ * Gather faces under features, so one choice settles several. Greedy: the feature including the
82
+ * most faces still ungathered goes first (the more specific, then the smaller, among equals) until
83
+ * every face is under one. A profile includes most of its direction's faces, so it is taken only for
84
+ * a face nothing else includes. A face no feature includes is a group of its own. Features come
85
+ * first, largest first, then the faces no feature includes.
86
+ */
87
+ declare const groupFaces: (faces: ReadonlyArray<Face>, features: ReadonlyArray<CoverageFeature>) => Array<FaceGroup>;
88
+
89
+ /** A feature type as a person says it: `open_pocket` → `Open pocket`. */
90
+ declare const featureTypeLabel: (type: string) => string;
91
+ /** A direction token, exactly as Toolpath served it: the kernel compares directions bit-exactly. */
92
+ interface PlanDirection {
93
+ x: number;
94
+ y: number;
95
+ z: number;
96
+ }
97
+ /** One pass of a setup: its tool, and the features (tags, hex) it cuts. */
98
+ interface EnginePlanAction {
99
+ idx: number;
100
+ toolName: string;
101
+ featureTags: Array<string>;
102
+ }
103
+ interface EnginePlanSetup {
104
+ idx: number;
105
+ /** The setup's first direction — a 3+2 setup has more, in {@link EnginePlan.setupPlan}. */
106
+ direction: PlanDirection | null;
107
+ /** Features this setup was meant to machine that no pass in it does. */
108
+ unmachined: Array<string>;
109
+ actions: Array<EnginePlanAction>;
110
+ }
111
+ /** What a setup was meant to machine and no pass in it does — Engine's `unmachined` — by tag. */
112
+ declare const notMachinedOf: (setup: Pick<EnginePlanSetup, "unmachined">) => Array<string>;
113
+ /** One direction of a setup, and the features planned from it. */
114
+ interface StatedOrientation {
115
+ direction: PlanDirection;
116
+ features: Array<string>;
117
+ }
118
+ /**
119
+ * A plan's statement of itself — every setup in order, each with all of its directions and the
120
+ * features planned from each. What Toolpath takes back to plan from a statement.
121
+ */
122
+ interface SetupPlan {
123
+ setups: Array<{
124
+ orientations: Array<StatedOrientation>;
125
+ }>;
126
+ }
127
+ /** What the plan leaves uncut: `Unseen`, `OutOfPlay` or `Incomplete`, with its area (mm²). */
128
+ interface PlanIssue {
129
+ kind: string;
130
+ area: number;
131
+ regionCount: number;
132
+ }
133
+ interface EnginePlan {
134
+ planId: string;
135
+ /**
136
+ * The job that made this run of the plan. Every run is a new plan now, but plans recalculated in
137
+ * place before that share a plan id, so a run is told by plan and job together (`runKey`). Null
138
+ * from a plan copy stored before it was read.
139
+ */
140
+ jobId: string | null;
141
+ /**
142
+ * How far the plan has got: `planned`, its setups built but not timed yet, or `toolpathed`, with
143
+ * its toolpaths and times. Null from a copy stored before Toolpath said.
144
+ */
145
+ level: 'planned' | 'toolpathed' | null;
146
+ kernelVersion: string | null;
147
+ issues: Array<PlanIssue>;
148
+ setups: Array<EnginePlanSetup>;
149
+ /** Null from an Engine that does not serve it (before API 1.19), or for a plan with no setup. */
150
+ setupPlan: SetupPlan | null;
151
+ }
152
+ /**
153
+ * Which run of a plan this is: its id and the job that made it. What the Plan page stamps a taken-out
154
+ * list or an added folder with, so both are let go once Toolpath has planned again. A plan read
155
+ * without a job falls back to its id.
156
+ */
157
+ declare const planRunOf: (plan: Pick<EnginePlan, "planId" | "jobId">) => string;
158
+
159
+ /**
160
+ * Where Toolpath's analysis of a direction a folder faces stands: its features are in; they are on
161
+ * their way; it detected the direction and can be asked to analyze it; or it never detected it, and
162
+ * nothing can be planned from it.
163
+ */
164
+ type DirectionAnalysis = 'analyzed' | 'analyzing' | 'unanalyzed' | 'undetected';
165
+ /** What the part's report and its pending request say of its directions. */
166
+ interface DirectionsKnown {
167
+ /** The directions analyzed — the report's candidates — or null before the report is read. */
168
+ analyzed: ReadonlyArray<PlanDirection> | null;
169
+ /** Every direction Toolpath detected, or null from a report that does not say. */
170
+ discovered: ReadonlyArray<PlanDirection> | null;
171
+ /** Toolpath is analyzing directions added to the part. */
172
+ pending: boolean;
173
+ }
174
+ declare const directionAnalysis: (direction: PlanDirection, { analyzed, discovered, pending }: DirectionsKnown) => DirectionAnalysis;
175
+
176
+ /** How deep a folder may sit below its setup (FLD7). */
177
+ declare const MAX_DEPTH = 6;
178
+
179
+ /** A folder: a grouping of work, the features pinned in it, and the folders inside it. */
180
+ interface DraftFolder {
181
+ id: string;
182
+ name: string;
183
+ /**
184
+ * Features pinned here — machined from this folder's direction, whatever else Toolpath decides.
185
+ * Tags (hex), each of that direction's reading of its surface. Only ever what someone pinned.
186
+ */
187
+ features: Array<string>;
188
+ folders: Array<DraftFolder>;
189
+ /** Set only on a tool orientation: the tilt it is cut from, inside an indexed setup. */
190
+ direction?: PlanDirection;
191
+ }
192
+ /** How a setup holds the part: indexed about one rotary axis, or two. Absent, it is 3 axis. */
193
+ type SetupProcess = '3+1' | '3+2';
194
+ /** A top-level folder: one way the part is held, facing its direction (Setup Z). */
195
+ interface DraftSetup extends DraftFolder {
196
+ direction: PlanDirection;
197
+ process?: SetupProcess;
198
+ }
199
+ /** The person's constraints: the setups and the faces ignored — what the plan's own edits change. */
200
+ interface Constraints {
201
+ setups: Array<DraftSetup>;
202
+ /**
203
+ * Faces already at their final surface, which no setup needs to reach: indices into the part
204
+ * report's regions, sorted. Sent to Toolpath with the plan as `doneRegions`.
205
+ */
206
+ done: Array<number>;
207
+ /**
208
+ * The kernel version of the part report the done faces were marked on: their indices are its
209
+ * numbering. Null with none marked.
210
+ */
211
+ doneKernel: string | null;
212
+ }
213
+ /** As many setups as the Engine takes in a stated plan, and the longest name worth keeping. */
214
+ declare const MAX_SETUPS = 64;
215
+ declare const MAX_NAME = 100;
216
+
217
+ /** Two directions are the same only bit for bit: Toolpath compares its direction tokens exactly. */
218
+ declare const sameDirection: (a: PlanDirection, b: PlanDirection) => boolean;
219
+ declare const isIndexed: (setup: Pick<DraftSetup, "process">) => boolean;
220
+ /** A folder where it sits: its setup, its parent, its depth, and the frame it is cut in. */
221
+ interface PlacedFolder {
222
+ folder: DraftFolder;
223
+ setup: DraftSetup;
224
+ parent: DraftFolder | null;
225
+ /** 0 for a setup. */
226
+ depth: number;
227
+ /** The direction it is cut from: its own as a setup or tool orientation, else its parent's. */
228
+ direction: PlanDirection;
229
+ /** The folder whose direction that is — itself for a setup or tool orientation. */
230
+ frameId: string;
231
+ /** Whether it is a tool orientation: a tilt of its own, inside an indexed setup. */
232
+ toolOrientation: boolean;
233
+ }
234
+ /**
235
+ * Every folder in tree order — each setup, then what is inside it depth first — with where it sits.
236
+ * A tool orientation counts only inside an indexed setup; elsewhere a folder's own direction is
237
+ * inert and it follows its parent.
238
+ */
239
+ declare const placedFolders: (setups: ReadonlyArray<DraftSetup>) => Array<PlacedFolder>;
240
+ declare const findPlaced: (setups: ReadonlyArray<DraftSetup>, id: string) => PlacedFolder | undefined;
241
+ /** A frame: one direction the plan is cut from, and every feature pinned in it or its followers. */
242
+ interface Frame {
243
+ /** The folder that faces it: a setup, or a tool orientation. */
244
+ id: string;
245
+ name: string;
246
+ /** The setup it is held in — its hold. */
247
+ holdId: string;
248
+ direction: PlanDirection;
249
+ features: Array<string>;
250
+ }
251
+ /** The plan's frames, in tree order: each setup's direction, then its tool orientations'. */
252
+ declare const framesOf: (setups: ReadonlyArray<DraftSetup>) => Array<Frame>;
253
+ /** How deep the folders run below this one, counting itself: 1 for a folder with none in it. */
254
+ declare const heightOf: (folder: DraftFolder) => number;
255
+ /**
256
+ * The draft with a folder, and everything in it, taken out. A setup goes from the top; a folder it
257
+ * leaves holding only one folder gives way to it (`liftLoneFolder`).
258
+ */
259
+ declare const removeFolder: (setups: ReadonlyArray<DraftSetup>, id: string) => Array<DraftSetup>;
260
+ /**
261
+ * The draft with several folders, and everything in them, taken out together — then each folder
262
+ * they leave holding only one folder gives way to it. All go before any gives way, so a folder
263
+ * taken out with its pair's parent can't be left standing in that parent's place.
264
+ */
265
+ declare const removeFolders: (setups: ReadonlyArray<DraftSetup>, ids: ReadonlyArray<string>) => Array<DraftSetup>;
266
+ /**
267
+ * No edit leaves a folder holding a single folder: the folder an edit leaves that way — one taken
268
+ * out of a pair, say — gives way to the folder in it, which comes up into its place. That folder
269
+ * keeps its name, its pins and its folders. It is cut as it was: where it followed, from the way its place was cut — a setup's direction, and its
270
+ * hold while a tilt is left in it to reach, or a tilt — and where it was a tilt of its own, from
271
+ * that tilt; a tilt come up to the top is a setup facing it, indexed only to reach the tilts inside
272
+ * it, as a tilt moved to the top is (FLD23).
273
+ *
274
+ * Only the folder named: a draft saved holding one elsewhere is left as it is, rather than
275
+ * restructured by an edit to something else. Its place's own count is unchanged, so nothing above
276
+ * it needs another look.
277
+ */
278
+ declare const liftLoneFolder: (setups: ReadonlyArray<DraftSetup>, id: string) => Array<DraftSetup>;
279
+ /** A new folder's name: "Folder N", one past the highest N any folder is called (FLD1). */
280
+ declare const nextFolderName: (names: ReadonlyArray<{
281
+ name: string;
282
+ }> | ReadonlyArray<string>) => string;
283
+ /**
284
+ * A folder inside another, at the end, following it in everything (FLD6) — or the draft unchanged
285
+ * where it would sit deeper than a folder may (FLD7). A folder holding no folders yet is split first:
286
+ * what it holds moves into a folder of its own, named as it is, and the new folder goes beside that —
287
+ * so no folder holds features and folders both, and none holds a single folder.
288
+ */
289
+ declare const addFolder: (setups: ReadonlyArray<DraftSetup>, parentId: string, id: string,
290
+ /** The id for the folder the work moves into, where the parent is split. */
291
+ workId?: string) => Array<DraftSetup>;
292
+ declare const renameFolder: (setups: ReadonlyArray<DraftSetup>, id: string, name: string) => Array<DraftSetup>;
293
+ /** What changing the plan did, or why it could not be done. */
294
+ type Edited = Array<DraftSetup> | {
295
+ refused: string;
296
+ };
297
+ /**
298
+ * Hold a setup 3 axis, 3+1 or 3+2. Back to 3 axis is refused while it holds tool orientations: they
299
+ * are tilts only an indexed setup reaches.
300
+ */
301
+ declare const setSetupProcess: (setups: ReadonlyArray<DraftSetup>, setupId: string, process: SetupProcess | undefined) => Edited;
302
+ /**
303
+ * Make a folder a tool orientation facing a direction of its own, or — with none — follow its parent
304
+ * again. A direction another frame already faces is refused: Toolpath takes each direction once.
305
+ */
306
+ declare const setToolOrientation: (setups: ReadonlyArray<DraftSetup>, folderId: string, direction: PlanDirection | null) => Edited;
307
+ /**
308
+ * Setups as stored before folders nested, read as a tree: every folder with a list of folders.
309
+ * Everything that reads a stored draft goes through this.
310
+ */
311
+ declare const withFolders: (setups: ReadonlyArray<DraftSetup>) => Array<DraftSetup>;
312
+ declare const isDirection: (value: unknown) => value is PlanDirection;
313
+ declare const copyDirection: ({ x, y, z }: PlanDirection) => PlanDirection;
314
+ /**
315
+ * A draft's setups as sent to be saved, checked — or why not. Folders at most six below their
316
+ * setup, every tag pinned once, and each direction a frame once, as Toolpath requires. Anything
317
+ * else stored with a folder — the stamps drafts once carried — is dropped without a word.
318
+ */
319
+ declare const parseDraftSetups: (value: unknown) => Array<DraftSetup> | string;
320
+ /** A setup facing a direction no frame faces yet, added last — or the draft unchanged. */
321
+ declare const addSetup: (setups: ReadonlyArray<DraftSetup>, direction: PlanDirection, id: string) => Array<DraftSetup>;
322
+ /** A setup of Toolpath's plan, as `foldersFromPlan` and `planFromResults` read it. */
323
+ interface PlannedSetup$1 {
324
+ orientations: ReadonlyArray<{
325
+ direction: PlanDirection;
326
+ /** The features planned from it, where the plan was served with its orientations. */
327
+ features?: ReadonlyArray<{
328
+ tag: string;
329
+ }>;
330
+ }>;
331
+ /** Every feature the setup takes, each once, marked where no pass cuts it. */
332
+ rows?: ReadonlyArray<{
333
+ tag: string;
334
+ mark?: string | false;
335
+ }>;
336
+ }
337
+ /** Folders facing each setup of Toolpath's plan, and nothing else: no pins (`statedFrom`). */
338
+ declare const foldersFromPlan: (planned: ReadonlyArray<PlannedSetup$1>, newId: () => string) => Array<DraftSetup>;
339
+ /** Toolpath's plan as constraints: its folders, and every feature pinned where it was planned (`statedFrom`). */
340
+ declare const planFromResults: (planned: ReadonlyArray<PlannedSetup$1>, newId: () => string) => Array<DraftSetup>;
341
+ /** A setup moved `by` places among the setups, clamped to the ends. */
342
+ declare const moveSetup: (setups: ReadonlyArray<DraftSetup>, id: string, by: number) => Array<DraftSetup>;
343
+ /**
344
+ * A folder moved `by` places among the folders beside it — the setups, or its parent's folders —
345
+ * clamped to the ends. Nothing about it changes but its place (FLD22).
346
+ */
347
+ declare const moveWithin: (setups: ReadonlyArray<DraftSetup>, id: string, by: number) => Array<DraftSetup>;
348
+ /**
349
+ * Indexed about one rotary axis or two: 3+1 when every tilt turns Setup Z about one axis square to
350
+ * it — every tilt in one plane through Setup Z — else 3+2. Straight up or down needs no particular
351
+ * axis.
352
+ */
353
+ declare const indexedFor: (setupDirection: PlanDirection, tilts: ReadonlyArray<PlanDirection>) => SetupProcess;
354
+ /** What pinning a feature did, or why it could not be done. */
355
+ type Pinned = {
356
+ setups: Array<DraftSetup>;
357
+ /** The folder it is pinned in, or was let go from. */
358
+ setupId: string;
359
+ /** A setup was added for the feature's direction, which no folder faced. */
360
+ added: boolean;
361
+ /** It was pinned there already, and is now let go. */
362
+ unpinned: boolean;
363
+ } | {
364
+ refused: string;
365
+ };
366
+ /** The folder a feature is pinned in, if any. */
367
+ declare const pinnedIn: (setups: ReadonlyArray<DraftSetup>, tag: string) => string | null;
368
+ /** The folder each feature is pinned in, by tag (`tagKey`): the first in tree order. */
369
+ declare const pinHomes: (setups: ReadonlyArray<DraftSetup>) => Map<string, string>;
370
+ /** A feature's pin, its tag in any case: the folder, and the tag as the pin spells it. */
371
+ declare const pinOf: (setups: ReadonlyArray<DraftSetup>, tag: string) => {
372
+ folderId: string;
373
+ tag: string;
374
+ } | null;
375
+ /**
376
+ * Pin a feature in a folder — taking it from wherever else it was pinned — or let it go if it is
377
+ * pinned there already. The caller has checked the folder faces the feature's way. A folder holds
378
+ * features or folders, never both: into one holding folders, the pin goes in a folder added inside
379
+ * it, following it, which holds just the feature.
380
+ */
381
+ declare const pinInto: (setups: ReadonlyArray<DraftSetup>, folderId: string, tag: string,
382
+ /** The id for the folder the pin goes in, where the folder named holds folders. */
383
+ newId?: string) => Pinned;
384
+ /**
385
+ * The folder a pin from this direction goes in: the frame facing that way — a setup or a tool
386
+ * orientation — or, where that holds folders, the first folder in it cut from its way that holds
387
+ * none (a folder holds features or folders, never both). Where the frame holds folders and none of
388
+ * them is cut from its way, the frame: `pinInto` adds a folder in it for the pin. Null where no
389
+ * frame faces it and pinning adds a setup.
390
+ */
391
+ declare const pinTargetOf: (setups: ReadonlyArray<DraftSetup>, direction: PlanDirection) => string | null;
392
+ /** The frame — a setup or a tool orientation — facing this direction: at most one does. */
393
+ declare const frameFacing: (setups: ReadonlyArray<DraftSetup>, direction: PlanDirection) => Frame | undefined;
394
+ /**
395
+ * Machine a feature from this direction: pin it in the folder facing that way — a setup or a tool
396
+ * orientation — or let it go if it is pinned there already. With no folder facing that way, a setup
397
+ * is added for it, last; `newId` is that setup's, or the folder's `pinInto` adds. Toolpath may refuse a pin — a profile outside the first setup, for now — and
398
+ * says so once Toolpath plans again.
399
+ */
400
+ declare const pinFrom: (setups: ReadonlyArray<DraftSetup>, direction: PlanDirection, tag: string, newId: string) => Pinned;
401
+ /** Let a pinned feature go: Toolpath decides again where it is machined. */
402
+ declare const unpinFeature: (setups: ReadonlyArray<DraftSetup>, folderId: string, tag: string) => Array<DraftSetup>;
403
+ /**
404
+ * A feature put back as `saved` had it: pinned, at its place, in the folders it was pinned in there,
405
+ * and in no other. Every other edit stands; a folder `saved` had that is gone since is passed over.
406
+ */
407
+ declare const restoreFeature: (setups: ReadonlyArray<DraftSetup>, saved: ReadonlyArray<DraftSetup>, tag: string) => Array<DraftSetup>;
408
+ /**
409
+ * A list stamped with what it was made against — faces marked done with a kernel's numbering — as
410
+ * it stands `now`: stamped with anything else, it no longer holds, and is let go.
411
+ */
412
+ declare const currentFor: <T>(list: ReadonlyArray<T> | undefined, stamp: string | null | undefined, now: string | null | undefined) => Array<T>;
413
+ /** Faces ignored, in order, numbered by `kernel` — none kept with no kernel to number them by. */
414
+ declare const ignoredAs: (done: ReadonlyArray<number>, kernel: string | null) => Pick<Constraints, "done" | "doneKernel">;
415
+ /** The faces ignored with `faces` among them, once each. */
416
+ declare const withIgnored: (plan: Pick<Constraints, "done" | "doneKernel">, faces: ReadonlyArray<number>, kernel: string | null) => Pick<Constraints, "done" | "doneKernel">;
417
+ /** The faces ignored with `faces` no longer among them, its kernel let go once none are left. */
418
+ declare const withoutIgnored: (plan: Pick<Constraints, "done" | "doneKernel">, faces: ReadonlyArray<number>, kernel: string | null) => Pick<Constraints, "done" | "doneKernel">;
419
+ /** The faces ignored with `faces` back as `saved` had them, and every other as `plan` has it. */
420
+ declare const ignoredAsSaved: (plan: Pick<Constraints, "done" | "doneKernel">, saved: Pick<Constraints, "done" | "doneKernel">, faces: ReadonlyArray<number>, kernel: string | null) => Pick<Constraints, "done" | "doneKernel">;
421
+ /** A pin of the person's: the feature, and the folder it is pinned in. */
422
+ interface PinnedFeature {
423
+ tag: string;
424
+ setupId: string;
425
+ }
426
+ /** The person's pins that `test` keeps, in every folder each is pinned in. */
427
+ declare const pinsWhere: (setups: ReadonlyArray<DraftSetup>, test: (tag: string) => boolean) => Array<PinnedFeature>;
428
+ /** What pinning, and ignoring faces, need to know of the part. */
429
+ interface PlanRules {
430
+ regionsOf: (tag: string) => ReadonlyArray<number>;
431
+ /** The kernel the part's faces are numbered by. */
432
+ kernel: string | null;
433
+ }
434
+ /** The plan as Toolpath's `setupPlan` takes it: setups in order, each one direction and its pins. */
435
+ interface Statement {
436
+ setups: Array<{
437
+ orientations: Array<{
438
+ direction: PlanDirection;
439
+ features: Array<string>;
440
+ }>;
441
+ }>;
442
+ }
443
+ /**
444
+ * What the draft tells Toolpath: every frame, in tree order, each a 3-axis setup of its own with
445
+ * its pins — a floor Toolpath appends to. Null with no frames: Toolpath plans the part itself.
446
+ * Setup `i` of the statement is frame `i`.
447
+ */
448
+ declare const statementOf: (setups: ReadonlyArray<DraftSetup>) => Statement | null;
449
+ /** A hold: one of the draft's setups, and the Engine setups cut in it. */
450
+ interface Hold {
451
+ key: string;
452
+ name: string;
453
+ setupIdxs: Array<number>;
454
+ }
455
+ /**
456
+ * Toolpath's setups grouped into the draft's holds: each setup cut from a direction one of the
457
+ * draft's frames faces belongs to that frame's setup's hold. Any other — one Toolpath added past
458
+ * the statement, or one with no direction — is a hold of its own, "Setup N". In the order Toolpath
459
+ * machines them.
460
+ */
461
+ declare const holdsFor: (setups: ReadonlyArray<DraftSetup>, planned: ReadonlyArray<{
462
+ idx: number;
463
+ direction?: PlanDirection | null;
464
+ }>) => Array<Hold>;
465
+ /** Where a moved folder lands: among the setups, or inside a folder — at a place in its list. */
466
+ interface Landing {
467
+ /** The folder it lands in, or null for the top: a setup. */
468
+ parentId: string | null;
469
+ /** Its place among what is there once it has left where it was. */
470
+ index: number;
471
+ }
472
+ /**
473
+ * Move a folder, with everything in it (FLD20–27), or say why not:
474
+ * - Reordered where it is, nothing about it changes.
475
+ * - To the top, a tool orientation becomes a setup facing its tilt — indexed, if it holds tilts of
476
+ * its own. A folder that follows can't: its direction is a setup already.
477
+ * - Into a folder cut from the same way, it follows it, dropping a setup's hold or its own tilt.
478
+ * - Into a folder cut from another way, it becomes a tool orientation keeping its direction, and the
479
+ * setup it lands in is indexed to turn the part to it: 3+1, or 3+2 where one axis won't reach.
480
+ * Never into itself, below a folder in it, deeper than six, or making a direction two frames.
481
+ */
482
+ declare const moveFolder: (setups: ReadonlyArray<DraftSetup>, id: string, to: Landing,
483
+ /** The id for a parent made to hold both, where it is dropped on a folder holding work. */
484
+ newId?: string) => Edited;
485
+ /**
486
+ * Move a feature's row into a folder — pinning it there, taking it from wherever else it was pinned
487
+ * — where the folder is cut from the feature's own direction; or say why not. Onto a parent, it
488
+ * goes to the first folder in it cut from that direction that holds no folders; with none, onto a
489
+ * parent cut from that direction itself, into a folder added in it, as `pinInto` adds.
490
+ */
491
+ declare const moveFeature: (setups: ReadonlyArray<DraftSetup>, tag: string, featureDirection: PlanDirection, folderId: string,
492
+ /** The id for a folder made to hold the row, where it is dropped on a parent. */
493
+ newId?: string) => Edited;
494
+
495
+ /** A region as the part's model has it: its index, and the CAD face it was split from. */
496
+ type SplitRegion = {
497
+ idx: number;
498
+ splitOrigin: number;
499
+ };
500
+ /**
501
+ * The regions of the CAD face a region was split from: those sharing its `splitOrigin`. A region
502
+ * with none — unknown to the model — is a face of its own.
503
+ */
504
+ declare const faceRegions: (regions: ReadonlyArray<SplitRegion>, region: number) => Array<number>;
505
+ /** Where a click is read from: an open folder's way, Ignore, or the whole part. */
506
+ type ReadingScope =
507
+ /** The folder's direction alone, largest first, the viewer's rank breaking ties. */
508
+ {
509
+ kind: 'folder';
510
+ id: string;
511
+ direction: PlanDirection;
512
+ }
513
+ /** The most specific feature first; profiles offered but never the default. */
514
+ | {
515
+ kind: 'ignore';
516
+ }
517
+ /** Every direction, largest first, the viewer's rank breaking ties. */
518
+ | {
519
+ kind: 'all';
520
+ };
521
+ /** What a click gives: the faces it is on, the viewer's ranking of their owners, and a feature meant. */
522
+ interface ReadingAt {
523
+ regions: ReadonlyArray<number>;
524
+ /** The viewer's ranking of the owners, best first — breaking ties in size. */
525
+ ranked?: ReadonlyArray<string>;
526
+ /** A feature to take as the default where it is among the readings: a list row's own, say. */
527
+ prefer?: string | null;
528
+ }
529
+ /** What the readings need of the part and the plan. */
530
+ interface ReadingContext {
531
+ /** The part's features, in report order. */
532
+ features: ReadonlyArray<CoverageFeature>;
533
+ /** A feature by tag in any case: the way it is cut. */
534
+ featureOf: (tag: string) => {
535
+ direction: PlanDirection;
536
+ } | null;
537
+ /** The folder a feature is pinned in, or null: a reading already pinned is the default. */
538
+ pinnedIn?: (tag: string) => string | null;
539
+ }
540
+ /** The features a click reads, in the scope's order, and the one it means by default. */
541
+ interface Readings {
542
+ tags: Array<string>;
543
+ default: string | null;
544
+ }
545
+ /**
546
+ * The features a click on `at.regions` reads in `scope`, and which it means by default: `prefer`
547
+ * where it is among them, else one already pinned — in the folder for `folder`, anywhere for
548
+ * `all` — else the first; for `ignore`, the first that is not a profile, else null.
549
+ */
550
+ declare const readingsFor: (at: ReadingAt, scope: ReadingScope, context: ReadingContext) => Readings;
551
+
552
+ /**
553
+ * Ignore faces. A pin — in any folder — whose every face is ignored with them is unpinned: the
554
+ * ignore wins. A plain unpin: the feature is open, its faces ignored.
555
+ */
556
+ declare const ignoreEdit: (plan: Constraints, regions: ReadonlyArray<number>, context: Pick<PlanRules, "kernel" | "regionsOf">) => {
557
+ intent: Constraints;
558
+ unpinned: Array<PinnedFeature>;
559
+ };
560
+ /** What a status note adds of the pins ignoring took out, by folder: nothing, or " Unpinned from …". */
561
+ declare const unpinnedNote: (unpinned: ReadonlyArray<PinnedFeature>, setups: ReadonlyArray<DraftSetup>) => string;
562
+ /** What a status note says of regions no longer ignored: nothing, or " Region 4 no longer ignored.". */
563
+ declare const unignoredNote: (regions: ReadonlyArray<number>) => string;
564
+ /** Stop ignoring faces. */
565
+ declare const unignoreEdit: (plan: Constraints, regions: ReadonlyArray<number>, context: Pick<PlanRules, "kernel">) => Constraints;
566
+ /**
567
+ * What a click on the part takes while ignoring: the region clicked, every region of the CAD face
568
+ * it was split from, or a feature's regions.
569
+ */
570
+ type IgnoreMode = 'region' | 'face' | 'feature';
571
+ /**
572
+ * Every feature a click on `region` reads, in Feature mode, as a choice offers them: the most
573
+ * specific first — fewest regions, then by tag — and profiles (`isFallback`) last, offered but never
574
+ * the default. Owners of exactly the same regions are one.
575
+ */
576
+ declare const featuresAt: (region: number, features: ReadonlyArray<CoverageFeature>) => Array<CoverageFeature>;
577
+ /** What a click took: the feature it means, in Feature mode, and the regions. */
578
+ interface IgnoredAs {
579
+ tag: string | null;
580
+ regions: ReadonlyArray<number>;
581
+ }
582
+ /**
583
+ * What a click on `region` takes, by mode: the region clicked; in Face mode every region of the CAD
584
+ * face it was split from (`faceRegions`, the kernel's `splitOrigin` lineage); in Feature mode the
585
+ * regions of the feature the click means (`featureAt`), the region alone where no feature does.
586
+ * What a click acts on and what the pointer lights, alike.
587
+ */
588
+ declare const ignoreSelection: ({ region, mode, features, regions, }: {
589
+ region: number;
590
+ mode: IgnoreMode;
591
+ features: ReadonlyArray<CoverageFeature>;
592
+ /** The part's regions, with the CAD face each was split from. */
593
+ regions: ReadonlyArray<SplitRegion>;
594
+ }) => IgnoredAs;
595
+ /**
596
+ * What a group of regions is called — a tray row, a status note: its region ids, ascending.
597
+ * "Region 4", or "Regions 4, 6" for a feature's regions. Never a feature's name.
598
+ */
599
+ declare const regionLabel: (regions: ReadonlyArray<number>) => string;
600
+ /** The plan with a click's regions ignored as `saved` had them, and nothing else changed. */
601
+ declare const takeBackIgnore: (plan: Constraints, saved: Constraints, regions: ReadonlyArray<number>, context: Pick<PlanRules, "kernel">) => Constraints;
602
+ /** What a click on the part does while ignoring (`ignoreClick`). */
603
+ type IgnoreClick =
604
+ /** The region was ignored: the ignored regions among those taken are let go. */
605
+ {
606
+ kind: 'unignore';
607
+ regions: Array<number>;
608
+ }
609
+ /** What the click takes is ignored. */
610
+ | {
611
+ kind: 'ignore';
612
+ regions: Array<number>;
613
+ };
614
+ /**
615
+ * What a click on region `region`, taking `regions` (`ignoreSelection`), does while ignoring:
616
+ * ignored, the ignored regions among those taken are let go; otherwise they are ignored.
617
+ */
618
+ declare const ignoreClick: ({ region, ignored, regions, }: {
619
+ region: number;
620
+ /** The regions ignored now. */
621
+ ignored: ReadonlySet<number>;
622
+ /** The regions the click takes: the CAD face clicked, or a feature's faces. */
623
+ regions: ReadonlyArray<number>;
624
+ }) => IgnoreClick;
625
+
626
+ /**
627
+ * One edit to a plan's constraints: its setups, folders, pins and ignored faces. Every id an action
628
+ * names for something it makes must be new to the draft, even where the edit ends up not needing it;
629
+ * ids from `crypto.randomUUID()` are.
630
+ * `direction` on a feature is the direction that reading of it was read from, as the part's
631
+ * features name it: the package can't check it.
632
+ */
633
+ type DraftAction =
634
+ /**
635
+ * A folder inside another, at the end (`addFolder`). `id` is the new folder's; `workId` is for the
636
+ * folder the parent's own work moves into, where the parent held no folders yet.
637
+ */
638
+ {
639
+ kind: 'addFolder';
640
+ parentId: string;
641
+ id: string;
642
+ workId: string;
643
+ } | {
644
+ kind: 'renameFolder';
645
+ id: string;
646
+ name: string;
647
+ }
648
+ /**
649
+ * What Delete removes: folders — setups too — with all they hold, and pinned features, each taken
650
+ * out of the folder named (`setupId`). With every setup named, it is Remove all: Toolpath plans the
651
+ * part as it would. Folders gone already are passed over.
652
+ */
653
+ | {
654
+ kind: 'remove';
655
+ folders: ReadonlyArray<string>;
656
+ features?: ReadonlyArray<PinnedFeature>;
657
+ }
658
+ /**
659
+ * A folder dropped somewhere in the tree (`moveFolder`). `newId` is for the parent made to hold
660
+ * both, where it is dropped on a folder holding work.
661
+ */
662
+ | {
663
+ kind: 'moveFolder';
664
+ id: string;
665
+ to: Landing;
666
+ newId: string;
667
+ }
668
+ /** A folder moved `by` whole places up (negative) or down among the folders beside it. */
669
+ | {
670
+ kind: 'moveWithin';
671
+ id: string;
672
+ by: number;
673
+ }
674
+ /** A setup facing a direction no setup or tool orientation faces yet, last. */
675
+ | {
676
+ kind: 'addSetup';
677
+ direction: PlanDirection;
678
+ id: string;
679
+ }
680
+ /** Hold a setup 3+1 or 3+2, or 3 axis (`null`). */
681
+ | {
682
+ kind: 'setProcess';
683
+ setupId: string;
684
+ process: SetupProcess | null;
685
+ }
686
+ /** Make a folder a tool orientation facing `direction`, or follow its parent again (`null`). */
687
+ | {
688
+ kind: 'setToolOrientation';
689
+ folderId: string;
690
+ direction: PlanDirection | null;
691
+ }
692
+ /**
693
+ * A click on the part in an open folder (`folderClick`), or a pin into a folder named (`pinEdit`):
694
+ * the feature pinned there — or, pinned there already, taken out. `newId` is for the folder a pin
695
+ * goes in, where the folder named holds folders.
696
+ */
697
+ | {
698
+ kind: 'pinInto';
699
+ tag: string;
700
+ direction: PlanDirection;
701
+ folderId: string;
702
+ newId: string;
703
+ }
704
+ /**
705
+ * Machine a feature from its direction (`pinEdit`): pinned in the folder facing that way, or in a
706
+ * new setup facing it — or, pinned in that direction's folders already, let go. `newId` is that
707
+ * setup's, or the folder's a pin into a parent makes.
708
+ */
709
+ | {
710
+ kind: 'pinFrom';
711
+ tag: string;
712
+ direction: PlanDirection;
713
+ newId: string;
714
+ }
715
+ /**
716
+ * A feature's row dropped on a folder (`moveFeature`): pinned there, or in the first folder in it
717
+ * cut from its direction, as any pin is (`withPin`). `newId` is for a folder made to hold it, where
718
+ * it is dropped on a parent.
719
+ */
720
+ | {
721
+ kind: 'moveFeature';
722
+ tag: string;
723
+ direction: PlanDirection;
724
+ folderId: string;
725
+ newId: string;
726
+ }
727
+ /**
728
+ * A pick among the features a click in a folder read (`chooseReading`): `reading` meant instead of
729
+ * `tag`, which the click pinned (`target: 'pin'`) or took out (`'takeOut'`) in `folderId`. Where
730
+ * the click's edit no longer stands — Undo, Discard — it is made again first, in the same step.
731
+ * `readings` are every feature the click read. Needs the plan as applied. A folder gone since
732
+ * — Undo — changes nothing.
733
+ */
734
+ | {
735
+ kind: 'choosePinReading';
736
+ tag: string;
737
+ target: 'pin' | 'takeOut';
738
+ reading: string;
739
+ readings: ReadonlyArray<string>;
740
+ folderId: string;
741
+ }
742
+ /**
743
+ * A pick among the features an Ignore click read: `tag` ignored instead of what the click took
744
+ * (`click`, as `ignoreSelection` answers it), whose faces go back as applied where its edit still
745
+ * stands. The click's own feature, its edit standing, changes nothing. Needs the plan as applied.
746
+ */
747
+ | {
748
+ kind: 'chooseIgnoreReading';
749
+ tag: string;
750
+ click: IgnoredAs;
751
+ }
752
+ /**
753
+ * Start from Toolpath's plan, on a plan with no folders: folders facing each of its setups
754
+ * (`foldersFromPlan`), and with `pins` every feature pinned where it was planned
755
+ * (`planFromResults`), its faces no longer ignored. New folders' ids are `idSeed`, `-` and a count: no `:`, which
756
+ * an app may use to join an id with other keys.
757
+ */
758
+ | {
759
+ kind: 'fromPlan';
760
+ planned: ReadonlyArray<PlannedSetup$1>;
761
+ pins: boolean;
762
+ idSeed: string;
763
+ }
764
+ /** Let a pinned feature go: Toolpath decides again where it is machined. */
765
+ | {
766
+ kind: 'unpin';
767
+ tag: string;
768
+ }
769
+ /** Ignore faces: region indices, in the kernel `PlanRules` names. */
770
+ | {
771
+ kind: 'ignore';
772
+ regions: ReadonlyArray<number>;
773
+ } | {
774
+ kind: 'unignore';
775
+ regions: ReadonlyArray<number>;
776
+ };
777
+ type DraftActionKind = DraftAction['kind'];
778
+ /** Every kind of action, in the order `actionsFor` lists them. */
779
+ declare const DRAFT_ACTION_KINDS: ReadonlyArray<DraftActionKind>;
780
+ /**
781
+ * What an action did beyond the draft, for the page to say: what Toolpath's own app puts on its
782
+ * status line. Empty lists and `false` where there is nothing to say.
783
+ */
784
+ interface DraftFacts {
785
+ /** A pin's: the person's pins it let go, because it covers every face of each. By tag. */
786
+ replaced: ReadonlyArray<string>;
787
+ /**
788
+ * Faces ignored before the action and not after, ascending: what a pin, `fromPlan` with pins and
789
+ * `unignore` give back. A pick among an Ignore click's readings says only what it ignores, so
790
+ * the faces it gives back are not here. Toolpath's own app says these after every kind but Clear
791
+ * (`unignore` of every ignored face), where it says nothing.
792
+ */
793
+ unignored: ReadonlyArray<number>;
794
+ /** An ignore's: the pins it let go, each with the folder it was in. */
795
+ unpinned: ReadonlyArray<PinnedFeature>;
796
+ /** A pin's: a setup was added for it, facing its way. */
797
+ added: boolean;
798
+ /** A pin's: it was pinned there already, and is now let go. */
799
+ letGo: boolean;
800
+ /** A pin's: the folder it is pinned in, or was let go from — what its note names. */
801
+ home: string | null;
802
+ }
803
+ /**
804
+ * What an action made of the draft, or why it can't be made. `folderId` is the folder Toolpath's own
805
+ * app opens after it: the one `addFolder`, `addSetup` or `moveFolder` made or moved, or the one a
806
+ * `moveFeature` row lands in. After any other action the open folder stays open. After `remove` the
807
+ * page chooses: Toolpath's own app opens the nearest folder the open one was in, or the part.
808
+ */
809
+ type DraftResult<T extends Constraints> = {
810
+ draft: T;
811
+ folderId?: string;
812
+ facts: DraftFacts;
813
+ } | {
814
+ refused: string;
815
+ };
816
+ /**
817
+ * Carry out one action on a draft: the draft after it, every other part of it as it was, or why it
818
+ * can't be made. `rules` reads the part: a feature's faces, and the kernel that numbers them.
819
+ *
820
+ * A pin is what pinning is in Toolpath's own app: the person's pins it covers are let go, and its
821
+ * faces are no longer ignored; pinning a feature where it is pinned already lets it go, as a click
822
+ * there does. Ignoring faces lets go of every pin they cover. An unpin of what is pinned nowhere, and
823
+ * a reorder past the end, change nothing. Where the functions in `plan-draft` would quietly change
824
+ * nothing — a folder too deep, a folder gone — this refuses, saying why. `saved`, the plan as
825
+ * applied, is what the two picks among a click's readings put back; `planSession` passes it.
826
+ */
827
+ declare const applyDraftAction: <T extends Constraints>(draft: T, action: DraftAction, rules: PlanRules, saved?: Constraints) => DraftResult<T>;
828
+ /** What a page asks `actionsFor` about: what the person clicked, or picked. */
829
+ type ActionTarget =
830
+ /** The part itself: the tree's top row. */
831
+ {
832
+ part: true;
833
+ }
834
+ /** A setup or a folder, by id. */
835
+ | {
836
+ folder: string;
837
+ }
838
+ /** One direction's reading of a feature: its tag, and the direction it is read from. */
839
+ | {
840
+ feature: string;
841
+ direction: PlanDirection;
842
+ }
843
+ /** Faces picked on the part: region indices, in the kernel `rules` names. */
844
+ | {
845
+ faces: ReadonlyArray<number>;
846
+ };
847
+ /**
848
+ * What can be done to this, as the draft stands: the kinds of action `applyDraftAction` would make
849
+ * here, in `DRAFT_ACTION_KINDS` order. A page offers these and no others. An action named here can
850
+ * still be refused for its details — a drop on one folder or another — and says why when it is.
851
+ * Three kinds follow other controls and are never named here: `choosePinReading` and
852
+ * `chooseIgnoreReading`, offered where a click read more than one feature, and `fromPlan`, offered
853
+ * while the plan holds no folders and Toolpath has planned the part.
854
+ */
855
+ declare const actionsFor: (draft: Constraints, target: ActionTarget, rules: Pick<PlanRules, "kernel">) => Array<DraftActionKind>;
856
+
857
+ /**
858
+ * The tree's part row: its key, its drop target's id, and as the page's open id the part active, its
859
+ * summary shown. No folder has it as an id.
860
+ */
861
+ declare const PART_ROW = "part";
862
+ /**
863
+ * What the page's `openId` holds while Ignore is open: not a folder, but held for its Save as one
864
+ * is, and left the same way. No folder has it as an id.
865
+ */
866
+ declare const IGNORE = "ignore";
867
+ /** One feature a direction takes: its tag, and its type and label from the part's analysis. */
868
+ interface PlanFeatureRow {
869
+ tag: string;
870
+ label: string;
871
+ /** The Engine's feature type (`blind_hole`, `open_pocket`), which its icon is drawn from. */
872
+ type?: string;
873
+ /** A hole's bore, once its sheet is in: what holes of a type are grouped by. */
874
+ bore?: FeatureBore;
875
+ }
876
+ /** A hole's bore: its diameter in millimetres, and as the page says it (`⌀6.35 mm`). */
877
+ interface FeatureBore {
878
+ diameter: number;
879
+ label: string;
880
+ }
881
+ /** A feature type as a group of them is headed: `blind_hole` → `Blind holes`, `boss` → `Bosses`. */
882
+ declare const featureTypePlural: (type: string | undefined) => string;
883
+ /** Whether a feature type is a hole, whose rows are grouped again by their bore. */
884
+ declare const isHoleType: (type: string | undefined) => boolean;
885
+ /**
886
+ * A group of a folder's rows under one header: the features of one type — and, inside a hole
887
+ * type's, those of one bore. Only a way of listing them: each row is still pinned, taken out and
888
+ * carried on its own, and nothing is dropped on a group.
889
+ */
890
+ interface FeatureGroupView {
891
+ /** Unique within the folder: what its fold is remembered by. */
892
+ key: string;
893
+ /** A type's group, or a bore's inside a hole type's. */
894
+ level: 'type' | 'bore';
895
+ type: string | undefined;
896
+ label: string;
897
+ /** The rows listed straight under it: a hole type's with no bore read yet, after its bores. */
898
+ rows: Array<PlanFeatureRow>;
899
+ /** A hole type's bores, smallest first. */
900
+ groups: Array<FeatureGroupView>;
901
+ /** Every tag in it, in the order listed: what taking the group out takes. */
902
+ tags: Array<string>;
903
+ }
904
+ /**
905
+ * A folder's rows as the tree lists them: a group per feature type, in the order its first row was
906
+ * pinned, each row in its pinned order — and a hole type's rows grouped again by bore, smallest
907
+ * first, any with no bore read yet after them. A row of no type read yet is under Other.
908
+ */
909
+ declare const featureGroups: (rows: ReadonlyArray<PlanFeatureRow>) => Array<FeatureGroupView>;
910
+ /** One direction of a setup — the way the tool points — with the features cut from it. */
911
+ interface PlanOrientationView {
912
+ id: string;
913
+ direction: PlanDirection;
914
+ /** Its place among the part's candidate directions, which is its colour; -1 when not one. */
915
+ directionIndex: number;
916
+ features: Array<PlanFeatureRow>;
917
+ }
918
+ /**
919
+ * A folder as the tree shows it — a setup at the top, the folders inside it below. Its one
920
+ * orientation is the direction it is cut from and the rows in it.
921
+ */
922
+ interface PlanSetupView {
923
+ id: string;
924
+ name: string;
925
+ /** A setup's hold: `3 axis` from one direction, `3+1` / `3+2` turning the part to tilts. */
926
+ process: '3axis' | '3+1' | '3+2';
927
+ orientations: Array<PlanOrientationView>;
928
+ /** 0 for a setup. */
929
+ depth: number;
930
+ /** The setup it is in (itself for a setup), and the folder it is in, if any. */
931
+ setupId: string;
932
+ parentId: string | null;
933
+ /** A tilt of its own inside an indexed setup. */
934
+ toolOrientation: boolean;
935
+ /** Whether it faces its own direction — a setup or tool orientation — rather than following. */
936
+ isFrame: boolean;
937
+ folders: Array<PlanSetupView>;
938
+ }
939
+ /** A setup of Toolpath's plan, as `planView` lays it out: its rows, and what it left uncut. */
940
+ interface PlannedSetupView extends PlanSetupView {
941
+ /** Features the setup was meant to machine that no pass in it does. */
942
+ notMachined: Array<PlanFeatureRow>;
943
+ /**
944
+ * Of those, the ones a pass in it does cut, but short: roughed, and owed a finish no pass gives
945
+ * (`notFinishedIn`). The rest are not machined at all.
946
+ */
947
+ notFinished: Array<string>;
948
+ operations: number;
949
+ }
950
+ /** Every folder of the tree, in tree order. */
951
+ declare const allFolders: <T extends PlanSetupView>(views: ReadonlyArray<T>) => Array<T>;
952
+ /** A folder's rows as the tree lists them. */
953
+ declare const rowsOf: (folder: PlanSetupView) => Array<PlanFeatureRow>;
954
+ /** Whether a folder lists a feature among its rows, its tag spelled in any case. */
955
+ declare const listsTag: (folder: PlanSetupView, tag: string) => boolean;
956
+ /** A folder's name with the folders it is in: `Folder 1 › Side`. */
957
+ declare const folderPath: (setups: ReadonlyArray<PlanSetupView>, folderId: string) => string;
958
+ /** What the view needs to know about the part: which candidate a direction is, and what a tag is. */
959
+ interface PlanPart {
960
+ directionIndex: (direction: PlanDirection) => number;
961
+ featureLabel: (tag: string) => string;
962
+ /** The Engine's type for a tag, when the part's analysis has read it. */
963
+ featureType?: (tag: string) => string | undefined;
964
+ /** A hole's bore, once its sheet is in. */
965
+ featureBore?: (tag: string) => FeatureBore | undefined;
966
+ }
967
+
968
+ /**
969
+ * The plan's setups, each with every direction it is machined from.
970
+ *
971
+ * The plan's own statement (`setupPlan`) says both, and is what a plan is edited from. An Engine
972
+ * that does not serve one (before API 1.19) gives each setup only its first direction, so the
973
+ * features are read off its passes instead: every tag an action cuts, in machining order.
974
+ */
975
+ declare const planView: (plan: Pick<EnginePlan, "setups" | "setupPlan">, part: PlanPart) => Array<PlannedSetupView>;
976
+ /**
977
+ * A plan's count of holds and of the directions they are machined from (FLD60): a setup is one
978
+ * hold — an indexed one however many tilts it turns to, a 3 axis one however its work is grouped —
979
+ * and each direction a frame is cut from is one orientation.
980
+ */
981
+ declare const planCounts: (setups: ReadonlyArray<PlanSetupView>) => {
982
+ setups: number;
983
+ orientations: number;
984
+ };
985
+ /** A colour on one feature, and how strongly — the viewer's `FeatureHighlight` (the DFM view's paint). */
986
+ interface PlanHighlight {
987
+ tag: string;
988
+ color: number;
989
+ weight: number;
990
+ }
991
+ /** A colour on one face, and how strongly it covers the surface — the viewer's `RegionHighlight`. */
992
+ interface FacePaint {
993
+ region: number;
994
+ color: number;
995
+ weight: number;
996
+ }
997
+ /** The colour ignored faces are painted, and Ignore's mark: slate — finished, so left alone. */
998
+ declare const DONE_COLOR = 6583435;
999
+ /** The red the faces nothing machines are painted, on every part viewer. */
1000
+ declare const UNMACHINED_FACE_COLOR = 14427686;
1001
+ /**
1002
+ * With a folder open, what only the others take: a dark neutral gray under their hatching (Tailwind
1003
+ * neutral-600), darker than ignored faces' slate, which is lighter and blue.
1004
+ */
1005
+ declare const OTHER_FOLDER_COLOR = 5395026;
1006
+ /** What the paint and the hatches read of the plan: which folder is open, and who lists each feature. */
1007
+ interface PlanPaintInput {
1008
+ faces: Coverage['faces'];
1009
+ setups: ReadonlyArray<PlanSetupView>;
1010
+ /** A folder's id; `PART_ROW` or `IGNORE`, no folder open. */
1011
+ openId: string;
1012
+ colorOf: (orientation: PlanOrientationView) => number;
1013
+ /** Direction colours on: every folder paints. Off, only the open folder and its insides. */
1014
+ everyFolder?: boolean;
1015
+ }
1016
+ /**
1017
+ * The model's colouring, face by face, as `classifyFaces` reads the plan — the one rule for what
1018
+ * machines each face, in either view. A pinned face takes its folder's colour in full, and so does
1019
+ * a face Toolpath machines, its setup's; an ignored face is slate (`DONE_COLOR`); an open face —
1020
+ * left to Toolpath — is left bare; a Not machined face red (`UNMACHINED_FACE_COLOR`). With no folder
1021
+ * open every folder paints, with secondary colours hatched on shared faces; with one open, only
1022
+ * its own direction does — it and the folders inside it facing the same way (FLD59). Every other
1023
+ * direction, inside it or not, is a dark gray
1024
+ * (`OTHER_FOLDER_COLOR`) with no tint of its own, hatched in its colour over the part
1025
+ * (`planHatch`). With direction colours off (MAP73), only the open folder's direction paints.
1026
+ */
1027
+ declare const planPaint: ({ uncovered, ...input }: PlanPaintInput & {
1028
+ /** Paint what no folder covers — Not machined red. Off where the DFM flags paint. */
1029
+ uncovered?: boolean;
1030
+ }) => Array<FacePaint>;
1031
+ /** Diagonal lines across one face, in one colour: the viewer canvas's `RegionHatch`. */
1032
+ interface FaceHatch {
1033
+ region: number;
1034
+ color: number;
1035
+ }
1036
+ /**
1037
+ * With a folder open, what the other directions take, as lines across the part rather than paint:
1038
+ * each face a feature of another direction includes — another folder's, or a tilt inside the open
1039
+ * one — is hatched in that direction's colour, over the gray, or over the open folder's own colour
1040
+ * where it takes the face too, so a face touched from more than one direction shows each. With no
1041
+ * folder open, the first owner's colour paints the face (`planPaint`), and the remaining colours
1042
+ * are hatched over it. A colour once per face. Nothing with direction colours off.
1043
+ */
1044
+ declare const planHatch: (input: PlanPaintInput) => Array<FaceHatch>;
1045
+ /**
1046
+ * The draft as the page lays it out: its folders, in its order and with its names, each listing
1047
+ * what is pinned in it in the order it was pinned (MP-5). Nothing of Toolpath's: the constraints,
1048
+ * and only those.
1049
+ */
1050
+ declare const draftView: (draft: Pick<Constraints, "setups">, part: PlanPart) => Array<PlanSetupView>;
1051
+ /**
1052
+ * The statements Toolpath refused of a stated plan, one per clause, from the error its job failed
1053
+ * with — or null when the job failed for some other reason. Toolpath lists the first few and says
1054
+ * how many more; that tail is kept as a clause of its own.
1055
+ */
1056
+ declare const refusalClauses: (error: string | null) => Array<string> | null;
1057
+
1058
+ /**
1059
+ * Where it would land (MAP48): on a folder's row, before it, inside it or after it — the top, middle
1060
+ * and bottom of the row — or on the part's row, first or last among the setups.
1061
+ */
1062
+ type DropAt = {
1063
+ id: string;
1064
+ zone: 'before' | 'inside' | 'after';
1065
+ } | {
1066
+ id: typeof PART_ROW;
1067
+ zone: 'first' | 'last';
1068
+ };
1069
+ /** A folder as the list shows it: where it sits, and how many levels of folders it holds. */
1070
+ interface FlatFolder {
1071
+ id: string;
1072
+ parentId: string | null;
1073
+ depth: number;
1074
+ /** Levels of folders below it, which go where it goes: 0 for one with none inside. */
1075
+ height: number;
1076
+ }
1077
+ interface FolderLike {
1078
+ id: string;
1079
+ parentId: string | null;
1080
+ depth: number;
1081
+ folders: ReadonlyArray<FolderLike>;
1082
+ }
1083
+ /**
1084
+ * The folders shown, in tree order: a folder's own inside it only while it is open. The carried
1085
+ * folder's are left out — they travel with it — so the list is what it can be dropped among.
1086
+ */
1087
+ declare const flattenFolders: (setups: ReadonlyArray<FolderLike>, isOpen: (id: string) => boolean, carriedId?: string | null) => Array<FlatFolder>;
1088
+ /** Where the carried folder would land: its depth, the folder it would be in, and the drop. */
1089
+ interface Projection {
1090
+ depth: number;
1091
+ parentId: string | null;
1092
+ /** The tree's drop for that place; null where it would land where it already is. */
1093
+ at: DropAt | null;
1094
+ }
1095
+ /**
1096
+ * Where a carried folder would land in the gap `gap` of the list without it — 0 before the first
1097
+ * folder, 1 after it, and so on — dragged `offsetX` sideways. Its depth is its own plus a level for
1098
+ * every `indent` dragged right, kept to what the place allows: no deeper than one below the folder
1099
+ * before it, no shallower than the one after it — and no deeper than the plan allows with the
1100
+ * folders it carries.
1101
+ */
1102
+ declare const projectFolder: (items: ReadonlyArray<FlatFolder>, activeId: string, gap: number, offsetX: number, indent: number, maxDepth: number) => Projection | null;
1103
+ /** The gap a point is in: how many of the folders' rows, without the carried one, it is below. */
1104
+ declare const gapAt: (centres: ReadonlyArray<{
1105
+ id: string;
1106
+ centreY: number;
1107
+ }>, activeId: string, y: number) => number;
1108
+
1109
+ /**
1110
+ * Why a feature is left: Toolpath gave it to a setup whose passes leave it (`planned`); left it out of
1111
+ * every setup (`leftOut`, with a setup facing its way, if one does); no feature includes the face; or
1112
+ * a pass roughs it but none finishes it (`notFinished`). Setups by index.
1113
+ */
1114
+ type NotMachinedWhy = {
1115
+ kind: 'planned';
1116
+ setup: number;
1117
+ } | {
1118
+ kind: 'leftOut';
1119
+ setup: number | null;
1120
+ } | {
1121
+ kind: 'noFeature';
1122
+ } | {
1123
+ kind: 'notFinished';
1124
+ setup: number;
1125
+ };
1126
+ /**
1127
+ * The one reason a list leads with: what the feature's own flag says of the tool or the corner,
1128
+ * as the more telling, else what the plan did with it.
1129
+ */
1130
+ type NotMachinedReason = NotMachinedWhy['kind'] | 'library' | 'sharpCorner';
1131
+ /**
1132
+ * Each reason in a few words, for a chip or a count: `2 · not planned`. What happened, not a cause
1133
+ * the plan never gave: Toolpath says which features it leaves, not why.
1134
+ */
1135
+ declare const REASON_SHORT: Record<NotMachinedReason, string>;
1136
+ /** A reason said in full: its few words, then what it means here — `Not planned: in no setup`. */
1137
+ declare const reasonLine: (reason: NotMachinedReason, detail: string) => string;
1138
+ /** A feature (or a face no feature includes) the plan leaves, as the DFM check stores it. */
1139
+ interface NotMachinedFeature {
1140
+ /** Null for a face no feature includes. */
1141
+ tag: string | null;
1142
+ /** The analysis's feature type, `blind_hole`; absent for a face no feature includes. */
1143
+ type?: string;
1144
+ /** The faces left, and their area (mm²). */
1145
+ regions: Array<number>;
1146
+ area: number;
1147
+ why: NotMachinedWhy;
1148
+ /** Its machining direction. */
1149
+ direction?: PlanDirection;
1150
+ /** For a hole: its bore and depth, mm. */
1151
+ hole?: {
1152
+ diameter: number;
1153
+ depth: number;
1154
+ };
1155
+ }
1156
+ /** A setup as Toolpath plans it: enough to say why a feature is left. */
1157
+ interface PlannedSetup {
1158
+ idx?: number;
1159
+ direction?: PlanDirection | null;
1160
+ unmachined?: ReadonlyArray<string> | null;
1161
+ actions: ReadonlyArray<{
1162
+ featureTags?: ReadonlyArray<string> | null;
1163
+ }>;
1164
+ }
1165
+ /** A direction looking up at the part: work cut from below. */
1166
+ declare const isFromBelow: (direction: PlanDirection | null | undefined) => boolean;
1167
+ /** Why a feature nothing machines is left. */
1168
+ declare const whyOf: (tag: string | null, setups: ReadonlyArray<PlannedSetup>, direction: PlanDirection | null) => NotMachinedWhy;
1169
+ /** What a setup roughs but no pass finishes: on its `unmachined` list, yet one of its passes cuts it. */
1170
+ declare const notFinishedIn: (setup: PlannedSetup) => Array<string>;
1171
+ /** Every feature a plan roughs but never finishes, each once, with the first setup that roughs it. */
1172
+ declare const notFinishedOf: (setups: ReadonlyArray<PlannedSetup>) => Array<{
1173
+ tag: string;
1174
+ setup: number;
1175
+ }>;
1176
+ /** The reason in words, given what names a setup — or none, where the list already says where. */
1177
+ declare const whyText: (why: NotMachinedWhy, setupName?: (setup: number) => string | null) => string;
1178
+
1179
+ /** What a pin needs to know of the part. */
1180
+ type PinContext = PlanRules;
1181
+ /**
1182
+ * The person's pins a new pin of `tag` replaces: each one, in any folder, whose every face it covers
1183
+ * — another direction's reading of those faces, or a smaller feature inside it. One it only overlaps
1184
+ * stays.
1185
+ */
1186
+ declare const replacedBy: (setups: ReadonlyArray<DraftSetup>, tag: string, regionsOf: (tag: string) => ReadonlyArray<number>) => Array<PinnedFeature>;
1187
+ /**
1188
+ * The plan with every face of `tags` no longer ignored, and those that were, ascending: what every
1189
+ * way of pinning ends with, as a pinned feature is machined whole.
1190
+ */
1191
+ declare const unignorePinned: (plan: Constraints, tags: ReadonlyArray<string>, context: PinContext) => {
1192
+ intent: Constraints;
1193
+ unignored: Array<number>;
1194
+ };
1195
+ /** What a pin did: the plan after it, where it went, the pins it replaced and the faces it un-ignored. */
1196
+ interface PinEdit {
1197
+ intent: Constraints;
1198
+ setupId: string;
1199
+ /** A setup was added for it, facing its way. */
1200
+ added: boolean;
1201
+ /** It was pinned there already, and is now unpinned. */
1202
+ unpinned: boolean;
1203
+ replaced: Array<string>;
1204
+ unignored: Array<number>;
1205
+ }
1206
+ /**
1207
+ * Pin a feature into a folder, or into the one facing its direction (adding one where none does), or
1208
+ * — pinned there already — unpin it. A new pin replaces the person's pins whose every face it
1209
+ * covers. One edit.
1210
+ */
1211
+ declare const pinEdit: (plan: Constraints, tag: string,
1212
+ /** `newId` is for the folder a pin into a parent makes, or the setup a pin from a direction adds. */
1213
+ at: {
1214
+ folderId: string;
1215
+ newId?: string;
1216
+ } | {
1217
+ direction: PlanDirection;
1218
+ newId: string;
1219
+ }, context: PinContext) => PinEdit | {
1220
+ refused: string;
1221
+ };
1222
+ /**
1223
+ * The plan once `tag` is pinned where `pinned` (the setups with the pin made) has it: the person's
1224
+ * pins it covers unpinned, and its faces no longer ignored (`unignorePinned`). What every way of
1225
+ * pinning one feature ends with — `pinEdit`, and a row dropped in a folder.
1226
+ */
1227
+ declare const withPin: (plan: Constraints, tag: string, pinned: ReadonlyArray<DraftSetup>, context: PinContext) => {
1228
+ intent: Constraints;
1229
+ replaced: Array<string>;
1230
+ unignored: Array<number>;
1231
+ };
1232
+ /** What a click does to its feature: pin it in the folder, or take it out — unpinned. */
1233
+ type PinTarget = 'pin' | 'takeOut';
1234
+ /** What a click made of a feature since the plan was saved: pinned in the folder, or taken out. */
1235
+ interface PinChange {
1236
+ tag: string;
1237
+ target: PinTarget;
1238
+ }
1239
+ /**
1240
+ * The plan with one line taken back: the feature as `saved` had it, and — where it is pinned since,
1241
+ * or moved — the pins that pin replaced, and its faces ignored as `saved` had them. Every other
1242
+ * edit stands.
1243
+ */
1244
+ declare const takeBack: (plan: Constraints, saved: Constraints, tag: string, context: PinContext) => Constraints;
1245
+ /**
1246
+ * What a click on the part in the open folder does, and what the status line says of it: a feature
1247
+ * pinned in the folder is taken out — unpinned, left to Toolpath; any other is pinned there. (A
1248
+ * click on the folder's tree row is the page's: it edits nothing, and only shows the feature.)
1249
+ */
1250
+ declare const folderClick: (plan: Constraints, feature: {
1251
+ tag: string;
1252
+ label: string;
1253
+ direction: PlanDirection;
1254
+ /** Pinned in the folder. */
1255
+ inFolder: boolean;
1256
+ }, folder: {
1257
+ id: string;
1258
+ name: string;
1259
+ }, context: PinContext) => {
1260
+ intent: Constraints;
1261
+ note: string;
1262
+ };
1263
+ /**
1264
+ * A line's choice among the features its click read. On a pin: itself, or another pinned in its
1265
+ * place. On a feature taken out: it stays out, and at most one other is pinned instead — choosing
1266
+ * again, or choosing to take it out, lets the one before go. A feature that goes leaves the folder as
1267
+ * a click takes it out: unpinned, never put back where it was before. Answers the plan, and the
1268
+ * lines whose choice is made — a pin swapped away keeps its choice unmade, so undo brings it back
1269
+ * to be made.
1270
+ */
1271
+ declare const chooseReading: (plan: Constraints, saved: Constraints, line: PinChange, reading: string,
1272
+ /** The features its click read, the line's among them. */
1273
+ read: ReadonlyArray<string>, folder: {
1274
+ id: string;
1275
+ direction: PlanDirection;
1276
+ }, context: PinContext) => {
1277
+ intent: Constraints;
1278
+ chosen: Array<string>;
1279
+ };
1280
+ /** A plan as a Pin features note reads it: every folder of the tree, and who machines each face. */
1281
+ interface PlanReading {
1282
+ folders: ReadonlyArray<PlanSetupView>;
1283
+ kindOf: (region: number) => CoverageKind;
1284
+ }
1285
+ /** A plan as a note reads it, from its folders and who machines each face (`classifyFaces`). */
1286
+ declare const readingOf: (folders: ReadonlyArray<PlanSetupView>, coverage: Coverage | null) => PlanReading;
1287
+ /**
1288
+ * What a choice says of a feature beside its name: how many faces, the way it is cut where that is
1289
+ * said, and where it is now (`stateOf`).
1290
+ */
1291
+ declare const readingDetail: (faces: number, state: string, way?: string) => string;
1292
+ /** Where a feature is: in the glossary's words, and the folders that names. */
1293
+ interface FeatureState {
1294
+ text: string;
1295
+ folders: Array<string>;
1296
+ }
1297
+ /**
1298
+ * Where a feature is in a plan, in the glossary's words, from the open folder (`folderId`): Pinned
1299
+ * (in a folder, or part of a larger feature pinned there), Ignored, or Open. Read off its faces, so
1300
+ * a feature inside another reads as that one's; faces in several folders name the first, and how
1301
+ * many more.
1302
+ */
1303
+ declare const stateOf: (tag: string, plan: PlanReading, folderId: string, regionsOf: (tag: string) => ReadonlyArray<number>) => FeatureState;
1304
+ /** A feature read from the open folder's direction, as its Pin features read it. */
1305
+ interface FolderFeature {
1306
+ tag: string;
1307
+ label: string;
1308
+ }
1309
+
1310
+ /** One thing worth saying about the plan before it is sent. `blocking` stops it being sent. */
1311
+ interface PlanCheck {
1312
+ tone: 'blocking' | 'warning' | 'info';
1313
+ text: string;
1314
+ }
1315
+ /** What the checks know of the part: its analysis, and the kernel Toolpath last planned with. */
1316
+ interface CheckContext {
1317
+ /** The part's directions: analyzed, detected, and being analyzed. `analyzed` is null before its model has been read. */
1318
+ directions: DirectionsKnown;
1319
+ /**
1320
+ * A feature's type, label and the direction it is cut from, by tag — or null for a tag the part's
1321
+ * model does not have.
1322
+ */
1323
+ feature: (tag: string) => {
1324
+ type: string;
1325
+ label: string;
1326
+ direction?: PlanDirection;
1327
+ } | null;
1328
+ /** The kernel Toolpath's plan was made by, whose tags the pins have to be. */
1329
+ kernelVersion: string | null;
1330
+ }
1331
+ /** What the checks read of a draft: its setups, and the kernel whose tags its pins name. */
1332
+ interface CheckedDraft extends Pick<Constraints, 'setups'> {
1333
+ /** The kernel whose tags the pins name; null until something is pinned. */
1334
+ kernelVersion: string | null;
1335
+ }
1336
+ /**
1337
+ * What would stop Toolpath taking the plan as the person has stated it, and what is worth knowing
1338
+ * before sending it: the rules its stated plan is held to (tp-kernel's `UserSetupPlan`), checked
1339
+ * here where they can be, so the answer comes before the round trip rather than after it.
1340
+ */
1341
+ declare const planChecks: (draft: CheckedDraft, context: CheckContext) => Array<PlanCheck>;
1342
+ /**
1343
+ * One of Toolpath's refusal clauses in the person's own terms: its setup by the folder's name — setup
1344
+ * `n` of the statement, counted from zero, is the draft's `n`th frame — and its features by their
1345
+ * labels.
1346
+ */
1347
+ declare const describeClause: (clause: string, draft: Pick<Constraints, "setups">, label: (tag: string) => string | null, tags: ReadonlyArray<string>) => string;
1348
+ /**
1349
+ * Where a check's Show goes: the Not machined list, a folder and a feature in it, or one of
1350
+ * Toolpath's setups in the Results view.
1351
+ */
1352
+ type ShowTarget = {
1353
+ kind: 'notMachined';
1354
+ } | {
1355
+ kind: 'folder';
1356
+ setupId: string;
1357
+ tag?: string;
1358
+ } | {
1359
+ kind: 'setup';
1360
+ idx: number;
1361
+ };
1362
+ /** One line of the confirm checklist. `ok` says a check passed; the rest are as {@link PlanCheck}. */
1363
+ interface ConfirmCheck {
1364
+ tone: PlanCheck['tone'] | 'ok';
1365
+ text: string;
1366
+ show?: ShowTarget;
1367
+ }
1368
+ /** What the confirm checklist looks at, beside the plan's own checks. */
1369
+ interface ConfirmContext {
1370
+ /** The constraints as applied changed since Toolpath's results: the results are of an earlier version. */
1371
+ changed: boolean;
1372
+ /** How many features nothing in Toolpath's plan machines: null before known. */
1373
+ notMachined: number | null;
1374
+ /**
1375
+ * Each of the person's folders that Toolpath plans a setup from, and whether the plan machines
1376
+ * something in it, or in a folder inside it. Empty unless the results are of the current constraints.
1377
+ */
1378
+ folders: ReadonlyArray<{
1379
+ id: string;
1380
+ name: string;
1381
+ machined: boolean;
1382
+ }>;
1383
+ /** Each setup of Toolpath's plan, with what it was meant to machine and no pass in it cuts. */
1384
+ setups: ReadonlyArray<{
1385
+ /** Its place in the plan: where Show goes. */
1386
+ idx: number;
1387
+ notMachined: Array<string>;
1388
+ /** Of `notMachined`, what a pass roughs but none finishes. */
1389
+ notFinished: Array<string>;
1390
+ }>;
1391
+ }
1392
+ /**
1393
+ * Whether the constraints changed since Toolpath's results: only with results to have changed
1394
+ * from — a part never planned has none. The Results banner's rule and
1395
+ * the checklist's, one place.
1396
+ */
1397
+ declare const changedSinceResults: (changed: boolean, setups: number) => boolean;
1398
+ /**
1399
+ * The checklist a move out of Plan shows: what stops the part moving on, what is worth a look
1400
+ * first — each with where to look — and what is fine. The plan's own checks come first.
1401
+ */
1402
+ declare const confirmChecks: (own: ReadonlyArray<PlanCheck>, context: ConfirmContext) => Array<ConfirmCheck>;
1403
+ /** Every line passed: the move goes straight on without asking. */
1404
+ declare const allClear: (checks: ReadonlyArray<ConfirmCheck>) => boolean;
1405
+
1406
+ /** How many steps Undo reaches back through. */
1407
+ declare const HISTORY = 100;
1408
+ /**
1409
+ * A page's edits to a plan. `D` is what an edit changes and Undo puts back: the constraints, and any
1410
+ * fields of the app's own held with them (a material, a stock). Keep save stamps, such as a version
1411
+ * or a time, out of it: Undo would put an old one back.
1412
+ */
1413
+ interface PlanSession<D extends Constraints> {
1414
+ /** The draft as applied: what the edits are measured from, and what Discard puts back. */
1415
+ saved: D;
1416
+ /** The draft as edited here. */
1417
+ draft: D;
1418
+ /** The drafts Undo goes back to, oldest first: what was done, in order. */
1419
+ past: ReadonlyArray<D>;
1420
+ /** The drafts Redo goes forward to, next first. */
1421
+ future: ReadonlyArray<D>;
1422
+ /** The run of edits joined as one step (`coalesce`): its key, and the draft before it. */
1423
+ run: {
1424
+ key: string;
1425
+ before: D;
1426
+ } | null;
1427
+ /** Why the last action was refused, to show the person; null when it was not. */
1428
+ refused: string | null;
1429
+ /** The folder to open after the last action (`DraftResult`'s `folderId`); null for none. */
1430
+ folderId: string | null;
1431
+ /** What the last action did beyond the draft, for the page to say (`DraftFacts`); null for none. */
1432
+ facts: DraftFacts | null;
1433
+ /** The save version of `saved`, where the app has one: an older plan read is not taken. */
1434
+ version: number | null;
1435
+ }
1436
+ /**
1437
+ * A draft's own fields beside the constraints: what an `edit` changes (a material, a stock). The
1438
+ * constraints change only through actions.
1439
+ */
1440
+ type AppFields<D extends Constraints> = Partial<Omit<D, keyof Constraints>>;
1441
+ /**
1442
+ * Everything a session can be told. Edits with the same `coalesce` key, one after another, are one
1443
+ * step — the changes made while a stock editor is open, say. Any other edit, Undo or Redo ends the
1444
+ * run.
1445
+ */
1446
+ type SessionEvent<D extends Constraints> =
1447
+ /**
1448
+ * A plan action, carried out by `applyDraftAction` on the draft as it is now, with the plan as
1449
+ * applied: every change to the setups, folders, pins and ignored faces.
1450
+ */
1451
+ {
1452
+ type: 'act';
1453
+ action: DraftAction;
1454
+ coalesce?: string;
1455
+ }
1456
+ /**
1457
+ * The app's own fields (`AppFields`: a material, a stock), as one step. `change` is given the draft
1458
+ * as it is now, so two edits in a row build on each other, and answers the fields it changes. It
1459
+ * must be pure: React may call it twice. The constraints never change here: any it answers are
1460
+ * passed over.
1461
+ */
1462
+ | {
1463
+ type: 'edit';
1464
+ change: (draft: D) => AppFields<D>;
1465
+ coalesce?: string;
1466
+ } | {
1467
+ type: 'undo';
1468
+ } | {
1469
+ type: 'redo';
1470
+ }
1471
+ /** Put the draft back as applied: one step, which Undo takes back. */
1472
+ | {
1473
+ type: 'discard';
1474
+ }
1475
+ /**
1476
+ * Apply saved `sent`, as `version` where the app counts saves. It is the draft as applied now; an
1477
+ * edit made while it saved stays held.
1478
+ */
1479
+ | {
1480
+ type: 'applied';
1481
+ sent: D;
1482
+ version?: number;
1483
+ }
1484
+ /**
1485
+ * The draft as applied, read again: after another tab applied, or Toolpath made a new plan. With
1486
+ * nothing held, the draft follows it; with edits held, they stay (`SessionRules.rebase`). A read
1487
+ * whose `version` is older than the session's — answered after an Apply moved on — is not taken.
1488
+ */
1489
+ | {
1490
+ type: 'read';
1491
+ saved: D;
1492
+ version?: number;
1493
+ };
1494
+ /** What a session needs to know of the part and the app. */
1495
+ interface SessionRules<D extends Constraints> extends PlanRules {
1496
+ /** The plan can't be changed now: no edit, Undo, Redo or Discard changes the draft. */
1497
+ locked?: boolean;
1498
+ /**
1499
+ * Whether two drafts are the same plan: an edit to the same plan is no step. Default: the same
1500
+ * values, whatever the order of each object's keys.
1501
+ */
1502
+ same?: (a: D, b: D) => boolean;
1503
+ /**
1504
+ * The edits held, onto a draft applied since (`now`), from the one they were made on (`was`).
1505
+ * Default: the constraints stay as held; each other field stays as held where it was edited here,
1506
+ * and follows `now` where it was not.
1507
+ */
1508
+ rebase?: (held: D, was: D, now: D) => D;
1509
+ }
1510
+ /**
1511
+ * A session on the draft as applied, at its save `version` if the app counts saves, with `held` —
1512
+ * edits kept from before a reload — if any.
1513
+ */
1514
+ declare const startSession: <D extends Constraints>(saved: D, { held, version }?: {
1515
+ held?: D;
1516
+ version?: number;
1517
+ }) => PlanSession<D>;
1518
+ /** Whether edits are held: the draft is not the plan as applied. What Apply and Discard need. */
1519
+ declare const isHeld: <D extends Constraints>(session: PlanSession<D>, rules?: Pick<SessionRules<D>, "same">) => boolean;
1520
+ /** Whether Undo would change the draft: a step to go back to, on a plan that can be changed. */
1521
+ declare const canUndo: (session: PlanSession<Constraints>, rules?: Pick<SessionRules<Constraints>, "locked">) => boolean;
1522
+ /** Whether Redo would change the draft: a step to go forward to, on a plan that can be changed. */
1523
+ declare const canRedo: (session: PlanSession<Constraints>, rules?: Pick<SessionRules<Constraints>, "locked">) => boolean;
1524
+ /**
1525
+ * The session after `event`: the one function that moves it on. It answers the session as it was
1526
+ * when the event changes nothing, so React draws nothing new. A refused action changes no draft and
1527
+ * says why in `refused`.
1528
+ *
1529
+ * ```ts
1530
+ * const [session, send] = useReducer(
1531
+ * (now: PlanSession<Draft>, event: SessionEvent<Draft>) => planSession(now, event, rules),
1532
+ * saved,
1533
+ * startSession,
1534
+ * )
1535
+ * ```
1536
+ */
1537
+ declare const planSession: <D extends Constraints>(session: PlanSession<D>, event: SessionEvent<D>, rules: SessionRules<D>) => PlanSession<D>;
1538
+
1539
+ /** A row's red mark: nothing cuts it, or a pass roughs it but none finishes it (MP-22). */
1540
+ type UnmachinedMark = false | 'notMachined' | 'notFinished';
1541
+ /** One feature a setup takes: what cuts it, and whether it is left short. */
1542
+ interface ResultsFeatureRow extends PlanFeatureRow {
1543
+ /** The tools whose passes cut it, each once; null where none does. */
1544
+ tool: string | null;
1545
+ mark: UnmachinedMark;
1546
+ }
1547
+ /** A setup of Toolpath's plan, as the Results tree lists it. */
1548
+ interface ResultsSetupView extends PlannedSetupView {
1549
+ /** Its place in the plan: `plan.setups[idx]`. */
1550
+ idx: number;
1551
+ /** Each feature it takes once, in the order its orientations list them. */
1552
+ rows: Array<ResultsFeatureRow>;
1553
+ /** The constraint frame it was planned from — one facing a way it is cut from — or null for one Toolpath added. */
1554
+ fromFolder: string | null;
1555
+ }
1556
+ interface ResultsView {
1557
+ setups: Array<ResultsSetupView>;
1558
+ /** Constraint frames no setup was planned from: nothing to machine from there, so left out. */
1559
+ leftOut: Array<{
1560
+ folderId: string;
1561
+ name: string;
1562
+ }>;
1563
+ }
1564
+ /**
1565
+ * Toolpath's plan laid out for the Results view. A setup takes the name of the first constraint
1566
+ * frame facing a direction it is cut from — a tilt's, with its setup's (`Setup 1 › Tilt`) — else
1567
+ * `Setup N`; the frames no setup faces are `leftOut`. The frames are the constraints the plan is
1568
+ * of, as applied: with none (edits held, or the plan of an earlier version) nothing is named and
1569
+ * nothing is left out.
1570
+ */
1571
+ declare const resultsView: ({ plan, constraints, part, }: {
1572
+ plan: EnginePlan | null;
1573
+ /** The applied constraints the plan is of; null where it is not of the constraints as applied. */
1574
+ constraints: Pick<Constraints, "setups"> | null;
1575
+ part: PlanPart;
1576
+ }) => ResultsView;
1577
+ /** The setup a feature is machined in, by tag in any case: the first listing it, or null. */
1578
+ declare const setupOf: (setups: ReadonlyArray<ResultsSetupView>, tag: string) => ResultsSetupView | null;
1579
+
1580
+ /**
1581
+ * A JSON-shaped value with every object's keys sorted, at every depth: what makes two equal values
1582
+ * stringify alike. (A replacer array would sort the top level, but also drop every nested key not in
1583
+ * it — a rule's `time` would read `{}` and a changed factor would change nothing.)
1584
+ */
1585
+ declare const sortedKeys: (value: unknown) => unknown;
1586
+ /** Whether two JSON-shaped values are the same, whatever the order of their properties. */
1587
+ declare const sameJson: (a: unknown, b: unknown) => boolean;
1588
+
1589
+ /**
1590
+ * The one place a physical value is turned from what we store into what a person reads.
1591
+ *
1592
+ * Units are a display preference, never a data one. Everything an app persists or sends is metric —
1593
+ * lengths in millimetres, density in kg/m³, weight in kilograms — the same system the Engine
1594
+ * speaks. These functions convert *for the screen only*, into whichever system the reader has
1595
+ * chosen; nothing here is written back. Kept pure and free of React so the conversions can be
1596
+ * tested as arithmetic.
1597
+ *
1598
+ * Metric is the identity, so a value passes through unchanged in `mm` and is converted only for a
1599
+ * reader who has asked for `in`.
1600
+ */
1601
+
1602
+ type Units = 'in' | 'mm';
1603
+ declare const isUnits: (value: unknown) => value is Units;
1604
+
1605
+ /**
1606
+ * A length in millimetres — a tool diameter, a cut length, a step, a stock edge.
1607
+ *
1608
+ * Millimetres to three decimals, inches to four: an inch reading is a tenth the count of a millimetre
1609
+ * one, so it needs the extra place to tell a chip load of 0.02" from 0.025".
1610
+ */
1611
+ declare const formatLength: (mm: number, units: Units) => string;
1612
+ /** A part or stock size in millimetres, as `50.8 x 38.1 x 12.7 mm` / `2 x 1.5 x 0.5 in`. */
1613
+ declare const formatDimensions: (sizeMm: {
1614
+ length: number;
1615
+ width: number;
1616
+ height: number;
1617
+ }, units: Units, shape?: "box" | "cylinder") => string;
1618
+ /** An area in mm², as `125.5 mm²` / `0.195 in²`. */
1619
+ declare const formatArea: (mm2: number, units: Units) => string;
1620
+ /** A feed rate in mm/min. */
1621
+ declare const formatFeed: (mmPerMin: number, units: Units) => string;
1622
+ /** A surface speed figured in m/min; imperial reads it as SFM (surface feet per minute). */
1623
+ declare const formatSurfaceSpeed: (mPerMin: number, units: Units) => string;
1624
+ /** A stock weight in kilograms, as `0.8 kg` / `1.76 lb`. */
1625
+ declare const formatWeight: (kg: number, units: Units) => string;
1626
+ /**
1627
+ * A quantity a profile stores canonical and a person types in either system. Ratios, angles and
1628
+ * counts have no unit to convert, but share the table so every field is shown and stored the same way.
1629
+ */
1630
+ type Quantity = 'density' | 'length' | 'ratio' | 'angle' | 'count';
1631
+ /**
1632
+ * Decimal places each quantity is shown, typed and stored at, per system.
1633
+ *
1634
+ * One table so the three can never disagree: a field's `step` is its places, the number shown is
1635
+ * rounded to them, and the value saved is rounded to the metric places — which is also what the
1636
+ * server stores. The imperial places are chosen so a figure typed in imperial, stored in metric and
1637
+ * shown again reads back exactly as typed: one step of the stored metric value is always less than
1638
+ * half a step of the imperial one.
1639
+ */
1640
+ declare const PRECISION: Record<Quantity, Record<Units, number>>;
1641
+ /** A number to exactly `places` decimals, as a number. */
1642
+ declare const roundTo: (value: number, places: number) => number;
1643
+ /** A canonical value at the precision it is stored at — what the server keeps. */
1644
+ declare const toStored: (quantity: Quantity, value: number) => number;
1645
+ /** The stored canonical value as the number to show in the field for this system. */
1646
+ declare const toInput: (quantity: Quantity, canonical: number, units: Units) => number;
1647
+ /** A value typed in this system, back to canonical at the precision it is stored at. */
1648
+ declare const fromInput: (quantity: Quantity, shown: number, units: Units) => number;
1649
+ /** The field's `step`: one unit in its last shown place, so every value it shows is valid. */
1650
+ declare const stepFor: (quantity: Quantity, units: Units) => string;
1651
+ declare const densityUnit: (units: Units) => string;
1652
+ /**
1653
+ * A tool length typed in `units`, back to canonical millimetres — undefined when it does not read
1654
+ * as a length. Inches take what a machinist writes: `0.25`, `.25`, `1/4`, `1-1/4`, `1 1/4`, with or
1655
+ * without a trailing `"` or `in`.
1656
+ */
1657
+ declare const parseToolLength: (text: string, units: Units) => number | undefined;
1658
+
1659
+ /** Engine 1.21 stock inputs. Every dimensional value is millimetres. */
1660
+ type StockPosition = 'modelCentered' | 'offsetFromTop' | 'offsetFromBottom';
1661
+ type AutomaticStock = {
1662
+ mode: 'automaticFlatBar';
1663
+ oversizeX?: number;
1664
+ oversizeY?: number;
1665
+ oversizeZTop?: number;
1666
+ oversizeZBottom?: number;
1667
+ snapX?: number;
1668
+ snapY?: number;
1669
+ snapZ?: number;
1670
+ } | {
1671
+ mode: 'automaticRoundStock';
1672
+ radialOversize?: number;
1673
+ axialOversize?: number;
1674
+ gripStock?: number;
1675
+ diaRoundToNearest?: number;
1676
+ lengthRoundToNearest?: number;
1677
+ verticalAxis?: boolean;
1678
+ };
1679
+ type FixedStock = {
1680
+ mode: 'fixedBox';
1681
+ dimensions: {
1682
+ x: number;
1683
+ y: number;
1684
+ z: number;
1685
+ };
1686
+ position: StockPosition;
1687
+ positionOffset?: number;
1688
+ } | {
1689
+ mode: 'fixedCylinder';
1690
+ diameter: number;
1691
+ length: number;
1692
+ position: StockPosition;
1693
+ positionOffset?: number;
1694
+ };
1695
+ type StockOption = AutomaticStock | FixedStock;
1696
+ declare const STOCK_LABELS: {
1697
+ readonly automaticFlatBar: "Flat Bar";
1698
+ readonly automaticRoundStock: "Round Stock";
1699
+ readonly fixedBox: "Fixed Box";
1700
+ readonly fixedCylinder: "Fixed Cylinder";
1701
+ };
1702
+ declare const FLAT_BAR_FIELDS: readonly [readonly ["oversizeX", "Width (X)"], readonly ["oversizeY", "Depth (Y)"], readonly ["oversizeZTop", "Thickness (Z)"], readonly ["snapX", "Width (X)"], readonly ["snapY", "Depth (Y)"], readonly ["snapZ", "Thickness (Z)"], readonly ["oversizeZBottom", "Stock Grip Amt."]];
1703
+ declare const ROUND_STOCK_FIELDS: readonly [readonly ["radialOversize", "Radial"], readonly ["axialOversize", "Front"], readonly ["diaRoundToNearest", "Diameter"], readonly ["lengthRoundToNearest", "Length"], readonly ["gripStock", "Stock Grip Amt."]];
1704
+ /** Legacy-style defaults in the stock setting's entry system, stored canonical. */
1705
+ declare const defaultStock: (mode?: AutomaticStock["mode"], units?: Units) => AutomaticStock;
1706
+ /** Validate the service contract, including its stock envelope, before saving or forwarding. */
1707
+ declare const parseStock: (value: unknown) => StockOption | string;
1708
+ /** Stable comparison of policy values, independent of JSON property order. */
1709
+ declare const sameStock: (a: StockOption | null | undefined, b: StockOption | null | undefined) => boolean;
1710
+ /**
1711
+ * Whether the saved policy is not the stock the part's times were calculated with. A calculation
1712
+ * echoes the stock it was sent (`stock.input`, read by `echoesStock`), so edited stock — or none
1713
+ * calculated yet — shows as a preview of the policy until a calculation of it lands. A part with
1714
+ * no policy has nothing edited.
1715
+ */
1716
+ declare const stockEdited: (policy: StockOption | null, baseline: Record<string, unknown> | null) => boolean;
1717
+ type ModelAxis = 'x' | 'y' | 'z';
1718
+ declare const NO_FIRST_FOLDER = "Add a folder first: a fixed box is measured from the first setup.";
1719
+ declare const TILTED_FIRST_FOLDER = "A fixed box needs a first folder facing along X, Y or Z.";
1720
+ declare const BOX_ENVELOPE = "The box must fit 80 \u00D7 50 in across the first folder\u2019s direction and 30 in along it.";
1721
+ /** The model axis a direction faces along, and which way; null for one off every axis. */
1722
+ declare const axisAlong: (direction: PlanDirection) => {
1723
+ axis: ModelAxis;
1724
+ sign: 1 | -1;
1725
+ } | null;
1726
+ /**
1727
+ * The stock as Toolpath is sent it, for a plan whose first stated setup faces `first` (null with
1728
+ * none stated): any stock but a fixed box as it is; a fixed box turned into that setup's frame, or
1729
+ * why it can't be — no first folder, one facing off the axes, or a box too thick along it.
1730
+ */
1731
+ declare const stockRequest: (stock: StockOption, first: PlanDirection | null) => StockOption | string;
1732
+ /**
1733
+ * The direction Toolpath placed a calculation's stock along (its first setup's), or null where it
1734
+ * can't be read: a box's frame `z`; a cylinder's axis where the stock asked for stood it along that
1735
+ * direction — a fixed cylinder, or Round Stock with `verticalAxis` — taken only facing along X, Y or
1736
+ * Z. A lying round bar's axis is the part's long side, not the direction, so it gives none.
1737
+ */
1738
+ declare const placedAlong: (envelope: unknown) => PlanDirection | null;
1739
+ /**
1740
+ * Whether a calculation's stock envelope echoes `policy` as it was sent (`stock.input`): the same
1741
+ * stock — but a fixed box turned into the frame Toolpath placed it in (`placedAlong`) or, with no
1742
+ * placement to read, into the frame of any one of the part's axes.
1743
+ */
1744
+ declare const echoesStock: (policy: StockOption, envelope: unknown) => boolean;
1745
+ /** A box in the part's model coordinates, mm: its least and greatest corners. */
1746
+ interface ModelBox {
1747
+ min: {
1748
+ x: number;
1749
+ y: number;
1750
+ z: number;
1751
+ };
1752
+ max: {
1753
+ x: number;
1754
+ y: number;
1755
+ z: number;
1756
+ };
1757
+ }
1758
+ /** A cylinder in the part's model coordinates, mm: its base centre, unit axis and size. */
1759
+ interface ModelCylinder {
1760
+ origin: PlanDirection;
1761
+ axis: PlanDirection;
1762
+ diameter: number;
1763
+ length: number;
1764
+ }
1765
+ /**
1766
+ * Where Toolpath builds a fixed box around the part, in model coordinates, by the frame reading
1767
+ * above — or null without a first folder facing along an axis. Its two sides across the direction
1768
+ * are laid longer along the part's longer side (the worker sends them so, tp-kernel loads them so);
1769
+ * `turned`: the other way round from how they were entered.
1770
+ */
1771
+ declare const fixedBoxPlacement: (stock: Extract<StockOption, {
1772
+ mode: "fixedBox";
1773
+ }>, first: PlanDirection | null, part: ModelBox) => (ModelBox & {
1774
+ turned: boolean;
1775
+ }) | null;
1776
+ /**
1777
+ * Where Toolpath builds any stock around the part, in model coordinates, standing it in the frame
1778
+ * of a first setup facing `first` along an axis (null otherwise): a block (`box`) or a cylinder.
1779
+ * Flat Bar: each side the part's extent plus its oversizes — `x` / `y` on either side across,
1780
+ * `zTop` toward the direction and the exact grip `zBottom` away from it — rounded up, the grip
1781
+ * kept exact (tp-rs `StockBox::relative`). Round Stock: lying along the part's longer side across
1782
+ * the direction, or standing along it (`verticalAxis`, default lying), its diameter the enclosing
1783
+ * circle and radial oversize rounded up, its length the grip, the part and the front oversize
1784
+ * rounded up, the grip at its base (`StockCylinder::relative`). A fixed cylinder stands along the
1785
+ * direction, placed along it by its position (`StockCylinder::fixed`).
1786
+ */
1787
+ declare const stockPlacement: (stock: StockOption, first: PlanDirection | null, part: ModelBox) => {
1788
+ box: ModelBox;
1789
+ } | {
1790
+ cylinder: ModelCylinder;
1791
+ } | null;
1792
+ /** What a fixed box held for Apply comes to (`fixedBoxCheck`). */
1793
+ type FixedBoxCheck =
1794
+ /** Apply waits on it: `problem` is said beside the stock, `applyReason` on Apply. */
1795
+ {
1796
+ problem: string;
1797
+ applyReason: string;
1798
+ }
1799
+ /** Said beside the stock; Apply does not wait on it. */
1800
+ | {
1801
+ note: string;
1802
+ };
1803
+ /**
1804
+ * A fixed box against the first folder and the part, as Apply would send it: why it can't be sent
1805
+ * (`stockRequest`), else how far the part stands outside it — the most along any one axis — else
1806
+ * that Toolpath turns it. Null for any other stock, or a box with nothing to say. The part's size is
1807
+ * its model box (`length`, `width` and `height` along X, Y and Z); unknown, the fit is not checked.
1808
+ */
1809
+ declare const fixedBoxCheck: (stock: StockOption | null, first: PlanDirection | null, size: {
1810
+ length: number;
1811
+ width: number;
1812
+ height: number;
1813
+ } | null, units: Units) => FixedBoxCheck | null;
1814
+
1815
+ /**
1816
+ * A tool crib: the tool libraries a part draws its tools from.
1817
+ *
1818
+ * A library is implicit when its tools are synthesized from settings, and explicit when they are a
1819
+ * shop's catalogued tools. Only implicit libraries exist yet; entries are tagged by kind so explicit
1820
+ * ones can join the same list.
1821
+ */
1822
+ interface ToolCribEntry {
1823
+ kind: 'implicit';
1824
+ id: string;
1825
+ }
1826
+ type ToolCrib = Array<ToolCribEntry>;
1827
+ /** The implicit libraries a crib names, by id, in its order. */
1828
+ declare const implicitLibraryIds: (crib: ReadonlyArray<ToolCribEntry>) => Array<string>;
1829
+ /**
1830
+ * Whether a library meant for these material families suits a part cut from `family`. A guide, not
1831
+ * a limit: a library meant for no family in particular suits every part, and a part with no material
1832
+ * is offered them all.
1833
+ */
1834
+ declare const suitsMaterial: (materialFamilies: ReadonlyArray<string>, family: string | null) => boolean;
1835
+ /** What a crib picks a library by. */
1836
+ interface CribLibrary {
1837
+ id: string;
1838
+ isDefault: boolean;
1839
+ materialFamilies: ReadonlyArray<string>;
1840
+ }
1841
+ /**
1842
+ * The library a crib starts on for a part cut from `family`: the first meant for that family in
1843
+ * particular, else the org's default if it suits, else the first that suits — and, when none does,
1844
+ * the default anyway, since a part has to be planned with something.
1845
+ */
1846
+ declare const startingLibrary: <Library extends CribLibrary>(libraries: ReadonlyArray<Library>, family: string | null) => Library | undefined;
1847
+ /**
1848
+ * The libraries a crib offers to add for a part cut from `family`: every one not already in it, those
1849
+ * that suit the material first. One meant for another material is still offered — the picker says
1850
+ * whom it is meant for, and a shop may know better.
1851
+ */
1852
+ declare const offeredLibraries: <Library extends CribLibrary>(libraries: ReadonlyArray<Library>, inCrib: ReadonlyArray<string>, family: string | null) => Array<Library>;
1853
+ /** A crib of one implicit library. */
1854
+ declare const cribOf: (library: CribLibrary) => ToolCrib;
1855
+ /**
1856
+ * Whether a crib looks as the dialog would have started it for a part cut from `family`: empty, or
1857
+ * just the library that material starts on. Only a saved part is judged this way, since nothing
1858
+ * records whether its crib was picked by hand; a crib edited in the open dialog is known to be.
1859
+ */
1860
+ declare const cribUntouched: (crib: ReadonlyArray<ToolCribEntry>, libraries: ReadonlyArray<CribLibrary>, family: string | null) => boolean;
1861
+ /** The crib with an implicit library added last — the lowest priority — unless it is already in. */
1862
+ declare const addLibrary: (crib: ToolCrib, id: string) => ToolCrib;
1863
+ /** The crib without a library. Its last one may go too: an empty crib is refused at upload or save. */
1864
+ declare const removeLibrary: (crib: ToolCrib, id: string) => ToolCrib;
1865
+ /** The crib with two libraries' places swapped, every other entry left where it is. */
1866
+ declare const swapLibraries: (crib: ToolCrib, a: string, b: string) => ToolCrib;
1867
+
1868
+ export { type ActionTarget, type AppFields, type AutomaticStock, BOX_ENVELOPE, COVERAGE_KINDS, COVERAGE_LABELS, type CheckContext, type CheckedDraft, type ConfirmCheck, type ConfirmContext, type Constraints, type ConstraintsCoverage, type Coverage, type CoverageFeature, type CoverageKind, DONE_COLOR, DRAFT_ACTION_KINDS, type DirectionAnalysis, type DirectionsKnown, type DraftAction, type DraftActionKind, type DraftFacts, type DraftFolder, type DraftResult, type DraftSetup, type DropAt, type Edited, type EnginePlan, type EnginePlanAction, type EnginePlanSetup, FLAT_BAR_FIELDS, type Face, type FaceGroup, type FaceHatch, type FacePaint, type FeatureBore, type FeatureGroupView, type FixedBoxCheck, type FixedStock, type FlatFolder, type FolderFeature, type Frame, HISTORY, type Hold, IGNORE, type IgnoreMode, type IgnoredAs, type Landing, MAX_DEPTH, MAX_NAME, MAX_SETUPS, type ModelAxis, type ModelBox, type ModelCylinder, NO_FIRST_FOLDER, type NotMachinedFeature, type NotMachinedReason, type NotMachinedWhy, OTHER_FOLDER_COLOR, PART_ROW, PRECISION, type PinChange, type PinContext, type PinEdit, type Pinned, type PinnedFeature, type PlacedFolder, type PlanCheck, type PlanDirection, type PlanFeatureRow, type PlanHighlight, type PlanIssue, type PlanOrientationView, type PlanPart, type PlanReading, type PlanRules, type PlanSession, type PlanSetupView, type PlannedSetup$1 as PlannedSetup, type PlannedSetupView, type Projection, type Quantity, REASON_SHORT, ROUND_STOCK_FIELDS, type ReadingAt, type ReadingContext, type ReadingScope, type ResultsCoverage, type ResultsFeatureRow, type ResultsSetupView, type ResultsView, STOCK_LABELS, type SessionEvent, type SessionRules, type SetupPlan, type SetupProcess, type ShowTarget, type SplitRegion, type StatedOrientation, type Statement, type StockOption, type StockPosition, TILTED_FIRST_FOLDER, type ToolCrib, type ToolCribEntry, UNMACHINED_FACE_COLOR, type Units, type UnmachinedMark, actionsFor, addFolder, addLibrary, addSetup, allClear, allFolders, applyDraftAction, areaOf, axisAlong, canRedo, canUndo, changedSinceResults, chooseReading, classifyFaces, confirmChecks, copyDirection, cribOf, cribUntouched, currentFor, defaultStock, densityUnit, describeClause, directionAnalysis, draftView, echoesStock, faceRegions, facesByRegion, featureGroups, featureTypeLabel, featureTypePlural, featuresAt, findPlaced, fixedBoxCheck, fixedBoxPlacement, flattenFolders, folderClick, folderPath, foldersFromPlan, formatArea, formatDimensions, formatFeed, formatLength, formatSurfaceSpeed, formatWeight, frameFacing, framesOf, fromInput, gapAt, groupFaces, heightOf, holdsFor, ignoreClick, ignoreEdit, ignoreSelection, ignoredAs, ignoredAsSaved, implicitLibraryIds, indexedFor, isDirection, isFallback, isFromBelow, isHeld, isHoleType, isIndexed, isUnits, liftLoneFolder, listsTag, moveFeature, moveFolder, moveSetup, moveWithin, nextFolderName, notFinishedIn, notFinishedOf, notMachinedOf, offeredLibraries, parseDraftSetups, parseStock, parseToolLength, pinEdit, pinFrom, pinHomes, pinInto, pinOf, pinTargetOf, pinnedIn, pinsWhere, placedAlong, placedFolders, planChecks, planCounts, planFromResults, planHatch, planPaint, planRunOf, planSession, planTags, planView, projectFolder, readingDetail, readingOf, readingsFor, reasonLine, refusalClauses, regionLabel, removeFolder, removeFolders, removeLibrary, renameFolder, replacedBy, restoreFeature, resultsView, roundTo, rowsOf, sameDirection, sameJson, sameStock, setSetupProcess, setToolOrientation, setupOf, sortedKeys, startSession, startingLibrary, stateOf, statementOf, stepFor, stockEdited, stockPlacement, stockRequest, suitsMaterial, swapLibraries, tagKey, tagSet, takeBack, takeBackIgnore, toInput, toStored, unignoreEdit, unignorePinned, unignoredNote, unpinFeature, unpinnedNote, whyOf, whyText, withFolders, withIgnored, withPin, withoutIgnored };