Repository navigation
Releases: GMH13552/dsh-mc-art
Release list
0.3.4:修掉让「MC 模组工作室」模式整轮跑不起来的 preset 变量
dsh-mc-art-panel 0.3.4
0.3.4
Fixed — one preset variable broke every session on the mode
presets/mc-studio/agent.cordis.yml carried suffix: Your working directory is {{cwd}}. in the
persona, and named the same variable again inside the prefix body. The current runtime registers only
provider and model for that prompt section, so rendering the system prompt threw
unknown prompt variable "{{cwd}}" and the whole turn failed before the model ever ran — the
session showed nothing but "处理失败 · 本轮运行失败".
- The working-directory sentence is gone and the prefix now says
本会话的工作目录; no prompt text
in the preset references an unregistered variable. tools/gen_preset_patch.mjs --writeregenerated both the standalonedesktop-generation.patch.yml
and the copy embedded inpanel/cordis.patch.yml, so the shipped package carries the fix.- New gate
preset-vars-test.js(plugin-preset-vars): every{{var}}in the preset YAMLs and
the packaged patch must be within{provider, model};--faultinjects an unknown variable and
exits 1.
Note
An agent's composition is fixed when its session is created, so a session that already failed keeps
failing. Restart DSH, then start a new conversation on the mode.
0.3.3:设置视图按专业工具重做;修掉「网格线透过方块」的假透明
dsh-mc-art-panel 0.3.3
0.3.3
Round one of the UI review targeted the settings view, because that is where "AI-made" showed
most: a flat pile of rows with inconsistent label columns, no grouping, and a typo.
Changed — settings, reviewed from a screenshot
- It is a real property grid now: a fixed 88px label column with labels right-aligned, values
starting on one axis, hints under the value column. The路径row no longer carries its own
indent (~39px off from every other label). - Grouped:
参考目录/生成/命名空间/通知/文件— each an 11px/600 muted header with
a 1px hairline, instead of one undifferentiated list. - A view, not an insert: settings opens as its own page with a
返回资产列表control; previously
it was stacked above the asset list and squeezed both the list and the 3D viewport. - Wording bug fixed: the detection line said
2242 张截图("2242 screenshots") where it meant
textures — now2242 张贴图, with the number in monospace and tabular figures. - Long paths (
设置文件 …) were clipped by the panel edge without an ellipsis; they truncate
properly now and carry the full path intitle. - Buttons share one 22px height; checkboxes are 12×12 with a 1px border and a brand-coloured check
when on, plus:focus-visible.
Fixed — the ground grid no longer shows through the block
The 3D viewport drew its ground grid after putImageData, with canvas 2D strokes. That paints
over every pixel already rendered, so grid lines crossed the block's faces — which reads exactly like
the block being semi-transparent. It never was: the rasteriser rejects faces below alpha 0.5 and
writes depth without blending, so the faces are opaque.
The grid is now rasterised into the colour/depth buffer with a depth test, so the block occludes
it and lines only appear on background pixels. The pick buffer is still untouched (the grid is not
clickable). A new gate, grid-occlusion-test.js, executes the emitted function against two synthetic
buffers and asserts that not one pixel inside a nearer occluder region gets stained — and
--fault deletes the depth test to prove that assertion can fail.
Gates
ui-testgained behaviour assertions for this view: the gear opens it, it is not rendered on
the same screen as the list/viewport, and返回资产列表brings the list back — plus
--fault-settings-back, which deletes that button's handler and turns the assertions red.ui-style-testgained assertions for the property grid, the group headers and the checkbox.- 51 conditions, two passes (default console encoding and
--encoding gbk): 50 green / 1 SKIP /
0 red.
0.3.2:UI 按书面规范重做第二轮(第一次是看着截图改的);修掉「宿主已卸载」与落点竞态
dsh-mc-art-panel 0.3.2
0.3.2
The UI pass this project needed was never "make it nicer": it was look at it. This release starts
with a written spec, then a machine that can see the result.
Added — two documents
docs/UI-STYLE.md— a design spec, not a mood: the reference language is a professional
inspector (Blender properties / VS Code panel — flat, dense, narrow, quiet), with an explicit
anti-list of what made the panel read as "AI-made": cards inside cards, large radii, pill buttons,
gradients, glow, animation, coloured chips, emoji icons, 16px+ padding, centred form labels.
It fixes the numbers: 12/11px type, 22px rows, 26px form rows, 28px toolbar, 22px controls,
radii 2/3 only, spacing 2/4/6/8, four interaction states, token-only colours.docs/CUA-UI-REVIEW.md— how an agent can see this panel: the official
@deepseek-ai/dsh-experimental-computer-use-cua-driver-mcpprovider (published by DeepSeek,
packages/experimental/…indeepseek-ai/deepseek-harness) mounted against the locally installed
Cua driver, plus the exact screenshot/zoom/click procedure and its traps (Electron exposes no UIA
tree; Chromium input fields only accept foreground delivery; coordinates are in the returned
screenshot's pixel space).
Changed — the panel, judged from screenshots
- Header: the breadcrumb leaked placement jargon (
中央面板) and repeated the tab title. It is
now one row — path only (mono 11px, muted, ellipsised, full path intitle). - Asset list: rows are two columns — localised name on the left, monospaced id right-aligned
and muted — instead of深渊砖 abyss_bricksrun together. The group header (方块 · 44) is
sticky with a hairline, the list fills its container and scrolls on its own, and the selected row's
2px left bar uses a brand-derived token (--mc-brand-bar, brand 75% + text 25%) rather than
reading as grey. - Toolbar: counts (
6 面 · 贴图 1/1) in mono muted on the left;重置/手动修改as icon buttons
with tooltips and 1px dividers;@ 提意见as the only primary action, right-aligned. - 3D viewport: the camera now auto-fits the bounding box by projecting all eight corners
into an 88% safe box (~12% margin), reserves room for the hotbar and shifts the content up so the
block is never clipped, and re-fits on asset switch and viewport resize. A subtle ground grid and
a small axis indicator give the model a ground and an orientation; the selection label moved from
a chip floating over the hotbar to a mono label in the corner. - Narrow widths: the settings "使用" button was clipped by the right sidebar; the input and button
group now wrap instead of overflowing.
Fixed — recovery instead of a raw error
- "宿主已卸载" is now actionable. After repeated rebuilds plus HMR the host half can end up
disposed (0 个方法), and the panel used to show that sentence and nothing else. It now says, in
two lines, that the plugin host did not load (which happens right after a rebuild) and that DSH
must be fully quit and reopened — with the technical detail collapsed under详情— and it
retries the operation once after a second before reporting. - Panel placement is deterministic. At boot the right sidebar service can appear after the panel;
the panel now retries the migration and removes the left/centre fallback once it lands on the right
sidebar.ui-test --fault-placementproves the retry is load-bearing (delete it → three assertions
go red).
Gates
- New
tools/mcart-plugin/ui-style-test.js(plugin-ui-style): 27 assertions over the CSS string
that actually ships — every anti-list item must be absent, every fixed number present; three fault
modes return exit 1.icon-testgained static assertions for fit/reset/grid/axis/details/retry/
two-column rows/placement retry;ui-testgained the placement-race and host-unloaded behaviours
without relaxing any existing behaviour assertion. - 51 conditions, two passes (default console encoding and
--encoding gbk): 50 green / 1 SKIP /
0 red.
Note
The visual review was done on the previous build with CUA screenshots; this batch's final look was
checked by code, tests and gates, and needs one page refresh to be seen.
0.3.1:@提意见直接插进输入框;三个「报告在指责产物」的坑修掉;母模型表单一真相
dsh-mc-art-panel 0.3.1
0.3.1
Changed
- 「@ 提意见」inserts straight into the composer. It used to set a pending reference and open a
bar ("引用给 AI" / path / 插入输入框 / 取消) that needed a second click. It now appends@<path>
(plus the sentence describing a settings change) to the draft immediately, keeping what the user
had already typed and leaving a trailing space. The dock entry stays registered because its render
is the only place the shell hands overinputActions.setDraft— it renders nothing on the normal
path and is kept solely as the cold-start fallback: if the handle is not available yet the bar
appears once, so a click never silently does nothing. Settings' "tell the AI" reuses the same
insertion path, and the reference bar now says so when the scene has no file path instead of
ignoring the click. - The red-line gate was retargeted to the new insertion point, so "insert writes the draft and never
a session" is still proven to be able to fail (ui-test --fault-inject→ 3 reds, exit 1).
Fixed — messages that accused the artifact
- A model file that exists but cannot be parsed was reported as "missing".
readJsonturned any
JSON parse error intoundefined, so the diagnosis said "项目自己的模型文件缺失 → 补上它" while
pointing at a file that was right there — following that advice overwrites the user's own file and
the real cause never surfaces.preloadnow records{file, why}, and the report has two distinct
sections: "在,但解析失败(不是缺失,不要照补文件处理)" with the parser's own message, versus
a genuine missing file. - Broken
lang/*.jsonwas silently skipped.readLangnow returns{table, problems}; the
diagnosis names each unreadable language file with its reason and says what it means (block names
fall back to raw ids). A missing locale is only reported when no names could be read at all —
en_usfine andzh_cnabsent is a normal state, not a failure. atlas.refIconsdropped a cell without saying why. An entry with nopng, an emptypng, or
no entry at all now lands infailedwith the reason (<id>(没有图标数据:<原因>)); the return
shape is unchanged.
Added
texture-path-parity-test.js— the same animated texture (16×N strip +.mcmeta) through
atlas.sceneandatlas.itemIconsmust resolve to the same data URL and the same animation facts
(strip, frames, frametime, order). Reverse fixture: stop the scene path from reading the project's
.mcmeta(the 0.2.9 bug) and five assertions go red. This is the invariant that keeps the two
paths from drifting apart again; unifying their implementations is still open.model-json-broken-test.js,lang-json-broken-test.js,ref-icons-failed-test.js— each with a
reverse fixture and a distinct "missing" versus "unreadable" pair of messages.- The vanilla-parent table has one source.
tools/mcart-plugin/vanilla-parents.jsonis the
truth: the build generateshost/06-vanilla-parents.generated.js(marked generated, ordered before
its user) and copies the same JSON into the package for the Python extractor, which reads it and
fails loudly when it is absent instead of falling back to a second table.verify-build
asserts fragment == regenerated, packaged copy == source byte for byte, and Python's table == JSON;
--fault-vanillaproves all three can fail. - The gate list is 50 (was 46); the runner, README and the module-layout doc agree on the number.
Changed — UI (second batch)
Sticky panel header; one control height (26px) across buttons, inputs, selects and icon buttons; the
settings card's switches and hints share an indent column; lists, hotbar, swatches and project
pickers share one thin scrollbar and scroll height; the editor canvas gets breathing room. Colours
remain token-only, with no gradients, animations, glow or stacked shadows.
Known limits
- The icon path and the scene path still have two implementations; the parity gate now makes drift
fail, but merging them is open. - The UI is verified by code and tests, not by eye in a browser.
0.3.0:两半源码拆成片段模块;门禁单一入口;产物不再运行时求值
dsh-mc-art-panel 0.3.0
0.3.0
A structural release: the same behaviour, in files you can find things in — plus the build,
gate and dependency hardening that came out of building it.
A correction first
The panel was never broken on DSH 0.2.1. An investigation into "the client UI does not
register" read an empty left sidebar slot (sidebar.panellist) as evidence of a dead client
half; the panel in fact registers in the right sidebar (sidebar.right.pane.tab, key
mc-art.atlas) and in the composer dock (conversation.input.dock, id mc-art-ref), as designed.
The hardening below is worth keeping, but it is not a fix for a missing panel, and this log does not
claim it was.
Changed — the two halves are now fragment modules
tools/mcart-plugin/host.js(4192 lines) is now 25 fragments under
tools/mcart-plugin/host/, ordered byhost.manifest.json;client.js(4013 lines) is 6
fragments undertools/mcart-plugin/client/, ordered byclient.manifest.json.panel/source.mjsis the single concatenation implementation:--writeregenerates the barrels,
--checkproves each barrel equals its manifest's concatenation byte for byte,--selftest
(with a--faultcounter-proof) covers ordering, empty-manifest and missing-file errors.host.js/client.jsremain the complete sources — as generated barrels — so every
existing gate and test keeps reading the artifact it always read.- The split is behaviour-preserving and mechanically proven, not judged by sight: batch 1/2
assert the barrel equals the pre-split source under the one wrapper (installHost, which exists
so blocks that share closure state can still be moved in order), and the barrel's sha256 was
asserted unchanged on every later batch. - What was deliberately not split, with the reason written into the code:
apply's closure body
(client ~3000 lines, and the host handler registry, 736 lines). Fragments share one top-level
scope; closure bodies cannot cross files without first introducing an explicit panel context
object, which is a separate refactor — and doing it half-way would trade one tangle for a worse
interface.
Added — one-command gate runner
node tools/gates.mjsis now the single source of "the 46 gates": it prints
绿 / SKIP / 红, lists every red command with its exit code, treats exit 3 as the reserved SKIP
code, supports--encoding gbk(second pass under the console code page),--only <substr>, and
--fault, which proves the runner itself can go red. The README's acceptance section now says
this one command instead of carrying a copy of the list.panel/verify-build.mjsgained two assertions that can fail: each barrel equals its manifest
concatenation (--fault-barrel), and eachlib/artifact equals the regenerated result
(--fault).tools/strip_gate.pyandtools/mcart-plugin/report-test.jsnow compare against the
concatenated source and cross-check the barrel, instead of assuming a single-file layout.tools/mcart-plugin/icon-test.jsandicon-render-test.jsno longer slice the source by string
offsets (indexOf('const sub =')…indexOf('const CSS = [')). That made fragment order depend on
gate internals — reordering files turned them red withReferenceError: drawItemIcon is not defined. They now evaluate the whole top-level declaration region through one shared helper, and
throw loudly if the region cannot be found instead of silently evaluating nothing.
Fixed — hardening found while restructuring
- Artifacts no longer evaluate their own source at runtime. Both halves are emitted as inline
function bodies;verify-build/entry-testassert no runtime evaluation remains, so the artifact
can be analysed statically and does not depend on a sandbox allowing it. - Inlining leaked CRLF into the artifacts (about 3,500 carriage returns) — caught by the EOL
gate the moment the source was no longer wrapped in a JSON string.strip()now normalizes to LF. - The client plugin declared too little to be safe: it injected only
timerand fetchedslots
softly, returning silently when absent — a cold-start ordering change disabled the whole panel with
nothing on screen or in the log. It now declaresinject: ['timer', 'slots']and reports a missing
slotsloudly. dsh.client.injectlisted two host-side packages (dsh-api-session-controller,
dsh-cordis-client-runner), which are not client modules — dependencies that could never resolve.
The list is now empty, because the real service dependencies are plugin-level ones.dsh.compatibility.dshdid not match the running DSH. Under node-semver a prerelease version
only satisfies a range that names a prerelease of the samemajor.minor.patch, so
>=0.1.0-rc.8 <0.3.0excludes0.2.1-rc.2. The range now accepts both lines.- The reference-directory placeholder in settings no longer looks like a Windows user-profile path,
which the publish-time privacy gate rightly flagged once the source stopped being hidden inside a
JSON string.
Changed — UI
- Colours now come from host theme tokens (
--dsw-alias-*with neutral fallbacks), so the panel
follows light/dark instead of hard-coding greys; content surfaces (3D viewport, pixel canvas, HUD)
deliberately keep a fixed neutral dark ground — they are content, not chrome. - One spacing grid (4/8), collapsed font and radius scales, unified borders, consistent
hover/active/disabled states, and:focus-visibleon every interactive control (custom
controls previously had no keyboard focus indication at all). - Empty/loading/error states share one visual language; the HUD's glow was removed. No gradients,
no animations, no stacked shadows.
Known limits
- Duplicate knowledge is not unified yet: the vanilla-parent table still exists in both
host/05-model-shape.jsand the Python extractor, the icon path and the scene path still resolve
textures separately, and "cannot read it, return silently" branches remain. Next round starts with
a drift gate between the two parent tables. - The UI was reviewed by code and tokens, not by eye in a browser: the theme-token inspect provider
timed out, so token names were read from the shipped DSH artifacts.
0.2.9:项目自己的动图,面板从来没当成动图;而且那句提示在指责文件
dsh-mc-art-panel 0.2.9
0.2.9
Fixed
- An animated texture in your own pack was never animated in the panel, and the panel blamed the
file for it.animationsFor()consulted only the reference textures' animation table, and
preload()collected the project's textures without ever looking for<name>.png.mcmeta— the
wordmcmetadid not appear in the host at all. A 16×192 strip (12 frames of 16,frametime4)
was therefore drawn as one 16×192 texture, which is the blur you saw, while the game read the
.mcmetaand animated it correctly. The host now reads the project's.mcmeta(its own IHDR size
reader; the same acceptance rules as the extractor'sanimation_of) andanimationsFor()consults
both tables. - The message no longer accuses the file of something the tool never checked. "shaped like a
strip but has no animation description" was printed whenever the shape looked like a strip and no
animation entry existed — including when the.mcmetawas right there. There are now three cases
saying three different things: a valid.mcmeta→ nothing is shown;.mcmetapresent but
unreadable (bad JSON, noanimationsection, or the image is not a strip) → "this texture
has an animation description file, but I cannot read it:<path>.mcmeta—<the real reason>"; genuinely absent → the shape-based message, which now also names the file to add. - Two unrelated drifts surfaced by gating this:
check_jdk_test.pyhad been rewritten to capture
output without declaring how to decode it, soencoding-test.js --faultcould not catch its own
reverse fixture (the static rule now requiresencoding=/text=whenever output is captured);
and the host's line endings had been normalised to CRLF, which made multi-line--faultpatches
match nothing silently (readHostSource()now normalises to LF). Both guards reported
"did not take effect" rather than turning green.
Added
tools/mcart-plugin/project-animation-test.js: fixture A (valid.mcmeta— must be 12 frames and
must produce neither message), B (absent — may produce the shape message), C (present but broken —
must produce the truthful message and must never say "no animation description"), D (a plain
16×16 — silent).--fault(remove the project.mcmetareading) turns 8 assertions red.panel/ui-test.mjsgained the same three cases plus--fault-animnotes, whose reverse fixture
turns exactly case C red while case B stays green — the fallback message is correct when the
host has nothing to say, so only "the host spoke and the client ignored it" may fail.
Note
The .mcmeta path was already parsed on the reference side (that is where the jar's animations come
from), which is why this only broke for textures in your own pack — precisely the case the panel
exists for.
0.2.8:引擎写出的方块模型在游戏里不能用,而所有门禁都说没问题
dsh-mc-art-panel 0.2.8
0.2.8
Fixed
- The block models the engine wrote were unusable in the game, and every gate said they were
fine.write_block_modelpassed the spec'selementsthrough verbatim, so a face written as
"stone"— a key into the model's owntexturesmap, which is the spec's convention and what
the engine's own audit validates — stayed"stone"in the emitted Minecraft model, where a value
without#is a path:<namespace>:textures/stone.png, which does not exist. Every face lost
its texture, so the model was invisible in game and undrawable in the panel. Measured on a real
project: 42 references in one hand-authored model, 38 in another — and those two were the
only broken ones, because they were the only ones going through the block-entity path.
Face textures are now emitted as#key; values that are already#…or namespaced paths are left
alone (vanilla writes those too). - The artifact is now validated by reading it back.
validate_written_modelre-reads the model
it just wrote and requires every face to be a#variablepresent in that model's owntextures,
or a path the pack really ships; otherwise it raises, so an illegal model cannot leave the
generator. It sits on the generation path, ahead of the preview — because the preview reads PNGs
from disk and therefore renders correctly even when the written model is broken. That split is
exactly why this shipped: the picture was right and the artifact was wrong. - The engine's own example
examples/example_block_entity/desk.jsonis a spec whose generated
model was broken; it now emits#wood/#paper, and the emitted model is read back and validated
(20 faces, zero bare words). - A second source of truth, removed by choice. A spec may now declare a texture's real asset id
({"path": …, "id": "ns:block/real_name"}), in which case nothing is copied. Copying stays the
default, but when the spec key differs from the source file's name the copy is reported with
its consequence: the pack ships those bytes renamed, so anything referring to the real asset id
will not find them.
Added
- The panel now names this mistake instead of sending you hunting for a missing PNG. A face
texture that is a bare word and matches a key in the model'stexturesmap is reported as
texture-missing-hash: it names the face, says the bare word is being read as a path, lists
the model's texture keys, and says "you probably meant#stone" — adding that the block is
broken in the game too, not only in the panel. A#variablethat is not in the map is a separate
reason (texture-variable-unresolved), and a genuinely missing file staystextures-unresolved;
the three no longer share one sentence.tools/mcart-plugin/texture-syntax-test.jscovers all
three plus two legal forms ("#stone", and a bare path likeblock/stone_tex) so the advice
cannot fire on correct input. - Unresolved textures that are the project's own no longer report
no-reference-directory; a
missing PNG in your own pack has nothing to do with whether a reference directory is set.
Changed
- Vendored
mc-artsnapshot:49793ad→a6e224c.
Note
mc-art doctor caught the installer's clone being one commit behind before this release — the
commit being this fix — and said which side was stale. Fast-forwarding that clone is now part of the
re-vendor step; without it the package would have shipped the broken model writer again.
0.2.7:母模型被取成空壳时整条链就断,而报告说「原因不明」
dsh-mc-art-panel 0.2.7
0.2.7
Fixed
- A block whose model parents
minecraft:block/cube_allcould report "the chain is complete, but
not one face was drawn" with原因:unknown. Two separate defects sat behind that one message:- The parent fallback chain accepted any truthy result as "resolved", so a parent fetched as
an empty shell ({}/{textures:{}}) short-circuited the built-in vanilla parent table
and the chain ended with no geometry. An empty shell is not a resolution. This is not a
hypothetical shape: the game's ownblock/blockcarries onlydisplay/gui_light— no
elements, no parent — so an ordinary chain really does contain one. no-quadswas only set whenelements !== undefined, so "the whole chain has no elements" fell
through tounknown— andunknownis not a diagnosis. It is nowno-geometry, and the
text names the real cause (a parent that could not be fetched) and says explicitly that this is
not evidence of a block entity.
- The parent fallback chain accepted any truthy result as "resolved", so a parent fetched as
- The report's line about the built-in parent table printed "(这次没走到)" whenever nothing was
missing — i.e. it claimed the table had not been used even when the table was what resolved the
chain. It now says what actually happened: the keys it hit and which one caught the chain, or that
it was consulted and did not have the key, or that it was not needed at all. tools/mcart-plugin/parent-fallback-test.js: a self-contained project whose pack contains an empty
shell must still draw; the control (nocube_allin the pack, so the built-in table must do the
work) must not go red; and the reason must not beunknown. The reverse fixture turns three
assertions red.
Note
The build that produced the report predated vanillaBare() (present from 0.2.3): a project model
written the way vanilla writes it resolved to nothing there. Worth recording because the panel's
host half only reloads when DSH is fully restarted — approving a new version is not enough on
its own.
Changed
- Vendored
mc-artsnapshot unchanged (49793ad): this release is panel-side only.
0.2.6:那条嵌入带量错了东西;判定器在含空格路径上跑不起来
dsh-mc-art-panel 0.2.6
0.2.6
This release is mostly one thing a user's own second session measured and wrote down: a
757-line log of what actually cost time while building a mod with these tools. Its first
finding was a defect in a gate we shipped two releases earlier.
Fixed
- The embedding band was measuring the wrong thing.
accent_base_gap's default 6..24 came
fromiron_ore, and it was the mean of a whole ore cluster, not of a speck. Measured across
all eight vanilla ores the figure runs −75.7 (redstone) … +106.6 (gold) and none of them
falls inside 6..24. Using the default as an ore's target compresses a deposit that should read
as bright into a recessive smudge — the session did that for seven rounds. The constants are now
named for their owner (ITEM_ACCENT_GAP*), the vanilla ore range is published as a fact,
accent_base_gap_min/maxdefault toNoneso the engine can tell a default from a
declaration, and an asset declared as a deposit that declares no band is refused with the
way out in the message. The default was not loosened: that would refuse items. mc-art gap-from-refsmeasures the band from your own references, and reports the
per-deposit figure (the one to declare) separately from the per-pixel boundary figure —
stating that averaging a cluster first is exactly how12.24was produced, and printing its mask
rule, because a different mask gives a different number.- The judge could not run on a path with spaces.
list2cmdline()was handed tosubprocessas
a single argv element, so cmd received a literal\"…\"and answered
'…' is not recognized— which looks like a Gradle failure. The user's own project path
(Release 2.8.3) has a space, so this was blocking. Windows now gets one command line. --faultreturned 0 even when it caught nothing, which made "the checker can say no"
unfalsifiable. It now returns 4 when the injected fault goes undetected (1 stays "the verdict
did not pass"), and says that the tool's own exit code carries no verdict.--fault's injection point was hardcoded to the example mod's expression, so any new project
had to writeExampleMod.EXAMPLE_BLOCKverbatim — polluting the subject to satisfy the tool.
--fault-find/--fault-replacewere added; the old pair stays as a compatibility default and
the failure now points at the flag.- The judge did not manage Gradle's home, and the default one is read-only to a sandboxed
process, so the wrapper died creating a lock file. It now probes candidates, really creates a
lock file to prove writability, prints which home it chose and why each other was rejected, and
passesGRADLE_USER_HOME. (gradlew's-gcannot fix this: the wrapper parses it only when it
precedes the task name.) geometry.uv_regionssilently cancelled contour conformance (appearance_onlyplus declared
regions degrade an item to a full opaque quad — measured 0 transparent pixels where vanilla has
188). The two declarations cancelling out are now reported.
Added
mc-art doctor— platform, engine root, module count, which interpreter works and why each
candidate was rejected, whether the three entry points really run, line endings against
git check-attr, writability, and whether the engine copies on this machine agree. On its first
run it caught a stale~/.dsh/skills/mc-artand said which side was behind.scripts/check-ore-gap.py(an undeclared ore is refused, a declared one passes; both
directions proven) andscripts/check-tiling.py— a real tiling-seam gate counting pattern
pixels on row 0/15 or column 0/15 against a declaredtiling_min_margin. Six of eight vanilla
ores keep a margin of 1; only emerald touches the edge, and the message says so.tests/test_doc_counts.py— the module count a document claims is compared against
mc_art/*.py, so the number can no longer drift (it caughtdoctor.pyimmediately: 34).
Changed
- The skill now teaches the path that was missing. Measure the reference corpus first —
colour and shape grammar (per-face blush count, cluster size, fill ratio, thickness, luma
levels; the vanilla ore contract measured across seven ores is 6–9 clusters, 4–29 px,
fill 0.70–0.84, thickness 5–9, 2–5 levels) — then state per-asset-class success criteria, then
draw. Plus: which gates are declarable versus fixed, that "attached a reference" is not "used the
reference", that layer matching runs both ways, and that the band a category needs comes from
its own references.windows.mdgained the measured PowerShell traps (write a.py, never
inline;Set-Content -Encoding UTF8writes a BOM that breaksjson.load), andtraps.mdgained
the one that quietly destroys good pixels: a "repair" step written before its premise was checked. - Vendored
mc-artsnapshot:427fd01→49793ad.
0.2.5:你自己包里的贴图保存不了(那条消息在撒谎)
dsh-mc-art-panel 0.2.5
0.2.5
Fixed
- Every texture in your own project pack refused to save. The panel said "this texture handle
is not a relative path inside the project pack" while the path plainly was inside your pack:
the sentence was true about the shape and false about the reason. The host stored your
project's own textures as absolute paths (preload()), that value travelled to the editor as
its save handle, and the client's safety check rejects drive-letter paths — so no texture in your
own pack could be saved, and the write path was never reached at all. The host now stores
pack-relative handles and resolves them against the project root when reading; the in-pack test
normalises separators, case and./..and compares real paths, and it accepts an in-pack
absolute path as well, so a stray absolute handle cannot lock you out again. The rejection
message now names what is actually wrong — empty / NUL / drive-letter / leading slash /../
outside the pack, five distinct reasons — instead of one sentence that blames your own pack. tools/mcart-plugin/texture-edit-test.js: the handle must pass the real client check
(safeTextureHandle, pulled out ofclient.jsrather than re-implemented) and the host must
actually land the bytes in the project pack (before/after compared). The reverse fixture puts the
absolute path back and turns six assertions red — including the message users actually saw,
verbatim — with the file unchanged at 224 B, i.e. not one byte written.
Changed
- Vendored
mc-artsnapshot unchanged (cf39eba): this release is panel-side only.