// ZPWR-HOOKS-EDITOR — ENGINEERING REPORT

Private frontend submodule · Monaco + monaco-vim + monaco-emacs + thin stryke-LSP adapter · esbuild IIFE bundle · build-on-each-consumer · one window.HooksEditor facade

Docs

>_EXECUTIVE SUMMARY

zpwr-hooks-editor is the shared stryke Hooks code editor of the MenkeTechnologies app stack — one JavaScript source of truth for a Monaco editor wired with monaco-vim, monaco-emacs and a thin stryke-LSP adapter. It was extracted from the Audio-Haxor frontend so the editor is no longer duplicated across apps; the source lives in src/ and each consuming app bundles it with its own monaco-* dependencies.

The bundle is produced with esbuild (IIFE, ES2020, minified) and exposes a single window.HooksEditor facade. Language intelligence — completion, hover, diagnostics, definitions, references, rename, signature help, document symbols, code actions, semantic tokens — comes from the stryke language server (stryke --lsp) over a caller-supplied transport, mapped onto Monaco's provider/marker APIs by a thin LSP JSON-RPC client.

Two Monarch grammars ship in the one bundle, picked per editor with create({ language }): stryke (the default, Perl tokens plus the full language server) and latex (grammar, structural snippets, document-driven \ref/\cite completion and a sectioning outline, with no language server). An app that edits LaTeX — zlatex's equation pane — reuses this editor instead of forking a second one, so the theme, the vim/emacs keymaps and the Monaco instance stay shared.

v0.1.0
Version
3
src .mjs files
1091
src lines
4
.mjs files (src + scripts)
1179
.mjs lines (src + scripts)
13
LSP providers
2
Monarch grammars
5
Facade methods
4
Consumer apps
4
Pinned devDeps
private
Tier

Counts derived from the repo: src/*.mjs = 3 files / 1091 lines; with scripts/build-hooks-editor.mjs = 4 files / 1179 lines; register…Provider(LANG_ID call sites = 13 (plus 3 LATEX_ID providers, 16 registrations in all); monaco.languages.setMonarchTokensProvider call sites = 2; window.HooksEditor methods = 5; consumers Audio-Haxor + traderview + ztranslator + zpwr-daw = 4; devDependencies in package.json = 4.


~ARCHITECTURE

One editor source, built per consumer. The entry registers the stryke and latex languages, the cyberpunk theme, the vim/emacs keymaps and the LSP↔Monaco provider mappings; the bundler runs inside each app to resolve its own Monaco deps and emit vendored IIFE artifacts.

LayerImplementation
Editor coreMonaco edcore.main — all editor contributions (suggest, hover, find, folding, multi-cursor, minimap, command palette), no bundled languages
stryke languagestryke is a Perl-5 superset, so it reuses Monaco's Perl Monarch grammar + language config (basic-languages/perl) registered under the stryke language id; server semantic tokens overlay the Monarch highlighting
latex languagea second Monarch grammar in the same bundle, selected with create({ language: 'latex' }) — control words/symbols, math shifts, % comments, brace/bracket matching and $/brace auto-closing. Three LATEX_ID providers: snippet completion for the structural constructs (\frac, \sqrt, \left…\right, \sum, pmatrix, cases, …), cross-reference completion that offers the document's own \labels inside \ref{} and its \bibitem keys inside \cite{}, and a document-symbol provider that turns \part\subparagraph into the outline. No language server is attached — the stryke server speaks stryke, so a LaTeX buffer is never opened against it
Modal editingmonaco-vim + monaco-emacs, switched at runtime via setMode('default'|'vim'|'emacs'); vim status/command line rendered into a caller element
LSP clientcreateLspCore — a thin JSON-RPC client (init/notify/request/receive/connected/isInitialized/onDiagnostics/ready) over a host-supplied transport; the entry maps it onto Monaco's 13 provider registrations + diagnostic markers
Facadewindow.HooksEditorinitClient / receive / clientReady / whenReady / create
Editor handlereturned by creategetValue / setValue / focus / setMode / language / insert / selectRange / bindKey / onSelection / destroy. bindKey(spec, handler) takes a key back from Monaco for this editor's lifetime (Electron-style spec, e.g. "CmdOrCtrl+Shift+O", which is otherwise Monaco's Go to Symbol); returns false on an unparseable spec
Buildesbuild IIFE, ES2020, minified; codicon .ttf inlined as a data URL; runs inside the consumer, writes to its frontend/lib

&LSP PROVIDER SURFACE

The entry registers 13 Monaco language providers against the stryke language id, each mapping a stryke-LSP method onto Monaco's provider API (LSP positions/ranges are 0-based, Monaco 1-based; kinds and severities are translated). Diagnostics arrive as server notifications and are applied as Monaco model markers. The latex id carries 3 further providers of its own (two completion, one document symbol) that are computed locally from the model and never touch the server.

Monaco providerRole
registerCompletionItemProvidercompletion popup (auto + trigger chars)
registerHoverProviderhover docs
registerSignatureHelpProvidersignature help
registerDefinitionProvider / registerDeclarationProvidergo-to definition / declaration
registerReferenceProviderfind references
registerDocumentHighlightProvideroccurrence highlight
registerRenameProviderrename symbol (workspace edit)
registerDocumentSymbolProvideroutline / document symbols
registerCodeActionProvidercode actions / quick fixes
registerDocumentFormattingEditProviderdocument formatting
registerFoldingRangeProviderfolding ranges
registerDocumentSemanticTokensProvidersemantic highlighting (server legend from the handshake)

/BUNDLER & RESOLVE FIXES

scripts/build-hooks-editor.mjs emits two bundles — hooks-editor.bundle.js (+ .css) and hooks-editor.worker.js — and carries esbuild resolve overrides to avoid AMD define() builds that throw in the WebView and silently degrade the editor to a textarea. monaco-vim is forced to its ESM build (dist/index.mjs) because the browser condition's UMD bundle ships an embedded CodeMirror vim keymap with a bare define(). Bare monaco-editor imports are pinned to esm/vs/editor/edcore.main.js (the same lean ESM instance the entry uses) instead of the AMD min build monaco-emacs' require() would pull. Deep monaco-editor/esm/* subpaths without a file extension get .js appended and resolve to the package dir directly. The build defaults its output to <cwd>/frontend/lib and honors HOOKS_EDITOR_OUT.


$CI GATES

This is a non-Rust (frontend / JS) Tier-6 submodule, so it is exempt from the meta repo's cargo gates (fmt / clippy / doc / cargo test). The umbrella MenkeTechnologiesMeta repo enforces the documentation and brand gates on docs/:

GateRequirement
doctype / charset / lang<!DOCTYPE html> first line, <meta charset="utf-8">, <html lang="en">
meta tagsnon-empty <title>, viewport meta, description meta on both pages
structureat least one <h1>; every <img> has alt; no deprecated HTML4 tags
linksexternal href/src https-only; no placeholder hrefs; target="_blank" carries rel="noopener noreferrer"; index ↔ report cross-linked
behaviorno inline event handlers (all via hud-theme.js); referenced css/js exist in docs/
brand"zpwr-hooks-editor" present in titles + headings

#PROJECT METADATA

ItemValue
Version0.1.0
Typemodule (ESM); private npm package
Pinned devDepsesbuild ^0.28.1, monaco-editor 0.55.1, monaco-vim 0.4.4, monaco-emacs 0.3.0 (canonical pins each consumer must match)
Bundle artifactshooks-editor.bundle.js + hooks-editor.bundle.css + hooks-editor.worker.js
Language serverstryke --lsp (strykelang), reached over a host-supplied transport
ConsumersAudio-Haxor, traderview, ztranslator (Tauri, crates/); zpwr-daw (JUCE, libs/)
AuthorMenkeTechnologies
Repositorygithub.com/MenkeTechnologies/zpwr-hooks-editor
Meta umbrellaMenkeTechnologiesMeta