lineadraw 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lineadraw.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // GENERATED — do not edit. Typings for the virtual "lineadraw" and
2
2
  // "lineadraw/helpers" modules block scripts import from, emitted from
3
- // packages/core/src/blocks/{blockTypes,blockHelpers}.ts. Regenerate with:
3
+ // packages/core/src/extensions/{scriptTypes,scriptHelpers}.ts. Regenerate with:
4
4
  // npm run gen:lineadraw-dts -w @lineadraw/core
5
5
 
6
6
  declare module "lineadraw" {
@@ -101,18 +101,22 @@ declare module "lineadraw" {
101
101
  position: Vec2Like;
102
102
  content: string;
103
103
  rotation?: number;
104
- /** Where the text SITS relative to the point. */
104
+ /** Justification, as in AutoCAD / DXF: which edge sits on the point —
105
+ * "left" = the text runs right of it, "right" = left of it; vAlign
106
+ * "bottom" = the text sits above the point, "top" = below it. */
105
107
  hAlign?: "left" | "center" | "right";
106
108
  vAlign?: "bottom" | "center" | "top";
107
109
  /** Word-wrap / frame width in mm (before `scale`); absent = no wrapping. */
108
110
  width?: number;
109
- frame?: "none" | "rectangle" | "bottom";
111
+ frame?: "none" | "rectangle" | "circle" | "slot" | "bottom" | "firstLine";
110
112
  /** MLEADER-style arrow polylines pointing at the text (arrowhead at [0]). */
111
113
  leaderLines?: readonly (readonly Vec2Like[])[];
112
114
  /** Style overrides; absent keys inherit the document text style. */
113
115
  styleOverride?: {
114
116
  font?: string;
115
117
  widthFactor?: number;
118
+ bold?: boolean;
119
+ italic?: boolean;
116
120
  /** Cap height in mm (before `scale`). */
117
121
  textHeight?: number;
118
122
  arrowSize?: number;
@@ -152,11 +156,48 @@ declare module "lineadraw" {
152
156
  /** Applied last, about the pivot (the first input point). */
153
157
  rotation?: number;
154
158
  scale?: number;
155
- params?: Record<string, number | string | boolean>;
159
+ params?: Record<string, number | string | boolean | readonly number[] | readonly string[]>;
156
160
  /** Input points in the PARENT's local coords; the first is the pivot. */
157
161
  inputs?: readonly Vec2Like[];
158
162
  }>;
159
- export type ModelObject = Line | Point | Polyline | Circle | Arc | Ellipse | Hatch | Text | Dimension | Block;
163
+ /** A table cell: plain text, or text with merge / alignment / style. */
164
+ export type TableCell = string | {
165
+ text?: string;
166
+ /** Merge from this (top-left) cell; covered cells are ignored. */
167
+ span?: {
168
+ cols: number;
169
+ rows: number;
170
+ };
171
+ hAlign?: "left" | "center" | "right";
172
+ vAlign?: "top" | "center" | "bottom";
173
+ styleId?: string;
174
+ styleOverride?: TextStyleOverride;
175
+ color?: string;
176
+ };
177
+ /** Grid of text cells hanging right/down from `position` (top-left);
178
+ * rows grow to fit their wrapped text. */
179
+ export type Table = Styled<{
180
+ type: "table";
181
+ position: Vec2Like;
182
+ /** Column widths (mm, before `scale`). */
183
+ columns: readonly number[];
184
+ /** Row count, or per-row settings (`minHeight` mm floor). */
185
+ rows: number | readonly {
186
+ minHeight?: number;
187
+ }[];
188
+ /** Row-major `cells[row][column]`, exactly rows × columns. */
189
+ cells: readonly (readonly TableCell[])[];
190
+ rotation?: number;
191
+ scale?: number;
192
+ /** Rows above the heavier header rule. */
193
+ headerRows?: number;
194
+ /** Text inset from the cell edges (mm). */
195
+ cellMargin?: number;
196
+ borders?: "all" | "outer" | "rows" | "none";
197
+ styleId?: string;
198
+ styleOverride?: TextStyleOverride;
199
+ }>;
200
+ export type ModelObject = Line | Point | Polyline | Circle | Arc | Ellipse | Hatch | Text | Dimension | Block | Table;
160
201
  /** Identity + shared style fields every stored object carries. */
161
202
  export type StoredObjectBase = {
162
203
  id: string;
@@ -250,12 +291,14 @@ declare module "lineadraw" {
250
291
  width?: number;
251
292
  hAlign: "left" | "center" | "right";
252
293
  vAlign: "bottom" | "center" | "top";
253
- frame?: "none" | "rectangle" | "bottom";
294
+ frame?: "none" | "rectangle" | "circle" | "slot" | "bottom" | "firstLine";
254
295
  styleId?: string;
255
296
  /** Only the keys the user actually overrode on this text. */
256
297
  styleOverride?: {
257
298
  font?: string;
258
299
  widthFactor?: number;
300
+ bold?: boolean;
301
+ italic?: boolean;
259
302
  textHeight?: number;
260
303
  arrowType?: "filled" | "open" | "tick" | "dot" | "none";
261
304
  arrowSize?: number;
@@ -274,6 +317,8 @@ declare module "lineadraw" {
274
317
  styleOverride?: {
275
318
  font?: string;
276
319
  widthFactor?: number;
320
+ bold?: boolean;
321
+ italic?: boolean;
277
322
  textHeight?: number;
278
323
  textOffset?: number;
279
324
  arrowType?: "filled" | "open" | "tick" | "dot" | "none";
@@ -290,7 +335,7 @@ declare module "lineadraw" {
290
335
  definitionId: string;
291
336
  rotation: number;
292
337
  scale: number;
293
- params: Readonly<Record<string, number | string | boolean>>;
338
+ params: Readonly<Record<string, number | string | boolean | readonly number[] | readonly string[]>>;
294
339
  /** World points and/or referenced object ids, in pick order. */
295
340
  inputs: readonly (Vec2 | string)[];
296
341
  }>;
@@ -318,8 +363,100 @@ declare module "lineadraw" {
318
363
  height: number;
319
364
  rotation: number;
320
365
  }>;
366
+ /** A LINKED file drawn in place (an xref); the document holds only this
367
+ * record — the file's content is not readable from scripts. */
368
+ export type StoredReference = StoredShape<{
369
+ type: "reference";
370
+ format: "linea" | "dxf" | "dwg" | "pdf" | "png" | "jpg";
371
+ name: string;
372
+ source: {
373
+ kind: "path";
374
+ path: string;
375
+ cacheKey?: string;
376
+ } | {
377
+ kind: "url";
378
+ url: string;
379
+ };
380
+ /** Where the file's origin lands. */
381
+ position: Vec2;
382
+ rotation: number;
383
+ scale: number;
384
+ mirrored?: boolean;
385
+ pdfPage?: number;
386
+ pdfMode?: "vector" | "raster";
387
+ /** The file's layers not drawn, by name. */
388
+ hiddenLayers: readonly string[];
389
+ /** Switched off: not drawn. */
390
+ hidden?: boolean;
391
+ /** Crop rectangle in file coordinates. */
392
+ clip?: {
393
+ minX: number;
394
+ minY: number;
395
+ maxX: number;
396
+ maxY: number;
397
+ };
398
+ /** Content bounds in file coordinates at the last load. */
399
+ extent?: {
400
+ minX: number;
401
+ minY: number;
402
+ maxX: number;
403
+ maxY: number;
404
+ };
405
+ }>;
406
+ /** Review note pinned to a point; the editor shows a screen-fixed marker. */
407
+ export type StoredComment = StoredShape<{
408
+ type: "comment";
409
+ /** Tail tip of the bubble (world/sheet mm). */
410
+ position: Vec2;
411
+ text: string;
412
+ tags: readonly string[];
413
+ }>;
414
+ /** Text style keys a text, table or table cell may override. */
415
+ export type TextStyleOverride = {
416
+ font?: string;
417
+ widthFactor?: number;
418
+ bold?: boolean;
419
+ italic?: boolean;
420
+ textHeight?: number;
421
+ arrowType?: "filled" | "open" | "tick" | "dot" | "none";
422
+ arrowSize?: number;
423
+ };
424
+ /** One table cell as stored. */
425
+ export type StoredTableCell = {
426
+ /** Plain text; "\n" = line break. */
427
+ text: string;
428
+ /** Merge, on the anchor (top-left) cell; covered cells are ignored. */
429
+ span?: {
430
+ cols: number;
431
+ rows: number;
432
+ };
433
+ hAlign?: "left" | "center" | "right";
434
+ vAlign?: "top" | "center" | "bottom";
435
+ styleId?: string;
436
+ styleOverride?: TextStyleOverride;
437
+ color?: string;
438
+ };
439
+ /** Grid of text cells hanging right/down from `position` (top-left). */
440
+ export type StoredTable = StoredShape<{
441
+ type: "table";
442
+ position: Vec2;
443
+ rotation: number;
444
+ scale: number;
445
+ /** Column widths (mm, before `scale`). */
446
+ columns: readonly number[];
447
+ rows: readonly {
448
+ minHeight?: number;
449
+ }[];
450
+ /** Row-major `cells[row][column]`. */
451
+ cells: readonly (readonly StoredTableCell[])[];
452
+ headerRows: number;
453
+ cellMargin: number;
454
+ borders: "all" | "outer" | "rows" | "none";
455
+ styleId?: string;
456
+ styleOverride?: TextStyleOverride;
457
+ }>;
321
458
  /** Any object as stored in the document — what reads hand to scripts. */
322
- export type StoredObject = StoredLine | StoredPoint | StoredPolyline | StoredCircle | StoredArc | StoredEllipse | StoredHatch | StoredText | StoredDimension | StoredBlock | StoredViewport | StoredImage;
459
+ export type StoredObject = StoredLine | StoredPoint | StoredPolyline | StoredCircle | StoredArc | StoredEllipse | StoredHatch | StoredText | StoredDimension | StoredBlock | StoredViewport | StoredImage | StoredComment | StoredTable | StoredReference;
323
460
  /**
324
461
  * One choice of a "Select" parameter: the value (what scripts receive) with
325
462
  * an optional properties-panel label. A plain string is shorthand for
@@ -328,44 +465,152 @@ declare module "lineadraw" {
328
465
  export type ParameterOption = string | {
329
466
  value: string;
330
467
  label?: string;
468
+ /** A `#rrggbb` color square before the option's label. */
469
+ swatch?: string;
331
470
  };
332
471
  /**
333
472
  * One entry of the module's optional `params` export — the block's
334
473
  * parameters table. `name` is the key scripts read from `params`, `label`
335
474
  * the properties-panel caption (defaults to the name).
336
475
  */
337
- export type ParamDef = {
476
+ /** What every params-table entry may carry: its key, panel caption and
477
+ * tooltip. */
478
+ type ParamBase = {
479
+ /** The key scripts read from `params`. */
338
480
  name: string;
481
+ /** The properties-panel caption (defaults to the name). */
339
482
  label?: string;
483
+ /** What the parameter means: the label's tooltip in the panel. */
484
+ hint?: string;
485
+ };
486
+ export type ParamDef = (ParamBase & {
340
487
  type: "number";
341
488
  default: number;
342
489
  min?: number;
343
490
  max?: number;
344
- } | {
345
- name: string;
346
- label?: string;
491
+ /** Whole numbers only. */
492
+ integer?: boolean;
493
+ /** ArrowUp / ArrowDown increment in the panel (default 1). */
494
+ step?: number;
495
+ /** Shown inside the field before / after the value ("1:", "mm"). */
496
+ prefix?: string;
497
+ suffix?: string;
498
+ /** Standard values offered in the field's dropdown; typing stays free. */
499
+ presets?: readonly number[];
500
+ }) | (ParamBase & {
347
501
  type: "string";
348
502
  default: string;
349
- } | {
350
- name: string;
351
- label?: string;
503
+ placeholder?: string;
504
+ /** A textarea; Shift+Enter starts a new line. */
505
+ multiline?: boolean;
506
+ presets?: readonly string[];
507
+ }) | (ParamBase & {
352
508
  type: "boolean";
353
509
  default: boolean;
354
- } | {
355
- name: string;
356
- label?: string;
510
+ /** "toggle": a toggle button showing the label (compact, e.g. in a
511
+ * row beside a picker) instead of a switch. */
512
+ display?: "switch" | "toggle";
513
+ })
514
+ /** A list of numbers, edited as space-separated text with Tekla-style
515
+ * `N*d` repeats ("0 2*7200" → [0, 7200, 7200]). */
516
+ | (ParamBase & {
517
+ type: "numberList";
518
+ default: readonly number[];
519
+ /** Shown while the list is empty. */
520
+ placeholder?: string;
521
+ min?: number;
522
+ max?: number;
523
+ presets?: readonly (readonly number[])[];
524
+ })
525
+ /** A list of strings, edited as space-separated words; double quotes group
526
+ * a phrase ('A "B 2"' → ["A", "B 2"]). */
527
+ | (ParamBase & {
528
+ type: "stringList";
529
+ default: readonly string[];
530
+ /** Shown while the list is empty. */
531
+ placeholder?: string;
532
+ presets?: readonly (readonly string[])[];
533
+ })
534
+ /** A `#rrggbb` color: a swatch with a picker; presets form a palette. */
535
+ | (ParamBase & {
536
+ type: "color";
537
+ default: string;
538
+ presets?: readonly string[];
539
+ }) | (ParamBase & {
357
540
  type: "enum";
358
541
  default: string;
359
542
  options: readonly ParameterOption[];
360
- }
543
+ /** "buttons": a segmented toggle group of the options (short
544
+ * choices); falls back to the dropdown when they don't fit. */
545
+ display?: "dropdown" | "buttons";
546
+ })
547
+ /** Pickers over the document's resources; the value is an id / name.
548
+ * textStyle / dimStyle: a style id ("" or unknown = the document's first
549
+ * style — read it in draw with `styles.text(id)` / `styles.dim(id)`, or
550
+ * hand it to children as `styleId`). font: a font id ("arial"…).
551
+ * lineType / hatchPattern: a linetype / pattern name. */
552
+ | (ParamBase & {
553
+ type: "textStyle" | "dimStyle" | "font" | "lineType" | "hatchPattern";
554
+ default?: string;
555
+ })
361
556
  /** A section label between rows in the properties panel. Carries no
362
557
  * value: it never appears in the `params` record `draw` receives.
363
558
  * `name` stays the unique key (paramVisibility can hide it by name). */
364
- | {
365
- name: string;
366
- label?: string;
559
+ | (ParamBase & {
367
560
  type: "label";
561
+ })
562
+ /** Layout only: 2–3 compact params on one panel row, each item's label a
563
+ * short prefix ("W", "H"). Values stay flat — `params.w`, `params.h`. */
564
+ | (ParamBase & {
565
+ type: "row";
566
+ items: readonly RowItemDef[];
567
+ });
568
+ /** A document text style as `draw` reads it (`styles.text(id)`). Heights
569
+ * and arrow sizes are mm before an object's `scale`. */
570
+ export type TextStyleInfo = {
571
+ readonly id: string;
572
+ readonly name: string;
573
+ readonly font: string;
574
+ readonly widthFactor: number;
575
+ readonly bold?: boolean;
576
+ readonly italic?: boolean;
577
+ readonly textHeight: number;
578
+ readonly arrowType: "filled" | "open" | "tick" | "dot" | "none";
579
+ readonly arrowSize: number;
368
580
  };
581
+ /** A document dimension style as `draw` reads it (`styles.dim(id)`). */
582
+ export type DimStyleInfo = {
583
+ readonly id: string;
584
+ readonly name: string;
585
+ readonly font: string;
586
+ readonly widthFactor: number;
587
+ readonly bold?: boolean;
588
+ readonly italic?: boolean;
589
+ readonly textHeight: number;
590
+ readonly textOffset: number;
591
+ readonly arrowType: "filled" | "open" | "tick" | "dot" | "none";
592
+ readonly arrowSize: number;
593
+ readonly extensionType: "long" | "short";
594
+ readonly extensionOffset: number;
595
+ readonly extensionOvershoot: number;
596
+ readonly precision: number;
597
+ };
598
+ /** `draw`'s `styles`: the document's styles by id. An empty or unknown id
599
+ * (a deleted style, a block from another drawing) gives the document's
600
+ * first style — the same rule a child's `styleId` follows. */
601
+ export interface BlockStyles {
602
+ text(id?: string): TextStyleInfo;
603
+ dim(id?: string): DimStyleInfo;
604
+ }
605
+ /** What a `row` may hold: the compact, single-line param kinds. */
606
+ export type RowItemDef = Extract<ParamDef, {
607
+ type: "number" | "string" | "boolean" | "enum" | "color" | "textStyle" | "dimStyle" | "font" | "lineType" | "hatchPattern";
608
+ }>;
609
+ /** A table entry's value-carrying params: a row's items, else itself. */
610
+ type FlatParam<Q> = Q extends {
611
+ type: "row";
612
+ items: readonly (infer I)[];
613
+ } ? I : Q;
369
614
  /**
370
615
  * The block's parameters table — what the `params` member of a BlockSpec
371
616
  * declares (or its function form returns).
@@ -384,7 +629,11 @@ declare module "lineadraw" {
384
629
  type: "number";
385
630
  } ? number : Q extends {
386
631
  type: "boolean";
387
- } ? boolean : string;
632
+ } ? boolean : Q extends {
633
+ type: "numberList";
634
+ } ? readonly number[] : Q extends {
635
+ type: "stringList";
636
+ } ? readonly string[] : string;
388
637
  /**
389
638
  * The values record a params table produces: each entry's `name` maps to
390
639
  * its runtime value type (number/string/boolean, or the enum's option
@@ -395,10 +644,469 @@ declare module "lineadraw" {
395
644
  * passes through unchanged.
396
645
  */
397
646
  export type ParamValues<P> = P extends () => infer R ? ParamValues<R> : P extends readonly (infer Q extends ParamDef)[] ? {
398
- readonly [E in Q as E extends {
647
+ readonly [E in FlatParam<Q> as E extends {
399
648
  type: "label";
400
- } ? never : E["name"]]: ParamValue<E>;
649
+ } ? never : E extends {
650
+ name: infer N extends string;
651
+ } ? N : never]: E extends ParamDef ? ParamValue<E> : never;
401
652
  } : P;
653
+ /** An axis-aligned box in world mm. */
654
+ export type Box = {
655
+ minX: number;
656
+ minY: number;
657
+ maxX: number;
658
+ maxY: number;
659
+ };
660
+ /** Filters for Drawing.query — all present filters AND together. */
661
+ export type ObjectQuery = {
662
+ ids?: readonly string[];
663
+ type?: ModelObject["type"];
664
+ /** Layer name or id. */
665
+ layer?: string;
666
+ /** #rrggbb override (objects without one inherit from their layer). */
667
+ color?: string;
668
+ lineType?: string;
669
+ /** Substring match on text content. */
670
+ content?: string;
671
+ /** Bounds intersect this box. */
672
+ bbox?: Box;
673
+ /** Bounds entirely inside this box. */
674
+ inside?: Box;
675
+ /** Geometry within `tol` mm of `point`. */
676
+ near?: {
677
+ point: Vec2Like;
678
+ tol: number;
679
+ };
680
+ /** Search this paper layout's sheet objects (name or id) instead of
681
+ * model space. */
682
+ layout?: string;
683
+ };
684
+ /** A STORED object as query() returns it (see StoredObject — schema
685
+ * output: defaults applied, points always {x, y}, identity present). */
686
+ export type ExistingObject = StoredObject;
687
+ /** Per-object measurements; null where the type has no natural value. */
688
+ export type Measurement = {
689
+ bbox: Box | null;
690
+ length: number | null;
691
+ area: number | null;
692
+ };
693
+ /** A layer as stored (defaults applied) plus the current-layer flag. */
694
+ export type LayerInfo = {
695
+ id: string;
696
+ name: string;
697
+ color: string;
698
+ lineType: string;
699
+ lineWidth: number;
700
+ opacity: number;
701
+ visible: boolean;
702
+ locked: boolean;
703
+ current: boolean;
704
+ [key: string]: unknown;
705
+ };
706
+ /** A paper layout as stored: sheet metadata + its sheet-space objects. */
707
+ export type LayoutInfo = {
708
+ id: string;
709
+ name: string;
710
+ sheet: {
711
+ width: number;
712
+ height: number;
713
+ };
714
+ printPalette: "color" | "grayscale" | "monochrome";
715
+ objects: readonly StoredObject[];
716
+ };
717
+ /** A block module's identity/metadata (from its exports). */
718
+ export type BlockInfo = {
719
+ id: string;
720
+ name: string;
721
+ description?: string;
722
+ version?: string;
723
+ authors?: readonly string[];
724
+ tags?: readonly string[];
725
+ dependencies?: readonly string[];
726
+ };
727
+ /** A command module's identity/metadata (from its exports). */
728
+ export type CommandInfo = {
729
+ id: string;
730
+ name: string;
731
+ description?: string;
732
+ version?: string;
733
+ authors?: readonly string[];
734
+ tags?: readonly string[];
735
+ /** Declared point inputs (labels), picked or supplied before `run`. */
736
+ inputs?: readonly string[];
737
+ /** Declared parameters (same table as a block's), prompted or supplied
738
+ * before `run`. */
739
+ params?: readonly ParamDef[];
740
+ };
741
+ /** What installing module sources reports. */
742
+ export type MergeReport = {
743
+ /** The full library after the merge. */
744
+ merged: readonly string[];
745
+ added: readonly {
746
+ script: string;
747
+ meta: {
748
+ id: string;
749
+ name: string;
750
+ };
751
+ }[];
752
+ replaced: readonly {
753
+ script: string;
754
+ meta: {
755
+ id: string;
756
+ name: string;
757
+ };
758
+ }[];
759
+ skipped: number;
760
+ rejected: readonly {
761
+ script: string;
762
+ error: string;
763
+ }[];
764
+ };
765
+ /** A sheet: a bare preset (orientation from context — landscape for a new
766
+ * layout, the current one when patching), a preset with its orientation, or
767
+ * explicit millimetres. */
768
+ export type SheetSpec = "A4" | "A3" | "A2" | "A1" | "A0" | {
769
+ name: "A4" | "A3" | "A2" | "A1" | "A0";
770
+ orientation: "portrait" | "landscape";
771
+ } | {
772
+ width: number;
773
+ height: number;
774
+ };
775
+ /** What an import added (`objectIds` = the new objects). */
776
+ export interface ImportReport {
777
+ objects: number;
778
+ objectIds: string[];
779
+ }
780
+ /** Options for Drawing.addLayout. */
781
+ export type LayoutSpec = {
782
+ /** Default: A3 landscape. */
783
+ sheet?: SheetSpec;
784
+ /** Viewport scale — `"1:50"` or the denominator; default: fitted. */
785
+ scale?: number | string;
786
+ /** One fitted model viewport (default), or `false` for a bare sheet. */
787
+ viewport?: {
788
+ rect?: {
789
+ x: number;
790
+ y: number;
791
+ w: number;
792
+ h: number;
793
+ };
794
+ scale?: number | string;
795
+ center?: Vec2Like;
796
+ } | false;
797
+ /** Tab position; default: append. */
798
+ index?: number;
799
+ };
800
+ /** The whole document as stored (defaults applied). */
801
+ export type StoredDocument = {
802
+ id: string;
803
+ version: number;
804
+ layers: readonly Omit<LayerInfo, "current">[];
805
+ currentLayerId: string;
806
+ objects: readonly StoredObject[];
807
+ layouts: readonly LayoutInfo[];
808
+ /** Raw block module sources. */
809
+ blockDefinitions: readonly string[];
810
+ /** Raw command module sources. */
811
+ commands: readonly string[];
812
+ [key: string]: unknown;
813
+ };
814
+ /** Where a draw-order move puts the objects. */
815
+ export type ReorderPlacement = "front" | "back" | {
816
+ above: string;
817
+ } | {
818
+ below: string;
819
+ };
820
+ /**
821
+ * The document as command scripts see it — the SAME `Drawing` interface
822
+ * the agent tools and the SDK use. Angles are RADIANS, point-valued
823
+ * arguments accept {x, y} or [x, y], `layer` resolves by name or id.
824
+ * Object mutations on an editor-attached drawing target the ACTIVE space.
825
+ * Methods throw on invalid input (an uncaught throw cancels the command
826
+ * and rolls its edits back). Reads return detached snapshots.
827
+ */
828
+ export interface Drawing {
829
+ /** The document's own id. */
830
+ readonly id: string;
831
+ /** Monotonic change counter. */
832
+ readonly revision: number;
833
+ /** The full document — a detached snapshot. */
834
+ readonly document: StoredDocument;
835
+ /** Counts by type/layer, bbox, layer + layout names. */
836
+ summary(): {
837
+ name: string;
838
+ objectCount: number;
839
+ byType: Record<string, number>;
840
+ byLayer: Record<string, number>;
841
+ bbox: Box | null;
842
+ layers: string[];
843
+ layouts: {
844
+ name: string;
845
+ objectCount: number;
846
+ }[];
847
+ };
848
+ /** Filtered objects — model space, or one layout via `filter.layout`. */
849
+ listObjects(filter?: ObjectQuery): ExistingObject[];
850
+ /** One object from ANY space, or undefined. */
851
+ getObject(id: string): ExistingObject | undefined;
852
+ /** bbox / curve length / enclosed area of one object. */
853
+ measure(id: string): Measurement;
854
+ listLayers(): LayerInfo[];
855
+ listLayouts(): LayoutInfo[];
856
+ /** Compilable block definitions in this document. */
857
+ listBlockDefinitions(): BlockInfo[];
858
+ /** Compilable command modules travelling with this document. */
859
+ listUserCommands(): CommandInfo[];
860
+ /** Model space (or a layout via `layout`) as an SVG string. */
861
+ renderSvg(opts?: {
862
+ layout?: string;
863
+ bbox?: Box;
864
+ padding?: number;
865
+ palette?: "color" | "grayscale" | "monochrome";
866
+ }): string;
867
+ /** Model space (or a layout) as PNG bytes — absent on hosts that can't
868
+ * rasterize, so check before calling. */
869
+ renderPng?(opts?: {
870
+ layout?: string;
871
+ bbox?: Box;
872
+ padding?: number;
873
+ palette?: "color" | "grayscale" | "monochrome";
874
+ /** Output width in px (height follows). Default 1024. */
875
+ width?: number;
876
+ /** Background fill, e.g. "#ffffff". Default: the dark canvas. */
877
+ background?: string;
878
+ }): Promise<Uint8Array>;
879
+ /** Multi-page PDF of the layouts (default: all) — absent on hosts
880
+ * without fonts, so check before calling. */
881
+ renderPdf?(opts?: {
882
+ layouts?: readonly string[];
883
+ palette?: "color" | "grayscale" | "monochrome";
884
+ }): Promise<Uint8Array>;
885
+ /** The whole document as DXF text. */
886
+ toDxf(): Promise<string>;
887
+ /** DWG bytes (default AC1027 — AutoCAD 2013). */
888
+ toDwg(opts?: {
889
+ version?: string;
890
+ }): Promise<Uint8Array>;
891
+ /** The `.linea` file text. */
892
+ toLinea(): string;
893
+ /** Add objects (each may carry `layer` — a name — instead of an id);
894
+ * returns the created ids. */
895
+ add(objects: readonly (ModelObject & {
896
+ layer?: string;
897
+ })[], opts?: {
898
+ layout?: string;
899
+ }): string[];
900
+ /** Apply per-object patches (`{ id, ...changedFields }`). */
901
+ update(entries: readonly ({
902
+ id: string;
903
+ } & Record<string, unknown>)[]): void;
904
+ /** Delete by id (unknown ids are skipped); returns how many went. */
905
+ remove(ids: readonly string[]): number;
906
+ /** Draw order: move the objects (bottom → top) to a placement. */
907
+ reorder(ids: readonly string[], placement: ReorderPlacement): void;
908
+ move(ids: readonly string[], delta: Vec2Like): void;
909
+ rotate(ids: readonly string[], angleRad: number, center?: Vec2Like): void;
910
+ scale(ids: readonly string[], factor: number, center?: Vec2Like): void;
911
+ mirror(ids: readonly string[], axisA: Vec2Like, axisB: Vec2Like): void;
912
+ /** Duplicate displaced by delta; returns the new ids. */
913
+ copy(ids: readonly string[], delta: Vec2Like): string[];
914
+ /** count TOTAL copies at multiples of delta; returns the new ids. */
915
+ array(ids: readonly string[], count: number, delta: Vec2Like): string[];
916
+ /** Create a paper layout; returns its id. */
917
+ addLayout(name: string, opts?: LayoutSpec): string;
918
+ /** Patch a layout's name / sheet / print palette. A bare preset keeps the
919
+ * layout's current orientation. */
920
+ updateLayout(nameOrId: string, patch: {
921
+ name?: string;
922
+ sheet?: SheetSpec;
923
+ printPalette?: "color" | "grayscale" | "monochrome";
924
+ }): void;
925
+ removeLayout(nameOrId: string): void;
926
+ /** Explicit total order (names or ids) — the PDF page order. */
927
+ reorderLayouts(order: readonly string[]): void;
928
+ /** Create a layer (unique name); returns its id. */
929
+ addLayer(props: {
930
+ name: string;
931
+ color?: string;
932
+ } & Record<string, unknown>): string;
933
+ updateLayer(nameOrId: string, patch: Record<string, unknown>): void;
934
+ /** Remove an EMPTY, non-current layer. */
935
+ removeLayer(nameOrId: string): void;
936
+ /** Explicit total order (names or ids, every layer exactly once). */
937
+ reorderLayers(order: readonly string[]): void;
938
+ setCurrentLayer(nameOrId: string): void;
939
+ listTextStyles(): ({
940
+ id: string;
941
+ name: string;
942
+ } & Record<string, unknown>)[];
943
+ listDimStyles(): ({
944
+ id: string;
945
+ name: string;
946
+ } & Record<string, unknown>)[];
947
+ /** Create a style (unique name; unset fields take the defaults); returns
948
+ * its id. Styles are addressed by name or id. */
949
+ addTextStyle(props: {
950
+ name: string;
951
+ } & Record<string, unknown>): string;
952
+ updateTextStyle(nameOrId: string, patch: Record<string, unknown>): void;
953
+ /** Remove a style no object uses (refused otherwise). */
954
+ removeTextStyle(nameOrId: string): void;
955
+ addDimStyle(props: {
956
+ name: string;
957
+ } & Record<string, unknown>): string;
958
+ updateDimStyle(nameOrId: string, patch: Record<string, unknown>): void;
959
+ removeDimStyle(nameOrId: string): void;
960
+ /** @deprecated Use updateDimStyle (default here: the first style). */
961
+ setDimStyle(patch: Record<string, unknown>, styleId?: string): void;
962
+ /** @deprecated Use updateTextStyle (default here: the first style). */
963
+ setTextStyle(patch: Record<string, unknown>, styleId?: string): void;
964
+ /** Embed image pixels (a data URL); returns the content-keyed assetId
965
+ * that `image` objects reference. */
966
+ addAsset(dataUrl: string): string;
967
+ /** Remove an asset (refused while an image references it). */
968
+ removeAsset(id: string): void;
969
+ /** Embedded image assets and how many images use each. */
970
+ listAssets(): {
971
+ id: string;
972
+ mimeType: string;
973
+ bytes: number;
974
+ users: number;
975
+ }[];
976
+ /** Merge DXF text (new layers, objects, layouts); `unitOverride` = mm
977
+ * per drawing unit. */
978
+ importDxfText(text: string, opts?: {
979
+ unitOverride?: number;
980
+ }): ImportReport & {
981
+ layers: number;
982
+ layouts: number;
983
+ layoutIds: string[];
984
+ };
985
+ /** Merge DWG bytes (transcoded to DXF). */
986
+ importDwgData(data: Uint8Array, opts?: {
987
+ unitOverride?: number;
988
+ }): Promise<ImportReport & {
989
+ layers: number;
990
+ layouts: number;
991
+ layoutIds: string[];
992
+ }>;
993
+ /** Merge a PDF: vectors/text onto the current layer, or (`as: "image"`,
994
+ * not available on every host) each page as an image at true scale. */
995
+ importPdfData(data: ArrayBuffer | Uint8Array, opts?: {
996
+ as?: "vectors" | "image";
997
+ origin?: Vec2Like;
998
+ }): Promise<ImportReport & {
999
+ pageCount: number;
1000
+ }>;
1001
+ /** Merge block module sources into the document library. */
1002
+ addBlockDefinitions(sources: readonly string[]): Promise<MergeReport>;
1003
+ removeBlockDefinition(id: string): void;
1004
+ addUserCommands(sources: readonly string[]): Promise<MergeReport>;
1005
+ removeUserCommand(id: string): void;
1006
+ /** Escape hatch: apply an already-shaped kernel op batch (validated,
1007
+ * atomic, one undo step). */
1008
+ applyOps(ops: readonly Record<string, unknown>[]): void;
1009
+ /**
1010
+ * Group edits into ONE undo step (a command run already is one; nested
1011
+ * calls join it). A throw rolls back what the transaction applied.
1012
+ */
1013
+ transaction<T>(fn: () => T, label?: string): T;
1014
+ /** Not available while a command runs (throws) — return or throw. */
1015
+ undo(): boolean;
1016
+ redo(): boolean;
1017
+ }
1018
+ /** The editor's state as a script sees it. */
1019
+ export type EditorState = {
1020
+ documentId: string;
1021
+ documentName: string;
1022
+ space: "model" | {
1023
+ layout: string;
1024
+ };
1025
+ selectedIds: string[];
1026
+ readOnly: boolean;
1027
+ canUndo: boolean;
1028
+ canRedo: boolean;
1029
+ };
1030
+ /** One runnable editor command (registry entry, macro, or insert-block). */
1031
+ export type EditorCommandInfo = {
1032
+ id: string;
1033
+ label: string;
1034
+ group: string;
1035
+ hotkey?: string;
1036
+ };
1037
+ /**
1038
+ * The interactive half of the context — present only when the command runs
1039
+ * inside a live editor (absent when a script runs headlessly, e.g. from the
1040
+ * CLI or the MCP server; branch on it). The pickers and `prompt` REJECT
1041
+ * when the user cancels (Escape) — let that propagate to abort the command
1042
+ * (all edits roll back), or catch it to finish an open-ended collection.
1043
+ */
1044
+ export interface EditorSurface {
1045
+ state(): EditorState;
1046
+ setActiveSpace(space: "model" | {
1047
+ layout: string;
1048
+ }): void;
1049
+ setSelection(ids: readonly string[]): void;
1050
+ /** "fit" (everything in the active space), "selection", some objects'
1051
+ * extents (`{ ids }`), or a window (`{ bbox }`, world mm; sheet mm in a
1052
+ * layout). */
1053
+ zoom(to: "fit" | "selection" | {
1054
+ ids: readonly string[];
1055
+ } | {
1056
+ bbox: Box;
1057
+ }): void;
1058
+ /** Await one snapped world point; `referencePoint` enables rubber-band
1059
+ * + relative typed entry from there. */
1060
+ pickPoint(opts?: {
1061
+ label?: string;
1062
+ referencePoint?: Vec2Like;
1063
+ }): Promise<Vec2>;
1064
+ /** Await one object click; resolves the object's id. */
1065
+ pickObject(opts?: {
1066
+ label?: string;
1067
+ }): Promise<string>;
1068
+ /** Await a typed value from a small input dialog. */
1069
+ prompt(message: string, opts?: {
1070
+ initial?: string;
1071
+ placeholder?: string;
1072
+ }): Promise<string>;
1073
+ toast(message: string, kind?: "info" | "success" | "error"): void;
1074
+ /** Registry commands + macros + insert-block entries. */
1075
+ listCommands(): EditorCommandInfo[];
1076
+ /** Trigger a command by id — like the user pressing its hotkey. A macro
1077
+ * takes its declared `inputs` / `params` up front (params passed skip its
1078
+ * params dialog). */
1079
+ runCommand(id: string, inputs?: readonly Vec2Like[], params?: Readonly<Record<string, unknown>>): Promise<void>;
1080
+ }
1081
+ /**
1082
+ * What `run` receives. `document` is the Drawing; `editor` the interactive
1083
+ * surface when there is one; `inputs` the points the command's declared
1084
+ * `inputs` labels produced (picked in the editor, or supplied by the
1085
+ * caller), in label order; `params` the values of the declared `params`
1086
+ * table (asked for in a dialog in the editor, or passed by the caller;
1087
+ * omitted ones take their defaults).
1088
+ */
1089
+ export interface CommandContext<P = Readonly<Record<string, unknown>>> {
1090
+ document: Drawing;
1091
+ editor?: EditorSurface;
1092
+ inputs: readonly Vec2[];
1093
+ params: P;
1094
+ /** @deprecated Use `editor.pickPoint({ label })` (throws without an editor). */
1095
+ pickPoint(label?: string): Promise<Vec2>;
1096
+ /** @deprecated Use `editor.pickObject({ label })`. */
1097
+ pickObject(label?: string): Promise<string>;
1098
+ /** @deprecated Use `editor.state().selectedIds`. */
1099
+ selection(): string[];
1100
+ /** @deprecated Use `editor.setSelection(ids)`. */
1101
+ setSelection(ids: readonly string[]): void;
1102
+ /** @deprecated Use `editor.prompt(message, options)`. */
1103
+ prompt(message: string, options?: {
1104
+ initial?: string;
1105
+ placeholder?: string;
1106
+ }): Promise<string>;
1107
+ /** @deprecated Use `editor.toast(message, kind)`. */
1108
+ showToast(message: string, kind?: "info" | "success" | "error"): void;
1109
+ }
402
1110
 
403
1111
  // ——— Script contract ———
404
1112
 
@@ -557,6 +1265,10 @@ declare module "lineadraw" {
557
1265
  draw: (props: {
558
1266
  params: ParamValues<P>;
559
1267
  inputs: PlaceInputs<Pl>;
1268
+ /** The document's text / dimension styles by id — for blocks that
1269
+ * lay out with real text sizes. Pass a picked id on to children as
1270
+ * `styleId` to let them follow the style. */
1271
+ styles: BlockStyles;
560
1272
  }) => BlockScriptResult;
561
1273
  }
562
1274
 
@@ -598,133 +1310,41 @@ declare module "lineadraw" {
598
1310
  ): BlockSpec<P, (props: PlaceProps<P>) => R>;
599
1311
 
600
1312
  // ——— Commands (macro scripts) ———
601
-
602
- /** An axis-aligned box in world mm. */
603
- export type Box = { minX: number; minY: number; maxX: number; maxY: number };
604
-
605
- /** Filters for CommandDocument.query — all present filters AND together. */
606
- export interface ObjectQuery {
607
- ids?: readonly string[];
608
- type?: ModelObject["type"];
609
- /** Layer name or id. */
610
- layer?: string;
611
- /** #rrggbb override (objects without one inherit from their layer). */
612
- color?: string;
613
- lineType?: string;
614
- /** Substring match on text content. */
615
- content?: string;
616
- /** Bounds intersect this box. */
617
- bbox?: Box;
618
- /** Bounds entirely inside this box. */
619
- inside?: Box;
620
- /** Geometry within `tol` mm of `point`. */
621
- near?: { point: Vec2Like; tol: number };
622
- }
623
-
624
- /** A STORED object as query() returns it (see StoredObject — schema
625
- * output: defaults applied, points always {x, y}, identity present). */
626
- export type ExistingObject = StoredObject;
627
-
628
- /** Per-object measurements; null where the type has no natural value. */
629
- export type Measurement = {
630
- bbox: Box | null;
631
- length: number | null;
632
- area: number | null;
633
- };
634
-
635
- /**
636
- * The document as command scripts see it — the same session surface the
637
- * agent tools are written against. Angles are RADIANS, point-valued
638
- * arguments accept {x, y} or [x, y], `layer` resolves by name or id.
639
- * Object mutations target the ACTIVE space. Methods throw on invalid
640
- * input (an uncaught throw cancels the command and rolls its edits back).
641
- */
642
- export interface CommandDocument {
643
- /** Add objects (each may carry `layer` — a name — instead of an id);
644
- * returns the created ids. */
645
- add(
646
- objects: readonly (ModelObject & { layer?: string })[],
647
- opts?: { layout?: string },
648
- ): string[];
649
- /** Apply per-object patches (`{ id, ...changedFields }`). */
650
- update(entries: readonly ({ id: string } & Record<string, unknown>)[]): void;
651
- /** Delete by id (unknown ids are skipped); returns how many went. */
652
- remove(ids: readonly string[]): number;
653
- move(ids: readonly string[], delta: Vec2Like): void;
654
- rotate(ids: readonly string[], angleRad: number, center?: Vec2Like): void;
655
- scale(ids: readonly string[], factor: number, center?: Vec2Like): void;
656
- mirror(ids: readonly string[], axisA: Vec2Like, axisB: Vec2Like): void;
657
- /** Duplicate displaced by delta; returns the new ids. */
658
- copy(ids: readonly string[], delta: Vec2Like): string[];
659
- /** count TOTAL copies at multiples of delta; returns the new ids. */
660
- array(ids: readonly string[], count: number, delta: Vec2Like): string[];
661
- /** Filtered MODEL-space objects. */
662
- query(filter: ObjectQuery): ExistingObject[];
663
- /** bbox / curve length / enclosed area of one object. */
664
- measure(id: string): Measurement;
665
- listLayers(): {
666
- id: string;
667
- name: string;
668
- current: boolean;
669
- [key: string]: unknown;
670
- }[];
671
- /** Create a layer (unique name); returns its id. */
672
- addLayer(
673
- props: { name: string; color?: string } & Record<string, unknown>,
674
- ): string;
675
- updateLayer(nameOrId: string, patch: Record<string, unknown>): void;
676
- /** Remove an EMPTY, non-current layer. */
677
- removeLayer(nameOrId: string): void;
678
- setCurrentLayer(nameOrId: string): void;
679
- /** Create a paper layout; returns its id. `scale` accepts "1:50". */
680
- createLayout(
681
- name: string,
682
- opts: {
683
- sheet?: "A4" | "A3" | "A2" | "A1" | "A0" | { width: number; height: number };
684
- orientation?: "portrait" | "landscape";
685
- scale?: string;
686
- },
687
- ): string;
688
- /** Counts by type/layer, bbox, layer + layout names. */
689
- summary(): Record<string, unknown>;
690
- }
691
-
692
- /**
693
- * What `run` receives. The pickers and `prompt` REJECT when the user
694
- * cancels (Escape) — let that propagate to abort the command (all edits
695
- * roll back), or catch it to finish an open-ended collection gracefully.
696
- */
697
- export interface CommandContext {
698
- document: CommandDocument;
699
- /** Await one snapped world point. */
700
- pickPoint(label?: string): Promise<Vec2>;
701
- /** Await one object click; resolves the object's id. */
702
- pickObject(label?: string): Promise<string>;
703
- /** Ids currently selected — a snapshot; call again after changes. */
704
- selection(): string[];
705
- setSelection(ids: readonly string[]): void;
706
- /** Await a typed value from a small input dialog. */
707
- prompt(
708
- message: string,
709
- options?: { initial?: string; placeholder?: string },
710
- ): Promise<string>;
711
- showToast(message: string, kind?: "info" | "success" | "error"): void;
712
- }
1313
+ // Drawing / EditorSurface / CommandContext are emitted from scriptTypes.ts
1314
+ // above (the script-facing mirror of core's real interfaces).
713
1315
 
714
1316
  /** One user command (macro): identity, metadata, and the `run` body. */
715
- export interface CommandSpec {
1317
+ export interface CommandSpec<P extends BlockParamDefs = readonly []> {
716
1318
  id: string;
717
1319
  name: string;
718
1320
  description?: string;
719
1321
  version?: string;
720
1322
  authors?: readonly string[];
721
1323
  tags?: readonly string[];
1324
+ /**
1325
+ * Point inputs the command needs, as labels (`["Start", "End"]`). In
1326
+ * the editor each is picked in turn before `run` (rubber-band from the
1327
+ * previous pick); a headless or remote caller supplies them up front.
1328
+ * They arrive as `ctx.inputs`, in this order. This is what lets one
1329
+ * script run in the editor, from a shell, and from an agent alike.
1330
+ */
1331
+ inputs?: readonly string[];
1332
+ /**
1333
+ * Parameters the command needs — the same table a block's `params`
1334
+ * declares (number / string / boolean / enum / label rows), or a
1335
+ * zero-arg function returning it. In the editor a dialog asks for them
1336
+ * before `run` (prefilled with the defaults); a headless or remote
1337
+ * caller passes them by name (unknown names and wrong types are an
1338
+ * error). They arrive as `ctx.params`, typed from this table.
1339
+ */
1340
+ params?: P | (() => P);
722
1341
  /**
723
1342
  * The macro body. The whole call is ONE undo step: mutations apply
724
1343
  * live while it runs; cancelling (Escape during a pick/prompt) or an
725
- * uncaught error rolls everything back.
1344
+ * uncaught error rolls everything back. A return value is handed to
1345
+ * the caller (the agent tool / CLI) — the editor ignores it.
726
1346
  */
727
- run(ctx: CommandContext): void | Promise<void>;
1347
+ run(ctx: CommandContext<ParamValues<P>>): unknown;
728
1348
  }
729
1349
 
730
1350
  /**
@@ -736,18 +1356,23 @@ declare module "lineadraw" {
736
1356
  * export default defineCommand({
737
1357
  * id: "…",
738
1358
  * name: "Number the selected texts",
739
- * run: async ({ document, prompt, selection, showToast }) => {
740
- * const start = Number(await prompt("First number", { initial: "1" }));
741
- * const texts = document
742
- * .query({ ids: selection(), type: "text" });
1359
+ * inputs: ["Anchor"],
1360
+ * params: [{ name: "start", label: "First number", type: "number", default: 1 }],
1361
+ * run: ({ document, editor, inputs: [anchor], params: { start } }) => {
1362
+ * const texts = document.listObjects({
1363
+ * type: "text",
1364
+ * near: { point: anchor, tol: 500 },
1365
+ * });
743
1366
  * texts.forEach((t, i) =>
744
1367
  * document.update([{ id: t.id, content: String(start + i) }]),
745
1368
  * );
746
- * showToast(`Numbered ${texts.length} texts`, "success");
1369
+ * editor?.toast(`Numbered ${texts.length} texts`, "success");
747
1370
  * },
748
1371
  * });
749
1372
  */
750
- export function defineCommand(spec: CommandSpec): CommandSpec;
1373
+ export function defineCommand<const P extends BlockParamDefs = readonly []>(
1374
+ spec: CommandSpec<P>,
1375
+ ): CommandSpec<P>;
751
1376
  }
752
1377
 
753
1378
  declare module "lineadraw/helpers" {
@@ -902,18 +1527,22 @@ type Text = Styled<{
902
1527
  position: Vec2Like;
903
1528
  content: string;
904
1529
  rotation?: number;
905
- /** Where the text SITS relative to the point. */
1530
+ /** Justification, as in AutoCAD / DXF: which edge sits on the point —
1531
+ * "left" = the text runs right of it, "right" = left of it; vAlign
1532
+ * "bottom" = the text sits above the point, "top" = below it. */
906
1533
  hAlign?: "left" | "center" | "right";
907
1534
  vAlign?: "bottom" | "center" | "top";
908
1535
  /** Word-wrap / frame width in mm (before `scale`); absent = no wrapping. */
909
1536
  width?: number;
910
- frame?: "none" | "rectangle" | "bottom";
1537
+ frame?: "none" | "rectangle" | "circle" | "slot" | "bottom" | "firstLine";
911
1538
  /** MLEADER-style arrow polylines pointing at the text (arrowhead at [0]). */
912
1539
  leaderLines?: readonly (readonly Vec2Like[])[];
913
1540
  /** Style overrides; absent keys inherit the document text style. */
914
1541
  styleOverride?: {
915
1542
  font?: string;
916
1543
  widthFactor?: number;
1544
+ bold?: boolean;
1545
+ italic?: boolean;
917
1546
  /** Cap height in mm (before `scale`). */
918
1547
  textHeight?: number;
919
1548
  arrowSize?: number;
@@ -953,11 +1582,48 @@ type Block = Styled<{
953
1582
  /** Applied last, about the pivot (the first input point). */
954
1583
  rotation?: number;
955
1584
  scale?: number;
956
- params?: Record<string, number | string | boolean>;
1585
+ params?: Record<string, number | string | boolean | readonly number[] | readonly string[]>;
957
1586
  /** Input points in the PARENT's local coords; the first is the pivot. */
958
1587
  inputs?: readonly Vec2Like[];
959
1588
  }>;
960
- type ModelObject = Line | Point | Polyline | Circle | Arc | Ellipse | Hatch | Text | Dimension | Block;
1589
+ /** A table cell: plain text, or text with merge / alignment / style. */
1590
+ type TableCell = string | {
1591
+ text?: string;
1592
+ /** Merge from this (top-left) cell; covered cells are ignored. */
1593
+ span?: {
1594
+ cols: number;
1595
+ rows: number;
1596
+ };
1597
+ hAlign?: "left" | "center" | "right";
1598
+ vAlign?: "top" | "center" | "bottom";
1599
+ styleId?: string;
1600
+ styleOverride?: TextStyleOverride;
1601
+ color?: string;
1602
+ };
1603
+ /** Grid of text cells hanging right/down from `position` (top-left);
1604
+ * rows grow to fit their wrapped text. */
1605
+ type Table = Styled<{
1606
+ type: "table";
1607
+ position: Vec2Like;
1608
+ /** Column widths (mm, before `scale`). */
1609
+ columns: readonly number[];
1610
+ /** Row count, or per-row settings (`minHeight` mm floor). */
1611
+ rows: number | readonly {
1612
+ minHeight?: number;
1613
+ }[];
1614
+ /** Row-major `cells[row][column]`, exactly rows × columns. */
1615
+ cells: readonly (readonly TableCell[])[];
1616
+ rotation?: number;
1617
+ scale?: number;
1618
+ /** Rows above the heavier header rule. */
1619
+ headerRows?: number;
1620
+ /** Text inset from the cell edges (mm). */
1621
+ cellMargin?: number;
1622
+ borders?: "all" | "outer" | "rows" | "none";
1623
+ styleId?: string;
1624
+ styleOverride?: TextStyleOverride;
1625
+ }>;
1626
+ type ModelObject = Line | Point | Polyline | Circle | Arc | Ellipse | Hatch | Text | Dimension | Block | Table;
961
1627
  /** Identity + shared style fields every stored object carries. */
962
1628
  type StoredObjectBase = {
963
1629
  id: string;
@@ -1051,12 +1717,14 @@ type StoredText = StoredShape<{
1051
1717
  width?: number;
1052
1718
  hAlign: "left" | "center" | "right";
1053
1719
  vAlign: "bottom" | "center" | "top";
1054
- frame?: "none" | "rectangle" | "bottom";
1720
+ frame?: "none" | "rectangle" | "circle" | "slot" | "bottom" | "firstLine";
1055
1721
  styleId?: string;
1056
1722
  /** Only the keys the user actually overrode on this text. */
1057
1723
  styleOverride?: {
1058
1724
  font?: string;
1059
1725
  widthFactor?: number;
1726
+ bold?: boolean;
1727
+ italic?: boolean;
1060
1728
  textHeight?: number;
1061
1729
  arrowType?: "filled" | "open" | "tick" | "dot" | "none";
1062
1730
  arrowSize?: number;
@@ -1075,6 +1743,8 @@ type StoredDimension = StoredShape<{
1075
1743
  styleOverride?: {
1076
1744
  font?: string;
1077
1745
  widthFactor?: number;
1746
+ bold?: boolean;
1747
+ italic?: boolean;
1078
1748
  textHeight?: number;
1079
1749
  textOffset?: number;
1080
1750
  arrowType?: "filled" | "open" | "tick" | "dot" | "none";
@@ -1091,7 +1761,7 @@ type StoredBlock = StoredShape<{
1091
1761
  definitionId: string;
1092
1762
  rotation: number;
1093
1763
  scale: number;
1094
- params: Readonly<Record<string, number | string | boolean>>;
1764
+ params: Readonly<Record<string, number | string | boolean | readonly number[] | readonly string[]>>;
1095
1765
  /** World points and/or referenced object ids, in pick order. */
1096
1766
  inputs: readonly (Vec2 | string)[];
1097
1767
  }>;
@@ -1119,8 +1789,100 @@ type StoredImage = StoredShape<{
1119
1789
  height: number;
1120
1790
  rotation: number;
1121
1791
  }>;
1792
+ /** A LINKED file drawn in place (an xref); the document holds only this
1793
+ * record — the file's content is not readable from scripts. */
1794
+ type StoredReference = StoredShape<{
1795
+ type: "reference";
1796
+ format: "linea" | "dxf" | "dwg" | "pdf" | "png" | "jpg";
1797
+ name: string;
1798
+ source: {
1799
+ kind: "path";
1800
+ path: string;
1801
+ cacheKey?: string;
1802
+ } | {
1803
+ kind: "url";
1804
+ url: string;
1805
+ };
1806
+ /** Where the file's origin lands. */
1807
+ position: Vec2;
1808
+ rotation: number;
1809
+ scale: number;
1810
+ mirrored?: boolean;
1811
+ pdfPage?: number;
1812
+ pdfMode?: "vector" | "raster";
1813
+ /** The file's layers not drawn, by name. */
1814
+ hiddenLayers: readonly string[];
1815
+ /** Switched off: not drawn. */
1816
+ hidden?: boolean;
1817
+ /** Crop rectangle in file coordinates. */
1818
+ clip?: {
1819
+ minX: number;
1820
+ minY: number;
1821
+ maxX: number;
1822
+ maxY: number;
1823
+ };
1824
+ /** Content bounds in file coordinates at the last load. */
1825
+ extent?: {
1826
+ minX: number;
1827
+ minY: number;
1828
+ maxX: number;
1829
+ maxY: number;
1830
+ };
1831
+ }>;
1832
+ /** Review note pinned to a point; the editor shows a screen-fixed marker. */
1833
+ type StoredComment = StoredShape<{
1834
+ type: "comment";
1835
+ /** Tail tip of the bubble (world/sheet mm). */
1836
+ position: Vec2;
1837
+ text: string;
1838
+ tags: readonly string[];
1839
+ }>;
1840
+ /** Text style keys a text, table or table cell may override. */
1841
+ type TextStyleOverride = {
1842
+ font?: string;
1843
+ widthFactor?: number;
1844
+ bold?: boolean;
1845
+ italic?: boolean;
1846
+ textHeight?: number;
1847
+ arrowType?: "filled" | "open" | "tick" | "dot" | "none";
1848
+ arrowSize?: number;
1849
+ };
1850
+ /** One table cell as stored. */
1851
+ type StoredTableCell = {
1852
+ /** Plain text; "\n" = line break. */
1853
+ text: string;
1854
+ /** Merge, on the anchor (top-left) cell; covered cells are ignored. */
1855
+ span?: {
1856
+ cols: number;
1857
+ rows: number;
1858
+ };
1859
+ hAlign?: "left" | "center" | "right";
1860
+ vAlign?: "top" | "center" | "bottom";
1861
+ styleId?: string;
1862
+ styleOverride?: TextStyleOverride;
1863
+ color?: string;
1864
+ };
1865
+ /** Grid of text cells hanging right/down from `position` (top-left). */
1866
+ type StoredTable = StoredShape<{
1867
+ type: "table";
1868
+ position: Vec2;
1869
+ rotation: number;
1870
+ scale: number;
1871
+ /** Column widths (mm, before `scale`). */
1872
+ columns: readonly number[];
1873
+ rows: readonly {
1874
+ minHeight?: number;
1875
+ }[];
1876
+ /** Row-major `cells[row][column]`. */
1877
+ cells: readonly (readonly StoredTableCell[])[];
1878
+ headerRows: number;
1879
+ cellMargin: number;
1880
+ borders: "all" | "outer" | "rows" | "none";
1881
+ styleId?: string;
1882
+ styleOverride?: TextStyleOverride;
1883
+ }>;
1122
1884
  /** Any object as stored in the document — what reads hand to scripts. */
1123
- type StoredObject = StoredLine | StoredPoint | StoredPolyline | StoredCircle | StoredArc | StoredEllipse | StoredHatch | StoredText | StoredDimension | StoredBlock | StoredViewport | StoredImage;
1885
+ type StoredObject = StoredLine | StoredPoint | StoredPolyline | StoredCircle | StoredArc | StoredEllipse | StoredHatch | StoredText | StoredDimension | StoredBlock | StoredViewport | StoredImage | StoredComment | StoredTable | StoredReference;
1124
1886
  /**
1125
1887
  * One choice of a "Select" parameter: the value (what scripts receive) with
1126
1888
  * an optional properties-panel label. A plain string is shorthand for
@@ -1129,44 +1891,152 @@ type StoredObject = StoredLine | StoredPoint | StoredPolyline | StoredCircle | S
1129
1891
  type ParameterOption = string | {
1130
1892
  value: string;
1131
1893
  label?: string;
1894
+ /** A `#rrggbb` color square before the option's label. */
1895
+ swatch?: string;
1132
1896
  };
1133
1897
  /**
1134
1898
  * One entry of the module's optional `params` export — the block's
1135
1899
  * parameters table. `name` is the key scripts read from `params`, `label`
1136
1900
  * the properties-panel caption (defaults to the name).
1137
1901
  */
1138
- type ParamDef = {
1902
+ /** What every params-table entry may carry: its key, panel caption and
1903
+ * tooltip. */
1904
+ type ParamBase = {
1905
+ /** The key scripts read from `params`. */
1139
1906
  name: string;
1907
+ /** The properties-panel caption (defaults to the name). */
1140
1908
  label?: string;
1909
+ /** What the parameter means: the label's tooltip in the panel. */
1910
+ hint?: string;
1911
+ };
1912
+ type ParamDef = (ParamBase & {
1141
1913
  type: "number";
1142
1914
  default: number;
1143
1915
  min?: number;
1144
1916
  max?: number;
1145
- } | {
1146
- name: string;
1147
- label?: string;
1917
+ /** Whole numbers only. */
1918
+ integer?: boolean;
1919
+ /** ArrowUp / ArrowDown increment in the panel (default 1). */
1920
+ step?: number;
1921
+ /** Shown inside the field before / after the value ("1:", "mm"). */
1922
+ prefix?: string;
1923
+ suffix?: string;
1924
+ /** Standard values offered in the field's dropdown; typing stays free. */
1925
+ presets?: readonly number[];
1926
+ }) | (ParamBase & {
1148
1927
  type: "string";
1149
1928
  default: string;
1150
- } | {
1151
- name: string;
1152
- label?: string;
1929
+ placeholder?: string;
1930
+ /** A textarea; Shift+Enter starts a new line. */
1931
+ multiline?: boolean;
1932
+ presets?: readonly string[];
1933
+ }) | (ParamBase & {
1153
1934
  type: "boolean";
1154
1935
  default: boolean;
1155
- } | {
1156
- name: string;
1157
- label?: string;
1936
+ /** "toggle": a toggle button showing the label (compact, e.g. in a
1937
+ * row beside a picker) instead of a switch. */
1938
+ display?: "switch" | "toggle";
1939
+ })
1940
+ /** A list of numbers, edited as space-separated text with Tekla-style
1941
+ * `N*d` repeats ("0 2*7200" → [0, 7200, 7200]). */
1942
+ | (ParamBase & {
1943
+ type: "numberList";
1944
+ default: readonly number[];
1945
+ /** Shown while the list is empty. */
1946
+ placeholder?: string;
1947
+ min?: number;
1948
+ max?: number;
1949
+ presets?: readonly (readonly number[])[];
1950
+ })
1951
+ /** A list of strings, edited as space-separated words; double quotes group
1952
+ * a phrase ('A "B 2"' → ["A", "B 2"]). */
1953
+ | (ParamBase & {
1954
+ type: "stringList";
1955
+ default: readonly string[];
1956
+ /** Shown while the list is empty. */
1957
+ placeholder?: string;
1958
+ presets?: readonly (readonly string[])[];
1959
+ })
1960
+ /** A `#rrggbb` color: a swatch with a picker; presets form a palette. */
1961
+ | (ParamBase & {
1962
+ type: "color";
1963
+ default: string;
1964
+ presets?: readonly string[];
1965
+ }) | (ParamBase & {
1158
1966
  type: "enum";
1159
1967
  default: string;
1160
1968
  options: readonly ParameterOption[];
1161
- }
1969
+ /** "buttons": a segmented toggle group of the options (short
1970
+ * choices); falls back to the dropdown when they don't fit. */
1971
+ display?: "dropdown" | "buttons";
1972
+ })
1973
+ /** Pickers over the document's resources; the value is an id / name.
1974
+ * textStyle / dimStyle: a style id ("" or unknown = the document's first
1975
+ * style — read it in draw with `styles.text(id)` / `styles.dim(id)`, or
1976
+ * hand it to children as `styleId`). font: a font id ("arial"…).
1977
+ * lineType / hatchPattern: a linetype / pattern name. */
1978
+ | (ParamBase & {
1979
+ type: "textStyle" | "dimStyle" | "font" | "lineType" | "hatchPattern";
1980
+ default?: string;
1981
+ })
1162
1982
  /** A section label between rows in the properties panel. Carries no
1163
1983
  * value: it never appears in the `params` record `draw` receives.
1164
1984
  * `name` stays the unique key (paramVisibility can hide it by name). */
1165
- | {
1166
- name: string;
1167
- label?: string;
1985
+ | (ParamBase & {
1168
1986
  type: "label";
1987
+ })
1988
+ /** Layout only: 2–3 compact params on one panel row, each item's label a
1989
+ * short prefix ("W", "H"). Values stay flat — `params.w`, `params.h`. */
1990
+ | (ParamBase & {
1991
+ type: "row";
1992
+ items: readonly RowItemDef[];
1993
+ });
1994
+ /** A document text style as `draw` reads it (`styles.text(id)`). Heights
1995
+ * and arrow sizes are mm before an object's `scale`. */
1996
+ type TextStyleInfo = {
1997
+ readonly id: string;
1998
+ readonly name: string;
1999
+ readonly font: string;
2000
+ readonly widthFactor: number;
2001
+ readonly bold?: boolean;
2002
+ readonly italic?: boolean;
2003
+ readonly textHeight: number;
2004
+ readonly arrowType: "filled" | "open" | "tick" | "dot" | "none";
2005
+ readonly arrowSize: number;
2006
+ };
2007
+ /** A document dimension style as `draw` reads it (`styles.dim(id)`). */
2008
+ type DimStyleInfo = {
2009
+ readonly id: string;
2010
+ readonly name: string;
2011
+ readonly font: string;
2012
+ readonly widthFactor: number;
2013
+ readonly bold?: boolean;
2014
+ readonly italic?: boolean;
2015
+ readonly textHeight: number;
2016
+ readonly textOffset: number;
2017
+ readonly arrowType: "filled" | "open" | "tick" | "dot" | "none";
2018
+ readonly arrowSize: number;
2019
+ readonly extensionType: "long" | "short";
2020
+ readonly extensionOffset: number;
2021
+ readonly extensionOvershoot: number;
2022
+ readonly precision: number;
1169
2023
  };
2024
+ /** `draw`'s `styles`: the document's styles by id. An empty or unknown id
2025
+ * (a deleted style, a block from another drawing) gives the document's
2026
+ * first style — the same rule a child's `styleId` follows. */
2027
+ interface BlockStyles {
2028
+ text(id?: string): TextStyleInfo;
2029
+ dim(id?: string): DimStyleInfo;
2030
+ }
2031
+ /** What a `row` may hold: the compact, single-line param kinds. */
2032
+ type RowItemDef = Extract<ParamDef, {
2033
+ type: "number" | "string" | "boolean" | "enum" | "color" | "textStyle" | "dimStyle" | "font" | "lineType" | "hatchPattern";
2034
+ }>;
2035
+ /** A table entry's value-carrying params: a row's items, else itself. */
2036
+ type FlatParam<Q> = Q extends {
2037
+ type: "row";
2038
+ items: readonly (infer I)[];
2039
+ } ? I : Q;
1170
2040
  /**
1171
2041
  * The block's parameters table — what the `params` member of a BlockSpec
1172
2042
  * declares (or its function form returns).
@@ -1185,7 +2055,11 @@ type ParamValue<Q extends ParamDef> = Q extends {
1185
2055
  type: "number";
1186
2056
  } ? number : Q extends {
1187
2057
  type: "boolean";
1188
- } ? boolean : string;
2058
+ } ? boolean : Q extends {
2059
+ type: "numberList";
2060
+ } ? readonly number[] : Q extends {
2061
+ type: "stringList";
2062
+ } ? readonly string[] : string;
1189
2063
  /**
1190
2064
  * The values record a params table produces: each entry's `name` maps to
1191
2065
  * its runtime value type (number/string/boolean, or the enum's option
@@ -1196,10 +2070,469 @@ type ParamValue<Q extends ParamDef> = Q extends {
1196
2070
  * passes through unchanged.
1197
2071
  */
1198
2072
  type ParamValues<P> = P extends () => infer R ? ParamValues<R> : P extends readonly (infer Q extends ParamDef)[] ? {
1199
- readonly [E in Q as E extends {
2073
+ readonly [E in FlatParam<Q> as E extends {
1200
2074
  type: "label";
1201
- } ? never : E["name"]]: ParamValue<E>;
2075
+ } ? never : E extends {
2076
+ name: infer N extends string;
2077
+ } ? N : never]: E extends ParamDef ? ParamValue<E> : never;
1202
2078
  } : P;
2079
+ /** An axis-aligned box in world mm. */
2080
+ type Box = {
2081
+ minX: number;
2082
+ minY: number;
2083
+ maxX: number;
2084
+ maxY: number;
2085
+ };
2086
+ /** Filters for Drawing.query — all present filters AND together. */
2087
+ type ObjectQuery = {
2088
+ ids?: readonly string[];
2089
+ type?: ModelObject["type"];
2090
+ /** Layer name or id. */
2091
+ layer?: string;
2092
+ /** #rrggbb override (objects without one inherit from their layer). */
2093
+ color?: string;
2094
+ lineType?: string;
2095
+ /** Substring match on text content. */
2096
+ content?: string;
2097
+ /** Bounds intersect this box. */
2098
+ bbox?: Box;
2099
+ /** Bounds entirely inside this box. */
2100
+ inside?: Box;
2101
+ /** Geometry within `tol` mm of `point`. */
2102
+ near?: {
2103
+ point: Vec2Like;
2104
+ tol: number;
2105
+ };
2106
+ /** Search this paper layout's sheet objects (name or id) instead of
2107
+ * model space. */
2108
+ layout?: string;
2109
+ };
2110
+ /** A STORED object as query() returns it (see StoredObject — schema
2111
+ * output: defaults applied, points always {x, y}, identity present). */
2112
+ type ExistingObject = StoredObject;
2113
+ /** Per-object measurements; null where the type has no natural value. */
2114
+ type Measurement = {
2115
+ bbox: Box | null;
2116
+ length: number | null;
2117
+ area: number | null;
2118
+ };
2119
+ /** A layer as stored (defaults applied) plus the current-layer flag. */
2120
+ type LayerInfo = {
2121
+ id: string;
2122
+ name: string;
2123
+ color: string;
2124
+ lineType: string;
2125
+ lineWidth: number;
2126
+ opacity: number;
2127
+ visible: boolean;
2128
+ locked: boolean;
2129
+ current: boolean;
2130
+ [key: string]: unknown;
2131
+ };
2132
+ /** A paper layout as stored: sheet metadata + its sheet-space objects. */
2133
+ type LayoutInfo = {
2134
+ id: string;
2135
+ name: string;
2136
+ sheet: {
2137
+ width: number;
2138
+ height: number;
2139
+ };
2140
+ printPalette: "color" | "grayscale" | "monochrome";
2141
+ objects: readonly StoredObject[];
2142
+ };
2143
+ /** A block module's identity/metadata (from its exports). */
2144
+ type BlockInfo = {
2145
+ id: string;
2146
+ name: string;
2147
+ description?: string;
2148
+ version?: string;
2149
+ authors?: readonly string[];
2150
+ tags?: readonly string[];
2151
+ dependencies?: readonly string[];
2152
+ };
2153
+ /** A command module's identity/metadata (from its exports). */
2154
+ type CommandInfo = {
2155
+ id: string;
2156
+ name: string;
2157
+ description?: string;
2158
+ version?: string;
2159
+ authors?: readonly string[];
2160
+ tags?: readonly string[];
2161
+ /** Declared point inputs (labels), picked or supplied before `run`. */
2162
+ inputs?: readonly string[];
2163
+ /** Declared parameters (same table as a block's), prompted or supplied
2164
+ * before `run`. */
2165
+ params?: readonly ParamDef[];
2166
+ };
2167
+ /** What installing module sources reports. */
2168
+ type MergeReport = {
2169
+ /** The full library after the merge. */
2170
+ merged: readonly string[];
2171
+ added: readonly {
2172
+ script: string;
2173
+ meta: {
2174
+ id: string;
2175
+ name: string;
2176
+ };
2177
+ }[];
2178
+ replaced: readonly {
2179
+ script: string;
2180
+ meta: {
2181
+ id: string;
2182
+ name: string;
2183
+ };
2184
+ }[];
2185
+ skipped: number;
2186
+ rejected: readonly {
2187
+ script: string;
2188
+ error: string;
2189
+ }[];
2190
+ };
2191
+ /** A sheet: a bare preset (orientation from context — landscape for a new
2192
+ * layout, the current one when patching), a preset with its orientation, or
2193
+ * explicit millimetres. */
2194
+ type SheetSpec = "A4" | "A3" | "A2" | "A1" | "A0" | {
2195
+ name: "A4" | "A3" | "A2" | "A1" | "A0";
2196
+ orientation: "portrait" | "landscape";
2197
+ } | {
2198
+ width: number;
2199
+ height: number;
2200
+ };
2201
+ /** What an import added (`objectIds` = the new objects). */
2202
+ interface ImportReport {
2203
+ objects: number;
2204
+ objectIds: string[];
2205
+ }
2206
+ /** Options for Drawing.addLayout. */
2207
+ type LayoutSpec = {
2208
+ /** Default: A3 landscape. */
2209
+ sheet?: SheetSpec;
2210
+ /** Viewport scale — `"1:50"` or the denominator; default: fitted. */
2211
+ scale?: number | string;
2212
+ /** One fitted model viewport (default), or `false` for a bare sheet. */
2213
+ viewport?: {
2214
+ rect?: {
2215
+ x: number;
2216
+ y: number;
2217
+ w: number;
2218
+ h: number;
2219
+ };
2220
+ scale?: number | string;
2221
+ center?: Vec2Like;
2222
+ } | false;
2223
+ /** Tab position; default: append. */
2224
+ index?: number;
2225
+ };
2226
+ /** The whole document as stored (defaults applied). */
2227
+ type StoredDocument = {
2228
+ id: string;
2229
+ version: number;
2230
+ layers: readonly Omit<LayerInfo, "current">[];
2231
+ currentLayerId: string;
2232
+ objects: readonly StoredObject[];
2233
+ layouts: readonly LayoutInfo[];
2234
+ /** Raw block module sources. */
2235
+ blockDefinitions: readonly string[];
2236
+ /** Raw command module sources. */
2237
+ commands: readonly string[];
2238
+ [key: string]: unknown;
2239
+ };
2240
+ /** Where a draw-order move puts the objects. */
2241
+ type ReorderPlacement = "front" | "back" | {
2242
+ above: string;
2243
+ } | {
2244
+ below: string;
2245
+ };
2246
+ /**
2247
+ * The document as command scripts see it — the SAME `Drawing` interface
2248
+ * the agent tools and the SDK use. Angles are RADIANS, point-valued
2249
+ * arguments accept {x, y} or [x, y], `layer` resolves by name or id.
2250
+ * Object mutations on an editor-attached drawing target the ACTIVE space.
2251
+ * Methods throw on invalid input (an uncaught throw cancels the command
2252
+ * and rolls its edits back). Reads return detached snapshots.
2253
+ */
2254
+ interface Drawing {
2255
+ /** The document's own id. */
2256
+ readonly id: string;
2257
+ /** Monotonic change counter. */
2258
+ readonly revision: number;
2259
+ /** The full document — a detached snapshot. */
2260
+ readonly document: StoredDocument;
2261
+ /** Counts by type/layer, bbox, layer + layout names. */
2262
+ summary(): {
2263
+ name: string;
2264
+ objectCount: number;
2265
+ byType: Record<string, number>;
2266
+ byLayer: Record<string, number>;
2267
+ bbox: Box | null;
2268
+ layers: string[];
2269
+ layouts: {
2270
+ name: string;
2271
+ objectCount: number;
2272
+ }[];
2273
+ };
2274
+ /** Filtered objects — model space, or one layout via `filter.layout`. */
2275
+ listObjects(filter?: ObjectQuery): ExistingObject[];
2276
+ /** One object from ANY space, or undefined. */
2277
+ getObject(id: string): ExistingObject | undefined;
2278
+ /** bbox / curve length / enclosed area of one object. */
2279
+ measure(id: string): Measurement;
2280
+ listLayers(): LayerInfo[];
2281
+ listLayouts(): LayoutInfo[];
2282
+ /** Compilable block definitions in this document. */
2283
+ listBlockDefinitions(): BlockInfo[];
2284
+ /** Compilable command modules travelling with this document. */
2285
+ listUserCommands(): CommandInfo[];
2286
+ /** Model space (or a layout via `layout`) as an SVG string. */
2287
+ renderSvg(opts?: {
2288
+ layout?: string;
2289
+ bbox?: Box;
2290
+ padding?: number;
2291
+ palette?: "color" | "grayscale" | "monochrome";
2292
+ }): string;
2293
+ /** Model space (or a layout) as PNG bytes — absent on hosts that can't
2294
+ * rasterize, so check before calling. */
2295
+ renderPng?(opts?: {
2296
+ layout?: string;
2297
+ bbox?: Box;
2298
+ padding?: number;
2299
+ palette?: "color" | "grayscale" | "monochrome";
2300
+ /** Output width in px (height follows). Default 1024. */
2301
+ width?: number;
2302
+ /** Background fill, e.g. "#ffffff". Default: the dark canvas. */
2303
+ background?: string;
2304
+ }): Promise<Uint8Array>;
2305
+ /** Multi-page PDF of the layouts (default: all) — absent on hosts
2306
+ * without fonts, so check before calling. */
2307
+ renderPdf?(opts?: {
2308
+ layouts?: readonly string[];
2309
+ palette?: "color" | "grayscale" | "monochrome";
2310
+ }): Promise<Uint8Array>;
2311
+ /** The whole document as DXF text. */
2312
+ toDxf(): Promise<string>;
2313
+ /** DWG bytes (default AC1027 — AutoCAD 2013). */
2314
+ toDwg(opts?: {
2315
+ version?: string;
2316
+ }): Promise<Uint8Array>;
2317
+ /** The `.linea` file text. */
2318
+ toLinea(): string;
2319
+ /** Add objects (each may carry `layer` — a name — instead of an id);
2320
+ * returns the created ids. */
2321
+ add(objects: readonly (ModelObject & {
2322
+ layer?: string;
2323
+ })[], opts?: {
2324
+ layout?: string;
2325
+ }): string[];
2326
+ /** Apply per-object patches (`{ id, ...changedFields }`). */
2327
+ update(entries: readonly ({
2328
+ id: string;
2329
+ } & Record<string, unknown>)[]): void;
2330
+ /** Delete by id (unknown ids are skipped); returns how many went. */
2331
+ remove(ids: readonly string[]): number;
2332
+ /** Draw order: move the objects (bottom → top) to a placement. */
2333
+ reorder(ids: readonly string[], placement: ReorderPlacement): void;
2334
+ move(ids: readonly string[], delta: Vec2Like): void;
2335
+ rotate(ids: readonly string[], angleRad: number, center?: Vec2Like): void;
2336
+ scale(ids: readonly string[], factor: number, center?: Vec2Like): void;
2337
+ mirror(ids: readonly string[], axisA: Vec2Like, axisB: Vec2Like): void;
2338
+ /** Duplicate displaced by delta; returns the new ids. */
2339
+ copy(ids: readonly string[], delta: Vec2Like): string[];
2340
+ /** count TOTAL copies at multiples of delta; returns the new ids. */
2341
+ array(ids: readonly string[], count: number, delta: Vec2Like): string[];
2342
+ /** Create a paper layout; returns its id. */
2343
+ addLayout(name: string, opts?: LayoutSpec): string;
2344
+ /** Patch a layout's name / sheet / print palette. A bare preset keeps the
2345
+ * layout's current orientation. */
2346
+ updateLayout(nameOrId: string, patch: {
2347
+ name?: string;
2348
+ sheet?: SheetSpec;
2349
+ printPalette?: "color" | "grayscale" | "monochrome";
2350
+ }): void;
2351
+ removeLayout(nameOrId: string): void;
2352
+ /** Explicit total order (names or ids) — the PDF page order. */
2353
+ reorderLayouts(order: readonly string[]): void;
2354
+ /** Create a layer (unique name); returns its id. */
2355
+ addLayer(props: {
2356
+ name: string;
2357
+ color?: string;
2358
+ } & Record<string, unknown>): string;
2359
+ updateLayer(nameOrId: string, patch: Record<string, unknown>): void;
2360
+ /** Remove an EMPTY, non-current layer. */
2361
+ removeLayer(nameOrId: string): void;
2362
+ /** Explicit total order (names or ids, every layer exactly once). */
2363
+ reorderLayers(order: readonly string[]): void;
2364
+ setCurrentLayer(nameOrId: string): void;
2365
+ listTextStyles(): ({
2366
+ id: string;
2367
+ name: string;
2368
+ } & Record<string, unknown>)[];
2369
+ listDimStyles(): ({
2370
+ id: string;
2371
+ name: string;
2372
+ } & Record<string, unknown>)[];
2373
+ /** Create a style (unique name; unset fields take the defaults); returns
2374
+ * its id. Styles are addressed by name or id. */
2375
+ addTextStyle(props: {
2376
+ name: string;
2377
+ } & Record<string, unknown>): string;
2378
+ updateTextStyle(nameOrId: string, patch: Record<string, unknown>): void;
2379
+ /** Remove a style no object uses (refused otherwise). */
2380
+ removeTextStyle(nameOrId: string): void;
2381
+ addDimStyle(props: {
2382
+ name: string;
2383
+ } & Record<string, unknown>): string;
2384
+ updateDimStyle(nameOrId: string, patch: Record<string, unknown>): void;
2385
+ removeDimStyle(nameOrId: string): void;
2386
+ /** @deprecated Use updateDimStyle (default here: the first style). */
2387
+ setDimStyle(patch: Record<string, unknown>, styleId?: string): void;
2388
+ /** @deprecated Use updateTextStyle (default here: the first style). */
2389
+ setTextStyle(patch: Record<string, unknown>, styleId?: string): void;
2390
+ /** Embed image pixels (a data URL); returns the content-keyed assetId
2391
+ * that `image` objects reference. */
2392
+ addAsset(dataUrl: string): string;
2393
+ /** Remove an asset (refused while an image references it). */
2394
+ removeAsset(id: string): void;
2395
+ /** Embedded image assets and how many images use each. */
2396
+ listAssets(): {
2397
+ id: string;
2398
+ mimeType: string;
2399
+ bytes: number;
2400
+ users: number;
2401
+ }[];
2402
+ /** Merge DXF text (new layers, objects, layouts); `unitOverride` = mm
2403
+ * per drawing unit. */
2404
+ importDxfText(text: string, opts?: {
2405
+ unitOverride?: number;
2406
+ }): ImportReport & {
2407
+ layers: number;
2408
+ layouts: number;
2409
+ layoutIds: string[];
2410
+ };
2411
+ /** Merge DWG bytes (transcoded to DXF). */
2412
+ importDwgData(data: Uint8Array, opts?: {
2413
+ unitOverride?: number;
2414
+ }): Promise<ImportReport & {
2415
+ layers: number;
2416
+ layouts: number;
2417
+ layoutIds: string[];
2418
+ }>;
2419
+ /** Merge a PDF: vectors/text onto the current layer, or (`as: "image"`,
2420
+ * not available on every host) each page as an image at true scale. */
2421
+ importPdfData(data: ArrayBuffer | Uint8Array, opts?: {
2422
+ as?: "vectors" | "image";
2423
+ origin?: Vec2Like;
2424
+ }): Promise<ImportReport & {
2425
+ pageCount: number;
2426
+ }>;
2427
+ /** Merge block module sources into the document library. */
2428
+ addBlockDefinitions(sources: readonly string[]): Promise<MergeReport>;
2429
+ removeBlockDefinition(id: string): void;
2430
+ addUserCommands(sources: readonly string[]): Promise<MergeReport>;
2431
+ removeUserCommand(id: string): void;
2432
+ /** Escape hatch: apply an already-shaped kernel op batch (validated,
2433
+ * atomic, one undo step). */
2434
+ applyOps(ops: readonly Record<string, unknown>[]): void;
2435
+ /**
2436
+ * Group edits into ONE undo step (a command run already is one; nested
2437
+ * calls join it). A throw rolls back what the transaction applied.
2438
+ */
2439
+ transaction<T>(fn: () => T, label?: string): T;
2440
+ /** Not available while a command runs (throws) — return or throw. */
2441
+ undo(): boolean;
2442
+ redo(): boolean;
2443
+ }
2444
+ /** The editor's state as a script sees it. */
2445
+ type EditorState = {
2446
+ documentId: string;
2447
+ documentName: string;
2448
+ space: "model" | {
2449
+ layout: string;
2450
+ };
2451
+ selectedIds: string[];
2452
+ readOnly: boolean;
2453
+ canUndo: boolean;
2454
+ canRedo: boolean;
2455
+ };
2456
+ /** One runnable editor command (registry entry, macro, or insert-block). */
2457
+ type EditorCommandInfo = {
2458
+ id: string;
2459
+ label: string;
2460
+ group: string;
2461
+ hotkey?: string;
2462
+ };
2463
+ /**
2464
+ * The interactive half of the context — present only when the command runs
2465
+ * inside a live editor (absent when a script runs headlessly, e.g. from the
2466
+ * CLI or the MCP server; branch on it). The pickers and `prompt` REJECT
2467
+ * when the user cancels (Escape) — let that propagate to abort the command
2468
+ * (all edits roll back), or catch it to finish an open-ended collection.
2469
+ */
2470
+ interface EditorSurface {
2471
+ state(): EditorState;
2472
+ setActiveSpace(space: "model" | {
2473
+ layout: string;
2474
+ }): void;
2475
+ setSelection(ids: readonly string[]): void;
2476
+ /** "fit" (everything in the active space), "selection", some objects'
2477
+ * extents (`{ ids }`), or a window (`{ bbox }`, world mm; sheet mm in a
2478
+ * layout). */
2479
+ zoom(to: "fit" | "selection" | {
2480
+ ids: readonly string[];
2481
+ } | {
2482
+ bbox: Box;
2483
+ }): void;
2484
+ /** Await one snapped world point; `referencePoint` enables rubber-band
2485
+ * + relative typed entry from there. */
2486
+ pickPoint(opts?: {
2487
+ label?: string;
2488
+ referencePoint?: Vec2Like;
2489
+ }): Promise<Vec2>;
2490
+ /** Await one object click; resolves the object's id. */
2491
+ pickObject(opts?: {
2492
+ label?: string;
2493
+ }): Promise<string>;
2494
+ /** Await a typed value from a small input dialog. */
2495
+ prompt(message: string, opts?: {
2496
+ initial?: string;
2497
+ placeholder?: string;
2498
+ }): Promise<string>;
2499
+ toast(message: string, kind?: "info" | "success" | "error"): void;
2500
+ /** Registry commands + macros + insert-block entries. */
2501
+ listCommands(): EditorCommandInfo[];
2502
+ /** Trigger a command by id — like the user pressing its hotkey. A macro
2503
+ * takes its declared `inputs` / `params` up front (params passed skip its
2504
+ * params dialog). */
2505
+ runCommand(id: string, inputs?: readonly Vec2Like[], params?: Readonly<Record<string, unknown>>): Promise<void>;
2506
+ }
2507
+ /**
2508
+ * What `run` receives. `document` is the Drawing; `editor` the interactive
2509
+ * surface when there is one; `inputs` the points the command's declared
2510
+ * `inputs` labels produced (picked in the editor, or supplied by the
2511
+ * caller), in label order; `params` the values of the declared `params`
2512
+ * table (asked for in a dialog in the editor, or passed by the caller;
2513
+ * omitted ones take their defaults).
2514
+ */
2515
+ interface CommandContext<P = Readonly<Record<string, unknown>>> {
2516
+ document: Drawing;
2517
+ editor?: EditorSurface;
2518
+ inputs: readonly Vec2[];
2519
+ params: P;
2520
+ /** @deprecated Use `editor.pickPoint({ label })` (throws without an editor). */
2521
+ pickPoint(label?: string): Promise<Vec2>;
2522
+ /** @deprecated Use `editor.pickObject({ label })`. */
2523
+ pickObject(label?: string): Promise<string>;
2524
+ /** @deprecated Use `editor.state().selectedIds`. */
2525
+ selection(): string[];
2526
+ /** @deprecated Use `editor.setSelection(ids)`. */
2527
+ setSelection(ids: readonly string[]): void;
2528
+ /** @deprecated Use `editor.prompt(message, options)`. */
2529
+ prompt(message: string, options?: {
2530
+ initial?: string;
2531
+ placeholder?: string;
2532
+ }): Promise<string>;
2533
+ /** @deprecated Use `editor.toast(message, kind)`. */
2534
+ showToast(message: string, kind?: "info" | "success" | "error"): void;
2535
+ }
1203
2536
 
1204
2537
  // Script-contract globals: aliases into the module (not re-declarations),
1205
2538
  // so the in-app editor's BlockParams substitution flows through them.
@@ -1215,10 +2548,6 @@ declare type BlockSpec<
1215
2548
  P extends import("lineadraw").BlockParamDefs = readonly [],
1216
2549
  Pl extends PlaceSpec<P> | undefined = undefined,
1217
2550
  > = import("lineadraw").BlockSpec<P, Pl>;
1218
- declare type Box = import("lineadraw").Box;
1219
- declare type ObjectQuery = import("lineadraw").ObjectQuery;
1220
- declare type ExistingObject = import("lineadraw").ExistingObject;
1221
- declare type Measurement = import("lineadraw").Measurement;
1222
- declare type CommandDocument = import("lineadraw").CommandDocument;
1223
- declare type CommandContext = import("lineadraw").CommandContext;
1224
- declare type CommandSpec = import("lineadraw").CommandSpec;
2551
+ declare type CommandSpec<
2552
+ P extends import("lineadraw").BlockParamDefs = readonly [],
2553
+ > = import("lineadraw").CommandSpec<P>;