pi-revit 0.1.9 → 0.2.1

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.
@@ -3,6 +3,7 @@ import { Type, type TSchema } from "typebox";
3
3
  import { readFile } from "node:fs/promises";
4
4
  import os from "node:os";
5
5
  import path from "node:path";
6
+ import { version as packageVersion } from "../../package.json";
6
7
 
7
8
  interface BridgeInfo {
8
9
  baseUrl: string;
@@ -195,6 +196,17 @@ function registerBridgeTool(pi: ExtensionAPI, descriptor: BridgeToolDescriptor)
195
196
  });
196
197
  }
197
198
 
199
+ /** `pi update --extensions` refreshes this package but not the deployed Revit add-in,
200
+ * so a newer extension can silently talk to an older bridge. The add-in reports the
201
+ * package version it was built from (stamped by scripts/build.ps1); any difference
202
+ * means the update is incomplete. */
203
+ function versionMismatch(addinVersion: unknown): string | null {
204
+ const addin = typeof addinVersion === "string" && addinVersion.length > 0 ? addinVersion : null;
205
+ if (addin === packageVersion) return null;
206
+ const state = addin ? `still runs version ${addin}` : "predates version reporting";
207
+ return `pi-revit ${packageVersion} is installed, but the Revit add-in ${state} — the update is incomplete. Close Revit and run: npx.cmd -y pi-revit (or ask the agent to run scripts\\deploy.ps1 from the installed package, then restart Revit).`;
208
+ }
209
+
198
210
  function registerPing(pi: ExtensionAPI) {
199
211
  pi.registerTool({
200
212
  name: "ping",
@@ -206,8 +218,9 @@ function registerPing(pi: ExtensionAPI) {
206
218
  executionMode: "sequential",
207
219
  async execute(_toolCallId, _params, signal) {
208
220
  const payload = await bridgeRequest("/ping", { method: "GET" }, signal, 10_000);
221
+ const warning = versionMismatch((payload as { addinVersion?: string }).addinVersion);
209
222
  return {
210
- content: [{ type: "text", text: JSON.stringify(payload) }],
223
+ content: [{ type: "text", text: JSON.stringify(payload) + (warning ? `\nWARNING: ${warning}` : "") }],
211
224
  details: payload,
212
225
  };
213
226
  },
@@ -219,6 +232,19 @@ export default async function revitConnector(pi: ExtensionAPI) {
219
232
  // bridge is down, so it is never part of /tools discovery.
220
233
  registerPing(pi);
221
234
 
235
+ // Surface an incomplete update (see versionMismatch) once per session, right
236
+ // where the user lands after running `pi update --extensions`. Bridge down at
237
+ // session start is the normal Revit-closed case: stay quiet.
238
+ pi.on("session_start", async (_event, ctx) => {
239
+ try {
240
+ const payload = (await bridgeRequest("/ping", { method: "GET" }, undefined, 3_000)) as { addinVersion?: string };
241
+ const warning = versionMismatch(payload.addinVersion);
242
+ if (warning) ctx.ui.notify(warning, "warning");
243
+ } catch {
244
+ // No bridge, no verdict.
245
+ }
246
+ });
247
+
222
248
  let descriptors: BridgeToolDescriptor[];
223
249
  try {
224
250
  const payload = (await bridgeRequest("/tools", { method: "GET" }, undefined, DISCOVERY_TIMEOUT_MS)) as {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-revit",
3
- "version": "0.1.9",
3
+ "version": "0.2.1",
4
4
  "description": "Native Pi connector for Autodesk Revit. Run npx.cmd -y pi-revit for the full Windows install.",
5
5
  "author": "Ahmad Altahlawi",
6
6
  "license": "MIT",
package/scripts/build.ps1 CHANGED
@@ -20,6 +20,17 @@ $ErrorActionPreference = 'Stop'
20
20
  $project = Join-Path $PSScriptRoot '..\src\Revit\RevitBridge.csproj'
21
21
 
22
22
  $buildArgs = @('build', $project, '-c', $Configuration)
23
+
24
+ # Stamp the package version into the assembly so the bridge can report which release
25
+ # the deployed add-in came from; the pi extension compares it against its own package
26
+ # version at session start to detect partial updates.
27
+ $packageJson = Join-Path $PSScriptRoot '..\package.json'
28
+ if (Test-Path $packageJson) {
29
+ $packageVersion = (Get-Content $packageJson -Raw | ConvertFrom-Json).version
30
+ if ($packageVersion) {
31
+ $buildArgs += "-p:Version=$packageVersion"
32
+ }
33
+ }
23
34
  if ($TargetFramework) {
24
35
  # Override TargetFrameworks (plural) rather than TargetFramework: NuGet restore ignores a
25
36
  # single -p:TargetFramework and still restores every framework the project declares, so a
@@ -30,7 +30,8 @@ Workflow guidance:
30
30
  - `get_elements` is the listing/counting primitive (`count_only: true` for bare counts). It returns identity fields only (id, name, category, typeName, levelId); read parameter values with `get_element_details`. Prefer a `category` or `of_class` scope when filtering by a parameter's display name.
31
31
  - The selection pipeline is `get_elements` -> ids -> `manage_selection` (action `set`); there is no inline filter on selection.
32
32
  - `set_parameters` is the home for bulk parameter writes AND renames (the `Name` parameter covers levels, views, sheets, types). One transaction per batch; per-element failures are reported.
33
- - Before writing `execute_csharp` code, verify unfamiliar classes/members with `search_api_docs` (works with no document open; first query builds the index and takes a few seconds).
33
+ - Before writing `execute_csharp` code, verify unfamiliar classes/members with `search_api_docs` (works with no document open; first query builds the index and takes a few seconds). The top match carries its remarks, parameter docs, and returns inline, and every public API enum value is searchable — trust the result over guessing or web search; narrow the query to promote a different match into the top slot.
34
+ - `export_documents` files its output under `Documents\pi-revit\Models\<model title>\exports` automatically when `output_dir` is omitted — keyed to the exported document, so it lands right even across many models. Pass `output_dir` only when the user names a different target.
34
35
 
35
36
  ## execute_csharp playbook
36
37
 
@@ -1,6 +1,7 @@
1
1
  using System.IO;
2
2
  using System.Net;
3
3
  using System.Net.Sockets;
4
+ using System.Reflection;
4
5
  using System.Text;
5
6
  using System.Text.Json;
6
7
 
@@ -22,6 +23,15 @@ namespace RevitBridge
22
23
  {
23
24
  private const int DefaultPort = 47777;
24
25
  private const int MaxPort = 47797;
26
+
27
+ /// <summary>Package version stamped into the assembly by scripts/build.ps1. The pi
28
+ /// extension compares this against its own package version to detect partial
29
+ /// updates (npm package updated, add-in not redeployed); a build made without
30
+ /// the stamp reports its default assembly version instead.</summary>
31
+ private static readonly string AddinVersion =
32
+ typeof(BridgeServer).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion?.Split('+')[0]
33
+ ?? typeof(BridgeServer).Assembly.GetName().Version?.ToString(3)
34
+ ?? "unknown";
25
35
  private const int MaxRequestBytes = 4_000_000;
26
36
  private const int MaxContentChars = 12_000;
27
37
 
@@ -260,7 +270,7 @@ namespace RevitBridge
260
270
  private async Task<(int Status, object Response)> RouteAsync(string method, string path, Dictionary<string, string> query, string body, CancellationToken token)
261
271
  {
262
272
  if (method == "GET" && path == "/ping")
263
- return (200, new { ok = true, service = "revit-bridge", revitVersion = _revitVersion, pid = Environment.ProcessId });
273
+ return (200, new { ok = true, service = "revit-bridge", revitVersion = _revitVersion, pid = Environment.ProcessId, addinVersion = AddinVersion });
264
274
 
265
275
  if (method == "GET" && path == "/tools")
266
276
  {