pi-revit 0.4.0 → 0.5.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/AGENTS.md +167 -0
- package/CHANGELOG.md +465 -430
- package/README.md +604 -548
- package/bin/pi-revit.js +9 -9
- package/docs/architecture.md +271 -0
- package/docs/evaluation.md +434 -0
- package/docs/invariants.json +147 -0
- package/extensions/pi-revit/completion-monitor.ts +55 -0
- package/extensions/pi-revit/contracts.ts +146 -0
- package/extensions/pi-revit/discovery.ts +93 -0
- package/extensions/pi-revit/index.ts +342 -255
- package/extensions/pi-revit/instance-router.ts +86 -86
- package/extensions/pi-revit/platform-prompt.ts +40 -0
- package/extensions/pi-revit/scope-monitor.ts +114 -0
- package/extensions/pi-revit/script-library.ts +144 -144
- package/extensions/pi-revit/tool-catalog.ts +113 -14
- package/extensions/pi-revit/tool-documentation.ts +72 -0
- package/extensions/pi-revit/tool-schema.ts +8 -0
- package/package.json +8 -2
- package/scripts/build.ps1 +9 -9
- package/scripts/check-sdk.ps1 +66 -66
- package/scripts/check-tool-documentation.mjs +287 -0
- package/scripts/deploy.ps1 +16 -16
- package/scripts/generate-contracts.mjs +80 -0
- package/scripts/lib/platform.mjs +226 -0
- package/scripts/test-extension.mjs +15 -0
- package/skills/pi-revit/SKILL.md +30 -218
- package/skills/pi-revit/contracts.generated.json +3524 -0
- package/skills/pi-revit/references/execution-rules.md +41 -0
- package/skills/pi-revit/references/model-audit-export.md +38 -27
- package/skills/pi-revit/references/operation-recovery.md +33 -0
- package/skills/pi-revit/references/room-documentation.md +37 -26
- package/skills/pi-revit/references/tool-index.md +89 -0
- package/skills/pi-revit/references/tools/capture_view.md +62 -0
- package/skills/pi-revit/references/tools/change_element_types.md +65 -0
- package/skills/pi-revit/references/tools/create_tags.md +85 -0
- package/skills/pi-revit/references/tools/delete_elements.md +66 -0
- package/skills/pi-revit/references/tools/execute_csharp.md +81 -0
- package/skills/pi-revit/references/tools/export_documents.md +75 -0
- package/skills/pi-revit/references/tools/find_revit_tools.md +96 -0
- package/skills/pi-revit/references/tools/get_element_details.md +66 -0
- package/skills/pi-revit/references/tools/get_element_relationships.md +61 -0
- package/skills/pi-revit/references/tools/get_element_types.md +67 -0
- package/skills/pi-revit/references/tools/get_elements.md +87 -0
- package/skills/pi-revit/references/tools/get_linked_elements.md +79 -0
- package/skills/pi-revit/references/tools/get_linked_models.md +57 -0
- package/skills/pi-revit/references/tools/get_model_coordinates.md +64 -0
- package/skills/pi-revit/references/tools/get_model_health.md +53 -0
- package/skills/pi-revit/references/tools/get_model_overview.md +57 -0
- package/skills/pi-revit/references/tools/get_revit_operation.md +54 -0
- package/skills/pi-revit/references/tools/get_schedule_fields.md +62 -0
- package/skills/pi-revit/references/tools/get_schedules.md +71 -0
- package/skills/pi-revit/references/tools/manage_element_sets.md +92 -0
- package/skills/pi-revit/references/tools/manage_revit_instances.md +63 -0
- package/skills/pi-revit/references/tools/manage_revit_scripts.md +109 -0
- package/skills/pi-revit/references/tools/manage_schedules.md +90 -0
- package/skills/pi-revit/references/tools/manage_selection.md +66 -0
- package/skills/pi-revit/references/tools/manage_sheet_placements.md +82 -0
- package/skills/pi-revit/references/tools/manage_sheets.md +71 -0
- package/skills/pi-revit/references/tools/manage_views.md +95 -0
- package/skills/pi-revit/references/tools/measure_geometry.md +71 -0
- package/skills/pi-revit/references/tools/open_view.md +59 -0
- package/skills/pi-revit/references/tools/ping.md +41 -0
- package/skills/pi-revit/references/tools/query_spatial_elements.md +74 -0
- package/skills/pi-revit/references/tools/read_revit_result.md +53 -0
- package/skills/pi-revit/references/tools/search_api_docs.md +65 -0
- package/skills/pi-revit/references/tools/set_parameters.md +75 -0
- package/skills/pi-revit/references/tools/summarize_elements.md +64 -0
- package/skills/pi-revit/references/tools/transform_elements.md +79 -0
- package/skills/pi-revit/references/visual-verification.md +36 -0
- package/skills/pi-revit/tool-manifest.json +338 -0
- package/src/Revit/BridgeServer.cs +93 -87
- package/src/Revit/OperationStore.cs +178 -178
- package/src/Revit/ToolRegistry.cs +88 -57
- package/src/Revit/Tools/CaptureView.cs +10 -2
- package/src/Revit/Tools/ChangeElementTypes.cs +74 -60
- package/src/Revit/Tools/ChangeSet.cs +39 -0
- package/src/Revit/Tools/CreateTags.cs +107 -95
- package/src/Revit/Tools/DeleteElements.cs +53 -44
- package/src/Revit/Tools/DocumentGuard.cs +74 -64
- package/src/Revit/Tools/ElementNames.cs +103 -0
- package/src/Revit/Tools/ElementQueryScope.cs +27 -27
- package/src/Revit/Tools/ElementTraits.cs +53 -0
- package/src/Revit/Tools/ExecuteCsharp.cs +54 -45
- package/src/Revit/Tools/ExportDocuments.cs +129 -121
- package/src/Revit/Tools/GetElementDetails.cs +37 -41
- package/src/Revit/Tools/GetElementRelationships.cs +82 -76
- package/src/Revit/Tools/GetElementTypes.cs +8 -0
- package/src/Revit/Tools/GetElements.cs +75 -86
- package/src/Revit/Tools/GetLinkedElements.cs +89 -82
- package/src/Revit/Tools/GetLinkedModels.cs +73 -66
- package/src/Revit/Tools/GetModelCoordinates.cs +56 -49
- package/src/Revit/Tools/GetModelHealth.cs +7 -0
- package/src/Revit/Tools/GetModelOverview.cs +185 -158
- package/src/Revit/Tools/GetScheduleFields.cs +44 -37
- package/src/Revit/Tools/GetSchedules.cs +96 -89
- package/src/Revit/Tools/InheritedState.Summary.cs +57 -0
- package/src/Revit/Tools/InheritedState.cs +144 -0
- package/src/Revit/Tools/ManageElementSets.cs +114 -106
- package/src/Revit/Tools/ManageSchedules.cs +174 -164
- package/src/Revit/Tools/ManageSelection.cs +45 -37
- package/src/Revit/Tools/ManageSheetPlacements.cs +113 -97
- package/src/Revit/Tools/ManageSheets.cs +72 -63
- package/src/Revit/Tools/ManageViews.cs +115 -100
- package/src/Revit/Tools/MeasureGeometry.cs +60 -54
- package/src/Revit/Tools/ModelChanges.cs +154 -0
- package/src/Revit/Tools/ModelEditBatch.cs +105 -102
- package/src/Revit/Tools/ModelEditInputs.cs +49 -49
- package/src/Revit/Tools/OpenView.cs +9 -2
- package/src/Revit/Tools/ParameterResolver.cs +94 -0
- package/src/Revit/Tools/QuerySpatialElements.cs +70 -63
- package/src/Revit/Tools/SearchApiDocs.cs +72 -4
- package/src/Revit/Tools/SetParameters.cs +60 -79
- package/src/Revit/Tools/SpatialBounds.cs +30 -30
- package/src/Revit/Tools/SummarizeElements.cs +94 -87
- package/src/Revit/Tools/ToolContract.cs +48 -0
- package/src/Revit/Tools/ToolSupport.cs +5 -1
- package/src/Revit/Tools/TransformElements.cs +72 -57
- package/workspace/AGENTS.md +26 -20
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 2,
|
|
3
|
+
"description": "Hand-maintained documentation index: one summary and group per public tool, plus guidance resources. Executable contracts (schemas, effects, keywords, limits, verification) are owned by code and generated into contracts.generated.json.",
|
|
4
|
+
"documentation_revision": "2026-09-29.1",
|
|
5
|
+
"groups": [
|
|
6
|
+
{
|
|
7
|
+
"id": "connection",
|
|
8
|
+
"title": "Connection, discovery, and local utilities"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"id": "inspection",
|
|
12
|
+
"title": "Model inspection and review"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "spatial",
|
|
16
|
+
"title": "Links, coordinates, and spatial analysis"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": "editing",
|
|
20
|
+
"title": "Selection and editing"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"id": "drawings",
|
|
24
|
+
"title": "Drawings, schedules, and delivery"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "api",
|
|
28
|
+
"title": "API and custom execution"
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"tools": [
|
|
32
|
+
{
|
|
33
|
+
"name": "capture_view",
|
|
34
|
+
"source": "bridge",
|
|
35
|
+
"group": "drawings",
|
|
36
|
+
"summary": "Capture a view as an image for visual verification."
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"name": "change_element_types",
|
|
40
|
+
"source": "bridge",
|
|
41
|
+
"group": "editing",
|
|
42
|
+
"summary": "Change element types with partial or atomic outcomes."
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "create_tags",
|
|
46
|
+
"source": "bridge",
|
|
47
|
+
"group": "drawings",
|
|
48
|
+
"summary": "Create host element, room, space and area tags."
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "delete_elements",
|
|
52
|
+
"source": "bridge",
|
|
53
|
+
"group": "editing",
|
|
54
|
+
"summary": "Preview or perform deletion including dependent elements."
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "execute_csharp",
|
|
58
|
+
"source": "bridge",
|
|
59
|
+
"group": "api",
|
|
60
|
+
"summary": "Execute custom synchronous C# in Revit."
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "export_documents",
|
|
64
|
+
"source": "bridge",
|
|
65
|
+
"group": "drawings",
|
|
66
|
+
"summary": "Export sheets, views or the model to PDF, DWG, PNG or IFC."
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"name": "find_revit_tools",
|
|
70
|
+
"source": "native",
|
|
71
|
+
"group": "connection",
|
|
72
|
+
"summary": "Discover tools, activate capabilities, or find packaged documentation."
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"name": "get_element_details",
|
|
76
|
+
"source": "bridge",
|
|
77
|
+
"group": "inspection",
|
|
78
|
+
"summary": "Inspect element parameters, geometry bounds and identity."
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"name": "get_element_relationships",
|
|
82
|
+
"source": "bridge",
|
|
83
|
+
"group": "inspection",
|
|
84
|
+
"summary": "Inspect hosts, joined elements, members and dependents."
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"name": "get_element_types",
|
|
88
|
+
"source": "bridge",
|
|
89
|
+
"group": "inspection",
|
|
90
|
+
"summary": "Discover available element types and family symbols."
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"name": "get_elements",
|
|
94
|
+
"source": "bridge",
|
|
95
|
+
"group": "inspection",
|
|
96
|
+
"summary": "Query, count and filter elements and project parameter values."
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"name": "get_linked_elements",
|
|
100
|
+
"source": "bridge",
|
|
101
|
+
"group": "spatial",
|
|
102
|
+
"summary": "Query elements inside a selected linked document."
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"name": "get_linked_models",
|
|
106
|
+
"source": "bridge",
|
|
107
|
+
"group": "spatial",
|
|
108
|
+
"summary": "Discover loaded and unloaded Revit link instances."
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "get_model_coordinates",
|
|
112
|
+
"source": "bridge",
|
|
113
|
+
"group": "spatial",
|
|
114
|
+
"summary": "Read base points, project locations and shared-coordinate mappings."
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"name": "get_model_health",
|
|
118
|
+
"source": "bridge",
|
|
119
|
+
"group": "inspection",
|
|
120
|
+
"summary": "Inspect model warnings and health information."
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"name": "get_model_overview",
|
|
124
|
+
"source": "bridge",
|
|
125
|
+
"group": "inspection",
|
|
126
|
+
"summary": "Inspect project identity, units, levels and category counts."
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"name": "get_revit_operation",
|
|
130
|
+
"source": "native",
|
|
131
|
+
"group": "connection",
|
|
132
|
+
"summary": "Inspect an original operation receipt after uncertain results."
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"name": "get_schedule_fields",
|
|
136
|
+
"source": "bridge",
|
|
137
|
+
"group": "drawings",
|
|
138
|
+
"summary": "Discover eligible parameter and field-type pairs."
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"name": "get_schedules",
|
|
142
|
+
"source": "bridge",
|
|
143
|
+
"group": "drawings",
|
|
144
|
+
"summary": "Inspect schedule fields, sorting, filters and table cells."
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"name": "manage_element_sets",
|
|
148
|
+
"source": "bridge",
|
|
149
|
+
"group": "inspection",
|
|
150
|
+
"summary": "Retain query membership and reread current member values."
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"name": "manage_revit_instances",
|
|
154
|
+
"source": "native",
|
|
155
|
+
"group": "connection",
|
|
156
|
+
"summary": "List and select local Revit bridge sessions."
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"name": "manage_revit_scripts",
|
|
160
|
+
"source": "native",
|
|
161
|
+
"group": "connection",
|
|
162
|
+
"summary": "Save, inspect and run exact versions of reusable scripts."
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"name": "manage_schedules",
|
|
166
|
+
"source": "bridge",
|
|
167
|
+
"group": "drawings",
|
|
168
|
+
"summary": "Create and configure schedules, fields, filters and sorting."
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"name": "manage_selection",
|
|
172
|
+
"source": "bridge",
|
|
173
|
+
"group": "editing",
|
|
174
|
+
"summary": "Read or change selection, zoom and temporary isolation."
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"name": "manage_sheet_placements",
|
|
178
|
+
"source": "bridge",
|
|
179
|
+
"group": "drawings",
|
|
180
|
+
"summary": "List, place and move viewports and schedules on sheets."
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"name": "manage_sheets",
|
|
184
|
+
"source": "bridge",
|
|
185
|
+
"group": "drawings",
|
|
186
|
+
"summary": "Create, rename and renumber sheets."
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"name": "manage_views",
|
|
190
|
+
"source": "bridge",
|
|
191
|
+
"group": "drawings",
|
|
192
|
+
"summary": "Create, duplicate and update plans, sections and 3D views."
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"name": "measure_geometry",
|
|
196
|
+
"source": "bridge",
|
|
197
|
+
"group": "spatial",
|
|
198
|
+
"summary": "Measure point distance or approximate element bounding-box gaps."
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"name": "open_view",
|
|
202
|
+
"source": "bridge",
|
|
203
|
+
"group": "editing",
|
|
204
|
+
"summary": "Activate a Revit view or sheet."
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"name": "ping",
|
|
208
|
+
"source": "native",
|
|
209
|
+
"group": "connection",
|
|
210
|
+
"summary": "Check Revit bridge availability and versions."
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
"name": "query_spatial_elements",
|
|
214
|
+
"source": "bridge",
|
|
215
|
+
"group": "spatial",
|
|
216
|
+
"summary": "Query elements by bounding-box intersection or containment."
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"name": "read_revit_result",
|
|
220
|
+
"source": "native",
|
|
221
|
+
"group": "connection",
|
|
222
|
+
"summary": "Read saved large results in bounded fragments."
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"name": "search_api_docs",
|
|
226
|
+
"source": "bridge",
|
|
227
|
+
"group": "api",
|
|
228
|
+
"summary": "Search installed Revit API classes, methods, signatures and enums."
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"name": "set_parameters",
|
|
232
|
+
"source": "bridge",
|
|
233
|
+
"group": "editing",
|
|
234
|
+
"summary": "Edit or preview parameter values with optional atomic rollback."
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"name": "summarize_elements",
|
|
238
|
+
"source": "bridge",
|
|
239
|
+
"group": "inspection",
|
|
240
|
+
"summary": "Count a whole element query grouped by type, category, level or parameter."
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"name": "transform_elements",
|
|
244
|
+
"source": "bridge",
|
|
245
|
+
"group": "editing",
|
|
246
|
+
"summary": "Move, copy or rotate elements with preview rollback."
|
|
247
|
+
}
|
|
248
|
+
],
|
|
249
|
+
"guidance": [
|
|
250
|
+
{
|
|
251
|
+
"name": "execution-rules",
|
|
252
|
+
"kind": "reference",
|
|
253
|
+
"path": "references/execution-rules.md",
|
|
254
|
+
"summary": "Shared rules for model targeting, document identity, parameters, units and transactions.",
|
|
255
|
+
"keywords": [
|
|
256
|
+
"identity",
|
|
257
|
+
"document id",
|
|
258
|
+
"expected_document_id",
|
|
259
|
+
"units",
|
|
260
|
+
"parameters",
|
|
261
|
+
"transactions",
|
|
262
|
+
"preview",
|
|
263
|
+
"atomic",
|
|
264
|
+
"localized names"
|
|
265
|
+
]
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"name": "operation-recovery",
|
|
269
|
+
"kind": "reference",
|
|
270
|
+
"path": "references/operation-recovery.md",
|
|
271
|
+
"summary": "Recover after timeouts, cancellations and uncertain outcomes using operation receipts.",
|
|
272
|
+
"keywords": [
|
|
273
|
+
"timeout",
|
|
274
|
+
"retry",
|
|
275
|
+
"receipt",
|
|
276
|
+
"uncertain",
|
|
277
|
+
"failed",
|
|
278
|
+
"bridge unavailable",
|
|
279
|
+
"no document"
|
|
280
|
+
]
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
"name": "visual-verification",
|
|
284
|
+
"kind": "reference",
|
|
285
|
+
"path": "references/visual-verification.md",
|
|
286
|
+
"summary": "Capture and inspect visible results and exported deliverables, then stop when the request is verified.",
|
|
287
|
+
"keywords": [
|
|
288
|
+
"verify",
|
|
289
|
+
"visual check",
|
|
290
|
+
"drawing check",
|
|
291
|
+
"image",
|
|
292
|
+
"overlap",
|
|
293
|
+
"layout",
|
|
294
|
+
"deliverable"
|
|
295
|
+
]
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
"name": "tool-index",
|
|
299
|
+
"kind": "reference",
|
|
300
|
+
"path": "references/tool-index.md",
|
|
301
|
+
"summary": "Every public tool grouped by task, with manual links.",
|
|
302
|
+
"keywords": [
|
|
303
|
+
"tools",
|
|
304
|
+
"capabilities",
|
|
305
|
+
"tool list",
|
|
306
|
+
"manuals"
|
|
307
|
+
]
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
"name": "room-documentation",
|
|
311
|
+
"kind": "workflow",
|
|
312
|
+
"path": "references/room-documentation.md",
|
|
313
|
+
"summary": "Room plans, sections, tags, schedules and sheets as one documentation workflow.",
|
|
314
|
+
"keywords": [
|
|
315
|
+
"rooms",
|
|
316
|
+
"room plan",
|
|
317
|
+
"room tags",
|
|
318
|
+
"room schedule",
|
|
319
|
+
"room sheets",
|
|
320
|
+
"room documentation"
|
|
321
|
+
]
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
"name": "model-audit-export",
|
|
325
|
+
"kind": "workflow",
|
|
326
|
+
"path": "references/model-audit-export.md",
|
|
327
|
+
"summary": "Multi-step model audit, data review and requested exports.",
|
|
328
|
+
"keywords": [
|
|
329
|
+
"audit",
|
|
330
|
+
"review",
|
|
331
|
+
"model quality",
|
|
332
|
+
"export",
|
|
333
|
+
"report",
|
|
334
|
+
"data review"
|
|
335
|
+
]
|
|
336
|
+
}
|
|
337
|
+
]
|
|
338
|
+
}
|
|
@@ -39,8 +39,8 @@ namespace RevitBridge
|
|
|
39
39
|
private readonly CommandQueue _queue;
|
|
40
40
|
private readonly ToolRegistry _registry;
|
|
41
41
|
private readonly string _revitVersion;
|
|
42
|
-
private readonly Func<bool> _hasOpenDocument;
|
|
43
|
-
private readonly OperationStore _operations = new();
|
|
42
|
+
private readonly Func<bool> _hasOpenDocument;
|
|
43
|
+
private readonly OperationStore _operations = new();
|
|
44
44
|
|
|
45
45
|
/// <summary>How often the bridge re-checks that bridge.json still points somewhere
|
|
46
46
|
/// live (see EnsureBridgeInfo). Cheap: one small file read per tick.</summary>
|
|
@@ -118,23 +118,23 @@ namespace RevitBridge
|
|
|
118
118
|
|
|
119
119
|
public static string BridgeInfoPath() => Path.Combine(BridgeInfoDirectory(), "bridge.json");
|
|
120
120
|
|
|
121
|
-
private void WriteBridgeInfo()
|
|
122
|
-
{
|
|
123
|
-
Directory.CreateDirectory(BridgeInfoDirectory());
|
|
124
|
-
string json = JsonSerializer.Serialize(new
|
|
121
|
+
private void WriteBridgeInfo()
|
|
122
|
+
{
|
|
123
|
+
Directory.CreateDirectory(BridgeInfoDirectory());
|
|
124
|
+
string json = JsonSerializer.Serialize(new
|
|
125
125
|
{
|
|
126
126
|
baseUrl = $"http://127.0.0.1:{_port}",
|
|
127
127
|
token = _token,
|
|
128
128
|
pid = Environment.ProcessId,
|
|
129
|
-
revitVersion = _revitVersion,
|
|
130
|
-
bridgeId = _operations.Generation,
|
|
131
|
-
supportsOperationTracking = true,
|
|
129
|
+
revitVersion = _revitVersion,
|
|
130
|
+
bridgeId = _operations.Generation,
|
|
131
|
+
supportsOperationTracking = true,
|
|
132
132
|
startedAtUtc = DateTime.UtcNow.ToString("o"),
|
|
133
|
-
}, new JsonSerializerOptions { WriteIndented = true });
|
|
134
|
-
string instances = Path.Combine(BridgeInfoDirectory(), "instances");
|
|
135
|
-
Directory.CreateDirectory(instances);
|
|
136
|
-
File.WriteAllText(Path.Combine(instances, _operations.Generation + ".json"), json);
|
|
137
|
-
File.WriteAllText(BridgeInfoPath(), json);
|
|
133
|
+
}, new JsonSerializerOptions { WriteIndented = true });
|
|
134
|
+
string instances = Path.Combine(BridgeInfoDirectory(), "instances");
|
|
135
|
+
Directory.CreateDirectory(instances);
|
|
136
|
+
File.WriteAllText(Path.Combine(instances, _operations.Generation + ".json"), json);
|
|
137
|
+
File.WriteAllText(BridgeInfoPath(), json);
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
/// <summary>
|
|
@@ -193,9 +193,9 @@ namespace RevitBridge
|
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
private void DeleteBridgeInfoIfOwned()
|
|
197
|
-
{
|
|
198
|
-
try { File.Delete(Path.Combine(BridgeInfoDirectory(), "instances", _operations.Generation + ".json")); } catch { }
|
|
196
|
+
private void DeleteBridgeInfoIfOwned()
|
|
197
|
+
{
|
|
198
|
+
try { File.Delete(Path.Combine(BridgeInfoDirectory(), "instances", _operations.Generation + ".json")); } catch { }
|
|
199
199
|
try
|
|
200
200
|
{
|
|
201
201
|
string path = BridgeInfoPath();
|
|
@@ -345,10 +345,10 @@ namespace RevitBridge
|
|
|
345
345
|
private async Task<(int Status, object Response)> RouteAsync(string method, string path, Dictionary<string, string> query, string body, CancellationToken token)
|
|
346
346
|
{
|
|
347
347
|
if (method == "GET" && path == "/ping")
|
|
348
|
-
return (200, new { ok = true, service = "revit-bridge", revitVersion = _revitVersion, pid = Environment.ProcessId, addinVersion = AddinVersion, bridgeId = _operations.Generation, supportsOperationTracking = true });
|
|
349
|
-
|
|
350
|
-
if (method == "GET" && path.StartsWith("/operations/", StringComparison.Ordinal))
|
|
351
|
-
return (200, _operations.Status(WebUtility.UrlDecode(path["/operations/".Length..])));
|
|
348
|
+
return (200, new { ok = true, service = "revit-bridge", revitVersion = _revitVersion, pid = Environment.ProcessId, addinVersion = AddinVersion, bridgeId = _operations.Generation, supportsOperationTracking = true });
|
|
349
|
+
|
|
350
|
+
if (method == "GET" && path.StartsWith("/operations/", StringComparison.Ordinal))
|
|
351
|
+
return (200, _operations.Status(WebUtility.UrlDecode(path["/operations/".Length..])));
|
|
352
352
|
|
|
353
353
|
if (method == "GET" && path == "/tools")
|
|
354
354
|
{
|
|
@@ -402,81 +402,87 @@ namespace RevitBridge
|
|
|
402
402
|
return (400, new { error = true, message = $"Invalid JSON tool arguments: {ex.Message}" });
|
|
403
403
|
}
|
|
404
404
|
|
|
405
|
-
int timeoutMs = ResolveTimeoutMs(query);
|
|
406
|
-
|
|
407
|
-
if (query.TryGetValue("operation_id", out string? operationId))
|
|
408
|
-
{
|
|
409
|
-
try
|
|
410
|
-
{
|
|
411
|
-
var (entry, isNew) = _operations.Reserve(operationId, name, args, TimeSpan.FromMilliseconds(timeoutMs));
|
|
412
|
-
var completion = _operations.Wait(entry);
|
|
413
|
-
if (isNew) _ = CompleteTrackedOperationAsync(entry, tool, args, timeoutMs);
|
|
414
|
-
var reply = await completion;
|
|
415
|
-
return (reply.Status, reply.Response);
|
|
416
|
-
}
|
|
417
|
-
catch (ArgumentException error) { return (409, new { error = true, message = error.Message, operation_id = operationId }); }
|
|
418
|
-
catch (InvalidOperationException error) { return (503, new { error = true, message = error.Message, operation_id = operationId }); }
|
|
419
|
-
}
|
|
420
|
-
var result = await RunToolAsync(tool, args, timeoutMs, null);
|
|
421
|
-
return (result.Status, result.Response);
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
private async Task CompleteTrackedOperationAsync(OperationStore.Entry entry, ITool tool, JsonElement args, int timeoutMs)
|
|
425
|
-
{
|
|
426
|
-
var reply = await RunToolAsync(tool, args, timeoutMs, entry);
|
|
427
|
-
_operations.Complete(entry, new OperationStore.Reply(reply.Status, reply.Response, reply.Outcome));
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
private async Task<(int Status, object Response, string? Outcome)> RunToolAsync(ITool tool, JsonElement args, int timeoutMs, OperationStore.Entry? operation)
|
|
431
|
-
{
|
|
432
|
-
string name = tool.Name;
|
|
433
|
-
// Cached receipts remain accessible even when the active document closes.
|
|
434
|
-
if (tool.RequiresDocument && !_hasOpenDocument())
|
|
435
|
-
return (409, new { error = true, hasActiveDocument = false, message = "No active Revit document is open." }, null);
|
|
436
|
-
|
|
437
|
-
void StartOperation()
|
|
438
|
-
{
|
|
439
|
-
if (operation != null && !_operations.TryStart(operation)) throw new TimeoutException("Operation expired before execution; no tool action was performed.");
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
try
|
|
405
|
+
int timeoutMs = ResolveTimeoutMs(query);
|
|
406
|
+
|
|
407
|
+
if (query.TryGetValue("operation_id", out string? operationId))
|
|
408
|
+
{
|
|
409
|
+
try
|
|
410
|
+
{
|
|
411
|
+
var (entry, isNew) = _operations.Reserve(operationId, name, args, TimeSpan.FromMilliseconds(timeoutMs));
|
|
412
|
+
var completion = _operations.Wait(entry);
|
|
413
|
+
if (isNew) _ = CompleteTrackedOperationAsync(entry, tool, args, timeoutMs);
|
|
414
|
+
var reply = await completion;
|
|
415
|
+
return (reply.Status, reply.Response);
|
|
416
|
+
}
|
|
417
|
+
catch (ArgumentException error) { return (409, new { error = true, message = error.Message, operation_id = operationId }); }
|
|
418
|
+
catch (InvalidOperationException error) { return (503, new { error = true, message = error.Message, operation_id = operationId }); }
|
|
419
|
+
}
|
|
420
|
+
var result = await RunToolAsync(tool, args, timeoutMs, null);
|
|
421
|
+
return (result.Status, result.Response);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
private async Task CompleteTrackedOperationAsync(OperationStore.Entry entry, ITool tool, JsonElement args, int timeoutMs)
|
|
425
|
+
{
|
|
426
|
+
var reply = await RunToolAsync(tool, args, timeoutMs, entry);
|
|
427
|
+
_operations.Complete(entry, new OperationStore.Reply(reply.Status, reply.Response, reply.Outcome));
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
private async Task<(int Status, object Response, string? Outcome)> RunToolAsync(ITool tool, JsonElement args, int timeoutMs, OperationStore.Entry? operation)
|
|
431
|
+
{
|
|
432
|
+
string name = tool.Name;
|
|
433
|
+
// Cached receipts remain accessible even when the active document closes.
|
|
434
|
+
if (tool.RequiresDocument && !_hasOpenDocument())
|
|
435
|
+
return (409, new { error = true, hasActiveDocument = false, message = "No active Revit document is open." }, null);
|
|
436
|
+
|
|
437
|
+
void StartOperation()
|
|
438
|
+
{
|
|
439
|
+
if (operation != null && !_operations.TryStart(operation)) throw new TimeoutException("Operation expired before execution; no tool action was performed.");
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
try
|
|
443
443
|
{
|
|
444
444
|
object? output = tool.RequiresDocument
|
|
445
445
|
? await _queue.RunAsync(uiApp =>
|
|
446
|
-
{
|
|
447
|
-
StartOperation();
|
|
448
|
-
var document = uiApp.ActiveUIDocument?.Document ?? throw new NoActiveDocumentException();
|
|
449
|
-
RevitBridge.Tools.DocumentGuard.CheckForTool(args, document, tool.Name, tool.Write);
|
|
450
|
-
|
|
446
|
+
{
|
|
447
|
+
StartOperation();
|
|
448
|
+
var document = uiApp.ActiveUIDocument?.Document ?? throw new NoActiveDocumentException();
|
|
449
|
+
RevitBridge.Tools.DocumentGuard.CheckForTool(args, document, tool.Name, tool.Write);
|
|
450
|
+
// A tool declared for other document kinds is refused before it runs (inv:document-kind-declared).
|
|
451
|
+
RevitBridge.Tools.DocumentGuard.CheckKind(tool, document);
|
|
452
|
+
// Every tool that can change the model reports what it changed (model_changes),
|
|
453
|
+
// without tool-specific code, so future tools inherit it.
|
|
454
|
+
using var changes = RevitBridge.Tools.ModelChangeRecorder.For(tool, uiApp.Application, document);
|
|
455
|
+
var result = tool.Execute(args, new ToolContext(document, uiApp));
|
|
456
|
+
return changes == null ? result : changes.Attach(result);
|
|
451
457
|
}, TimeSpan.FromMilliseconds(timeoutMs))
|
|
452
458
|
// RequiresDocument = false tools never touch the Revit API, so they
|
|
453
459
|
// run right here on the server task instead of the CommandQueue.
|
|
454
|
-
: ExecuteWithoutDocument();
|
|
455
|
-
|
|
456
|
-
try { return (200, BuildToolResponse(name, output), null); }
|
|
457
|
-
catch (Exception error)
|
|
458
|
-
{
|
|
459
|
-
return (500, new { error = true, toolName = name, result_unavailable = true,
|
|
460
|
-
message = "The tool finished, but its response could not be constructed. Model or other effects may already have occurred; inspect them before retrying. " + error.Message }, "result_unavailable");
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
object? ExecuteWithoutDocument()
|
|
464
|
-
{
|
|
465
|
-
StartOperation();
|
|
466
|
-
return tool.Execute(args, new ToolContext(null, null));
|
|
467
|
-
}
|
|
460
|
+
: ExecuteWithoutDocument();
|
|
461
|
+
|
|
462
|
+
try { return (200, BuildToolResponse(name, output), null); }
|
|
463
|
+
catch (Exception error)
|
|
464
|
+
{
|
|
465
|
+
return (500, new { error = true, toolName = name, result_unavailable = true,
|
|
466
|
+
message = "The tool finished, but its response could not be constructed. Model or other effects may already have occurred; inspect them before retrying. " + error.Message }, "result_unavailable");
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
object? ExecuteWithoutDocument()
|
|
470
|
+
{
|
|
471
|
+
StartOperation();
|
|
472
|
+
return tool.Execute(args, new ToolContext(null, null));
|
|
473
|
+
}
|
|
468
474
|
}
|
|
469
475
|
catch (NoActiveDocumentException ex)
|
|
470
476
|
{
|
|
471
|
-
return (409, new { error = true, hasActiveDocument = false, message = ex.Message }, null);
|
|
477
|
+
return (409, new { error = true, hasActiveDocument = false, message = ex.Message }, null);
|
|
472
478
|
}
|
|
473
479
|
catch (ArgumentException ex)
|
|
474
480
|
{
|
|
475
|
-
return (400, new { error = true, toolName = name, message = ex.Message }, null);
|
|
481
|
+
return (400, new { error = true, toolName = name, message = ex.Message }, null);
|
|
476
482
|
}
|
|
477
483
|
catch (Exception ex)
|
|
478
484
|
{
|
|
479
|
-
return (500, new { error = true, toolName = name, message = ex.Message }, null);
|
|
485
|
+
return (500, new { error = true, toolName = name, message = ex.Message }, null);
|
|
480
486
|
}
|
|
481
487
|
}
|
|
482
488
|
|
|
@@ -486,9 +492,9 @@ namespace RevitBridge
|
|
|
486
492
|
? Math.Clamp(value, 1_000, 600_000)
|
|
487
493
|
: 30_000;
|
|
488
494
|
|
|
489
|
-
/// <summary>Complete bounded JSON for model context; the full payload always
|
|
490
|
-
/// remains in details for the extension's saved-result retrieval. ToolOutput
|
|
491
|
-
/// compact text is a display summary, not a substitute for requested data.</summary>
|
|
495
|
+
/// <summary>Complete bounded JSON for model context; the full payload always
|
|
496
|
+
/// remains in details for the extension's saved-result retrieval. ToolOutput
|
|
497
|
+
/// compact text is a display summary, not a substitute for requested data.</summary>
|
|
492
498
|
private static object BuildToolResponse(string toolName, object? output)
|
|
493
499
|
{
|
|
494
500
|
object? payload = output;
|
|
@@ -499,11 +505,11 @@ namespace RevitBridge
|
|
|
499
505
|
compact = toolOutput.CompactText;
|
|
500
506
|
}
|
|
501
507
|
|
|
502
|
-
string text = JsonSerializer.Serialize(payload);
|
|
508
|
+
string text = JsonSerializer.Serialize(payload);
|
|
503
509
|
bool truncated = text.Length > MaxContentChars;
|
|
504
510
|
if (truncated)
|
|
505
511
|
{
|
|
506
|
-
text = $"Result exceeds the {MaxContentChars}-character inline limit. The complete value is in details.payload; the Pi extension saves it locally and provides read_revit_result for bounded retrieval.";
|
|
512
|
+
text = $"Result exceeds the {MaxContentChars}-character inline limit. The complete value is in details.payload; the Pi extension saves it locally and provides read_revit_result for bounded retrieval.";
|
|
507
513
|
}
|
|
508
514
|
|
|
509
515
|
return new
|
|
@@ -511,7 +517,7 @@ namespace RevitBridge
|
|
|
511
517
|
success = true,
|
|
512
518
|
toolName,
|
|
513
519
|
content = new[] { new { type = "text", text } },
|
|
514
|
-
details = new { payload, summary = compact, contentTruncated = truncated },
|
|
520
|
+
details = new { payload, summary = compact, contentTruncated = truncated },
|
|
515
521
|
isError = false,
|
|
516
522
|
};
|
|
517
523
|
}
|