@thatopen/services 0.4.0 → 0.6.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.
@@ -1,256 +1,375 @@
1
1
  # That Open — Revit Collaboration Quickstart (for AI assistants)
2
2
 
3
- You are an AI assistant. A user pointed you at this guide so you can set up or join
4
- **real‑time Revit collaboration** through the That Open platform. Follow the steps **in
5
- order**. Ask the user for anything you don't already have. **You may run the setup commands
6
- yourself** (install the CLI, install the add‑in, launch Revit) — do it, don't just tell the
7
- user to, *except* where a step says only the user can. Everything is driven by the
8
- `thatopen` CLI.
3
+ You are an AI assistant. A user pointed you at this guide so you can set up or join **real-time
4
+ Revit collaboration** through the That Open platform, and review the **proposals** other tools send
5
+ into their model. Follow the steps **in order**. Ask the user for anything you don't already have.
6
+ **You may run the setup commands yourself** — install the CLI, install the add-in, launch Revit —
7
+ *except* where a step says only the user can.
8
+
9
+ Needs add-in **1.2.17 or later**. `thatopen revit status` prints `addinVersion`; if it is older,
10
+ Step 2 updates it. Several things below did not exist or behaved differently before that.
9
11
 
10
12
  ## What this does
11
- Multiple people work on **one shared Revit central model** using Revit's native
12
- worksharing. The central lives on the That Open platform. Each person has their own local;
13
- when they **sync**, their changes go up and their teammates' come down. All syncs are
14
- **queued**, so the central never conflicts or diverges.
13
+
14
+ Two halves, and they are independent. A team can use the first without ever touching the second.
15
+
16
+ **Collaboration.** Several people work on **one shared Revit central** using Revit's own
17
+ worksharing. The central lives on the platform. Everyone has their own local; syncing sends their
18
+ changes up and brings the team's down. Syncs are **queued**, so the central never diverges.
19
+
20
+ **Proposals.** A change authored *outside* Revit arrives as a proposal: a list of adds, edits and
21
+ deletions naming Revit elements. Somebody in Revit reads it and decides. Nothing is applied behind
22
+ anyone's back, and applying it is an ordinary Revit edit that syncs like any other.
23
+
24
+ The proposal system is **open on the authoring side on purpose**. This package does not care what
25
+ wrote one — a Rhino plug-in, a cloud component, a script, a web app. What it defines is the format
26
+ and what Revit does when one arrives. Rhino is the example that exists today; it is an example, not
27
+ the point.
15
28
 
16
29
  ## Rules (follow throughout)
30
+
17
31
  - **Never** print, echo, store, or commit the user's access token.
18
32
  - **Ask, don't assume.** Missing a project id, file path, or central name? Ask first.
19
- - **Use only the `thatopen` CLI** for platform actions. Don't call HTTP APIs by hand.
20
- - You may **install software and launch Revit** on the user's machine — briefly tell the
21
- user what you're about to run before you run it.
22
- - After each command, **check the output** before moving on.
33
+ - Prefer the **`thatopen` CLI** for platform actions. For the things it does not cover — proposals,
34
+ and reading who holds what — talk to the **add-in's local API** as described in *Talking to the
35
+ add-in directly* below. Do not call the platform's own HTTP API by hand.
36
+ - You may **install software and launch Revit** on the user's machine. Say what you are about to
37
+ run, briefly, before you run it.
38
+ - After each command, **check the output** before moving on. A command that answered is not the
39
+ same as a command that did what you wanted.
23
40
 
24
41
  ---
25
42
 
26
43
  ## Step 0 — Ask what the user wants to do
27
- Ask the user:
44
+
28
45
  > "What would you like to do?
29
46
  > (A) **Share** a Revit model with my team for the first time.
30
47
  > (B) **Connect** to a shared central a teammate already uploaded.
31
- > (C) I **already have my local open** in Revit — just sync it."
32
-
33
- Then collect the inputs for their choice (ask now — you'll need them below):
48
+ > (C) I **already have my local open** in Revit — just sync it.
49
+ > (D) **Review a proposal** somebody sent into my model."
34
50
 
35
- - **(A) Share:** the **absolute path** to the `.rvt` to share, and a short lowercase
36
- **name** for the shared central (e.g. `tower-central`). Also the platform **Project ID**
37
- (see below). The file may or may not already be a workshared central — you'll check that
38
- in Step 3; either way **the user's original file is never modified** (a copy is uploaded).
51
+ Then collect what that choice needs. Ask now; you will need it below.
39
52
 
40
- - **(B) Connect:** ask the user to identify the existing central by **one** of:
41
- - the **project folder id** of the central — the `revit-<name>` folder inside the
42
- project's `bimterop` folder in the That Open dashboard (copy its id from the folder), **or**
43
- - the **local path** to the shared central on their PC, if they already have it
44
- (looks like `C:\ThatOpenShared\<project>\<name>\<file>.rvt`).
53
+ - **(A) Share:** the **absolute path** to the `.rvt`, a short lowercase **name** for the shared
54
+ central (e.g. `tower-central`), and the platform **Project ID** (in the project's settings and in
55
+ its URL in the dashboard). The file may or may not already be a workshared central — Step 3
56
+ checks. Either way **the user's original file is never modified**; a copy is uploaded.
45
57
 
46
- (If they already have their local *open* in Revit, that's really case **(C)** — just sync.)
58
+ - **(B) Connect:** identify the existing central by **one** of:
59
+ - the **project folder id** of the central — the `revit-<name>` folder inside the project's
60
+ `bimterop` folder in the dashboard, or
61
+ - the **local path**, if they already have it: `C:\ThatOpenShared\<project>\<name>\<file>.rvt`.
47
62
 
48
- - **(A) — Project ID:** find it in the That Open dashboard — open the project; the ID is in
49
- the project settings and the project URL. The user's token (Step 2) must belong to an
50
- account with access to this project, or platform calls fail with **403** (see
51
- Troubleshooting). For **(B)** the folder id / local path already encodes the project, so
52
- you don't need to ask the Project ID separately.
63
+ - **(C)** and **(D):** nothing extra, but Revit must have their local open.
53
64
 
54
- - **(C):** nothing extra — Revit must have their local open.
55
-
56
- Do **not** ask for the access token yet (that's Step 2).
65
+ Do **not** ask for the access token yet. That is Step 1.
57
66
 
58
67
  ---
59
68
 
60
- ## Step 1 — Make sure the tools are ready (do this yourself)
61
- 1. **CLI.** Run:
69
+ ## Step 1 — CLI and login
70
+
71
+ 1. **CLI:**
62
72
  ```
63
73
  npm install -g @thatopen/services@latest
64
74
  ```
65
- Verify `thatopen --version` prints a version. (Needs Node.js 18+; if `node -v` fails,
66
- ask the user to install Node.js, then continue.)
75
+ Check `thatopen --version` prints something. Needs Node.js 18+; if `node -v` fails, ask the user
76
+ to install Node.js first.
67
77
 
68
- 2. **Revit + add‑in.** Run:
69
- ```
70
- thatopen revit status
71
- ```
72
- - Prints `"loaded": true` → the add‑in is running. Go to **Step 2**.
73
- - Errors **"The That Open Revit add‑in is not running"** → work through (a) then (b):
78
+ 2. **Token.** Ask for it, and say exactly where to get it:
79
+
80
+ > "To log in I need your That Open **access token**:
81
+ > 1. Open your dashboard — **production:** https://platform.thatopen.com ·
82
+ > **dev:** https://dev.platform.thatopen.com (use the one that matches your team).
83
+ > 2. Go to **Data → API Tokens**.
84
+ > 3. **Create a new token**, copy it, and paste it here."
74
85
 
75
- **(a) Is Revit 2026 open?** If not, launch it (Windows):
76
86
  ```
77
- powershell -Command "Start-Process 'C:\Program Files\Autodesk\Revit 2026\Revit.exe'"
87
+ thatopen login --token <TOKEN>
78
88
  ```
79
- Cold start can take 1–3 minutes. Wait, then re‑run `thatopen revit status`. If it now
80
- says `"loaded": true`, go to Step 2.
81
-
82
- **(b) Revit is open but status still errors → the add‑in isn't installed. Install it:**
83
- - The add‑in files ship in **this same folder** as this guide (`install.ps1`,
84
- `RevitFlowAddin.dll`, `RevitFlowCore.dll`, `revitflow.addin`). From this folder, run:
85
- ```
86
- powershell -ExecutionPolicy Bypass -File install.ps1
87
- ```
88
- *(If you don't have those files, download the plugin zip here, unzip it, then run
89
- `install.ps1` from the unzipped folder:
90
- https://drive.google.com/file/d/1HL_Ti7N_qN0Q-X7vNYOQst3yEgIY-xXO/view?usp=drive_link )*
91
- - **Restart Revit** so it loads the add‑in: close Revit, then launch it again with the
92
- `Start-Process` command above.
93
- - On the first launch after installing, Revit shows an **"unsigned add‑in"** prompt.
94
- **Only the user can click it — ask them to choose "Always Load".**
95
- - Re‑run `thatopen revit status` every ~10s until it prints `"loaded": true`.
89
+ Production is the default. For dev, add `--api-url https://dev.platform.thatopen.com`.
90
+
91
+ **Log in before Step 2**, not after: installing the add-in downloads a private package and needs
92
+ these credentials.
96
93
 
97
94
  ---
98
95
 
99
- ## Step 2 — Log in
100
- The user needs a personal **access token** from the That Open platform. Ask them for it and
101
- tell them exactly where to get it:
96
+ ## Step 2 — The add-in
97
+
98
+ ```
99
+ thatopen revit status
100
+ ```
101
+
102
+ - Prints `"loaded": true` → the add-in is running. Check `addinVersion` is **1.2.17 or later**; if
103
+ not, update it with the same command as below. Then go to Step 3.
104
+ - Errors *"The That Open Revit add-in is not running"* → work through (a), then (b).
102
105
 
103
- > "To log in I need your That Open **access token**. To create one:
104
- > 1. Open your That Open dashboard in a browser — **production:** https://platform.thatopen.com
105
- > · **dev:** https://dev.platform.thatopen.com (use the one that matches your team).
106
- > 2. Go to **Data → API Tokens**.
107
- > 3. Click **Create a new token** and **copy** it.
108
- > 4. Paste it here."
106
+ **(a) Is Revit 2026 open?** If not, launch it:
107
+ ```
108
+ powershell -Command "Start-Process 'C:\Program Files\Autodesk\Revit 2026\Revit.exe'"
109
+ ```
110
+ A cold start takes a while. Re-run `thatopen revit status`.
109
111
 
110
- **Never print, echo, or store the token.** Once the user pastes it, run:
112
+ **(b) Revit is open but status still errors → install the add-in.** Revit must be **closed** for
113
+ this, because it holds its add-in files open while it runs. Ask the user to close it, then:
111
114
  ```
112
- thatopen login --token <TOKEN>
115
+ thatopen revit install
113
116
  ```
114
- - **Production is the default.** For the **dev** environment, also add:
115
- `--api-url https://dev.platform.thatopen.com`
116
- - Success prints `Logged in successfully…`. If it fails with **"Unauthorized"**, the token
117
- is invalid or for the other environment — see **Troubleshooting**, then ask for a fresh
118
- token and retry.
117
+ This fetches the current package from the registry and runs the installer that ships inside it.
118
+ `--version <v>` pins a specific one; the default is the latest.
119
+
120
+ Then **launch Revit again**. On the first start after an install, Revit shows an **unsigned add-in**
121
+ prompt. **Only the user can answer it — ask them to choose "Always Load".** There is no way around
122
+ it from a script, and it comes back after every update until the add-in is signed.
123
+
124
+ Re-run `thatopen revit status` every ten seconds or so until `"loaded": true`.
119
125
 
120
126
  ---
121
127
 
122
128
  ## Step 3 — Do the action
123
129
 
124
130
  ### (A) Share a model — `inspect`, then `publish-central`
125
- First check whether the file is already a workshared central:
131
+
126
132
  ```
127
133
  thatopen revit inspect --file "<FILE>"
128
134
  ```
129
- - **`"isCentral": true`** → it's already a central. Tell the user: *"This is already a
130
- central; I'll upload a copy to the shared location — your original file won't be touched."*
131
- Then publish (no `--convert` needed):
135
+
136
+ - **`"isCentral": true`** → already a central. Tell the user you will upload a copy and their
137
+ original is untouched, then:
132
138
  ```
133
139
  thatopen revit publish-central --project <PROJECT> --doc <DOC> --file "<FILE>"
134
140
  ```
135
- - **`"isCentral": false`** → it's a plain model. **Tell the user and ask for consent:**
136
- *"This file isn't a shared central yet. To share it I need to turn it into one. I'll do
137
- that on a COPY, so your original file stays exactly as it is. Shall I go ahead?"*
138
- Only after the user agrees, publish **with `--convert`**:
141
+ - **`"isCentral": false`** → a plain model. **Ask for consent first:** *"This file isn't a shared
142
+ central yet. To share it I need to turn it into one. I'll do that on a COPY, so your original
143
+ stays exactly as it is. Shall I go ahead?"* Only then:
139
144
  ```
140
145
  thatopen revit publish-central --project <PROJECT> --doc <DOC> --file "<FILE>" --convert
141
146
  ```
142
147
 
143
- `<DOC>` is the short central name from Step 0; `<FILE>` is the `.rvt` path. Publishing saves
144
- the central at the shared canonical location, uploads it, and opens **your** local in Revit
145
- (takes a bit). Success: `Published (…). Central: … (version N). Your original file was not
146
- modified.` Tell teammates to connect with the **project folder id** shown in the dashboard,
147
- or with `thatopen revit join --project <PROJECT> --doc <DOC>`.
148
-
149
- > If you skip `inspect` and the file isn't a central, `publish-central` will refuse with a
150
- > message telling you to re-run with `--convert` — still ask the user first.
148
+ Publishing uploads the central and opens **the user's own local** in Revit. Success ends with
149
+ `Published (…). Central: … (version N). Your original file was not modified.` Teammates connect with
150
+ the folder id from the dashboard, or with `--project` and `--doc`.
151
151
 
152
152
  ### (B) Connect to a central — `join`
153
- Use whichever identifier the user gave you in Step 0:
153
+
154
154
  ```
155
- thatopen revit join --folder-id <FOLDER_ID> # the revit-<name> folder id in the project
156
- thatopen revit join --path "<C:\ThatOpenShared\...\central.rvt>" # a local shared-central path
155
+ thatopen revit join --folder-id <FOLDER_ID>
156
+ thatopen revit join --path "C:\ThatOpenShared\<project>\<name>\<file>.rvt"
157
157
  ```
158
- (Advanced: `--project <PROJECT> --doc <DOC>` also works if the user knows both.)
159
- This downloads the central, creates the user's **local**, and opens it in Revit.
160
- Success: `Joined. Your local was created and opened in Revit: …`.
158
+ `--project <PROJECT> --doc <DOC>` also works when the user knows both. This downloads the central,
159
+ creates the user's local, and opens it.
161
160
 
162
161
  ### (C) Already have a local open — `sync`
162
+
163
163
  ```
164
164
  thatopen revit sync
165
165
  ```
166
- Reads everything from the open local. Nothing else needed.
166
+
167
+ ### (D) Review a proposal
168
+
169
+ Go to **Step 6**.
167
170
 
168
171
  ---
169
172
 
170
173
  ## Step 4 — Work, then sync
171
- Tell the user to **model normally** in the local Revit opened. To send their changes to the
172
- team and pull the team's changes, run:
174
+
175
+ Tell the user to **model normally**. To send their changes and pull the team's, they use **Revit's
176
+ own Synchronize with Central** on the Collaborate tab, exactly as on any worksharing job. The add-in
177
+ listens for it: it takes a turn in the team queue and brings the central up to date *before* Revit
178
+ merges, then publishes the result. A corner notice reports each step and ends with
179
+ `Synced. vN → vM.`
180
+
181
+ There is no "sync to team" button, on purpose. Two buttons that must mean the same thing are a
182
+ question nobody should have to answer twice a day.
183
+
184
+ For a script or an agent, the same round trip is `thatopen revit sync`.
185
+
186
+ ---
187
+
188
+ ## Step 5 — Worksets, so two people don't edit the same thing
189
+
190
+ **Claiming one is Revit's own dialog:** Collaborate → Worksets, tick *Editable* on the row you want.
191
+ Same dialog, same rules and same messages as any Revit job. Ownership reaches everybody within
192
+ seconds, because the add-in replicates the worksharing files the central keeps beside it and each
193
+ Revit re-reads them by itself.
194
+
195
+ Only **one person at a time** owns a workset, and **Revit** enforces it: a teammate who tries to
196
+ take what you hold is told who holds it. That also means only *you* can give yours back — there is
197
+ no API that relinquishes on somebody else's behalf, so "ask them to release it" is the real answer
198
+ rather than a workaround.
199
+
200
+ **Release** by relinquishing in Revit, or simply by syncing, which relinquishes as part of the
201
+ dialog's terms.
202
+
203
+ From a script:
173
204
  ```
174
- thatopen revit sync
205
+ thatopen revit worksets # who holds what
206
+ thatopen revit take --workset "<NAME>"
207
+ thatopen revit untake --workset "<NAME>"
175
208
  ```
176
- …or click **"Sync to team"** in the **"That Open"** panel of Revit's **Add‑Ins** tab.
177
- Success: `Synced. vN → vM.` Repeat as often as they like; syncs are queued, no conflicts.
209
+
210
+ > Editing an element makes you its **borrower** automatically, element by element. Taking a workset
211
+ > makes you its **owner**. Revit only blocks editing worksets owned by **somebody else**; free ones
212
+ > are borrowed on demand.
178
213
 
179
214
  ---
180
215
 
181
- ## Step 5 — Worksets (so two people don't edit the same thing)
182
- Syncs never corrupt the central, but if **two people edit the SAME element** without
183
- coordinating, the second one's sync is rejected and their local can get stuck. To avoid
184
- that, claim the part of the model you're about to edit using **worksets** — the unit of
185
- ownership. Typically one workset per area or per person (this central already has one per
186
- floor/level).
216
+ ## Step 6 — Proposals
217
+
218
+ A proposal is a change authored **outside** this Revit: a set of `add`, `set` and `remove` entries
219
+ naming elements by their Revit UniqueId, carried in a `.frag` and queued against one document. It is
220
+ a request, not an edit. Until a person applies it, nothing in the model has moved.
221
+
222
+ **Who writes them is deliberately open.** A Rhino plug-in, a cloud component, a web app, a script:
223
+ anything that can produce the format can queue one. This package's job starts when one arrives,
224
+ which is why nothing below asks where it came from.
225
+
226
+ If the user asks how to send changes *from* their own tool — or you are being asked to write that
227
+ tool — the format is documented: **[Writing a flow plugin](./flow-plugin-guide.md)** is the byte
228
+ contract, and **[the architecture notes](./flow-architecture.md)** say why it is shaped that way.
229
+ Publishing a proposal is the smallest of the three jobs described there: it needs no ownership, no
230
+ history, and no collaboration layer.
231
+
232
+ **This is where you use the add-in's local API** — the CLI has no proposal commands yet.
187
233
 
188
- **See the worksets and who owns each:**
234
+ **List what is waiting:**
189
235
  ```
190
- thatopen revit worksets
236
+ POST /ops → { ok, ops: [ { OpId, Title, Author, State, BaseCommit, AffectedIds } ] }
191
237
  ```
238
+ `State` is `pending`, `applied` or `discarded`. Show the user the pending ones by title and author.
192
239
 
193
- **Claim a workset before editing it — two equivalent ways:**
194
- - **Ribbon (easiest):** in Revit's **Add-Ins → That Open** panel, select any element that
195
- belongs to the workset you want, then click **"Take workset"**.
196
- - **CLI:**
197
- ```
198
- thatopen revit take --workset "<NAME>"
199
- ```
200
- Only **one person at a time** can own a workset. If someone else already holds it, you get
201
- `✗ held by <user>` — coordinate or pick another. If two people click Take at the same
202
- instant, the platform lock gives it to exactly one and denies the other (no corruption).
203
-
204
- **⚠️ Ownership only protects you AFTER a sync round.** Taking a workset is instant for the
205
- *claim* (nobody else can take it), but Revit only **blocks teammates' edits** once the
206
- ownership reaches their copy: **you Sync (push your ownership), then each teammate Syncs
207
- (pulls it).** So the reliable sequence is:
208
- 1. `thatopen revit take --workset "<NAME>"` (or the Take workset button)
209
- 2. `thatopen revit sync` ← you push the ownership
210
- 3. teammates `thatopen revit sync` ← now Revit blocks them from editing your workset
211
-
212
- Until teammates have synced, they could still auto-borrow an element in that workset by
213
- editing it directly. After the round, they'll see it as owned by you and be blocked.
214
-
215
- **Release when you're done** so teammates can take it:
216
- - **Ribbon:** click **"Release worksets"** (frees everything you own).
217
- - **CLI:** `thatopen revit untake --workset "<NAME>"`
218
- Then `sync` so the release propagates.
219
-
220
- > Note: simply editing an element makes you its **borrower** automatically (element-level);
221
- > **taking a workset** makes you the **owner** (workset-level). Revit only blocks editing
222
- > worksets owned by **someone else** — so the Take→Sync→Sync round above is what creates the
223
- > protection.
240
+ **Check one before touching anything.** This is read-only; no transaction is opened:
241
+ ```
242
+ POST /op-check { "opId": "op-…" }
243
+ ```
244
+ Read three things out of the answer, and tell the user all three:
245
+
246
+ - `plan.canApply` — whether it can be applied right now.
247
+ - `plan.blocker` — if not, why, phrased as the next thing to do. Read it out rather than paraphrase
248
+ it. It names the person to go and ask when a workset is held by somebody, and it points at Revit's
249
+ own dialog when the workset is merely free. "You need permissions" loses both.
250
+ - `authoredAgainst`, `youAreOn`, `behind` — the version the proposal was written against and the one
251
+ the model is on now. **A proposal does not expire and is not blocked for being old**: it says
252
+ *move this by two metres*, not *put it at this coordinate*, so it still means what it said. But
253
+ when `behind` is present, say so before the user approves. The model has moved underneath it.
254
+
255
+ **Expect this one, it is not a bug:** an `add` lands on the document's **active** workset, so
256
+ whoever applies has to hold *that* one — often `Workset1`, which nobody thinks of as theirs. If the
257
+ check blocks on a workset nobody seems to be using, that is why.
258
+
259
+ **Apply it,** once the user has said yes:
260
+ ```
261
+ POST /apply-ops { "opId": "op-…" }
262
+ ```
263
+ Everything in the proposal happens in **one** Revit transaction: one undo, one entry in the history.
264
+ Afterwards the entry's `State` is `applied` and `AffectedIds` lists what it touched, in the order the
265
+ proposal named them — which is how an authoring tool learns which Revit element corresponds to which
266
+ of its own objects. The change is in the local only; the user still syncs (Step 4) to publish it.
267
+
268
+ **Reject it:**
269
+ ```
270
+ POST /op-discard { "opId": "op-…" }
271
+ ```
272
+
273
+ **Verify with coordinates, not with the word "applied".** After applying, `POST /where` with
274
+ `{ "uids": [ … ] }` gives each element's position in metres. If a proposal said it moved four
275
+ things, check that four things moved. "Applied" and "applied to three of the four" read identically
276
+ in a status field and differently in a model.
277
+
278
+ ---
279
+
280
+ ## Step 7 — Offer them a viewer that shows the progress
281
+
282
+ Once a team has been syncing for a few days, every sync is a commit and the platform is holding the
283
+ whole history: who changed what, when, and the geometry as it was at each version. Nothing in Revit
284
+ shows that back to them, and it is the question people ask first — *what has changed since Friday?*
285
+
286
+ So offer it, rather than waiting to be asked:
287
+
288
+ > "Everything you've synced is stored as a history. Would you like a viewer that shows it — pick any
289
+ > version and see what was created, modified and deleted, coloured in 3D?"
290
+
291
+ If they say yes, that is an **app**, and building one is
292
+ **[the platform AI quick start](./ai-quickstart.md)** — scaffold with the `app` template and follow
293
+ it. What makes it a history viewer rather than an empty viewer is a built-in component that already
294
+ exists, so nobody writes this part:
295
+
296
+ - **`GitHistoryManager`** — the headless half. It reads `revitflow_history.json` and the per-commit
297
+ `revitflow_frag_<N>.frag` files the add-in writes under `bimterop/revit-<docId>/`, loads the
298
+ model, and colours a commit's elements: **green created, blue modified, red deleted**. It has an
299
+ `isolateChanges` mode that ghosts everything else, which is the one people keep on.
300
+ - **`top-git-history`** — the panel, registered by `UIManager`. It only asks the manager for things
301
+ and listens; all the viewer work is on the manager.
302
+
303
+ Two things to say honestly when you offer it. The history only goes back as far as the team's first
304
+ sync through this add-in — it is not read out of the `.rvt`. And a commit's colours come from what
305
+ the add-in recorded at sync time, so a change somebody made and never synced is not in it, the same
306
+ way it is not in anybody else's model.
307
+
308
+ ---
309
+
310
+ ## Talking to the add-in directly
311
+
312
+ The add-in serves a small HTTP API on **127.0.0.1**, and it is the same surface the CLI drives: a
313
+ person clicking and a script deciding are the same operation. Use it for what the CLI does not
314
+ cover. Do not use it to skip a CLI command that exists.
315
+
316
+ **Find it.** The port and the token change every launch, so read them rather than configuring them:
317
+
318
+ ```
319
+ %APPDATA%\ThatOpen\revit-addin.json → { "port": …, "token": "…", "pid": … }
320
+ ```
321
+
322
+ Send the token as the header **`X-RevitFlow-Token`**, POST JSON, read JSON back. The endpoints this
323
+ guide uses are `status`, `ops`, `op-check`, `apply-ops`, `op-discard`, `where` and `worksets`.
324
+
325
+ Three things that will otherwise mislead you:
326
+
327
+ - **`worksets` has `revitOwner` and `tocOwner`, and no field called `owner`.** Reading `owner`
328
+ returns nothing for every row, which looks exactly like "nobody owns anything" and is a lie.
329
+ `revitOwner` is Revit's answer, and Revit's answer is the one that decides.
330
+ - **The add-in serves one request at a time.** A machine in the middle of a sync answers nothing,
331
+ and from outside that is indistinguishable from a crash. Diagnose from
332
+ `%APPDATA%\ThatOpen\revitflow.log`, which keeps being written throughout. Never conclude anything
333
+ from a timeout alone.
334
+ - **A modal dialog in Revit stops everything.** The add-in does its work when Revit is idle, and a
335
+ dialog waiting for a click means Revit never is. If a call hangs, ask the user to look at Revit's
336
+ window before assuming something is broken.
224
337
 
225
338
  ---
226
339
 
227
340
  ## Troubleshooting
228
- - **`thatopen login` fails with "Unauthorized"** → the token is invalid/expired, or it's
229
- for a different environment than `--api-url`. Ask the user to generate a fresh token in
230
- the dashboard (Data → API Tokens) for the SAME environment: production tokens use **no**
231
- `--api-url`; dev tokens use `--api-url https://dev.platform.thatopen.com`. Then retry.
232
- - **publish/join fails with HTTP 403** on `item/folder?projectId=…` → login worked but the
233
- user's account is **not authorized for that Project ID** (wrong project, wrong
234
- environment, or no access). Confirm the Project ID with the user and that their token
235
- (Step 2) belongs to an account with access to it, then retry.
236
- - **"add‑in not running"** after Revit is open → the add‑in isn't installed; do Step 1(b).
237
- - **"Could not reach the Revit add‑in"** → Revit was closed; reopen it and retry.
238
- - **"Not logged in"** → do Step 2.
239
- - **publish says a value is missing** → re‑run with `--project`, `--doc`, and `--file`.
240
- - **publish refuses: "not a workshared central … re-run with convert=true"** → the file is a
241
- plain model. Ask the user for consent to convert a **copy** (original untouched), then add
242
- `--convert`.
243
- - **`join` says "Identify the central … with one of …"** → provide `--folder-id`, or
244
- `--path`, or both `--project` and `--doc`.
245
- - **`take` returns `✗ held by <user>`** → someone else owns that workset. Ask them to
246
- Release + sync, or claim a different workset. This is expected, not an error.
247
- - **A teammate can still edit "my" workset** → ownership hasn't reached them yet. Make sure
248
- **you synced after taking it, and they synced afterwards** (Step 5). Until both sync
249
- rounds happen, Revit on their side doesn't know you own it.
341
+
342
+ - **`thatopen login` fails with "Unauthorized"** → the token is invalid, expired, or from the other
343
+ environment. Production tokens use no `--api-url`; dev tokens use
344
+ `--api-url https://dev.platform.thatopen.com`. Ask for a fresh one from the same environment.
345
+ - **HTTP 403 on `item/folder?projectId=…`** → login worked, but that account has no access to that
346
+ Project ID. Confirm the id and the environment with the user.
347
+ - **"add-in not running" while Revit is open** → it is not installed. Step 2(b).
348
+ - **`thatopen revit install` refuses** → Revit is still open. Close it.
349
+ - **`take` answers `taken: false` with `deniedBy`** → somebody else holds that workset. Expected,
350
+ not an error. Ask them to release and sync, or take another.
351
+ - **`take` answers `offline: true`** → the platform is unreachable. The take is **refused, not
352
+ queued**, and deliberately: the platform is what arbitrates the race, so with it gone nobody can
353
+ know whether a colleague already holds it. Nothing was changed. Retry when `status` says
354
+ `online: true`.
355
+ - **`locks` answers `offline: true` instead of a list** → the same outage. That is **not** an empty
356
+ list; claims still stand. `worksets` still answers from Revit with `registry: false`, and that
357
+ half needs no network at all — use it to see what the user themselves holds.
358
+ - **A teammate can still edit "my" workset** → ownership has not reached them yet. You must sync
359
+ after taking it, and they must sync afterwards.
360
+ - **A proposal blocks on a workset nobody seems to own** → it is probably the **active** workset,
361
+ needed by its `add` entries. See Step 6.
362
+ - **Everything hangs and nothing new is in the log** → a Revit dialog is waiting for a click.
363
+
364
+ ---
250
365
 
251
366
  ## Rules recap (for the AI)
252
- - Ask for every value you don't have — never guess a project id, file path, or central name.
253
- - Never echo or store the user's token.
254
- - You may install the CLI/add‑in and launch Revit yourself; only the "Always Load" prompt
255
- needs the user.
256
- - Use only the `thatopen` CLI commands above; verify each command's output before proceeding.
367
+
368
+ - Ask for every value you do not have. Never guess a project id, a file path or a central name.
369
+ - Never echo or store the token.
370
+ - You may install the CLI and the add-in and launch Revit. Only the "Always Load" prompt needs the
371
+ user — and so does every decision about applying a proposal.
372
+ - CLI first; the add-in's local API for proposals and for reading ownership; never the platform's
373
+ own HTTP API by hand.
374
+ - Read each answer before the next step, and prefer a measured value to a status word: coordinates
375
+ over "applied", `revitOwner` over "it should be fine".
package/package.json CHANGED
@@ -15,7 +15,7 @@
15
15
  "access": "public"
16
16
  },
17
17
  "private": false,
18
- "version": "0.4.0",
18
+ "version": "0.6.0",
19
19
  "main": "dist/index.cjs.js",
20
20
  "module": "dist/index.es.js",
21
21
  "types": "dist/index.d.ts",