@thatopen/services 0.6.0 → 0.7.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 (71) hide show
  1. package/README.md +62 -62
  2. package/dist/built-in/index.d.ts +485 -100
  3. package/dist/cli.js +12 -23
  4. package/dist/index.cjs.js +2 -2
  5. package/dist/index.es.js +41 -50
  6. package/dist/vite-env.d.ts +1 -1
  7. package/docs/ai-quickstart.md +18 -3
  8. package/docs/cli/create.md +29 -29
  9. package/docs/cli/local-server.md +38 -38
  10. package/docs/cli/login.md +32 -32
  11. package/docs/cli/publish.md +31 -31
  12. package/docs/cli/run.md +26 -26
  13. package/docs/cli/serve.md +43 -43
  14. package/docs/cli/swap.md +30 -30
  15. package/docs/flow-architecture.md +1 -1
  16. package/docs/flow-plugin-guide.md +1 -1
  17. package/docs/platform-token.md +81 -0
  18. package/docs/revit-collab-quickstart.md +89 -18
  19. package/docs/rhino-interop-quickstart.md +391 -0
  20. package/package.json +1 -1
  21. package/resources/AGENTS.md +40 -40
  22. package/src/built-in/CDEManager/example.ts +214 -214
  23. package/src/built-in/CDEManager/examples/FileEditing/example.ts +226 -226
  24. package/src/built-in/CDEManager/examples/FileMoves/example.ts +186 -186
  25. package/src/built-in/CDEManager/examples/FileOperations/example.ts +295 -295
  26. package/src/built-in/CDEManager/examples/FileTransfers/example.ts +210 -210
  27. package/src/built-in/CDEManager/examples/FolderManagement/example.ts +230 -230
  28. package/src/built-in/CDEManager/examples/MetadataSchema/example.ts +230 -230
  29. package/src/built-in/CDEManager/examples/MetadataViews/example.ts +166 -166
  30. package/src/built-in/CDEManager/examples/ProjectConfig/example.ts +177 -177
  31. package/src/built-in/UIManager/src/app/example.ts +97 -97
  32. package/src/built-in/UIManager/src/app/examples/AppState/example.ts +140 -140
  33. package/src/built-in/UIManager/src/app/examples/Banner/example.ts +159 -159
  34. package/src/built-in/UIManager/src/app/examples/Contexts/example.ts +123 -123
  35. package/src/built-in/UIManager/src/app/examples/FileDrop/example.ts +124 -124
  36. package/src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts +90 -90
  37. package/src/built-in/UIManager/src/app/examples/Modal/example.ts +163 -163
  38. package/src/built-in/UIManager/src/app/examples/Notifications/example.ts +133 -133
  39. package/src/built-in/UIManager/src/app/examples/ProjectFileStorage/example.ts +150 -150
  40. package/src/built-in/UIManager/src/app/examples/Sidebar/example.ts +102 -102
  41. package/src/built-in/UIManager/src/clashes-panel/example.ts +183 -183
  42. package/src/built-in/UIManager/src/git-history-panel/example.ts +70 -70
  43. package/src/built-in/UIManager/src/models-list/example.ts +122 -122
  44. package/src/built-in/UIManager/src/topics-panel/example.ts +170 -170
  45. package/src/built-in/index.ts +485 -100
  46. package/src/cli/templates/app/index.html +35 -35
  47. package/src/cli/templates/app/package.json +32 -32
  48. package/src/cli/templates/app/src/bim-components/CloudRunner/index.ts +95 -95
  49. package/src/cli/templates/app/src/bim-components/CloudRunner/src/index.ts +1 -1
  50. package/src/cli/templates/app/src/bim-components/CloudRunner/src/types.ts +5 -5
  51. package/src/cli/templates/app/src/bim-components/index.ts +1 -1
  52. package/src/cli/templates/app/src/globals.ts +1 -1
  53. package/src/cli/templates/app/src/ui-components/app-info-section/index.ts +26 -26
  54. package/src/cli/templates/app/src/ui-components/app-info-section/src/index.ts +1 -1
  55. package/src/cli/templates/app/src/ui-components/app-info-section/src/types.ts +15 -15
  56. package/src/cli/templates/app/src/ui-components/cloud-runner-section/index.ts +37 -37
  57. package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/index.ts +1 -1
  58. package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/types.ts +14 -14
  59. package/src/cli/templates/app/src/ui-components/index.ts +2 -2
  60. package/src/cli/templates/app/tsconfig.json +16 -16
  61. package/src/cli/templates/app/vite.config.js +57 -57
  62. package/src/cli/templates/cloud-component/README.md +205 -205
  63. package/src/cli/templates/cloud-component/_thatopen +5 -5
  64. package/src/cli/templates/cloud-component/declarations.json +4 -4
  65. package/src/cli/templates/cloud-component/package.json +21 -21
  66. package/src/cli/templates/cloud-component/src/main.ts +70 -70
  67. package/src/cli/templates/cloud-component/tsconfig.json +16 -16
  68. package/src/cli/templates/cloud-component/vite.config.js +46 -46
  69. package/src/cli/templates/shared/AGENTS.md +8 -8
  70. package/src/cli/templates/shared/CLAUDE.md +1 -1
  71. package/src/cli/templates/shared/_gitignore +5 -5
package/docs/cli/serve.md CHANGED
@@ -1,43 +1,43 @@
1
- ---
2
- description: "Start a local dev server for a browser app. Uses esbuild in watch mode and serves the IIFE bundle on port 4000 with SSE live reload. To connect: open the project on platform.thatopen.com, click the Local App icon, then Get Started."
3
- ---
4
-
5
- ## thatopen serve
6
-
7
- Builds the app in watch mode and serves the IIFE bundle locally. On every save, esbuild rebuilds and the platform reloads the bundle automatically via SSE.
8
-
9
- Does **not** open a browser tab — the app runs inside the platform iframe. Open your project on the platform, then click the debug button to connect it to the local server.
10
-
11
- **Usage:**
12
- ```bash
13
- thatopen serve [flags]
14
- ```
15
-
16
- **Flags:**
17
-
18
- - `--port <port>` — Port to serve the bundle on. Default: `4000`.
19
-
20
- **Endpoints served:**
21
-
22
- - `GET /bundle.js` — The compiled IIFE bundle.
23
- - `GET /bundle.js.map` — Source map.
24
- - `GET /events` — SSE stream for live reload.
25
-
26
- **Example:**
27
- ```bash
28
- thatopen serve
29
- thatopen serve --port 4321
30
- ```
31
-
32
- **Connecting the platform to your local server:**
33
-
34
- 1. Go to [https://platform.thatopen.com](https://platform.thatopen.com) and open a project (create one first if needed).
35
- 2. In the top right corner, click the **Local App** icon.
36
- 3. Click **Get Started**.
37
-
38
- The platform loads the bundle from port 4000 and renders the app inside the project context, with full access to its models, data, and users. The dev server must be running before opening this URL — if nothing is served on port 4000, the platform will fail to load the app.
39
-
40
- The resulting URL follows this pattern:
41
- ```
42
- https://platform.thatopen.com/dashboard/projects/{projectId}/apps/local-app
43
- ```
1
+ ---
2
+ description: "Start a local dev server for a browser app. Uses esbuild in watch mode and serves the IIFE bundle on port 4000 with SSE live reload. To connect: open the project on platform.thatopen.com, click the Local App icon, then Get Started."
3
+ ---
4
+
5
+ ## thatopen serve
6
+
7
+ Builds the app in watch mode and serves the IIFE bundle locally. On every save, esbuild rebuilds and the platform reloads the bundle automatically via SSE.
8
+
9
+ Does **not** open a browser tab — the app runs inside the platform iframe. Open your project on the platform, then click the debug button to connect it to the local server.
10
+
11
+ **Usage:**
12
+ ```bash
13
+ thatopen serve [flags]
14
+ ```
15
+
16
+ **Flags:**
17
+
18
+ - `--port <port>` — Port to serve the bundle on. Default: `4000`.
19
+
20
+ **Endpoints served:**
21
+
22
+ - `GET /bundle.js` — The compiled IIFE bundle.
23
+ - `GET /bundle.js.map` — Source map.
24
+ - `GET /events` — SSE stream for live reload.
25
+
26
+ **Example:**
27
+ ```bash
28
+ thatopen serve
29
+ thatopen serve --port 4321
30
+ ```
31
+
32
+ **Connecting the platform to your local server:**
33
+
34
+ 1. Go to [https://platform.thatopen.com](https://platform.thatopen.com) and open a project (create one first if needed).
35
+ 2. In the top right corner, click the **Local App** icon.
36
+ 3. Click **Get Started**.
37
+
38
+ The platform loads the bundle from port 4000 and renders the app inside the project context, with full access to its models, data, and users. The dev server must be running before opening this URL — if nothing is served on port 4000, the platform will fail to load the app.
39
+
40
+ The resulting URL follows this pattern:
41
+ ```
42
+ https://platform.thatopen.com/dashboard/projects/{projectId}/apps/local-app
43
+ ```
package/docs/cli/swap.md CHANGED
@@ -1,30 +1,30 @@
1
- ---
2
- description: "Toggle or explicitly set the engine library mode between stable public packages (@thatopen/*) and private beta packages (@thatopen-platform/*-beta). Updates package.json and .thatopen, then runs npm install. Source code never changes — aliases handle resolution."
3
- ---
4
-
5
- ## thatopen swap
6
-
7
- Switches the project between stable and beta engine libraries. Without flags, it toggles from the current state. Updates `package.json` dependencies and sets `beta` in `.thatopen` so `thatopen serve`, `thatopen local-server`, and `vite build` all pick up the change automatically.
8
-
9
- Source code stays unchanged — `@thatopen/components` imports resolve to the correct package via esbuild/vite aliases based on the `beta` flag in `.thatopen`.
10
-
11
- **Usage:**
12
- ```bash
13
- thatopen swap # toggle: stable → beta or beta → stable
14
- thatopen swap --beta # force beta
15
- thatopen swap --stable # force stable
16
- ```
17
-
18
- **Flags:**
19
-
20
- - `--beta` — Switch to beta libraries (`@thatopen-platform/*-beta`).
21
- - `--stable` — Switch back to stable public libraries (`@thatopen/*`).
22
-
23
- **Examples:**
24
- ```bash
25
- thatopen swap
26
- thatopen swap --beta
27
- thatopen swap --stable
28
- ```
29
-
30
- > Beta packages are private and the access must be explicitly granted by That Open Company.
1
+ ---
2
+ description: "Toggle or explicitly set the engine library mode between stable public packages (@thatopen/*) and private beta packages (@thatopen-platform/*-beta). Updates package.json and .thatopen, then runs npm install. Source code never changes — aliases handle resolution."
3
+ ---
4
+
5
+ ## thatopen swap
6
+
7
+ Switches the project between stable and beta engine libraries. Without flags, it toggles from the current state. Updates `package.json` dependencies and sets `beta` in `.thatopen` so `thatopen serve`, `thatopen local-server`, and `vite build` all pick up the change automatically.
8
+
9
+ Source code stays unchanged — `@thatopen/components` imports resolve to the correct package via esbuild/vite aliases based on the `beta` flag in `.thatopen`.
10
+
11
+ **Usage:**
12
+ ```bash
13
+ thatopen swap # toggle: stable → beta or beta → stable
14
+ thatopen swap --beta # force beta
15
+ thatopen swap --stable # force stable
16
+ ```
17
+
18
+ **Flags:**
19
+
20
+ - `--beta` — Switch to beta libraries (`@thatopen-platform/*-beta`).
21
+ - `--stable` — Switch back to stable public libraries (`@thatopen/*`).
22
+
23
+ **Examples:**
24
+ ```bash
25
+ thatopen swap
26
+ thatopen swap --beta
27
+ thatopen swap --stable
28
+ ```
29
+
30
+ > Beta packages are private and the access must be explicitly granted by That Open Company.
@@ -386,4 +386,4 @@ Rhino kernel, so a converter can run server-side while real modelling operations
386
386
 
387
387
  The concrete wire formats — where each file lives on the platform, what the proposal envelope
388
388
  contains, how the queue and the ownership registry work — are in
389
- [the plugin guide](./flow-plugin-guide.md), which is what to read if you are writing a plugin.
389
+ [the plugin guide](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/flow-plugin-guide.md), which is what to read if you are writing a plugin.
@@ -1,6 +1,6 @@
1
1
  # Writing a flow plugin
2
2
 
3
- The concrete contract. [The architecture notes](./flow-architecture.md) say why any of this is
3
+ The concrete contract. [The architecture notes](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/flow-architecture.md) say why any of this is
4
4
  shaped the way it is; this says what the bytes look like.
5
5
 
6
6
  Nothing here is aspirational. Every rule below is what the Revit and Rhino plugins already do, and
@@ -0,0 +1,81 @@
1
+ # Logging in to That Open Platform
2
+
3
+ Everything else in these guides needs this, and it is the same three lines every time, so it lives
4
+ here rather than in each of them.
5
+
6
+ ## Get the token
7
+
8
+ Say this to the user, and wait:
9
+
10
+ > "To log in I need a That Open Platform **access token**. You create it yourself:
11
+ > **https://platform.thatopen.com/dashboard/data → API Tokens → create → copy**, then paste it
12
+ > here."
13
+
14
+ **Never print it back, never write it into a file, never commit it.** Not into a script, not into a
15
+ `.env` you are about to show, not into a chat message quoting the command you ran.
16
+
17
+ ## Log in
18
+
19
+ ```bash
20
+ thatopen login --token <TOKEN>
21
+ ```
22
+
23
+ Credentials go to `~/.thatopen/config.json`, as `accessToken` and `apiUrl`. `--local` writes them to
24
+ a `.thatopen` file in the project instead, which is what a scaffolded project uses.
25
+
26
+ You do not need an npm account or an npm token for the private packages. The CLI derives access to
27
+ them from this one.
28
+
29
+ ## Everyone is on production
30
+
31
+ **Do not ask the user which environment they want.** Production is the answer, it is the default,
32
+ and the plain command above is already correct. Asking turns a decision nobody has into a question
33
+ they cannot answer, at the worst possible moment — the first thing you say to them.
34
+
35
+ There is a `dev` platform, and it exists for the people building That Open Platform itself. If the
36
+ user is one of them they already know, and they will tell you without being asked.
37
+
38
+ Everything below this line is for that case only. If nothing has mentioned dev, skip it.
39
+
40
+ <details>
41
+ <summary>Dev, for the platform team</summary>
42
+
43
+ Two platforms, not two views of one. Separate accounts, separate tokens, separate projects. A token
44
+ from one is refused by the other, and a model published to the wrong one lands somewhere the user's
45
+ team cannot see — while every command reports success.
46
+
47
+ ```bash
48
+ thatopen login --token <TOKEN> --api-url https://dev.platform.thatopen.com
49
+ ```
50
+
51
+ Its dashboard is the same page on that host: `https://dev.platform.thatopen.com/dashboard/data`.
52
+
53
+ </details>
54
+
55
+ ## Check, do not ask
56
+
57
+ **`login` prints "Logged in successfully" and does not name the environment**, so nothing on screen
58
+ would contradict a wrong assumption. Read `apiUrl` from `~/.thatopen/config.json` yourself.
59
+
60
+ If it says production — which it will — say nothing about it and carry on. There is no decision to
61
+ report.
62
+
63
+ **Only if it says dev**, and the user has not told you they work there, is there anything to say:
64
+
65
+ > "This machine is pointed at the dev platform, which is the one the That Open team builds on. I'll
66
+ > move it to production — that will need a token from **https://platform.thatopen.com/dashboard/data**,
67
+ > since dev tokens are not accepted there."
68
+
69
+ Check this **even when the machine is already logged in**, and especially then. A saved login is
70
+ whoever used this machine last, not an answer to a question you have asked.
71
+
72
+ ## When it fails
73
+
74
+ - **`Unauthorized`** — the token is invalid, expired, or from the other environment. Production
75
+ tokens use no `--api-url`; dev tokens need it. Ask for a fresh one from the same environment as
76
+ the URL you are using.
77
+ - **HTTP 403 on `item/folder?projectId=…`** — login worked. The account simply has no access to that
78
+ project, or the project is in the other environment. Confirm the project id with the user before
79
+ assuming anything is broken.
80
+ - **A private package fails to install** — you are not logged in, or logged in to the environment
81
+ that does not have it. Log in again and retry; there is no separate npm login to do.
@@ -37,6 +37,10 @@ the point.
37
37
  run, briefly, before you run it.
38
38
  - After each command, **check the output** before moving on. A command that answered is not the
39
39
  same as a command that did what you wanted.
40
+ - **Whatever you find already set up on this machine is somebody's previous session, not this
41
+ user's choice.** A saved login, an environment, a joined project, a model already open in Revit:
42
+ none of it is an answer to a question you have not asked. Report what you found and ask. This is
43
+ the single most likely way to get the whole thing wrong while every command succeeds.
40
44
 
41
45
  ---
42
46
 
@@ -51,9 +55,24 @@ the point.
51
55
  Then collect what that choice needs. Ask now; you will need it below.
52
56
 
53
57
  - **(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.
58
+ central (e.g. `tower-central`), and the platform **Project ID**. The file may or may not already
59
+ be a workshared central — Step 3 checks. Either way **the user's original file is never
60
+ modified**; a copy is uploaded.
61
+
62
+ **Sharing a new central means a new project. Always send them to make one, every time:**
63
+
64
+ > "A shared central lives inside a platform project, so let's make one for it. Open
65
+ > **https://platform.thatopen.com/dashboard/projects**, create a project, then paste me either its
66
+ > id or just the URL of the page you land on — I can take the id out of the URL."
67
+
68
+ Take the **URL** if that is easier for them; the id is the segment after `/projects/`. Asking
69
+ somebody to copy a hex string off a settings page is a worse experience than asking for the
70
+ address bar, and it is the same information.
71
+
72
+ **You cannot do this part for them.** The CLI has no command to list projects and none to create
73
+ one, so there is no menu to offer and nothing to pick from — which also means: do not guess an id,
74
+ and do not reuse one you saw in `status`. Every command after this needs it, and a wrong one fails
75
+ with a 403 that reads like a permissions problem rather than a typo.
57
76
 
58
77
  - **(B) Connect:** identify the existing central by **one** of:
59
78
  - the **project folder id** of the central — the `revit-<name>` folder inside the project's
@@ -77,16 +96,24 @@ Do **not** ask for the access token yet. That is Step 1.
77
96
 
78
97
  2. **Token.** Ask for it, and say exactly where to get it:
79
98
 
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."
99
+ > "To log in I need a That Open Platform **access token**. You create it yourself:
100
+ > **https://platform.thatopen.com/dashboard/data → API Tokens → create → copy**, then paste it
101
+ > here."
85
102
 
86
103
  ```
87
104
  thatopen login --token <TOKEN>
88
105
  ```
89
- Production is the default. For dev, add `--api-url https://dev.platform.thatopen.com`.
106
+
107
+ That command is already right: **it logs in to production, which is where everybody is.** Do not
108
+ ask the user to choose an environment — there is a dev platform, it is for the people building
109
+ That Open Platform, and they will say so without being asked.
110
+
111
+ **Log in even if the machine is already logged in.** A saved login is whoever used this machine
112
+ last. Never print the token back.
113
+
114
+ [Logging in to That Open Platform](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/platform-token.md) is the short page for when this does not
115
+ go smoothly: what to do if the machine turns out to be pointed at dev, and why `Unauthorized` and
116
+ `403` mean different things.
90
117
 
91
118
  **Log in before Step 2**, not after: installing the add-in downloads a private package and needs
92
119
  these credentials.
@@ -101,6 +128,16 @@ thatopen revit status
101
128
 
102
129
  - Prints `"loaded": true` → the add-in is running. Check `addinVersion` is **1.2.17 or later**; if
103
130
  not, update it with the same command as below. Then go to Step 3.
131
+
132
+ > **`status` also reports a `project`, a `doc` and a `central`. Do not use any of them.** They are
133
+ > whatever this machine did last, which on a colleague's laptop or a shared machine is somebody
134
+ > else's work. Say what you found and ask:
135
+ >
136
+ > > "This machine is still connected to project `<id>`, document `<doc>`. Do you want to keep
137
+ > > working on that one, connect to a different project, or share a new model?"
138
+ >
139
+ > Publishing into the wrong project succeeds, looks completely normal, and puts somebody's model
140
+ > somewhere their team cannot see it.
104
141
  - Errors *"The That Open Revit add-in is not running"* → work through (a), then (b).
105
142
 
106
143
  **(a) Is Revit 2026 open?** If not, launch it:
@@ -224,11 +261,16 @@ anything that can produce the format can queue one. This package's job starts wh
224
261
  which is why nothing below asks where it came from.
225
262
 
226
263
  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.
264
+ tool — the format is documented: **[Writing a flow plugin](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/flow-plugin-guide.md)** is the byte
265
+ contract, and **[the architecture notes](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/flow-architecture.md)** say why it is shaped that way.
229
266
  Publishing a proposal is the smallest of the three jobs described there: it needs no ownership, no
230
267
  history, and no collaboration layer.
231
268
 
269
+ If the tool is **Rhino**, the whole path is already written and worked through end to end:
270
+ **[Rhino → Revit, start to finish](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/rhino-interop-quickstart.md)**. Read that
271
+ instead of assembling it from the two documents above — it covers installing the plug-in, driving
272
+ Rhino without a keyboard, and the traps that cost a night.
273
+
232
274
  **This is where you use the add-in's local API** — the CLI has no proposal commands yet.
233
275
 
234
276
  **List what is waiting:**
@@ -279,18 +321,47 @@ in a status field and differently in a model.
279
321
 
280
322
  ## Step 7 — Offer them a viewer that shows the progress
281
323
 
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?*
324
+ **Offer this as soon as the central exists — right after Step 3, before they start working.** Not
325
+ at the end. Every sync from that moment on becomes a commit they can watch arrive, and setting it up
326
+ costs the same on day one as on day thirty. Left to the end it sounds like an extra; offered at the
327
+ start it is the thing that makes the rest visible.
328
+
329
+ Every sync is a commit, and the platform keeps the lot: who changed what, when, and the geometry as
330
+ it was at each version. Nothing in Revit shows that back, and it is the first thing people ask —
331
+ *what has changed since Friday?*
285
332
 
286
- So offer it, rather than waiting to be asked:
333
+ Say it plainly and wait:
287
334
 
288
- > "Everything you've synced is stored as a history. Would you like a viewer that shows it — pick any
335
+ > "Everything you sync is stored as a history. Would you like a viewer that shows it — pick any
289
336
  > version and see what was created, modified and deleted, coloured in 3D?"
290
337
 
291
338
  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
339
+ **[the platform AI quick start](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/ai-quickstart.md)** — scaffold with the `app` template and follow
340
+ it.
341
+
342
+ **Do not ask them how to add the panel.** Add a **new layout** called `History`, and leave the
343
+ scaffold's own layouts alone. It is a two-line change, it keeps the app they were given intact, and
344
+ it is the answer every time — asking hands somebody a UI decision about a screen they have not seen
345
+ yet.
346
+
347
+ ```ts
348
+ app.elements = {
349
+ ...app.elements,
350
+ history: () => html`<top-git-history></top-git-history>`,
351
+ };
352
+ ```
353
+
354
+ **For the layout, copy one of the scaffold's own panel layouts and swap its panel for `history`** —
355
+ same side, same width, same shape. Do not choose a side and do not pick a width: the app already
356
+ answered both, and the answer is written in `app.layouts` right there in `main.ts`.
357
+
358
+ A panel that opens on the opposite side from every other one, at a different size, is the first
359
+ thing anybody notices, and it reads as bolted on however good the contents are.
360
+
361
+ For the layout's `icon`, use **`at-icons:git-branch`** — That Open's own icon set, and the branch
362
+ mark is what the panel actually shows.
363
+
364
+ What makes it a history viewer rather than an empty viewer is a built-in component that already
294
365
  exists, so nobody writes this part:
295
366
 
296
367
  - **`GitHistoryManager`** — the headless half. It reads `revitflow_history.json` and the per-commit