ide
ide::Bootstrap Boots the IDE in a browser tab: load the one wasm bundle (IdeSession), then restore the URL hash's workspace — a share link mounts in memory and needs no disk — or fall back to the launcher. File System Access support gates only the disk features (open folder, save, watch): without it those actions are disabled with a notice, while share links and the bundled examples still open.
Parent
- for ide::WebIde
Inbound
- call ide::WebIde · start
Outbound
- from → ide::bool
- call → ide::Launcher · show
Scenarios
Missing File System Access disables disk features, never the IDE.
- given a browser without the File System Access API (Firefox, Safari)
- when the IDE boots
- then share links and bundled examples still open in memory
- and the disk actions — open folder, save, watch — are disabled with a notice naming the supported browsers
- but no full-screen wall blocks the product
ide::BrowserWorkspace The in-browser workspace state the session holds: the open `.pds` modules, the `pds.toml` manifest text, and the dependency modules resolved from `pds_modules/` as externals (LANG.md §8.3). Held in memory — a decoded sample/share link or a local directory loaded through the file-system port. Edits never leave the tab.
Inbound
- from ide::Samples
ide::CodeMirrorAdapter The editor adapter over CodeMirror 6: the text/cursor model, the completion source, the hover tooltip, the diagnostics gutter, and edit events forwarded into the session. The only place CodeMirror specifics live — it drives the session and applies the typed values it gets back.
Parent
- for ide::WebIde
Outbound
- call → ide::IdeSession · setSource
- call → ide::LanguageSession · diagnostics
- call → ide::LanguageSession · complete
- call → ide::LanguageSession · hover
ide::Completion A completion candidate offered as the author types: the inserted label, the integer LSP `CompletionItemKind` the editor maps to an icon, and detail text (absent for candidates with nothing to add).
ide::DiagramCanvas The diagram canvas: draws the **JSON** `Scene` interactively (Svelte Flow pan/zoom over geometry positioned by `emit`'s layout engine for C4, a depth-collapsible timeline for sequences), and exports the current view as **PNG or SVG**, both produced in the browser from the drawn diagram. JSON is the draw format; no diagram image crosses the wasm surface. The editor port's diagram seam binds to this.
Parent
- for ide::WebIde
Scenarios
A projected diagram is drawn from the JSON scene; no diagram image crosses the IDE's wasm surface — PNG and SVG exports are produced client-side.
- given a projected view of the held workspace
- when the IDE draws or exports a diagram
- then the JSON `Scene` from the session's `emitScene` draws the interactive canvas — the same geometry the HTML doc site's client islands draw
- and PNG and SVG exports are produced in the browser from the drawn diagram
- but no image crosses the IDE wasm — its surface carries only the JSON scene; the `emit` crate's static SVG remains the CLI/doc path
ide::Diagrams Diagram projection: builds the workspace graph and projects a view to the JSON `Scene` via `emit::Projector`; the host's canvas draws it. The wasm surface carries only the JSON scene and layout — SVG and PNG are export concerns of the canvas (PNG rasterised in the browser), and the static SVG form is a CLI/doc concern of the `emit` crate, not exposed here.
Parent
- for ide::IdeSession
Scenarios
The C4 canvas drives `emit`'s layout under the UI's tweaks and pins.
- given a C4 view open on the canvas and the UI's layout toggles
- when the view is laid out
- then the session passes the tweaks and any drag-to-pin cells to emit's C4 placement
- and the canvas redraws from the re-positioned scene
ide::DocConfig The doc-site build input: the manifest plus each authored page's Markdown, loaded by the host. Field detail is the wasm boundary's concern.
ide::Docs The doc-site builder: renders the whole site in-browser through the same `pseudoscript-doc` crate `pds doc` runs, driving SSR through a render callback the host supplies (the browser's JS engine is the SSR engine) — so the IDE writes the exact site the CLI ships, health page included. The site builds to the opened folder's `target/doc/` only; an in-memory workspace is told to open a folder first (no blob-preview path).
Parent
- for ide::IdeSession
Outbound
- call → model::Model · checkWorkspaceModules
- call → doc::Doc · prepareDiagnostics
ide::FimClient Provider-agnostic completion client: one `complete` contract over OpenAI-compatible HTTP, so one client covers Codestral, OpenRouter, Together, Ollama, and vLLM. Stateless — the caller hands it the settings snapshot and owns cancellation (`GhostText` aborts the in-flight request on the next keystroke; the client honours the abort). Every failure comes back as a classified `ProviderError`, so the caller can surface why a request bailed.
Parent
- for ide::WebIde
Inbound
- call ide::GhostText · complete
Outbound
- from → ide::bool
- call → ide::LlmProvider · fimComplete
- call → ide::LlmProvider · chatComplete
- call → ide::LlmProvider · listModels
- from → ide::Result
- from → ide::FimPrompt
- from → ide::Result
- from → ide::Result
ide::FimPrompt The assembled fill-in-the-middle request: the windowed buffer text before and after the caret, and the cached grammar primer that steers a general model to emit valid PseudoScript.
Inbound
- from ide::FimClient
- from ide::GhostText
ide::FsAccessAdapter The file-system adapter over the browser File System Access API: directory picker, recursive walk for `.pds` modules, deriving each module's flat FQN from its path (LANG.md §8.1, ADR-031), `pds.lock` + `pds_modules/` reads for dependency externals, and per-file read/write through handles. The only place FS-Access specifics live; it pushes what it reads into the session via `mount`.
Parent
- for ide::WebIde
Inbound
- call ide::Launcher · pickFolder
- call ide::Launcher · readModules
- call ide::Launcher · readDependencies
Outbound
- from → ide::string
- from → ide::VendoredInput
- from → ide::LocalInput
- call → ide::Workspace · dependencyModules
- from → ide::Result
- from → model::WorkspaceModule
- from → model::WorkspaceModule
ide::GhostText Inline ghost-text completion over CodeMirror 6, beside the grammar dropdown: structural candidates stay local and deterministic in `CodeMirrorAdapter`; the remote model supplies only multi-token greyed text. CodeMirror has no native inline-suggestion UI, so this is a custom view plugin rendering a widget decoration at the caret — Tab accepts, Esc dismisses, any edit clears.
Parent
- for ide::WebIde
Outbound
- call → ide::LlmSettingsStore · isEnabled
- call → ide::LlmSettingsStore · current
- from → ide::FimPrompt
- call → ide::FimClient · complete
- call → ide::LlmSettingsStore · reportFailure
- call → ide::LlmSettingsStore · clearFailure
- from → ide::bool
- call → ide::LlmSettingsStore · noteDrop
- call → ide::LlmSettingsStore · clearDrop
- from → ide::string
- call → ide::LanguageSession · outline
- from → ide::string
Scenarios
Ghost text comes from the configured provider, rendered as-is for the author to judge.
- given AI completion enabled with a configured OpenAI-compatible provider
- when the author pauses typing
- then the windowed prefix/suffix and the grammar primer go to the provider
- and the suggestion renders as greyed inline text — Tab accepts, Esc dismisses
- but the suggestion is the author's to judge — accepting one with a syntax error lights the live diagnostics — and a provider failure surfaces on the AI status chip with the reason; it never blocks typing
The remote model augments, never replaces, the local grammar completer.
- given the grammar dropdown completer answering from the wasm session
- when AI completion is enabled beside it
- then structural candidates stay local and deterministic
- and the remote model supplies only multi-token inline suggestions
- but with AI completion off or unconfigured, the editor behaves exactly as before
ide::GridPin A node the user has dragged onto a grid cell, identified by FQN. Carried inside `LayoutTweaks`; honoured only under experimental grid placement.
ide::IdeSession `crates/pseudoscript-ide` — the IDE application, Rust compiled to a single wasm. It owns the workspace state and is the whole browser API: the host pushes modules in (`mount`/`setSource`) and pulls every answer out as a typed value — the session never calls the DOM, CodeMirror, or the File System Access API. It delegates language intelligence to `lsp_core` and `model::Checks`, diagrams to `emit::Projector`, the 3D universe to `universe::Adapter`, and the doc site to `doc::SiteBuilder` — each a Rust library linked in, never a separate wasm. The one outbound seam is the doc build's SSR render callback the host supplies. Everything here is Rust.
Parent
Inbound
- call ide::CodeMirrorAdapter · setSource
- call ide::Launcher · mount
- call ide::Launcher · mount
Scenarios
The IDE is one Rust crate compiled to one typed wasm; the toolchain is linked in as libraries, not consumed as a second wasm.
- given the IDE application compiled to WebAssembly as `pseudoscript-ide`
- when it needs language intelligence, a diagram, the 3D universe, or the doc site
- then it calls the `lsp_core`, `model`, `emit`, `universe`, and `doc` crates as linked Rust libraries
- and exposes one typed surface to JavaScript — DTOs `tsify` projects to TS, not JSON strings
- but there is no second wasm, so no bridge can drift from the app that uses it
ide::LanguageSession The language session: diagnostics, completion, hover, go-to, references, rename, outline, folding, and semantic tokens over the held workspace, every answer delegated to the pure toolchain logic (`model::Checks` for diagnostics, `lsp_core` for cursor features) with the dependency externals bound. Every answer is a typed value the host applies — the session pushes nothing at the editor.
Parent
- for ide::IdeSession
Inbound
- call ide::CodeMirrorAdapter · diagnostics
- call ide::CodeMirrorAdapter · complete
- call ide::CodeMirrorAdapter · hover
- call ide::GhostText · outline
Outbound
- call → model::Model · check
- from → model::ModuleDiagnostics
- from → ide::Option
- from → ide::OutlineNode
Scenarios
A cross-workspace reference resolves because dependencies load as externals.
- given a workspace that declares a git dependency, vendored under `pds_modules/`
- when the file-system port reads `pds.lock` + `pds_modules/` and the session resolves them
- then every language query binds the dependency modules as externals (§8.3)
- and a `dep::module::Node` reference resolves — checked, hovered, and completed
- but the dependency's own modules are never offered as raw `pds_modules::…` paths
ide::Launcher The project launcher — the first surface. Offers the recents, open-a-folder, New Project, and the bundled examples. Examples and share links mount in memory and need no disk; only the disk actions gate on File System Access support. Dismissible, so the menus, help, and settings stay reachable without a project.
Parent
- for ide::WebIde
Inbound
- call ide::Bootstrap · show
Outbound
- call → ide::Samples · workspaceOf
- call → ide::IdeSession · mount
- call → ide::FsAccessAdapter · pickFolder
- call → ide::FsAccessAdapter · readModules
- call → ide::FsAccessAdapter · readDependencies
- call → ide::IdeSession · mount
Scenarios
Examples open in memory — value before any commitment.
- given a first-time visitor on the launcher
- when they open a bundled example
- then it mounts in memory with no name, no folder, and no disk permission
- and the same session-only mount path a share link uses carries it
- but saving to a folder later upgrades it to a real on-disk workspace
A pick failure is surfaced; a cancel is silent.
- given the native folder picker invoked from Open or New Project
- when it closes without a folder
- then a user cancel changes nothing, silently
- but a failure — blocked API, permission policy, embedder denial — renders inline at the control with the cause
ide::LayoutTweaks The IDE's per-diagram C4 layout toggles, crossing to JS as a typed object: run the long-edge optimiser, the reading `orientation` (`"tb"`/`"lr"`), a `spacing` preset (`"compact"`/`"comfortable"`/`"roomy"`), and the experimental grid dials and pins. Translated to `emit::C4Tweaks` inside the session.
ide::LlmProvider The author's configured OpenAI-compatible completion provider — hosted (OpenAI, Codestral, OpenRouter, Together) or local (Ollama, vLLM). External: the IDE only speaks its HTTP API; transport and HTTP failures surface as classified `ProviderError`s.
Inbound
- call ide::FimClient · fimComplete
- call ide::FimClient · chatComplete
- call ide::FimClient · listModels
ide::LlmSettings The author's AI-completion provider settings, persisted in the browser: the feature toggle, the chosen preset (`"ollama"`, `"openai"`, or `"custom"` — the presets pin the endpoint and wire shape so setup is pick-and-go), the OpenAI-compatible endpoint, the bring-your-own API key (stored in localStorage, sent only to the configured endpoint), the model id, and the wire shape (`"fim"` for a native fill-in-the-middle route, `"chat"` for the chat-completions fallback).
Inbound
- from ide::LlmSettingsStore
- from ide::LlmSettingsStore
ide::LlmSettingsStore The author's AI-completion settings, persisted to browser localStorage and edited through the Settings dialog's "AI Completion" tab. Bring-your-own key: it never leaves the tab except on requests to the configured endpoint. Setup is preset-first: picking a provider applies its pinned endpoint and wire shape, so only the Custom preset exposes the raw fields. The store also carries the session's last completion failure (never persisted) so the status chip and the settings tab can show why ghost text is bailing.
Parent
- for ide::WebIde
Inbound
- call ide::GhostText · isEnabled
- call ide::GhostText · current
- call ide::GhostText · reportFailure
- call ide::GhostText · clearFailure
- call ide::GhostText · noteDrop
- call ide::GhostText · clearDrop
Outbound
- from → ide::LlmSettings
- from → ide::bool
- from → ide::LlmSettings
Scenarios
Setup is preset-first; the connection test explains a failure instead of leaving the author guessing.
- given the Settings dialog's AI Completion tab
- when the author picks the Ollama or OpenAI preset
- then the endpoint and wire shape are pinned by the preset — no raw URL to type
- and the model dropdown fills from the provider's live model list
- and Test connection round-trips the provider and reports success or the classified failure with its fix hint
- but the Custom preset still exposes every field for any OpenAI-compatible endpoint
ide::LocalInput One local-source dependency file the host reads for `dependencyModules`: the dependency name (ADR-026), its FQN within the dependency workspace, and its source.
Inbound
- from ide::FsAccessAdapter
ide::Occurrence One occurrence of a symbol: the module it lies in, its line/column span, the source line text with the match offsets within it, and whether it is the declaration site.
ide::OutlineNode One row of the workspace outline: a node's FQN, simple name, C4 kind, containment parent (absent on roots), whether it is a triggered flow entry, its `///` summary (absent when undocumented), and its declaration line/column.
Inbound
- from ide::LanguageSession
ide::PickError Why a folder pick yielded no workspace: the picker failed — the API missing, blocked by permission policy, or denied by the embedder. Distinct from a user cancel, which is silent: a cancel is the user's choice, a failure is the product's to explain.
ide::ProviderError A classified completion-provider failure: `kind` is `"network"` (endpoint unreachable or CORS-blocked), `"auth"` (401/403), `"notFound"` (404 route or model), `"timeout"`, or `"http"` (any other non-OK status); `message` states what failed and `hint` names the fix for the configured provider (e.g. the `OLLAMA_ORIGINS` command for a CORS-blocked local Ollama).
ide::References The find-references result for the symbol under the caret: the symbol's FQN, a human title, and every occurrence across the workspace.
ide::RenameSelection One occurrence the user chose to rename, keyed by the module FQN and the 1-based line/column an `ide::Occurrence` reported. The rename rewrites only the selected occurrences, not every match.
ide::RenamedSource One module rewritten by a rename: its FQN and new source text.
ide::RenderedFile One file of the rendered documentation site: its site-relative path and contents.
ide::Samples The bundled example catalogue, discovered at build time from the samples folder (one folder per example: meta.json, the `.pds` modules, `pds.toml`, doc pages). Each entry doubles as a New-project template and as an in-memory workspace.
Parent
- for ide::WebIde
Inbound
- call ide::Launcher · workspaceOf
Outbound
- from → ide::BrowserWorkspace
ide::Universe The 3D universe: builds the software graph from the held workspace and flattens it to a snapshot the `ForceGraph` renders, with the entry-point flows traced in Rust. Delegates to the `universe` crate; the wasm surface carries only the flat snapshot and flows — positions are the renderer's.
Parent
- for ide::IdeSession
Outbound
- call → universe::Universe · build
- call → universe::Universe · snapshot
- call → model::Model · graph
- call → universe::Universe · flows
Scenarios
The 3D universe is built in Rust and crosses as a flat snapshot.
- given the held workspace
- when the IDE opens the 3D relationship view
- then the universe crate builds the software graph and flattens it to a snapshot
- and the snapshot crosses the typed boundary as nodes and directed weighted edges
- but no positions cross — the browser's force layout places the nodes
ide::UniverseEdge One directed relationship in the 3D graph, weighted by traffic (call count). The wire field is `from`; `from` is a PseudoScript keyword, so the model names it `source`.
ide::UniverseNode One node in the 3D relationship graph the IDE draws: its FQN, C4 level, and containment parent (absent on roots). The typed boundary form of a `universe::NodeOut`.
ide::UniverseSnapshot The 3D-view snapshot the session hands the `ForceGraph`: nodes and directed weighted edges, no positions (the renderer lays them out). The typed boundary form of a `universe::Snapshot`.
ide::VendoredInput One vendored git-dependency file the host reads for `dependencyModules`: its `pds_modules/` slug, its FQN within the dependency workspace (the host's path→FQN derivation, LANG.md §8.1), and its source.
Inbound
- from ide::FsAccessAdapter
ide::WebIde `web-ide` — the IDE at `ide.pdscript.dev`: a SvelteKit shell on Cloudflare Workers static assets. Pure glue — it loads the one wasm bundle and binds the adapters to the session's ports. It holds no language logic.
Scenarios
JavaScript exists only in the adapters plus the host's path→FQN derivation; all language and projection logic is Rust.
- given the IDE session, the language queries, and diagram projection all in Rust
- when the application touches the file system or the editor surface
- then an adapter — `FsAccessAdapter`, `CodeMirrorAdapter` — pushes state into the typed session and applies the values it returns
- and those adapters are the only JavaScript: File System Access and CodeMirror specifics live there
- but the FS adapter also derives each module's flat FQN from its path (LANG.md §8.1, ADR-031) — the one workspace rule the host runs before pushing modules to the Rust core
Editing a model in the browser checks and redraws it live, with no backend.
- given a `.pds` module open in the browser IDE
- when the author edits it through the CodeMirror adapter
- then the edit drives the Rust session, which re-checks against the externals
- and diagnostics and the projected C4 or sequence diagram update live
- but nothing is sent to a server
ide::Workspace The in-memory project the session holds: the parsed modules keyed by FQN (an open buffer overlays via `setSource`), the dependency externals, and the memoised resolved workspace + graph — invalidated by any mutation, rebuilt once for the query burst between keystrokes. Edits never leave the tab; an explicit save writes through the host's file handles, not this session.
Parent
- for ide::IdeSession
Inbound
- call ide::FsAccessAdapter · dependencyModules