@miclivs/cadcli 0.1.2 → 0.3.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.
@@ -1,21 +1,45 @@
1
1
  ---
2
2
  name: cadcli
3
- description: Inspect, search, summarize, preview, and safely edit DWG/DXF CAD drawings with the cadcli CLI. Use when the user asks about CAD files, floorplans, DWG/DXF contents, layers, blocks, entities, text, previews, or jq-backed CAD edits.
3
+ description: Inspect, search, summarize, preview, and safely edit DWG/DXF CAD drawings with the cadcli CLI. Use when the user asks about CAD files, floorplans, DWG/DXF contents, layers, blocks, entities, text, previews, or CAD edits.
4
4
  ---
5
5
 
6
6
  # cadcli
7
7
 
8
- Use `cadcli` for progressive CAD file discovery. Start broad, then narrow down:
8
+ Use `cadcli` for progressive CAD file discovery. Follow this order when trying to understand a drawing:
9
+
10
+ ```bash
11
+ cadcli info <file> --json # size, format, counts, bounds
12
+ cadcli overview <file> # human clues: layers, labels, blocks, hints
13
+ cadcli layers <file> --json # major groupings
14
+ cadcli blocks <file> --json # reusable object definitions
15
+ cadcli query <file> --schema # learn query tables before writing SQL
16
+ cadcli search <file> "query" --json # fuzzy discovery from overview terms
17
+ cadcli entities <file> --limit 20 --json # raw drilldown only when needed
18
+ ```
19
+
20
+ When working with a drawing, build a human-readable understanding of what is in it. Do not stop at listing CAD primitives such as layers, blocks, handles, entity types, or raw coordinates. Use those details as evidence, then explain the drawing in the terms a person would use: rooms, entrances, furniture, doors, fixtures, workstations, corridors, core/service areas, labels, structural elements, mechanical/electrical items, or other project-specific objects.
21
+
22
+ Do this as evidence-based discovery. Say what the file appears to contain and cite the clues that support it: layer names, block names, text samples, entity counts, and coordinates/handles where useful. Avoid imposing generic assumptions. Different drawings encode meaning differently: one file may identify rooms through text labels, another through room-tag blocks, another through closed polylines, and another not at all. Follow the file's own conventions and translate the underlying CAD structure into concepts users can understand.
23
+
24
+ Use each command for a different job. `overview` is for clues and vocabulary. `search` is for fuzzy discovery when you have a term from the overview or the user. `query` is for tabular/repeatable questions. `entities` is for raw drilldown after you know what type or layer matters.
25
+
26
+ Always run `cadcli query <file> --schema` before writing SQL for a file. The query engine exposes narrow in-memory tables: `summary`, `metadata`, `layers`, `blocks`, `entities`, `texts`, and `inserts`.
27
+
28
+ For a question like "how many rooms are there", use this pattern:
9
29
 
10
30
  ```bash
11
- cadcli info <file> --json
12
31
  cadcli overview <file>
13
- cadcli layers <file> --json
14
- cadcli entities <file> --limit 20 --json
15
- cadcli search <file> "query" --json
32
+ cadcli query <file> --schema
33
+ cadcli query <file> --sql "select id, text, layer, x, y from texts where text like 'Room%'" --json
16
34
  ```
17
35
 
18
- For visual checks, prefer the high-fidelity native path when available:
36
+ Adapt the query terms to the drawing's language and labels. For Hebrew drawings, text may already be normalized by cadcli, so a room query may use `text like 'חדר%'`. For drawings where rooms are block tags rather than text labels, query `inserts` instead of `texts`.
37
+
38
+ If the drawing shows furniture or door layers, inspect their `INSERT` entities and block names. Use `cadcli query` for questions like "where are the inserted chair blocks", "which labels start with room", or "which layers have the most entities". If it shows cryptic layers like `A2` or `A3`, infer cautiously from the entity mix and repeated block/text evidence rather than from the layer name alone.
39
+
40
+ When answering the user, communicate in ordinary language. Use terms like "rooms", "furniture", "doors", "labels", "support spaces", "architectural linework", and "evidence". Do not lead with implementation details like entity types, raw JSON fields, SQL tables, or file internals unless they are needed to justify the answer or the user asks for them.
41
+
42
+ For visual checks, render an SVG preview:
19
43
 
20
44
  ```bash
21
45
  cadcli view <file> -o preview.svg
@@ -27,8 +51,25 @@ For lightweight previews from the normalized model:
27
51
  cadcli svg <file> -o preview.svg
28
52
  ```
29
53
 
30
- For edits, never overwrite by default. Write to a new file unless the user explicitly asks for in-place edits:
54
+ For edits, find handles first, then write an edited copy. Never overwrite by default; use `--overwrite` only when the user explicitly asks for in-place edits:
31
55
 
32
56
  ```bash
33
- cadcli edit <file> --jq '<jq expression>' -o edited.dwg
57
+ cadcli entities <file> --type TEXT --json
58
+ cadcli search <file> "office" --json
59
+
60
+ cadcli edit <file> --set-text 'New label' --text-id <id> -o edited.dwg
61
+ cadcli edit <file> --set-layer A-TEXT --layer-id <id> -o edited.dwg
62
+ cadcli edit <file> --set-color '#ff0000' --color-id <id> -o edited.dwg
63
+ cadcli edit <file> --move <id> --dx 10 --dy 0 -o edited.dwg
64
+ cadcli edit <file> --rotate <id> --angle 90 --origin 0,0 -o edited.dwg
65
+ cadcli edit <file> --scale <id> --factor 2 -o edited.dwg
66
+ cadcli edit <file> --copy <id> --dx 10 --dy 0 -o edited.dwg
67
+ cadcli edit <file> --delete <id> -o edited.dwg
68
+
69
+ cadcli edit <file> --add-line 0,0:10,0 --new-layer A-WALL -o edited.dwg
70
+ cadcli edit <file> --add-circle 5,5:2 -o edited.dwg
71
+ cadcli edit <file> --add-text 'Label' --at 5,5 --height 2.5 -o edited.dwg
72
+ cadcli edit <file> --points '0,0;10,0;10,5' --closed -o edited.dwg
34
73
  ```
74
+
75
+ Edit formats: points are `x,y` or `x,y,z`; line is `from:to`; circle is `center:radius`; arc is `center:radius:startAngle:endAngle`; color is `bylayer`, `byblock`, an AutoCAD color index, `#rrggbb`, or `r,g,b`.
@@ -1,37 +0,0 @@
1
- export type LibreDwgToolName = "dwgread" | "dwgfilter";
2
- export interface LibreDwgEditResult {
3
- input: string;
4
- output: string;
5
- expression: string;
6
- backend: "LibreDWG";
7
- tool: "dwgfilter";
8
- stderr: string;
9
- }
10
- export interface LibreDwgViewResult {
11
- input: string;
12
- output?: string;
13
- svg: string;
14
- backend: "LibreDWG";
15
- tool: "dwgread";
16
- stderr: string;
17
- }
18
- export interface LibreDwgJsonResult {
19
- input: string;
20
- json: unknown;
21
- backend: "LibreDWG";
22
- tool: "dwgread";
23
- stderr: string;
24
- }
25
- export declare function readJsonWithLibreDwg(file: string, opts?: {
26
- toolDir?: string;
27
- }): LibreDwgJsonResult;
28
- export declare function renderSvgWithLibreDwg(file: string, opts?: {
29
- toolDir?: string;
30
- }): LibreDwgViewResult;
31
- export declare function editWithLibreDwgFilter(opts: {
32
- input: string;
33
- output: string;
34
- expression: string;
35
- overwrite?: boolean;
36
- toolDir?: string;
37
- }): LibreDwgEditResult;
@@ -1,86 +0,0 @@
1
- import { spawnSync } from "node:child_process";
2
- import { copyFileSync, existsSync } from "node:fs";
3
- import { basename, delimiter, join } from "node:path";
4
- import { EXIT_ERROR, EXIT_UNAVAILABLE, EXIT_USER_ERROR, } from "../utils/exit-codes.js";
5
- import { DwgCliError } from "./errors.js";
6
- const WINDOWS_EXTENSIONS = [".exe", ".cmd", ".bat", ".com"];
7
- function candidateNames(tool) {
8
- return [tool, ...WINDOWS_EXTENSIONS.map((ext) => `${tool}${ext}`)];
9
- }
10
- function findTool(tool, toolDir) {
11
- const dirs = toolDir ? [toolDir] : (process.env.PATH ?? "").split(delimiter);
12
- for (const dir of dirs.filter(Boolean)) {
13
- for (const name of candidateNames(tool)) {
14
- const candidate = join(dir, name);
15
- if (existsSync(candidate))
16
- return candidate;
17
- }
18
- }
19
- return undefined;
20
- }
21
- function requireTool(tool, toolDir) {
22
- const path = findTool(tool, toolDir);
23
- if (path)
24
- return path;
25
- throw new DwgCliError(`LibreDWG tool not found: ${tool}. Install LibreDWG and make sure ${tool} is on PATH.`, "LIBREDWG_TOOL_NOT_FOUND", EXIT_UNAVAILABLE);
26
- }
27
- function preview(value) {
28
- const trimmed = value.trim();
29
- if (trimmed.length <= 500)
30
- return trimmed;
31
- return `${trimmed.slice(0, 500)}…`;
32
- }
33
- function runLibreDwgTool(tool, args, toolDir) {
34
- const path = requireTool(tool, toolDir);
35
- const result = spawnSync(path, args, { encoding: "utf-8" });
36
- if (result.error) {
37
- throw new DwgCliError(`Could not run ${tool}: ${result.error.message}`, "LIBREDWG_RUN_FAILED", EXIT_ERROR);
38
- }
39
- if (result.status !== 0) {
40
- const details = preview(result.stderr || result.stdout);
41
- throw new DwgCliError(`${tool} failed for ${basename(args.at(-1) ?? "input")}${details ? `: ${details}` : ""}`, "LIBREDWG_RUN_FAILED", EXIT_USER_ERROR);
42
- }
43
- return { stdout: result.stdout, stderr: result.stderr };
44
- }
45
- export function readJsonWithLibreDwg(file, opts = {}) {
46
- const result = runLibreDwgTool("dwgread", ["-O", "JSON", file], opts.toolDir);
47
- try {
48
- return {
49
- input: file,
50
- json: JSON.parse(result.stdout),
51
- backend: "LibreDWG",
52
- tool: "dwgread",
53
- stderr: result.stderr,
54
- };
55
- }
56
- catch (error) {
57
- const details = preview(result.stdout);
58
- throw new DwgCliError(`dwgread produced invalid JSON for ${basename(file)}: ${error.message}${details ? `; stdout: ${details}` : ""}`, "LIBREDWG_INVALID_JSON", EXIT_USER_ERROR);
59
- }
60
- }
61
- export function renderSvgWithLibreDwg(file, opts = {}) {
62
- const result = runLibreDwgTool("dwgread", ["-O", "SVG", file], opts.toolDir);
63
- return {
64
- input: file,
65
- svg: result.stdout,
66
- backend: "LibreDWG",
67
- tool: "dwgread",
68
- stderr: result.stderr,
69
- };
70
- }
71
- export function editWithLibreDwgFilter(opts) {
72
- if (opts.input === opts.output && !opts.overwrite) {
73
- throw new DwgCliError("Refusing to edit in place without --overwrite. Provide --output or pass --overwrite.", "EDIT_REQUIRES_OUTPUT_OR_OVERWRITE", EXIT_USER_ERROR);
74
- }
75
- if (opts.input !== opts.output)
76
- copyFileSync(opts.input, opts.output);
77
- const result = runLibreDwgTool("dwgfilter", ["-i", opts.expression, opts.output], opts.toolDir);
78
- return {
79
- input: opts.input,
80
- output: opts.output,
81
- expression: opts.expression,
82
- backend: "LibreDWG",
83
- tool: "dwgfilter",
84
- stderr: result.stderr,
85
- };
86
- }