Repository navigation
Conversation
ControllerService hardcoded SdlKeyMappingDefaults.Create() and never read keymapping.json, so edits in the key-mapping window never took effect. The runtime now resolves the effective config through an in-memory KeyMappingStore (legacy WinForms-VK files fall back to SDL defaults) and hot-reloads the active binder on save. Also unifies the duplicated SDL scancode tables into SdlScancodeMap (fixes digits/F-keys/numpad being dropped on the virtual-pad overlay path) and swaps the key map atomically to avoid a data race with the SDL event thread.
…ion pattern Make IConnection public and add a protected virtual NintendoSwitch.CreateConnection seam so tests can inject a fake connection. New EasyCon.SDLInput.Tests drives the real SdlKeyboardInputBinder.HandleKeyEvent path and asserts the HID packet dequeued to the fake serial port: default/numpad/stick mappings, unbound/disabled/Esc cases, golden bytes, plus config cache and legacy-fallback resolution. The pattern is documented in AGENTS.md for reuse by other modules.
The key-mapping mockup is working reference material, not a shipped asset. Move docs/design to a local .design folder and ignore it so it cannot be committed by accident.
Avalonia.Headless renders the mapping window off-screen so its layout and pixels can be asserted in tests, and Svg.Controls.Skia.Avalonia draws the controller asset. Versions are declared in Directory.Packages.props per central package management.
The mapping canvas needs over a hundred keycap and button glyphs. Keeping them as individual XAML resources does not scale, so the path data now lives in Resources/Icons.json and a small IconView control draws it, scaling a 64x64 design canvas into its bounds and caching parsed geometry. This replaces the previous per-icon SVG resource folder with a single embedded asset.
ThemeManager now publishes the Mapping colour and brush pairs (background, accent, title, muted, unmapped, highlight, conflict) so the canvas follows the active colour scheme. The accent stays one fixed muted steel blue in every scheme, and the conflict red is shared for the same reason: the controller art should read identically regardless of theme.
Esc and Backspace now clear a binding instead of being bound themselves, and OS-reserved keys (Win, Apps, PrintScreen, Pause, CapsLock, NumLock, ScrollLock) are refused. Those either never reach the application or leave the keyboard in a changed global state, so binding them is a trap. The rule is a policy layer on top of the existing map, so FromAvaloniaKey is untouched and existing configs still display correctly.
The controller SVG (34 KB, about 50 symbols) and Icons.json (135 KB) were parsed lazily the first time the key mapping window opened, which showed up as a stall. Both are now warmed once the main window is up: the JSON parse on a background thread, the Skia build on the UI thread after the first frame so startup itself is not slowed. The window reuses one shared SvgSource instead of re-parsing per instance.
…as view model The window moved from a list to a fixed 1440x960 design canvas, so a row is now an observable KeyMappingRow carrying its canvas coordinates plus listening, highlight and conflict state, and the window view model owns the row set, key capture and conflict recomputation. Conflicts are accepted and marked rather than blocked: refusing a duplicate interrupts editing, and the red marker already makes the clash obvious.
Replaces the old list UI with the redesigned canvas: an NS2 controller SVG with live hit testing, leader lines out to 26 keycap and Switch icon pairs, and a legend. Controller groups grey out when unbound and highlight while listening by injecting CSS into the SVG, and conflicting bindings render red on both the keycap and the Switch icon. A smoke test guards that the controller asset still parses and renders. Also pins the status bar to a minimum height: it sat in an Auto row, so an emoji in the status text raised its line box by 2px, which rescaled the Viewbox and visibly shifted every row.
Adds a headless Avalonia test project that renders the mapping window in all three colour schemes to PNG for visual inspection, and locks the behaviours built above: conflicts are accepted and flagged on both rows, the highlight clears once a binding is applied, Esc and Backspace clear, reserved keys are refused while listening stays active, and the status bar can no longer resize the canvas.
…proj insert_final_newline=false in .editorconfig only covers *.cs, so project files keep their trailing newline like the other eleven csproj files. The newline was removed incidentally while embedding the icon and controller SVG resources.
…closed shape
The shoulder/trigger arcs (l-zl, r-zr) are open paths (M + A, no z) but carried the ec-shell class, which sets fill. SVG fills an open path as if it were implicitly closed, so the arc and its chord enclosed a 5% opacity lens: invisible on the dark scheme, a dirty pale wedge across the shoulder area of both Joy-Cons on the light scheme. The rule that was meant to prevent this (.ec-shoulders path { fill: none; }) is in the stylesheet but referenced by nothing after these arcs became ec-shell so they could act as the colour and hit-test targets for the L/ZL and R/ZR rows. An id-selector rule now clears the fill on those two arcs only, leaving the closed body shells filled as intended.
… Skia PNG crash Both screenshot tests now carry [Explicit] + [Category(Manual)] and SaveFrame encodes the frame with SkiaSharp directly instead of WriteableBitmap.Save. That call goes through Avalonia.Skia.ImageSavingHelper to the SkiaSharp native PNG encoder and crashes the test host natively at random (Fatal error at sk_pngencoder_encode), which showed up as runs that silently executed fewer tests and exited non-zero; ci.yml runs ci\test.bat, so it would have turned a dev -> main PR red intermittently. A six-run control with the old call also passed, so the crash rate is low and this mitigation is not proven - but taking the Save path out of CI is deterministic by construction: the screenshots are a debugging aid, not an assertion. The crash, its stack and the documented way to regenerate the PNGs are recorded in AGENTS.md and in the fixture summary.
The test expects msvcrt.dll to fail loading, which only happens off
Windows. CI runs on windows-latest, where the FFI call succeeds and
Assert.Catch fails. Add [Platform("Linux,MacOsX")] to skip it on Windows.
按键映射功能修复与UI优化
Apply the fix wave from ARCHITECTURE_REVIEW_REPORT.md (94 findings), verified by a second review pass; the regressions the wave itself introduced are fixed here before landing: - ecs_vm.c: the load-time validator no longer rejects legal KeyV images (a is a key code, only b is a target slot), and GetFI/PutFI compare ext unsigned so 0xFFFFFFFF cannot slip past the slot check; corpus gains a variable-duration key case and a validator test that provably fails against the old over-strict check - Capture: dispose the cloned target Mats in the Search hot path - Device: TTLSerialClient no longer double-fires StatusChanged on Error - UiTests: double-buffer polling tolerates the transient disposed buffer between pool rebuild and the first resized frame Wave highlights: - ecs_vm.c: load-time static validator for slot/ext operands (P0); CI CVM differential now really runs on Windows and the macOS job runs dotnet test - Device: reconnect races removed (cancellable loop, serialized connect) - AI agent: MCP stderr drained (4KB pipe deadlock), ToolRegistry made concurrent-safe, provider/tool error paths surfaced and tested - OCR: init failures surfaced instead of being swallowed into empty text - LSP: keyword/builtin tables derived from the lexer/manifest single source; CLI failures return non-zero exit codes - UI: view models moved into EasyCon2.Avalonia.Core (compiler-enforced no-Avalonia zone), view components moved to EasyCon2.Avalonia; dead WinInput project, ProjectManager, IFirmwareService, Core Assist WebSocket, ImgLabelX/HSVColor/OCRDetect and bundled deps DLLs removed - Docs updated (Framework/VM2/GETTING_STARTED/VmSemanticContract/Device) and the review report checked in
修复桌面 VM 槽位限制、模块加载与相对 FFI 路径
…ions The previous small-screen change only let the preview shrink: enlarging the window left it at 822x282 with empty space around it, and making the window shorter just added a scroll bar. The preview now follows the window size. - Lay the window out as a grid whose first row takes the remaining space; the preview's Viewbox scales up and down (Stretch=Uniform) to fill it while keeping the canvas aspect ratio - Buttons, inputs and texts keep their normal size; parameter groups still wrap when the window is narrow - Drop SizeToContent and the scroll viewer; default to 900x500 and a 480x480 minimum, which fits every control even in English - Tests: nothing overflows at the minimum size, the preview grows with a larger window and shrinks when the window gets shorter, and clicks map to canvas coordinates whether the preview is scaled up or down
The ink threshold was hard-coded at half brightness, and the preview showed the original picture, so there was no way to tell or tune which pixels would actually be drawn. - Add an explicit binarization stage: InkMask.Binarize turns the canvas into a per-pixel ink mask using a threshold percentage and the invert option; SearchLines now scans the mask, and Reverse moves out of DrawingBoardSettings into the binarization options - Add a threshold slider (0-100%, default 50%, the legacy boundary); the only difference from the legacy rule at 50% is that a pixel exactly on the boundary (R+G+B = 382), which used to keep the current run state, now counts as ink - The preview shows the mask (black = will be drawn) and refreshes as the threshold or invert option changes; "Show original" switches back to the picture - Drawing takes a snapshot of the mask when it starts, so adjusting the options mid-draw does not affect the running drawing - Tests cover the legacy boundary, threshold and invert combinations, the mask preview, preview updates and that the threshold changes what is drawn
Only 320x120 pictures were accepted; anything else was rejected and had to be resized by hand. Pictures of any size are now fitted onto the 320x120 canvas. - Add IImageProcessor.FitTo with three modes: fit with letterbox (default, keeps the whole picture undistorted; the transparent margins count as white and are not drawn), fill with a centered crop, and stretch; SkiaImageProcessor resamples with a Mitchell cubic filter - A picture that is already 320x120 is returned untouched, so pixel art keeps its exact pixels - The view model keeps the decoded original and refits from it when the mode changes, without reading the file again - Show the original size next to the fit selector; drop the "must be 320x120" message - Rename the stop-drawing CancellationTokenSource to _drawCancellation - Tests cover the fitting modes against SkiaSharp and the view model's default mode, refitting and size display
Messages_AreOwnedByTheDrawingBoardWindow failed about one run in five with "the calling thread cannot access this object". After the message box closed, the continuation of the awaited dialog resumed through NUnit's synchronization context on a thread-pool thread, where AsyncRelayCommand raised CanExecuteChanged and the button read its Command property off the UI thread. Run the test under AvaloniaSynchronizationContext so the continuation is posted to the dispatcher and executed by RunJobs on the UI thread. The app itself always runs under Avalonia's context, so only the test was affected. 10 consecutive full UI test runs pass.
A plain threshold turns grayscale photos into flat black and white blobs. Add an optional dithering mode that spreads each pixel's quantization error to its unprocessed neighbours (7/16, 3/16, 5/16, 1/16), so shades come out as dot density. - BinarizeOptions gains Dither (off by default; when off the mask is unchanged); threshold and invert keep working with dithering on - Pure black and white areas, including letterbox margins, stay exactly as without dithering, so nothing is drawn in blank space - Add a Dither checkbox with a tooltip noting that dots are more scattered and drawing takes longer - Tests: mid gray becomes about half dots, pure black/white are unchanged (also inverted), dot density follows a gradient, and the option updates the mask immediately
The dither option was a single Floyd-Steinberg checkbox. Replace it with a dropdown of algorithms, since they trade quality against the number of segments, which is what drives drawing time: - Off (default), Floyd-Steinberg, Floyd-Steinberg with serpentine scanning (odd rows right to left, fewer diagonal streaks), Atkinson (diffuses only 3/4 of the error: fewer dots in light areas, more contrast, fewest segments), Jarvis-Judice-Ninke and Stucki (12-neighbour kernels, smoother), and 8x8 Bayer ordered dithering (regular grid) - Error diffusion is one routine driven by a kernel table; serpentine rows mirror the kernel horizontally. Bayer shifts the threshold per grid cell around the slider value, so the threshold and invert options work with every algorithm - At 50% pure black and white stay unchanged with every algorithm - On a 400x400 radial gradient (fill mode, default timings) the estimate ranges from 81 min (Atkinson) to about 103 min (Floyd-Steinberg/Bayer) - Tests run the shared properties for every algorithm and check that Atkinson uses fewer dots in light areas, that serpentine changes the pattern but not the density, that Bayer repeats every 8 pixels, and that the dropdown lists every mode in enum order
Pictures taken or saved in the wrong orientation had to be fixed in an external editor before drawing. Add orientation options that apply to the decoded original before it is fitted onto the canvas: - Rotate 0/90/180/270 degrees clockwise (dropdown), then flip horizontally and/or vertically relative to the rotated picture - PixelImage.Orient only moves pixels (no resampling, so pixel art stays sharp) and returns the same image when nothing changes; 90/270 swap the dimensions, so a rotated picture is fitted as portrait - Like the fit mode, changing orientation recomputes from the decoded original without reading the file again; the size label keeps showing the original size, and "show original" shows the rotated/flipped one - The extra row wraps the parameters onto a third line at the default width, so raise the default window height from 500 to 560 to keep the preview at nearly full width - Tests pin every rotation/flip combination on a numbered 3x2 picture, the identity shortcut, how orientation moves what gets drawn, and that a 90-degree rotation fits a portrait picture
The estimate only appeared after clicking the legacy "估算耗时" button, and went stale as soon as the picture or a parameter changed. Remove the button and keep the bottom-right estimate up to date instead. - Recompute the estimate whenever the mask changes (loading, rotation, flips, fit mode, threshold, invert, dithering) and whenever the start position, size, key hold or delay changes - With no picture it still shows "耗时:"; an invalid parameter shows "耗时:参数有误" instead of opening a message box while typing - A full dithered canvas takes only milliseconds to estimate, so the value follows slider drags in real time - Rename EvaluateText to EstimateText and drop EvaluateCommand and the Text.DrawingBoard.Estimate button label - Tests cover the estimate appearing on load, following picture and parameter changes, and the invalid-parameter hint without a dialog
In the game A is the pen and B the eraser. For pictures that are mostly black it is much faster to fill the whole canvas by hand with the largest brush and then erase the blank parts than to draw every ink point. Add an eraser mode for that workflow: - When enabled, plan strokes over the blank points (the inverted mask) and hold B instead of A; scanning, ordering and movement are the same as in pen mode - The preview keeps showing the final picture, which is identical in both modes, and the bottom-right estimate switches with the mode so the two can be compared - Show the preparation steps below the parameters while the mode is on (fill the canvas black, pick the smallest brush, cursor to the top left; only the drawing region is processed and the rest stays black) - The mode is snapshotted with the mask when drawing starts - Add InkMask.Inverted and a pen key parameter to SplatoonDrawing - Tests: B is held and only blank points in the region are erased, a mostly black picture estimates far faster in eraser mode, the preview is unchanged, and nothing overflows at the minimum window size with the help text shown
There was no way to keep the processed result: after tuning rotation, fit, threshold and dithering, the work was lost when the window closed. Add a "Save Picture" button next to "Load Picture". - Save exactly what the preview shows at 320x120: by default the black-and-white mask (what will be drawn), or, with "Show original", the rotated and fitted original - A saved mask is pure black and white at canvas size, so loading it again skips resampling and binarizes to the same mask at the default 50% threshold - Suggest "<source name>-320x120.png"; log the saved path, and report a failure in a message box - Add IImageProcessor.SavePng (lossless SkiaSharp PNG encode, alpha preserved); the button is disabled until a picture is loaded - Tests cover availability, saving the mask or the original, cancelling the dialog, failures, a lossless round trip and an unwritable path
Three picture-input improvements in one change: Drag and drop - Dropping a file anywhere on the drawing board window loads it, reusing the existing FileDropBehavior More formats - The open dialog now lists every format SkiaSharp decodes here: PNG, JPG/JPEG, BMP, GIF, WebP, ICO and WBMP (HEIC, TIFF, PSD, TGA and JPEG 2000 were probed and do not decode) - The load-failure message names the supported formats and suggests converting HEIC/TIFF first; the load button tooltip mentions dropping Cover framing - In fill (crop) mode, add free rotation (-180 to 180 degrees, applied after the 90-degree steps and flips), zoom (100-400%) and horizontal and vertical framing sliders, plus a "Reset framing" button; they are shown only in fill mode and only refit there - The base scale grows with the angle so a centered picture still covers the whole canvas at any angle; framing moves within the picture's overflow (with rotation, extreme positions may expose transparent corners, which count as white) - FitTo takes an optional CoverTransform; the identity transform renders exactly like the previous centered crop, and the same-size shortcut is skipped when framing is adjusted - Reset recomputes once instead of once per slider Tests cover cover-only behaviour, the transform passed to FitTo, reset, dropping, the dialog filter, decoding each listed format, framing, zoom, 90-degree and arbitrary-angle coverage, and the drop wiring.
Pure move, no behaviour change: the drawing board view model had grown to 536 lines and its test file to 1220, mixing unrelated concerns. - DrawingBoardViewModel becomes partial files by responsibility: core (dependencies, position, localized texts, disposal), .Picture (load, drop, save and the orient/fit/framing/binarize pipeline), .Settings (parameter inputs, validation and the automatic estimate) and .Drawing (start/stop, background run, progress, eraser mode) - Move DitherMode and the dithering kernels/algorithms from InkMask into Dithering; InkMask keeps the mask, binarization, inversion and preview - Split DrawingBoardTests into SplatoonDrawingTests, InkMaskTests, PixelImageOrientTests and DrawingBoardPicture/Run/SettingsTests, with shared builders and fakes in DrawingBoardTestKit and the zh_CN locale setup in DrawingBoardTestBase - Move the FitTo and cover framing tests from SkiaImageProcessorTests into SkiaImageFitTests Moved code lines were compared before and after; only access modifiers, class headers and the dither dispatch location changed. Test counts are unchanged (Core 319, UI 81) and all pass.
…election Pause and resume - Add a Pause/Continue button while drawing. The pause takes effect before the next key press; if the pen is down it is lifted first and pressed again in place on resume (redrawing the same cell is harmless). The controller lease is kept, so scripts and manual input stay blocked. Stopping or closing the window cancels a paused draw immediately. - Paused time is excluded from the elapsed clock and the remaining-time calibration; the planned progress still ends at exactly 100%. Progress - The status line now shows completed/total segments, e.g. "37% · 第 1234/5678 段 · 已用 12:05 · 剩余约 20:13", and "已暂停 · …" while paused. - While drawing, the preview shows an estimate of the in-game canvas: pen mode draws done ink black and pending ink light gray; eraser mode shows erased cells white, pending cells dark gray and the rest black. The cursor is marked with a red dot and ring. The image refreshes with the throttled progress and immediately on pause, stays after finishing or stopping, and is cleared once the picture or its options change. - SplatoonDrawing reports the cursor and pen state after every step; the key sequence is unchanged when not paused. Drawing region - Remove the start row/column and row/column count inputs: drawing always covers the whole canvas from the top-left by default, since exact coordinates are hard to confirm in the game. - Add an advanced "select drawing region" option: drag on the preview to select a rectangle, framed in translucent orange, with a "whole canvas" reset and a text summary. The region cannot change while drawing, and outside it the progress preview shows the untouched canvas. - The saved picture never includes the progress or region overlays. Tests cover pausing with the pen down, progress unaffected by pauses, cancelling while paused, step reporting, overlay colours and cursor ring, region outline and restriction, pause/continue texts, stopping while paused, segment counting, the finished preview, region selection by dragging (including in the headless window) and the region lock while drawing.
…and outline Add an "advanced picture adjustments" expander (collapsed by default) with four options; their defaults leave every result unchanged. The pipeline is now: orient -> fit (optionally nearest-neighbour) -> tone -> threshold/dither -> invert -> remove specks -> outline. - Pixel art: FitTo gains a nearest-neighbour mode, so enlarged pixel art keeps hard edges instead of grey transitions that thicken or break lines after binarization - Brightness, contrast and gamma (ToneAdjust) are applied to the composited brightness before the threshold and dithering; a reset button restores them with a single recompute - Remove specks: drop 8-connected ink blobs of at most N points (0-20, shown as "关闭" at 0). On a radial gradient with Atkinson dithering, N=3 cuts the estimate from 83 to 66 minutes - Outline mode keeps only ink cells with a blank (or canvas-edge) 4-neighbour, hollowing solid areas while lines and dots stay - The controls below the preview are grouped so the window's minimum height follows their height; expanding the adjustments grows the window instead of pushing controls out of view. Default height is now 600 to keep the preview near full width - Put the new options in DrawingBoardViewModel.Adjust and the mask filters in InkMask.Filters Tests cover the tone math and its effect on binarization, speck removal by blob size and connectivity, outlines, the view model wiring (nearest-neighbour refit, mask/estimate updates, single-update reset), nearest-neighbour scaling without grey pixels, and no overflow at the minimum size with the adjustments expanded.
…verted Outline mode kept every ink cell next to a blank cell or the canvas edge. With "invert" on, the white background becomes ink, so the whole canvas border was kept as an outline: a black disc on white produced 1048 outline cells, 876 of them a frame around the canvas that is not in the picture and adds minutes of drawing. The canvas edge no longer counts as an outline; a cell is kept only when a 4-neighbour inside the canvas is blank. Inverted, the same disc now yields a 172-cell ring just outside the disc, matching the 168-cell ring inside it without inversion. An ink area touching the canvas edge no longer gets a contour along that edge, and a fully inked canvas has no outline at all. Tests pin the inverted disc (no border cells, ring size close to the non-inverted one) and the fully inked canvas, and update the corner block expectation.
Invert was applied right after thresholding, before speck removal and the outline, so with outline mode on it merely outlined the background instead of the subject: the result looked almost the same whether or not invert was checked. The previous fix (0d2d93e) only removed the canvas frame and did not address this ordering. The pipeline is now orient -> fit -> tone -> threshold/dither -> remove specks -> outline -> invert: invert swaps black and white in the fully processed result, so a black outline becomes white lines on black and speck removal works on the subject's dark specks before inversion. Without speck removal or outline the result is unchanged, since inverting before or after a plain threshold is the same. - Binarize with Reverse=false in the view model and invert the final mask; BinarizeOptions.Reverse keeps its meaning for direct callers - Add a tooltip to the invert checkbox stating it is applied last - Keep the canvas-edge rule from 0d2d93e (edges are not contours) and reword its rationale - Tests: invert after outline equals the inverted outline, a removed speck turns into ink after inversion, and invert alone still matches the plain inverted threshold
With a drawing region selected, the progress preview rendered everything outside the region as the untouched canvas (blank in pen mode, black in eraser mode), so the rest of the picture vanished as soon as drawing started. The progress image also stayed after stopping, and reselecting a region did not bring the full preview back, leaving nothing to select against. - Render cells outside the region faintly instead: ink as very light grey in pen mode, would-be-erased cells as near-black in eraser mode, distinct from done and pending cells inside the region - Clear the leftover progress image as soon as the region is reselected, reset to the whole canvas or region selection is toggled, so the full preview is shown while choosing the next region - Drop InkMask.Within, which only served the old blank-outside rendering Tests cover the faint outside rendering in both modes, and stopping a region draw then reselecting by dragging, which now shows the whole picture again.
…s tabs Put load/save and start/pause/stop in a toolbar above the preview, a single-line status row (region, position, estimate) and the progress bar below it, and the parameters in four tabs that follow the processing order: picture, tone, black & white, drawing. The preparation tip at the bottom switches to the eraser steps in eraser mode. Status texts are shorter and truncate instead of wrapping.
Add a Reset button that restores every option to its default while keeping the loaded picture, recomputing once at the end; it is disabled while drawing. Show a drop hint in the empty preview. Move the eraser steps into the eraser checkbox's tooltip and keep the bottom tip fixed. Remove the clicked-position readout; clicks on the preview now only start a region selection.
…ming overhead Homing: the Switch may drop the first input frame after connecting. When that first input was the pen press, the whole first row went missing, and any mispositioned start shifted the entire picture. Drawing now starts by pushing the left stick fully up-left for 50 ms (a sacrificial input) and then for 4 s, so the cursor lands in the top-left corner from anywhere. It is a default-on option; turning it off warns that dropped frames can cause unpredictable misalignment. Estimates: the plan only summed key durations and delays, but every click, pen press and release also costs a device round trip, so pictures with many segments (dithering) ran far longer than estimated. Each operation type's overhead is now measured during drawing; the remaining time uses those per-type figures instead of a global ratio, and later estimates in the same session include the learned overhead (also written to the log). Also fixes a crash: localized text was formatted on the drawing thread (learned-overhead log, error message), which threw a cross-thread exception on stop and took the app down. Both now run on the UI thread, guarded by a regression test. A replay test checks that the emitted key sequence paints exactly the ink pixels, including the first and last columns.
…rules Mark the reference timings as planned time, explain why the first estimate after launch is short, add troubleshooting rows for a missing first row and for turning auto homing off, and record the maintainer rules: how overhead is measured and learned, and that localized text must only be formatted on the UI thread.
Once the macOS screen saver started, every wait of the draw loop overran by about 20 ms, so a picture estimated at 47 minutes took 66. Sleep on either platform also interrupts the draw. While drawing, the run now holds an NSProcessInfo activity (user initiated, idle display sleep disabled, latency critical) on macOS and SetThreadExecutionState on Windows, released when drawing ends. It is best effort and never fails the draw. Exposed as a "keep awake while drawing" option, on by default; the runner interface takes the flag per run.
feat(device): 完善 pokeldn 串口控制并支持 ESP32-S3 服务连接
refactor(device): 分离通用串口协议与蓝牙桥接入口
Add ezcon init with canonical project templates and conflict checks. Reject explicit import cycles after graph discovery and cover scaffold safety and module cycles with regression tests. Document project layout, import rules, and PATH-based CLI usage.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
发布版本
v1.7.0-rc2
变更内容
验证
注意事项
关联 Issue / PR
发布检查清单