@ifc-lite/mcp 0.2.0 → 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/dist/prompts/templates.d.ts.map +1 -1
- package/dist/prompts/templates.js +13 -3
- package/dist/prompts/templates.js.map +1 -1
- package/dist/safe-path.d.ts +18 -0
- package/dist/safe-path.d.ts.map +1 -0
- package/dist/safe-path.js +172 -0
- package/dist/safe-path.js.map +1 -0
- package/dist/tools/bcf.d.ts.map +1 -1
- package/dist/tools/bcf.js +2 -11
- package/dist/tools/bcf.js.map +1 -1
- package/dist/tools/clash.d.ts +3 -0
- package/dist/tools/clash.d.ts.map +1 -0
- package/dist/tools/clash.js +209 -0
- package/dist/tools/clash.js.map +1 -0
- package/dist/tools/discovery.d.ts.map +1 -1
- package/dist/tools/discovery.js +10 -2
- package/dist/tools/discovery.js.map +1 -1
- package/dist/tools/export.d.ts.map +1 -1
- package/dist/tools/export.js +4 -18
- package/dist/tools/export.js.map +1 -1
- package/dist/tools/geometry.d.ts.map +1 -1
- package/dist/tools/geometry.js +3 -24
- package/dist/tools/geometry.js.map +1 -1
- package/dist/tools/ids-accessor.d.ts +3 -4
- package/dist/tools/ids-accessor.d.ts.map +1 -1
- package/dist/tools/ids-accessor.js +2 -125
- package/dist/tools/ids-accessor.js.map +1 -1
- package/dist/tools/index.d.ts +2 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +3 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/mutate.d.ts.map +1 -1
- package/dist/tools/mutate.js +2 -11
- package/dist/tools/mutate.js.map +1 -1
- package/dist/tools/validation.d.ts.map +1 -1
- package/dist/tools/validation.js +5 -14
- package/dist/tools/validation.js.map +1 -1
- package/package.json +19 -17
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/prompts/templates.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAUzC,eAAO,MAAM,UAAU,EAAE,MAuBxB,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,MAsBhC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,MAqBhC,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAkB7B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,MAgB/B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/prompts/templates.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAUzC,eAAO,MAAM,UAAU,EAAE,MAuBxB,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,MAsBhC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,MAqBhC,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAkB7B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,MAgB/B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,MAqBzB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAkB7B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,MAiB3B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,MAqBzB,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,MAkBxC,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,MAuB5B,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,MAAM,EAY9B,CAAC"}
|
|
@@ -112,12 +112,22 @@ export const spaceProgramCheck = {
|
|
|
112
112
|
};
|
|
113
113
|
export const clashReview = {
|
|
114
114
|
name: 'clash_review',
|
|
115
|
-
description: 'Run
|
|
116
|
-
|
|
115
|
+
description: 'Run the discipline clash matrix, group by trade, prioritize by severity.',
|
|
116
|
+
arguments: [
|
|
117
|
+
{ name: 'mode', description: 'Clash mode: hard (interpenetration) or clearance (gap).', required: false },
|
|
118
|
+
],
|
|
119
|
+
render(args) {
|
|
120
|
+
const mode = args.mode ?? 'hard';
|
|
117
121
|
return {
|
|
118
122
|
description: 'Clash review',
|
|
119
123
|
messages: [
|
|
120
|
-
|
|
124
|
+
systemMessage('You are a BIM coordination lead triaging clash results.'),
|
|
125
|
+
userMessage([
|
|
126
|
+
`Run \`clash_matrix\` (mode="${mode}") on the model.`,
|
|
127
|
+
'Summarize the byRule and bySeverity breakdowns, then produce a top-20 priority list ordered by severity and |distance|.',
|
|
128
|
+
'For any discipline pair you want to drill into, follow up with `clash_check` using the two TYPE selectors (e.g. a="IfcDuct*|IfcPipe*", b="IfcWall*").',
|
|
129
|
+
'Always state the display cap and how many clashes were not shown.',
|
|
130
|
+
].join('\n')),
|
|
121
131
|
],
|
|
122
132
|
};
|
|
123
133
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/prompts/templates.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/prompts/templates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ModelRegistry, ServerConfig } from './context.js';
|
|
2
|
+
interface PathContext {
|
|
3
|
+
config: Pick<ServerConfig, 'allowedPaths'>;
|
|
4
|
+
registry: Pick<ModelRegistry, 'list'>;
|
|
5
|
+
}
|
|
6
|
+
export type PathMode = 'read' | 'write';
|
|
7
|
+
/**
|
|
8
|
+
* Validate and canonicalise a path supplied by an MCP tool caller.
|
|
9
|
+
*
|
|
10
|
+
* - `mode === 'read'`: the file must exist; its realpath must land in an
|
|
11
|
+
* allowed root.
|
|
12
|
+
* - `mode === 'write'`: the file may not exist yet. The realpath of the
|
|
13
|
+
* closest existing ancestor is used for the bounds check, then the missing
|
|
14
|
+
* tail is reattached.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveSafePath(raw: unknown, ctx: PathContext, mode: PathMode): Promise<string>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=safe-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-path.d.ts","sourceRoot":"","sources":["../src/safe-path.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGhE,UAAU,WAAW;IACnB,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IAC3C,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;CACvC;AAqBD,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAExC;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,QAAQ,GACb,OAAO,CAAC,MAAM,CAAC,CAejB"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/**
|
|
5
|
+
* Safe path resolution for LLM-supplied file paths.
|
|
6
|
+
*
|
|
7
|
+
* Every tool that reads from or writes to a path passed in by the LLM should
|
|
8
|
+
* route through `resolveSafePath`. The helper:
|
|
9
|
+
*
|
|
10
|
+
* 1. Verifies the resolved absolute path falls inside an allowed root.
|
|
11
|
+
* - When the operator passed `--allow <dir>` flags, those are the only
|
|
12
|
+
* roots. This is the strict mode for production deployments.
|
|
13
|
+
* - Otherwise a "sensible workspace" default is used: the directories
|
|
14
|
+
* of currently-loaded models, the operator's working directory, and
|
|
15
|
+
* `os.tmpdir()`. This keeps the OOTB experience usable without
|
|
16
|
+
* defaulting to the whole filesystem.
|
|
17
|
+
* 2. Follows symlinks (via realpath) and re-checks the canonical target
|
|
18
|
+
* against the allowlist — a link sitting in an allowed directory
|
|
19
|
+
* cannot redirect to arbitrary locations.
|
|
20
|
+
* 3. Refuses paths that land in a small fixed list of sensitive
|
|
21
|
+
* $HOME subdirectories (credentials stores), regardless of how the
|
|
22
|
+
* allowlist is configured.
|
|
23
|
+
*/
|
|
24
|
+
import { realpath } from 'node:fs/promises';
|
|
25
|
+
import { homedir, tmpdir } from 'node:os';
|
|
26
|
+
import { basename, dirname, resolve, sep } from 'node:path';
|
|
27
|
+
import { ToolErrorCode, ToolExecutionError } from './errors.js';
|
|
28
|
+
/**
|
|
29
|
+
* Top-level entries under $HOME we always refuse, even when other guards
|
|
30
|
+
* would allow them. Credentials and key material live here; legitimate tool
|
|
31
|
+
* workflows almost never need to touch them.
|
|
32
|
+
*/
|
|
33
|
+
const SENSITIVE_HOME_ENTRIES = new Set([
|
|
34
|
+
'.ssh',
|
|
35
|
+
'.aws',
|
|
36
|
+
'.gnupg',
|
|
37
|
+
'.gpg',
|
|
38
|
+
'.kube',
|
|
39
|
+
'.docker',
|
|
40
|
+
'.gcloud',
|
|
41
|
+
'.azure',
|
|
42
|
+
'.npmrc',
|
|
43
|
+
'.netrc',
|
|
44
|
+
'.pgpass',
|
|
45
|
+
]);
|
|
46
|
+
/**
|
|
47
|
+
* Validate and canonicalise a path supplied by an MCP tool caller.
|
|
48
|
+
*
|
|
49
|
+
* - `mode === 'read'`: the file must exist; its realpath must land in an
|
|
50
|
+
* allowed root.
|
|
51
|
+
* - `mode === 'write'`: the file may not exist yet. The realpath of the
|
|
52
|
+
* closest existing ancestor is used for the bounds check, then the missing
|
|
53
|
+
* tail is reattached.
|
|
54
|
+
*/
|
|
55
|
+
export async function resolveSafePath(raw, ctx, mode) {
|
|
56
|
+
if (typeof raw !== 'string' || raw.length === 0) {
|
|
57
|
+
throw new ToolExecutionError({
|
|
58
|
+
code: ToolErrorCode.INVALID_INPUT,
|
|
59
|
+
message: 'file_path must be a non-empty string',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
const requested = resolve(raw);
|
|
63
|
+
const roots = await buildAllowedRoots(ctx);
|
|
64
|
+
rejectIfSensitiveHome(requested);
|
|
65
|
+
ensureWithinRoots(requested, roots);
|
|
66
|
+
const canonical = await canonicalise(requested, mode);
|
|
67
|
+
rejectIfSensitiveHome(canonical);
|
|
68
|
+
ensureWithinRoots(canonical, roots);
|
|
69
|
+
return canonical;
|
|
70
|
+
}
|
|
71
|
+
async function buildAllowedRoots(ctx) {
|
|
72
|
+
const raw = new Set();
|
|
73
|
+
for (const p of ctx.config.allowedPaths ?? []) {
|
|
74
|
+
raw.add(resolve(p));
|
|
75
|
+
}
|
|
76
|
+
if (raw.size === 0) {
|
|
77
|
+
for (const m of ctx.registry.list()) {
|
|
78
|
+
if (m.filePath)
|
|
79
|
+
raw.add(dirname(m.filePath));
|
|
80
|
+
}
|
|
81
|
+
raw.add(resolve(process.cwd()));
|
|
82
|
+
raw.add(resolve(tmpdir()));
|
|
83
|
+
}
|
|
84
|
+
// Include both the configured form and its realpath. The bounds check
|
|
85
|
+
// runs first against the requested path (configured form) and then
|
|
86
|
+
// against its realpath (canonical form); covering both shapes here
|
|
87
|
+
// ensures a symlinked root (e.g. --allow /workspace where /workspace is
|
|
88
|
+
// itself a symlink) still accepts files that legitimately live inside.
|
|
89
|
+
const roots = new Set(raw);
|
|
90
|
+
for (const root of raw) {
|
|
91
|
+
try {
|
|
92
|
+
roots.add(await realpath(root));
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
/* root does not yet exist on disk; the configured form stays in. */
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return [...roots];
|
|
99
|
+
}
|
|
100
|
+
function ensureWithinRoots(absolute, roots) {
|
|
101
|
+
if (roots.length === 0) {
|
|
102
|
+
throw new ToolExecutionError({
|
|
103
|
+
code: ToolErrorCode.PERMISSION_DENIED,
|
|
104
|
+
message: 'No allowed roots configured; pass --allow <dir> or load a model first.',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
const ok = roots.some((root) => absolute === root || absolute.startsWith(root + sep));
|
|
108
|
+
if (!ok) {
|
|
109
|
+
throw new ToolExecutionError({
|
|
110
|
+
code: ToolErrorCode.PERMISSION_DENIED,
|
|
111
|
+
message: `Path '${absolute}' is outside allowed roots`,
|
|
112
|
+
details: { roots },
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function rejectIfSensitiveHome(absolute) {
|
|
117
|
+
const home = resolve(homedir());
|
|
118
|
+
if (absolute !== home && !absolute.startsWith(home + sep))
|
|
119
|
+
return;
|
|
120
|
+
const rest = absolute === home ? '' : absolute.slice(home.length + 1);
|
|
121
|
+
if (rest.length === 0)
|
|
122
|
+
return;
|
|
123
|
+
const first = rest.split(sep)[0];
|
|
124
|
+
if (first && SENSITIVE_HOME_ENTRIES.has(first)) {
|
|
125
|
+
throw new ToolExecutionError({
|
|
126
|
+
code: ToolErrorCode.PERMISSION_DENIED,
|
|
127
|
+
message: `Refusing to access '${absolute}': sensitive home entry '${first}'`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function canonicalise(p, mode) {
|
|
132
|
+
try {
|
|
133
|
+
return await realpath(p);
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
if (err.code !== 'ENOENT')
|
|
137
|
+
throw err;
|
|
138
|
+
}
|
|
139
|
+
if (mode === 'read') {
|
|
140
|
+
throw new ToolExecutionError({
|
|
141
|
+
code: ToolErrorCode.INVALID_INPUT,
|
|
142
|
+
message: `Path '${p}' does not exist`,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
// Write target: walk up until we find an existing ancestor, realpath it,
|
|
146
|
+
// then reattach the missing tail. This catches symlinks anywhere along
|
|
147
|
+
// the existing portion of the path. We use basename() for each segment
|
|
148
|
+
// so the logic stays correct when an ancestor is the filesystem root
|
|
149
|
+
// (where slice-by-length arithmetic would be off by one).
|
|
150
|
+
let cursor = dirname(p);
|
|
151
|
+
const tail = [basename(p)];
|
|
152
|
+
while (true) {
|
|
153
|
+
try {
|
|
154
|
+
const real = await realpath(cursor);
|
|
155
|
+
return resolve(real, ...tail);
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
if (err.code !== 'ENOENT')
|
|
159
|
+
throw err;
|
|
160
|
+
}
|
|
161
|
+
const parent = dirname(cursor);
|
|
162
|
+
if (parent === cursor) {
|
|
163
|
+
throw new ToolExecutionError({
|
|
164
|
+
code: ToolErrorCode.INVALID_INPUT,
|
|
165
|
+
message: `Path '${p}' has no existing ancestor`,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
tail.unshift(basename(cursor));
|
|
169
|
+
cursor = parent;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=safe-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-path.js","sourceRoot":"","sources":["../src/safe-path.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/bcf.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bcf.d.ts","sourceRoot":"","sources":["../../src/tools/bcf.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bcf.d.ts","sourceRoot":"","sources":["../../src/tools/bcf.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAiMvC,eAAO,MAAM,QAAQ,EAAE,IAAI,EAAiG,CAAC"}
|
package/dist/tools/bcf.js
CHANGED
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
* single .bcfzip via `bcf_export`.
|
|
11
11
|
*/
|
|
12
12
|
import { writeFile } from 'node:fs/promises';
|
|
13
|
-
import { resolve } from 'node:path';
|
|
14
13
|
import { addCommentToTopic, addTopicToProject, addViewpointToTopic, createBCFComment, createBCFProject, createBCFTopic, updateTopicStatus, writeBCF, } from '@ifc-lite/bcf';
|
|
15
14
|
import { okResult } from './util.js';
|
|
16
15
|
import { ToolErrorCode, ToolExecutionError } from '../errors.js';
|
|
16
|
+
import { resolveSafePath } from '../safe-path.js';
|
|
17
17
|
// One project per server instance. We keep it on a module-level Map keyed by
|
|
18
18
|
// session — for stdio that's exactly one entry; for HTTP each session gets
|
|
19
19
|
// its own server, so this naturally scopes per-session.
|
|
@@ -180,16 +180,7 @@ const bcfExport = {
|
|
|
180
180
|
},
|
|
181
181
|
async handler(input, ctx) {
|
|
182
182
|
const project = getProject(ctx.registry);
|
|
183
|
-
const filePath =
|
|
184
|
-
if (ctx.config.allowedPaths && ctx.config.allowedPaths.length > 0) {
|
|
185
|
-
const ok = ctx.config.allowedPaths.some((p) => filePath === p || filePath.startsWith(p + '/'));
|
|
186
|
-
if (!ok) {
|
|
187
|
-
throw new ToolExecutionError({
|
|
188
|
-
code: ToolErrorCode.PERMISSION_DENIED,
|
|
189
|
-
message: `Path '${filePath}' outside allowed roots`,
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
}
|
|
183
|
+
const filePath = await resolveSafePath(input.file_path, ctx, 'write');
|
|
193
184
|
const blob = (await writeBCF(project));
|
|
194
185
|
const buffer = Buffer.from(await blob.arrayBuffer());
|
|
195
186
|
await writeFile(filePath, buffer);
|
package/dist/tools/bcf.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bcf.js","sourceRoot":"","sources":["../../src/tools/bcf.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,
|
|
1
|
+
{"version":3,"file":"bcf.js","sourceRoot":"","sources":["../../src/tools/bcf.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clash.d.ts","sourceRoot":"","sources":["../../src/tools/clash.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAkNvC,eAAO,MAAM,UAAU,EAAE,IAAI,EAA8B,CAAC"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/**
|
|
5
|
+
* Clash detection tools (spec section 7.3).
|
|
6
|
+
*
|
|
7
|
+
* These wire the headless geometry pipeline (@ifc-lite/geometry) to the
|
|
8
|
+
* representation-agnostic clash engine (@ifc-lite/clash). The whole model is
|
|
9
|
+
* meshed once and cached by model id; the engine's rule SELECTORS (TYPE-based,
|
|
10
|
+
* e.g. `IfcDuct*|IfcPipe*`) pick the element groups for each run.
|
|
11
|
+
*
|
|
12
|
+
* - clash_check one ad-hoc rule: A vs B, a self-clash within A, or — with no
|
|
13
|
+
* selectors at all — ALL clashes in the model (every element
|
|
14
|
+
* vs every other, no discipline matrix needed).
|
|
15
|
+
* - clash_matrix the standard discipline matrix (MEP x STR, HVAC x ARCH, ...).
|
|
16
|
+
*
|
|
17
|
+
* Clash lists are always capped for display; the cap and the dropped count are
|
|
18
|
+
* stated explicitly so output never silently truncates.
|
|
19
|
+
*/
|
|
20
|
+
import { readFile } from 'node:fs/promises';
|
|
21
|
+
import { GeometryProcessor } from '@ifc-lite/geometry';
|
|
22
|
+
import { createClashEngine, disciplineMatrixRules, } from '@ifc-lite/clash';
|
|
23
|
+
import { elementsFromStep } from '@ifc-lite/clash/step';
|
|
24
|
+
import { okResult, resolveModel } from './util.js';
|
|
25
|
+
import { ToolErrorCode, ToolExecutionError } from '../errors.js';
|
|
26
|
+
/** Cap on clashes returned in a tool result. The dropped count is reported. */
|
|
27
|
+
const CLASH_DISPLAY_CAP = 50;
|
|
28
|
+
/**
|
|
29
|
+
* Module-level mesh cache, keyed by model id, so repeated clash calls on the
|
|
30
|
+
* same model don't re-run the (expensive) headless tessellation.
|
|
31
|
+
*/
|
|
32
|
+
const meshCache = new Map();
|
|
33
|
+
/** Mesh the whole model once (headless, no DOM) and cache by model id. */
|
|
34
|
+
async function meshModel(m, ctx) {
|
|
35
|
+
const cached = meshCache.get(m.id);
|
|
36
|
+
if (cached)
|
|
37
|
+
return cached;
|
|
38
|
+
const bytes = await resolveIfcBytes(m);
|
|
39
|
+
ctx.progress.report(0.1, 'Tessellating model geometry', 1);
|
|
40
|
+
const gp = new GeometryProcessor();
|
|
41
|
+
await gp.init();
|
|
42
|
+
if (ctx.signal.aborted) {
|
|
43
|
+
throw new ToolExecutionError({ code: ToolErrorCode.INTERNAL_ERROR, message: 'Clash run cancelled before meshing.' });
|
|
44
|
+
}
|
|
45
|
+
const result = await gp.process(bytes);
|
|
46
|
+
const meshes = result.meshes;
|
|
47
|
+
if (meshes.length === 0) {
|
|
48
|
+
throw new ToolExecutionError({
|
|
49
|
+
code: ToolErrorCode.UNSUPPORTED_OPERATION,
|
|
50
|
+
message: 'No mesh geometry could be produced for this model; clash detection needs tessellated solids.',
|
|
51
|
+
hint: 'Confirm the model carries explicit geometry (not quantity-only data).',
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
meshCache.set(m.id, meshes);
|
|
55
|
+
return meshes;
|
|
56
|
+
}
|
|
57
|
+
/** Raw IFC bytes for meshing: prefer the in-memory source, fall back to disk. */
|
|
58
|
+
async function resolveIfcBytes(m) {
|
|
59
|
+
if (m.store.source && m.store.source.byteLength > 0)
|
|
60
|
+
return m.store.source;
|
|
61
|
+
if (m.filePath)
|
|
62
|
+
return readFile(m.filePath);
|
|
63
|
+
throw new ToolExecutionError({
|
|
64
|
+
code: ToolErrorCode.UNSUPPORTED_OPERATION,
|
|
65
|
+
message: 'Model has no in-memory source bytes and no file path to re-read for meshing.',
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/** Run a rule set against a model, returning the engine result. */
|
|
69
|
+
async function runRules(m, rules, ctx) {
|
|
70
|
+
const meshes = await meshModel(m, ctx);
|
|
71
|
+
const { elements, exclusions } = elementsFromStep({ store: m.store, meshes, modelId: m.id });
|
|
72
|
+
const engine = createClashEngine({ backend: 'ts' });
|
|
73
|
+
return engine.run(elements, rules, {
|
|
74
|
+
exclusions,
|
|
75
|
+
signal: ctx.signal,
|
|
76
|
+
onProgress: (p) => {
|
|
77
|
+
const ratio = p.total > 0 ? p.done / p.total : 0;
|
|
78
|
+
ctx.progress.report(0.2 + ratio * 0.8, `Clash ${p.phase}: ${p.rule} (${p.done}/${p.total})`, 1);
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/** Project a `Clash` down to a compact, JSON-friendly display row. */
|
|
83
|
+
function displayClash(c) {
|
|
84
|
+
return {
|
|
85
|
+
id: c.id,
|
|
86
|
+
rule: c.rule,
|
|
87
|
+
status: c.status,
|
|
88
|
+
severity: c.severity,
|
|
89
|
+
distance: c.distance,
|
|
90
|
+
point: c.point,
|
|
91
|
+
a: { key: c.a.key, ref: c.a.ref, tag: c.a.tag, name: c.a.name },
|
|
92
|
+
b: { key: c.b.key, ref: c.b.ref, tag: c.b.tag, name: c.b.name },
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Top clashes by signed distance (deepest penetration / smallest gap first),
|
|
97
|
+
* capped for display. Returns the rows plus an explicit `truncated` note when
|
|
98
|
+
* capped.
|
|
99
|
+
*
|
|
100
|
+
* Sort by RAW distance ascending, not |distance|: hard clashes carry a negative
|
|
101
|
+
* penetration depth, so most-negative-first surfaces the DEEPEST penetrations
|
|
102
|
+
* (the worst, most actionable rows) instead of burying them past the cap;
|
|
103
|
+
* clearance/touch gaps are positive, so the same order surfaces the tightest
|
|
104
|
+
* gaps first. (An |distance| sort inverted the hard-mode order — issue caught in
|
|
105
|
+
* review.)
|
|
106
|
+
*/
|
|
107
|
+
function topClashes(clashes, cap) {
|
|
108
|
+
const sorted = [...clashes].sort((x, y) => x.distance - y.distance);
|
|
109
|
+
const shown = sorted.slice(0, cap);
|
|
110
|
+
const rows = shown.map(displayClash);
|
|
111
|
+
if (sorted.length > cap) {
|
|
112
|
+
return { rows, truncated: { shown: shown.length, dropped: sorted.length - shown.length, total: sorted.length } };
|
|
113
|
+
}
|
|
114
|
+
return { rows, truncated: null };
|
|
115
|
+
}
|
|
116
|
+
const clashCheck = {
|
|
117
|
+
name: 'clash_check',
|
|
118
|
+
description: 'Clash detection on a single model. Omit BOTH a and b to detect ALL clashes inside the model '
|
|
119
|
+
+ '(every element vs every other — no discipline matrix needed). Give only a TYPE selector for a to '
|
|
120
|
+
+ 'self-clash within a group (a="IfcDuct*"), or both a and b for a pairwise check (a="IfcDuct*", b="IfcWall*"). '
|
|
121
|
+
+ 'Meshes the model headlessly and returns a summary plus the top clashes by |distance|.',
|
|
122
|
+
scope: 'read',
|
|
123
|
+
inputSchema: {
|
|
124
|
+
type: 'object',
|
|
125
|
+
properties: {
|
|
126
|
+
model_id: { type: 'string' },
|
|
127
|
+
a: { type: 'string', description: 'Type selector for set A. Defaults to "*" (all elements). e.g. "IfcDuct*|IfcPipe*", "!IfcSpace".' },
|
|
128
|
+
b: { type: 'string', description: 'Type selector for set B. OMIT for a self-clash within A (every element vs every other in the group).' },
|
|
129
|
+
mode: { type: 'string', enum: ['hard', 'clearance'], default: 'hard' },
|
|
130
|
+
tolerance: { type: 'number', description: 'Touching band (m). Defaults to the engine tolerance.' },
|
|
131
|
+
clearance: { type: 'number', description: 'Required gap (m) for mode="clearance".' },
|
|
132
|
+
},
|
|
133
|
+
additionalProperties: false,
|
|
134
|
+
},
|
|
135
|
+
async handler(input, ctx) {
|
|
136
|
+
const m = resolveModel(ctx, input.model_id);
|
|
137
|
+
const a = input.a ?? '*';
|
|
138
|
+
const b = input.b;
|
|
139
|
+
const mode = input.mode ?? 'hard';
|
|
140
|
+
const tolerance = input.tolerance;
|
|
141
|
+
const clearance = input.clearance;
|
|
142
|
+
// No `b` => self-clash within A (every element vs every other in the group);
|
|
143
|
+
// with the default a="*" that is "all clashes in the model".
|
|
144
|
+
const label = b ? `${a} vs ${b}` : a === '*' ? 'all elements (self-clash)' : `${a} (self-clash)`;
|
|
145
|
+
const rule = {
|
|
146
|
+
id: 'clash_check',
|
|
147
|
+
name: label,
|
|
148
|
+
a,
|
|
149
|
+
...(b != null ? { b } : {}),
|
|
150
|
+
mode,
|
|
151
|
+
...(tolerance != null ? { tolerance } : {}),
|
|
152
|
+
...(clearance != null ? { clearance } : {}),
|
|
153
|
+
};
|
|
154
|
+
const result = await runRules(m, [rule], ctx);
|
|
155
|
+
const { rows, truncated } = topClashes(result.clashes, CLASH_DISPLAY_CAP);
|
|
156
|
+
const settings = { a, b: b ?? null, mode, tolerance: tolerance ?? null, clearance: clearance ?? null };
|
|
157
|
+
const capNote = truncated
|
|
158
|
+
? ` Showing top ${truncated.shown} by |distance|; ${truncated.dropped} more not shown.`
|
|
159
|
+
: '';
|
|
160
|
+
return okResult(`Found ${result.summary.total} clash(es) for ${label} (mode=${mode}).${capNote}`, {
|
|
161
|
+
summary: result.summary,
|
|
162
|
+
settings,
|
|
163
|
+
engineSettings: result.settings,
|
|
164
|
+
truncated: result.truncated ?? null,
|
|
165
|
+
clashes: rows,
|
|
166
|
+
clashesTruncated: truncated,
|
|
167
|
+
});
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
const clashMatrix = {
|
|
171
|
+
name: 'clash_matrix',
|
|
172
|
+
description: 'Run the standard discipline clash matrix (MEP x STR, HVAC x ARCH, ...) over the whole model. '
|
|
173
|
+
+ 'Returns per-rule and per-severity breakdowns plus a sample of the worst clashes.',
|
|
174
|
+
scope: 'read',
|
|
175
|
+
inputSchema: {
|
|
176
|
+
type: 'object',
|
|
177
|
+
properties: {
|
|
178
|
+
model_id: { type: 'string' },
|
|
179
|
+
mode: { type: 'string', enum: ['hard', 'clearance'], default: 'hard' },
|
|
180
|
+
clearance: { type: 'number', description: 'Required gap (m) applied to every matrix rule when mode="clearance". Without it a clearance matrix reports nothing.' },
|
|
181
|
+
},
|
|
182
|
+
additionalProperties: false,
|
|
183
|
+
},
|
|
184
|
+
async handler(input, ctx) {
|
|
185
|
+
const m = resolveModel(ctx, input.model_id);
|
|
186
|
+
const mode = input.mode ?? 'hard';
|
|
187
|
+
const clearance = input.clearance;
|
|
188
|
+
const rules = disciplineMatrixRules(mode, clearance);
|
|
189
|
+
const result = await runRules(m, rules, ctx);
|
|
190
|
+
const { rows, truncated } = topClashes(result.clashes, CLASH_DISPLAY_CAP);
|
|
191
|
+
const capNote = truncated
|
|
192
|
+
? ` Sampling top ${truncated.shown} by |distance|; ${truncated.dropped} more not shown.`
|
|
193
|
+
: '';
|
|
194
|
+
return okResult(`Discipline matrix (mode=${mode}, ${rules.length} rules): ${result.summary.total} clash(es).${capNote}`, {
|
|
195
|
+
mode,
|
|
196
|
+
ruleCount: rules.length,
|
|
197
|
+
byRule: result.summary.byRule,
|
|
198
|
+
bySeverity: result.summary.bySeverity,
|
|
199
|
+
byTypePair: result.summary.byTypePair,
|
|
200
|
+
summary: result.summary,
|
|
201
|
+
engineSettings: result.settings,
|
|
202
|
+
truncated: result.truncated ?? null,
|
|
203
|
+
sampleClashes: rows,
|
|
204
|
+
sampleTruncated: truncated,
|
|
205
|
+
});
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
export const clashTools = [clashCheck, clashMatrix];
|
|
209
|
+
//# sourceMappingURL=clash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clash.js","sourceRoot":"","sources":["../../src/tools/clash.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/tools/discovery.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/tools/discovery.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAMvC,eAAO,MAAM,SAAS,EAAE,IAyCvB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,IAyBvB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,IAuCvB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,IAuBzB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,IA2C5B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,IAAI,EAMhC,CAAC"}
|
package/dist/tools/discovery.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { extractGeoreferencingOnDemand, extractLengthUnitScale, getAllAttributesForEntity, getEntityMetadata, getInheritanceChainForEntity, isKnownEntity, } from '@ifc-lite/parser';
|
|
11
11
|
import { resolveModel, okResult } from './util.js';
|
|
12
12
|
import { loadIfcModel } from '../loader.js';
|
|
13
|
+
import { resolveSafePath } from '../safe-path.js';
|
|
13
14
|
import { ToolErrorCode, ToolExecutionError } from '../errors.js';
|
|
14
15
|
export const modelInfo = {
|
|
15
16
|
name: 'model_info',
|
|
@@ -88,17 +89,24 @@ export const modelLoad = {
|
|
|
88
89
|
additionalProperties: false,
|
|
89
90
|
},
|
|
90
91
|
async handler(input, ctx) {
|
|
91
|
-
|
|
92
|
+
// Resolve the LLM-supplied path through the safe-path policy first.
|
|
93
|
+
// The resulting absolute path is symlink-canonicalised and bounds-checked
|
|
94
|
+
// before we touch the filesystem in `loadIfcModel`.
|
|
95
|
+
const filePath = await resolveSafePath(input.file_path, ctx, 'read');
|
|
92
96
|
try {
|
|
93
97
|
const loaded = await loadIfcModel(filePath, {
|
|
94
98
|
modelId: input.model_id,
|
|
95
|
-
|
|
99
|
+
// Path was already validated; loader's secondary check would be a
|
|
100
|
+
// tautology, so pass a single-entry allowlist matching the file.
|
|
101
|
+
allowedPaths: [filePath],
|
|
96
102
|
});
|
|
97
103
|
ctx.registry.add(loaded);
|
|
98
104
|
ctx.log.log('info', 'model_load', { id: loaded.id, file: filePath, entities: loaded.store.entityCount });
|
|
99
105
|
return okResult(`Loaded '${loaded.name}' as model '${loaded.id}' (${loaded.store.entityCount.toLocaleString()} entities).`, { id: loaded.id, name: loaded.name, schema: loaded.store.schemaVersion, entityCount: loaded.store.entityCount });
|
|
100
106
|
}
|
|
101
107
|
catch (err) {
|
|
108
|
+
if (err instanceof ToolExecutionError)
|
|
109
|
+
throw err;
|
|
102
110
|
throw new ToolExecutionError({
|
|
103
111
|
code: ToolErrorCode.PARSE_FAILED,
|
|
104
112
|
message: `Failed to load '${filePath}': ${err.message}`,
|