@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.
Files changed (38) hide show
  1. package/dist/prompts/templates.d.ts.map +1 -1
  2. package/dist/prompts/templates.js +13 -3
  3. package/dist/prompts/templates.js.map +1 -1
  4. package/dist/safe-path.d.ts +18 -0
  5. package/dist/safe-path.d.ts.map +1 -0
  6. package/dist/safe-path.js +172 -0
  7. package/dist/safe-path.js.map +1 -0
  8. package/dist/tools/bcf.d.ts.map +1 -1
  9. package/dist/tools/bcf.js +2 -11
  10. package/dist/tools/bcf.js.map +1 -1
  11. package/dist/tools/clash.d.ts +3 -0
  12. package/dist/tools/clash.d.ts.map +1 -0
  13. package/dist/tools/clash.js +209 -0
  14. package/dist/tools/clash.js.map +1 -0
  15. package/dist/tools/discovery.d.ts.map +1 -1
  16. package/dist/tools/discovery.js +10 -2
  17. package/dist/tools/discovery.js.map +1 -1
  18. package/dist/tools/export.d.ts.map +1 -1
  19. package/dist/tools/export.js +4 -18
  20. package/dist/tools/export.js.map +1 -1
  21. package/dist/tools/geometry.d.ts.map +1 -1
  22. package/dist/tools/geometry.js +3 -24
  23. package/dist/tools/geometry.js.map +1 -1
  24. package/dist/tools/ids-accessor.d.ts +3 -4
  25. package/dist/tools/ids-accessor.d.ts.map +1 -1
  26. package/dist/tools/ids-accessor.js +2 -125
  27. package/dist/tools/ids-accessor.js.map +1 -1
  28. package/dist/tools/index.d.ts +2 -1
  29. package/dist/tools/index.d.ts.map +1 -1
  30. package/dist/tools/index.js +3 -1
  31. package/dist/tools/index.js.map +1 -1
  32. package/dist/tools/mutate.d.ts.map +1 -1
  33. package/dist/tools/mutate.js +2 -11
  34. package/dist/tools/mutate.js.map +1 -1
  35. package/dist/tools/validation.d.ts.map +1 -1
  36. package/dist/tools/validation.js +5 -14
  37. package/dist/tools/validation.js.map +1 -1
  38. 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,MAWzB,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"}
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 clash_check, group by trade, prioritize by severity.',
116
- render() {
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
- userMessage('Run `clash_check` on the model. Group results by IFC type pair (e.g. IfcWall × IfcDuct) and produce a top-20 priority list for review.'),
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":"AAAA;;+DAE+D;AAE/D;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAE5D,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAOhE;;;;GAIG;AACH,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC;IACrC,MAAM;IACN,MAAM;IACN,QAAQ;IACR,MAAM;IACN,OAAO;IACP,SAAS;IACT,SAAS;IACT,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,SAAS;CACV,CAAC,CAAC;AAIH;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAY,EACZ,GAAgB,EAChB,IAAc;IAEd,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,kBAAkB,CAAC;YAC3B,IAAI,EAAE,aAAa,CAAC,aAAa;YACjC,OAAO,EAAE,sCAAsC;SAChD,CAAC,CAAC;IACL,CAAC;IACD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAC3C,qBAAqB,CAAC,SAAS,CAAC,CAAC;IACjC,iBAAiB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACtD,qBAAqB,CAAC,SAAS,CAAC,CAAC;IACjC,iBAAiB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACpC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,GAAgB;IAC/C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,EAAE,CAAC;QAC9C,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IACD,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACnB,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YACpC,IAAI,CAAC,CAAC,QAAQ;gBAAE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC/C,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAChC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC7B,CAAC;IACD,sEAAsE;IACtE,mEAAmE;IACnE,mEAAmE;IACnE,wEAAwE;IACxE,uEAAuE;IACvE,MAAM,KAAK,GAAG,IAAI,GAAG,CAAS,GAAG,CAAC,CAAC;IACnC,KAAK,MAAM,IAAI,IAAI,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC;YACH,KAAK,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,oEAAoE;QACtE,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;AACpB,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAgB,EAAE,KAAe;IAC1D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,kBAAkB,CAAC;YAC3B,IAAI,EAAE,aAAa,CAAC,iBAAiB;YACrC,OAAO,EACL,wEAAwE;SAC3E,CAAC,CAAC;IACL,CAAC;IACD,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,CACnB,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,GAAG,GAAG,CAAC,CAC/D,CAAC;IACF,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,MAAM,IAAI,kBAAkB,CAAC;YAC3B,IAAI,EAAE,aAAa,CAAC,iBAAiB;YACrC,OAAO,EAAE,SAAS,QAAQ,4BAA4B;YACtD,OAAO,EAAE,EAAE,KAAK,EAAE;SACnB,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAAC,QAAgB;IAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAChC,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,GAAG,GAAG,CAAC;QAAE,OAAO;IAClE,MAAM,IAAI,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACtE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,KAAK,IAAI,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,kBAAkB,CAAC;YAC3B,IAAI,EAAE,aAAa,CAAC,iBAAiB;YACrC,OAAO,EAAE,uBAAuB,QAAQ,4BAA4B,KAAK,GAAG;SAC7E,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,CAAS,EAAE,IAAc;IACnD,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,GAAG,CAAC;IAClE,CAAC;IACD,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,IAAI,kBAAkB,CAAC;YAC3B,IAAI,EAAE,aAAa,CAAC,aAAa;YACjC,OAAO,EAAE,SAAS,CAAC,kBAAkB;SACtC,CAAC,CAAC;IACL,CAAC;IACD,yEAAyE;IACzE,uEAAuE;IACvE,uEAAuE;IACvE,qEAAqE;IACrE,0DAA0D;IAC1D,IAAI,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACxB,MAAM,IAAI,GAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACrC,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;YACpC,OAAO,OAAO,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,GAAG,CAAC;QAClE,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,MAAM,IAAI,kBAAkB,CAAC;gBAC3B,IAAI,EAAE,aAAa,CAAC,aAAa;gBACjC,OAAO,EAAE,SAAS,CAAC,4BAA4B;aAChD,CAAC,CAAC;QACL,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/B,MAAM,GAAG,MAAM,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"bcf.d.ts","sourceRoot":"","sources":["../../src/tools/bcf.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAyMvC,eAAO,MAAM,QAAQ,EAAE,IAAI,EAAiG,CAAC"}
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 = resolve(input.file_path);
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);
@@ -1 +1 @@
1
- {"version":3,"file":"bcf.js","sourceRoot":"","sources":["../../src/tools/bcf.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bcf.js","sourceRoot":"","sources":["../../src/tools/bcf.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Tool } from './types.js';
2
+ export declare const clashTools: Tool[];
3
+ //# sourceMappingURL=clash.d.ts.map
@@ -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":"AAAA;;+DAE+D;AAE/D;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAiB,MAAM,oBAAoB,CAAC;AACtE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,GAKtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGjE,+EAA+E;AAC/E,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAE7B;;;GAGG;AACH,MAAM,SAAS,GAAG,IAAI,GAAG,EAAsB,CAAC;AAEhD,0EAA0E;AAC1E,KAAK,UAAU,SAAS,CAAC,CAAc,EAAE,GAAgB;IACvD,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACnC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,CAAC,CAAC,CAAC;IACvC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,6BAA6B,EAAE,CAAC,CAAC,CAAC;IAC3D,MAAM,EAAE,GAAG,IAAI,iBAAiB,EAAE,CAAC;IACnC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;IAChB,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,kBAAkB,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,cAAc,EAAE,OAAO,EAAE,qCAAqC,EAAE,CAAC,CAAC;IACvH,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,kBAAkB,CAAC;YAC3B,IAAI,EAAE,aAAa,CAAC,qBAAqB;YACzC,OAAO,EAAE,8FAA8F;YACvG,IAAI,EAAE,uEAAuE;SAC9E,CAAC,CAAC;IACL,CAAC;IACD,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC5B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,iFAAiF;AACjF,KAAK,UAAU,eAAe,CAAC,CAAc;IAC3C,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;IAC3E,IAAI,CAAC,CAAC,QAAQ;QAAE,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,IAAI,kBAAkB,CAAC;QAC3B,IAAI,EAAE,aAAa,CAAC,qBAAqB;QACzC,OAAO,EAAE,8EAA8E;KACxF,CAAC,CAAC;AACL,CAAC;AAED,mEAAmE;AACnE,KAAK,UAAU,QAAQ,CAAC,CAAc,EAAE,KAAkB,EAAE,GAAgB;IAC1E,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACvC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,gBAAgB,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7F,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE;QACjC,UAAU;QACV,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE;YAChB,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACjD,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,EAAE,SAAS,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC;QAClG,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,sEAAsE;AACtE,SAAS,YAAY,CAAC,CAAQ;IAC5B,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;QAC/D,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;KAChE,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,UAAU,CAAC,OAAgB,EAAE,GAAW;IAI/C,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IACpE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACrC,IAAI,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QACxB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;IACnH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,GAAS;IACvB,IAAI,EAAE,aAAa;IACnB,WAAW,EACT,8FAA8F;UAC5F,mGAAmG;UACnG,+GAA+G;UAC/G,uFAAuF;IAC3F,KAAK,EAAE,MAAM;IACb,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC5B,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iGAAiG,EAAE;YACrI,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sGAAsG,EAAE;YAC1I,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE;YACtE,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sDAAsD,EAAE;YAClG,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,wCAAwC,EAAE;SACrF;QACD,oBAAoB,EAAE,KAAK;KAC5B;IACD,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;QACtB,MAAM,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,QAA8B,CAAC,CAAC;QAClE,MAAM,CAAC,GAAI,KAAK,CAAC,CAAwB,IAAI,GAAG,CAAC;QACjD,MAAM,CAAC,GAAG,KAAK,CAAC,CAAuB,CAAC;QACxC,MAAM,IAAI,GAAI,KAAK,CAAC,IAA8B,IAAI,MAAM,CAAC;QAC7D,MAAM,SAAS,GAAG,KAAK,CAAC,SAA+B,CAAC;QACxD,MAAM,SAAS,GAAG,KAAK,CAAC,SAA+B,CAAC;QACxD,6EAA6E;QAC7E,6DAA6D;QAC7D,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC;QAEjG,MAAM,IAAI,GAAc;YACtB,EAAE,EAAE,aAAa;YACjB,IAAI,EAAE,KAAK;YACX,CAAC;YACD,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3B,IAAI;YACJ,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3C,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5C,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QAC9C,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;QAE1E,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,IAAI,IAAI,EAAE,SAAS,EAAE,SAAS,IAAI,IAAI,EAAE,CAAC;QACvG,MAAM,OAAO,GAAG,SAAS;YACvB,CAAC,CAAC,gBAAgB,SAAS,CAAC,KAAK,mBAAmB,SAAS,CAAC,OAAO,kBAAkB;YACvF,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,QAAQ,CACb,SAAS,MAAM,CAAC,OAAO,CAAC,KAAK,kBAAkB,KAAK,UAAU,IAAI,KAAK,OAAO,EAAE,EAChF;YACE,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,QAAQ;YACR,cAAc,EAAE,MAAM,CAAC,QAAQ;YAC/B,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI;YACnC,OAAO,EAAE,IAAI;YACb,gBAAgB,EAAE,SAAS;SAC5B,CACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,MAAM,WAAW,GAAS;IACxB,IAAI,EAAE,cAAc;IACpB,WAAW,EACT,+FAA+F;UAC7F,kFAAkF;IACtF,KAAK,EAAE,MAAM;IACb,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC5B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE;YACtE,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,qHAAqH,EAAE;SAClK;QACD,oBAAoB,EAAE,KAAK;KAC5B;IACD,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;QACtB,MAAM,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,QAA8B,CAAC,CAAC;QAClE,MAAM,IAAI,GAAI,KAAK,CAAC,IAA8B,IAAI,MAAM,CAAC;QAC7D,MAAM,SAAS,GAAG,KAAK,CAAC,SAA+B,CAAC;QACxD,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAErD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QAC7C,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;QAE1E,MAAM,OAAO,GAAG,SAAS;YACvB,CAAC,CAAC,iBAAiB,SAAS,CAAC,KAAK,mBAAmB,SAAS,CAAC,OAAO,kBAAkB;YACxF,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,QAAQ,CACb,2BAA2B,IAAI,KAAK,KAAK,CAAC,MAAM,YAAY,MAAM,CAAC,OAAO,CAAC,KAAK,cAAc,OAAO,EAAE,EACvG;YACE,IAAI;YACJ,SAAS,EAAE,KAAK,CAAC,MAAM;YACvB,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM;YAC7B,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,UAAU;YACrC,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,UAAU;YACrC,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,cAAc,EAAE,MAAM,CAAC,QAAQ;YAC/B,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI;YACnC,aAAa,EAAE,IAAI;YACnB,eAAe,EAAE,SAAS;SAC3B,CACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAW,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC"}
@@ -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;AAKvC,eAAO,MAAM,SAAS,EAAE,IAyCvB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,IAyBvB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,IAiCvB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,IAuBzB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,IA2C5B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,IAAI,EAMhC,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"}
@@ -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
- const filePath = input.file_path;
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
- allowedPaths: ctx.config.allowedPaths,
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}`,