@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.
- package/README.md +70 -14
- package/dist/commands/edit.d.ts +42 -2
- package/dist/commands/edit.js +281 -7
- package/dist/commands/json.js +0 -1
- package/dist/commands/query.d.ts +7 -0
- package/dist/commands/query.js +45 -0
- package/dist/commands/shared.d.ts +0 -1
- package/dist/commands/shared.js +0 -1
- package/dist/commands/svg.js +0 -1
- package/dist/commands/thumbnail.js +0 -1
- package/dist/commands/view.d.ts +0 -1
- package/dist/commands/view.js +5 -7
- package/dist/core/acad-edit.d.ts +142 -0
- package/dist/core/acad-edit.js +234 -0
- package/dist/core/acad-view.d.ts +6 -0
- package/dist/core/acad-view.js +22 -0
- package/dist/core/acad.d.ts +11 -0
- package/dist/core/acad.js +82 -0
- package/dist/core/adapter.d.ts +0 -6
- package/dist/core/adapter.js +16 -14
- package/dist/core/drawing.d.ts +0 -1
- package/dist/core/drawing.js +2 -1
- package/dist/core/normalize.js +4 -1
- package/dist/core/query.d.ts +17 -0
- package/dist/core/query.js +232 -0
- package/dist/core/text-normalize.d.ts +3 -0
- package/dist/core/text-normalize.js +104 -0
- package/dist/index.d.ts +2 -1
- package/dist/main.js +98 -7
- package/dist/sdk.d.ts +5 -7
- package/dist/sdk.js +6 -6
- package/dist/types.d.ts +9 -0
- package/package.json +2 -2
- package/skills/cadcli/SKILL.md +50 -9
- package/dist/core/libredwg.d.ts +0 -37
- package/dist/core/libredwg.js +0 -86
package/skills/cadcli/SKILL.md
CHANGED
|
@@ -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
|
|
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.
|
|
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
|
|
14
|
-
cadcli
|
|
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
|
|
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,
|
|
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
|
|
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`.
|
package/dist/core/libredwg.d.ts
DELETED
|
@@ -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;
|
package/dist/core/libredwg.js
DELETED
|
@@ -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
|
-
}
|