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.
Files changed (119) hide show
  1. package/AGENTS.md +167 -0
  2. package/CHANGELOG.md +465 -430
  3. package/README.md +604 -548
  4. package/bin/pi-revit.js +9 -9
  5. package/docs/architecture.md +271 -0
  6. package/docs/evaluation.md +434 -0
  7. package/docs/invariants.json +147 -0
  8. package/extensions/pi-revit/completion-monitor.ts +55 -0
  9. package/extensions/pi-revit/contracts.ts +146 -0
  10. package/extensions/pi-revit/discovery.ts +93 -0
  11. package/extensions/pi-revit/index.ts +342 -255
  12. package/extensions/pi-revit/instance-router.ts +86 -86
  13. package/extensions/pi-revit/platform-prompt.ts +40 -0
  14. package/extensions/pi-revit/scope-monitor.ts +114 -0
  15. package/extensions/pi-revit/script-library.ts +144 -144
  16. package/extensions/pi-revit/tool-catalog.ts +113 -14
  17. package/extensions/pi-revit/tool-documentation.ts +72 -0
  18. package/extensions/pi-revit/tool-schema.ts +8 -0
  19. package/package.json +8 -2
  20. package/scripts/build.ps1 +9 -9
  21. package/scripts/check-sdk.ps1 +66 -66
  22. package/scripts/check-tool-documentation.mjs +287 -0
  23. package/scripts/deploy.ps1 +16 -16
  24. package/scripts/generate-contracts.mjs +80 -0
  25. package/scripts/lib/platform.mjs +226 -0
  26. package/scripts/test-extension.mjs +15 -0
  27. package/skills/pi-revit/SKILL.md +30 -218
  28. package/skills/pi-revit/contracts.generated.json +3524 -0
  29. package/skills/pi-revit/references/execution-rules.md +41 -0
  30. package/skills/pi-revit/references/model-audit-export.md +38 -27
  31. package/skills/pi-revit/references/operation-recovery.md +33 -0
  32. package/skills/pi-revit/references/room-documentation.md +37 -26
  33. package/skills/pi-revit/references/tool-index.md +89 -0
  34. package/skills/pi-revit/references/tools/capture_view.md +62 -0
  35. package/skills/pi-revit/references/tools/change_element_types.md +65 -0
  36. package/skills/pi-revit/references/tools/create_tags.md +85 -0
  37. package/skills/pi-revit/references/tools/delete_elements.md +66 -0
  38. package/skills/pi-revit/references/tools/execute_csharp.md +81 -0
  39. package/skills/pi-revit/references/tools/export_documents.md +75 -0
  40. package/skills/pi-revit/references/tools/find_revit_tools.md +96 -0
  41. package/skills/pi-revit/references/tools/get_element_details.md +66 -0
  42. package/skills/pi-revit/references/tools/get_element_relationships.md +61 -0
  43. package/skills/pi-revit/references/tools/get_element_types.md +67 -0
  44. package/skills/pi-revit/references/tools/get_elements.md +87 -0
  45. package/skills/pi-revit/references/tools/get_linked_elements.md +79 -0
  46. package/skills/pi-revit/references/tools/get_linked_models.md +57 -0
  47. package/skills/pi-revit/references/tools/get_model_coordinates.md +64 -0
  48. package/skills/pi-revit/references/tools/get_model_health.md +53 -0
  49. package/skills/pi-revit/references/tools/get_model_overview.md +57 -0
  50. package/skills/pi-revit/references/tools/get_revit_operation.md +54 -0
  51. package/skills/pi-revit/references/tools/get_schedule_fields.md +62 -0
  52. package/skills/pi-revit/references/tools/get_schedules.md +71 -0
  53. package/skills/pi-revit/references/tools/manage_element_sets.md +92 -0
  54. package/skills/pi-revit/references/tools/manage_revit_instances.md +63 -0
  55. package/skills/pi-revit/references/tools/manage_revit_scripts.md +109 -0
  56. package/skills/pi-revit/references/tools/manage_schedules.md +90 -0
  57. package/skills/pi-revit/references/tools/manage_selection.md +66 -0
  58. package/skills/pi-revit/references/tools/manage_sheet_placements.md +82 -0
  59. package/skills/pi-revit/references/tools/manage_sheets.md +71 -0
  60. package/skills/pi-revit/references/tools/manage_views.md +95 -0
  61. package/skills/pi-revit/references/tools/measure_geometry.md +71 -0
  62. package/skills/pi-revit/references/tools/open_view.md +59 -0
  63. package/skills/pi-revit/references/tools/ping.md +41 -0
  64. package/skills/pi-revit/references/tools/query_spatial_elements.md +74 -0
  65. package/skills/pi-revit/references/tools/read_revit_result.md +53 -0
  66. package/skills/pi-revit/references/tools/search_api_docs.md +65 -0
  67. package/skills/pi-revit/references/tools/set_parameters.md +75 -0
  68. package/skills/pi-revit/references/tools/summarize_elements.md +64 -0
  69. package/skills/pi-revit/references/tools/transform_elements.md +79 -0
  70. package/skills/pi-revit/references/visual-verification.md +36 -0
  71. package/skills/pi-revit/tool-manifest.json +338 -0
  72. package/src/Revit/BridgeServer.cs +93 -87
  73. package/src/Revit/OperationStore.cs +178 -178
  74. package/src/Revit/ToolRegistry.cs +88 -57
  75. package/src/Revit/Tools/CaptureView.cs +10 -2
  76. package/src/Revit/Tools/ChangeElementTypes.cs +74 -60
  77. package/src/Revit/Tools/ChangeSet.cs +39 -0
  78. package/src/Revit/Tools/CreateTags.cs +107 -95
  79. package/src/Revit/Tools/DeleteElements.cs +53 -44
  80. package/src/Revit/Tools/DocumentGuard.cs +74 -64
  81. package/src/Revit/Tools/ElementNames.cs +103 -0
  82. package/src/Revit/Tools/ElementQueryScope.cs +27 -27
  83. package/src/Revit/Tools/ElementTraits.cs +53 -0
  84. package/src/Revit/Tools/ExecuteCsharp.cs +54 -45
  85. package/src/Revit/Tools/ExportDocuments.cs +129 -121
  86. package/src/Revit/Tools/GetElementDetails.cs +37 -41
  87. package/src/Revit/Tools/GetElementRelationships.cs +82 -76
  88. package/src/Revit/Tools/GetElementTypes.cs +8 -0
  89. package/src/Revit/Tools/GetElements.cs +75 -86
  90. package/src/Revit/Tools/GetLinkedElements.cs +89 -82
  91. package/src/Revit/Tools/GetLinkedModels.cs +73 -66
  92. package/src/Revit/Tools/GetModelCoordinates.cs +56 -49
  93. package/src/Revit/Tools/GetModelHealth.cs +7 -0
  94. package/src/Revit/Tools/GetModelOverview.cs +185 -158
  95. package/src/Revit/Tools/GetScheduleFields.cs +44 -37
  96. package/src/Revit/Tools/GetSchedules.cs +96 -89
  97. package/src/Revit/Tools/InheritedState.Summary.cs +57 -0
  98. package/src/Revit/Tools/InheritedState.cs +144 -0
  99. package/src/Revit/Tools/ManageElementSets.cs +114 -106
  100. package/src/Revit/Tools/ManageSchedules.cs +174 -164
  101. package/src/Revit/Tools/ManageSelection.cs +45 -37
  102. package/src/Revit/Tools/ManageSheetPlacements.cs +113 -97
  103. package/src/Revit/Tools/ManageSheets.cs +72 -63
  104. package/src/Revit/Tools/ManageViews.cs +115 -100
  105. package/src/Revit/Tools/MeasureGeometry.cs +60 -54
  106. package/src/Revit/Tools/ModelChanges.cs +154 -0
  107. package/src/Revit/Tools/ModelEditBatch.cs +105 -102
  108. package/src/Revit/Tools/ModelEditInputs.cs +49 -49
  109. package/src/Revit/Tools/OpenView.cs +9 -2
  110. package/src/Revit/Tools/ParameterResolver.cs +94 -0
  111. package/src/Revit/Tools/QuerySpatialElements.cs +70 -63
  112. package/src/Revit/Tools/SearchApiDocs.cs +72 -4
  113. package/src/Revit/Tools/SetParameters.cs +60 -79
  114. package/src/Revit/Tools/SpatialBounds.cs +30 -30
  115. package/src/Revit/Tools/SummarizeElements.cs +94 -87
  116. package/src/Revit/Tools/ToolContract.cs +48 -0
  117. package/src/Revit/Tools/ToolSupport.cs +5 -1
  118. package/src/Revit/Tools/TransformElements.cs +72 -57
  119. package/workspace/AGENTS.md +26 -20
@@ -1,97 +1,113 @@
1
- using System.Text.Json;
2
- using Autodesk.Revit.DB;
3
-
4
- namespace RevitBridge.Tools;
5
-
6
- internal sealed class ManageSheetPlacements : ITool
7
- {
8
- public string Name => "manage_sheet_placements";
9
- public string Label => "Manage Sheet Placements";
10
- public string Tier => "advanced";
11
- public bool Write => true;
12
- public string Description => "List, place or move viewports and schedule instances on a sheet. Positions are paper-space sheet coordinates with explicit length units, [x,y,0]; never multiply by view scale. For viewports position is the box center excluding its label; for schedules it is the insertion point. Place requires sheet_id/view_id, move requires placement_id. Viewports may rotate none/clockwise/counterclockwise; schedule rotation is not supported. preview=true commit-validates then rolls back; new placement IDs are temporary. List includes both viewports and schedules with paging. Exact document identity is required for every action.";
13
- public object ParametersSchema => new
14
- {
15
- type = "object", properties = new
16
- {
17
- action = new { type = "string", @enum = new[] { "list", "place", "move" } },
18
- sheet_id = new { type = "integer", minimum = 1 }, view_id = new { type = "integer", minimum = 1 }, placement_id = new { type = "integer", minimum = 1 },
19
- position = ModelEditInputs.VectorSchema("Sheet paper-space [x,y,0] in unit."), unit = ModelEditInputs.LengthUnitSchema,
20
- rotation = new { type = "string", @enum = new[] { "none", "clockwise", "counterclockwise" } },
21
- offset = new { type = "integer", minimum = 0 }, limit = new { type = "integer", minimum = 1, maximum = 200 }, preview = ModelEditInputs.PreviewSchema,
22
- }, required = new[] { "action" },
23
- };
24
- public object Execute(JsonElement args, ToolContext context)
25
- {
26
- var doc = context.Document ?? throw new NoActiveDocumentException();
27
- string action = JsonArgs.GetString(args, "action") ?? "";
28
- ElementId Id(string name) => new(JsonArgs.GetLong(args, name) is long id && id > 0 ? id : throw new ArgumentException($"{name} must be a positive ID."));
29
- if (action == "list")
30
- {
31
- var sheet = doc.GetElement(Id("sheet_id")) as ViewSheet ?? throw new ArgumentException("sheet_id is not a sheet.");
32
- var items = new FilteredElementCollector(doc).OwnedByView(sheet.Id).WhereElementIsNotElementType()
33
- .Where(e => e is Viewport or ScheduleSheetInstance).OrderBy(e => e.Id.Value).ToArray();
34
- int offset = JsonArgs.GetInt(args, "offset", 0), limit = JsonArgs.GetInt(args, "limit", 100);
35
- if (offset < 0 || limit is < 1 or > 200) throw new ArgumentException("Invalid paging range.");
36
- var page = items.Skip(offset).Take(limit).Select(Describe).ToArray();
37
- return new { sheet_id = sheet.Id.Value, total_count = items.Length, offset, returned_count = page.Length, next_offset = offset + page.Length < items.Length ? (int?)(offset + page.Length) : null, placements = page, coordinate_system = "sheet_paper", unit = "feet" };
38
- }
39
- if (action is not ("place" or "move")) throw new ArgumentException("action must be list, place or move.");
40
- var point = ModelEditInputs.Vector(args, "position").Multiply(ModelEditInputs.LengthScale(args));
41
- if (Math.Abs(point.Z) > 1e-9) throw new ArgumentException("Sheet position Z must be zero.");
42
- var rotation = JsonArgs.GetString(args, "rotation") switch
43
- {
44
- null => (ViewportRotation?)null, "none" => ViewportRotation.None, "clockwise" => ViewportRotation.Clockwise,
45
- "counterclockwise" => ViewportRotation.Counterclockwise, _ => throw new ArgumentException("Invalid rotation."),
46
- };
47
- return ModelEditBatch.Run(doc, Name, args, new[] { new ModelEditBatch.Step(new() { ["action"] = action }, () =>
48
- {
49
- Element placement;
50
- object? before = null;
51
- if (action == "place")
52
- {
53
- var sheet = doc.GetElement(Id("sheet_id")) as ViewSheet ?? throw new ArgumentException("sheet_id is not a sheet.");
54
- if (sheet.IsPlaceholder) throw new ArgumentException("Cannot place content on a placeholder sheet.");
55
- var view = doc.GetElement(Id("view_id")) as View ?? throw new ArgumentException("view_id is not a view or schedule.");
56
- if (view is ViewSchedule schedule)
57
- {
58
- if (rotation != null) throw new ArgumentException("Schedules do not support viewport rotation.");
59
- placement = ScheduleSheetInstance.Create(doc, sheet.Id, schedule.Id, point);
60
- }
61
- else
62
- {
63
- if (!Viewport.CanAddViewToSheet(doc, sheet.Id, view.Id)) throw new ArgumentException("This view cannot be added to that sheet; it may already be placed.");
64
- placement = Viewport.Create(doc, sheet.Id, view.Id, point);
65
- }
66
- }
67
- else
68
- {
69
- placement = doc.GetElement(Id("placement_id")) ?? throw new ArgumentException("placement_id was not found.");
70
- if (args.TryGetProperty("sheet_id", out _) && placement.OwnerViewId != Id("sheet_id")) throw new ArgumentException("The placement does not belong to the expected sheet_id.");
71
- if (placement.Pinned) throw new ArgumentException("Placement is pinned; it was not unpinned.");
72
- before = Describe(placement);
73
- if (placement is Viewport viewport) viewport.SetBoxCenter(point);
74
- else if (placement is ScheduleSheetInstance schedule)
75
- {
76
- if (rotation != null) throw new ArgumentException("Schedules do not support viewport rotation.");
77
- schedule.Point = point;
78
- }
79
- else throw new ArgumentException("placement_id must identify a viewport or schedule instance.");
80
- }
81
- if (rotation != null && placement is Viewport target) target.Rotation = rotation.Value;
82
- doc.Regenerate();
83
- if (placement is Viewport positioned) { positioned.SetBoxCenter(point); doc.Regenerate(); }
84
- return new() { ["before"] = before, ["placement"] = Describe(placement), ["created"] = action == "place", ["id_is_temporary"] = action == "place" && JsonArgs.GetBool(args, "preview", false) };
85
- }) }).Payload;
86
- }
87
- private static object Describe(Element element)
88
- {
89
- static double[] Point(XYZ p) => new[] { p.X, p.Y, p.Z };
90
- return element switch
91
- {
92
- Viewport v => new { id = v.Id.Value, unique_id = v.UniqueId, kind = "viewport", sheet_id = v.SheetId.Value, view_id = v.ViewId.Value, position = Point(v.GetBoxCenter()), position_kind = "box_center_excluding_label", rotation = v.Rotation.ToString(), unit = "feet" } as object,
93
- ScheduleSheetInstance s => new { id = s.Id.Value, unique_id = s.UniqueId, kind = "schedule", sheet_id = s.OwnerViewId.Value, view_id = s.ScheduleId.Value, position = Point(s.Point), position_kind = "insertion_point", unit = "feet" },
94
- _ => throw new ArgumentException("Element is not a sheet placement."),
95
- };
96
- }
97
- }
1
+ using System.Text.Json;
2
+ using Autodesk.Revit.DB;
3
+
4
+ namespace RevitBridge.Tools;
5
+
6
+ internal sealed class ManageSheetPlacements : ITool
7
+ {
8
+ public string Name => "manage_sheet_placements";
9
+ public IReadOnlyList<string> DocumentKinds => DocumentKind.ProjectOnly;
10
+ public IReadOnlyList<string> Keywords => new[] { "viewport", "place view on sheet", "sheet layout", "move viewport", "schedule on sheet", "arrange sheet" };
11
+ public IReadOnlyList<ToolLimit> Limits => new[]
12
+ {
13
+ new ToolLimit("Creating the source view or schedule", "tool", "manage_views; manage_schedules"),
14
+ new ToolLimit("Rotating schedule instances", "api", "ScheduleSheetInstance.Rotation"),
15
+ new ToolLimit("Changing the titleblock", "tool", "change_element_types on the titleblock instance"),
16
+ };
17
+ public string? Verification => "capture";
18
+ public string Label => "Manage Sheet Placements";
19
+ public string Tier => "advanced";
20
+ public bool Write => true;
21
+ public string Description => "List, place or move viewports and schedule instances on a sheet. Positions are paper-space sheet coordinates with explicit length units, [x,y,0]; never multiply by view scale. For viewports position is the box center excluding its label; for schedules it is the insertion point. Place requires sheet_id/view_id, move requires placement_id. Viewports may rotate none/clockwise/counterclockwise; schedule rotation is not supported. preview=true commit-validates then rolls back; new placement IDs are temporary. List includes viewports, schedules and the titleblock's own revision schedules (kind titleblock_revision_schedule: part of the titleblock, not placed content), with paging and per-kind counts over the whole sheet. Exact document identity is required for every action.";
22
+ public object ParametersSchema => new
23
+ {
24
+ type = "object", properties = new
25
+ {
26
+ action = new { type = "string", @enum = new[] { "list", "place", "move" } },
27
+ sheet_id = new { type = "integer", minimum = 1 }, view_id = new { type = "integer", minimum = 1 }, placement_id = new { type = "integer", minimum = 1 },
28
+ position = ModelEditInputs.VectorSchema("Sheet paper-space [x,y,0] in unit."), unit = ModelEditInputs.LengthUnitSchema,
29
+ rotation = new { type = "string", @enum = new[] { "none", "clockwise", "counterclockwise" } },
30
+ offset = new { type = "integer", minimum = 0 }, limit = new { type = "integer", minimum = 1, maximum = 200 }, preview = ModelEditInputs.PreviewSchema,
31
+ }, required = new[] { "action" },
32
+ };
33
+ public object Execute(JsonElement args, ToolContext context)
34
+ {
35
+ var doc = context.Document ?? throw new NoActiveDocumentException();
36
+ string action = JsonArgs.GetString(args, "action") ?? "";
37
+ ElementId Id(string name) => new(JsonArgs.GetLong(args, name) is long id && id > 0 ? id : throw new ArgumentException($"{name} must be a positive ID."));
38
+ if (action == "list")
39
+ {
40
+ var sheet = doc.GetElement(Id("sheet_id")) as ViewSheet ?? throw new ArgumentException("sheet_id is not a sheet.");
41
+ var items = new FilteredElementCollector(doc).OwnedByView(sheet.Id).WhereElementIsNotElementType()
42
+ .Where(e => e is Viewport or ScheduleSheetInstance).OrderBy(e => e.Id.Value).ToArray();
43
+ int offset = JsonArgs.GetInt(args, "offset", 0), limit = JsonArgs.GetInt(args, "limit", 100);
44
+ if (offset < 0 || limit is < 1 or > 200) throw new ArgumentException("Invalid paging range.");
45
+ var page = items.Skip(offset).Take(limit).Select(Describe).ToArray();
46
+ // Counts cover the whole sheet, so "is anything placed?" never depends on paging
47
+ // or on mistaking the titleblock's revision schedule for placed content.
48
+ var kinds = items.Select(ElementTraits.PlacementKind).ToArray();
49
+ var counts = new { viewports = kinds.Count(k => k == "viewport"), schedules = kinds.Count(k => k == "schedule"),
50
+ titleblock_revision_schedules = kinds.Count(k => k == "titleblock_revision_schedule") };
51
+ return new { sheet_id = sheet.Id.Value, total_count = items.Length, counts, offset, returned_count = page.Length, next_offset = offset + page.Length < items.Length ? (int?)(offset + page.Length) : null, placements = page, coordinate_system = "sheet_paper", unit = "feet" };
52
+ }
53
+ if (action is not ("place" or "move")) throw new ArgumentException("action must be list, place or move.");
54
+ var point = ModelEditInputs.Vector(args, "position").Multiply(ModelEditInputs.LengthScale(args));
55
+ if (Math.Abs(point.Z) > 1e-9) throw new ArgumentException("Sheet position Z must be zero.");
56
+ var rotation = JsonArgs.GetString(args, "rotation") switch
57
+ {
58
+ null => (ViewportRotation?)null, "none" => ViewportRotation.None, "clockwise" => ViewportRotation.Clockwise,
59
+ "counterclockwise" => ViewportRotation.Counterclockwise, _ => throw new ArgumentException("Invalid rotation."),
60
+ };
61
+ return ModelEditBatch.Run(doc, Name, args, new[] { new ModelEditBatch.Step(new() { ["action"] = action }, () =>
62
+ {
63
+ Element placement;
64
+ object? before = null;
65
+ if (action == "place")
66
+ {
67
+ var sheet = doc.GetElement(Id("sheet_id")) as ViewSheet ?? throw new ArgumentException("sheet_id is not a sheet.");
68
+ if (sheet.IsPlaceholder) throw new ArgumentException("Cannot place content on a placeholder sheet.");
69
+ var view = doc.GetElement(Id("view_id")) as View ?? throw new ArgumentException("view_id is not a view or schedule.");
70
+ if (view is ViewSchedule schedule)
71
+ {
72
+ if (rotation != null) throw new ArgumentException("Schedules do not support viewport rotation.");
73
+ placement = ScheduleSheetInstance.Create(doc, sheet.Id, schedule.Id, point);
74
+ }
75
+ else
76
+ {
77
+ if (!Viewport.CanAddViewToSheet(doc, sheet.Id, view.Id)) throw new ArgumentException("This view cannot be added to that sheet; it may already be placed.");
78
+ placement = Viewport.Create(doc, sheet.Id, view.Id, point);
79
+ }
80
+ }
81
+ else
82
+ {
83
+ placement = doc.GetElement(Id("placement_id")) ?? throw new ArgumentException("placement_id was not found.");
84
+ if (args.TryGetProperty("sheet_id", out _) && placement.OwnerViewId != Id("sheet_id")) throw new ArgumentException("The placement does not belong to the expected sheet_id.");
85
+ if (placement.Pinned) throw new ArgumentException("Placement is pinned; it was not unpinned.");
86
+ if (ElementTraits.PlacementKind(placement) == "titleblock_revision_schedule")
87
+ throw new ArgumentException("This is the titleblock's revision schedule; it belongs to the titleblock family and is not moved as a placement.");
88
+ before = Describe(placement);
89
+ if (placement is Viewport viewport) viewport.SetBoxCenter(point);
90
+ else if (placement is ScheduleSheetInstance schedule)
91
+ {
92
+ if (rotation != null) throw new ArgumentException("Schedules do not support viewport rotation.");
93
+ schedule.Point = point;
94
+ }
95
+ else throw new ArgumentException("placement_id must identify a viewport or schedule instance.");
96
+ }
97
+ if (rotation != null && placement is Viewport target) target.Rotation = rotation.Value;
98
+ doc.Regenerate();
99
+ if (placement is Viewport positioned) { positioned.SetBoxCenter(point); doc.Regenerate(); }
100
+ return new() { ["before"] = before, ["placement"] = Describe(placement), ["created"] = action == "place", ["id_is_temporary"] = action == "place" && JsonArgs.GetBool(args, "preview", false) };
101
+ }) }).Payload;
102
+ }
103
+ private static object Describe(Element element)
104
+ {
105
+ static double[] Point(XYZ p) => new[] { p.X, p.Y, p.Z };
106
+ return element switch
107
+ {
108
+ Viewport v => new { id = v.Id.Value, unique_id = v.UniqueId, kind = ElementTraits.PlacementKind(v), sheet_id = v.SheetId.Value, view_id = v.ViewId.Value, position = Point(v.GetBoxCenter()), position_kind = "box_center_excluding_label", rotation = v.Rotation.ToString(), unit = "feet", traits = ElementTraits.For(v) } as object,
109
+ ScheduleSheetInstance s => new { id = s.Id.Value, unique_id = s.UniqueId, kind = ElementTraits.PlacementKind(s), sheet_id = s.OwnerViewId.Value, view_id = s.ScheduleId.Value, position = Point(s.Point), position_kind = "insertion_point", unit = "feet", traits = ElementTraits.For(s) },
110
+ _ => throw new ArgumentException("Element is not a sheet placement."),
111
+ };
112
+ }
113
+ }
@@ -1,63 +1,72 @@
1
- using System.Text.Json;
2
- using Autodesk.Revit.DB;
3
-
4
- namespace RevitBridge.Tools;
5
-
6
- internal sealed class ManageSheets : ITool
7
- {
8
- public string Name => "manage_sheets";
9
- public string Label => "Manage Sheets";
10
- public string Tier => "advanced";
11
- public bool Write => true;
12
- public string Description => "Create or rename/renumber a drawing sheet. Creation requires name and number; optional titleblock_type_id chooses a loaded titleblock FamilySymbol, otherwise creates a sheet without a titleblock. Update requires sheet_id and accepts name/number. Revit validates unique sheet numbers and valid text; sheet names may repeat; the call rolls back on failure. preview=true commit-validates and rolls back, and new preview sheet IDs are temporary. Use manage_sheet_placements for views/schedules, get_elements for querying sheets, and delete_elements for removal.";
13
- public object ParametersSchema => new
14
- {
15
- type = "object", properties = new
16
- {
17
- action = new { type = "string", @enum = new[] { "create", "update" } },
18
- sheet_id = new { type = "integer", minimum = 1 }, name = new { type = "string", minLength = 1 }, number = new { type = "string", minLength = 1 },
19
- titleblock_type_id = new { type = "integer", minimum = 1, description = "Creation only; omitted means no titleblock." }, preview = ModelEditInputs.PreviewSchema,
20
- }, required = new[] { "action" },
21
- };
22
- public object Execute(JsonElement args, ToolContext context)
23
- {
24
- var doc = context.Document ?? throw new NoActiveDocumentException();
25
- string action = JsonArgs.GetString(args, "action") ?? "";
26
- if (action is not ("create" or "update")) throw new ArgumentException("action must be create or update.");
27
- string? ReadText(string key)
28
- {
29
- if (!args.TryGetProperty(key, out var value)) return null;
30
- if (value.ValueKind != JsonValueKind.String || string.IsNullOrWhiteSpace(value.GetString())) throw new ArgumentException($"{key} must be a nonempty string.");
31
- return value.GetString();
32
- }
33
- string? name = ReadText("name"), number = ReadText("number");
34
- if (action == "create" && (name == null || number == null)) throw new ArgumentException("Sheet creation requires name and number.");
35
- if (action == "update" && args.TryGetProperty("titleblock_type_id", out _)) throw new ArgumentException("titleblock_type_id is only supported when creating a sheet; use change_element_types on an existing titleblock instance.");
36
- return ModelEditBatch.Run(doc, Name, args, new[] { new ModelEditBatch.Step(new() { ["action"] = action }, () =>
37
- {
38
- ViewSheet sheet;
39
- object? before = null;
40
- if (action == "create")
41
- {
42
- var typeId = ElementId.InvalidElementId;
43
- if (args.TryGetProperty("titleblock_type_id", out _))
44
- {
45
- typeId = new ElementId(JsonArgs.GetLong(args, "titleblock_type_id") ?? 0);
46
- var type = doc.GetElement(typeId) as FamilySymbol;
47
- if (type?.Category?.Id.Value != (long)BuiltInCategory.OST_TitleBlocks) throw new ArgumentException("titleblock_type_id must identify a titleblock FamilySymbol.");
48
- }
49
- sheet = ViewSheet.Create(doc, typeId);
50
- }
51
- else
52
- {
53
- sheet = doc.GetElement(new ElementId(JsonArgs.GetLong(args, "sheet_id") ?? 0)) as ViewSheet ?? throw new ArgumentException("sheet_id is not a sheet.");
54
- before = Describe(sheet);
55
- }
56
- if (number != null) sheet.SheetNumber = number;
57
- if (name != null) sheet.Name = name;
58
- doc.Regenerate();
59
- return new() { ["before"] = before, ["sheet"] = Describe(sheet), ["created"] = action == "create", ["id_is_temporary"] = action == "create" && JsonArgs.GetBool(args, "preview", false) };
60
- }) }).Payload;
61
- }
62
- private static object Describe(ViewSheet sheet) => new { id = sheet.Id.Value, unique_id = sheet.UniqueId, name = sheet.Name, number = sheet.SheetNumber, placeholder = sheet.IsPlaceholder };
63
- }
1
+ using System.Text.Json;
2
+ using Autodesk.Revit.DB;
3
+
4
+ namespace RevitBridge.Tools;
5
+
6
+ internal sealed class ManageSheets : ITool
7
+ {
8
+ public string Name => "manage_sheets";
9
+ public IReadOnlyList<string> DocumentKinds => DocumentKind.ProjectOnly;
10
+ public IReadOnlyList<string> Keywords => new[] { "sheet", "drawing sheet", "sheet number", "rename sheet", "renumber", "titleblock", "new sheet" };
11
+ public IReadOnlyList<ToolLimit> Limits => new[]
12
+ {
13
+ new ToolLimit("Placing views or schedules on a sheet", "tool", "manage_sheet_placements"),
14
+ new ToolLimit("Revisions and revision clouds", "api", "Revision.Create; RevisionCloud.Create"),
15
+ new ToolLimit("Deleting sheets", "tool", "delete_elements"),
16
+ };
17
+ public string? Verification => "reread";
18
+ public string Label => "Manage Sheets";
19
+ public string Tier => "advanced";
20
+ public bool Write => true;
21
+ public string Description => "Create or rename/renumber a drawing sheet. Creation requires name and number; optional titleblock_type_id chooses a loaded titleblock FamilySymbol, otherwise creates a sheet without a titleblock. Update requires sheet_id and accepts name/number. Revit validates unique sheet numbers and valid text; sheet names may repeat; the call rolls back on failure. preview=true commit-validates and rolls back, and new preview sheet IDs are temporary. Use manage_sheet_placements for views/schedules, get_elements for querying sheets, and delete_elements for removal.";
22
+ public object ParametersSchema => new
23
+ {
24
+ type = "object", properties = new
25
+ {
26
+ action = new { type = "string", @enum = new[] { "create", "update" } },
27
+ sheet_id = new { type = "integer", minimum = 1 }, name = new { type = "string", minLength = 1 }, number = new { type = "string", minLength = 1 },
28
+ titleblock_type_id = new { type = "integer", minimum = 1, description = "Creation only; omitted means no titleblock." }, preview = ModelEditInputs.PreviewSchema,
29
+ }, required = new[] { "action" },
30
+ };
31
+ public object Execute(JsonElement args, ToolContext context)
32
+ {
33
+ var doc = context.Document ?? throw new NoActiveDocumentException();
34
+ string action = JsonArgs.GetString(args, "action") ?? "";
35
+ if (action is not ("create" or "update")) throw new ArgumentException("action must be create or update.");
36
+ string? ReadText(string key)
37
+ {
38
+ if (!args.TryGetProperty(key, out var value)) return null;
39
+ if (value.ValueKind != JsonValueKind.String || string.IsNullOrWhiteSpace(value.GetString())) throw new ArgumentException($"{key} must be a nonempty string.");
40
+ return value.GetString();
41
+ }
42
+ string? name = ReadText("name"), number = ReadText("number");
43
+ if (action == "create" && (name == null || number == null)) throw new ArgumentException("Sheet creation requires name and number.");
44
+ if (action == "update" && args.TryGetProperty("titleblock_type_id", out _)) throw new ArgumentException("titleblock_type_id is only supported when creating a sheet; use change_element_types on an existing titleblock instance.");
45
+ return ModelEditBatch.Run(doc, Name, args, new[] { new ModelEditBatch.Step(new() { ["action"] = action }, () =>
46
+ {
47
+ ViewSheet sheet;
48
+ object? before = null;
49
+ if (action == "create")
50
+ {
51
+ var typeId = ElementId.InvalidElementId;
52
+ if (args.TryGetProperty("titleblock_type_id", out _))
53
+ {
54
+ typeId = new ElementId(JsonArgs.GetLong(args, "titleblock_type_id") ?? 0);
55
+ var type = doc.GetElement(typeId) as FamilySymbol;
56
+ if (type?.Category?.Id.Value != (long)BuiltInCategory.OST_TitleBlocks) throw new ArgumentException("titleblock_type_id must identify a titleblock FamilySymbol.");
57
+ }
58
+ sheet = ViewSheet.Create(doc, typeId);
59
+ }
60
+ else
61
+ {
62
+ sheet = doc.GetElement(new ElementId(JsonArgs.GetLong(args, "sheet_id") ?? 0)) as ViewSheet ?? throw new ArgumentException("sheet_id is not a sheet.");
63
+ before = Describe(sheet);
64
+ }
65
+ if (number != null) ElementNames.AssignSheetNumber(sheet, number);
66
+ if (name != null) ElementNames.Assign(sheet, name);
67
+ doc.Regenerate();
68
+ return new() { ["before"] = before, ["sheet"] = Describe(sheet), ["created"] = action == "create", ["id_is_temporary"] = action == "create" && JsonArgs.GetBool(args, "preview", false) };
69
+ }) }).Payload;
70
+ }
71
+ private static object Describe(ViewSheet sheet) => new { id = sheet.Id.Value, unique_id = sheet.UniqueId, name = sheet.Name, number = sheet.SheetNumber, placeholder = sheet.IsPlaceholder };
72
+ }