@nbt-dev/components 0.0.10 → 0.1.1

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.
@@ -17,7 +17,7 @@ import {
17
17
  indentWithTab
18
18
  } from "@codemirror/commands";
19
19
  import {
20
- syntaxHighlighting,
20
+ syntaxHighlighting as syntaxHighlighting2,
21
21
  defaultHighlightStyle,
22
22
  bracketMatching,
23
23
  indentUnit as indentUnit2
@@ -201,6 +201,8 @@ function nbtLanguageSupport() {
201
201
 
202
202
  // src/editor/editor-themes.ts
203
203
  import { EditorView } from "@codemirror/view";
204
+ import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
205
+ import { tags as t } from "@lezer/highlight";
204
206
  import {
205
207
  amy,
206
208
  ayuLight,
@@ -241,8 +243,51 @@ var defaultTheme = EditorView.theme(
241
243
  },
242
244
  { dark: true }
243
245
  );
246
+ var nimbitDarkChrome = EditorView.theme(
247
+ {
248
+ "&": { backgroundColor: "#0b0b0e", color: "#e4e4e7" },
249
+ ".cm-content": { caretColor: "#facc15" },
250
+ ".cm-cursor, .cm-dropCursor": { borderLeftColor: "#facc15" },
251
+ "&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": { backgroundColor: "rgba(250, 204, 21, 0.18)" },
252
+ ".cm-gutters": {
253
+ backgroundColor: "#0b0b0e",
254
+ color: "#52525b",
255
+ borderRight: "1px solid rgba(255, 255, 255, 0.06)"
256
+ },
257
+ ".cm-activeLine": { backgroundColor: "rgba(250, 204, 21, 0.06)" },
258
+ ".cm-activeLineGutter": { backgroundColor: "rgba(250, 204, 21, 0.06)", color: "#a1a1aa" },
259
+ ".cm-tooltip": {
260
+ backgroundColor: "#18181b",
261
+ color: "#e4e4e7",
262
+ border: "1px solid rgba(255, 255, 255, 0.1)"
263
+ },
264
+ ".cm-tooltip-autocomplete ul li[aria-selected]": {
265
+ backgroundColor: "rgba(250, 204, 21, 0.15)",
266
+ color: "#fafafa"
267
+ }
268
+ },
269
+ { dark: true }
270
+ );
271
+ var nimbitDarkHighlight = HighlightStyle.define([
272
+ { tag: t.keyword, color: "#facc15", fontWeight: "500" },
273
+ // entity, enum, …
274
+ { tag: [t.typeName, t.className, t.tagName], color: "#e5e7eb", fontWeight: "500" },
275
+ // types + entity refs
276
+ { tag: [t.propertyName, t.variableName, t.attributeName], color: "#cbd5e1" },
277
+ // field names
278
+ { tag: [t.string, t.special(t.string)], color: "#fde047" },
279
+ { tag: [t.number, t.bool, t.atom, t.null], color: "#fbbf24" },
280
+ // numbers, true/false
281
+ { tag: [t.meta, t.annotation], color: "#f472b6", fontWeight: "500" },
282
+ // @relation, @@index, …
283
+ { tag: t.comment, color: "#71717a", fontStyle: "italic" },
284
+ { tag: [t.operator, t.punctuation, t.separator], color: "#a1a1aa" },
285
+ { tag: t.invalid, color: "#f87171" }
286
+ ]);
287
+ var nimbitDark = [nimbitDarkChrome, syntaxHighlighting(nimbitDarkHighlight)];
244
288
  var EDITOR_THEMES = [
245
289
  { id: "default", label: "Default (panel)", extension: defaultTheme },
290
+ { id: "nimbitDark", label: "Nimbit Dark", extension: nimbitDark },
246
291
  { id: "dracula", label: "Dracula", extension: dracula },
247
292
  { id: "tomorrow", label: "Tomorrow", extension: tomorrow },
248
293
  { id: "cobalt", label: "Cobalt", extension: cobalt },
@@ -260,7 +305,7 @@ var EDITOR_THEMES = [
260
305
  { id: "smoothy", label: "Smoothy", extension: smoothy },
261
306
  { id: "solarizedLight", label: "Solarized Light", extension: solarizedLight }
262
307
  ];
263
- var byId = new Map(EDITOR_THEMES.map((t) => [t.id, t.extension]));
308
+ var byId = new Map(EDITOR_THEMES.map((t2) => [t2.id, t2.extension]));
264
309
  function themeExtension(id) {
265
310
  return byId.get(id) ?? EDITOR_THEMES[0].extension;
266
311
  }
@@ -467,7 +512,7 @@ var NbtEditor = ({
467
512
  bracketMatching(),
468
513
  closeBrackets(),
469
514
  lintGutter(),
470
- syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
515
+ syntaxHighlighting2(defaultHighlightStyle, { fallback: true }),
471
516
  nbtLanguageSupport(),
472
517
  indentComp.current.of(indentConfig(s.tabSize)),
473
518
  themeComp.current.of([sizingTheme(s.fontSize), themeExtension(s.theme)]),
@@ -717,4 +762,4 @@ export {
717
762
  NbtEditor,
718
763
  NbtLspClient
719
764
  };
720
- //# sourceMappingURL=chunk-TNIHD62H.js.map
765
+ //# sourceMappingURL=chunk-PI7ZMVVU.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/editor/nbt-editor.tsx", "../src/editor/nbt-language.ts", "../src/editor/editor-themes.ts", "../src/editor/lsp-extensions.ts", "../src/editor/lsp-client.ts"],
4
+ "sourcesContent": ["// CodeMirror 6 React wrapper for one NBT buffer. Recreated per uri (keyed by\n// the host); owns the EditorView lifecycle, Ctrl+S save, and the LSP wiring.\n// Theme / font size / line-wrap / tab size are live-tunable via compartments so\n// changing a setting doesn't blow away cursor + scroll.\n\nimport React from \"react\";\nimport { Compartment, EditorState, Prec } from \"@codemirror/state\";\nimport {\n EditorView,\n keymap,\n lineNumbers,\n drawSelection,\n highlightActiveLine,\n} from \"@codemirror/view\";\nimport {\n defaultKeymap,\n history,\n historyKeymap,\n indentWithTab,\n} from \"@codemirror/commands\";\nimport {\n syntaxHighlighting,\n defaultHighlightStyle,\n bracketMatching,\n indentUnit,\n} from \"@codemirror/language\";\nimport { lintGutter } from \"@codemirror/lint\";\nimport { searchKeymap } from \"@codemirror/search\";\nimport { completionKeymap, closeBrackets } from \"@codemirror/autocomplete\";\nimport { nbtLanguageSupport } from \"./nbt-language\";\nimport { themeExtension } from \"./editor-themes\";\nimport { lspExtensions, type GotoDefHandler } from \"./lsp-extensions\";\nimport { NbtLspClient } from \"./lsp-client\";\n\n// Sizing only \u2014 the selected color theme owns the rest. Built per font-size so\n// the theme compartment can carry both.\nfunction sizingTheme(fontSize: number) {\n return EditorView.theme({\n \"&\": { height: \"100%\", fontSize: `${fontSize}px` },\n \".cm-content\": { fontFamily: \"ui-monospace, monospace\" },\n \"&.cm-focused\": { outline: \"none\" },\n });\n}\n\n// `Prec.high` so this wins the indentUnit/tabSize facets over the\n// `indentUnit.of(\" \")` baked into nbtLanguageSupport().\nfunction indentConfig(tabSize: number) {\n return Prec.high([\n indentUnit.of(\" \".repeat(tabSize)),\n EditorState.tabSize.of(tabSize),\n ]);\n}\n\nexport type NbtEditorProps = {\n uri: string;\n value: string;\n readOnly?: boolean;\n lsp?: NbtLspClient | null;\n onChange?: (text: string) => void;\n onSave?: (text: string) => void;\n onGotoDefinition?: GotoDefHandler;\n theme?: string;\n fontSize?: number;\n lineWrap?: boolean;\n tabSize?: number;\n};\n\nexport const NbtEditor: React.FC<NbtEditorProps> = ({\n uri,\n value,\n readOnly = false,\n lsp,\n onChange,\n onSave,\n onGotoDefinition,\n theme = \"default\",\n fontSize = 12,\n lineWrap = false,\n tabSize = 2,\n}) => {\n const hostRef = React.useRef<HTMLDivElement | null>(null);\n const viewRef = React.useRef<EditorView | null>(null);\n\n // Latest callbacks without recreating the view.\n const onChangeRef = React.useRef(onChange);\n onChangeRef.current = onChange;\n const onSaveRef = React.useRef(onSave);\n onSaveRef.current = onSave;\n const onGotoRef = React.useRef(onGotoDefinition);\n onGotoRef.current = onGotoDefinition;\n\n // Live-tunable settings live in compartments. Keep the latest values in a ref\n // so a view rebuild (new uri/mode) seeds the right config without listing the\n // settings in the create-effect deps.\n const themeComp = React.useRef(new Compartment());\n const wrapComp = React.useRef(new Compartment());\n const indentComp = React.useRef(new Compartment());\n const settingsRef = React.useRef({ theme, fontSize, lineWrap, tabSize });\n settingsRef.current = { theme, fontSize, lineWrap, tabSize };\n\n React.useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n\n const s = settingsRef.current;\n const extensions = [\n lineNumbers(),\n history(),\n drawSelection(),\n highlightActiveLine(),\n bracketMatching(),\n closeBrackets(),\n lintGutter(),\n syntaxHighlighting(defaultHighlightStyle, { fallback: true }),\n nbtLanguageSupport(),\n indentComp.current.of(indentConfig(s.tabSize)),\n themeComp.current.of([sizingTheme(s.fontSize), themeExtension(s.theme)]),\n wrapComp.current.of(s.lineWrap ? EditorView.lineWrapping : []),\n keymap.of([\n {\n key: \"Mod-s\",\n run: (view) => {\n onSaveRef.current?.(view.state.doc.toString());\n return true;\n },\n },\n ...defaultKeymap,\n ...historyKeymap,\n ...searchKeymap,\n ...completionKeymap,\n indentWithTab,\n ]),\n EditorView.updateListener.of((u) => {\n if (u.docChanged) onChangeRef.current?.(u.state.doc.toString());\n }),\n EditorState.readOnly.of(readOnly),\n ];\n if (lsp && !readOnly) {\n extensions.push(\n lspExtensions(lsp, uri, (defUri, line) => onGotoRef.current?.(defUri, line)),\n );\n }\n\n const view = new EditorView({\n state: EditorState.create({ doc: value, extensions }),\n parent: host,\n });\n viewRef.current = view;\n return () => {\n view.destroy();\n viewRef.current = null;\n };\n // Recreate per buffer identity / mode; `value` is only the initial doc.\n // Settings changes are handled by the reconfigure effect below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [uri, readOnly, lsp]);\n\n // Retune the live view when a setting changes \u2014 no destroy, so cursor/scroll\n // survive.\n React.useEffect(() => {\n const view = viewRef.current;\n if (!view) return;\n view.dispatch({\n effects: [\n themeComp.current.reconfigure([\n sizingTheme(fontSize),\n themeExtension(theme),\n ]),\n wrapComp.current.reconfigure(lineWrap ? EditorView.lineWrapping : []),\n indentComp.current.reconfigure(indentConfig(tabSize)),\n ],\n });\n }, [theme, fontSize, lineWrap, tabSize]);\n\n return <div ref={hostRef} className=\"h-full min-h-0 overflow-hidden\" />;\n};\n", "// NBT syntax highlighting for CodeMirror 6 \u2014 a StreamLanguage tokenizer ported\n// from the console tokenizer (modules/lang_common/scan.jai) and the VSCode\n// grammar (editors/vscode/nbt/syntaxes/nbt.tmLanguage.json). Highlighting is\n// local; everything semantic (diagnostics/completion/hover) comes via the LSP.\n\nimport {\n StreamLanguage,\n LanguageSupport,\n indentUnit,\n type StreamParser,\n} from \"@codemirror/language\";\n\nconst KEYWORDS = new Set([\n \"entity\", \"enum\", \"struct\", \"const\", \"export\", \"extends\",\n \"fn\", \"on\", \"action\", \"activity\", \"task\", \"variant\", \"workflow\", \"command\",\n \"middleware\", \"schedule\", \"every\", \"jai\",\n \"migration\", \"test\", \"mock\", \"assert\",\n \"cartridge\", \"service\", \"component\", \"app\", \"route\", \"layout\",\n \"import\", \"from\",\n \"if\", \"elif\", \"else\", \"while\", \"for\", \"in\", \"return\", \"break\", \"continue\",\n \"delete\", \"defer\", \"print\", \"sleep\", \"fail\",\n]);\n\nconst TYPES = new Set([\n \"string\", \"bool\", \"ulid\", \"document\", \"dict\", \"blob\", \"DateTime\",\n \"u8\", \"u16\", \"u32\", \"u64\", \"s8\", \"s16\", \"s32\", \"s64\",\n \"int\", \"integer\", \"float\", \"float64\", \"f32\", \"f64\", \"double\",\n \"time\", \"bytes\", \"any\", \"name\", \"ref\",\n]);\n\ntype NbtState = {\n tripleString: boolean;\n};\n\n// NBT strings carry NO escapes (scan.jai consumes to the bare closing quote),\n// so a backslash before a quote does not extend the string.\nfunction eatSingleLineString(stream: StringStream, quote: string): string {\n while (!stream.eol()) {\n if (stream.next() === quote) break;\n }\n return \"string\";\n}\n\ntype StringStream = Parameters<StreamParser<NbtState>[\"token\"]>[0];\n\nconst nbtParser: StreamParser<NbtState> = {\n name: \"nbt\",\n startState: () => ({ tripleString: false }),\n token(stream, state) {\n if (state.tripleString) {\n while (!stream.eol()) {\n if (stream.match('\"\"\"')) {\n state.tripleString = false;\n return \"string\";\n }\n stream.next();\n }\n return \"string\";\n }\n\n if (stream.eatSpace()) return null;\n\n const ch = stream.peek();\n if (ch == null) return null;\n\n if (ch === \"#\") {\n stream.skipToEnd();\n return \"comment\";\n }\n\n if (stream.match('\"\"\"')) {\n state.tripleString = true;\n // Rest of line is string body unless it closes on the same line.\n while (!stream.eol()) {\n if (stream.match('\"\"\"')) {\n state.tripleString = false;\n return \"string\";\n }\n stream.next();\n }\n return \"string\";\n }\n\n if (ch === '\"') {\n stream.next();\n return eatSingleLineString(stream, '\"');\n }\n if (ch === \"'\") {\n // Like the scanner: only a string opener when not glued to an identifier\n // (lets contractions inside docs pass).\n const before = stream.string.charAt(stream.pos - 1);\n if (!/[A-Za-z0-9_]/.test(before)) {\n stream.next();\n return eatSingleLineString(stream, \"'\");\n }\n stream.next();\n return null;\n }\n\n // f-strings: f\"...\" \u2014 body highlighted as a string (interpolation holes\n // are cosmetic only).\n if (ch === \"f\" && stream.string.charAt(stream.pos + 1) === '\"') {\n stream.next();\n stream.next();\n return eatSingleLineString(stream, '\"');\n }\n\n // @attr / @@attr\n if (ch === \"@\") {\n stream.next();\n stream.eat(\"@\");\n stream.eatWhile(/[A-Za-z0-9_]/);\n return \"meta\";\n }\n\n // Numbers. The optional fraction backtracks on `0..9` ranges (matches \"0\",\n // not \"0.\").\n if (/\\d/.test(ch)) {\n stream.match(/^\\d+(\\.\\d+)?/);\n return \"number\";\n }\n\n if (/[A-Za-z_]/.test(ch)) {\n stream.eatWhile(/[A-Za-z0-9_]/);\n const word = stream.current();\n if (word === \"true\" || word === \"false\") return \"atom\";\n if (KEYWORDS.has(word)) return \"keyword\";\n if (TYPES.has(word)) return \"typeName\";\n if (/^[A-Z]/.test(word)) return \"typeName\"; // entity/enum references\n return \"variableName\";\n }\n\n if (/[+\\-*/=<>!&|?.,:;]/.test(ch)) {\n stream.next();\n stream.eatWhile(/[+\\-*/=<>!&|.]/);\n return \"operator\";\n }\n\n stream.next();\n return null;\n },\n languageData: {\n commentTokens: { line: \"#\" },\n },\n};\n\nexport const nbtLanguage = StreamLanguage.define(nbtParser);\n\nexport function nbtLanguageSupport(): LanguageSupport {\n return new LanguageSupport(nbtLanguage, [indentUnit.of(\" \")]);\n}\n", "// Preloaded CodeMirror color themes for the NBT editor. \"default\" matches the\n// devtools panel chrome via its CSS variables (the editor renders inside the\n// .nimbit-devtools subtree, so these resolve to the scoped tokens); the rest\n// come from `thememirror`. Color only \u2014 sizing (font size/family/height) is\n// applied separately by the editor so it can follow the font-size setting.\n\nimport { EditorView } from \"@codemirror/view\";\nimport type { Extension } from \"@codemirror/state\";\nimport { HighlightStyle, syntaxHighlighting } from \"@codemirror/language\";\nimport { tags as t } from \"@lezer/highlight\";\nimport {\n amy,\n ayuLight,\n barf,\n bespin,\n birdsOfParadise,\n boysAndGirls,\n clouds,\n cobalt,\n coolGlow,\n dracula,\n espresso,\n noctisLilac,\n rosePineDawn,\n smoothy,\n solarizedLight,\n tomorrow,\n} from \"thememirror\";\n\nconst defaultTheme = EditorView.theme(\n {\n \"&\": {\n backgroundColor: \"var(--background)\",\n color: \"var(--foreground)\",\n },\n \".cm-gutters\": {\n backgroundColor: \"var(--background)\",\n color: \"var(--muted-foreground)\",\n borderRight: \"1px solid var(--border)\",\n },\n \".cm-activeLine\": {\n backgroundColor: \"color-mix(in srgb, var(--accent) 35%, transparent)\",\n },\n \".cm-tooltip\": {\n backgroundColor: \"var(--popover)\",\n color: \"var(--popover-foreground)\",\n border: \"1px solid var(--border)\",\n },\n },\n { dark: true },\n);\n\n// \"Nimbit Dark\" \u2014 the brand theme, matching the marketing hero's code panel:\n// brand-yellow keywords, pink @-directives, foreground type names, muted-italic\n// comments. Unlike `default` it ships its own HighlightStyle (so syntax colors\n// are branded, not CodeMirror's fallback) and uses fixed colors so it looks the\n// same regardless of the surrounding CSS variables. The NBT StreamLanguage emits\n// standard token names (\"keyword\"/\"typeName\"/\"meta\"/\u2026 in nbt-language.ts) which\n// map to these Lezer tags.\nconst nimbitDarkChrome = EditorView.theme(\n {\n \"&\": { backgroundColor: \"#0b0b0e\", color: \"#e4e4e7\" },\n \".cm-content\": { caretColor: \"#facc15\" },\n \".cm-cursor, .cm-dropCursor\": { borderLeftColor: \"#facc15\" },\n \"&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection\":\n { backgroundColor: \"rgba(250, 204, 21, 0.18)\" },\n \".cm-gutters\": {\n backgroundColor: \"#0b0b0e\",\n color: \"#52525b\",\n borderRight: \"1px solid rgba(255, 255, 255, 0.06)\",\n },\n \".cm-activeLine\": { backgroundColor: \"rgba(250, 204, 21, 0.06)\" },\n \".cm-activeLineGutter\": { backgroundColor: \"rgba(250, 204, 21, 0.06)\", color: \"#a1a1aa\" },\n \".cm-tooltip\": {\n backgroundColor: \"#18181b\",\n color: \"#e4e4e7\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n },\n \".cm-tooltip-autocomplete ul li[aria-selected]\": {\n backgroundColor: \"rgba(250, 204, 21, 0.15)\",\n color: \"#fafafa\",\n },\n },\n { dark: true },\n);\n\nconst nimbitDarkHighlight = HighlightStyle.define([\n { tag: t.keyword, color: \"#facc15\", fontWeight: \"500\" }, // entity, enum, \u2026\n { tag: [t.typeName, t.className, t.tagName], color: \"#e5e7eb\", fontWeight: \"500\" }, // types + entity refs\n { tag: [t.propertyName, t.variableName, t.attributeName], color: \"#cbd5e1\" }, // field names\n { tag: [t.string, t.special(t.string)], color: \"#fde047\" },\n { tag: [t.number, t.bool, t.atom, t.null], color: \"#fbbf24\" }, // numbers, true/false\n { tag: [t.meta, t.annotation], color: \"#f472b6\", fontWeight: \"500\" }, // @relation, @@index, \u2026\n { tag: t.comment, color: \"#71717a\", fontStyle: \"italic\" },\n { tag: [t.operator, t.punctuation, t.separator], color: \"#a1a1aa\" },\n { tag: t.invalid, color: \"#f87171\" },\n]);\n\nconst nimbitDark: Extension = [nimbitDarkChrome, syntaxHighlighting(nimbitDarkHighlight)];\n\nexport type EditorTheme = { id: string; label: string; extension: Extension };\n\nexport const EDITOR_THEMES: EditorTheme[] = [\n { id: \"default\", label: \"Default (panel)\", extension: defaultTheme },\n { id: \"nimbitDark\", label: \"Nimbit Dark\", extension: nimbitDark },\n { id: \"dracula\", label: \"Dracula\", extension: dracula },\n { id: \"tomorrow\", label: \"Tomorrow\", extension: tomorrow },\n { id: \"cobalt\", label: \"Cobalt\", extension: cobalt },\n { id: \"espresso\", label: \"Espresso\", extension: espresso },\n { id: \"barf\", label: \"Barf\", extension: barf },\n { id: \"bespin\", label: \"Bespin\", extension: bespin },\n { id: \"birdsOfParadise\", label: \"Birds of Paradise\", extension: birdsOfParadise },\n { id: \"boysAndGirls\", label: \"Boys and Girls\", extension: boysAndGirls },\n { id: \"coolGlow\", label: \"Cool Glow\", extension: coolGlow },\n { id: \"amy\", label: \"Amy\", extension: amy },\n { id: \"ayuLight\", label: \"Ayu Light\", extension: ayuLight },\n { id: \"clouds\", label: \"Clouds\", extension: clouds },\n { id: \"noctisLilac\", label: \"Noctis Lilac\", extension: noctisLilac },\n { id: \"rosePineDawn\", label: \"Ros\u00E9 Pine Dawn\", extension: rosePineDawn },\n { id: \"smoothy\", label: \"Smoothy\", extension: smoothy },\n { id: \"solarizedLight\", label: \"Solarized Light\", extension: solarizedLight },\n];\n\nconst byId = new Map(EDITOR_THEMES.map((t) => [t.id, t.extension]));\n\nexport function themeExtension(id: string): Extension {\n return byId.get(id) ?? EDITOR_THEMES[0].extension;\n}\n", "// CodeMirror extensions wiring an editor buffer to the NbtLspClient:\n// full-text didChange sync (debounced), pushed publishDiagnostics \u2192 lint,\n// completion, hover, and F12 go-to-definition.\n\nimport { type Extension, type Text } from \"@codemirror/state\";\nimport {\n EditorView,\n ViewPlugin,\n type ViewUpdate,\n hoverTooltip,\n keymap,\n} from \"@codemirror/view\";\nimport {\n autocompletion,\n type CompletionContext,\n type CompletionResult,\n} from \"@codemirror/autocomplete\";\nimport { setDiagnostics, type Diagnostic } from \"@codemirror/lint\";\nimport {\n NbtLspClient,\n type LspDiagnostic,\n type LspPosition,\n type LspCompletionItem,\n type LspLocation,\n} from \"./lsp-client\";\n\nfunction toLspPos(doc: Text, offset: number): LspPosition {\n const line = doc.lineAt(offset);\n return { line: line.number - 1, character: offset - line.from };\n}\n\nfunction fromLspPos(doc: Text, pos: LspPosition): number {\n const lineNo = Math.min(Math.max(pos.line + 1, 1), doc.lines);\n const line = doc.line(lineNo);\n return Math.min(line.from + Math.max(pos.character, 0), line.to);\n}\n\nfunction toCmDiagnostics(doc: Text, diags: LspDiagnostic[]): Diagnostic[] {\n return diags.map((d) => {\n const from = fromLspPos(doc, d.range.start);\n let to = fromLspPos(doc, d.range.end);\n if (to <= from) to = Math.min(from + 1, doc.length);\n const severity =\n d.severity === 2 ? \"warning\" : d.severity === 3 || d.severity === 4 ? \"info\" : \"error\";\n return { from, to, severity, message: d.message, source: d.source ?? \"nbt\" };\n });\n}\n\n// LSP CompletionItemKind \u2192 CM completion type (drives the icon).\nfunction completionType(kind?: number): string {\n switch (kind) {\n case 3: return \"function\";\n case 5: return \"property\";\n case 13: return \"enum\";\n case 14: return \"keyword\";\n case 22: return \"class\";\n default: return \"variable\";\n }\n}\n\nexport type GotoDefHandler = (uri: string, line: number) => void;\n\nexport function lspExtensions(\n client: NbtLspClient,\n uri: string,\n onGotoDefinition?: GotoDefHandler,\n): Extension[] {\n // Sync + diagnostics plugin. didOpen on create, debounced didChange,\n // diagnostics pushed by the server are dispatched into the lint state.\n const syncPlugin = ViewPlugin.fromClass(\n class {\n private timer: ReturnType<typeof setTimeout> | null = null;\n private unsubscribe: () => void;\n\n constructor(readonly view: EditorView) {\n client.didOpen(uri, view.state.doc.toString());\n this.unsubscribe = client.onDiagnostics(uri, (diags) => {\n const cm = toCmDiagnostics(this.view.state.doc, diags);\n this.view.dispatch(setDiagnostics(this.view.state, cm));\n });\n }\n\n update(u: ViewUpdate) {\n if (!u.docChanged) return;\n if (this.timer) clearTimeout(this.timer);\n this.timer = setTimeout(() => {\n this.timer = null;\n client.didChange(uri, this.view.state.doc.toString());\n }, 200);\n }\n\n destroy() {\n if (this.timer) {\n clearTimeout(this.timer);\n client.didChange(uri, this.view.state.doc.toString());\n }\n this.unsubscribe();\n }\n },\n );\n\n const completionSource = async (\n ctx: CompletionContext,\n ): Promise<CompletionResult | null> => {\n const word = ctx.matchBefore(/\\w*/);\n if (!word) return null;\n if (word.from === word.to && !ctx.explicit) {\n // Only fire automatically right after a trigger character.\n const before = ctx.state.doc.sliceString(Math.max(0, ctx.pos - 1), ctx.pos);\n if (before !== \".\" && before !== \":\" && before !== '\"') return null;\n }\n // Flush any pending edit so the server completes against the live buffer.\n client.didChange(uri, ctx.state.doc.toString());\n let result;\n try {\n result = await client.completion(uri, toLspPos(ctx.state.doc, ctx.pos));\n } catch {\n return null;\n }\n const items: LspCompletionItem[] = Array.isArray(result)\n ? result\n : (result?.items ?? []);\n if (items.length === 0) return null;\n return {\n from: word.from,\n options: items.map((it) => ({\n label: it.label,\n type: completionType(it.kind),\n detail: it.detail,\n })),\n };\n };\n\n const hover = hoverTooltip(async (view, pos) => {\n let result;\n try {\n result = await client.hover(uri, toLspPos(view.state.doc, pos));\n } catch {\n return null;\n }\n const value = result?.contents?.value;\n if (!value) return null;\n return {\n pos,\n create: () => {\n const dom = document.createElement(\"pre\");\n dom.className = \"nbt-hover-tooltip\";\n dom.style.cssText =\n \"margin:0;padding:6px 8px;max-width:480px;white-space:pre-wrap;font-size:11px;\";\n // Server emits fenced markdown code blocks; strip the fences, show text.\n dom.textContent = value.replace(/```\\w*\\n?/g, \"\");\n return { dom };\n },\n };\n });\n\n const gotoDef = keymap.of([\n {\n key: \"F12\",\n run: (view) => {\n const pos = toLspPos(view.state.doc, view.state.selection.main.head);\n client\n .definition(uri, pos)\n .then((result) => {\n const loc: LspLocation | null = Array.isArray(result)\n ? (result[0] ?? null)\n : result;\n if (!loc?.uri) return;\n if (loc.uri === uri) {\n const off = fromLspPos(view.state.doc, loc.range.start);\n view.dispatch({\n selection: { anchor: off },\n scrollIntoView: true,\n });\n } else {\n onGotoDefinition?.(loc.uri, loc.range.start.line);\n }\n })\n .catch(() => {});\n return true;\n },\n },\n ]);\n\n return [\n syncPlugin,\n autocompletion({ override: [completionSource] }),\n hover,\n gotoDef,\n ];\n}\n", "// Minimal LSP client over WebSocket for the console's dev-mode nbt_lsp bridge\n// (/_console/dev/lsp). One JSON-RPC message per WS text frame \u2014 no\n// Content-Length framing (the bridge's write_proc emits bare JSON).\n//\n// Hand-rolled on purpose: the server speaks ~10 methods with full-text sync,\n// and a library client (codemirror-languageserver) would drag transitive\n// runtime deps into every host app.\n\nexport type LspPosition = { line: number; character: number };\nexport type LspRange = { start: LspPosition; end: LspPosition };\nexport type LspDiagnostic = {\n range: LspRange;\n severity?: number; // 1=error 2=warning 3=info 4=hint\n message: string;\n source?: string;\n};\nexport type LspCompletionItem = {\n label: string;\n kind?: number;\n detail?: string;\n};\nexport type LspLocation = { uri: string; range: LspRange };\n\ntype Pending = {\n resolve: (v: unknown) => void;\n reject: (e: Error) => void;\n};\n\nexport class NbtLspClient {\n private url: string;\n private rootUri: string | null = null;\n private ws: WebSocket | null = null;\n private nextId = 1;\n private pending = new Map<number, Pending>();\n private diagHandlers = new Map<string, (d: LspDiagnostic[]) => void>();\n // Open buffers, kept for replay across reconnects.\n private docs = new Map<string, { text: string; version: number }>();\n private ready = false;\n private queue: string[] = [];\n private closed = false;\n private retryMs = 500;\n\n constructor(url: string) {\n this.url = url;\n this.connect();\n }\n\n dispose() {\n this.closed = true;\n this.ws?.close();\n this.pending.forEach((p) => p.reject(new Error(\"lsp client disposed\")));\n this.pending.clear();\n }\n\n private connect() {\n if (this.closed) return;\n const ws = new WebSocket(this.url);\n this.ws = ws;\n ws.onopen = () => {\n this.retryMs = 500;\n if (this.rootUri) this.sendInitialize(this.rootUri);\n };\n ws.onmessage = (ev) => {\n if (typeof ev.data !== \"string\") return;\n this.onMessage(ev.data);\n };\n ws.onclose = () => {\n this.ready = false;\n this.ws = null;\n for (const p of this.pending.values())\n p.reject(new Error(\"lsp connection closed\"));\n this.pending.clear();\n if (!this.closed) {\n setTimeout(() => this.connect(), this.retryMs);\n this.retryMs = Math.min(this.retryMs * 2, 10_000);\n }\n };\n }\n\n // Called once by the host with file://<projectRoot>; also re-sent after every\n // reconnect, followed by didOpen replays for tracked buffers.\n initialize(rootUri: string) {\n this.rootUri = rootUri;\n if (this.ws?.readyState === WebSocket.OPEN) this.sendInitialize(rootUri);\n }\n\n private sendInitialize(rootUri: string) {\n const id = this.nextId++;\n this.pending.set(id, {\n resolve: () => {\n this.sendRaw({ jsonrpc: \"2.0\", method: \"initialized\", params: {} });\n this.ready = true;\n for (const [uri, d] of this.docs) {\n this.sendRaw({\n jsonrpc: \"2.0\",\n method: \"textDocument/didOpen\",\n params: {\n textDocument: {\n uri,\n languageId: \"nbt\",\n version: d.version,\n text: d.text,\n },\n },\n });\n }\n const q = this.queue;\n this.queue = [];\n for (const m of q) this.ws?.send(m);\n },\n reject: () => {},\n });\n this.ws?.send(\n JSON.stringify({\n jsonrpc: \"2.0\",\n id,\n method: \"initialize\",\n params: { rootUri },\n }),\n );\n }\n\n private sendRaw(msg: object) {\n const s = JSON.stringify(msg);\n if (this.ready && this.ws?.readyState === WebSocket.OPEN) this.ws.send(s);\n else this.queue.push(s);\n }\n\n private onMessage(data: string) {\n let msg: any;\n try {\n msg = JSON.parse(data);\n } catch {\n return;\n }\n if (msg.id != null && (msg.result !== undefined || msg.error)) {\n const p = this.pending.get(msg.id);\n if (!p) return;\n this.pending.delete(msg.id);\n if (msg.error) p.reject(new Error(msg.error.message ?? \"lsp error\"));\n else p.resolve(msg.result);\n return;\n }\n if (msg.method === \"textDocument/publishDiagnostics\") {\n const uri = msg.params?.uri as string;\n const handler = this.diagHandlers.get(uri);\n if (handler) handler((msg.params?.diagnostics ?? []) as LspDiagnostic[]);\n }\n }\n\n request<T>(method: string, params: object): Promise<T> {\n const id = this.nextId++;\n const p = new Promise<T>((resolve, reject) => {\n this.pending.set(id, { resolve: resolve as Pending[\"resolve\"], reject });\n });\n this.sendRaw({ jsonrpc: \"2.0\", id, method, params });\n return p;\n }\n\n onDiagnostics(uri: string, handler: (d: LspDiagnostic[]) => void): () => void {\n this.diagHandlers.set(uri, handler);\n return () => {\n if (this.diagHandlers.get(uri) === handler) this.diagHandlers.delete(uri);\n };\n }\n\n didOpen(uri: string, text: string) {\n const existing = this.docs.get(uri);\n if (existing) {\n // Re-opening an already-tracked buffer (tab switch) \u2014 just resync.\n this.didChange(uri, text);\n return;\n }\n this.docs.set(uri, { text, version: 1 });\n this.sendRaw({\n jsonrpc: \"2.0\",\n method: \"textDocument/didOpen\",\n params: { textDocument: { uri, languageId: \"nbt\", version: 1, text } },\n });\n }\n\n didChange(uri: string, text: string) {\n const d = this.docs.get(uri);\n if (!d) return this.didOpen(uri, text);\n if (d.text === text) return;\n d.text = text;\n d.version += 1;\n this.sendRaw({\n jsonrpc: \"2.0\",\n method: \"textDocument/didChange\",\n params: {\n textDocument: { uri, version: d.version },\n contentChanges: [{ text }],\n },\n });\n }\n\n didClose(uri: string) {\n if (!this.docs.delete(uri)) return;\n this.sendRaw({\n jsonrpc: \"2.0\",\n method: \"textDocument/didClose\",\n params: { textDocument: { uri } },\n });\n }\n\n completion(uri: string, pos: LspPosition): Promise<{ items: LspCompletionItem[] } | LspCompletionItem[] | null> {\n return this.request(\"textDocument/completion\", {\n textDocument: { uri },\n position: pos,\n });\n }\n\n hover(uri: string, pos: LspPosition): Promise<{ contents?: { value?: string } } | null> {\n return this.request(\"textDocument/hover\", {\n textDocument: { uri },\n position: pos,\n });\n }\n\n definition(uri: string, pos: LspPosition): Promise<LspLocation | LspLocation[] | null> {\n return this.request(\"textDocument/definition\", {\n textDocument: { uri },\n position: pos,\n });\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["EditorView", "keymap", "syntaxHighlighting", "indentUnit", "t", "EditorView", "indentUnit", "syntaxHighlighting", "keymap", "view"]
7
+ }
@@ -7,5 +7,7 @@ export { useLiveBulkRegistry } from "./use-cartridge-info";
7
7
  export type { BulkEntity, BulkRegistry, LiveRegistryState, } from "./use-cartridge-info";
8
8
  export { useGsheetsApi } from "./use-gsheets";
9
9
  export type { GsheetSyncConfig, GsheetSaveInput } from "./use-gsheets";
10
+ export { useWorkflowsApi, isWfTerminal, WF_TERMINAL } from "./use-workflows";
11
+ export type { WfStatus, WfListItem, WfExecution, WfEvent, WfDetail, WfStats, WfVersion, WfExecReply, } from "./use-workflows";
10
12
  export { getDevToolsToken, setDevToolsToken, clearDevToolsToken, authHeaders, fetchWhoAmI, devToolsSignIn, devToolsSignUp, devToolsSignOut, wsAuthProtocols, fetchDevtoolsSettings, saveDevtoolsSettings, } from "./auth";
11
13
  export type { WhoAmI } from "./auth";
@@ -0,0 +1,68 @@
1
+ export declare const WF_TERMINAL: readonly ["COMPLETED", "FAILED", "CANCELLED", "CONTINUED"];
2
+ export type WfStatus = "RUNNING" | "SUSPENDED" | "COMPLETED" | "FAILED" | "CANCELLED" | "CONTINUED";
3
+ export type WfListItem = {
4
+ id: string;
5
+ status: WfStatus;
6
+ workflowName: string;
7
+ createdAt: number;
8
+ updatedAt: number;
9
+ lane: string;
10
+ deployVersion: number;
11
+ };
12
+ export type WfExecution = {
13
+ id: string;
14
+ status: WfStatus;
15
+ workflowName: string;
16
+ args?: string;
17
+ result?: string;
18
+ error?: string;
19
+ cursor: number;
20
+ lane?: string;
21
+ deployVersion: number;
22
+ createdAt: number;
23
+ updatedAt: number;
24
+ };
25
+ export type WfEvent = {
26
+ id: string;
27
+ seq: number;
28
+ kind: string;
29
+ capability?: string;
30
+ target?: string;
31
+ op?: string;
32
+ payload?: string;
33
+ };
34
+ export type WfDetail = {
35
+ execution: WfExecution;
36
+ events: WfEvent[];
37
+ };
38
+ export type WfStats = {
39
+ writes: number;
40
+ reads: number;
41
+ emails: number;
42
+ fetches: number;
43
+ emits: number;
44
+ retries: number;
45
+ async_inflight: number;
46
+ async_peak: number;
47
+ };
48
+ export type WfVersion = {
49
+ version: number;
50
+ refcount: number;
51
+ current: boolean;
52
+ };
53
+ export type WfExecReply = {
54
+ id: string;
55
+ outcome: string;
56
+ status: string;
57
+ result?: string;
58
+ error?: string;
59
+ };
60
+ export declare function isWfTerminal(status: string): boolean;
61
+ export declare function useWorkflowsApi(): {
62
+ listExecutions: () => Promise<WfListItem[]>;
63
+ getExecution: (id: string) => Promise<WfDetail>;
64
+ getStats: () => Promise<WfStats>;
65
+ getVersions: () => Promise<WfVersion[]>;
66
+ cancel: (id: string) => Promise<WfExecReply>;
67
+ advance: (id: string) => Promise<WfExecReply>;
68
+ };
@@ -7,7 +7,7 @@ import {
7
7
  nbtLanguage,
8
8
  nbtLanguageSupport,
9
9
  themeExtension
10
- } from "../chunk-TNIHD62H.js";
10
+ } from "../chunk-PI7ZMVVU.js";
11
11
  export {
12
12
  EDITOR_THEMES,
13
13
  NbtEditor,
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  nbtLanguage,
8
8
  nbtLanguageSupport,
9
9
  themeExtension
10
- } from "./chunk-TNIHD62H.js";
10
+ } from "./chunk-PI7ZMVVU.js";
11
11
  import {
12
12
  DiagramView,
13
13
  EntityNode,
@@ -162,6 +162,83 @@ function useGsheetsApi() {
162
162
  );
163
163
  return useMemo(() => ({ list, save, syncNow, remove }), [list, save, syncNow, remove]);
164
164
  }
165
+
166
+ // src/core/use-workflows.ts
167
+ import { useCallback as useCallback2, useMemo as useMemo2 } from "react";
168
+ var WF_TERMINAL = ["COMPLETED", "FAILED", "CANCELLED", "CONTINUED"];
169
+ async function jsonOrThrow2(r) {
170
+ const body = await r.json().catch(() => ({}));
171
+ if (!r.ok) throw new Error(body?.error ?? `HTTP ${r.status}`);
172
+ return body;
173
+ }
174
+ function isWfTerminal(status) {
175
+ return WF_TERMINAL.includes(status);
176
+ }
177
+ function useWorkflowsApi() {
178
+ const { apiBaseUrl } = useDevToolsConfig();
179
+ const listExecutions = useCallback2(
180
+ async () => jsonOrThrow2(
181
+ await fetch(`${apiBaseUrl}/_console/wf`, {
182
+ credentials: "include",
183
+ headers: authHeaders()
184
+ })
185
+ ),
186
+ [apiBaseUrl]
187
+ );
188
+ const getExecution = useCallback2(
189
+ async (id) => jsonOrThrow2(
190
+ await fetch(`${apiBaseUrl}/_console/wf/${encodeURIComponent(id)}`, {
191
+ credentials: "include",
192
+ headers: authHeaders()
193
+ })
194
+ ),
195
+ [apiBaseUrl]
196
+ );
197
+ const getStats = useCallback2(
198
+ async () => jsonOrThrow2(
199
+ await fetch(`${apiBaseUrl}/_console/wf/stats`, {
200
+ credentials: "include",
201
+ headers: authHeaders()
202
+ })
203
+ ),
204
+ [apiBaseUrl]
205
+ );
206
+ const getVersions = useCallback2(
207
+ async () => jsonOrThrow2(
208
+ await fetch(`${apiBaseUrl}/_console/wf/versions`, {
209
+ credentials: "include",
210
+ headers: authHeaders()
211
+ })
212
+ ),
213
+ [apiBaseUrl]
214
+ );
215
+ const cancel = useCallback2(
216
+ async (id) => jsonOrThrow2(
217
+ await fetch(`${apiBaseUrl}/_console/wf/cancel`, {
218
+ method: "POST",
219
+ credentials: "include",
220
+ headers: authHeaders({ "content-type": "application/json" }),
221
+ body: JSON.stringify({ id })
222
+ })
223
+ ),
224
+ [apiBaseUrl]
225
+ );
226
+ const advance = useCallback2(
227
+ async (id) => jsonOrThrow2(
228
+ await fetch(`${apiBaseUrl}/_console/wf/advance`, {
229
+ method: "POST",
230
+ credentials: "include",
231
+ headers: authHeaders({ "content-type": "application/json" }),
232
+ body: JSON.stringify({ id })
233
+ })
234
+ ),
235
+ [apiBaseUrl]
236
+ );
237
+ return useMemo2(
238
+ () => ({ listExecutions, getExecution, getStats, getVersions, cancel, advance }),
239
+ [listExecutions, getExecution, getStats, getVersions, cancel, advance]
240
+ );
241
+ }
165
242
  export {
166
243
  BulkStreamProvider,
167
244
  data_table_default as DataTable,
@@ -172,6 +249,7 @@ export {
172
249
  NbtEditor,
173
250
  NbtLspClient,
174
251
  value_popover_default as ValuePopover,
252
+ WF_TERMINAL,
175
253
  authHeaders,
176
254
  buildEntityGraphModel,
177
255
  cartsFromContracts,
@@ -185,6 +263,7 @@ export {
185
263
  fetchWhoAmI,
186
264
  filterEntityGraphModel,
187
265
  getDevToolsToken,
266
+ isWfTerminal,
188
267
  lspExtensions,
189
268
  nbtLanguage,
190
269
  nbtLanguageSupport,
@@ -196,6 +275,7 @@ export {
196
275
  useDevToolsConfig,
197
276
  useGsheetsApi,
198
277
  useLiveBulkRegistry,
278
+ useWorkflowsApi,
199
279
  wsAuthProtocols,
200
280
  wsBaseFrom
201
281
  };
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/core/use-cartridge-info.ts", "../src/core/use-gsheets.ts"],
4
- "sourcesContent": ["import { useEffect, useState } from \"react\";\nimport { useDevToolsConfig } from \"./config\";\nimport { authHeaders } from \"./auth\";\n\n// Live cartridge/entity registry for the Data tab. Instead of the build-time\n// `BULK_REGISTRY` (every cart in the repo, generated by `nbt generate`), we\n// read the daemon's `/_console/contracts` \u2014 which only lists *running*\n// cartridges and carries each entity's `searchFields`. Bulk WS routes are\n// derived live (`/_ws/bulk/<cart>/<entity-lower>`) and fed straight into\n// useBulkStream. So the tab reflects what is actually installed right now.\n\nexport type BulkEntity = {\n name: string;\n route: string;\n searchFields: readonly string[];\n};\nexport type BulkRegistry = Record<string, BulkEntity[]>;\n\ntype Contract = {\n cartridge?: string;\n core?: boolean;\n installed?: boolean;\n owns?: Record<string, { searchFields?: string[] }>;\n};\n\nfunction buildRegistry(\n contracts: Contract[],\n): { reg: BulkRegistry; core: Set<string>; installed: Set<string> } {\n const reg: BulkRegistry = {};\n const core = new Set<string>();\n const installed = new Set<string>();\n for (const c of contracts) {\n const cart = c.cartridge;\n if (!cart || !c.owns) continue;\n const entities: BulkEntity[] = [];\n for (const [name, ent] of Object.entries(c.owns)) {\n const sf = Array.isArray(ent?.searchFields) ? ent.searchFields : [];\n entities.push({\n name,\n route: `/_ws/bulk/${cart}/${name.toLowerCase()}`,\n searchFields: sf,\n });\n }\n if (entities.length > 0) {\n reg[cart] = entities;\n if (c.core) core.add(cart);\n if (c.installed) installed.add(cart);\n }\n }\n return { reg, core, installed };\n}\n\nexport type LiveRegistryState = {\n registry: BulkRegistry;\n carts: string[];\n // Cartridge slugs flagged `core` by the daemon. The Data tab keeps `auth`\n // visible but tucks the rest of these behind a \"more cartridges\" menu so\n // deployed (user) cartridges are what's shown by default.\n coreCarts: Set<string>;\n // Cartridge slugs the user (or boot) explicitly installed/activated. The Data\n // tab shows these (plus `auth`) by default; bundled-but-not-installed carts\n // stay behind the \"more cartridges\" menu until the user opens them.\n installedCarts: Set<string>;\n loading: boolean;\n error: string | null;\n};\n\nexport function useLiveBulkRegistry(): LiveRegistryState {\n const { apiBaseUrl } = useDevToolsConfig();\n const [registry, setRegistry] = useState<BulkRegistry>({});\n const [coreCarts, setCoreCarts] = useState<Set<string>>(new Set());\n const [installedCarts, setInstalledCarts] = useState<Set<string>>(new Set());\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const ac = new AbortController();\n let cancelled = false;\n setLoading(true);\n setError(null);\n (async () => {\n try {\n const r = await fetch(`${apiBaseUrl}/_console/contracts`, {\n signal: ac.signal,\n credentials: \"include\",\n headers: authHeaders(),\n });\n if (!r.ok) throw new Error(`HTTP ${r.status}`);\n const data = (await r.json()) as Contract[];\n if (!Array.isArray(data)) throw new Error(\"malformed contracts response\");\n if (cancelled) return;\n const { reg, core, installed } = buildRegistry(data);\n setRegistry(reg);\n setCoreCarts(core);\n setInstalledCarts(installed);\n } catch (e) {\n if (cancelled || (e as { name?: string }).name === \"AbortError\") return;\n setError(e instanceof Error ? e.message : String(e));\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n ac.abort();\n };\n }, [apiBaseUrl]);\n\n const carts = Object.keys(registry).sort();\n return { registry, carts, coreCarts, installedCarts, loading, error };\n}\n", "// Fetchers + hook for the Google Sheets cartridge-sync admin endpoints\n// (/_console/integrations/gsheets/*). Admin-gated server-side \u2014 the requests\n// carry the devtools Bearer token (authHeaders) like the contracts probe.\n\nimport { useCallback, useMemo } from \"react\";\nimport { useDevToolsConfig } from \"./config\";\nimport { authHeaders } from \"./auth\";\n\nexport type GsheetSyncConfig = {\n cartridge: string;\n spreadsheetId: string;\n saEmail: string;\n hasServiceAccount: boolean;\n intervalSeconds: number;\n enabled: boolean;\n lastSyncAt: number; // ms epoch, 0 = never\n status: string; // \"ok\" | \"error\" | \"\"\n lastError: string;\n};\n\nexport type GsheetSaveInput = {\n cartridge: string;\n spreadsheetUrl: string;\n serviceAccountJson?: string; // omit to keep the stored key\n intervalSeconds: number;\n enabled: boolean;\n};\n\nasync function jsonOrThrow(r: Response) {\n const body = await r.json().catch(() => ({}));\n if (!r.ok) throw new Error((body as { error?: string })?.error ?? `HTTP ${r.status}`);\n return body;\n}\n\nexport function useGsheetsApi() {\n const { apiBaseUrl } = useDevToolsConfig();\n\n const list = useCallback(\n async (): Promise<GsheetSyncConfig[]> =>\n jsonOrThrow(\n await fetch(`${apiBaseUrl}/_console/integrations/gsheets`, {\n credentials: \"include\",\n headers: authHeaders(),\n }),\n ),\n [apiBaseUrl],\n );\n\n const save = useCallback(\n async (input: GsheetSaveInput): Promise<GsheetSyncConfig> =>\n jsonOrThrow(\n await fetch(`${apiBaseUrl}/_console/integrations/gsheets`, {\n method: \"POST\",\n credentials: \"include\",\n headers: authHeaders({ \"content-type\": \"application/json\" }),\n body: JSON.stringify(input),\n }),\n ),\n [apiBaseUrl],\n );\n\n const syncNow = useCallback(\n async (cartridge: string): Promise<{ ok: boolean; error: string }> =>\n jsonOrThrow(\n await fetch(`${apiBaseUrl}/_console/integrations/gsheets/sync`, {\n method: \"POST\",\n credentials: \"include\",\n headers: authHeaders({ \"content-type\": \"application/json\" }),\n body: JSON.stringify({ cartridge }),\n }),\n ),\n [apiBaseUrl],\n );\n\n const remove = useCallback(\n async (cartridge: string): Promise<{ ok: boolean }> =>\n jsonOrThrow(\n await fetch(`${apiBaseUrl}/_console/integrations/gsheets/${encodeURIComponent(cartridge)}`, {\n method: \"DELETE\",\n credentials: \"include\",\n headers: authHeaders(),\n }),\n ),\n [apiBaseUrl],\n );\n\n return useMemo(() => ({ list, save, syncNow, remove }), [list, save, syncNow, remove]);\n}\n"],
5
- "mappings": "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",
6
- "names": []
3
+ "sources": ["../src/core/use-cartridge-info.ts", "../src/core/use-gsheets.ts", "../src/core/use-workflows.ts"],
4
+ "sourcesContent": ["import { useEffect, useState } from \"react\";\nimport { useDevToolsConfig } from \"./config\";\nimport { authHeaders } from \"./auth\";\n\n// Live cartridge/entity registry for the Data tab. Instead of the build-time\n// `BULK_REGISTRY` (every cart in the repo, generated by `nbt generate`), we\n// read the daemon's `/_console/contracts` \u2014 which only lists *running*\n// cartridges and carries each entity's `searchFields`. Bulk WS routes are\n// derived live (`/_ws/bulk/<cart>/<entity-lower>`) and fed straight into\n// useBulkStream. So the tab reflects what is actually installed right now.\n\nexport type BulkEntity = {\n name: string;\n route: string;\n searchFields: readonly string[];\n};\nexport type BulkRegistry = Record<string, BulkEntity[]>;\n\ntype Contract = {\n cartridge?: string;\n core?: boolean;\n installed?: boolean;\n owns?: Record<string, { searchFields?: string[] }>;\n};\n\nfunction buildRegistry(\n contracts: Contract[],\n): { reg: BulkRegistry; core: Set<string>; installed: Set<string> } {\n const reg: BulkRegistry = {};\n const core = new Set<string>();\n const installed = new Set<string>();\n for (const c of contracts) {\n const cart = c.cartridge;\n if (!cart || !c.owns) continue;\n const entities: BulkEntity[] = [];\n for (const [name, ent] of Object.entries(c.owns)) {\n const sf = Array.isArray(ent?.searchFields) ? ent.searchFields : [];\n entities.push({\n name,\n route: `/_ws/bulk/${cart}/${name.toLowerCase()}`,\n searchFields: sf,\n });\n }\n if (entities.length > 0) {\n reg[cart] = entities;\n if (c.core) core.add(cart);\n if (c.installed) installed.add(cart);\n }\n }\n return { reg, core, installed };\n}\n\nexport type LiveRegistryState = {\n registry: BulkRegistry;\n carts: string[];\n // Cartridge slugs flagged `core` by the daemon. The Data tab keeps `auth`\n // visible but tucks the rest of these behind a \"more cartridges\" menu so\n // deployed (user) cartridges are what's shown by default.\n coreCarts: Set<string>;\n // Cartridge slugs the user (or boot) explicitly installed/activated. The Data\n // tab shows these (plus `auth`) by default; bundled-but-not-installed carts\n // stay behind the \"more cartridges\" menu until the user opens them.\n installedCarts: Set<string>;\n loading: boolean;\n error: string | null;\n};\n\nexport function useLiveBulkRegistry(): LiveRegistryState {\n const { apiBaseUrl } = useDevToolsConfig();\n const [registry, setRegistry] = useState<BulkRegistry>({});\n const [coreCarts, setCoreCarts] = useState<Set<string>>(new Set());\n const [installedCarts, setInstalledCarts] = useState<Set<string>>(new Set());\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const ac = new AbortController();\n let cancelled = false;\n setLoading(true);\n setError(null);\n (async () => {\n try {\n const r = await fetch(`${apiBaseUrl}/_console/contracts`, {\n signal: ac.signal,\n credentials: \"include\",\n headers: authHeaders(),\n });\n if (!r.ok) throw new Error(`HTTP ${r.status}`);\n const data = (await r.json()) as Contract[];\n if (!Array.isArray(data)) throw new Error(\"malformed contracts response\");\n if (cancelled) return;\n const { reg, core, installed } = buildRegistry(data);\n setRegistry(reg);\n setCoreCarts(core);\n setInstalledCarts(installed);\n } catch (e) {\n if (cancelled || (e as { name?: string }).name === \"AbortError\") return;\n setError(e instanceof Error ? e.message : String(e));\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n ac.abort();\n };\n }, [apiBaseUrl]);\n\n const carts = Object.keys(registry).sort();\n return { registry, carts, coreCarts, installedCarts, loading, error };\n}\n", "// Fetchers + hook for the Google Sheets cartridge-sync admin endpoints\n// (/_console/integrations/gsheets/*). Admin-gated server-side \u2014 the requests\n// carry the devtools Bearer token (authHeaders) like the contracts probe.\n\nimport { useCallback, useMemo } from \"react\";\nimport { useDevToolsConfig } from \"./config\";\nimport { authHeaders } from \"./auth\";\n\nexport type GsheetSyncConfig = {\n cartridge: string;\n spreadsheetId: string;\n saEmail: string;\n hasServiceAccount: boolean;\n intervalSeconds: number;\n enabled: boolean;\n lastSyncAt: number; // ms epoch, 0 = never\n status: string; // \"ok\" | \"error\" | \"\"\n lastError: string;\n};\n\nexport type GsheetSaveInput = {\n cartridge: string;\n spreadsheetUrl: string;\n serviceAccountJson?: string; // omit to keep the stored key\n intervalSeconds: number;\n enabled: boolean;\n};\n\nasync function jsonOrThrow(r: Response) {\n const body = await r.json().catch(() => ({}));\n if (!r.ok) throw new Error((body as { error?: string })?.error ?? `HTTP ${r.status}`);\n return body;\n}\n\nexport function useGsheetsApi() {\n const { apiBaseUrl } = useDevToolsConfig();\n\n const list = useCallback(\n async (): Promise<GsheetSyncConfig[]> =>\n jsonOrThrow(\n await fetch(`${apiBaseUrl}/_console/integrations/gsheets`, {\n credentials: \"include\",\n headers: authHeaders(),\n }),\n ),\n [apiBaseUrl],\n );\n\n const save = useCallback(\n async (input: GsheetSaveInput): Promise<GsheetSyncConfig> =>\n jsonOrThrow(\n await fetch(`${apiBaseUrl}/_console/integrations/gsheets`, {\n method: \"POST\",\n credentials: \"include\",\n headers: authHeaders({ \"content-type\": \"application/json\" }),\n body: JSON.stringify(input),\n }),\n ),\n [apiBaseUrl],\n );\n\n const syncNow = useCallback(\n async (cartridge: string): Promise<{ ok: boolean; error: string }> =>\n jsonOrThrow(\n await fetch(`${apiBaseUrl}/_console/integrations/gsheets/sync`, {\n method: \"POST\",\n credentials: \"include\",\n headers: authHeaders({ \"content-type\": \"application/json\" }),\n body: JSON.stringify({ cartridge }),\n }),\n ),\n [apiBaseUrl],\n );\n\n const remove = useCallback(\n async (cartridge: string): Promise<{ ok: boolean }> =>\n jsonOrThrow(\n await fetch(`${apiBaseUrl}/_console/integrations/gsheets/${encodeURIComponent(cartridge)}`, {\n method: \"DELETE\",\n credentials: \"include\",\n headers: authHeaders(),\n }),\n ),\n [apiBaseUrl],\n );\n\n return useMemo(() => ({ list, save, syncNow, remove }), [list, save, syncNow, remove]);\n}\n", "// Fetchers + hook for the workflow-engine introspection endpoints\n// (/_console/wf*). The read routes are ungated like /_console/metrics; the two\n// mutating ones (cancel/advance) are admin-gated server-side, so every request\n// carries the devtools Bearer token (authHeaders) like the contracts probe.\n\nimport { useCallback, useMemo } from \"react\";\nimport { useDevToolsConfig } from \"./config\";\nimport { authHeaders } from \"./auth\";\n\n// Terminal statuses a workflow can settle into \u2014 used to decide whether to keep\n// polling an open instance and whether Cancel is offered.\nexport const WF_TERMINAL = [\"COMPLETED\", \"FAILED\", \"CANCELLED\", \"CONTINUED\"] as const;\n\nexport type WfStatus =\n | \"RUNNING\"\n | \"SUSPENDED\"\n | \"COMPLETED\"\n | \"FAILED\"\n | \"CANCELLED\"\n | \"CONTINUED\";\n\n// Row from GET /_console/wf \u2014 the enriched list (createdAt/updatedAt are unix ms).\nexport type WfListItem = {\n id: string;\n status: WfStatus;\n workflowName: string;\n createdAt: number;\n updatedAt: number;\n lane: string;\n deployVersion: number;\n};\n\n// The execution record from GET /_console/wf/:id (raw entity field names).\nexport type WfExecution = {\n id: string;\n status: WfStatus;\n workflowName: string;\n args?: string;\n result?: string;\n error?: string;\n cursor: number;\n lane?: string;\n deployVersion: number;\n createdAt: number;\n updatedAt: number;\n};\n\n// One journal entry. kind \u2208 HOST_CALL_INTENT | HOST_CALL_RESULT | SUSPENDED |\n// RESUMED | RETRY | COMPLETED | FAILED | CANCELLED | CONTINUED.\nexport type WfEvent = {\n id: string;\n seq: number;\n kind: string;\n capability?: string;\n target?: string;\n op?: string;\n payload?: string;\n};\n\nexport type WfDetail = { execution: WfExecution; events: WfEvent[] };\n\nexport type WfStats = {\n writes: number;\n reads: number;\n emails: number;\n fetches: number;\n emits: number;\n retries: number;\n async_inflight: number;\n async_peak: number;\n};\n\nexport type WfVersion = { version: number; refcount: number; current: boolean };\n\n// The exec-reply shape returned by run/signal/advance/cancel.\nexport type WfExecReply = {\n id: string;\n outcome: string;\n status: string;\n result?: string;\n error?: string;\n};\n\nasync function jsonOrThrow(r: Response) {\n const body = await r.json().catch(() => ({}));\n if (!r.ok) throw new Error((body as { error?: string })?.error ?? `HTTP ${r.status}`);\n return body;\n}\n\nexport function isWfTerminal(status: string): boolean {\n return (WF_TERMINAL as readonly string[]).includes(status);\n}\n\nexport function useWorkflowsApi() {\n const { apiBaseUrl } = useDevToolsConfig();\n\n const listExecutions = useCallback(\n async (): Promise<WfListItem[]> =>\n jsonOrThrow(\n await fetch(`${apiBaseUrl}/_console/wf`, {\n credentials: \"include\",\n headers: authHeaders(),\n }),\n ),\n [apiBaseUrl],\n );\n\n const getExecution = useCallback(\n async (id: string): Promise<WfDetail> =>\n jsonOrThrow(\n await fetch(`${apiBaseUrl}/_console/wf/${encodeURIComponent(id)}`, {\n credentials: \"include\",\n headers: authHeaders(),\n }),\n ),\n [apiBaseUrl],\n );\n\n const getStats = useCallback(\n async (): Promise<WfStats> =>\n jsonOrThrow(\n await fetch(`${apiBaseUrl}/_console/wf/stats`, {\n credentials: \"include\",\n headers: authHeaders(),\n }),\n ),\n [apiBaseUrl],\n );\n\n const getVersions = useCallback(\n async (): Promise<WfVersion[]> =>\n jsonOrThrow(\n await fetch(`${apiBaseUrl}/_console/wf/versions`, {\n credentials: \"include\",\n headers: authHeaders(),\n }),\n ),\n [apiBaseUrl],\n );\n\n const cancel = useCallback(\n async (id: string): Promise<WfExecReply> =>\n jsonOrThrow(\n await fetch(`${apiBaseUrl}/_console/wf/cancel`, {\n method: \"POST\",\n credentials: \"include\",\n headers: authHeaders({ \"content-type\": \"application/json\" }),\n body: JSON.stringify({ id }),\n }),\n ),\n [apiBaseUrl],\n );\n\n const advance = useCallback(\n async (id: string): Promise<WfExecReply> =>\n jsonOrThrow(\n await fetch(`${apiBaseUrl}/_console/wf/advance`, {\n method: \"POST\",\n credentials: \"include\",\n headers: authHeaders({ \"content-type\": \"application/json\" }),\n body: JSON.stringify({ id }),\n }),\n ),\n [apiBaseUrl],\n );\n\n return useMemo(\n () => ({ listExecutions, getExecution, getStats, getVersions, cancel, advance }),\n [listExecutions, getExecution, getStats, getVersions, cancel, advance],\n );\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["useCallback", "useMemo", "jsonOrThrow", "useCallback", "useMemo"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nbt-dev/components",
3
- "version": "0.0.10",
3
+ "version": "0.1.1",
4
4
  "description": "Reusable React building blocks for NBT-console apps: the CodeMirror NBT editor (+LSP), the entity graph, and the live data table.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/core/index.ts CHANGED
@@ -23,6 +23,17 @@ export type {
23
23
  } from "./use-cartridge-info";
24
24
  export { useGsheetsApi } from "./use-gsheets";
25
25
  export type { GsheetSyncConfig, GsheetSaveInput } from "./use-gsheets";
26
+ export { useWorkflowsApi, isWfTerminal, WF_TERMINAL } from "./use-workflows";
27
+ export type {
28
+ WfStatus,
29
+ WfListItem,
30
+ WfExecution,
31
+ WfEvent,
32
+ WfDetail,
33
+ WfStats,
34
+ WfVersion,
35
+ WfExecReply,
36
+ } from "./use-workflows";
26
37
  export {
27
38
  getDevToolsToken,
28
39
  setDevToolsToken,
@@ -0,0 +1,171 @@
1
+ // Fetchers + hook for the workflow-engine introspection endpoints
2
+ // (/_console/wf*). The read routes are ungated like /_console/metrics; the two
3
+ // mutating ones (cancel/advance) are admin-gated server-side, so every request
4
+ // carries the devtools Bearer token (authHeaders) like the contracts probe.
5
+
6
+ import { useCallback, useMemo } from "react";
7
+ import { useDevToolsConfig } from "./config";
8
+ import { authHeaders } from "./auth";
9
+
10
+ // Terminal statuses a workflow can settle into — used to decide whether to keep
11
+ // polling an open instance and whether Cancel is offered.
12
+ export const WF_TERMINAL = ["COMPLETED", "FAILED", "CANCELLED", "CONTINUED"] as const;
13
+
14
+ export type WfStatus =
15
+ | "RUNNING"
16
+ | "SUSPENDED"
17
+ | "COMPLETED"
18
+ | "FAILED"
19
+ | "CANCELLED"
20
+ | "CONTINUED";
21
+
22
+ // Row from GET /_console/wf — the enriched list (createdAt/updatedAt are unix ms).
23
+ export type WfListItem = {
24
+ id: string;
25
+ status: WfStatus;
26
+ workflowName: string;
27
+ createdAt: number;
28
+ updatedAt: number;
29
+ lane: string;
30
+ deployVersion: number;
31
+ };
32
+
33
+ // The execution record from GET /_console/wf/:id (raw entity field names).
34
+ export type WfExecution = {
35
+ id: string;
36
+ status: WfStatus;
37
+ workflowName: string;
38
+ args?: string;
39
+ result?: string;
40
+ error?: string;
41
+ cursor: number;
42
+ lane?: string;
43
+ deployVersion: number;
44
+ createdAt: number;
45
+ updatedAt: number;
46
+ };
47
+
48
+ // One journal entry. kind ∈ HOST_CALL_INTENT | HOST_CALL_RESULT | SUSPENDED |
49
+ // RESUMED | RETRY | COMPLETED | FAILED | CANCELLED | CONTINUED.
50
+ export type WfEvent = {
51
+ id: string;
52
+ seq: number;
53
+ kind: string;
54
+ capability?: string;
55
+ target?: string;
56
+ op?: string;
57
+ payload?: string;
58
+ };
59
+
60
+ export type WfDetail = { execution: WfExecution; events: WfEvent[] };
61
+
62
+ export type WfStats = {
63
+ writes: number;
64
+ reads: number;
65
+ emails: number;
66
+ fetches: number;
67
+ emits: number;
68
+ retries: number;
69
+ async_inflight: number;
70
+ async_peak: number;
71
+ };
72
+
73
+ export type WfVersion = { version: number; refcount: number; current: boolean };
74
+
75
+ // The exec-reply shape returned by run/signal/advance/cancel.
76
+ export type WfExecReply = {
77
+ id: string;
78
+ outcome: string;
79
+ status: string;
80
+ result?: string;
81
+ error?: string;
82
+ };
83
+
84
+ async function jsonOrThrow(r: Response) {
85
+ const body = await r.json().catch(() => ({}));
86
+ if (!r.ok) throw new Error((body as { error?: string })?.error ?? `HTTP ${r.status}`);
87
+ return body;
88
+ }
89
+
90
+ export function isWfTerminal(status: string): boolean {
91
+ return (WF_TERMINAL as readonly string[]).includes(status);
92
+ }
93
+
94
+ export function useWorkflowsApi() {
95
+ const { apiBaseUrl } = useDevToolsConfig();
96
+
97
+ const listExecutions = useCallback(
98
+ async (): Promise<WfListItem[]> =>
99
+ jsonOrThrow(
100
+ await fetch(`${apiBaseUrl}/_console/wf`, {
101
+ credentials: "include",
102
+ headers: authHeaders(),
103
+ }),
104
+ ),
105
+ [apiBaseUrl],
106
+ );
107
+
108
+ const getExecution = useCallback(
109
+ async (id: string): Promise<WfDetail> =>
110
+ jsonOrThrow(
111
+ await fetch(`${apiBaseUrl}/_console/wf/${encodeURIComponent(id)}`, {
112
+ credentials: "include",
113
+ headers: authHeaders(),
114
+ }),
115
+ ),
116
+ [apiBaseUrl],
117
+ );
118
+
119
+ const getStats = useCallback(
120
+ async (): Promise<WfStats> =>
121
+ jsonOrThrow(
122
+ await fetch(`${apiBaseUrl}/_console/wf/stats`, {
123
+ credentials: "include",
124
+ headers: authHeaders(),
125
+ }),
126
+ ),
127
+ [apiBaseUrl],
128
+ );
129
+
130
+ const getVersions = useCallback(
131
+ async (): Promise<WfVersion[]> =>
132
+ jsonOrThrow(
133
+ await fetch(`${apiBaseUrl}/_console/wf/versions`, {
134
+ credentials: "include",
135
+ headers: authHeaders(),
136
+ }),
137
+ ),
138
+ [apiBaseUrl],
139
+ );
140
+
141
+ const cancel = useCallback(
142
+ async (id: string): Promise<WfExecReply> =>
143
+ jsonOrThrow(
144
+ await fetch(`${apiBaseUrl}/_console/wf/cancel`, {
145
+ method: "POST",
146
+ credentials: "include",
147
+ headers: authHeaders({ "content-type": "application/json" }),
148
+ body: JSON.stringify({ id }),
149
+ }),
150
+ ),
151
+ [apiBaseUrl],
152
+ );
153
+
154
+ const advance = useCallback(
155
+ async (id: string): Promise<WfExecReply> =>
156
+ jsonOrThrow(
157
+ await fetch(`${apiBaseUrl}/_console/wf/advance`, {
158
+ method: "POST",
159
+ credentials: "include",
160
+ headers: authHeaders({ "content-type": "application/json" }),
161
+ body: JSON.stringify({ id }),
162
+ }),
163
+ ),
164
+ [apiBaseUrl],
165
+ );
166
+
167
+ return useMemo(
168
+ () => ({ listExecutions, getExecution, getStats, getVersions, cancel, advance }),
169
+ [listExecutions, getExecution, getStats, getVersions, cancel, advance],
170
+ );
171
+ }
@@ -6,6 +6,8 @@
6
6
 
7
7
  import { EditorView } from "@codemirror/view";
8
8
  import type { Extension } from "@codemirror/state";
9
+ import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
10
+ import { tags as t } from "@lezer/highlight";
9
11
  import {
10
12
  amy,
11
13
  ayuLight,
@@ -48,10 +50,59 @@ const defaultTheme = EditorView.theme(
48
50
  { dark: true },
49
51
  );
50
52
 
53
+ // "Nimbit Dark" — the brand theme, matching the marketing hero's code panel:
54
+ // brand-yellow keywords, pink @-directives, foreground type names, muted-italic
55
+ // comments. Unlike `default` it ships its own HighlightStyle (so syntax colors
56
+ // are branded, not CodeMirror's fallback) and uses fixed colors so it looks the
57
+ // same regardless of the surrounding CSS variables. The NBT StreamLanguage emits
58
+ // standard token names ("keyword"/"typeName"/"meta"/… in nbt-language.ts) which
59
+ // map to these Lezer tags.
60
+ const nimbitDarkChrome = EditorView.theme(
61
+ {
62
+ "&": { backgroundColor: "#0b0b0e", color: "#e4e4e7" },
63
+ ".cm-content": { caretColor: "#facc15" },
64
+ ".cm-cursor, .cm-dropCursor": { borderLeftColor: "#facc15" },
65
+ "&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection":
66
+ { backgroundColor: "rgba(250, 204, 21, 0.18)" },
67
+ ".cm-gutters": {
68
+ backgroundColor: "#0b0b0e",
69
+ color: "#52525b",
70
+ borderRight: "1px solid rgba(255, 255, 255, 0.06)",
71
+ },
72
+ ".cm-activeLine": { backgroundColor: "rgba(250, 204, 21, 0.06)" },
73
+ ".cm-activeLineGutter": { backgroundColor: "rgba(250, 204, 21, 0.06)", color: "#a1a1aa" },
74
+ ".cm-tooltip": {
75
+ backgroundColor: "#18181b",
76
+ color: "#e4e4e7",
77
+ border: "1px solid rgba(255, 255, 255, 0.1)",
78
+ },
79
+ ".cm-tooltip-autocomplete ul li[aria-selected]": {
80
+ backgroundColor: "rgba(250, 204, 21, 0.15)",
81
+ color: "#fafafa",
82
+ },
83
+ },
84
+ { dark: true },
85
+ );
86
+
87
+ const nimbitDarkHighlight = HighlightStyle.define([
88
+ { tag: t.keyword, color: "#facc15", fontWeight: "500" }, // entity, enum, …
89
+ { tag: [t.typeName, t.className, t.tagName], color: "#e5e7eb", fontWeight: "500" }, // types + entity refs
90
+ { tag: [t.propertyName, t.variableName, t.attributeName], color: "#cbd5e1" }, // field names
91
+ { tag: [t.string, t.special(t.string)], color: "#fde047" },
92
+ { tag: [t.number, t.bool, t.atom, t.null], color: "#fbbf24" }, // numbers, true/false
93
+ { tag: [t.meta, t.annotation], color: "#f472b6", fontWeight: "500" }, // @relation, @@index, …
94
+ { tag: t.comment, color: "#71717a", fontStyle: "italic" },
95
+ { tag: [t.operator, t.punctuation, t.separator], color: "#a1a1aa" },
96
+ { tag: t.invalid, color: "#f87171" },
97
+ ]);
98
+
99
+ const nimbitDark: Extension = [nimbitDarkChrome, syntaxHighlighting(nimbitDarkHighlight)];
100
+
51
101
  export type EditorTheme = { id: string; label: string; extension: Extension };
52
102
 
53
103
  export const EDITOR_THEMES: EditorTheme[] = [
54
104
  { id: "default", label: "Default (panel)", extension: defaultTheme },
105
+ { id: "nimbitDark", label: "Nimbit Dark", extension: nimbitDark },
55
106
  { id: "dracula", label: "Dracula", extension: dracula },
56
107
  { id: "tomorrow", label: "Tomorrow", extension: tomorrow },
57
108
  { id: "cobalt", label: "Cobalt", extension: cobalt },
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/editor/nbt-editor.tsx", "../src/editor/nbt-language.ts", "../src/editor/editor-themes.ts", "../src/editor/lsp-extensions.ts", "../src/editor/lsp-client.ts"],
4
- "sourcesContent": ["// CodeMirror 6 React wrapper for one NBT buffer. Recreated per uri (keyed by\n// the host); owns the EditorView lifecycle, Ctrl+S save, and the LSP wiring.\n// Theme / font size / line-wrap / tab size are live-tunable via compartments so\n// changing a setting doesn't blow away cursor + scroll.\n\nimport React from \"react\";\nimport { Compartment, EditorState, Prec } from \"@codemirror/state\";\nimport {\n EditorView,\n keymap,\n lineNumbers,\n drawSelection,\n highlightActiveLine,\n} from \"@codemirror/view\";\nimport {\n defaultKeymap,\n history,\n historyKeymap,\n indentWithTab,\n} from \"@codemirror/commands\";\nimport {\n syntaxHighlighting,\n defaultHighlightStyle,\n bracketMatching,\n indentUnit,\n} from \"@codemirror/language\";\nimport { lintGutter } from \"@codemirror/lint\";\nimport { searchKeymap } from \"@codemirror/search\";\nimport { completionKeymap, closeBrackets } from \"@codemirror/autocomplete\";\nimport { nbtLanguageSupport } from \"./nbt-language\";\nimport { themeExtension } from \"./editor-themes\";\nimport { lspExtensions, type GotoDefHandler } from \"./lsp-extensions\";\nimport { NbtLspClient } from \"./lsp-client\";\n\n// Sizing only \u2014 the selected color theme owns the rest. Built per font-size so\n// the theme compartment can carry both.\nfunction sizingTheme(fontSize: number) {\n return EditorView.theme({\n \"&\": { height: \"100%\", fontSize: `${fontSize}px` },\n \".cm-content\": { fontFamily: \"ui-monospace, monospace\" },\n \"&.cm-focused\": { outline: \"none\" },\n });\n}\n\n// `Prec.high` so this wins the indentUnit/tabSize facets over the\n// `indentUnit.of(\" \")` baked into nbtLanguageSupport().\nfunction indentConfig(tabSize: number) {\n return Prec.high([\n indentUnit.of(\" \".repeat(tabSize)),\n EditorState.tabSize.of(tabSize),\n ]);\n}\n\nexport type NbtEditorProps = {\n uri: string;\n value: string;\n readOnly?: boolean;\n lsp?: NbtLspClient | null;\n onChange?: (text: string) => void;\n onSave?: (text: string) => void;\n onGotoDefinition?: GotoDefHandler;\n theme?: string;\n fontSize?: number;\n lineWrap?: boolean;\n tabSize?: number;\n};\n\nexport const NbtEditor: React.FC<NbtEditorProps> = ({\n uri,\n value,\n readOnly = false,\n lsp,\n onChange,\n onSave,\n onGotoDefinition,\n theme = \"default\",\n fontSize = 12,\n lineWrap = false,\n tabSize = 2,\n}) => {\n const hostRef = React.useRef<HTMLDivElement | null>(null);\n const viewRef = React.useRef<EditorView | null>(null);\n\n // Latest callbacks without recreating the view.\n const onChangeRef = React.useRef(onChange);\n onChangeRef.current = onChange;\n const onSaveRef = React.useRef(onSave);\n onSaveRef.current = onSave;\n const onGotoRef = React.useRef(onGotoDefinition);\n onGotoRef.current = onGotoDefinition;\n\n // Live-tunable settings live in compartments. Keep the latest values in a ref\n // so a view rebuild (new uri/mode) seeds the right config without listing the\n // settings in the create-effect deps.\n const themeComp = React.useRef(new Compartment());\n const wrapComp = React.useRef(new Compartment());\n const indentComp = React.useRef(new Compartment());\n const settingsRef = React.useRef({ theme, fontSize, lineWrap, tabSize });\n settingsRef.current = { theme, fontSize, lineWrap, tabSize };\n\n React.useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n\n const s = settingsRef.current;\n const extensions = [\n lineNumbers(),\n history(),\n drawSelection(),\n highlightActiveLine(),\n bracketMatching(),\n closeBrackets(),\n lintGutter(),\n syntaxHighlighting(defaultHighlightStyle, { fallback: true }),\n nbtLanguageSupport(),\n indentComp.current.of(indentConfig(s.tabSize)),\n themeComp.current.of([sizingTheme(s.fontSize), themeExtension(s.theme)]),\n wrapComp.current.of(s.lineWrap ? EditorView.lineWrapping : []),\n keymap.of([\n {\n key: \"Mod-s\",\n run: (view) => {\n onSaveRef.current?.(view.state.doc.toString());\n return true;\n },\n },\n ...defaultKeymap,\n ...historyKeymap,\n ...searchKeymap,\n ...completionKeymap,\n indentWithTab,\n ]),\n EditorView.updateListener.of((u) => {\n if (u.docChanged) onChangeRef.current?.(u.state.doc.toString());\n }),\n EditorState.readOnly.of(readOnly),\n ];\n if (lsp && !readOnly) {\n extensions.push(\n lspExtensions(lsp, uri, (defUri, line) => onGotoRef.current?.(defUri, line)),\n );\n }\n\n const view = new EditorView({\n state: EditorState.create({ doc: value, extensions }),\n parent: host,\n });\n viewRef.current = view;\n return () => {\n view.destroy();\n viewRef.current = null;\n };\n // Recreate per buffer identity / mode; `value` is only the initial doc.\n // Settings changes are handled by the reconfigure effect below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [uri, readOnly, lsp]);\n\n // Retune the live view when a setting changes \u2014 no destroy, so cursor/scroll\n // survive.\n React.useEffect(() => {\n const view = viewRef.current;\n if (!view) return;\n view.dispatch({\n effects: [\n themeComp.current.reconfigure([\n sizingTheme(fontSize),\n themeExtension(theme),\n ]),\n wrapComp.current.reconfigure(lineWrap ? EditorView.lineWrapping : []),\n indentComp.current.reconfigure(indentConfig(tabSize)),\n ],\n });\n }, [theme, fontSize, lineWrap, tabSize]);\n\n return <div ref={hostRef} className=\"h-full min-h-0 overflow-hidden\" />;\n};\n", "// NBT syntax highlighting for CodeMirror 6 \u2014 a StreamLanguage tokenizer ported\n// from the console tokenizer (modules/lang_common/scan.jai) and the VSCode\n// grammar (editors/vscode/nbt/syntaxes/nbt.tmLanguage.json). Highlighting is\n// local; everything semantic (diagnostics/completion/hover) comes via the LSP.\n\nimport {\n StreamLanguage,\n LanguageSupport,\n indentUnit,\n type StreamParser,\n} from \"@codemirror/language\";\n\nconst KEYWORDS = new Set([\n \"entity\", \"enum\", \"struct\", \"const\", \"export\", \"extends\",\n \"fn\", \"on\", \"action\", \"activity\", \"task\", \"variant\", \"workflow\", \"command\",\n \"middleware\", \"schedule\", \"every\", \"jai\",\n \"migration\", \"test\", \"mock\", \"assert\",\n \"cartridge\", \"service\", \"component\", \"app\", \"route\", \"layout\",\n \"import\", \"from\",\n \"if\", \"elif\", \"else\", \"while\", \"for\", \"in\", \"return\", \"break\", \"continue\",\n \"delete\", \"defer\", \"print\", \"sleep\", \"fail\",\n]);\n\nconst TYPES = new Set([\n \"string\", \"bool\", \"ulid\", \"document\", \"dict\", \"blob\", \"DateTime\",\n \"u8\", \"u16\", \"u32\", \"u64\", \"s8\", \"s16\", \"s32\", \"s64\",\n \"int\", \"integer\", \"float\", \"float64\", \"f32\", \"f64\", \"double\",\n \"time\", \"bytes\", \"any\", \"name\", \"ref\",\n]);\n\ntype NbtState = {\n tripleString: boolean;\n};\n\n// NBT strings carry NO escapes (scan.jai consumes to the bare closing quote),\n// so a backslash before a quote does not extend the string.\nfunction eatSingleLineString(stream: StringStream, quote: string): string {\n while (!stream.eol()) {\n if (stream.next() === quote) break;\n }\n return \"string\";\n}\n\ntype StringStream = Parameters<StreamParser<NbtState>[\"token\"]>[0];\n\nconst nbtParser: StreamParser<NbtState> = {\n name: \"nbt\",\n startState: () => ({ tripleString: false }),\n token(stream, state) {\n if (state.tripleString) {\n while (!stream.eol()) {\n if (stream.match('\"\"\"')) {\n state.tripleString = false;\n return \"string\";\n }\n stream.next();\n }\n return \"string\";\n }\n\n if (stream.eatSpace()) return null;\n\n const ch = stream.peek();\n if (ch == null) return null;\n\n if (ch === \"#\") {\n stream.skipToEnd();\n return \"comment\";\n }\n\n if (stream.match('\"\"\"')) {\n state.tripleString = true;\n // Rest of line is string body unless it closes on the same line.\n while (!stream.eol()) {\n if (stream.match('\"\"\"')) {\n state.tripleString = false;\n return \"string\";\n }\n stream.next();\n }\n return \"string\";\n }\n\n if (ch === '\"') {\n stream.next();\n return eatSingleLineString(stream, '\"');\n }\n if (ch === \"'\") {\n // Like the scanner: only a string opener when not glued to an identifier\n // (lets contractions inside docs pass).\n const before = stream.string.charAt(stream.pos - 1);\n if (!/[A-Za-z0-9_]/.test(before)) {\n stream.next();\n return eatSingleLineString(stream, \"'\");\n }\n stream.next();\n return null;\n }\n\n // f-strings: f\"...\" \u2014 body highlighted as a string (interpolation holes\n // are cosmetic only).\n if (ch === \"f\" && stream.string.charAt(stream.pos + 1) === '\"') {\n stream.next();\n stream.next();\n return eatSingleLineString(stream, '\"');\n }\n\n // @attr / @@attr\n if (ch === \"@\") {\n stream.next();\n stream.eat(\"@\");\n stream.eatWhile(/[A-Za-z0-9_]/);\n return \"meta\";\n }\n\n // Numbers. The optional fraction backtracks on `0..9` ranges (matches \"0\",\n // not \"0.\").\n if (/\\d/.test(ch)) {\n stream.match(/^\\d+(\\.\\d+)?/);\n return \"number\";\n }\n\n if (/[A-Za-z_]/.test(ch)) {\n stream.eatWhile(/[A-Za-z0-9_]/);\n const word = stream.current();\n if (word === \"true\" || word === \"false\") return \"atom\";\n if (KEYWORDS.has(word)) return \"keyword\";\n if (TYPES.has(word)) return \"typeName\";\n if (/^[A-Z]/.test(word)) return \"typeName\"; // entity/enum references\n return \"variableName\";\n }\n\n if (/[+\\-*/=<>!&|?.,:;]/.test(ch)) {\n stream.next();\n stream.eatWhile(/[+\\-*/=<>!&|.]/);\n return \"operator\";\n }\n\n stream.next();\n return null;\n },\n languageData: {\n commentTokens: { line: \"#\" },\n },\n};\n\nexport const nbtLanguage = StreamLanguage.define(nbtParser);\n\nexport function nbtLanguageSupport(): LanguageSupport {\n return new LanguageSupport(nbtLanguage, [indentUnit.of(\" \")]);\n}\n", "// Preloaded CodeMirror color themes for the NBT editor. \"default\" matches the\n// devtools panel chrome via its CSS variables (the editor renders inside the\n// .nimbit-devtools subtree, so these resolve to the scoped tokens); the rest\n// come from `thememirror`. Color only \u2014 sizing (font size/family/height) is\n// applied separately by the editor so it can follow the font-size setting.\n\nimport { EditorView } from \"@codemirror/view\";\nimport type { Extension } from \"@codemirror/state\";\nimport {\n amy,\n ayuLight,\n barf,\n bespin,\n birdsOfParadise,\n boysAndGirls,\n clouds,\n cobalt,\n coolGlow,\n dracula,\n espresso,\n noctisLilac,\n rosePineDawn,\n smoothy,\n solarizedLight,\n tomorrow,\n} from \"thememirror\";\n\nconst defaultTheme = EditorView.theme(\n {\n \"&\": {\n backgroundColor: \"var(--background)\",\n color: \"var(--foreground)\",\n },\n \".cm-gutters\": {\n backgroundColor: \"var(--background)\",\n color: \"var(--muted-foreground)\",\n borderRight: \"1px solid var(--border)\",\n },\n \".cm-activeLine\": {\n backgroundColor: \"color-mix(in srgb, var(--accent) 35%, transparent)\",\n },\n \".cm-tooltip\": {\n backgroundColor: \"var(--popover)\",\n color: \"var(--popover-foreground)\",\n border: \"1px solid var(--border)\",\n },\n },\n { dark: true },\n);\n\nexport type EditorTheme = { id: string; label: string; extension: Extension };\n\nexport const EDITOR_THEMES: EditorTheme[] = [\n { id: \"default\", label: \"Default (panel)\", extension: defaultTheme },\n { id: \"dracula\", label: \"Dracula\", extension: dracula },\n { id: \"tomorrow\", label: \"Tomorrow\", extension: tomorrow },\n { id: \"cobalt\", label: \"Cobalt\", extension: cobalt },\n { id: \"espresso\", label: \"Espresso\", extension: espresso },\n { id: \"barf\", label: \"Barf\", extension: barf },\n { id: \"bespin\", label: \"Bespin\", extension: bespin },\n { id: \"birdsOfParadise\", label: \"Birds of Paradise\", extension: birdsOfParadise },\n { id: \"boysAndGirls\", label: \"Boys and Girls\", extension: boysAndGirls },\n { id: \"coolGlow\", label: \"Cool Glow\", extension: coolGlow },\n { id: \"amy\", label: \"Amy\", extension: amy },\n { id: \"ayuLight\", label: \"Ayu Light\", extension: ayuLight },\n { id: \"clouds\", label: \"Clouds\", extension: clouds },\n { id: \"noctisLilac\", label: \"Noctis Lilac\", extension: noctisLilac },\n { id: \"rosePineDawn\", label: \"Ros\u00E9 Pine Dawn\", extension: rosePineDawn },\n { id: \"smoothy\", label: \"Smoothy\", extension: smoothy },\n { id: \"solarizedLight\", label: \"Solarized Light\", extension: solarizedLight },\n];\n\nconst byId = new Map(EDITOR_THEMES.map((t) => [t.id, t.extension]));\n\nexport function themeExtension(id: string): Extension {\n return byId.get(id) ?? EDITOR_THEMES[0].extension;\n}\n", "// CodeMirror extensions wiring an editor buffer to the NbtLspClient:\n// full-text didChange sync (debounced), pushed publishDiagnostics \u2192 lint,\n// completion, hover, and F12 go-to-definition.\n\nimport { type Extension, type Text } from \"@codemirror/state\";\nimport {\n EditorView,\n ViewPlugin,\n type ViewUpdate,\n hoverTooltip,\n keymap,\n} from \"@codemirror/view\";\nimport {\n autocompletion,\n type CompletionContext,\n type CompletionResult,\n} from \"@codemirror/autocomplete\";\nimport { setDiagnostics, type Diagnostic } from \"@codemirror/lint\";\nimport {\n NbtLspClient,\n type LspDiagnostic,\n type LspPosition,\n type LspCompletionItem,\n type LspLocation,\n} from \"./lsp-client\";\n\nfunction toLspPos(doc: Text, offset: number): LspPosition {\n const line = doc.lineAt(offset);\n return { line: line.number - 1, character: offset - line.from };\n}\n\nfunction fromLspPos(doc: Text, pos: LspPosition): number {\n const lineNo = Math.min(Math.max(pos.line + 1, 1), doc.lines);\n const line = doc.line(lineNo);\n return Math.min(line.from + Math.max(pos.character, 0), line.to);\n}\n\nfunction toCmDiagnostics(doc: Text, diags: LspDiagnostic[]): Diagnostic[] {\n return diags.map((d) => {\n const from = fromLspPos(doc, d.range.start);\n let to = fromLspPos(doc, d.range.end);\n if (to <= from) to = Math.min(from + 1, doc.length);\n const severity =\n d.severity === 2 ? \"warning\" : d.severity === 3 || d.severity === 4 ? \"info\" : \"error\";\n return { from, to, severity, message: d.message, source: d.source ?? \"nbt\" };\n });\n}\n\n// LSP CompletionItemKind \u2192 CM completion type (drives the icon).\nfunction completionType(kind?: number): string {\n switch (kind) {\n case 3: return \"function\";\n case 5: return \"property\";\n case 13: return \"enum\";\n case 14: return \"keyword\";\n case 22: return \"class\";\n default: return \"variable\";\n }\n}\n\nexport type GotoDefHandler = (uri: string, line: number) => void;\n\nexport function lspExtensions(\n client: NbtLspClient,\n uri: string,\n onGotoDefinition?: GotoDefHandler,\n): Extension[] {\n // Sync + diagnostics plugin. didOpen on create, debounced didChange,\n // diagnostics pushed by the server are dispatched into the lint state.\n const syncPlugin = ViewPlugin.fromClass(\n class {\n private timer: ReturnType<typeof setTimeout> | null = null;\n private unsubscribe: () => void;\n\n constructor(readonly view: EditorView) {\n client.didOpen(uri, view.state.doc.toString());\n this.unsubscribe = client.onDiagnostics(uri, (diags) => {\n const cm = toCmDiagnostics(this.view.state.doc, diags);\n this.view.dispatch(setDiagnostics(this.view.state, cm));\n });\n }\n\n update(u: ViewUpdate) {\n if (!u.docChanged) return;\n if (this.timer) clearTimeout(this.timer);\n this.timer = setTimeout(() => {\n this.timer = null;\n client.didChange(uri, this.view.state.doc.toString());\n }, 200);\n }\n\n destroy() {\n if (this.timer) {\n clearTimeout(this.timer);\n client.didChange(uri, this.view.state.doc.toString());\n }\n this.unsubscribe();\n }\n },\n );\n\n const completionSource = async (\n ctx: CompletionContext,\n ): Promise<CompletionResult | null> => {\n const word = ctx.matchBefore(/\\w*/);\n if (!word) return null;\n if (word.from === word.to && !ctx.explicit) {\n // Only fire automatically right after a trigger character.\n const before = ctx.state.doc.sliceString(Math.max(0, ctx.pos - 1), ctx.pos);\n if (before !== \".\" && before !== \":\" && before !== '\"') return null;\n }\n // Flush any pending edit so the server completes against the live buffer.\n client.didChange(uri, ctx.state.doc.toString());\n let result;\n try {\n result = await client.completion(uri, toLspPos(ctx.state.doc, ctx.pos));\n } catch {\n return null;\n }\n const items: LspCompletionItem[] = Array.isArray(result)\n ? result\n : (result?.items ?? []);\n if (items.length === 0) return null;\n return {\n from: word.from,\n options: items.map((it) => ({\n label: it.label,\n type: completionType(it.kind),\n detail: it.detail,\n })),\n };\n };\n\n const hover = hoverTooltip(async (view, pos) => {\n let result;\n try {\n result = await client.hover(uri, toLspPos(view.state.doc, pos));\n } catch {\n return null;\n }\n const value = result?.contents?.value;\n if (!value) return null;\n return {\n pos,\n create: () => {\n const dom = document.createElement(\"pre\");\n dom.className = \"nbt-hover-tooltip\";\n dom.style.cssText =\n \"margin:0;padding:6px 8px;max-width:480px;white-space:pre-wrap;font-size:11px;\";\n // Server emits fenced markdown code blocks; strip the fences, show text.\n dom.textContent = value.replace(/```\\w*\\n?/g, \"\");\n return { dom };\n },\n };\n });\n\n const gotoDef = keymap.of([\n {\n key: \"F12\",\n run: (view) => {\n const pos = toLspPos(view.state.doc, view.state.selection.main.head);\n client\n .definition(uri, pos)\n .then((result) => {\n const loc: LspLocation | null = Array.isArray(result)\n ? (result[0] ?? null)\n : result;\n if (!loc?.uri) return;\n if (loc.uri === uri) {\n const off = fromLspPos(view.state.doc, loc.range.start);\n view.dispatch({\n selection: { anchor: off },\n scrollIntoView: true,\n });\n } else {\n onGotoDefinition?.(loc.uri, loc.range.start.line);\n }\n })\n .catch(() => {});\n return true;\n },\n },\n ]);\n\n return [\n syncPlugin,\n autocompletion({ override: [completionSource] }),\n hover,\n gotoDef,\n ];\n}\n", "// Minimal LSP client over WebSocket for the console's dev-mode nbt_lsp bridge\n// (/_console/dev/lsp). One JSON-RPC message per WS text frame \u2014 no\n// Content-Length framing (the bridge's write_proc emits bare JSON).\n//\n// Hand-rolled on purpose: the server speaks ~10 methods with full-text sync,\n// and a library client (codemirror-languageserver) would drag transitive\n// runtime deps into every host app.\n\nexport type LspPosition = { line: number; character: number };\nexport type LspRange = { start: LspPosition; end: LspPosition };\nexport type LspDiagnostic = {\n range: LspRange;\n severity?: number; // 1=error 2=warning 3=info 4=hint\n message: string;\n source?: string;\n};\nexport type LspCompletionItem = {\n label: string;\n kind?: number;\n detail?: string;\n};\nexport type LspLocation = { uri: string; range: LspRange };\n\ntype Pending = {\n resolve: (v: unknown) => void;\n reject: (e: Error) => void;\n};\n\nexport class NbtLspClient {\n private url: string;\n private rootUri: string | null = null;\n private ws: WebSocket | null = null;\n private nextId = 1;\n private pending = new Map<number, Pending>();\n private diagHandlers = new Map<string, (d: LspDiagnostic[]) => void>();\n // Open buffers, kept for replay across reconnects.\n private docs = new Map<string, { text: string; version: number }>();\n private ready = false;\n private queue: string[] = [];\n private closed = false;\n private retryMs = 500;\n\n constructor(url: string) {\n this.url = url;\n this.connect();\n }\n\n dispose() {\n this.closed = true;\n this.ws?.close();\n this.pending.forEach((p) => p.reject(new Error(\"lsp client disposed\")));\n this.pending.clear();\n }\n\n private connect() {\n if (this.closed) return;\n const ws = new WebSocket(this.url);\n this.ws = ws;\n ws.onopen = () => {\n this.retryMs = 500;\n if (this.rootUri) this.sendInitialize(this.rootUri);\n };\n ws.onmessage = (ev) => {\n if (typeof ev.data !== \"string\") return;\n this.onMessage(ev.data);\n };\n ws.onclose = () => {\n this.ready = false;\n this.ws = null;\n for (const p of this.pending.values())\n p.reject(new Error(\"lsp connection closed\"));\n this.pending.clear();\n if (!this.closed) {\n setTimeout(() => this.connect(), this.retryMs);\n this.retryMs = Math.min(this.retryMs * 2, 10_000);\n }\n };\n }\n\n // Called once by the host with file://<projectRoot>; also re-sent after every\n // reconnect, followed by didOpen replays for tracked buffers.\n initialize(rootUri: string) {\n this.rootUri = rootUri;\n if (this.ws?.readyState === WebSocket.OPEN) this.sendInitialize(rootUri);\n }\n\n private sendInitialize(rootUri: string) {\n const id = this.nextId++;\n this.pending.set(id, {\n resolve: () => {\n this.sendRaw({ jsonrpc: \"2.0\", method: \"initialized\", params: {} });\n this.ready = true;\n for (const [uri, d] of this.docs) {\n this.sendRaw({\n jsonrpc: \"2.0\",\n method: \"textDocument/didOpen\",\n params: {\n textDocument: {\n uri,\n languageId: \"nbt\",\n version: d.version,\n text: d.text,\n },\n },\n });\n }\n const q = this.queue;\n this.queue = [];\n for (const m of q) this.ws?.send(m);\n },\n reject: () => {},\n });\n this.ws?.send(\n JSON.stringify({\n jsonrpc: \"2.0\",\n id,\n method: \"initialize\",\n params: { rootUri },\n }),\n );\n }\n\n private sendRaw(msg: object) {\n const s = JSON.stringify(msg);\n if (this.ready && this.ws?.readyState === WebSocket.OPEN) this.ws.send(s);\n else this.queue.push(s);\n }\n\n private onMessage(data: string) {\n let msg: any;\n try {\n msg = JSON.parse(data);\n } catch {\n return;\n }\n if (msg.id != null && (msg.result !== undefined || msg.error)) {\n const p = this.pending.get(msg.id);\n if (!p) return;\n this.pending.delete(msg.id);\n if (msg.error) p.reject(new Error(msg.error.message ?? \"lsp error\"));\n else p.resolve(msg.result);\n return;\n }\n if (msg.method === \"textDocument/publishDiagnostics\") {\n const uri = msg.params?.uri as string;\n const handler = this.diagHandlers.get(uri);\n if (handler) handler((msg.params?.diagnostics ?? []) as LspDiagnostic[]);\n }\n }\n\n request<T>(method: string, params: object): Promise<T> {\n const id = this.nextId++;\n const p = new Promise<T>((resolve, reject) => {\n this.pending.set(id, { resolve: resolve as Pending[\"resolve\"], reject });\n });\n this.sendRaw({ jsonrpc: \"2.0\", id, method, params });\n return p;\n }\n\n onDiagnostics(uri: string, handler: (d: LspDiagnostic[]) => void): () => void {\n this.diagHandlers.set(uri, handler);\n return () => {\n if (this.diagHandlers.get(uri) === handler) this.diagHandlers.delete(uri);\n };\n }\n\n didOpen(uri: string, text: string) {\n const existing = this.docs.get(uri);\n if (existing) {\n // Re-opening an already-tracked buffer (tab switch) \u2014 just resync.\n this.didChange(uri, text);\n return;\n }\n this.docs.set(uri, { text, version: 1 });\n this.sendRaw({\n jsonrpc: \"2.0\",\n method: \"textDocument/didOpen\",\n params: { textDocument: { uri, languageId: \"nbt\", version: 1, text } },\n });\n }\n\n didChange(uri: string, text: string) {\n const d = this.docs.get(uri);\n if (!d) return this.didOpen(uri, text);\n if (d.text === text) return;\n d.text = text;\n d.version += 1;\n this.sendRaw({\n jsonrpc: \"2.0\",\n method: \"textDocument/didChange\",\n params: {\n textDocument: { uri, version: d.version },\n contentChanges: [{ text }],\n },\n });\n }\n\n didClose(uri: string) {\n if (!this.docs.delete(uri)) return;\n this.sendRaw({\n jsonrpc: \"2.0\",\n method: \"textDocument/didClose\",\n params: { textDocument: { uri } },\n });\n }\n\n completion(uri: string, pos: LspPosition): Promise<{ items: LspCompletionItem[] } | LspCompletionItem[] | null> {\n return this.request(\"textDocument/completion\", {\n textDocument: { uri },\n position: pos,\n });\n }\n\n hover(uri: string, pos: LspPosition): Promise<{ contents?: { value?: string } } | null> {\n return this.request(\"textDocument/hover\", {\n textDocument: { uri },\n position: pos,\n });\n }\n\n definition(uri: string, pos: LspPosition): Promise<LspLocation | LspLocation[] | null> {\n return this.request(\"textDocument/definition\", {\n textDocument: { uri },\n position: pos,\n });\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["EditorView", "keymap", "indentUnit", "EditorView", "indentUnit", "keymap", "view"]
7
- }