You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 4a9803f
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: docs/WEB.md
+36-12Lines changed: 36 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -107,7 +107,7 @@ extension, a stylesheet or a build-time edit of the browser build's own copy of
107
107
108
108
| Piece | Where | What it does, and what it depends on |
109
109
| --- | --- | --- |
110
-
| Colour themes |`web/theme/levelcode-web-theme/` (staged as a built-in extension by `build-web.mjs`) | "LevelCode Web Dark" / "LevelCode Web Light": neutral chrome with the editor one step lighter, hairline borders, one violet accent. They carry the `agentsPanel.*` keys the floating cards use. Follows the system (`window.autoDetectColorScheme` + the two preferred-theme settings). |
110
+
| Colour themes |`web/theme/levelcode-web-theme/` (staged as a built-in extension by `build-web.mjs`) | "LevelCode Web Dark" / "LevelCode Web Light": neutral chrome with the editor one step lighter, hairline borders, one violet accent. They carry the `agentsPanel.*` keys the floating cards use. Follows the system (`window.autoDetectColorScheme` + the two preferred-theme settings). The syntax colours are One Dark's and One Light's with every one under 4.5:1 on the editor moved in lightness only, hue kept (the light constants darkened with them, so numbers stay apart from class names); `theme.test.js` holds every syntax colour to 4.5:1. The editor paints no token *backgrounds*, so none is set (`invalid` is red text). |
111
111
| First paint |`initialColorTheme` in `web/lib/config.mjs`, picked by `pickInitialTheme` in `web/main.js`| The colours painted for the half second before the theme extension has loaded, so a dark visitor does not see a light flash. |
112
112
| Default theme |`withoutConfigurationDefaults` in `web/lib/extensions.mjs`| An extension's `configurationDefaults`**outrank** the embedder's. `levelcode-themes` pins its own default theme, so the staged copy of it has that key removed (its two themes stay selectable). The desktop source is untouched. |
113
113
| Panels, activity bar |`workbench.experimental.modernUI`, `workbench.activityBar.location: top`, `workbench.layoutControl.type: toggles`| Code-OSS's own switches. `modernUI` is **experimental**: if a bump renames or drops it the editor is still fine, only plainer (`e2e-look.mjs` still passes its theme and layout checks; its screenshots are the thing to look at). |
@@ -121,13 +121,16 @@ extension, a stylesheet or a build-time edit of the browser build's own copy of
121
121
**Layouts.**`levelcode.web.layout` is `chatFirst` (the chat alone, side bars closed, conversations on its
122
122
left — the way a chat app is used) or `split` (Explorer, files on the left, the chat docked on the right — the
123
123
way an editor is used). The status bar item at the left and **LevelCode: Layout: Switch** change the setting
124
-
(there is no default key binding: `Cmd+Alt+L` is Find in Selection on macOS); one listener applies it, so Settings
125
-
does the same. The first start in a workspace is `chatFirst`. The chat panel is not restored by a reload, so a
124
+
(there is no default key binding: `Cmd+Alt+L` is Find in Selection on macOS) where it takes effect — the workspace's
125
+
value when `.vscode/settings.json` has one, since that outranks the user's, the user's otherwise; one listener
126
+
applies it, so Settings does the same. The first start in a workspace is `chatFirst`. The chat panel is not restored by a reload, so a
126
127
`split` layout docks the chat again at start — without revealing the Explorer or moving the focus (that is done
127
128
once per workspace, `workspaceState`), so an Explorer the visitor closed stays closed. The start-up and a switch wait
128
129
for the chat's tab to exist (`onDidChangeTabs`, 2.5 s) rather than reading the tab model at a guessed time. Only
129
130
existing workbench commands are used, so what the visitor then arranges by hand is an ordinary layout. Files that are
130
-
open when going back to `chatFirst` stay as tabs beside the chat.
131
+
open when going back to `chatFirst` stay open as tabs behind the chat: a group that still has files (a split file
132
+
editor, say) is joined into the chat's (`workbench.action.joinAllGroups`, which moves them in inactive), and that one
133
+
group is unlocked, because a group the chat was docked in is locked and would send the next file into a new split.
131
134
132
135
**Widths.** The chat page decides by **its own width**, not the window's: from 1000 px it docks the
133
136
conversation list as a 264 px rail; below 760 px it compacts; in between the list is the dialog it is on the
@@ -141,7 +144,15 @@ Constraints worth knowing before changing it:
141
144
142
145
- The chat webview's CSP has no `font-src`: the skin uses the system font stack only.
143
146
- A group that is emptied by moving the chat out of it is closed, so `split` opens a file in the first group
144
-
**before** it moves the chat (`applyLayout`, pinned by `workspace.test.js`).
147
+
**before** it moves the chat — the README, or an empty untitled document when there is none and the chat is the
148
+
group's only tab (`applyLayout`, pinned by `workspace.test.js`).
149
+
- The move and join commands act on the **active editor**, and `levelcode.ai.focus` returns before the reveal has
150
+
reached the tab model. The window is read only once the chat is in front (until then an editor that was in front
151
+
of it, such as a settings editor in a group of its own, still counts as a group). Each move or join then runs only
152
+
when the tab model says the chat is the active editor, read immediately
153
+
before it (after waiting up to 1.5 s for that); otherwise it is skipped, as is every later one in that arrangement,
154
+
and so is one that a newer layout request has overtaken. A skipped move leaves the window as it was; a guessed one
155
+
would move the file beside the chat.
145
156
- The rail asks the page for its conversations with `listSessions`; it must never call `openSessions()`,
146
157
which seeds the list with sample conversations when nothing has arrived yet.
147
158
- Text drawn in the theme's accent uses `textLink.foreground`, not `focusBorder` (which is translucent and a line
@@ -157,28 +168,39 @@ The extension's existing PKCE flow, with the browser's pieces in place of the OS
|`--webview-origin 'https://{{uuid}}.view.example.com'` (`LEVELCODE_WEB_WEBVIEW_ORIGIN`) | Self-host the webview origin. Without it the page uses Code-OSS's CDN at this build's own commit. Needs wildcard DNS and TLS — see below. |
258
280
|`--ext-host-origin 'https://{{uuid}}.ext.example.com'` (`LEVELCODE_WEB_EXTHOST_ORIGIN`) | Run the extension host on an origin of its own. Optional while no third-party code is loaded. |
259
281
|`--static <dir>`| Use a prebuilt client (skips the gulp build). |
260
-
|`--id <id>`| Override the build id (default: a fingerprint of the client, the page and the extension). |
282
+
|`--id <id>`| Override the build id (default: a hash of everything the build put under `/_/<id>/`, staged first and named after it). |
levelcode-ai,levelcode-web --account <origin>`, plus `--product <json>` and `--config-defaults
@@ -365,7 +387,9 @@ causing the effect). Use another registrable domain.
365
387
| Editor settings, layout | the workbench's own storage | editor origin |
366
388
367
389
Clearing the browser's site data removes all of it. A private window may discard it on close; the
368
-
secret store then falls back to memory for the session.
390
+
secret store then falls back to memory for the session. The key the secrets are sealed with is created
391
+
once per browser profile: two tabs opened together on a fresh profile store it in one IndexedDB
392
+
transaction, so both end with the same key.
369
393
370
394
## Keeping the desktop and the browser in step
371
395
@@ -392,7 +416,7 @@ secret store then falls back to memory for the session.
392
416
393
417
| Check | Command | What it proves |
394
418
| --- | --- | --- |
395
-
| Unit gate |`./scripts/test-extensions.sh`| Includes `web/test/unit/*.test.js`: the shims against Node, `host.js` on both sides, `main.js`'s functions (address check, delivery, the shared secret store, `?signin=1`), the manifest, the copy rewrites, the chat skin (what it inserts and that every rule is scoped), the themes (required colours, contrast of the text pairs, the page's defaults naming themes that exist) and the layout commands. Runs in CI on every PR (`test.yml`). Also run on Linux / Node 18 in a container with the network refused. |
419
+
| Unit gate |`./scripts/test-extensions.sh`| Includes `web/test/unit/*.test.js`: the shims against Node, `host.js` on both sides, `main.js`'s functions (address check, delivery, the shared secret store, `?signin=1`), the manifest, the copy rewrites, the chat skin (what it inserts and that every rule is scoped), the themes (required colours, contrast of the text pairs, every syntax colour at 4.5:1 on the editor, the page's defaults naming themes that exist) and the layout commands. Runs in CI on every PR (`test.yml`). Also run on Linux / Node 18 in a container with the network refused. |
396
420
| The shell |`./scripts/test-extensions.sh` (the unit suites `web/test/unit/shell-*.test.js`) | The engine: a differential against GNU bash 5.1 (905 cases, a shrink-only table of the ones that differ), fuzzing, every patch of the vendored code with its anchors, the build; the runtime: the commit and its refusals, kill and deadline against a **real engine in a worker thread**, limits; the terminal: key bytes, the line editor against real xterm.js 6.1 in its headless build, width, the output filter, history. With the Code-OSS checkout present the real-xterm halves run; `LEVELCODE_REQUIRE_XTERM=1` and `LEVELCODE_REQUIRE_WORKER=1` make a skip a failure, which is what CI sets. |
397
421
| Mutations |`node web/test/helpers/mutation/mutate.mjs`| 371 edits to the runtime, the commit and the sanitiser, each of which a suite must catch (a tool, not a suite). |
398
422
| The shell, in a browser |`node web/test/e2e-shell.mjs --static … --extensions …`| Real headless Chrome and the real nested Worker: nothing of the shell is fetched until it is used; a terminal from the palette; typing, files, a working folder that persists, 127, Ctrl+C on `sleep 60`, a link to `path:line:col` that opens the file at that line, a pasted three-line buffer through a resize; hostile output that does not type into the prompt or rename the terminal; the agent offered `run_command` without background, a file written through the review (Keep/Undo), a `.vscode` write refused whole, a timeout that applies nothing, the mirror tab. |
if(!r.ok){vscode.window.showWarningMessage('LevelCode: that link cannot be opened — '+r.reason+'.');dbg('diagram.link.refused',{reason: r.reason});return;}
1122
1126
recordDiagramStat({type: 'link'});
1123
1127
try{
@@ -3567,10 +3571,16 @@ async function handleAuthCallback(uri) {
0 commit comments