Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"dependencies": {
"@dimaka/interface": "0.0.3-alpha.0",
"@floating-ui/react": "^0.26.1",
"@monaco-editor/react": "^4.7.0",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Missing peer dependency: add "monaco-editor" and verify worker bundling with Rsbuild.

@monaco-editor/react requires monaco-editor as a peer. It's not present in dependencies, which will likely break build/runtime or force a fallback you don't want. Also, Monaco needs its web workers bundled/configured for languages to work under Rsbuild/Rspack.

Apply this diff to add monaco-editor (pin to the peer range of your installed @monaco-editor/react):

   "@floating-ui/react": "^0.26.1",
+  "monaco-editor": "^0.52.0",
   "@monaco-editor/react": "^4.7.0",

Follow-ups:

  • Verify the exact peer range by checking @monaco-editor/react’s peerDependencies and adjust the version accordingly.
  • Confirm worker bundling works in your setup (ts.worker.js, editor.worker.js, etc.). If workers don’t load, consider configuring Rspack worker rules or adding a Monaco plugin compatible with Rsbuild/Rspack, or set MonacoEnvironment.getWorker to custom URLs.

🏁 Script executed:

#!/bin/bash
# Verify if monaco-editor is declared in package.json
grep -R "\"monaco-editor\"" -n package.json || echo "monaco-editor not found in package.json"

# Show the context around the @monaco-editor/react entry
grep -R -n -C2 "\"@monaco-editor/react\"" package.json

Length of output: 411


🌐 Web query:

What are the peerDependencies of @monaco-editor/[email protected]?

💡 Result:

The peerDependencies for @monaco-editor/[email protected] are:

If you want, I can show the package.json / package-lock excerpt that contains these entries.

Citations:


Add the missing monaco-editor dependency and verify worker bundling

Your project is currently missing the monaco-editor package, which is a required peer for @monaco-editor/[email protected] (it declares

"peerDependencies": {
  "monaco-editor": ">=0.25.0 <1",
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
  "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}

) . Omitting it will lead to runtime errors or unintended fallbacks.

Please update your package.json like so:

  "@floating-ui/react": "^0.26.1",
+ "monaco-editor": "^0.52.0",    // satisfies >=0.25.0 <1
  "@monaco-editor/react": "^4.7.0",

Then:

  • Double-check the exact peer range in your lockfile or node_modules/@monaco-editor/react/package.json and adjust "monaco-editor"’s version if needed (any 0.x ≥ 0.25 will do).
  • Verify that Monaco’s web workers load correctly under your Rsbuild/Rspack setup. If they fail to bundle (e.g., ts.worker.js, editor.worker.js), you’ll need to configure worker rules or use a plugin/override (MonacoEnvironment.getWorkerUrl) to point to the proper URLs.

"@nxg-org/mineflayer-auto-jump": "^0.7.18",
"@nxg-org/mineflayer-tracker": "1.3.0",
"@react-oauth/google": "^0.12.1",
Expand Down
58 changes: 44 additions & 14 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

106 changes: 106 additions & 0 deletions src/core/ideChannels.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { proxy } from 'valtio'

export const ideState = proxy({
id: '',
contents: '',
line: 0,
column: 0,
language: 'typescript',
title: '',
})
globalThis.ideState = ideState

Comment on lines +3 to +12
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Type error risk: globalThis augmentation missing for ideState.

Assigning globalThis.ideState without a global augmentation will fail type-checking in TS (“Property 'ideState' does not exist on type 'typeof globalThis'”).

Apply this diff to add a typed state shape and a safe global augmentation:

-import { proxy } from 'valtio'
+import { proxy } from 'valtio'
+
+type IdeState = {
+  id: string
+  contents: string
+  line: number   // note: Monaco uses 1-based positions; see comment below
+  column: number // note: Monaco uses 1-based positions; see comment below
+  language: string
+  title: string
+}
 
-export const ideState = proxy({
+export const ideState = proxy<IdeState>({
   id: '',
   contents: '',
   line: 0,
   column: 0,
   language: 'typescript',
   title: '',
 })
-globalThis.ideState = ideState
+declare global {
+  // eslint-disable-next-line no-var
+  var ideState: typeof ideState
+}
+globalThis.ideState = ideState
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const ideState = proxy({
id: '',
contents: '',
line: 0,
column: 0,
language: 'typescript',
title: '',
})
globalThis.ideState = ideState
import { proxy } from 'valtio'
type IdeState = {
id: string
contents: string
line: number // note: Monaco uses 1-based positions; see comment below
column: number // note: Monaco uses 1-based positions; see comment below
language: string
title: string
}
export const ideState = proxy<IdeState>({
id: '',
contents: '',
line: 0,
column: 0,
language: 'typescript',
title: '',
})
declare global {
// eslint-disable-next-line no-var
var ideState: typeof ideState
}
globalThis.ideState = ideState
🤖 Prompt for AI Agents
In src/core/ideChannels.ts around lines 3 to 12, TypeScript will error because
globalThis is not augmented for ideState; add a typed shape and a safe global
augmentation: define an interface/type for the IDE state (fields id, contents,
line, column, language, title), type the proxy return value accordingly, declare
a global augmentation (declare global { var ideState?: IDEStateType }) so the
compiler knows about globalThis.ideState, and then assign to globalThis.ideState
= ideState (or use conditional assignment globalThis.ideState ||= ideState)
without casting to any.

export const registerIdeChannels = () => {
registerIdeOpenChannel()
registerIdeSaveChannel()
}

const registerIdeOpenChannel = () => {
const CHANNEL_NAME = 'minecraft-web-client:ide-open'

const packetStructure = [
'container',
[
{
name: 'id',
type: ['pstring', { countType: 'i16' }]
},
{
name: 'language',
type: ['pstring', { countType: 'i16' }]
},
{
name: 'contents',
type: ['pstring', { countType: 'i16' }]
},
{
name: 'line',
type: 'i32'
},
{
name: 'column',
type: 'i32'
},
{
name: 'title',
type: ['pstring', { countType: 'i16' }]
}
]
]

bot._client.registerChannel(CHANNEL_NAME, packetStructure, true)

bot._client.on(CHANNEL_NAME as any, (data) => {
const { id, language, contents, line, column, title } = data

ideState.contents = contents
ideState.line = line
ideState.column = column
ideState.id = id
ideState.language = language || 'typescript'
ideState.title = title
})

console.debug(`registered custom channel ${CHANNEL_NAME} channel`)
}
const IDE_SAVE_CHANNEL_NAME = 'minecraft-web-client:ide-save'
const registerIdeSaveChannel = () => {

const packetStructure = [
'container',
[
{
name: 'id',
type: ['pstring', { countType: 'i16' }]
},
{
name: 'contents',
type: ['pstring', { countType: 'i16' }]
},
{
name: 'language',
type: ['pstring', { countType: 'i16' }]
},
{
name: 'line',
type: 'i32'
},
{
name: 'column',
type: 'i32'
},
]
]
bot._client.registerChannel(IDE_SAVE_CHANNEL_NAME, packetStructure, true)
}

export const saveIde = () => {
bot._client.writeChannel(IDE_SAVE_CHANNEL_NAME, {
id: ideState.id,
contents: ideState.contents,
language: ideState.language,
// todo: reflect updated
line: ideState.line,
column: ideState.column,
})
}
Comment on lines +97 to +106
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Harden saveIde against disconnects and sync cursor position.

  • writeChannel will throw if _client is not connected (e.g., user disconnects while modal open).
  • Comment notes line/column aren’t updated; Monaco uses 1-based positions, so ensure you convert and keep them in sync before saving.
-export const saveIde = () => {
-  bot._client.writeChannel(IDE_SAVE_CHANNEL_NAME, {
+export const saveIde = () => {
+  // Guard against disconnects
+  // @ts-expect-error: internal client state
+  if (!bot?._client || bot?._client?.ended) return
+  bot._client.writeChannel(IDE_SAVE_CHANNEL_NAME, {
     id: ideState.id,
     contents: ideState.contents,
     language: ideState.language,
-    // todo: reflect updated
-    line: ideState.line,
-    column: ideState.column,
+    // NOTE: keep these updated from the editor and convert to 1-based if needed.
+    line: ideState.line,
+    column: ideState.column,
   })
}

Follow-ups:

  • Wire editor cursor/selection changes to ideState.line/column and normalize to 1-based before saving.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const saveIde = () => {
bot._client.writeChannel(IDE_SAVE_CHANNEL_NAME, {
id: ideState.id,
contents: ideState.contents,
language: ideState.language,
// todo: reflect updated
line: ideState.line,
column: ideState.column,
})
}
export const saveIde = () => {
// Guard against disconnects
// @ts-expect-error: internal client state
if (!bot?._client || bot?._client?.ended) return
bot._client.writeChannel(IDE_SAVE_CHANNEL_NAME, {
id: ideState.id,
contents: ideState.contents,
language: ideState.language,
// NOTE: keep these updated from the editor and convert to 1-based if needed.
line: ideState.line,
column: ideState.column,
})
}

2 changes: 2 additions & 0 deletions src/customChannels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import PItem from 'prismarine-item'
import { getThreeJsRendererMethods } from 'renderer/viewer/three/threeJsMethods'
import { options } from './optionsStorage'
import { jeiCustomCategories } from './inventoryWindows'
import { registerIdeChannels } from './core/ideChannels'

export default () => {
customEvents.on('mineflayerBotCreated', async () => {
Expand All @@ -17,6 +18,7 @@ export default () => {
registeredJeiChannel()
registerBlockInteractionsCustomizationChannel()
registerWaypointChannels()
registerIdeChannels()
})
}

Expand Down
58 changes: 58 additions & 0 deletions src/react/MonacoEditor.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.monaco-editor-container {
position: fixed;
inset: 0;
z-index: 1000;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 16px;
background-color: rgba(0, 0, 0, 0.5);
}

.monaco-editor-title {
font-size: 20px;
font-weight: bold;
color: #fff;
margin-bottom: 8px;
}

.monaco-editor-wrapper {
position: relative;
width: 100%;
height: 100%;
max-width: 80vw;
max-height: 80vh;
border: 3px solid #000;
background-color: #000;
padding: 3px;
box-shadow: inset 0 0 0 1px #fff, inset 0 0 0 2px #000;
}

.monaco-editor-close {
position: fixed;
top: 16px;
left: 16px;
z-index: 1001;
cursor: pointer;
padding: 8px;
}

@media (max-width: 768px) {
.monaco-editor-container {
padding: 0;
}
.monaco-editor-wrapper {
max-width: 100%;
max-height: 100%;
border-radius: 0;
}
.monaco-editor-close {
top: 8px;
left: 8px;
}
.monaco-editor-title {
/* todo: make it work on mobile */
display: none;
}
}
Loading
Loading