lineadraw 0.5.0 → 0.6.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;
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;
368
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,392 @@ 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
+ /** Options for Drawing.createLayout. */
776
+ export type LayoutSpec = {
777
+ /** Default: A3 landscape. */
778
+ sheet?: SheetSpec;
779
+ /** Viewport scale — `"1:50"` or the denominator; default: fitted. */
780
+ scale?: number | string;
781
+ /** One fitted model viewport (default), or `false` for a bare sheet. */
782
+ viewport?: {
783
+ rect?: {
784
+ x: number;
785
+ y: number;
786
+ w: number;
787
+ h: number;
788
+ };
789
+ scale?: number | string;
790
+ center?: Vec2Like;
791
+ } | false;
792
+ /** Tab position; default: append. */
793
+ index?: number;
794
+ };
795
+ /** The whole document as stored (defaults applied). */
796
+ export type StoredDocument = {
797
+ id: string;
798
+ version: number;
799
+ layers: readonly Omit<LayerInfo, "current">[];
800
+ currentLayerId: string;
801
+ objects: readonly StoredObject[];
802
+ layouts: readonly LayoutInfo[];
803
+ /** Raw block module sources. */
804
+ blockDefinitions: readonly string[];
805
+ /** Raw command module sources. */
806
+ commands: readonly string[];
807
+ [key: string]: unknown;
808
+ };
809
+ /** Where a draw-order move puts the objects. */
810
+ export type ReorderPlacement = "front" | "back" | {
811
+ above: string;
812
+ } | {
813
+ below: string;
814
+ };
815
+ /**
816
+ * The document as command scripts see it — the SAME `Drawing` interface
817
+ * the agent tools and the SDK use. Angles are RADIANS, point-valued
818
+ * arguments accept {x, y} or [x, y], `layer` resolves by name or id.
819
+ * Object mutations on an editor-attached drawing target the ACTIVE space.
820
+ * Methods throw on invalid input (an uncaught throw cancels the command
821
+ * and rolls its edits back). Reads return detached snapshots.
822
+ */
823
+ export interface Drawing {
824
+ /** The document's own id. */
825
+ readonly id: string;
826
+ /** Monotonic change counter. */
827
+ readonly revision: number;
828
+ /** The full document — a detached snapshot. */
829
+ readonly document: StoredDocument;
830
+ /** Counts by type/layer, bbox, layer + layout names. */
831
+ summary(): {
832
+ name: string;
833
+ objectCount: number;
834
+ byType: Record<string, number>;
835
+ byLayer: Record<string, number>;
836
+ bbox: Box | null;
837
+ layers: string[];
838
+ layouts: {
839
+ name: string;
840
+ objectCount: number;
841
+ }[];
842
+ };
843
+ /** Filtered objects — model space, or one layout via `filter.layout`. */
844
+ query(filter?: ObjectQuery): ExistingObject[];
845
+ /** One object from ANY space, or undefined. */
846
+ getObject(id: string): ExistingObject | undefined;
847
+ /** bbox / curve length / enclosed area of one object. */
848
+ measure(id: string): Measurement;
849
+ listLayers(): LayerInfo[];
850
+ listLayouts(): LayoutInfo[];
851
+ /** Compilable block definitions in this document. */
852
+ listBlocks(): BlockInfo[];
853
+ /** Compilable command modules travelling with this document. */
854
+ listCommands(): CommandInfo[];
855
+ /** Model space (or a layout via `layout`) as an SVG string. */
856
+ renderSvg(opts?: {
857
+ layout?: string;
858
+ bbox?: Box;
859
+ padding?: number;
860
+ palette?: "color" | "grayscale" | "monochrome";
861
+ }): string;
862
+ /** Multi-page PDF of the layouts (default: all) — absent on hosts
863
+ * without fonts, so check before calling. */
864
+ renderPdf?(opts?: {
865
+ layouts?: readonly string[];
866
+ palette?: "color" | "grayscale" | "monochrome";
867
+ }): Promise<Uint8Array>;
868
+ /** The whole document as DXF text. */
869
+ toDxf(): Promise<string>;
870
+ /** DWG bytes (default AC1027 — AutoCAD 2013). */
871
+ toDwg(opts?: {
872
+ version?: string;
873
+ }): Promise<Uint8Array>;
874
+ /** The `.linea` file text. */
875
+ toJson(): string;
876
+ /** Add objects (each may carry `layer` — a name — instead of an id);
877
+ * returns the created ids. */
878
+ add(objects: readonly (ModelObject & {
879
+ layer?: string;
880
+ })[], opts?: {
881
+ layout?: string;
882
+ }): string[];
883
+ /** Apply per-object patches (`{ id, ...changedFields }`). */
884
+ update(entries: readonly ({
885
+ id: string;
886
+ } & Record<string, unknown>)[]): void;
887
+ /** Delete by id (unknown ids are skipped); returns how many went. */
888
+ remove(ids: readonly string[]): number;
889
+ /** Draw order: move the objects (bottom → top) to a placement. */
890
+ reorder(ids: readonly string[], placement: ReorderPlacement): void;
891
+ move(ids: readonly string[], delta: Vec2Like): void;
892
+ rotate(ids: readonly string[], angleRad: number, center?: Vec2Like): void;
893
+ scale(ids: readonly string[], factor: number, center?: Vec2Like): void;
894
+ mirror(ids: readonly string[], axisA: Vec2Like, axisB: Vec2Like): void;
895
+ /** Duplicate displaced by delta; returns the new ids. */
896
+ copy(ids: readonly string[], delta: Vec2Like): string[];
897
+ /** count TOTAL copies at multiples of delta; returns the new ids. */
898
+ array(ids: readonly string[], count: number, delta: Vec2Like): string[];
899
+ /** Create a paper layout; returns its id. */
900
+ createLayout(name: string, opts?: LayoutSpec): string;
901
+ /** Patch a layout's name / sheet / print palette. A bare preset keeps the
902
+ * layout's current orientation. */
903
+ updateLayout(nameOrId: string, patch: {
904
+ name?: string;
905
+ sheet?: SheetSpec;
906
+ printPalette?: "color" | "grayscale" | "monochrome";
907
+ }): void;
908
+ removeLayout(nameOrId: string): void;
909
+ /** Explicit total order (names or ids) — the PDF page order. */
910
+ reorderLayouts(order: readonly string[]): void;
911
+ /** Create a layer (unique name); returns its id. */
912
+ addLayer(props: {
913
+ name: string;
914
+ color?: string;
915
+ } & Record<string, unknown>): string;
916
+ updateLayer(nameOrId: string, patch: Record<string, unknown>): void;
917
+ /** Remove an EMPTY, non-current layer. */
918
+ removeLayer(nameOrId: string): void;
919
+ /** Explicit total order (names or ids, every layer exactly once). */
920
+ reorderLayers(order: readonly string[]): void;
921
+ setCurrentLayer(nameOrId: string): void;
922
+ /** Patch a document dimension style (default: the first). */
923
+ setDimStyle(patch: Record<string, unknown>, styleId?: string): void;
924
+ /** Patch a document text style (default: the first). */
925
+ setTextStyle(patch: Record<string, unknown>, styleId?: string): void;
926
+ /** Embed image pixels (a data URL); returns the content-keyed assetId
927
+ * that `image` objects reference. */
928
+ addAsset(dataUrl: string): string;
929
+ /** Remove an asset (refused while an image references it). */
930
+ removeAsset(id: string): void;
931
+ /** Merge block module sources into the document library. */
932
+ installBlocks(sources: readonly string[]): Promise<MergeReport>;
933
+ removeBlock(id: string): void;
934
+ installCommands(sources: readonly string[]): Promise<MergeReport>;
935
+ removeCommand(id: string): void;
936
+ /** Escape hatch: apply an already-shaped kernel op batch (validated,
937
+ * atomic, one undo step). */
938
+ applyOps(ops: readonly Record<string, unknown>[]): void;
939
+ /**
940
+ * Group edits into ONE undo step (a command run already is one; nested
941
+ * calls join it). A throw rolls back what the transaction applied.
942
+ */
943
+ transaction<T>(fn: () => T, label?: string): T;
944
+ /** Not available while a command runs (throws) — return or throw. */
945
+ undo(): boolean;
946
+ redo(): boolean;
947
+ }
948
+ /** The editor's state as a script sees it. */
949
+ export type EditorState = {
950
+ documentId: string;
951
+ documentName: string;
952
+ space: "model" | {
953
+ layout: string;
954
+ };
955
+ selectedIds: string[];
956
+ readOnly: boolean;
957
+ canUndo: boolean;
958
+ canRedo: boolean;
959
+ };
960
+ /** One runnable editor command (registry entry, macro, or insert-block). */
961
+ export type EditorCommandInfo = {
962
+ id: string;
963
+ label: string;
964
+ group: string;
965
+ hotkey?: string;
966
+ };
967
+ /**
968
+ * The interactive half of the context — present only when the command runs
969
+ * inside a live editor (absent when a script runs headlessly, e.g. from the
970
+ * CLI or the MCP server; branch on it). The pickers and `prompt` REJECT
971
+ * when the user cancels (Escape) — let that propagate to abort the command
972
+ * (all edits roll back), or catch it to finish an open-ended collection.
973
+ */
974
+ export interface EditorSurface {
975
+ state(): EditorState;
976
+ setActiveSpace(space: "model" | {
977
+ layout: string;
978
+ }): void;
979
+ setSelection(ids: readonly string[]): void;
980
+ zoom(to: "fit" | "selection"): void;
981
+ /** Await one snapped world point; `referencePoint` enables rubber-band
982
+ * + relative typed entry from there. */
983
+ pickPoint(opts?: {
984
+ label?: string;
985
+ referencePoint?: Vec2Like;
986
+ }): Promise<Vec2>;
987
+ /** Await one object click; resolves the object's id. */
988
+ pickObject(opts?: {
989
+ label?: string;
990
+ }): Promise<string>;
991
+ /** Await a typed value from a small input dialog. */
992
+ prompt(message: string, opts?: {
993
+ initial?: string;
994
+ placeholder?: string;
995
+ }): Promise<string>;
996
+ toast(message: string, kind?: "info" | "success" | "error"): void;
997
+ /** Registry commands + macros + insert-block entries. */
998
+ listCommands(): EditorCommandInfo[];
999
+ /** Trigger a command by id — like the user pressing its hotkey. A macro
1000
+ * takes its declared `inputs` / `params` up front (params passed skip its
1001
+ * params dialog). */
1002
+ runCommand(id: string, inputs?: readonly Vec2Like[], params?: Readonly<Record<string, unknown>>): Promise<void>;
1003
+ }
1004
+ /**
1005
+ * What `run` receives. `document` is the Drawing; `editor` the interactive
1006
+ * surface when there is one; `inputs` the points the command's declared
1007
+ * `inputs` labels produced (picked in the editor, or supplied by the
1008
+ * caller), in label order; `params` the values of the declared `params`
1009
+ * table (asked for in a dialog in the editor, or passed by the caller;
1010
+ * omitted ones take their defaults).
1011
+ */
1012
+ export interface CommandContext<P = Readonly<Record<string, unknown>>> {
1013
+ document: Drawing;
1014
+ editor?: EditorSurface;
1015
+ inputs: readonly Vec2[];
1016
+ params: P;
1017
+ /** @deprecated Use `editor.pickPoint({ label })` (throws without an editor). */
1018
+ pickPoint(label?: string): Promise<Vec2>;
1019
+ /** @deprecated Use `editor.pickObject({ label })`. */
1020
+ pickObject(label?: string): Promise<string>;
1021
+ /** @deprecated Use `editor.state().selectedIds`. */
1022
+ selection(): string[];
1023
+ /** @deprecated Use `editor.setSelection(ids)`. */
1024
+ setSelection(ids: readonly string[]): void;
1025
+ /** @deprecated Use `editor.prompt(message, options)`. */
1026
+ prompt(message: string, options?: {
1027
+ initial?: string;
1028
+ placeholder?: string;
1029
+ }): Promise<string>;
1030
+ /** @deprecated Use `editor.toast(message, kind)`. */
1031
+ showToast(message: string, kind?: "info" | "success" | "error"): void;
1032
+ }
402
1033
 
403
1034
  // ——— Script contract ———
404
1035
 
@@ -557,6 +1188,10 @@ declare module "lineadraw" {
557
1188
  draw: (props: {
558
1189
  params: ParamValues<P>;
559
1190
  inputs: PlaceInputs<Pl>;
1191
+ /** The document's text / dimension styles by id — for blocks that
1192
+ * lay out with real text sizes. Pass a picked id on to children as
1193
+ * `styleId` to let them follow the style. */
1194
+ styles: BlockStyles;
560
1195
  }) => BlockScriptResult;
561
1196
  }
562
1197
 
@@ -598,133 +1233,41 @@ declare module "lineadraw" {
598
1233
  ): BlockSpec<P, (props: PlaceProps<P>) => R>;
599
1234
 
600
1235
  // ——— 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
- }
1236
+ // Drawing / EditorSurface / CommandContext are emitted from scriptTypes.ts
1237
+ // above (the script-facing mirror of core's real interfaces).
713
1238
 
714
1239
  /** One user command (macro): identity, metadata, and the `run` body. */
715
- export interface CommandSpec {
1240
+ export interface CommandSpec<P extends BlockParamDefs = readonly []> {
716
1241
  id: string;
717
1242
  name: string;
718
1243
  description?: string;
719
1244
  version?: string;
720
1245
  authors?: readonly string[];
721
1246
  tags?: readonly string[];
1247
+ /**
1248
+ * Point inputs the command needs, as labels (`["Start", "End"]`). In
1249
+ * the editor each is picked in turn before `run` (rubber-band from the
1250
+ * previous pick); a headless or remote caller supplies them up front.
1251
+ * They arrive as `ctx.inputs`, in this order. This is what lets one
1252
+ * script run in the editor, from a shell, and from an agent alike.
1253
+ */
1254
+ inputs?: readonly string[];
1255
+ /**
1256
+ * Parameters the command needs — the same table a block's `params`
1257
+ * declares (number / string / boolean / enum / label rows), or a
1258
+ * zero-arg function returning it. In the editor a dialog asks for them
1259
+ * before `run` (prefilled with the defaults); a headless or remote
1260
+ * caller passes them by name (unknown names and wrong types are an
1261
+ * error). They arrive as `ctx.params`, typed from this table.
1262
+ */
1263
+ params?: P | (() => P);
722
1264
  /**
723
1265
  * The macro body. The whole call is ONE undo step: mutations apply
724
1266
  * live while it runs; cancelling (Escape during a pick/prompt) or an
725
- * uncaught error rolls everything back.
1267
+ * uncaught error rolls everything back. A return value is handed to
1268
+ * the caller (the agent tool / CLI) — the editor ignores it.
726
1269
  */
727
- run(ctx: CommandContext): void | Promise<void>;
1270
+ run(ctx: CommandContext<ParamValues<P>>): unknown;
728
1271
  }
729
1272
 
730
1273
  /**
@@ -736,18 +1279,23 @@ declare module "lineadraw" {
736
1279
  * export default defineCommand({
737
1280
  * id: "…",
738
1281
  * 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" });
1282
+ * inputs: ["Anchor"],
1283
+ * params: [{ name: "start", label: "First number", type: "number", default: 1 }],
1284
+ * run: ({ document, editor, inputs: [anchor], params: { start } }) => {
1285
+ * const texts = document.query({
1286
+ * type: "text",
1287
+ * near: { point: anchor, tol: 500 },
1288
+ * });
743
1289
  * texts.forEach((t, i) =>
744
1290
  * document.update([{ id: t.id, content: String(start + i) }]),
745
1291
  * );
746
- * showToast(`Numbered ${texts.length} texts`, "success");
1292
+ * editor?.toast(`Numbered ${texts.length} texts`, "success");
747
1293
  * },
748
1294
  * });
749
1295
  */
750
- export function defineCommand(spec: CommandSpec): CommandSpec;
1296
+ export function defineCommand<const P extends BlockParamDefs = readonly []>(
1297
+ spec: CommandSpec<P>,
1298
+ ): CommandSpec<P>;
751
1299
  }
752
1300
 
753
1301
  declare module "lineadraw/helpers" {
@@ -902,18 +1450,22 @@ type Text = Styled<{
902
1450
  position: Vec2Like;
903
1451
  content: string;
904
1452
  rotation?: number;
905
- /** Where the text SITS relative to the point. */
1453
+ /** Justification, as in AutoCAD / DXF: which edge sits on the point —
1454
+ * "left" = the text runs right of it, "right" = left of it; vAlign
1455
+ * "bottom" = the text sits above the point, "top" = below it. */
906
1456
  hAlign?: "left" | "center" | "right";
907
1457
  vAlign?: "bottom" | "center" | "top";
908
1458
  /** Word-wrap / frame width in mm (before `scale`); absent = no wrapping. */
909
1459
  width?: number;
910
- frame?: "none" | "rectangle" | "bottom";
1460
+ frame?: "none" | "rectangle" | "circle" | "slot" | "bottom" | "firstLine";
911
1461
  /** MLEADER-style arrow polylines pointing at the text (arrowhead at [0]). */
912
1462
  leaderLines?: readonly (readonly Vec2Like[])[];
913
1463
  /** Style overrides; absent keys inherit the document text style. */
914
1464
  styleOverride?: {
915
1465
  font?: string;
916
1466
  widthFactor?: number;
1467
+ bold?: boolean;
1468
+ italic?: boolean;
917
1469
  /** Cap height in mm (before `scale`). */
918
1470
  textHeight?: number;
919
1471
  arrowSize?: number;
@@ -953,11 +1505,48 @@ type Block = Styled<{
953
1505
  /** Applied last, about the pivot (the first input point). */
954
1506
  rotation?: number;
955
1507
  scale?: number;
956
- params?: Record<string, number | string | boolean>;
1508
+ params?: Record<string, number | string | boolean | readonly number[] | readonly string[]>;
957
1509
  /** Input points in the PARENT's local coords; the first is the pivot. */
958
1510
  inputs?: readonly Vec2Like[];
959
1511
  }>;
960
- type ModelObject = Line | Point | Polyline | Circle | Arc | Ellipse | Hatch | Text | Dimension | Block;
1512
+ /** A table cell: plain text, or text with merge / alignment / style. */
1513
+ type TableCell = string | {
1514
+ text?: string;
1515
+ /** Merge from this (top-left) cell; covered cells are ignored. */
1516
+ span?: {
1517
+ cols: number;
1518
+ rows: number;
1519
+ };
1520
+ hAlign?: "left" | "center" | "right";
1521
+ vAlign?: "top" | "center" | "bottom";
1522
+ styleId?: string;
1523
+ styleOverride?: TextStyleOverride;
1524
+ color?: string;
1525
+ };
1526
+ /** Grid of text cells hanging right/down from `position` (top-left);
1527
+ * rows grow to fit their wrapped text. */
1528
+ type Table = Styled<{
1529
+ type: "table";
1530
+ position: Vec2Like;
1531
+ /** Column widths (mm, before `scale`). */
1532
+ columns: readonly number[];
1533
+ /** Row count, or per-row settings (`minHeight` mm floor). */
1534
+ rows: number | readonly {
1535
+ minHeight?: number;
1536
+ }[];
1537
+ /** Row-major `cells[row][column]`, exactly rows × columns. */
1538
+ cells: readonly (readonly TableCell[])[];
1539
+ rotation?: number;
1540
+ scale?: number;
1541
+ /** Rows above the heavier header rule. */
1542
+ headerRows?: number;
1543
+ /** Text inset from the cell edges (mm). */
1544
+ cellMargin?: number;
1545
+ borders?: "all" | "outer" | "rows" | "none";
1546
+ styleId?: string;
1547
+ styleOverride?: TextStyleOverride;
1548
+ }>;
1549
+ type ModelObject = Line | Point | Polyline | Circle | Arc | Ellipse | Hatch | Text | Dimension | Block | Table;
961
1550
  /** Identity + shared style fields every stored object carries. */
962
1551
  type StoredObjectBase = {
963
1552
  id: string;
@@ -1051,12 +1640,14 @@ type StoredText = StoredShape<{
1051
1640
  width?: number;
1052
1641
  hAlign: "left" | "center" | "right";
1053
1642
  vAlign: "bottom" | "center" | "top";
1054
- frame?: "none" | "rectangle" | "bottom";
1643
+ frame?: "none" | "rectangle" | "circle" | "slot" | "bottom" | "firstLine";
1055
1644
  styleId?: string;
1056
1645
  /** Only the keys the user actually overrode on this text. */
1057
1646
  styleOverride?: {
1058
1647
  font?: string;
1059
1648
  widthFactor?: number;
1649
+ bold?: boolean;
1650
+ italic?: boolean;
1060
1651
  textHeight?: number;
1061
1652
  arrowType?: "filled" | "open" | "tick" | "dot" | "none";
1062
1653
  arrowSize?: number;
@@ -1075,6 +1666,8 @@ type StoredDimension = StoredShape<{
1075
1666
  styleOverride?: {
1076
1667
  font?: string;
1077
1668
  widthFactor?: number;
1669
+ bold?: boolean;
1670
+ italic?: boolean;
1078
1671
  textHeight?: number;
1079
1672
  textOffset?: number;
1080
1673
  arrowType?: "filled" | "open" | "tick" | "dot" | "none";
@@ -1091,7 +1684,7 @@ type StoredBlock = StoredShape<{
1091
1684
  definitionId: string;
1092
1685
  rotation: number;
1093
1686
  scale: number;
1094
- params: Readonly<Record<string, number | string | boolean>>;
1687
+ params: Readonly<Record<string, number | string | boolean | readonly number[] | readonly string[]>>;
1095
1688
  /** World points and/or referenced object ids, in pick order. */
1096
1689
  inputs: readonly (Vec2 | string)[];
1097
1690
  }>;
@@ -1119,8 +1712,100 @@ type StoredImage = StoredShape<{
1119
1712
  height: number;
1120
1713
  rotation: number;
1121
1714
  }>;
1715
+ /** A LINKED file drawn in place (an xref); the document holds only this
1716
+ * record — the file's content is not readable from scripts. */
1717
+ type StoredReference = StoredShape<{
1718
+ type: "reference";
1719
+ format: "linea" | "dxf" | "dwg" | "pdf" | "png" | "jpg";
1720
+ name: string;
1721
+ source: {
1722
+ kind: "path";
1723
+ path: string;
1724
+ cacheKey?: string;
1725
+ } | {
1726
+ kind: "url";
1727
+ url: string;
1728
+ };
1729
+ /** Where the file's origin lands. */
1730
+ position: Vec2;
1731
+ rotation: number;
1732
+ scale: number;
1733
+ mirrored?: boolean;
1734
+ pdfPage?: number;
1735
+ pdfMode?: "vector" | "raster";
1736
+ /** The file's layers not drawn, by name. */
1737
+ hiddenLayers: readonly string[];
1738
+ /** Switched off: not drawn. */
1739
+ hidden?: boolean;
1740
+ /** Crop rectangle in file coordinates. */
1741
+ clip?: {
1742
+ minX: number;
1743
+ minY: number;
1744
+ maxX: number;
1745
+ maxY: number;
1746
+ };
1747
+ /** Content bounds in file coordinates at the last load. */
1748
+ extent?: {
1749
+ minX: number;
1750
+ minY: number;
1751
+ maxX: number;
1752
+ maxY: number;
1753
+ };
1754
+ }>;
1755
+ /** Review note pinned to a point; the editor shows a screen-fixed marker. */
1756
+ type StoredComment = StoredShape<{
1757
+ type: "comment";
1758
+ /** Tail tip of the bubble (world/sheet mm). */
1759
+ position: Vec2;
1760
+ text: string;
1761
+ tags: readonly string[];
1762
+ }>;
1763
+ /** Text style keys a text, table or table cell may override. */
1764
+ type TextStyleOverride = {
1765
+ font?: string;
1766
+ widthFactor?: number;
1767
+ bold?: boolean;
1768
+ italic?: boolean;
1769
+ textHeight?: number;
1770
+ arrowType?: "filled" | "open" | "tick" | "dot" | "none";
1771
+ arrowSize?: number;
1772
+ };
1773
+ /** One table cell as stored. */
1774
+ type StoredTableCell = {
1775
+ /** Plain text; "\n" = line break. */
1776
+ text: string;
1777
+ /** Merge, on the anchor (top-left) cell; covered cells are ignored. */
1778
+ span?: {
1779
+ cols: number;
1780
+ rows: number;
1781
+ };
1782
+ hAlign?: "left" | "center" | "right";
1783
+ vAlign?: "top" | "center" | "bottom";
1784
+ styleId?: string;
1785
+ styleOverride?: TextStyleOverride;
1786
+ color?: string;
1787
+ };
1788
+ /** Grid of text cells hanging right/down from `position` (top-left). */
1789
+ type StoredTable = StoredShape<{
1790
+ type: "table";
1791
+ position: Vec2;
1792
+ rotation: number;
1793
+ scale: number;
1794
+ /** Column widths (mm, before `scale`). */
1795
+ columns: readonly number[];
1796
+ rows: readonly {
1797
+ minHeight?: number;
1798
+ }[];
1799
+ /** Row-major `cells[row][column]`. */
1800
+ cells: readonly (readonly StoredTableCell[])[];
1801
+ headerRows: number;
1802
+ cellMargin: number;
1803
+ borders: "all" | "outer" | "rows" | "none";
1804
+ styleId?: string;
1805
+ styleOverride?: TextStyleOverride;
1806
+ }>;
1122
1807
  /** 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;
1808
+ type StoredObject = StoredLine | StoredPoint | StoredPolyline | StoredCircle | StoredArc | StoredEllipse | StoredHatch | StoredText | StoredDimension | StoredBlock | StoredViewport | StoredImage | StoredComment | StoredTable | StoredReference;
1124
1809
  /**
1125
1810
  * One choice of a "Select" parameter: the value (what scripts receive) with
1126
1811
  * an optional properties-panel label. A plain string is shorthand for
@@ -1129,44 +1814,152 @@ type StoredObject = StoredLine | StoredPoint | StoredPolyline | StoredCircle | S
1129
1814
  type ParameterOption = string | {
1130
1815
  value: string;
1131
1816
  label?: string;
1817
+ /** A `#rrggbb` color square before the option's label. */
1818
+ swatch?: string;
1132
1819
  };
1133
1820
  /**
1134
1821
  * One entry of the module's optional `params` export — the block's
1135
1822
  * parameters table. `name` is the key scripts read from `params`, `label`
1136
1823
  * the properties-panel caption (defaults to the name).
1137
1824
  */
1138
- type ParamDef = {
1825
+ /** What every params-table entry may carry: its key, panel caption and
1826
+ * tooltip. */
1827
+ type ParamBase = {
1828
+ /** The key scripts read from `params`. */
1139
1829
  name: string;
1830
+ /** The properties-panel caption (defaults to the name). */
1140
1831
  label?: string;
1832
+ /** What the parameter means: the label's tooltip in the panel. */
1833
+ hint?: string;
1834
+ };
1835
+ type ParamDef = (ParamBase & {
1141
1836
  type: "number";
1142
1837
  default: number;
1143
1838
  min?: number;
1144
1839
  max?: number;
1145
- } | {
1146
- name: string;
1147
- label?: string;
1840
+ /** Whole numbers only. */
1841
+ integer?: boolean;
1842
+ /** ArrowUp / ArrowDown increment in the panel (default 1). */
1843
+ step?: number;
1844
+ /** Shown inside the field before / after the value ("1:", "mm"). */
1845
+ prefix?: string;
1846
+ suffix?: string;
1847
+ /** Standard values offered in the field's dropdown; typing stays free. */
1848
+ presets?: readonly number[];
1849
+ }) | (ParamBase & {
1148
1850
  type: "string";
1149
1851
  default: string;
1150
- } | {
1151
- name: string;
1152
- label?: string;
1852
+ placeholder?: string;
1853
+ /** A textarea; Shift+Enter starts a new line. */
1854
+ multiline?: boolean;
1855
+ presets?: readonly string[];
1856
+ }) | (ParamBase & {
1153
1857
  type: "boolean";
1154
1858
  default: boolean;
1155
- } | {
1156
- name: string;
1157
- label?: string;
1859
+ /** "toggle": a toggle button showing the label (compact, e.g. in a
1860
+ * row beside a picker) instead of a switch. */
1861
+ display?: "switch" | "toggle";
1862
+ })
1863
+ /** A list of numbers, edited as space-separated text with Tekla-style
1864
+ * `N*d` repeats ("0 2*7200" → [0, 7200, 7200]). */
1865
+ | (ParamBase & {
1866
+ type: "numberList";
1867
+ default: readonly number[];
1868
+ /** Shown while the list is empty. */
1869
+ placeholder?: string;
1870
+ min?: number;
1871
+ max?: number;
1872
+ presets?: readonly (readonly number[])[];
1873
+ })
1874
+ /** A list of strings, edited as space-separated words; double quotes group
1875
+ * a phrase ('A "B 2"' → ["A", "B 2"]). */
1876
+ | (ParamBase & {
1877
+ type: "stringList";
1878
+ default: readonly string[];
1879
+ /** Shown while the list is empty. */
1880
+ placeholder?: string;
1881
+ presets?: readonly (readonly string[])[];
1882
+ })
1883
+ /** A `#rrggbb` color: a swatch with a picker; presets form a palette. */
1884
+ | (ParamBase & {
1885
+ type: "color";
1886
+ default: string;
1887
+ presets?: readonly string[];
1888
+ }) | (ParamBase & {
1158
1889
  type: "enum";
1159
1890
  default: string;
1160
1891
  options: readonly ParameterOption[];
1161
- }
1892
+ /** "buttons": a segmented toggle group of the options (short
1893
+ * choices); falls back to the dropdown when they don't fit. */
1894
+ display?: "dropdown" | "buttons";
1895
+ })
1896
+ /** Pickers over the document's resources; the value is an id / name.
1897
+ * textStyle / dimStyle: a style id ("" or unknown = the document's first
1898
+ * style — read it in draw with `styles.text(id)` / `styles.dim(id)`, or
1899
+ * hand it to children as `styleId`). font: a font id ("arial"…).
1900
+ * lineType / hatchPattern: a linetype / pattern name. */
1901
+ | (ParamBase & {
1902
+ type: "textStyle" | "dimStyle" | "font" | "lineType" | "hatchPattern";
1903
+ default?: string;
1904
+ })
1162
1905
  /** A section label between rows in the properties panel. Carries no
1163
1906
  * value: it never appears in the `params` record `draw` receives.
1164
1907
  * `name` stays the unique key (paramVisibility can hide it by name). */
1165
- | {
1166
- name: string;
1167
- label?: string;
1908
+ | (ParamBase & {
1168
1909
  type: "label";
1910
+ })
1911
+ /** Layout only: 2–3 compact params on one panel row, each item's label a
1912
+ * short prefix ("W", "H"). Values stay flat — `params.w`, `params.h`. */
1913
+ | (ParamBase & {
1914
+ type: "row";
1915
+ items: readonly RowItemDef[];
1916
+ });
1917
+ /** A document text style as `draw` reads it (`styles.text(id)`). Heights
1918
+ * and arrow sizes are mm before an object's `scale`. */
1919
+ type TextStyleInfo = {
1920
+ readonly id: string;
1921
+ readonly name: string;
1922
+ readonly font: string;
1923
+ readonly widthFactor: number;
1924
+ readonly bold?: boolean;
1925
+ readonly italic?: boolean;
1926
+ readonly textHeight: number;
1927
+ readonly arrowType: "filled" | "open" | "tick" | "dot" | "none";
1928
+ readonly arrowSize: number;
1169
1929
  };
1930
+ /** A document dimension style as `draw` reads it (`styles.dim(id)`). */
1931
+ type DimStyleInfo = {
1932
+ readonly id: string;
1933
+ readonly name: string;
1934
+ readonly font: string;
1935
+ readonly widthFactor: number;
1936
+ readonly bold?: boolean;
1937
+ readonly italic?: boolean;
1938
+ readonly textHeight: number;
1939
+ readonly textOffset: number;
1940
+ readonly arrowType: "filled" | "open" | "tick" | "dot" | "none";
1941
+ readonly arrowSize: number;
1942
+ readonly extensionType: "long" | "short";
1943
+ readonly extensionOffset: number;
1944
+ readonly extensionOvershoot: number;
1945
+ readonly precision: number;
1946
+ };
1947
+ /** `draw`'s `styles`: the document's styles by id. An empty or unknown id
1948
+ * (a deleted style, a block from another drawing) gives the document's
1949
+ * first style — the same rule a child's `styleId` follows. */
1950
+ interface BlockStyles {
1951
+ text(id?: string): TextStyleInfo;
1952
+ dim(id?: string): DimStyleInfo;
1953
+ }
1954
+ /** What a `row` may hold: the compact, single-line param kinds. */
1955
+ type RowItemDef = Extract<ParamDef, {
1956
+ type: "number" | "string" | "boolean" | "enum" | "color" | "textStyle" | "dimStyle" | "font" | "lineType" | "hatchPattern";
1957
+ }>;
1958
+ /** A table entry's value-carrying params: a row's items, else itself. */
1959
+ type FlatParam<Q> = Q extends {
1960
+ type: "row";
1961
+ items: readonly (infer I)[];
1962
+ } ? I : Q;
1170
1963
  /**
1171
1964
  * The block's parameters table — what the `params` member of a BlockSpec
1172
1965
  * declares (or its function form returns).
@@ -1185,7 +1978,11 @@ type ParamValue<Q extends ParamDef> = Q extends {
1185
1978
  type: "number";
1186
1979
  } ? number : Q extends {
1187
1980
  type: "boolean";
1188
- } ? boolean : string;
1981
+ } ? boolean : Q extends {
1982
+ type: "numberList";
1983
+ } ? readonly number[] : Q extends {
1984
+ type: "stringList";
1985
+ } ? readonly string[] : string;
1189
1986
  /**
1190
1987
  * The values record a params table produces: each entry's `name` maps to
1191
1988
  * its runtime value type (number/string/boolean, or the enum's option
@@ -1196,10 +1993,392 @@ type ParamValue<Q extends ParamDef> = Q extends {
1196
1993
  * passes through unchanged.
1197
1994
  */
1198
1995
  type ParamValues<P> = P extends () => infer R ? ParamValues<R> : P extends readonly (infer Q extends ParamDef)[] ? {
1199
- readonly [E in Q as E extends {
1996
+ readonly [E in FlatParam<Q> as E extends {
1200
1997
  type: "label";
1201
- } ? never : E["name"]]: ParamValue<E>;
1998
+ } ? never : E extends {
1999
+ name: infer N extends string;
2000
+ } ? N : never]: E extends ParamDef ? ParamValue<E> : never;
1202
2001
  } : P;
2002
+ /** An axis-aligned box in world mm. */
2003
+ type Box = {
2004
+ minX: number;
2005
+ minY: number;
2006
+ maxX: number;
2007
+ maxY: number;
2008
+ };
2009
+ /** Filters for Drawing.query — all present filters AND together. */
2010
+ type ObjectQuery = {
2011
+ ids?: readonly string[];
2012
+ type?: ModelObject["type"];
2013
+ /** Layer name or id. */
2014
+ layer?: string;
2015
+ /** #rrggbb override (objects without one inherit from their layer). */
2016
+ color?: string;
2017
+ lineType?: string;
2018
+ /** Substring match on text content. */
2019
+ content?: string;
2020
+ /** Bounds intersect this box. */
2021
+ bbox?: Box;
2022
+ /** Bounds entirely inside this box. */
2023
+ inside?: Box;
2024
+ /** Geometry within `tol` mm of `point`. */
2025
+ near?: {
2026
+ point: Vec2Like;
2027
+ tol: number;
2028
+ };
2029
+ /** Search this paper layout's sheet objects (name or id) instead of
2030
+ * model space. */
2031
+ layout?: string;
2032
+ };
2033
+ /** A STORED object as query() returns it (see StoredObject — schema
2034
+ * output: defaults applied, points always {x, y}, identity present). */
2035
+ type ExistingObject = StoredObject;
2036
+ /** Per-object measurements; null where the type has no natural value. */
2037
+ type Measurement = {
2038
+ bbox: Box | null;
2039
+ length: number | null;
2040
+ area: number | null;
2041
+ };
2042
+ /** A layer as stored (defaults applied) plus the current-layer flag. */
2043
+ type LayerInfo = {
2044
+ id: string;
2045
+ name: string;
2046
+ color: string;
2047
+ lineType: string;
2048
+ lineWidth: number;
2049
+ opacity: number;
2050
+ visible: boolean;
2051
+ locked: boolean;
2052
+ current: boolean;
2053
+ [key: string]: unknown;
2054
+ };
2055
+ /** A paper layout as stored: sheet metadata + its sheet-space objects. */
2056
+ type LayoutInfo = {
2057
+ id: string;
2058
+ name: string;
2059
+ sheet: {
2060
+ width: number;
2061
+ height: number;
2062
+ };
2063
+ printPalette: "color" | "grayscale" | "monochrome";
2064
+ objects: readonly StoredObject[];
2065
+ };
2066
+ /** A block module's identity/metadata (from its exports). */
2067
+ type BlockInfo = {
2068
+ id: string;
2069
+ name: string;
2070
+ description?: string;
2071
+ version?: string;
2072
+ authors?: readonly string[];
2073
+ tags?: readonly string[];
2074
+ dependencies?: readonly string[];
2075
+ };
2076
+ /** A command module's identity/metadata (from its exports). */
2077
+ type CommandInfo = {
2078
+ id: string;
2079
+ name: string;
2080
+ description?: string;
2081
+ version?: string;
2082
+ authors?: readonly string[];
2083
+ tags?: readonly string[];
2084
+ /** Declared point inputs (labels), picked or supplied before `run`. */
2085
+ inputs?: readonly string[];
2086
+ /** Declared parameters (same table as a block's), prompted or supplied
2087
+ * before `run`. */
2088
+ params?: readonly ParamDef[];
2089
+ };
2090
+ /** What installing module sources reports. */
2091
+ type MergeReport = {
2092
+ /** The full library after the merge. */
2093
+ merged: readonly string[];
2094
+ added: readonly {
2095
+ script: string;
2096
+ meta: {
2097
+ id: string;
2098
+ name: string;
2099
+ };
2100
+ }[];
2101
+ replaced: readonly {
2102
+ script: string;
2103
+ meta: {
2104
+ id: string;
2105
+ name: string;
2106
+ };
2107
+ }[];
2108
+ skipped: number;
2109
+ rejected: readonly {
2110
+ script: string;
2111
+ error: string;
2112
+ }[];
2113
+ };
2114
+ /** A sheet: a bare preset (orientation from context — landscape for a new
2115
+ * layout, the current one when patching), a preset with its orientation, or
2116
+ * explicit millimetres. */
2117
+ type SheetSpec = "A4" | "A3" | "A2" | "A1" | "A0" | {
2118
+ name: "A4" | "A3" | "A2" | "A1" | "A0";
2119
+ orientation: "portrait" | "landscape";
2120
+ } | {
2121
+ width: number;
2122
+ height: number;
2123
+ };
2124
+ /** Options for Drawing.createLayout. */
2125
+ type LayoutSpec = {
2126
+ /** Default: A3 landscape. */
2127
+ sheet?: SheetSpec;
2128
+ /** Viewport scale — `"1:50"` or the denominator; default: fitted. */
2129
+ scale?: number | string;
2130
+ /** One fitted model viewport (default), or `false` for a bare sheet. */
2131
+ viewport?: {
2132
+ rect?: {
2133
+ x: number;
2134
+ y: number;
2135
+ w: number;
2136
+ h: number;
2137
+ };
2138
+ scale?: number | string;
2139
+ center?: Vec2Like;
2140
+ } | false;
2141
+ /** Tab position; default: append. */
2142
+ index?: number;
2143
+ };
2144
+ /** The whole document as stored (defaults applied). */
2145
+ type StoredDocument = {
2146
+ id: string;
2147
+ version: number;
2148
+ layers: readonly Omit<LayerInfo, "current">[];
2149
+ currentLayerId: string;
2150
+ objects: readonly StoredObject[];
2151
+ layouts: readonly LayoutInfo[];
2152
+ /** Raw block module sources. */
2153
+ blockDefinitions: readonly string[];
2154
+ /** Raw command module sources. */
2155
+ commands: readonly string[];
2156
+ [key: string]: unknown;
2157
+ };
2158
+ /** Where a draw-order move puts the objects. */
2159
+ type ReorderPlacement = "front" | "back" | {
2160
+ above: string;
2161
+ } | {
2162
+ below: string;
2163
+ };
2164
+ /**
2165
+ * The document as command scripts see it — the SAME `Drawing` interface
2166
+ * the agent tools and the SDK use. Angles are RADIANS, point-valued
2167
+ * arguments accept {x, y} or [x, y], `layer` resolves by name or id.
2168
+ * Object mutations on an editor-attached drawing target the ACTIVE space.
2169
+ * Methods throw on invalid input (an uncaught throw cancels the command
2170
+ * and rolls its edits back). Reads return detached snapshots.
2171
+ */
2172
+ interface Drawing {
2173
+ /** The document's own id. */
2174
+ readonly id: string;
2175
+ /** Monotonic change counter. */
2176
+ readonly revision: number;
2177
+ /** The full document — a detached snapshot. */
2178
+ readonly document: StoredDocument;
2179
+ /** Counts by type/layer, bbox, layer + layout names. */
2180
+ summary(): {
2181
+ name: string;
2182
+ objectCount: number;
2183
+ byType: Record<string, number>;
2184
+ byLayer: Record<string, number>;
2185
+ bbox: Box | null;
2186
+ layers: string[];
2187
+ layouts: {
2188
+ name: string;
2189
+ objectCount: number;
2190
+ }[];
2191
+ };
2192
+ /** Filtered objects — model space, or one layout via `filter.layout`. */
2193
+ query(filter?: ObjectQuery): ExistingObject[];
2194
+ /** One object from ANY space, or undefined. */
2195
+ getObject(id: string): ExistingObject | undefined;
2196
+ /** bbox / curve length / enclosed area of one object. */
2197
+ measure(id: string): Measurement;
2198
+ listLayers(): LayerInfo[];
2199
+ listLayouts(): LayoutInfo[];
2200
+ /** Compilable block definitions in this document. */
2201
+ listBlocks(): BlockInfo[];
2202
+ /** Compilable command modules travelling with this document. */
2203
+ listCommands(): CommandInfo[];
2204
+ /** Model space (or a layout via `layout`) as an SVG string. */
2205
+ renderSvg(opts?: {
2206
+ layout?: string;
2207
+ bbox?: Box;
2208
+ padding?: number;
2209
+ palette?: "color" | "grayscale" | "monochrome";
2210
+ }): string;
2211
+ /** Multi-page PDF of the layouts (default: all) — absent on hosts
2212
+ * without fonts, so check before calling. */
2213
+ renderPdf?(opts?: {
2214
+ layouts?: readonly string[];
2215
+ palette?: "color" | "grayscale" | "monochrome";
2216
+ }): Promise<Uint8Array>;
2217
+ /** The whole document as DXF text. */
2218
+ toDxf(): Promise<string>;
2219
+ /** DWG bytes (default AC1027 — AutoCAD 2013). */
2220
+ toDwg(opts?: {
2221
+ version?: string;
2222
+ }): Promise<Uint8Array>;
2223
+ /** The `.linea` file text. */
2224
+ toJson(): string;
2225
+ /** Add objects (each may carry `layer` — a name — instead of an id);
2226
+ * returns the created ids. */
2227
+ add(objects: readonly (ModelObject & {
2228
+ layer?: string;
2229
+ })[], opts?: {
2230
+ layout?: string;
2231
+ }): string[];
2232
+ /** Apply per-object patches (`{ id, ...changedFields }`). */
2233
+ update(entries: readonly ({
2234
+ id: string;
2235
+ } & Record<string, unknown>)[]): void;
2236
+ /** Delete by id (unknown ids are skipped); returns how many went. */
2237
+ remove(ids: readonly string[]): number;
2238
+ /** Draw order: move the objects (bottom → top) to a placement. */
2239
+ reorder(ids: readonly string[], placement: ReorderPlacement): void;
2240
+ move(ids: readonly string[], delta: Vec2Like): void;
2241
+ rotate(ids: readonly string[], angleRad: number, center?: Vec2Like): void;
2242
+ scale(ids: readonly string[], factor: number, center?: Vec2Like): void;
2243
+ mirror(ids: readonly string[], axisA: Vec2Like, axisB: Vec2Like): void;
2244
+ /** Duplicate displaced by delta; returns the new ids. */
2245
+ copy(ids: readonly string[], delta: Vec2Like): string[];
2246
+ /** count TOTAL copies at multiples of delta; returns the new ids. */
2247
+ array(ids: readonly string[], count: number, delta: Vec2Like): string[];
2248
+ /** Create a paper layout; returns its id. */
2249
+ createLayout(name: string, opts?: LayoutSpec): string;
2250
+ /** Patch a layout's name / sheet / print palette. A bare preset keeps the
2251
+ * layout's current orientation. */
2252
+ updateLayout(nameOrId: string, patch: {
2253
+ name?: string;
2254
+ sheet?: SheetSpec;
2255
+ printPalette?: "color" | "grayscale" | "monochrome";
2256
+ }): void;
2257
+ removeLayout(nameOrId: string): void;
2258
+ /** Explicit total order (names or ids) — the PDF page order. */
2259
+ reorderLayouts(order: readonly string[]): void;
2260
+ /** Create a layer (unique name); returns its id. */
2261
+ addLayer(props: {
2262
+ name: string;
2263
+ color?: string;
2264
+ } & Record<string, unknown>): string;
2265
+ updateLayer(nameOrId: string, patch: Record<string, unknown>): void;
2266
+ /** Remove an EMPTY, non-current layer. */
2267
+ removeLayer(nameOrId: string): void;
2268
+ /** Explicit total order (names or ids, every layer exactly once). */
2269
+ reorderLayers(order: readonly string[]): void;
2270
+ setCurrentLayer(nameOrId: string): void;
2271
+ /** Patch a document dimension style (default: the first). */
2272
+ setDimStyle(patch: Record<string, unknown>, styleId?: string): void;
2273
+ /** Patch a document text style (default: the first). */
2274
+ setTextStyle(patch: Record<string, unknown>, styleId?: string): void;
2275
+ /** Embed image pixels (a data URL); returns the content-keyed assetId
2276
+ * that `image` objects reference. */
2277
+ addAsset(dataUrl: string): string;
2278
+ /** Remove an asset (refused while an image references it). */
2279
+ removeAsset(id: string): void;
2280
+ /** Merge block module sources into the document library. */
2281
+ installBlocks(sources: readonly string[]): Promise<MergeReport>;
2282
+ removeBlock(id: string): void;
2283
+ installCommands(sources: readonly string[]): Promise<MergeReport>;
2284
+ removeCommand(id: string): void;
2285
+ /** Escape hatch: apply an already-shaped kernel op batch (validated,
2286
+ * atomic, one undo step). */
2287
+ applyOps(ops: readonly Record<string, unknown>[]): void;
2288
+ /**
2289
+ * Group edits into ONE undo step (a command run already is one; nested
2290
+ * calls join it). A throw rolls back what the transaction applied.
2291
+ */
2292
+ transaction<T>(fn: () => T, label?: string): T;
2293
+ /** Not available while a command runs (throws) — return or throw. */
2294
+ undo(): boolean;
2295
+ redo(): boolean;
2296
+ }
2297
+ /** The editor's state as a script sees it. */
2298
+ type EditorState = {
2299
+ documentId: string;
2300
+ documentName: string;
2301
+ space: "model" | {
2302
+ layout: string;
2303
+ };
2304
+ selectedIds: string[];
2305
+ readOnly: boolean;
2306
+ canUndo: boolean;
2307
+ canRedo: boolean;
2308
+ };
2309
+ /** One runnable editor command (registry entry, macro, or insert-block). */
2310
+ type EditorCommandInfo = {
2311
+ id: string;
2312
+ label: string;
2313
+ group: string;
2314
+ hotkey?: string;
2315
+ };
2316
+ /**
2317
+ * The interactive half of the context — present only when the command runs
2318
+ * inside a live editor (absent when a script runs headlessly, e.g. from the
2319
+ * CLI or the MCP server; branch on it). The pickers and `prompt` REJECT
2320
+ * when the user cancels (Escape) — let that propagate to abort the command
2321
+ * (all edits roll back), or catch it to finish an open-ended collection.
2322
+ */
2323
+ interface EditorSurface {
2324
+ state(): EditorState;
2325
+ setActiveSpace(space: "model" | {
2326
+ layout: string;
2327
+ }): void;
2328
+ setSelection(ids: readonly string[]): void;
2329
+ zoom(to: "fit" | "selection"): void;
2330
+ /** Await one snapped world point; `referencePoint` enables rubber-band
2331
+ * + relative typed entry from there. */
2332
+ pickPoint(opts?: {
2333
+ label?: string;
2334
+ referencePoint?: Vec2Like;
2335
+ }): Promise<Vec2>;
2336
+ /** Await one object click; resolves the object's id. */
2337
+ pickObject(opts?: {
2338
+ label?: string;
2339
+ }): Promise<string>;
2340
+ /** Await a typed value from a small input dialog. */
2341
+ prompt(message: string, opts?: {
2342
+ initial?: string;
2343
+ placeholder?: string;
2344
+ }): Promise<string>;
2345
+ toast(message: string, kind?: "info" | "success" | "error"): void;
2346
+ /** Registry commands + macros + insert-block entries. */
2347
+ listCommands(): EditorCommandInfo[];
2348
+ /** Trigger a command by id — like the user pressing its hotkey. A macro
2349
+ * takes its declared `inputs` / `params` up front (params passed skip its
2350
+ * params dialog). */
2351
+ runCommand(id: string, inputs?: readonly Vec2Like[], params?: Readonly<Record<string, unknown>>): Promise<void>;
2352
+ }
2353
+ /**
2354
+ * What `run` receives. `document` is the Drawing; `editor` the interactive
2355
+ * surface when there is one; `inputs` the points the command's declared
2356
+ * `inputs` labels produced (picked in the editor, or supplied by the
2357
+ * caller), in label order; `params` the values of the declared `params`
2358
+ * table (asked for in a dialog in the editor, or passed by the caller;
2359
+ * omitted ones take their defaults).
2360
+ */
2361
+ interface CommandContext<P = Readonly<Record<string, unknown>>> {
2362
+ document: Drawing;
2363
+ editor?: EditorSurface;
2364
+ inputs: readonly Vec2[];
2365
+ params: P;
2366
+ /** @deprecated Use `editor.pickPoint({ label })` (throws without an editor). */
2367
+ pickPoint(label?: string): Promise<Vec2>;
2368
+ /** @deprecated Use `editor.pickObject({ label })`. */
2369
+ pickObject(label?: string): Promise<string>;
2370
+ /** @deprecated Use `editor.state().selectedIds`. */
2371
+ selection(): string[];
2372
+ /** @deprecated Use `editor.setSelection(ids)`. */
2373
+ setSelection(ids: readonly string[]): void;
2374
+ /** @deprecated Use `editor.prompt(message, options)`. */
2375
+ prompt(message: string, options?: {
2376
+ initial?: string;
2377
+ placeholder?: string;
2378
+ }): Promise<string>;
2379
+ /** @deprecated Use `editor.toast(message, kind)`. */
2380
+ showToast(message: string, kind?: "info" | "success" | "error"): void;
2381
+ }
1203
2382
 
1204
2383
  // Script-contract globals: aliases into the module (not re-declarations),
1205
2384
  // so the in-app editor's BlockParams substitution flows through them.
@@ -1215,10 +2394,6 @@ declare type BlockSpec<
1215
2394
  P extends import("lineadraw").BlockParamDefs = readonly [],
1216
2395
  Pl extends PlaceSpec<P> | undefined = undefined,
1217
2396
  > = 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;
2397
+ declare type CommandSpec<
2398
+ P extends import("lineadraw").BlockParamDefs = readonly [],
2399
+ > = import("lineadraw").CommandSpec<P>;