Compare commits

...

1466 commits

Author SHA1 Message Date
Anon
d50e90d860
fix: send dedicated attack packet on 26.1+
Some checks failed
Build MCC and Documents / determine-build (push) Has been cancelled
Build MCC and Documents / fetch-translations (push) Has been cancelled
Build MCC and Documents / create-tag (push) Has been cancelled
Build MCC and Documents / build (linux-arm) (push) Has been cancelled
Build MCC and Documents / build (linux-arm64) (push) Has been cancelled
Build MCC and Documents / build (linux-x64) (push) Has been cancelled
Build MCC and Documents / build (osx-arm64) (push) Has been cancelled
Build MCC and Documents / build (osx-x64) (push) Has been cancelled
Build MCC and Documents / build (win-arm64) (push) Has been cancelled
Build MCC and Documents / build (win-x64) (push) Has been cancelled
Build MCC and Documents / build (win-x86) (push) Has been cancelled
Build MCC and Documents / create-release (push) Has been cancelled
fix: send dedicated attack packet on 26.1+
2026-08-11 19:02:13 +02:00
Anon
196dc54222 fix: send dedicated attack packet on 26.1+ 2026-08-11 18:43:06 +02:00
Anon
a0710fd82f
feat: expose block state properties through MCP
feat: expose block state properties through MCP
2026-08-11 17:57:33 +02:00
Anon
cfb77088b6 feat: add block state data to all palettes 2026-08-11 16:44:16 +02:00
Anon
f1d844afbe feat: expose block state properties through MCP 2026-08-11 14:51:13 +02:00
Anon
1fd4b0244d
[skipci]Merge pull request #3202 from MCCTeam/dependabot/npm_and_yarn/docs/mermaid-11.16.1
chore(deps-dev): bump mermaid from 11.15.0 to 11.16.1 in /docs
2026-08-09 19:55:10 +02:00
Anon
844fa7af2e
[skipci]Merge pull request #3201 from MCCTeam/dependabot/npm_and_yarn/docs/fast-uri-3.1.5
chore(deps): bump fast-uri from 3.1.4 to 3.1.5 in /docs
2026-08-09 19:55:01 +02:00
Anon
9523275eb6
[skipci]Merge pull request #3200 from MCCTeam/dependabot/npm_and_yarn/docs/undici-7.29.0
chore(deps): bump undici from 7.28.0 to 7.29.0 in /docs
2026-08-09 19:54:51 +02:00
Anon
8e11304bf9
fix: Colored Timestamps
It solves the problem of timestamps being colored according to the last message's color.
2026-08-09 19:54:22 +02:00
dependabot[bot]
34e9fd46fd
chore(deps-dev): bump mermaid from 11.15.0 to 11.16.1 in /docs
Bumps [mermaid](https://github.com/mermaid-js/mermaid) from 11.15.0 to 11.16.1.
- [Release notes](https://github.com/mermaid-js/mermaid/releases)
- [Commits](https://github.com/mermaid-js/mermaid/compare/mermaid@11.15.0...mermaid@11.16.1)

---
updated-dependencies:
- dependency-name: mermaid
  dependency-version: 11.16.1
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-08 04:51:56 +00:00
dependabot[bot]
15dd55d10a
chore(deps): bump fast-uri from 3.1.4 to 3.1.5 in /docs
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.4 to 3.1.5.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.4...v3.1.5)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-05 15:33:07 +00:00
dependabot[bot]
8f8e03b1c9
chore(deps): bump undici from 7.28.0 to 7.29.0 in /docs
Bumps [undici](https://github.com/nodejs/undici) from 7.28.0 to 7.29.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v7.28.0...v7.29.0)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 7.29.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-04 09:58:03 +00:00
Somersault
c9225aac58 Zaman damgalarının son mesaj rengine göre renklenme sorununu çözer. 2026-08-01 19:26:22 +03:00
Anon
7b100a3149
fix: accept semicolonless script using directives - #3196
fix: accept semicolonless script using directives
2026-07-31 19:17:40 +02:00
Anon
dbce402842 fix: accept semicolonless script using directives
Fixes #3195
2026-07-31 19:12:51 +02:00
Anon
503652a760
fix: decode modern chat type holders correctly 1.21.1+
fix: decode modern chat type holders correctly
2026-07-27 22:25:07 +02:00
Anon
3ae1d746fa fix: decode modern chat type holders correctly 2026-07-27 21:58:01 +02:00
Anon
4a68205f02
[skipci]Merge pull request #3190 from MCCTeam/dependabot/npm_and_yarn/docs/lodash-es-4.18.1
chore(deps): bump lodash-es from 4.17.23 to 4.18.1 in /docs
2026-07-27 19:14:14 +02:00
Anon
c377e52306
[skipci]Merge pull request #3191 from MCCTeam/dependabot/npm_and_yarn/docs/ws-8.21.1
chore(deps): bump ws from 8.20.0 to 8.21.1 in /docs
2026-07-27 19:14:04 +02:00
Anon
7fee87c98f
[skipci]Merge pull request #3192 from MCCTeam/dependabot/npm_and_yarn/docs/postcss-8.5.23
chore(deps): bump postcss from 8.5.14 to 8.5.23 in /docs
2026-07-27 19:13:57 +02:00
dependabot[bot]
07aa032214
chore(deps): bump postcss from 8.5.14 to 8.5.23 in /docs
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.14 to 8.5.23.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.14...8.5.23)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-27 16:57:56 +00:00
dependabot[bot]
6b0f1a8f77
chore(deps): bump ws from 8.20.0 to 8.21.1 in /docs
Bumps [ws](https://github.com/websockets/ws) from 8.20.0 to 8.21.1.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.20.0...8.21.1)

---
updated-dependencies:
- dependency-name: ws
  dependency-version: 8.21.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-27 16:57:44 +00:00
dependabot[bot]
a780312c19
chore(deps): bump lodash-es from 4.17.23 to 4.18.1 in /docs
Bumps [lodash-es](https://github.com/lodash/lodash) from 4.17.23 to 4.18.1.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

---
updated-dependencies:
- dependency-name: lodash-es
  dependency-version: 4.18.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-27 16:57:40 +00:00
Anon
19f02dfc25
[skipci]chore: update build dependencies
chore: update build dependencies
2026-07-27 18:56:19 +02:00
Anon
dc472c3df6 chore: update build dependencies 2026-07-27 17:58:08 +02:00
Anon
90fda17365
Fix: prevent duplicate AutoRelog retries (#3186)
Fix: prevent duplicate AutoRelog retries (#3186)
2026-07-27 17:34:57 +02:00
Anon
5655e3fc89 Fix restart publication races (#3186)
Prepare offline routing before restart requests become observable, reject stale route owners, and wait for source-client cleanup before executing automatic retries.

Add deterministic publication-order, cleanup-gate, and stale-route regression tests.
2026-07-27 17:26:52 +02:00
Anon
456a548cbc Fix: make AutoRelog retries single-owner (#3186)
Login rejections could schedule and execute multiple restarts for one failure while leaving no usable console route during reconnect delays.

Changes:
- Bind failure and restart work to immutable connection attempts
- Coalesce automatic retries while allowing explicit settings replacement until commit
- Preserve held bots and offline command routing across failed logins
- Add deterministic retry, ownership, and routing regression tests

Fixes #3186
2026-07-27 17:26:52 +02:00
Anon
92212d2b95
Merge pull request #3187 from MCCTeam/fix/configuration-disconnect-reason
fix: preserve queued disconnect reason
2026-07-27 14:12:00 +02:00
Anon
eea631f69e fix: preserve queued disconnect reason 2026-07-27 00:35:18 +02:00
Anon
6e4bca5073
feat: Added first-time guided login + simplifed Yggdrasil configuration
feat: add guided login and authlib URL setup
2026-07-26 18:13:44 +02:00
Anon
630a5fabef feat: add guided login and authlib URL setup 2026-07-26 14:17:59 +02:00
Anon
47bc47786a
fix: preserve account selection across reconnects
fix: preserve account selection across reconnects
2026-07-26 01:31:50 +02:00
Anon
9b90b535d8 fix: isolate queued restart settings 2026-07-26 01:16:07 +02:00
Anon
1686d00f30 fix: use selected account for offline reconnect 2026-07-26 01:08:14 +02:00
Anon
23b83a45f5
[skipci]Merge pull request #3175 from MCCTeam/dependabot/npm_and_yarn/docs/linkify-it-5.0.2
chore(deps): bump linkify-it from 5.0.1 to 5.0.2 in /docs
2026-07-22 21:26:51 +02:00
Anon
97631acc55
[skipci]Merge pull request #3174 from MCCTeam/dependabot/npm_and_yarn/docs/fast-uri-3.1.4
chore(deps): bump fast-uri from 3.1.2 to 3.1.4 in /docs
2026-07-22 21:26:40 +02:00
Anon
03beb51fb7
[skipci]Merge pull request #3176 from MCCTeam/dependabot/npm_and_yarn/docs/webpack-dev-server-5.2.6
chore(deps): bump webpack-dev-server from 5.2.5 to 5.2.6 in /docs
2026-07-22 21:26:31 +02:00
Anon
9d1c7ac4bd
[skipci]Merge pull request #3177 from MCCTeam/dependabot/npm_and_yarn/docs/shell-quote-1.10.0
chore(deps): bump shell-quote from 1.8.4 to 1.10.0 in /docs
2026-07-22 21:26:21 +02:00
Anon
668cbf7e6a
[skipci]Merge pull request #3178 from MCCTeam/dependabot/npm_and_yarn/docs/immutable-5.1.9
chore(deps): bump immutable from 5.1.5 to 5.1.9 in /docs
2026-07-22 21:26:11 +02:00
Anon
bf99df7cde
[skipci]Merge pull request #3179 from MCCTeam/dependabot/npm_and_yarn/docs/svgo-4.0.2
chore(deps): bump svgo from 4.0.1 to 4.0.2 in /docs
2026-07-22 21:26:02 +02:00
Anon
4c6b2b3190
[skipci]chore(deps): bump dompurify from 3.4.11 to 3.4.12 in /docs
chore(deps): bump dompurify from 3.4.11 to 3.4.12 in /docs
2026-07-22 21:25:49 +02:00
dependabot[bot]
fd0c99b2d3
chore(deps): bump dompurify from 3.4.11 to 3.4.12 in /docs
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.4.11 to 3.4.12.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.4.11...3.4.12)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-version: 3.4.12
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-22 18:57:02 +00:00
dependabot[bot]
ba134476af
chore(deps): bump shell-quote from 1.8.4 to 1.10.0 in /docs
Bumps [shell-quote](https://github.com/ljharb/shell-quote) from 1.8.4 to 1.10.0.
- [Changelog](https://github.com/ljharb/shell-quote/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/shell-quote/compare/v1.8.4...v1.10.0)

---
updated-dependencies:
- dependency-name: shell-quote
  dependency-version: 1.10.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-22 18:57:01 +00:00
dependabot[bot]
1dc1d06f51
chore(deps): bump immutable from 5.1.5 to 5.1.9 in /docs
Bumps [immutable](https://github.com/immutable-js/immutable-js) from 5.1.5 to 5.1.9.
- [Release notes](https://github.com/immutable-js/immutable-js/releases)
- [Changelog](https://github.com/immutable-js/immutable-js/blob/main/CHANGELOG.md)
- [Commits](https://github.com/immutable-js/immutable-js/compare/v5.1.5...v5.1.9)

---
updated-dependencies:
- dependency-name: immutable
  dependency-version: 5.1.9
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-22 18:57:01 +00:00
dependabot[bot]
78da20b4e4
chore(deps): bump svgo from 4.0.1 to 4.0.2 in /docs
Bumps [svgo](https://github.com/svg/svgo) from 4.0.1 to 4.0.2.
- [Release notes](https://github.com/svg/svgo/releases)
- [Commits](https://github.com/svg/svgo/compare/v4.0.1...v4.0.2)

---
updated-dependencies:
- dependency-name: svgo
  dependency-version: 4.0.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-22 18:57:01 +00:00
dependabot[bot]
a951b5b6c6
chore(deps): bump webpack-dev-server from 5.2.5 to 5.2.6 in /docs
Bumps [webpack-dev-server](https://github.com/webpack/webpack-dev-server) from 5.2.5 to 5.2.6.
- [Release notes](https://github.com/webpack/webpack-dev-server/releases)
- [Changelog](https://github.com/webpack/webpack-dev-server/blob/v5.2.6/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-dev-server/compare/v5.2.5...v5.2.6)

---
updated-dependencies:
- dependency-name: webpack-dev-server
  dependency-version: 5.2.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-22 18:56:57 +00:00
dependabot[bot]
4a2837d862
chore(deps): bump linkify-it from 5.0.1 to 5.0.2 in /docs
Bumps [linkify-it](https://github.com/markdown-it/linkify-it) from 5.0.1 to 5.0.2.
- [Changelog](https://github.com/markdown-it/linkify-it/blob/master/CHANGELOG.md)
- [Commits](https://github.com/markdown-it/linkify-it/compare/5.0.1...5.0.2)

---
updated-dependencies:
- dependency-name: linkify-it
  dependency-version: 5.0.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-22 18:56:54 +00:00
dependabot[bot]
85672cc0a2
chore(deps): bump fast-uri from 3.1.2 to 3.1.4 in /docs
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.2 to 3.1.4.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.2...v3.1.4)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-22 18:56:53 +00:00
Anon
b1200af588
fix: Auto Relog reconnect lifecycle
fix: Auto Relog reconnect lifecycle
2026-07-22 17:54:46 +02:00
Anon
64c1dc55e0 Fix Auto Relog reconnect lifecycle 2026-07-19 14:42:10 +02:00
Anon
c19fdd6634
fix: Exit on failure setting
fix: Exit on failure setting
2026-07-19 11:26:45 +02:00
Anon
fceed9b4d7 chore: remove run-exit-on-failure-test.sh 2026-07-19 11:23:31 +02:00
Anon
25bbe35718 fix: exit on failure instead of prompting 2026-07-17 19:16:00 +02:00
Anon
419c140dc4
[skipci]Merge pull request #3168 from MCCTeam/dependabot/npm_and_yarn/docs/websocket-driver-0.7.5
chore(deps): bump websocket-driver from 0.7.4 to 0.7.5 in /docs
2026-07-17 07:48:46 +02:00
dependabot[bot]
720183955d
chore(deps): bump websocket-driver from 0.7.4 to 0.7.5 in /docs
Bumps [websocket-driver](https://github.com/faye/websocket-driver-node) from 0.7.4 to 0.7.5.
- [Changelog](https://github.com/faye/websocket-driver-node/blob/main/CHANGELOG.md)
- [Commits](https://github.com/faye/websocket-driver-node/compare/0.7.4...0.7.5)

---
updated-dependencies:
- dependency-name: websocket-driver
  dependency-version: 0.7.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-15 22:09:19 +00:00
Anon
142fb107db
feat: Added Minecraft 26.2 support
Add Minecraft 26.2 support (protocol 776)
2026-07-04 21:58:48 +02:00
Anon
99f5744715
feat: Expose NBT/component data in inventory MCP tools
feat(inventory): expose NBT/component data in inventory MCP tools
2026-07-04 21:53:42 +02:00
Reed Pennock
d1df44aae5 chore: Update physics shapes, minimap data and version table for 26.2
- BlockShapeData.json: add the 28 new sulfur/cinnabar blocks by copying
  shape entries from analogous blocks (stone, stone_slab, stone_stairs,
  stone_brick_wall, pointed_dripstone); state counts verified against the
  26.2 server blocks.json. PrismarineJS minecraft-data has no 26.x data
  yet, so these should be regenerated once it does.
- MinimapBlockColors.json: add new blocks with MapColor values taken from
  the decompiled 26.2 Blocks.java (COLOR_YELLOW / GOLD / COLOR_RED).
  Merged by hand because gen_block_color_map.py cannot parse the new
  BlockItemIds-based registration format yet.
- MinimapEntityCategories.json: add SulfurCube as hostile
  (MobCategory.MONSTER in EntityTypes.java, which now holds entity
  registrations instead of EntityType.java).
- AGENTS.md: add the 26.2 row to the version support table.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 16:43:44 -05:00
Reed Pennock
e4161af158 feat: Wire MC 26.2 (protocol 776) routing and adapt Teams packet parsing
- Add MC_26_2_Version = 776 and bump all upper-bound feature gates
- Route 26.2 to the new item/block/entity palettes and
  StructuredComponentsRegistry262
- Reuse PacketPalette261 (play/config packet IDs are unchanged in 26.2;
  the only registry change is spectate_entity renamed to spectator_action
  at the same ID, which MCC does not send) and EntityMetadataPalette261
  (serializer list is identical)
- Add a 26.2 branch for Set Player Team parsing: field order changed to
  displayName, prefix, suffix, visibility, collision rule, then color as
  Optional<TeamColor> (absent maps to -1) and options byte last
- Register protocol 776 in both supported-protocol lists and the
  version string mappings; bump MCHighestVersion to 26.2

JoinGame gained a trailing onlineMode bool and LoginFinished a trailing
session UUID in 26.2; both sit after every field MCC reads, so parsing
is unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 16:43:31 -05:00
Reed Pennock
22685a720c feat: Add MC 26.2 palettes, registries and new sulfur/cinnabar content
Generated from the 26.2 server data reports (registries.json / blocks.json):
- ItemPalette262 (1537 items, 31 new; IDs shifted by early sulfur/cinnabar inserts)
- Palette262 blocks (1196 blocks, 32366 states, 28 new)
- EntityPalette262 (158 entities, new sulfur_cube)
- StructuredComponentsRegistry262 with new sulfur_cube_content component
  at ID 78 (shifts IDs 78-109 up by one); wire format is one ItemStackTemplate
- New ItemType/Material/EntityType enum entries for the sulfur and
  cinnabar families, MusicDiscBounce, SulfurSpike and SulfurCube

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 16:43:20 -05:00
Ítalo Seara
f34b8ba989 feat(inventory): expose NBT/component data in inventory MCP tools
Add a nullable `Nbt` field to `MccInventorySnapshotSlot`,
`MccInventorySearchMatch`, and `MccItemStackSnapshot` so that callers
can access the full item metadata beyond just material and count.

For 1.20.6+ servers the field is a map of component name
(e.g. "minecraft:custom_data") to the serialized component object.
For legacy servers it is the raw NBT dictionary. The field is omitted
entirely for vanilla items that carry no extra data, so there is no
noise for plain items like Stone or Dirt.

Implementation:
- `StructuredComponent`: add `ComponentName` property (set by the
  registry during parse) and mark both it and `TypeId` with
  `[JsonIgnore]` so they are excluded from component serialization.
- `StructuredComponentRegistry.ParseComponent`: assign `ComponentName`
  after instantiation.
- `MccGameCommon.BuildNbt`: new helper that serializes components by
  runtime type (fixing the polymorphism issue with System.Text.Json)
  keyed by component name, falling back to the legacy NBT dictionary.
- Snapshot and search query builders updated to call `BuildNbt`.
2026-06-27 14:41:41 -03:00
Anon
95031338bf
feat: Added Data Path utility for C# scripts/ChatBots
Adds a utility class that allows C# scripts to init a configuration folder for them and get it's path.
2026-06-25 23:10:18 +02:00
Anon
d3c87fcd36
[skipci]chores: Updated skills
chores: Updated skills
2026-06-25 23:06:35 +02:00
Anon
3c452dfcc5 Updated skills 2026-06-25 23:02:43 +02:00
Andy
aee35c3f58
Add English translations to DataPath comments
Updated comments to include English translations for clarity.
2026-06-21 10:53:11 +08:00
Anon
c23a71c489
[skipci]Merge pull request #3159 from MCCTeam/dependabot/npm_and_yarn/docs/webpack-dev-server-5.2.5
chore(deps): bump webpack-dev-server from 5.2.4 to 5.2.5 in /docs
2026-06-20 23:05:44 +02:00
dependabot[bot]
800f757804
chore(deps): bump webpack-dev-server from 5.2.4 to 5.2.5 in /docs
Bumps [webpack-dev-server](https://github.com/webpack/webpack-dev-server) from 5.2.4 to 5.2.5.
- [Release notes](https://github.com/webpack/webpack-dev-server/releases)
- [Changelog](https://github.com/webpack/webpack-dev-server/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-dev-server/compare/v5.2.4...v5.2.5)

---
updated-dependencies:
- dependency-name: webpack-dev-server
  dependency-version: 5.2.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-20 21:01:34 +00:00
Anon
e0ba34f7fe
[skipci]Merge pull request #3156 from MCCTeam/dependabot/npm_and_yarn/docs/undici-7.28.0
chore(deps): bump undici from 7.24.5 to 7.28.0 in /docs
2026-06-20 23:00:36 +02:00
Anon
9edf53250a
[skipci]Merge pull request #3158 from MCCTeam/dependabot/npm_and_yarn/docs/dompurify-3.4.11
chore(deps): bump dompurify from 3.4.10 to 3.4.11 in /docs
2026-06-20 23:00:26 +02:00
dependabot[bot]
3501ea142f
chore(deps): bump dompurify from 3.4.10 to 3.4.11 in /docs
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.4.10 to 3.4.11.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.4.10...3.4.11)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-version: 3.4.11
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-20 17:15:53 +00:00
dependabot[bot]
e8afeea3d6
chore(deps): bump undici from 7.24.5 to 7.28.0 in /docs
Bumps [undici](https://github.com/nodejs/undici) from 7.24.5 to 7.28.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v7.24.5...v7.28.0)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 7.28.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-20 10:57:02 +00:00
Andy
aa1b6f968e
Add DataPath.cs and revert CSharpRunner.cs changes
# Submission Instructions

## Content of this submission

### 1.  Synchronize official CSharpRunner.cs
- Synchronize `CSharpRunner.cs` to the latest official version
- **Removed** extended support for non-standard metadata formats (XML, C# style, JS style)
- Restore to the official standard metadata parsing method

### 2.  Migrate DataPath.cs
- Migrate `DataPath.cs` to the new version of the code repository
- Maintain the original functionality unchanged:
  - `DataPath.Init("ScriptName")` - create a configuration folder
  - `DataPath.Get()` - Gets the path of the configuration folder

## Reason for change
1. **Facilitate official merging**: Retaining custom metadata formats increases the risk of conflicts with the official codebase. Removing them allows for smoother acceptance of official updates
2. **Reduce maintenance costs**: The official CSharpRunner.cs undergoes frequent changes, making the maintenance of custom branches a significant workload
3. **Maintain consistency**: Keep consistent with the official version to avoid compatibility issues caused by format differences

## Scope of impact
- Previously supported non-standard metadata formats (XML, C# style, JS style) will no longer be recognized
- Only supports official standard metadata formats
- The functionality of DataPath.cs remains unaffected, and the configuration management function is still operational and available

## Remarks
- DataPath.cs and CSharpRunner.cs have previously been modified, and this time it is only for migration and synchronization purposes
- AI-assisted participation was involved in the previous modification process
2026-06-19 13:18:04 +08:00
Anon
25a2f5a4a3
bugfix: handle null/empty profile name in ProfileComponent serialization
fix: handle null/empty profile name in ProfileComponent serialization
2026-06-17 11:31:17 +02:00
Anon
85fe6b451b fix: handle null/empty profile name in ProfileComponent serialization
Prevents NullReferenceException crash when receiving player head items
with an empty or absent profile name. The Minecraft protocol permits
empty names in the profile component; the serialization path now
falls back to an empty string instead of throwing.
2026-06-17 11:27:23 +02:00
Anon
72200fc1ef
bugfix: restore full color depth for hex color codes (§#RRGGBB)
bugfix: restore full color depth for hex color codes (§#RRGGBB)
2026-06-17 11:07:59 +02:00
Anon
c05c1f3c02
[skipci]Merge pull request #3148 from MCCTeam/dependabot/npm_and_yarn/docs/launch-editor-2.14.1
chore(deps): bump launch-editor from 2.13.2 to 2.14.1 in /docs
2026-06-17 11:06:04 +02:00
Anon
73377685b4 fix: restore full color depth for hex color codes (§#RRGGBB)
After the dialog system PR (#3143), ResolveHexColors in ClassicConsoleBackend
mapped every §#RRGGBB hex color to the nearest of 16 standard Minecraft colors
via NearestMcColor. This meant all server-sent hex colors were downgraded to
4-bit ANSI regardless of the user's ConsoleColorMode setting.

Replaced the nearest-color lookup with ColorHelper.GetColorEscapeCode, which
generates the right output for each mode: 24-bit ANSI in vt100_24bit mode, 8-bit
in vt100_8bit, 4-bit in vt100_4bit, ConsoleColor in legacy_4bit.

Fixes #3146.
2026-06-17 11:04:06 +02:00
Anon
e6b461e7b2
[skipci]Merge pull request #3149 from MCCTeam/dependabot/npm_and_yarn/docs/markdown-it-14.2.0
chore(deps): bump markdown-it from 14.1.1 to 14.2.0 in /docs
2026-06-17 10:49:23 +02:00
dependabot[bot]
327d3a1c37
chore(deps): bump markdown-it from 14.1.1 to 14.2.0 in /docs
Bumps [markdown-it](https://github.com/markdown-it/markdown-it) from 14.1.1 to 14.2.0.
- [Changelog](https://github.com/markdown-it/markdown-it/blob/master/CHANGELOG.md)
- [Commits](https://github.com/markdown-it/markdown-it/compare/14.1.1...14.2.0)

---
updated-dependencies:
- dependency-name: markdown-it
  dependency-version: 14.2.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-17 08:40:45 +00:00
dependabot[bot]
ef1c8fe740
chore(deps): bump launch-editor from 2.13.2 to 2.14.1 in /docs
Bumps [launch-editor](https://github.com/vitejs/launch-editor) from 2.13.2 to 2.14.1.
- [Commits](https://github.com/vitejs/launch-editor/compare/v2.13.2...v2.14.1)

---
updated-dependencies:
- dependency-name: launch-editor
  dependency-version: 2.14.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-17 08:40:37 +00:00
Anon
31876d485a
[skipci]Merge pull request #3147 from MCCTeam/dependabot/npm_and_yarn/docs/dompurify-3.4.10
chore(deps): bump dompurify from 3.4.0 to 3.4.10 in /docs
2026-06-17 10:39:13 +02:00
dependabot[bot]
3f71f7afef
chore(deps): bump dompurify from 3.4.0 to 3.4.10 in /docs
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.4.0 to 3.4.10.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.4.0...3.4.10)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-version: 3.4.10
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-17 05:39:12 +00:00
Anon
aaa4908f7d
feat: Implement the Dialog System (1.21.6+)
feat: Implement the Dialog System (1.21.6+)
2026-06-14 02:31:50 +02:00
Anon
7f2a71f9fe Messaging improvements + Added auto show dialogs in classic console mode 2026-06-14 02:28:13 +02:00
Anon
c0d983272b Cosmetic changes, UX/UI improvements in TUI mode, added colored text support in dialogs 2026-06-14 02:11:04 +02:00
Anon
2aa85cbb17 Added Docs, Added Translations for Dialog Types 2026-06-14 01:25:18 +02:00
Anon
bd29c7fc5c Fixes to Dialogs + Full integration testing script, Fully Tested in CLI mode 2026-06-14 01:05:12 +02:00
Anon
35db711ea4
feat: Add script line and column details to C# compile errors
feat: Add script line and column details to C# compile errors
2026-06-14 00:06:25 +02:00
Anon
3d988c932f Dialog System First iteration, not tested 2026-06-13 23:59:44 +02:00
copilot-swe-agent[bot]
a1b542dad6
Tidy script diagnostic helpers 2026-06-13 21:49:12 +00:00
copilot-swe-agent[bot]
7d7b880a7c
Preserve script compile source locations 2026-06-13 21:41:52 +00:00
Anon
37cf19c175
bugfix: Protocol gap fixes (Entity Effect Duration, Villager Trading on 1.20.6+, Enchanting effected)
bugfix: Protocol gap fixes (Entity Effect Duration, Villager Trading on 1.20.6+, Enchanting effected)
2026-06-12 01:14:28 +02:00
Anon
5e5fa539bb protocol gap fixes 2026-06-12 01:05:19 +02:00
Anon
981a996344
bugfix: Fixed and tested all structured components and issues with Empty packets sent by some servers
bugfix: Fixed and tested all structured components and issues with Empty packets sent by some servers
2026-06-11 22:05:35 +02:00
Anon
98dfde6cc2 Gate empty-packet log under debug, add packet exclusion list
- Change empty packet log from log.Warn to log.Debug so it only
  shows when DebugMessages is enabled
- Add PacketDebugExclusions config (List<string>) to suppress
  specific packet types like KeepAlive, Ping from packet debug output
- Check exclusion in both LogIncomingPacket and LogOutgoingPacket
- Add ConfigComments resource entry for the new setting
2026-06-11 22:03:36 +02:00
Anon
28e845d1ca Add structured component test reference to AGENTS.md and integration testing skill
- AGENTS.md: instruct to never generate config files in repo root
- SKILL.md: add structured components test mode (section 4) with
  usage example and script reference
2026-06-11 21:56:35 +02:00
Anon
de96462659 Fix structured components: audit fixes, codec helpers, and serialize implementations
- Fix 5 class naming typos: Unbrekable->Unbreakable, Blook->Book,
  Omnious->Ominous, FoodComponentComponent->FoodComponent
- Fix IntangibleProjectileComponent: extends EmptyComponent (Unit type)
- Delete dead code JukeBoxPlayableComponent.cs (duplicated)
- Implement proper Serialize() on BlocksAttacksComponent,
  KineticWeaponComponent, PiercingWeaponComponent
- Extract shared SoundEventHolder/HolderSet codec helpers into
  StructuredComponentCodecHelpers
- Add TypedEntityDataComponent/TypedBlockEntityDataComponent base classes
  for 1.21.9+ typed entity data format
- Fix variable name: uses1218AttributeAndEquippableFormats ->
  uses1216AttributeAndEquippableFormats
- Add entity data version gate (1.21.9+) to v1215 registry
- Fix chicken/variant and zombie_nautilus/variant component types
- Fix empty packet hang in Protocol18 ReadNextPacket loop
- Add structured components integration test harness
2026-06-11 21:33:48 +02:00
Anon
02b34a8d13
bugfix: Custom model data decoding for 1.21.4+
bugfix: Custom model data decoding for 1.21.4+
2026-06-11 16:26:28 +02:00
Anon
20756b351e
[skipci]Merge pull request #3136 from MCCTeam/dependabot/npm_and_yarn/docs/shell-quote-1.8.4
chore(deps): bump shell-quote from 1.8.3 to 1.8.4 in /docs
2026-06-11 16:25:01 +02:00
Anon
16637f7eba Fix custom model data decoding for 1.21.4 2026-06-11 16:20:42 +02:00
dependabot[bot]
d38afe8e1e
chore(deps): bump shell-quote from 1.8.3 to 1.8.4 in /docs
Bumps [shell-quote](https://github.com/ljharb/shell-quote) from 1.8.3 to 1.8.4.
- [Changelog](https://github.com/ljharb/shell-quote/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/shell-quote/compare/v1.8.3...v1.8.4)

---
updated-dependencies:
- dependency-name: shell-quote
  dependency-version: 1.8.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-10 17:32:15 +00:00
Anon
883ed12ccd
feat: Patch the client to support Hypixel
feat: Patch the client to support Hypixel
2026-06-10 17:28:01 +02:00
Anon
98d4781d2c add packet debug toggle 2026-06-10 17:24:25 +02:00
Anon
e744ff206b hypixel book fixes 2026-06-10 17:16:30 +02:00
Anon
61c2cbf7c3
bugfix: Fixed Telegram Bridge not displaying player names properly for players with an underscore in their nick names
Update TelegramBridge.cs
2026-06-07 14:11:54 +02:00
werfrag
2e383403c3
Update TelegramBridge.cs
The names of players containing the "_" symbol were not read.
2026-06-07 01:36:38 +02:00
Anon
80c07634e2
bugfix: Fixed not being able to send messages on legacy versions (1.4.6 - 1.6.4)
bugfix: Fixed not being able to send messages on legacy versions (1.4.6 - 1.6.4)
2026-06-06 14:14:52 +02:00
Anon
eeb89d676b Formatting 2026-06-06 14:12:28 +02:00
Anon
9980e08bac Fixed chat on legacy versions 2026-06-06 14:09:54 +02:00
Anon
861084db9b
bugfix: Fixed inventory sync and Script Scheduler dupliating instances of bots on reconnects
bugfix: Fixed inventory sync and Script Scheduler dupliating instances of bots on reconnects
2026-06-06 13:14:29 +02:00
Anon
71f935eaeb
Merge pull request #23 from milutinke/bugfix/script-scheduler-reconnect
bugfix: Fixed Script Scheduler bug
2026-06-06 12:12:11 +02:00
Anon
a5423211ad Fixed Script Scheduler bug 2026-06-06 12:09:36 +02:00
Anon
fc74cc066c
Merge branch 'MCCTeam:master' into master 2026-06-06 11:12:31 +02:00
Anon
5b13e740ef
bugfix: Player inventory state sync from the Container inventory
bugfix: Player inventory state sync from the Container inventory
2026-06-06 10:35:53 +02:00
Anon
b1d02edd99 Remove local inventory report from branch 2026-06-06 10:27:20 +02:00
Anon
6bfcd9e9ca Fix mirrored player inventory sync 2026-06-06 10:22:45 +02:00
Anon
3c59bfe13a Experimental inventory sync 2026-06-06 09:13:19 +02:00
Anon
654d9d4dd7
Revert inventory sync changes
chores: Revert inventory sync changes
2026-06-06 09:05:40 +02:00
Anon
0a514d1351 Revert inventory sync changes 2026-06-06 09:02:02 +02:00
Anon
913c0f0f72
bugfix: Fix offline LAN encrypted login
bugfix: Fix offline LAN encrypted login
2026-06-05 22:14:10 +02:00
Anon
4bbc751cc1 Fix offline LAN encrypted login 2026-06-05 22:09:52 +02:00
Anon
5f0ca8837f
bugfix: Fixed crashing and bugs on 1.9, 1.9.1, 1.9.2, 1.16.2, 1.21.10 and Player Inventory
bugfix: Fixed crashing and bugs on 1.9, 1.9.1, 1.9.2, 1.16.2, 1.21.10 and Player Inventory
2026-06-05 21:46:49 +02:00
Anon
f25fe53881
Merge pull request #20 from milutinke/fix/inventory-version-regressions
chores: Improved skills, pulled from master, formatted, removed unused imports.
2026-06-05 21:19:24 +02:00
Anon
82555bd823 Keep version adaptation skill generalized 2026-06-05 21:17:09 +02:00
Anon
29b0087a3a Merge branch 'master' of https://github.com/MCCTeam/Minecraft-Console-Client into fix/inventory-version-regressions
# Conflicts:
#	MinecraftClient/Mapping/World.cs
2026-06-05 21:13:59 +02:00
Anon
b10bd81bee Keep inventory sweep generalized 2026-06-05 21:00:39 +02:00
Anon
5545aabb60 Add reusable inventory sweep tooling 2026-06-05 20:57:49 +02:00
Anon
c98c2a8f83
Merge pull request #19 from milutinke/fix/inventory-version-regressions
bugfix: Fixed crashing and bugs on 1.9, 1.9.1, 1.9.2, 1.16.2, 1.21.10 and Player Inventory
2026-06-05 20:52:49 +02:00
Anon
b698f122cf
Merge branch 'master' into fix/inventory-version-regressions 2026-06-05 20:52:35 +02:00
Anon
5228670131 Fix inventory handling across protocol versions 2026-06-05 20:26:29 +02:00
Anon
c4df73ab6a
bugfix: Script Scheduler crashing after multiple reconnects
Fix Script bots accumulating across reconnects causing command spam
2026-06-05 08:47:54 +02:00
copilot-swe-agent[bot]
8757533fb9
Fix Script bots accumulating on reconnect by unloading on disconnect
Script ChatBots were persisted in the static botsOnHold list across
reconnects. When ScriptScheduler triggered new scripts on login, the
old Script bots were still running, causing duplicate commands to be
sent simultaneously. This led to command spam and crashes.

Adding OnDisconnect to the Script ChatBot ensures scripts are removed
from the bots list before they can be saved to botsOnHold, preventing
accumulation of duplicate script instances on reconnect.
2026-06-05 06:29:43 +00:00
copilot-swe-agent[bot]
2b05b7420e
Initial plan 2026-06-05 06:23:11 +00:00
Anon
701441d424
[skipci]chores: Documented the new change in Auto Attack bot
Document AutoAttack cooldown range and RandomMode options
2026-06-04 23:54:28 +02:00
copilot-swe-agent[bot]
546345e816
Update AutoAttack bot translation for Cooldown_Time 2026-06-04 19:31:21 +00:00
copilot-swe-agent[bot]
d835da76d2
Update AutoAttack bot Cooldown_Time documentation to reflect new Min/Max/RandomMode options 2026-06-04 18:06:25 +00:00
Anon
6db8c817e0
feat: Auto Attack chat bot -> Add a random cooldown range option
feat: Auto Attack chat bot -> Add a random cooldown range option
2026-06-04 11:48:18 +02:00
Anon
c6ca3dc13d Formatted the code and removed logs from Auto Attack 2026-06-04 11:42:41 +02:00
Anon
a4ff7ae438 feat(AutoAttack): implement random cooldown range for attack timing 2026-06-04 11:20:24 +02:00
Anon
45734ba294
[skipci]chores: Updated Android installation guide
[skipci]chores: Updated Android installation guide
2026-06-03 21:10:47 +02:00
Anon
6670685f51 Updated Android installation guide 2026-06-03 21:08:13 +02:00
Anon
de7af06d11
[skipci]Revert docs changes to fix search
docs: remove committed translation files, keep search freeze fix only
2026-06-03 12:07:47 +02:00
copilot-swe-agent[bot]
59e98867b3
chore: remove generated translation files and revert unrelated changes
Translation files under docs/translations/ are generated by the CI pipeline
and should not be committed. Also reverts unrelated changes to
docs/.vuepress/translations/en.json, docs/package-lock.json, and docs/yarn.lock.
2026-06-03 10:04:54 +00:00
copilot-swe-agent[bot]
a7dd9fff09
fix: remove getExtraFields from searchPlugin to fix search freeze regression
The getExtraFields callback added in 6456149 dumped entire page content
as a single extraFields string. plugin-search joins title+extraFields
with .join(' ') and runs a RegExp against the result for every page on
every keystroke — multi-kilobyte strings per page caused 2–3 s blocking
tasks, freezing the page.

Fix: remove getExtraFields (and the now-unused normalizeSearchText /
htmlEntityMap helpers), restoring the pre-regression search coverage
(page titles + section headings).
2026-06-03 09:32:19 +00:00
copilot-swe-agent[bot]
1796e7f80c
Plan: restore search by removing getExtraFields regression 2026-06-03 09:19:30 +00:00
Anon
e331eae03c
bugfix: Fix Auto Relog not working in certain scenarios
bugfix: Fix Auto Relog not working in certain scenarios
2026-06-02 12:31:49 +02:00
Anon
4cc5fc00c3
bugfix: /useitem offhand handling for edible items
Fix `/useitem` offhand handling for edible items
2026-06-02 10:47:13 +02:00
Anon
03e2e0d3fd
Merge pull request #18 from milutinke/bugfix/autorelog-retry-accounting
bugfix: Fix AutoRelog retry accounting
2026-06-02 10:29:52 +02:00
Anon
47de24cf1d Fix AutoRelog retry accounting 2026-06-02 10:24:59 +02:00
copilot-swe-agent[bot]
04a975d011
fix: support offhand food useitem fallback 2026-06-02 07:57:13 +00:00
copilot-swe-agent[bot]
2d31199f97
Initial plan 2026-06-02 07:43:21 +00:00
Anon
f39fe2d067
Merge pull request #3111 from milutinke/fix/autodig-mining-timing
bugfix: Fixed mining timing and block hadress values
2026-05-23 23:43:27 +02:00
Anon
8e26e55650 Removed a temporary tool tools/verify_mining_data.py 2026-05-23 23:40:41 +02:00
Anon
75f8f29d1a
[skipci]Merge pull request #3110 from MCCTeam/copilot/fix-search-index-details-tag
Index collapsed docs content in site search and fix the ItemType source link
2026-05-23 12:08:07 +02:00
Anon
b74364d465 Fix AutoDig mining timing 2026-05-23 10:56:06 +02:00
copilot-swe-agent[bot]
6456149d39
Fix docs search indexing
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/d698c0ee-5e22-482e-a065-7cc71068340a

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-05-23 07:53:01 +00:00
copilot-swe-agent[bot]
858f88d9ec
Plan docs search fix
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/d698c0ee-5e22-482e-a065-7cc71068340a

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-05-23 07:51:54 +00:00
Anon
a2dabe1aa8
[skipci]Merge pull request #3109 from MCCTeam/dependabot/npm_and_yarn/docs/webpack-dev-server-5.2.4
chore(deps): bump webpack-dev-server from 5.2.3 to 5.2.4 in /docs
2026-05-23 09:45:46 +02:00
dependabot[bot]
67bd944179
chore(deps): bump webpack-dev-server from 5.2.3 to 5.2.4 in /docs
Bumps [webpack-dev-server](https://github.com/webpack/webpack-dev-server) from 5.2.3 to 5.2.4.
- [Release notes](https://github.com/webpack/webpack-dev-server/releases)
- [Changelog](https://github.com/webpack/webpack-dev-server/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-dev-server/compare/v5.2.3...v5.2.4)

---
updated-dependencies:
- dependency-name: webpack-dev-server
  dependency-version: 5.2.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-20 11:10:16 +00:00
Anon
b13511f201
[skipci]Merge pull request #3105 from MCCTeam/dependabot/npm_and_yarn/docs/postcss-8.5.14
chore(deps): bump postcss from 8.5.8 to 8.5.14 in /docs
2026-05-13 11:40:23 +02:00
dependabot[bot]
f91319cdfe
chore(deps): bump postcss from 8.5.8 to 8.5.14 in /docs
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.8 to 8.5.14.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.8...8.5.14)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.14
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-12 20:53:36 +00:00
Anon
44e3685454
[skipci]Merge pull request #3102 from MCCTeam/dependabot/npm_and_yarn/docs/fast-uri-3.1.2
chore(deps): bump fast-uri from 3.1.0 to 3.1.2 in /docs
2026-05-12 19:20:08 +02:00
Anon
5c1361169c
[skipci]Merge pull request #3104 from MCCTeam/dependabot/npm_and_yarn/docs/mermaid-11.15.0
chore(deps-dev): bump mermaid from 11.13.0 to 11.15.0 in /docs
2026-05-12 19:19:47 +02:00
dependabot[bot]
b282476607
chore(deps-dev): bump mermaid from 11.13.0 to 11.15.0 in /docs
Bumps [mermaid](https://github.com/mermaid-js/mermaid) from 11.13.0 to 11.15.0.
- [Release notes](https://github.com/mermaid-js/mermaid/releases)
- [Commits](https://github.com/mermaid-js/mermaid/compare/mermaid@11.13.0...mermaid@11.15.0)

---
updated-dependencies:
- dependency-name: mermaid
  dependency-version: 11.15.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-11 20:59:28 +00:00
dependabot[bot]
ea66dd4c13
chore(deps): bump fast-uri from 3.1.0 to 3.1.2 in /docs
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.0 to 3.1.2.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.0...v3.1.2)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-09 00:05:05 +00:00
Anon
3f64a9158c
bugfix: Fixed Structured Components on 26.1 causing crashing with Shulkers 2026-05-07 20:26:08 +02:00
Anon
6331478e30
Merge pull request #17 from milutinke/fix/shulker-crash 2026-05-07 19:59:30 +02:00
Anon
d55fd75520 Fixed shulker crashing on 26.1 (Structured Components) 2026-05-07 19:57:23 +02:00
Anon
6673b398b1
Merge pull request #3098 from MCCTeam/copilot/bugfix-out-of-bounds-exception 2026-05-07 00:10:23 +02:00
copilot-swe-agent[bot]
93d9939378
fix: guard sky-limit block updates
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/c65d23bd-cf8c-4c62-8195-db980026eb94

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-05-06 20:31:28 +00:00
copilot-swe-agent[bot]
a57fb7f61f
Initial plan 2026-05-06 20:18:44 +00:00
Anon
ba04636d06
feat: Load Forge mod translations from local mod jars 2026-05-04 22:23:11 +02:00
copilot-swe-agent[bot]
21a52b3bcc
fix: streamline forge translation preload
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/3b2dd335-d070-4067-b864-5584bb94571b

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-05-04 20:15:56 +00:00
copilot-swe-agent[bot]
7ce4f82871
feat: discover forge translation mod sources
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/3b2dd335-d070-4067-b864-5584bb94571b

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-05-04 20:11:43 +00:00
copilot-swe-agent[bot]
67066a145d
refactor: parse forge mods toml for translations
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/3d9090fb-cdf3-48e7-a7ce-575b54161f0e

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-05-04 19:08:22 +00:00
copilot-swe-agent[bot]
d256517e21
feat: load forge mod translations from local jars
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/3d9090fb-cdf3-48e7-a7ce-575b54161f0e

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-05-04 19:02:44 +00:00
copilot-swe-agent[bot]
90a3777dac
Initial plan 2026-05-04 18:52:10 +00:00
Anon
effc05aec3
feat: Load translation keys from server resource packs in chat parsing 2026-05-04 20:17:38 +02:00
copilot-swe-agent[bot]
b543825200
chore: finalize resource pack cache toggle
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/70cfa855-cff8-495e-ac06-9a65bb5cc913

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-05-04 12:47:41 +00:00
copilot-swe-agent[bot]
b87b5abbe2
feat: add cached resource pack translation setting
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/70cfa855-cff8-495e-ac06-9a65bb5cc913

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-05-04 12:32:13 +00:00
copilot-swe-agent[bot]
9f974da00d
chore: finalize resource pack translation support
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/d7467a13-d1ff-4cd6-a332-1ac389c445da

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-05-04 12:21:28 +00:00
copilot-swe-agent[bot]
34f45543c3
feat: load chat translations from server resource packs
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/d7467a13-d1ff-4cd6-a332-1ac389c445da

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-05-04 12:05:55 +00:00
copilot-swe-agent[bot]
9c47456455
Initial plan 2026-05-04 11:59:00 +00:00
Anon
92ab2f7378
feat: Add console chat visibility controls and clear-console commands 2026-05-04 13:42:17 +02:00
copilot-swe-agent[bot]
e515921df2
Document console chat visibility commands
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/c900b80f-7e2c-486b-abbf-2c190a9bb750

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-05-04 11:40:00 +00:00
copilot-swe-agent[bot]
1a1caec30a
Polish console chat visibility implementation
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/159bd460-7950-4afe-9e69-4892220665e1

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-05-04 11:36:01 +00:00
copilot-swe-agent[bot]
7bf342baab
Implement console chat visibility controls
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/159bd460-7950-4afe-9e69-4892220665e1

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-05-04 11:17:45 +00:00
copilot-swe-agent[bot]
9c994de2ee
Initial plan 2026-05-04 11:09:33 +00:00
Anon
03d3d6f950
feat: modernize ReplayCapture 2026-05-04 13:04:15 +02:00
Anon
98a1551f6a feat: modernize ReplayCapture
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-04 11:49:44 +02:00
Anon
acabe95801
feat: Added Written Book Support 2026-05-03 20:22:45 +02:00
Anon
12ab759f3b Fix TUI book controls
Polish TUI book navigation and signed-book handling, update localized shortcut text, and document the final PageUp/PageDown interaction.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-03 20:12:52 +02:00
Anon
41b33b6599
feat: Enable Farmer bot support for legacy 1.8 to 1.12.2
feat: Enable Farmer bot support for legacy 1.8 to 1.12.2
2026-05-03 16:43:47 +02:00
Anon
c282f2783c Fix legacy Farmer placement support 2026-05-03 15:46:16 +02:00
Anon
72001554a8 Complete 1.13-1.14 item palettes 2026-05-02 19:22:08 +02:00
Anon
8e31a37ea9 Document book command support
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-02 18:51:40 +02:00
Anon
c94be261fd Added Book Support 2026-05-02 17:52:17 +02:00
Anon
b5af631a40
bugfix: Fix structured components on 26.1 2026-04-30 16:25:52 +02:00
Anon
05741da9f1 Rename 26.1 structured component folder 2026-04-30 16:22:43 +02:00
Anon
5ad0d55705 Fix 26.1 structured component decoding 2026-04-30 16:18:59 +02:00
copilot-swe-agent[bot]
5279609561
Polish legacy Farmer validation logic
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/395596c2-cc40-4295-8100-a8408243f45b

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-04-17 08:00:41 +00:00
copilot-swe-agent[bot]
9549743c6d
Implement legacy Farmer support updates
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/395596c2-cc40-4295-8100-a8408243f45b

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-04-17 07:55:25 +00:00
Anon
8ba95c6140
[skipci]Merge pull request #3086 from MCCTeam/dependabot/npm_and_yarn/docs/dompurify-3.4.0 2026-04-16 10:41:27 +02:00
dependabot[bot]
0852d54991
chore(deps): bump dompurify from 3.3.3 to 3.4.0 in /docs
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.3.3 to 3.4.0.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.3.3...3.4.0)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-version: 3.4.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-16 03:36:32 +00:00
Anon
2bccb7f8e9
feat: Handle configuration-state code-of-conduct packets on 1.21.9+ servers 2026-04-15 22:57:27 +02:00
copilot-swe-agent[bot]
e564da3e09
chore: document code-of-conduct payload read
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/672da423-8a3f-412e-833d-a50c9a605b9d

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-04-15 20:51:35 +00:00
copilot-swe-agent[bot]
4dbce45676
fix: accept configuration code of conduct
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/672da423-8a3f-412e-833d-a50c9a605b9d

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-04-15 20:47:18 +00:00
Anon
5ec1bcd9db
feat: Add %date% variable 2026-04-15 22:24:25 +02:00
copilot-swe-agent[bot]
c1635a999f
Initial plan 2026-04-15 20:23:47 +00:00
copilot-swe-agent[bot]
4a28430ef5
Remove accidentally committed MCC debug config file
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/d60853e9-6f56-45f7-8346-a423657c5673

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-04-15 20:22:01 +00:00
copilot-swe-agent[bot]
c7053ec015
Add %date% variable returning file-safe yyyy-MM-dd format
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/d60853e9-6f56-45f7-8346-a423657c5673

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-04-15 20:21:25 +00:00
copilot-swe-agent[bot]
abffb58e5f
Initial plan 2026-04-15 20:00:09 +00:00
Anon
e511d33452
feat: Suppress duplicate active effect notifications 2026-04-15 18:42:14 +02:00
copilot-swe-agent[bot]
4bd0929ebf
Document ShowEffectMessages setting
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/88621e8e-27e0-4be5-9259-efcdf8730704

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-04-15 14:27:00 +00:00
copilot-swe-agent[bot]
443f4874df
Suppress duplicate active effect notifications
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/8649d41a-e2aa-4fdd-aee8-96f4b35c9be0

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-04-15 13:46:57 +00:00
Anon
b445d2bdec
[skipci]Merge pull request #3080 from MCCTeam/dependabot/npm_and_yarn/docs/follow-redirects-1.16.0 2026-04-15 11:05:14 +02:00
BruceChen
58ad896021 [skipci] docs: update .gitignore and config for superpowers documentation 2026-04-14 17:11:09 +00:00
BruceChen
8dccdaa7aa [skipci] chore: increase Node.js memory limit for documentation build 2026-04-14 17:05:11 +00:00
dependabot[bot]
5890cdef50
chore(deps): bump follow-redirects from 1.15.6 to 1.16.0 in /docs
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.6 to 1.16.0.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.6...v1.16.0)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-version: 1.16.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-14 01:13:01 +00:00
BruceChen
4013d39068
[skipci] Merge pull request #3078 from BruceChenQAQ/bruce/shared-server-mcc-sessions
Add MCC wrappers and guards for build and publish
2026-04-13 02:39:32 +08:00
BruceChen
ab29180e39 Add MCC wrappers and guards for build and publish 2026-04-12 18:37:03 +00:00
BruceChen
248a7a2f6f
Merge pull request #3077 from BruceChenQAQ/bruce/shared-server-mcc-sessions
tools: isolate MCC sessions while sharing local servers
2026-04-12 23:51:25 +08:00
BruceChen
8e0db1402f chore: remove remaining CursorBot references 2026-04-12 23:43:54 +08:00
BruceChen
ca5c9f73e3 docs: describe shared server MCC sessions 2026-04-12 23:33:59 +08:00
BruceChen
af285866dc tools: harden shared server session workflow 2026-04-12 23:33:45 +08:00
BruceChen
b665ebfeac Add session-scoped dual-session smoke test and harness updates 2026-04-12 20:46:39 +08:00
BruceChen
e4d71d970b Make tmpfs dotnet env wrapper bash-3 compatible 2026-04-12 20:21:59 +08:00
BruceChen
0a041b37c5 Add worktree-isolated tmpfs build outputs 2026-04-12 20:07:15 +08:00
BruceChen
e0752d8d98 tools: harden task3 session debug scripts 2026-04-12 19:57:54 +08:00
BruceChen
0519eac4a8 tools: run file-input debug sessions in tmux 2026-04-12 19:47:36 +08:00
BruceChen
bf292ea1be tools: scope mcc debug runtime artifacts by session 2026-04-12 19:38:53 +08:00
BruceChen
afee31e918 Ensure mcc-cmd handles unquoted multi-token commands 2026-04-12 19:26:32 +08:00
BruceChen
e03b7de959 Preserve full command in mcc-cmd and broaden tests 2026-04-12 19:25:25 +08:00
BruceChen
1be001bdf8 Fix session parser robustness and test assertion 2026-04-12 19:21:07 +08:00
BruceChen
4c6d5b566b Make MCC helpers session-aware and add reset test 2026-04-12 19:10:00 +08:00
BruceChen
d9c6826443 tools: fix tmpfs build root test 2026-04-12 19:04:38 +08:00
BruceChen
fdb6e5db4c tools: harden session helper and tests 2026-04-12 19:00:42 +08:00
BruceChen
3b65085a66 tools: add MCC session and build root helpers 2026-04-12 18:52:17 +08:00
BruceChen
6b986dcddd chore: update ModelContextProtocol package version to 1.2.0 and adjust Consolonia and Sentry package versions 2026-04-12 18:46:57 +08:00
BruceChen
158a4b1b13 docs: add MCC worktree session design 2026-04-12 17:37:13 +08:00
acamq
f3e8f65fe5 fix: correct /bed translation typo 2026-04-12 16:44:51 +08:00
Anon
8c8962f1ea
bugfix: correct scoreboard packet parsing for UpdateScore and ScoreboardObjective 2026-04-09 15:35:40 +02:00
adsicmes
fbacc550e2 fix: correct scoreboard packet parsing for UpdateScore and ScoreboardObjective
UpdateScore Display Name was read with ReadNextString instead of ReadNextChat. In 1.20.4+ Text Components are NBT-encoded, causing ReadNextString to misinterpret the tag type byte as a string length prefix, corrupting the read offset and exhausting the packet queue.

Also fix incomplete Number Format consumption in both UpdateScore and ScoreboardObjective: the styled (Compound Tag) and fixed (Text Component) payloads after the VarInt enum were not being read, leaving stale bytes in the packet queue.
2026-04-09 17:15:55 +08:00
Anon
d96396f74d
Merge pull request #3072 from milutinke/bugfix/srv-resolution 2026-04-08 18:15:22 +02:00
Anon
e0b21dd1d2 fixed the MCC incorrectly restarts the console input reader after transfer in classic mode. 2026-04-08 18:11:26 +02:00
BruceChen
229c9eba0a
[skipci] fix: update translation links for help section across multiple languages 2026-04-08 22:39:16 +08:00
BruceChen
2ac7e84b37 fix: update translation links for help section across multiple languages
- Changed the link for the "help us translate" section from crwd.in to crowdin.com for consistency and accuracy in localization configurations for various languages.
2026-04-08 22:38:37 +08:00
BruceChen
5aa1816621
[skipci] Fix document site build fail
[skipci] Fix document site build fail
2026-04-08 22:30:45 +08:00
BruceChen
b10e332e31 docs: update usage guide for MCC instance and note formatting
- Removed unnecessary period from the MCC instance reference.
- Reorganized the note section to improve clarity, moving it to a more appropriate location and ensuring consistent formatting for examples involving single and double quotes.
2026-04-08 22:29:42 +08:00
BruceChen
906d66a713 feat: add vue-template-tolerant plugin for error handling in translation pages
- Implemented a new Vite plugin that detects HTML errors in Vue translation pages and logs detailed error messages to the console.
- The plugin replaces the content of pages with a placeholder if errors are found, improving the robustness of the translation process.
- Integrated the plugin into the Vite bundler configuration for enhanced localization support.
2026-04-08 22:29:42 +08:00
BruceChen
b69708c637 chore: add websocket guide translations to Crowdin configuration
- Included new translation paths for markdown files located in the /docs/guide/websocket directory, enhancing the localization support for websocket-related documentation.
2026-04-08 22:29:42 +08:00
BruceChen
5363ef7bc1
Merge pull request #3068 from BruceChenQAQ/master
refactor: simplify color handling in ClassicConsoleBackend
2026-04-08 03:10:07 +08:00
BruceChen
740de13d98 refactor: enhance XLIFF parsing in Crowdin translation script
- Added support for an `include_paths` parameter to filter files based on specified prefixes, taking priority over `exclude_paths`.
- Updated the `parse_xliff` and `process_language` functions to accommodate the new filtering logic.
- Enhanced command-line argument parsing to allow users to specify files for translation directly, improving flexibility in translation management.
2026-04-08 02:52:07 +08:00
BruceChen
edadd91016 chore: update subproject commit reference for ConsoleInteractive 2026-04-08 02:50:39 +08:00
BruceChen
ff00d01fd7 refactor: simplify color handling in ClassicConsoleBackend
- Removed hex color handling logic from ClassicConsoleBackend, streamlining the WriteLineFormatted method.
- Updated ColorHelper to ensure consistent formatting for color codes.
- Ensured console-specific settings are reapplied after backend initialization in Program.cs.
2026-04-08 02:05:26 +08:00
BruceChen
64c42bb4b5
[skipci] Merge pull request #3067 from BruceChenQAQ/master
Optimize translate script
2026-04-08 01:32:38 +08:00
BruceChen
698a562156 refactor: update output directory handling in Crowdin translation script
- Removed the default output directory constant and updated the logic to set the output directory based on the provided argument or default to a "translated" subdirectory within the bundle directory.
- Improved help text for the output directory argument to clarify its default behavior.
2026-04-08 01:30:35 +08:00
BruceChen
7ec9d64b5b refactor: optimize translation unit handling in Crowdin script
- Introduced a new variable to track successfully translated units, improving clarity and efficiency in the processing logic.
- Updated the logic for combining existing and new translation units, ensuring accurate output and preventing unnecessary uploads when no new translations are available.
2026-04-08 01:30:35 +08:00
Anon
756bc1e11f
bugfix: Fixed a non-existant configuration packet from crashing the client. 2026-04-07 18:25:43 +02:00
Anon
5a5165e89f Fixed a non-existant configuration packet from crashing the client. 2026-04-07 17:00:01 +02:00
Anon
0e15806722
bugfix: Fixed SRV resolution during transfer 2026-04-07 15:43:12 +02:00
Anon
37271c5988 Fixed SRV resolution during transfer 2026-04-07 15:41:12 +02:00
BruceChen
35fd34b19d
Merge pull request #3062 from BruceChenQAQ/master
feat: add Crowdin translation automation script
2026-04-07 02:15:28 +08:00
BruceChen
ad065225ba feat: enhance game language support in settings
- Added documentation for mapping system CultureInfo names to Minecraft game language codes.
- Included support for Tagalog (tl and tl-PH) language codes in the game settings.
2026-04-07 02:03:02 +08:00
BruceChen
0445d95c23 feat: add support for additional game languages in settings
- Added support for Filipino (fil and fil-PH) and Norwegian (no) language codes in the game settings.
- Corrected formatting for existing language codes to ensure consistency and prevent potential issues with language recognition.
2026-04-07 01:58:29 +08:00
BruceChen
37bda82828 feat: add deduplication for cached domain prompt translations
- Implemented a new function to remove duplicate paragraphs from cached translations, addressing issues with the API returning repeated content.
- Updated the caching logic to apply deduplication both when loading from cache and after generating new translations, ensuring cleaner and more accurate cached data.
2026-04-07 00:52:18 +08:00
BruceChen
5dde778b53 refactor: improve XLIFF file handling in translation script
- Enhanced the `find_xliff_files` function to preserve the order of locales when mapping Crowdin locales to XLIFF paths.
- Updated the logic to return all available locales when no specific locales are provided, ensuring better handling of XLIFF files.
- Simplified the iteration over XLIFF files by removing unnecessary sorting in the final loop.
2026-04-07 00:50:24 +08:00
BruceChen
47f13a815c feat: add Crowdin translation automation script
- Introduced a new Python script for automating the translation of Crowdin XLIFF bundles using the Alibaba Cloud Qwen-MT API.
- Updated .gitignore to include the Crowdin translation working directory, ensuring that temporary files are not tracked.
- The script supports downloading, parsing, translating, and uploading XLIFF files, streamlining the localization process.
2026-04-07 00:30:52 +08:00
BruceChen
f432637710 fix: update GitHub link in MccBannerPanelBuilder
- Changed the GitHub link in the MccBannerPanelBuilder to use the full URL format for better accessibility.
2026-04-06 20:36:12 +08:00
BruceChen
e81700bf0e Fix warnings 2026-04-06 20:36:12 +08:00
BruceChen
b6bfecc622 fix: update build command in GitHub Actions workflow
- Modified the build command in the GitHub Actions workflow to use the .csproj file directly instead of the solution file, ensuring a more accurate build process for the specified project.
2026-04-06 20:36:12 +08:00
BruceChen
44e7f205c8 fix: disable transitive Avalonia compilation in project file
- Added a property to the MinecraftClient.csproj to disable the default Avalonia compilation, preventing file-lock races during parallel builds, as the project does not utilize XAML resources.
2026-04-06 20:36:12 +08:00
BruceChen
3073137006 fix: conditionally upload sources to Crowdin based on repository
- Updated the GitHub Actions workflow to conditionally upload sources to Crowdin only for the MCCTeam/Minecraft-Console-Client repository, enhancing the workflow's flexibility.
2026-04-06 20:14:02 +08:00
BruceChen
5c323772b3 fix: update Crowdin project URL in documentation and settings
- Corrected the Crowdin project URL in README.md, Settings.cs, and contributing.md to the official link.
2026-04-06 19:57:45 +08:00
BruceChen
0f32771075 fix: prevent concurrent restart flood on rapid /reco (#3046)
- Add reentrant guard to Program.Restart: track the active restart
  thread and silently drop concurrent calls from other threads while
  allowing the restart thread itself to chain a new restart (needed
  for AutoRelog retry flow).
- Fix double AutoRelog.OnDisconnectStatic invocation in HandleFailure:
  the method was called once in the error-message branch and again in
  the interactive-mode branch for the same failure event, doubling the
  retry counter increment and potentially spawning duplicate restarts.

Made-with: Cursor
2026-04-06 19:51:17 +08:00
BruceChen
e6ea29c914
[skipci] Merge pull request #3055 from BruceChenQAQ/master
[skipci] feat: Enhance GitHub Actions workflow with secret checks for deployment
2026-04-06 01:36:22 +08:00
BruceChen
e1f3dd5fdb
feat: Enhance GitHub Actions workflow with secret checks for deployment
- Added a job to check for the presence of required secrets (GH_PAGES_TOKEN, Crowdin secrets) before proceeding with documentation deployment and translation downloads.
- Updated the deployment job to conditionally run based on the results of the secret checks.
- Upgraded the Crowdin GitHub Action to version 2.4.0 for improved functionality.
2026-04-06 01:33:34 +08:00
BruceChen
7fd70ccf38 fix: Support hex RGB colors (#RRGGBB) in chat messages (fixes #2054)
Minecraft 1.16+ servers can send custom hex colors in JSON text
components ("color": "#RRGGBB"). MCC's ChatParser.Color2tag() only
recognized the 16 named colors, silently dropping hex values and
leaving gradient/custom-colored chat as uncolored plain text.

- ChatParser: recognize hex color values and emit internal §#rrggbb
  encoding; extend ColorCodeRegex to match the new format
- ClassicConsoleBackend: resolve §#rrggbb to ANSI escape codes via
  ColorHelper before passing to ConsoleInteractive (adapts to the
  configured ConsoleColorMode: 24-bit, 8-bit, 4-bit, or disable)
- McColorParser (TUI): parse §#rrggbb into exact SolidColorBrush
  for full RGB fidelity in Avalonia
- ChatBot.GetVerbatim(): skip the full 8-char §#rrggbb sequence
  instead of only 2 chars, preventing hex digits from leaking into
  stripped text

Made-with: Cursor
2026-04-06 01:19:19 +08:00
BruceChen
914c56fc6e
Merge pull request #3053 from BruceChenQAQ/master
Fix: chat colors not displayed in the TUI inventory screen
2026-04-06 00:36:23 +08:00
BruceChen
7f3b2c26da chore: Update Sentry package reference to version 6.3.0 2026-04-06 00:35:15 +08:00
BruceChen
49b7b98ba8 chore: Update package references for Consolonia and Magick.NET to latest versions 2026-04-06 00:35:15 +08:00
BruceChen
7405aad68f refactor: Simplify MainTuiView by removing architecture check for default return value 2026-04-06 00:35:15 +08:00
BruceChen
b083336bf6 refactor: Replace TextBlock creation with McColorParser for improved text rendering in chat display 2026-04-06 00:35:15 +08:00
BruceChen
a40188cb09
Merge pull request #3049 from BruceChenQAQ/master
feat: Add TUI support for /map
2026-04-06 00:24:27 +08:00
BruceChen
c7166f1cbc fix: Update zoom display in MapOverlay to show one decimal place for improved readability 2026-04-05 18:11:05 +08:00
BruceChen
c19ce62e98 fix: Adjust zoom step in MapOverlay for finer control during zooming 2026-04-05 18:09:20 +08:00
BruceChen
98ad174999 refactor: Simplify zoom functionality in MapOverlay by introducing NextStepScale method for smoother zoom transitions 2026-04-05 18:08:08 +08:00
BruceChen
296070f7e4 feat: Update map overlay to support interactive zoom and pan, and enhance header with zoom percentage display 2026-04-05 18:03:10 +08:00
BruceChen
0dde017ecc Add TUI support for /map 2026-04-05 17:41:32 +08:00
BruceChen
871bc7651f feat: Enhance command input handling by adding support for multi-line text input and refining text change logic 2026-04-05 17:41:11 +08:00
BruceChen
a6c832b744 Replaces the 120-TextBlock Grid (one per pixel) with a 7-TextBlock StackPanel using Run inlines for coloring. This eliminates ~113 unnecessary composition visual nodes from the banner icon. 2026-04-05 17:40:51 +08:00
Anon
33144b16d4
bugfix: Fixed the explosion packet on 26.1 2026-04-04 23:13:23 +02:00
Anon
81be654601 Fixed the explosion packet on 26.1 2026-04-04 23:12:05 +02:00
Anon
0cc34e6e22
bugfix: Fixed teams packet for 1.8 - 1.12.3 + Added text formatting for names in the tab list 2026-04-04 22:27:34 +02:00
Anon
32d5ad1108 Added text parsing in the tab player list 2026-04-04 22:25:40 +02:00
Anon
16e3a69211 Fixed teams packet for 1.8 - 1.12.3 2026-04-04 21:34:52 +02:00
BruceChen
6e86edc632 feat: Refactor MapColors class to load color palette from JSON resource 2026-04-05 01:17:57 +08:00
Anon
76c3403700
feat: Added a /tab command to display the list of online players 2026-04-04 16:21:06 +02:00
Anon
c8286f60c1 Added a /tab command 2026-04-04 16:17:49 +02:00
Anon
23262de6c2
bugfix: Fixed teams packet crash 2026-04-04 14:32:12 +02:00
Anon
a12ba29c45 Fixed teams packet crash 2026-04-04 14:30:44 +02:00
Anon
1ca023be36 Added a Github star reminder 2026-04-03 21:15:02 +02:00
Anon
0fda37b017
[skipci]Merge pull request #3043 from MCCTeam/dependabot/npm_and_yarn/docs/lodash-4.18.1 2026-04-03 20:59:39 +02:00
dependabot[bot]
75df2e0c71
Bump lodash from 4.17.23 to 4.18.1 in /docs
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.23 to 4.18.1.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-03 18:53:12 +00:00
Anon
d6b3dec8ad
feat: Implemented Model Context Protocol (MCP) into MCC 2026-04-03 20:51:54 +02:00
Anon
4b86e93764 Improved the documentation for MCP 2026-04-03 20:49:03 +02:00
Anon
8906f69839 Added documentation 2026-04-03 20:37:38 +02:00
Anon
f4c160979c Merge origin/master into feat/mcp-server 2026-04-03 20:03:37 +02:00
Anon
691057fe13 Bugfixes to the Looking and Movement. Added General prompt engineer. 2026-04-03 19:54:26 +02:00
Anon
dfef24ad10 Refactored to share the new utilities between the MCP and the Chat Bot API 2026-04-03 19:06:43 +02:00
Anon
a16af89dac
bugfix: Fix TPS average bias caused by discarding samples above 20 2026-04-03 18:27:08 +02:00
copilot-swe-agent[bot]
744dcd73cd
Fix TPS calculation: clamp values above 20 instead of discarding them
The old code filtered out any instantaneous TPS sample > 20 with
`if (tps <= 20 && tps > 0)`. Because time-update packets arrive with
OS/network jitter, many measurements on a healthy server land slightly
above 20.0 and were silently discarded, leaving only sub-20 samples in
the rolling average. This caused the reported TPS to be virtually always
lower than the true server TPS.

A Minecraft server cannot genuinely run faster than 20 TPS (it sleeps
for the remainder of each 50 ms tick budget), so any measurement above
20 is definitionally timing noise. Clamp to Math.Min(tps, 20.0) instead
of discarding the sample so a healthy server's rolling average converges
to 20.0 as expected.

Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/826926c5-78fa-4059-ab8f-4abd209f120d

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-04-03 16:24:38 +00:00
copilot-swe-agent[bot]
bca4532328
Initial plan 2026-04-03 16:18:22 +00:00
Anon
3557239c43
chores: Minor Optimizations 2026-04-03 16:40:54 +02:00
Anon
22e987070a Merge remote-tracking branch 'origin/master' into feat/optimization
# Conflicts:
#	tools/run-creative-e2e.sh
2026-04-03 15:44:59 +02:00
Anon
e987b525be Merge remote-tracking branch 'origin/master' into feat/optimization 2026-04-03 14:35:41 +02:00
BruceChen
512445cb1d fix: prevent TUI StackOverflowException from excessive log controls
The TUI log view used an ItemsControl with 5000 max entries and no UI
virtualization. Avalonia's composition renderer traverses the entire
visual tree on each frame -- with thousands of TextBlock controls, the
recursive Render/RenderCore calls exceed the thread stack size on
constrained devices (especially ARM where each stack frame is larger
due to ABI differences), causing a StackOverflowException in
ServerCompositionContainerVisual.Render.

Changes:
- Enable VirtualizingStackPanel on the log ItemsControl so Avalonia
  only creates visuals for the rows currently in the viewport.
- Add [Console.General] TUI_Log_Scrollback config option so users can
  control max log lines in TUI mode. Default is 0 (automatic: 3000 on
  x86/x64, 500 on ARM/ARM64).

Made-with: Cursor
2026-04-03 03:17:53 +08:00
BruceChen
2003786608 fix: resolve AutoRelog reconnect errors (#3036)
- Reset _BotRecoAttempts on successful game join so retry counter
  does not carry stale state across sessions
- Display "unlimited" instead of near-int.MaxValue retry count when
  Retries is set to -1 (infinite)
- Guard SendText with CanSendMessage check to prevent
  NullReferenceException when bots call send after disconnect
- Catch SocketException/IOException in Protocol18 Updater thread so
  a closed socket triggers OnConnectionLost gracefully instead of an
  unhandled exception

Made-with: Cursor
2026-04-03 01:28:26 +08:00
BruceChen
2441c67178 fix: work around Consolonia libcoreclr.so DllNotFoundException on Linux single-file publish
Consolonia's Unix.Terminal uses [DllImport("libcoreclr.so")] to load
dlopen/dlsym on .NET Core. It ships a SetDllImportResolver that maps
the library name to the current process handle, but the resolver is
guarded by #if NET6_0 (exact TFM match) instead of NET6_0_OR_GREATER.
Since Consolonia targets net8.0, the resolver is never compiled in.

On self-contained single-file publishes, libcoreclr.so is bundled
inside the host binary and does not exist on disk. Without the
resolver the OS linker cannot find it, causing a DllNotFoundException
that crashes the TUI on startup. This primarily affects ARM64 Linux
users (e.g. Raspberry Pi / Debian Trixie) who almost exclusively use
self-contained publishes.

This commit registers an AssemblyLoadContext.Default.ResolvingUnmanagedDll
handler in Program.Main (before TUI init) that returns (IntPtr)(-1) for
libcoreclr.so, which the runtime interprets as the current process.

This is a temporary workaround until the upstream fix lands:
https://github.com/Consolonia/Consolonia/pull/605

Made-with: Cursor
2026-04-03 01:11:36 +08:00
milutinke
a88ca3cb71 Improved the guidance prompt 2026-04-01 13:55:18 +02:00
milutinke
fc05d2c98c Fixed item dropping issue. 2026-04-01 13:45:12 +02:00
milutinke
ee6eb84bd8 Improved the Web Based Harness 2026-04-01 13:45:12 +02:00
Anon
82ebdd00ee
feat: Added automatic tool switching feature to Auto Dig
feat: Add low-durability tool switching to AutoDig
2026-03-31 11:43:22 +02:00
copilot-swe-agent[bot]
737a94475a fix: clarify autodig switch log formatting
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/e83f9c2a-a85c-4763-821b-c5b4a0db75a6

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-31 08:50:43 +00:00
copilot-swe-agent[bot]
1a86655dfb feat: add autodig tool switching
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/e83f9c2a-a85c-4763-821b-c5b4a0db75a6

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-31 08:44:23 +00:00
copilot-swe-agent[bot]
65dec59687 Initial plan 2026-03-31 08:14:25 +00:00
Anon
5f9549586a
feat: Added in-game teams support 2026-03-31 02:05:40 +02:00
copilot-swe-agent[bot]
4c54d2bbb7 docs: add /teams command entry and scoreboard teams bot API section
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/5dff6cc2-149d-431b-b0b1-2b29128a428e

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-31 00:02:38 +00:00
copilot-swe-agent[bot]
fdbffcc5bb feat: add Teams packet support (parsing, state tracking, /teams command, bot API)
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/72ea891e-ba62-4dfc-bbba-f197cd1d0404

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-30 23:41:11 +00:00
copilot-swe-agent[bot]
cf65c6f241 Initial plan 2026-03-30 23:31:09 +00:00
Anon
ee48c24f69
feat: Improved Auto Fishing detection 2026-03-31 01:03:08 +02:00
Anon
c9b0913c1a feat(autofishing): add velocity and sound bite detection 2026-03-31 00:18:31 +02:00
Anon
c3c57c058a Moved the operator prompt from a skill to an embedded resourcce 2026-03-30 23:21:36 +02:00
Anon
968800b95a Added a bunch of new useful MCP Tools 2026-03-30 23:14:28 +02:00
Anon
d5358d3d1a
feat: Add automatic mining-speed and dig-duration handling 2026-03-30 21:41:06 +02:00
Anon
5de72de234 Fixed a wrong effect decoding on 1.20.4 2026-03-30 21:37:53 +02:00
Anon
d158bfdf21 Fixed bugs 2026-03-30 20:20:58 +02:00
BruceChen
b9b7160e19 Enhance decompile.sh to support version metadata resolution and improved decompilation handling
- Added functionality to fetch version metadata from Mojang's manifest.
- Implemented checks for the presence of Proguard mappings to determine decompilation method.
- Enhanced the script to handle unobfuscated versions by downloading and extracting inner jars when necessary.
- Improved error handling for missing dependencies and added informative output messages during the decompilation process.
2026-03-31 01:28:24 +08:00
BruceChen
35dd3c4f06 Add support for ItemStackTemplate in DataTypes and Protocol18
- Implemented ReadNextItemStackTemplate method to read ItemStackTemplate data with item-first encoding.
- Updated Protocol18 to utilize ReadItemStackTemplateLabel for improved item display handling.
- Enhanced item component parsing to accommodate new structured components.
2026-03-31 01:28:24 +08:00
BruceChen
eae96a8fbc Cave mode for minimap 2026-03-31 01:28:24 +08:00
Anon
be20b97478
Merge branch 'master' into copilot/implement-automatic-mining-handling 2026-03-30 19:13:39 +02:00
Anon
1e35a4c624
[skipci]Merge pull request #3029 from MCCTeam/codex/improve-mcc-testing-workflow 2026-03-30 19:09:42 +02:00
BruceChen
354a498f21
Add icon startup banner 2026-03-31 00:05:54 +08:00
BruceChen
435887cc04 Update translation for banner label to clarify supported Minecraft versions 2026-03-31 00:05:22 +08:00
BruceChen
f7bc817408 Refactor color definitions in MccBannerPanelBuilder for improved clarity
- Removed unused color definitions for screen and dark screen.
- Updated pixel array to use the new screen background color consistently.
- Adjusted prompt text colors for better visibility in the TUI.
2026-03-31 00:03:29 +08:00
BruceChen
eaf4704473 Add icon banner display option and refactor startup banner logic
- Introduced a configuration option `Display_Icon_Banner` to control the visibility of the startup icon banner.
- Refactored `ProcessStartupState` to utilize TUI for displaying the banner if enabled, falling back to a classic banner display otherwise.
- Added new methods for building the banner panel and icon grid for improved visual representation.
- Updated translations and resource comments to support the new banner features.
2026-03-31 00:03:29 +08:00
milutinke
76e5cab248 Improve MCC testing workflow resilience 2026-03-30 18:02:10 +02:00
Anon
6b5435629f
feat: Added achievements/advancements support
feat: Add achievements/advancements support
2026-03-30 17:31:47 +02:00
milutinke
62740ee94e Document achievements feature 2026-03-30 17:28:15 +02:00
milutinke
0881cbaa1c Fix legacy achievements and add test harness 2026-03-30 17:25:08 +02:00
copilot-swe-agent[bot]
22455905a7 Add automatic mining-speed and dig-duration handling
- Add BlockHardness.cs with hardness data for all 1053 blocks from MC 1.21.11
- Add MiningCalculator.cs with version-aware dig duration computation
  - Tool speed from ToolComponent (1.20.6+) or legacy hardcoded tables
  - Efficiency enchantment (legacy: level^2+1, 1.21.11+: mining_efficiency attribute)
  - Haste/Conduit Power/Mining Fatigue effects
  - BLOCK_BREAK_SPEED attribute (1.20.6+)
  - MINING_EFFICIENCY and SUBMERGED_MINING_SPEED attributes (1.21.11+)
  - Underwater penalty with Aqua Affinity support (legacy) or attribute (modern)
  - Airborne penalty
  - Correct tool for drops check (30 vs 100 divisor)
- Modify McClient.DigBlock to auto-compute duration for survival/adventure mode
- Cache player attributes from OnEntityProperties in McClient
- Expose duration parameter in ChatBot.cs scripting wrapper
- Add /downloads/ to .gitignore

Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/579df446-a335-4174-9a8b-4d66173c82b1

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-30 08:24:00 +00:00
copilot-swe-agent[bot]
962c8b1ab2 Fix 26.1 RecipeBookAdd crash: update SlotDisplay registry IDs for 26.1
MC 26.1 changed the minecraft:slot_display registry, inserting 3 new
types (with_any_potion, only_with_component, dyed) and shifting all
existing IDs. This caused MCC to misparse recipe display data, leading
to a Queue empty crash in SkipItemHolderSet.

Add version-gated ReadSlotDisplayLabel with correct 26.1 type mapping
and reader methods for the 3 new slot display types.

Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/47b0c937-1491-4216-8ee0-1aca866e99ab

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-30 08:09:33 +00:00
copilot-swe-agent[bot]
c55d32bb70 Diagnose root cause of 26.1 RecipeBookAdd crash
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/47b0c937-1491-4216-8ee0-1aca866e99ab

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-30 08:03:56 +00:00
copilot-swe-agent[bot]
c95fe131e3 Initial plan 2026-03-30 07:40:08 +00:00
copilot-swe-agent[bot]
0f3289dfdf Fix criteria version boundary: criteria list removed from wire format in MC 1.20.2, not 1.20.6
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/5da0ec37-35e2-4aae-b165-66ddd82df985

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-29 21:16:45 +00:00
copilot-swe-agent[bot]
5705df43bd Fix Advancements packet parsing: sendsTelemetryEvent added in 1.20, deduplicate requirements reading
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/5da0ec37-35e2-4aae-b165-66ddd82df985

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-29 21:07:17 +00:00
copilot-swe-agent[bot]
7b3e5ee492 Address code review: eliminate unnecessary allocation in progress-only updates
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/9db483a8-4a5f-47b1-a6f4-30b6e39075bd

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-29 20:27:12 +00:00
copilot-swe-agent[bot]
65ef3dde6b Implement unified achievements feature: data model, protocol handling, state management, ChatBot API, and /achievement command
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/9db483a8-4a5f-47b1-a6f4-30b6e39075bd

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-29 20:22:31 +00:00
copilot-swe-agent[bot]
6dc42d9bd1 Initial plan 2026-03-29 20:10:15 +00:00
Anon
1165f32bb7
[skipci]chores: Add Quick Install section to README 2026-03-29 22:08:01 +02:00
copilot-swe-agent[bot]
534e337f10 Add Quick Install section to README with one-liner install commands
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/0a622d0a-bb4e-4cba-96f6-df2afa3bf4b7

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-29 20:05:16 +00:00
copilot-swe-agent[bot]
031dbb16d4 Initial plan 2026-03-29 20:03:11 +00:00
Anon
ec53f53f42
[skipci]chores: Added one line install scripts 2026-03-29 22:01:36 +02:00
copilot-swe-agent[bot]
f10556a162 fix: use Console::Write for progress bar to avoid duplicate bars when piped via iex
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/2c598307-7028-46d4-ac37-045f5ce125ed

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-29 19:45:40 +00:00
copilot-swe-agent[bot]
46fdd687c7 feat: add ASCII progress bars to both install scripts
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/00d3b725-2246-40c5-93e4-d9813d95c333

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-29 19:39:58 +00:00
copilot-swe-agent[bot]
53afc252ea fix: use precise regex in install.ps1 asset matching
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/bfeecfa8-81d9-45da-b1a7-b2dd6804b34f

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-29 19:31:26 +00:00
copilot-swe-agent[bot]
8c4acb0ad5 chore: remove Sentry cache dir and add to .gitignore
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/bfeecfa8-81d9-45da-b1a7-b2dd6804b34f

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-29 19:30:24 +00:00
copilot-swe-agent[bot]
d08cf803b8 feat: add install.sh and install.ps1 download scripts with docs update
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/bfeecfa8-81d9-45da-b1a7-b2dd6804b34f

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-29 19:30:05 +00:00
copilot-swe-agent[bot]
301ea6b9db Initial plan 2026-03-29 19:25:17 +00:00
Anon
ef106c80c2
feat: Implemented the Recipe Book into MCC 2026-03-29 21:05:38 +02:00
Anon
7b415d5388 Added a Skill for MCP 2026-03-29 20:57:16 +02:00
copilot-swe-agent[bot]
d97861888d docs: document recipebook command
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/1287ecfd-6d64-45ee-9aaf-96cbce9c3713

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-29 18:52:32 +00:00
BruceChen
90ea05b17d Enhance server status display and player information handling
- Updated `ServerStatusDisplay` to use `ChatBot.GetVerbatim` for version name formatting.
- Modified `ServerStatusPanelBuilder` to improve player name display with color parsing.
- Changed translation for online player label to "Online Players:" for clarity.
- Refactored protocol version checks to streamline logic in server status handling.
2026-03-30 02:46:34 +08:00
copilot-swe-agent[bot]
b05c8cfe0d fix: support 1.21.11 recipe book display ids
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/4cdf26f2-112b-4502-88f7-8f589c424f69

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-29 18:45:14 +00:00
BruceChen
b25579a105 Fix CI script injection via commit message special characters
Pass commit message through env vars instead of direct ${{ }} expansion
in shell scripts to prevent backticks and other special characters from
being interpreted as shell commands.

Made-with: Cursor
2026-03-30 02:26:03 +08:00
copilot-swe-agent[bot]
dfc1164839 chore: finalize recipe book support polish
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/00c8527f-5755-43c1-8916-8d571d28860b

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-29 18:12:01 +00:00
copilot-swe-agent[bot]
893be203e5 chore: polish recipe book support
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/00c8527f-5755-43c1-8916-8d571d28860b

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-29 18:07:09 +00:00
copilot-swe-agent[bot]
d5308ba8c6 feat: add recipe book command support
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/00c8527f-5755-43c1-8916-8d571d28860b

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-29 18:00:44 +00:00
copilot-swe-agent[bot]
3a28634592 Initial plan 2026-03-29 17:48:49 +00:00
BruceChen
871305bd72 Add server status display and protocol version upgrade handling
- Introduced a new `ServerStatusInfo` class to encapsulate server status data including MOTD, player counts, and version information.
- Implemented `ServerStatusDisplay` to format and display server status information in both classic and TUI modes.
- Added protocol version upgrade logic in `ProtocolHandler` to determine the highest supported protocol version for multi-version servers.
- Updated translations to support new server status labels and messages.
- Created `ServerStatusPanelBuilder` for TUI to visually represent server status with player information and connection details.
2026-03-30 01:39:37 +08:00
BruceChen
2f03f66f5c Enhance useblock command to support hand selection
- Updated the 'useblock' command to allow specifying the hand (mainhand or offhand) for block placement.
- Modified command usage description to reflect the new optional parameter.
- Adjusted the command execution logic to handle the selected hand during block placement.
2026-03-29 22:40:43 +08:00
BruceChen
d05e3148f1 Refactor explosion packet handling for protocol version updates
- Updated explosion packet processing to accommodate changes in Minecraft protocol versions, specifically for versions 1.21.2 and 1.20.4.
- Removed obsolete fields such as explosion strength and block records for newer versions, and added support for optional knockback and particle data.
- Enhanced backward compatibility for earlier versions by maintaining existing logic for explosion data retrieval.
2026-03-29 22:40:43 +08:00
BruceChen
c6b9121a59
Add Minimap for MCC (with mouse support) 2026-03-29 19:54:54 +08:00
BruceChen
d427a6e160 Add tooltip service and integrate with MinimapControl
- Introduced TuiTooltipService for managing tooltips across TUI components.
- Updated MinimapControl to utilize the new tooltip service for enhanced entity information display.
- Refactored tooltip rendering logic to improve visibility and interaction based on mouse position.
2026-03-29 19:53:50 +08:00
BruceChen
0566f2518b Add tooltip functionality to MinimapControl
- Introduced a tooltip system for displaying entity information on the minimap.
- Enhanced the SampleResult class to include entity mapping and block type summaries.
- Updated the rendering logic to incorporate tooltips and improve user interaction with the minimap.
2026-03-29 19:53:50 +08:00
BruceChen
a1516e9680 Add message aggregation and relay options for DiscordBridge
- Introduced message aggregation functionality with a configurable interval to reduce Discord API rate limits.
- Added options to relay all messages from Minecraft, including system messages, to Discord.
- Updated configuration comments to reflect new settings and their purposes.
2026-03-29 19:53:50 +08:00
BruceChen
6631180f8a Minimap support 2026-03-29 19:53:50 +08:00
BruceChen
c2475ea9e5
Merge pull request #3018 from BruceChenQAQ/master
Handle TUI startup failures with classic fallback
2026-03-29 01:58:18 +08:00
BruceChen
157d90273b Handle TUI startup failures with classic fallback 2026-03-29 01:57:21 +08:00
BruceChen
17d4b78022
Merge pull request #3017 from BruceChenQAQ/master
Add tryout command for TUI onboarding
2026-03-29 01:36:08 +08:00
BruceChen
b757215dbb Temporarily disable classic mode TUI recommendation
Commented out the MaybePrintClassicModeTuiRecommendation function call to prevent its execution until the related issue is resolved. Reference to the issue is included for tracking purposes.
2026-03-29 01:34:10 +08:00
BruceChen
83f14a64f8 Add tryout command for TUI onboarding
Add a new /tryout command as an extensible entry point for recommended feature trials, with /tryout tui as the first action. The command updates [Console.General] ConsoleMode to "tui", writes the config back immediately, and explains both how to revert the change and that a restart is required.

Also show a startup recommendation in classic console mode when stdin is interactive, so users can discover the TUI experience without manually editing MinecraftClient.ini. All user-facing text is routed through the translation resources.
2026-03-29 01:34:10 +08:00
BruceChen
0d34d5e33d
Merge pull request #3016 from BruceChenQAQ/master
Fix NullReferenceException in ConsoleIO
2026-03-29 00:56:44 +08:00
BruceChen
9cada9d19d Refactor ConsoleIO and Program settings handling
- Updated ConsoleIO to allow writing to the console when Backend is null, improving error handling.
- Simplified settings write-back logic in Program.cs to ensure default settings are written correctly based on configuration results.
2026-03-29 00:54:34 +08:00
Anon
cf382122e9 Added inventory manipulation to the MCP, improved the test harness 2026-03-28 16:44:22 +01:00
BruceChen
f0fda8ce9f Update base_path in crowdin.yml to use relative path 2026-03-28 23:38:56 +08:00
BruceChen
2d677e0f0d Fix skill frontmatter validation 2026-03-28 23:19:47 +08:00
Anon
7f9023e7bb More tools, added debug tools, fixed issues with some tools. 2026-03-28 04:12:37 +01:00
Anon
79b091cab6 Implemented a first version of an MCP server as a Chat Bot 2026-03-28 02:08:47 +01:00
BruceChen
5270aed315
Merge pull request #3011: TUI support for more container 2026-03-28 02:20:09 +08:00
BruceChen
0194380fbc TUI support for more container 2026-03-28 02:18:11 +08:00
BruceChen
ef133f3d6d Enhance container handling for Minecraft protocol updates
- Updated the Container class to include a protocol version parameter for accurate container type mapping.
- Modified the GetContainerType method to account for changes in container types introduced in Minecraft 1.20.4.
- Added new container types, including Crafter, to the ContainerType enum.
- Adjusted ContainerTypeExtensions to reflect the new container mappings and ensure compatibility with the updated protocol.
2026-03-28 02:17:47 +08:00
BruceChen
22f46d14a9 Fix negative location error 2026-03-28 02:17:47 +08:00
BruceChen
448e1ef6f5
Merge pull request #3010 from BruceChenQAQ/master
Update Crowdin GitHub Action version in build-and-release.yml
2026-03-28 00:48:31 +08:00
BruceChen
19a60fd85c Update Crowdin GitHub Action version in build-and-release.yml
- Upgraded the Crowdin GitHub Action from v1.20.4 to v2.4.0 to incorporate the latest updates and improvements.
2026-03-28 00:43:28 +08:00
BruceChen
ef8e41196b Update Crowdin GitHub Action version in build-and-release.yml
- Upgraded the Crowdin GitHub Action from v1.6.0 to v1.20.4 to leverage the latest features and improvements.
2026-03-28 00:40:05 +08:00
BruceChen
da330a158e Enhance Crowdin integration in build-and-release.yml
- Added a step to check for the availability of Crowdin secrets before downloading translations.
- Updated the condition for fetching translations to rely on the new check for Crowdin credentials.
- Corrected the assembly configuration to use the correct date format for builds.
2026-03-28 00:36:02 +08:00
BruceChen
c42133797e Update build-and-release.yml to enhance translation fetching logic
- Modified the condition for fetching translations to include checks for CROWDIN_PROJECT_ID and CROWDIN_PERSONAL_TOKEN.
- Added environment variables for CROWDIN credentials to streamline the translation process.
2026-03-28 00:30:53 +08:00
Anon
ce7bf0f400
Fixed shovel not creating paths from grass when used 2026-03-27 16:48:34 +01:00
Anon
0a9948a92a Merge branch 'master' of github.com:MCCTeam/Minecraft-Console-Client into fix/use-item 2026-03-27 16:46:29 +01:00
Anon
0c9ff137b2 Fixed shovel not being able to be used on dirt 2026-03-27 16:43:53 +01:00
Anon
57cf5c75c0
[skipci]Merge pull request #3007 from MCCTeam/copilot/remove-empty-warning-rename-tips 2026-03-27 15:53:47 +01:00
Anon
df05eb6dc4
Implemented effects support 2026-03-27 15:51:00 +01:00
Anon
f6446b198d Implemented effects support, as a command, chat notification and added in TUI mode 2026-03-27 15:47:27 +01:00
BruceChen
4b9e0e93aa Fix: cursor locate at the beginning when pressing Up to view history 2026-03-27 22:47:20 +08:00
copilot-swe-agent[bot]
4993498d52 docs: remove empty warning, rename Tips to Notes, add MCC.js recommendation
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/8f04f3c4-cedd-427c-ad3c-c2488363fe6f

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
2026-03-27 13:45:45 +00:00
copilot-swe-agent[bot]
20f536188a Initial plan 2026-03-27 13:36:21 +00:00
breadbyte
a7a3566756
Update build-and-release.yml
Fixes long commit message >256 chars breaking releases
Cleanup build code and consolidate variables
Make skip ci more user-friendly by including all variations of skip-ci and ci-skip
Add PublishSingleFile flag
2026-03-27 13:05:20 +08:00
breadbyte
cac9e5c625 skipci update ConsoleInteractive library 2026-03-27 12:08:05 +08:00
Anon
7a75328f0a Fixed a JSON exception 2026-03-26 19:16:48 +01:00
Anon
747662ea8c More minor optimizations 2026-03-26 18:01:56 +01:00
BruceChen
ac1d5c37a6 Refactor tab cycling logic in TUI command input handling
- Simplified the condition for disabling tab cycling by checking only for the Tab key.
- Improved clarity in the command key down event handling for better user experience.
2026-03-27 00:30:52 +08:00
BruceChen
fe7ab9f373 Implement startup state management and enhance configuration loading
- Introduced a new `StartupState` class to encapsulate the state collected before the console backend initialization.
- Updated the configuration loading process to handle legacy upgrades and provide detailed feedback on configuration status.
- Enhanced the TUI backend to utilize the new startup state for improved initialization flow.
- Refactored the `LoadFromFile` method in `Settings` to return a structured result, improving error handling and clarity.
2026-03-27 00:30:52 +08:00
BruceChen
b33ee7e4a1 Refactor exit handling and command input in TUI
- Improved the exit process by ensuring the backend shutdown is called after handling offline prompts.
- Enhanced command input history management by encapsulating text setting logic in a dedicated method to prevent event handler interference.
- Adjusted the background color in the color parser for better visibility.
- Increased the sleep duration in the TUI exit guard thread to ensure a smoother shutdown process.
2026-03-27 00:30:52 +08:00
Anon
ca5e7520cb Optimized SendPacket 2026-03-26 14:14:14 +01:00
Anon
0ceaaead10
[skipci]Merge pull request #2999 from milutinke/master 2026-03-26 01:01:04 +01:00
Anon
129f5bda9f
Reverted adding -p:PublishSingleFile=true 2026-03-26 01:00:36 +01:00
Anon
59332be062
[skipci]Merge pull request #2998 from milutinke/fix-git-action-parameter 2026-03-26 00:53:15 +01:00
Anon
5df03b0abd
Added PublishSingleFile to fix a build issue with TUI version 2026-03-26 00:52:24 +01:00
Anon
a2f7511ef7 Optimized World.cs 2026-03-25 23:57:02 +01:00
Anon
7da47d36dc
[skipci]Fixed session id changing not working in the Web Socket Chat bot. 2026-03-25 22:02:22 +01:00
Anon
05afeaf5bc Fixed session if changing in the Web Socket Chat bot. 2026-03-25 21:59:01 +01:00
Anon
966b787a4c
feat: Added missing enchantments for new versions 2026-03-25 20:01:43 +01:00
BruceChen
6beb00bae4
Fix open container crash (#2996) 2026-03-26 02:37:11 +08:00
BruceChen
e5b81fe428 feat: add support for unsupported container type in inventory TUI
- Implemented a check in the Inventory command to log a warning and return a failure status if the container type is not PlayerInventory.
- Added a new localized string for the warning message to inform users about unsupported container types.

These changes improve user feedback and error handling in the inventory management system.
2026-03-26 02:35:50 +08:00
BruceChen
dcfff3f1ba feat: enhance Protocol18 and SocketWrapper for improved functionality
- Added support for the new world border hit flag in Protocol18 for protocol version 1.21.2.
- Updated SocketWrapper to throw a SocketException if SendDataRAW is called when not connected, improving error handling.

These changes enhance the protocol handling and error management in the Minecraft Console Client.
2026-03-26 02:35:43 +08:00
BruceChen
8456e363f5
TUI for MCC (#2976)
* feat: implement interactive TUI inventory viewer

- Added InventoryTui command to open an interactive terminal user interface for inventory management.
- Introduced InventoryApp and InventoryMainView classes for TUI layout and functionality.
- Created InventoryViewModel and SlotViewModel to manage inventory data and display.
- Integrated Consolonia for enhanced console UI experience.
- Updated McClient to support console message handling during TUI operation.

These changes enhance user interaction with inventory management in Minecraft Console Client.

* feat: enhance debugging workflow with mcc-debug.sh and TUI support

- Introduced mcc-debug.sh for streamlined one-step build, server start, and MCC launch.
- Added TUI mode for improved user experience during debugging sessions.
- Updated mcc-env.sh to include new debug helpers and TUI mode functionality.
- Enhanced SKILL.md with detailed instructions for using the new debugging tools and console modes.

These changes significantly improve the debugging process for Minecraft Console Client, making it more efficient and user-friendly.

* feat: introduce TUI console backend and related enhancements

- Added ClassicConsoleBackend and TuiConsoleBackend to support different console I/O modes.
- Implemented IConsoleBackend interface for better abstraction of console operations.
- Enhanced ConsoleIO to utilize the new backend structure for input and output handling.
- Introduced MainTuiView and MccTuiApp for a full-screen TUI experience using Avalonia.
- Updated InventoryTuiHost to manage TUI lifecycle and interactions.

These changes significantly improve the console experience in Minecraft Console Client, providing a more flexible and user-friendly interface.

* refactor: remove InventoryTui command implementation

- Deleted the InventoryTui class, which provided an interactive terminal user interface for inventory management.
- This change simplifies the command structure as part of ongoing improvements to the console experience in Minecraft Console Client.

The removal of this command is aligned with recent enhancements to the console backend and user interface.

* refactor: update InventoryMainView and MainTuiView for improved UI handling

- Changed several fields from readonly to mutable in InventoryMainView to allow for dynamic updates.
- Introduced a new McColorParser class for parsing Minecraft color codes and creating colored text blocks.
- Enhanced MainTuiView to support formatted log lines and improved notification handling.
- Updated chat scrolling behavior to ensure better user experience during text input and log display.

These changes streamline the UI components and enhance the overall console experience in Minecraft Console Client.

* feat: enhance command input handling in MainTuiView

- Updated command input to use event routing for better key handling.
- Added support for Ctrl key shortcuts to improve text manipulation (e.g., word deletion, caret movement).
- Implemented text cleaning on input change to prevent newline characters.
- Improved health and food status bar rendering with a new method for building bar text.

These changes significantly enhance the user experience in the TUI by providing more intuitive command input functionality.

* feat: enhance TUI command suggestion functionality

- Introduced a new CommandSuggestion struct for backend-independent suggestion handling.
- Updated ConsoleIO to streamline suggestion updates for both Classic and TUI backends.
- Enhanced MainTuiView to display command suggestions with improved visibility and interaction.
- Increased the maximum number of displayed suggestions from 6 to 10 for better user experience.

These changes significantly improve the command input experience in the TUI, making it more intuitive and user-friendly.

* feat: enhance offline command autocomplete functionality

- Introduced an OfflineAutocompleteHandler to provide command suggestions for offline commands.
- Added support for tab cycling through suggestions in the TUI.
- Improved command input handling to clear suggestions when necessary and manage user input more effectively.
- Updated TuiConsoleBackend to integrate with the new autocomplete feature.

These changes significantly enhance the user experience by making command input more intuitive and responsive in offline scenarios.

* feat: enhance localization and user feedback in TUI

- Updated various TUI components to utilize localized strings for improved user experience.
- Enhanced debug state output with translated labels for better clarity.
- Improved inventory command help messages with localized text.
- Added new translations for console mode descriptions and inventory viewer prompts.

These changes significantly enhance the usability and accessibility of the TUI in Minecraft Console Client, making it more user-friendly and informative.

* feat: enforce localization for user-facing strings in AGENTS.md

- Added guidelines to ensure all user-facing text, including log messages and error messages, is managed through the translation system.
- Specified the use of `Translations.resx` and `Translations.Designer.cs` for localization, emphasizing the importance of avoiding hardcoded strings in source code.

These changes improve the consistency and accessibility of user-facing content across the application.
2026-03-26 02:08:18 +08:00
copilot-swe-agent[bot]
d9f79bf512 fix: correct enchantment mapping typo messages
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/16e21ef0-6f09-4280-b539-8d704ddc3b67
2026-03-25 18:05:56 +00:00
copilot-swe-agent[bot]
a79373c713 refactor: make enchantment version buckets explicit
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/16e21ef0-6f09-4280-b539-8d704ddc3b67
2026-03-25 18:03:36 +00:00
copilot-swe-agent[bot]
71c01c739a refactor: simplify fallback enchantment reverse maps
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/16e21ef0-6f09-4280-b539-8d704ddc3b67
2026-03-25 18:02:12 +00:00
copilot-swe-agent[bot]
d4faea9ecc fix: add lunge enchantment mapping for 1.21.11
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/16e21ef0-6f09-4280-b539-8d704ddc3b67
2026-03-25 18:00:38 +00:00
Anon
a17b7d4bd3
feat: Updated the Item Extensions utilities 2026-03-25 18:46:29 +01:00
copilot-swe-agent[bot]
a4ade66b8e fix: keep item classification ordering consistent
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/eb7f44aa-fc12-4c47-85ca-fe7ab80cfe30
2026-03-25 17:31:56 +00:00
copilot-swe-agent[bot]
69070f0157 fix: update manual item stack classifications
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/eb7f44aa-fc12-4c47-85ca-fe7ab80cfe30
2026-03-25 17:30:38 +00:00
copilot-swe-agent[bot]
d61a44ba34 Initial plan 2026-03-25 17:22:48 +00:00
copilot-swe-agent[bot]
d3c3e5a554 fix: add names for new enchantments
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/99915717-46df-4681-a568-5a9f0b244361
2026-03-25 17:21:17 +00:00
copilot-swe-agent[bot]
2c993247d2 Initial plan 2026-03-25 17:17:35 +00:00
Anon
00c3a8cb51
[skipci]chore: Lint and format the documentation markdown 2026-03-25 18:06:38 +01:00
copilot-swe-agent[bot]
3931d15c7d Fix ordered list numbering in docs/guide markdown with mdformat --number
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/659576c1-9e03-4d03-a9f2-99390ba4f390
2026-03-25 17:02:47 +00:00
copilot-swe-agent[bot]
cb4eb15784 Lint and format docs/guide markdown with mdformat, fix empty warning in chat-bots.md
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/3040312a-cbdf-43fe-918b-133ef19fc30f
2026-03-25 16:58:16 +00:00
copilot-swe-agent[bot]
a242f97c14 Initial plan 2026-03-25 16:55:32 +00:00
Anon
bd55fc3ed3
[skipci]Merge pull request #2992 from milutinke/skills/csharp-dotnet-cli-optimization 2026-03-25 16:04:25 +01:00
Anon
5fecd667a3 Created a skill for optimizations 2026-03-25 16:03:26 +01:00
Anon
a384d29b64
feat+bugfix: Re-introduced Web Socket Chat bot (as external script) and fixed a bug in Script compiler 2026-03-25 15:54:48 +01:00
copilot-swe-agent[bot]
eeb4383099 Fix Roslyn compiler references for WebSocket/HttpListener and fix MCCScript using directive semicolons
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/6fa57d65-60be-4a4b-b15a-ad3541ac6de3
2026-03-25 14:32:39 +00:00
copilot-swe-agent[bot]
ed0a69185f Fix timing attack in password comparison using constant-time XOR
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/c762752f-46be-44f6-a05d-8c5effc8ef43
2026-03-25 13:57:34 +00:00
copilot-swe-agent[bot]
d5a9ae3deb Address code review feedback: fix password placeholder, IPv4 regex, and doc references
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/c762752f-46be-44f6-a05d-8c5effc8ef43
2026-03-25 13:54:04 +00:00
copilot-swe-agent[bot]
6d6d1105eb Restore websocket docs and add sidebar navigation
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/c762752f-46be-44f6-a05d-8c5effc8ef43
2026-03-25 13:51:10 +00:00
copilot-swe-agent[bot]
c8c9f9ada5 Add WebSocketBot as external MCCScript bot with string enum serialization (#2805)
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/c762752f-46be-44f6-a05d-8c5effc8ef43
2026-03-25 13:47:33 +00:00
copilot-swe-agent[bot]
7fca2acd24 Add WebSocketBot as external MCCScript bot with string enum serialization
Port the WebSocket bot functionality to an external standalone script that:
- Uses //MCCScript 1.0 format instead of being a built-in bot
- Uses System.Text.Json instead of Newtonsoft.Json (no external DLL)
- Serializes ItemType, EntityType, and other enums as string names
  instead of numeric IDs (addresses #2805)
- Adds GetItemTypeMappings and GetEntityTypeMappings commands
- Accepts both string names and numeric IDs for enum parameters
- Uses 4096 byte WebSocket buffer for better message handling

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-25 13:42:01 +00:00
copilot-swe-agent[bot]
ba45f71f6e Initial plan 2026-03-25 13:22:53 +00:00
Anon
154778a488
bugfix: Fixed transfering breaking on multiple versions 2026-03-25 14:11:48 +01:00
Anon
41a1a1db9b Fixed transfering breaking on multiple versions 2026-03-25 14:05:43 +01:00
Anon
d40a3d9a0b
feat: Re-introduced the "--section.setting=value" into the CLI command parameters 2026-03-25 13:52:44 +01:00
copilot-swe-agent[bot]
f405548529 Harden CLI setting value conversion error handling
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/d53ef12a-695a-4687-bb53-f467c7121aea
2026-03-25 12:47:12 +00:00
copilot-swe-agent[bot]
87593b17b9 Implement CLI --section.setting=value overrides in Settings.LoadArguments
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/d53ef12a-695a-4687-bb53-f467c7121aea
2026-03-25 12:30:24 +00:00
copilot-swe-agent[bot]
fb41b1ffe1 Initial plan 2026-03-25 12:20:18 +00:00
Anon
52eda4ccdd
bugfix: Fixed more components on 1.21.5, 1.21.11 and 26.1 and crashing on 1.21.8 2026-03-25 12:50:10 +01:00
Anon
2f40cc1538 More component updates and fixes for 1.21.5, 1.21.11 and 26.1 2026-03-25 12:46:43 +01:00
Anon
a1ab366787
bufix: Fixed a bug in Auto Relog and improved reliability 2026-03-25 12:36:44 +01:00
copilot-swe-agent[bot]
5c9319c10d Fix AutoRelog not triggering when initial TCP connection fails (server offline)
When AutoRelog was enabled and the server was offline (SocketException during
initial connection), AutoRelog's reconnection logic was never invoked. The
Retry block's else branch either called HandleFailure() without a disconnect
reason (so AutoRelog.OnDisconnectStatic was skipped) or did nothing at all.

Now the else branch directly calls AutoRelog.OnDisconnectStatic with the
standard "Connection has been lost" message (matching the default
Kick_Messages), ensuring reconnection is properly triggered.

Fixes MCCTeam/Minecraft-Console-Client#2781

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/30698499-fdeb-44ce-9552-a64c4c5fb62b
2026-03-25 10:43:50 +00:00
copilot-swe-agent[bot]
33d050583a Initial plan 2026-03-25 10:26:11 +00:00
Anon
fec46ccd76
feat: Implemented support for bold, italic, underline, strikethrough and obfuscated text in chat 2026-03-25 11:21:08 +01:00
copilot-swe-agent[bot]
7e9be430db Merge remote-tracking branch 'origin/master' into copilot/reimplement-chat-formatting-feature
# Conflicts:
#	MinecraftClient/Protocol/Message/ChatParser.cs
2026-03-25 10:05:37 +00:00
Anon
c85dd4b498
bugfix: Fixed the component system from 1.20.6 - 1.21.11 2026-03-25 02:25:25 +01:00
Anon
c43b157b55 More fixed for 1.21.5, 1.21.9, 1.21.11, stress tested against everything from 1.20.6 - 1.21.11 2026-03-25 02:08:59 +01:00
Anon
17808bb652 Fixed the component system from 1.20.6 - 1.21.11 2026-03-25 01:08:27 +01:00
copilot-swe-agent[bot]
6c70685d52 Changes before error encountered
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/e56a9086-4921-4504-ab06-ebb912cf52ce
2026-03-24 21:11:43 +00:00
Anon
6f30f9b79a
bugfix: Fixed Web Requests in Chat Bots and a sample script 2026-03-24 21:21:53 +01:00
Anon
699b2cad6b
bugfix: Fixed scoreboard command crashing the client on 1.20.4 2026-03-24 21:20:14 +01:00
copilot-swe-agent[bot]
3fb7625b39 Add chat formatting code propagation (bold, italic, underline, strikethrough, obfuscated)
Re-implements PR #2851 against the current System.Text.Json.Nodes codebase.

Changes:
- ChatParser.cs: Add FormattingCodes dict, update JSONData2String to propagate
  formatting codes alongside colors, update NbtToString for the NBT chat path
  (used in MC 1.20.4+), fix root-string shortcut to preserve formatting prefix
- DiscordBridge.cs: Add GetDiscordText() converting § codes to Discord Markdown,
  handle unclosed formatting codes with end-of-string matching

End-to-end tested against Minecraft 1.21.11 (MC 26.1) offline server.
All 8 formatting types verified: bold(§l), italic(§o), strikethrough(§m),
underline(§n), combined, nested, reset-via-false, obfuscated(§k).

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/65b0d230-287c-4ed8-9b3c-a5ea25411804
2026-03-24 20:18:53 +00:00
copilot-swe-agent[bot]
8ab9f8505f Fix crash when scoreboard is updated on MC 1.20.4+
ChatParser.NbtToString crashed with InvalidCastException when a scoreboard
update was received. The switch expressions for extra/with NBT arrays only
handled int and string; everything else fell through to a hard cast to
Dictionary<string,object>, which fails for long/short/byte/float/double.

Replace with a pattern that explicitly matches string and Dictionary, and
converts all other values (any numeric NBT type) to a text component via
ToString(). This matches the behavior that ReadNbtField can return for
TAG_Byte, TAG_Short, TAG_Int, TAG_Long, TAG_Float, and TAG_Double.

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/44b66082-14ee-4966-9c23-4074134e0187
2026-03-24 19:58:58 +00:00
Anon
7f8ee0e2d6
feat: Add %players% built-in AppVar 2026-03-24 20:55:33 +01:00
copilot-swe-agent[bot]
461be9f368 docs: clarify players app var behavior
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/c9f7aa87-50b7-4725-aa39-613eba1a07fd
2026-03-24 19:51:46 +00:00
copilot-swe-agent[bot]
c9f1f88e62 refine sample http client usage
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/9bf31c0e-e47b-4654-be10-6ea50f27a581
2026-03-24 19:48:48 +00:00
copilot-swe-agent[bot]
7b534ca547 feat: add built-in players app var
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/c9f7aa87-50b7-4725-aa39-613eba1a07fd
2026-03-24 19:47:10 +00:00
copilot-swe-agent[bot]
0168cf8aa1 Initial plan 2026-03-24 19:46:19 +00:00
copilot-swe-agent[bot]
802cc696d6 fix sample http request script on latest runtime
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/9bf31c0e-e47b-4654-be10-6ea50f27a581
2026-03-24 19:44:05 +00:00
copilot-swe-agent[bot]
4c1b2197d7 Initial plan 2026-03-24 19:43:05 +00:00
copilot-swe-agent[bot]
16a3ad2b69 Initial plan 2026-03-24 19:34:21 +00:00
copilot-swe-agent[bot]
a2ff094369 Initial plan 2026-03-24 19:30:26 +00:00
Anon
79008cb0e5
[skipci]Merge pull request #2980 from MCCTeam/copilot/2979-add-documentation-for-feature 2026-03-24 20:24:38 +01:00
copilot-swe-agent[bot]
be084f6bea docs: add MaxChatMessageLength configuration documentation
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/3476aa22-a6b8-442a-8d91-0acbbaaf46f6
2026-03-24 19:21:50 +00:00
copilot-swe-agent[bot]
3745834f33 Initial plan 2026-03-24 19:19:36 +00:00
Anon
4d851b6339
feat: Add configurable MaxChatMessageLength for older protocol versions 2026-03-24 20:18:02 +01:00
copilot-swe-agent[bot]
db5faa22b1 Add configurable MaxChatMessageLength to override default limits for older versions
Adds a MaxChatMessageLength config option under [Main.Advanced] that allows
users to override the protocol-defined maximum chat message length. Default is
0 (auto: 100 for MC 1.10 and below, 256 for MC 1.11+). Some servers like
Hypixel support longer messages on older versions, so this lets users set a
custom limit (e.g. 256 on 1.8.9). Includes a warning about potential kicks
if set incorrectly.

Closes #2947

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/39c78e6a-f748-4f41-a905-2f5d27f99eff
2026-03-24 18:50:01 +00:00
copilot-swe-agent[bot]
f15c000868 Initial plan 2026-03-24 18:41:25 +00:00
Anon
dacf09b553
bugfix: Fixed command registration for external MCC scripts 2026-03-24 19:24:31 +01:00
copilot-swe-agent[bot]
9eba4d026c Improve UnregisterChatBotCommands doc comment per review feedback
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/d34fe951-43e5-412d-8d7f-cf9bee3a0d77
2026-03-24 18:15:01 +00:00
copilot-swe-agent[bot]
da3b2de2ce Fix Roslyn compiler missing netstandard/System.Runtime references (CS0012)
Add netstandard.dll and System.Runtime.dll as metadata references in both
the self-contained and non-self-contained compilation paths. These facade
assemblies are required when scripts reference libraries targeting
netstandard (e.g. Brigadier.NET), preventing CS0012 errors like:
"The type 'Object' is defined in an assembly that is not referenced."

Also make the self-contained path resilient to missing facade assemblies
by catching FileNotFoundException instead of throwing.

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/d34fe951-43e5-412d-8d7f-cf9bee3a0d77
2026-03-24 18:10:04 +00:00
copilot-swe-agent[bot]
54e07cd233 Address review: use TrimEntries in ChatBotCommand args split for consistency
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/27fc44b8-50d8-4194-8057-019a29675d4a
2026-03-24 17:44:35 +00:00
copilot-swe-agent[bot]
687d1746ed Fix command registration for external MCC scripts
- Update Roslyn compiler LanguageVersion from CSharp9 to Latest
- Implement ChatBotCommand.RegisterCommand() (was empty)
- Add RegisterChatBotCommand() helper to ChatBot base class
- Add automatic command cleanup in BotUnLoad via UnregisterChatBotCommands()
- Fix external scripts using Handler.dispatcher (CS0176 static via instance)
- Fix AutoTree.cs wrong Initialize/OnUnload signatures (CS0115)
- EntityCount.cs RegisterChatBotCommand() now works with new helper

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/27fc44b8-50d8-4194-8057-019a29675d4a
2026-03-24 17:43:14 +00:00
copilot-swe-agent[bot]
34bc6c5400 Initial plan 2026-03-24 17:29:28 +00:00
Anon
84858a55ee
[skipci]Merge pull request #2977 from milutinke/skills/integration-testing-improvements 2026-03-24 18:16:26 +01:00
Anon
a98b15fb3c Tightened the rules. 2026-03-24 18:15:32 +01:00
Anon
54d7b81e7b Improved the integration testing skill based on usage 2026-03-24 17:50:04 +01:00
Anon
bce1cd9290
[skipci]Merge pull request #2975 from milutinke/master 2026-03-24 16:35:23 +01:00
Anon
d6aa9d101f
Merge pull request #15 from milutinke/copilot/create-csharp-optimization-skill 2026-03-24 16:34:02 +01:00
Anon
7aee32d079
Merge pull request #2974 from milutinke/master 2026-03-24 16:32:07 +01:00
Anon
8f99f1b2be
Merge pull request #14 from milutinke/copilot/modernize-code-to-csharp-14 2026-03-24 15:41:33 +01:00
Anon
f64757edea Fixed inventory crashing on 1.13-1.13.2 2026-03-24 15:39:50 +01:00
copilot-swe-agent[bot]
47e943562e Optimize csharp-optimization skill using writing-skills and prompt engineering insights
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/milutinke/Minecraft-Console-Client/sessions/6df02c0b-e2cd-445e-9793-4ca4652d78d3
2026-03-24 10:17:52 +00:00
copilot-swe-agent[bot]
bd6aae0060 Add writing-skills from sickn33/antigravity-awesome-skills
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/milutinke/Minecraft-Console-Client/sessions/6df02c0b-e2cd-445e-9793-4ca4652d78d3
2026-03-24 10:13:33 +00:00
copilot-swe-agent[bot]
0a409ad394 Address code review feedback: fix pidof command, document ThreadStatic reentrancy caveat, fix endian swap example
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/milutinke/Minecraft-Console-Client/sessions/bcd1f692-997d-4646-b364-02e1179643bb
2026-03-24 10:04:28 +00:00
copilot-swe-agent[bot]
4808b61b9a Add csharp-optimization skill for C# performance optimization in MCC
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/milutinke/Minecraft-Console-Client/sessions/bcd1f692-997d-4646-b364-02e1179643bb
2026-03-24 10:02:54 +00:00
copilot-swe-agent[bot]
eca27be1fa Initial plan 2026-03-24 09:55:21 +00:00
copilot-swe-agent[bot]
aeec731ae5 Merge remote-tracking branch 'origin/master' into copilot/modernize-code-to-csharp-14 2026-03-24 08:52:57 +00:00
Anon
3a5283285a
Merge pull request #2971 from MCCTeam/copilot/modernize-authentication-module 2026-03-24 09:49:42 +01:00
copilot-swe-agent[bot]
654a16907b Modernize data carriers to records and add primary constructors
Convert 14 data carrier classes to records:
- VillagerInfo, MapIcon, EnchantmentData: non-positional records (mutable properties)
- ForgeMod, SkinInfo, VillagerTrade, Node, Response: positional records
- CommandNode: sealed positional record
- CommandArgumentDescriptor: readonly record struct
- ColorRGBA: record struct (multiple constructors preserved)
- RecipeConfig, Recipe, BannerLayer: non-positional records

Add primary constructors to 6 classes:
- DataTypes, Protocol18Terrain, Protocol18Forge, ItemMovingHelper,
  LastSeenMessageList, Acknowledgment, SuggestionTooltip

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 01:31:17 +00:00
copilot-swe-agent[bot]
81b756292e Fix all compilation warnings (CS9107, CS8600, CS8604, CS8618, CS0168, CS0169, CS0649)
- Fix CS9107: Replace lowercase primary constructor parameter refs with
  PascalCase base class properties in 90+ StructuredComponent files
- Fix CS8618: Add null! initializers for late-initialized properties
- Fix CS8600: Use nullable out parameters in World.cs, ChatParser.cs
- Fix CS8604: Add null guard in Compiler.cs, fix null-conditional in McClient.cs
- Fix CS0168: Replace unused variable with discard in DataTypes.cs
- Fix CS0169: Remove unused motionY field from McClient.cs
- Fix CS0649: Remove never-assigned steps field, simplify ClientIsMoving()
- Initialize client/handler with null! to avoid CS8618 cascade

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/milutinke/Minecraft-Console-Client/sessions/7fcee1b2-21e2-4457-b01b-5e0a1f07752f
2026-03-24 01:25:50 +00:00
copilot-swe-agent[bot]
640a4e39b7 Fix CS9107 warnings: use base class properties instead of captured primary constructor parameters
Replace lowercase primary constructor parameter references (dataTypes.,
subComponentRegistry., itemPalette.) with PascalCase base class property
references (DataTypes., SubComponentRegistry., ItemPalette.) in method
bodies of all StructuredComponent and SubComponent subclasses.

This eliminates CS9107 warnings where subclass primary constructor
parameters shadow the base class properties they are assigned to.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 01:16:05 +00:00
copilot-swe-agent[bot]
94bf42710a refactor: use pattern matching for null checks (is null / is not null)
Convert remaining == null to is null and != null to is not null
across 17 files in CommandHandler/ArgumentType, StructuredComponents,
and DeclareCommands for idiomatic C# style.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 00:47:03 +00:00
copilot-swe-agent[bot]
c7bc25aa17 refactor: convert == null / != null to is null / is not null in 31 files
Replace old-style null comparisons with modern C# pattern matching
syntax across Commands, Protocol, Mapping, ChatBots, Physics,
Inventory, Logger, CommandHandler, Scripting, Crypto, and other modules.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 00:42:59 +00:00
copilot-swe-agent[bot]
446c6e7739 refactor: convert redundant new TypeName() to target-typed new()
Replace explicit constructor calls with target-typed new() expressions
where the type is already specified on the left side of the assignment.
This is a C# 9+ feature that reduces redundancy.

Files changed:
- Container.cs: field assignments in constructors
- EntityPalette18/112/113.cs: static field initializers
- ChatParser.cs: StringBuilder local variable
- Movement.cs: field assignments in constructor
- PacketPalette18.cs: field initializers
- EnchantmentMapping.cs: field reassignments

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 00:37:35 +00:00
copilot-swe-agent[bot]
2ae31e269f Convert switch statements to expressions and adopt collection expressions
- DirectionExtensions.cs: Convert GetOpposite() to switch expression,
  use file-scoped namespace, use collection expression for HORIZONTAL
- McClient.cs: Convert InteractType switch to expression, use collection
  expressions for array literals
- Protocol18.cs: Replace Array.Empty<byte>() with [], use collection
  expressions for byte/int array literals
- DataTypes.cs: Use collection expression for TAG_End byte array
- ChatBot.cs: Use collection expressions for string/char arrays
- Location.cs: Use collection expressions and modernize null check

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/milutinke/Minecraft-Console-Client/sessions/4e9bd25b-22c5-47c2-98f9-6025d927b1d6
2026-03-24 00:34:00 +00:00
copilot-swe-agent[bot]
c5df6a49c6 Modernize null-check patterns: use 'is null' and 'is not null'
Replace '== null' with 'is null' and '!= null' with 'is not null'
across 19 core files following modern C# pattern matching conventions.

Only literal null comparisons are changed. Assignments, value
comparisons, and LINQ expressions are left untouched.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 00:28:02 +00:00
copilot-swe-agent[bot]
902e944cbb Modernize null-check patterns in Protocol18.cs
Replace '== null' with 'is null' and '!= null' with 'is not null'
for all 25 null comparisons in the file, following modern C# pattern
matching conventions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 00:23:31 +00:00
copilot-swe-agent[bot]
cf34db526b refactor: modernize null-check patterns in McClient.cs
Replace '== null' with 'is null' and '!= null' with 'is not null'
across 51 occurrences to use idiomatic C# pattern matching.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 00:21:37 +00:00
copilot-swe-agent[bot]
74def7c512 Modernize lock object declarations from object to System.Threading.Lock
Replace all lock object declarations using 'object' type with the C# 13
System.Threading.Lock type across 12 files. The Lock type provides a
more efficient locking mechanism - when used with lock(), the compiler
automatically uses Lock.EnterScope() instead of Monitor.Enter/Exit.

Also made two previously non-readonly lock fields readonly:
- McClient.DigLock
- Protocol18.MessageSigningLock

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 00:15:21 +00:00
copilot-swe-agent[bot]
e09b997cdf Initial plan 2026-03-24 00:05:56 +00:00
Anon
99e73b1df4
[skipci]Merge pull request #2973 from milutinke/misc/prompt-engineering-skill
Added the mcc-prompt-engineer skill to docs for ai assisted development
2026-03-23 17:35:40 +01:00
Anon
23ac2f9639
[skipci]Merge pull request #2972 from milutinke/misc/prompt-engineering-skill 2026-03-23 17:33:48 +01:00
Anon
d4c6f4d708 Added the mcc-prompt-engineer skill to docs for ai assisted development 2026-03-23 17:31:08 +01:00
Anon
102a175881 Added a prompt engineering skill 2026-03-23 17:15:17 +01:00
copilot-swe-agent[bot]
a9930b0a67 Update authentication documentation for OAuth 2.0 device code flow
- Update Account setting in configuration.md: clarify that Microsoft
  accounts don't need passwords (device code flow with 2FA support),
  add separate examples for Microsoft, offline, and Yggdrasil accounts
- Update usage.md: add tip about device code flow for Microsoft accounts,
  update command-line examples to show Microsoft and offline patterns,
  clarify that password is not needed in config files for Microsoft auth
- Update README.md features list: add Microsoft authentication with 2FA
  support as a listed feature

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/3afd0e85-19ae-45c7-ac4b-c2b7bf733008
2026-03-23 15:59:35 +00:00
copilot-swe-agent[bot]
94c6425a2b Address code review: add SlowDownIncrementSeconds constant, return OtherError for device code failures
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/e13b31f3-8d76-4240-bb69-a519a145fc6a
2026-03-23 15:41:25 +00:00
copilot-swe-agent[bot]
5147fb42df Replace PPFT/urlPost HTML scraping with OAuth 2.0 device code flow for 2FA support
- Add Microsoft.RequestDeviceCode() and Microsoft.PollDeviceCodeToken() methods
- Remove XboxLive.PreAuth() and XboxLive.UserLogin() (HTML scraping)
- Remove PreAuthResponse struct, PPFT/urlPost regex patterns
- Update XblAuthenticate to always use "d=" prefix for OAuth tokens
- Update MicrosoftMCCLogin to use device code flow
- Skip password prompting for Microsoft device code method
- Add translation strings for device code prompts
- Update config comments and documentation

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/e13b31f3-8d76-4240-bb69-a519a145fc6a
2026-03-23 15:38:47 +00:00
copilot-swe-agent[bot]
daeec49789 Initial plan 2026-03-23 15:23:27 +00:00
Anon
8f4e6b08b3
[skipci]Merge pull request #2970 from milutinke/feature/true-20-tps-runtime 2026-03-23 15:39:19 +01:00
Anon
b2eeb80659 Improved AGENTS.md 2026-03-23 15:38:29 +01:00
Anon
445c236914 Improved the development workflow and testing skills using skill-creator and a real server testing + feedback from actual workflow 2026-03-23 15:35:34 +01:00
Anon
932d01fb30
Merge pull request #2969 from milutinke/feature/true-20-tps-runtime 2026-03-23 15:34:54 +01:00
Anon
9efb7ef767 Remove obsolete 20 TPS smoke harness 2026-03-23 14:37:37 +01:00
Anon
484133f07a Run MCC at true 20 TPS 2026-03-23 14:29:04 +01:00
Anon
a18b5d2415
[skipci]Merge pull request #2968 from MCCTeam/copilot/update-termux-installation-docs 2026-03-23 13:56:57 +01:00
copilot-swe-agent[bot]
a0a69caeea docs: replace .NET 8 with .NET 10 in Android/Termux install section
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/4d7542ac-8231-4da1-bc87-b617d718cc97
2026-03-23 12:43:10 +00:00
copilot-swe-agent[bot]
a16152410e Fix 404 MCC download in Android/Termux install docs
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/f43c042f-896c-40a8-a28f-67a945e5dbcb
2026-03-23 12:35:47 +00:00
copilot-swe-agent[bot]
7e2e2f3f53 Update Termux installation docs to 2026: proot-distro, F-Droid, dotnet-install.sh
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/9ba5d661-a024-469c-8382-651f34b090ca
2026-03-23 12:01:51 +00:00
copilot-swe-agent[bot]
a0171af007 Initial plan 2026-03-23 11:54:49 +00:00
Anon
5f7e302213
Merge pull request #2967 from milutinke/fix/discord-rpc-unix-ipc-paths 2026-03-23 03:08:26 +01:00
Anon
2d8412ce29 Embed Discord RPC pipe client in DiscordRpc bot 2026-03-23 03:06:00 +01:00
Anon
1d4ff226e0 Limit custom Discord RPC pipe client to Linux 2026-03-23 03:01:06 +01:00
Anon
8bedcece52 Fix Discord RPC Unix IPC path detection 2026-03-23 02:58:43 +01:00
Anon
19a4f8132a
[skipci]Merge pull request #2966 from MCCTeam/copilot/update-chat-bots-documentation 2026-03-23 02:41:56 +01:00
copilot-swe-agent[bot]
a5896d47b5 docs: add Discord RPC docs and update Discord Bridge docs
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/2b93eea6-4093-4793-a817-4ac97a8255da
2026-03-23 01:20:56 +00:00
copilot-swe-agent[bot]
15a50dc844 Initial plan 2026-03-23 01:18:01 +00:00
Anon
9db4ad86b4
Merge pull request #2965 from MCCTeam/copilot/implement-discord-rpc-integration 2026-03-23 02:13:14 +01:00
copilot-swe-agent[bot]
221b82643d Fix DiscordRpc to send presence only after game join, apply C# best practices, remove temp E2E scripts
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/80d151a5-aee7-4ae6-8497-9e7487d25136
2026-03-23 01:05:48 +00:00
copilot-swe-agent[bot]
6c1449439c Add Discord RPC E2E test scripts and address code review feedback
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/a41f3e83-c88d-4c57-971b-54c380891556
2026-03-23 00:49:34 +00:00
copilot-swe-agent[bot]
5a9786cb0b Add Discord RPC setup tutorial, Discord Bridge AllowOtherBotMessages config, and enhance integration tests
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/a41f3e83-c88d-4c57-971b-54c380891556
2026-03-23 00:41:40 +00:00
copilot-swe-agent[bot]
02686de79c Add granular privacy controls: ShowCoordinates, ShowHealth, ShowDimension, ShowGamemode
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/43388021-4264-47e6-8403-7a1bca66d86f
2026-03-23 00:13:03 +00:00
copilot-swe-agent[bot]
8743129e72 Address code review: fix party max, rename food variable, add ShowServerAddress option
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/43388021-4264-47e6-8403-7a1bca66d86f
2026-03-23 00:08:08 +00:00
copilot-swe-agent[bot]
a2d032b549 Add Discord Rich Presence ChatBot integration
- Add DiscordRichPresence NuGet package (v1.143.0)
- Create DiscordRpc.cs ChatBot with configurable presence display
- Wire config in Settings.cs ChatBotConfig class
- Register bot in McClient.cs RegisterBots()
- Add translation strings to Translations.resx and Designer
- Add config comments to ConfigComments.resx and Designer
- Support placeholders: {server_host}, {server_port}, {username},
  {health}, {max_health}, {food}, {dimension}, {gamemode},
  {x}, {y}, {z}, {player_count}, {protocol}

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/43388021-4264-47e6-8403-7a1bca66d86f
2026-03-23 00:03:55 +00:00
Anon
5d21b4575f
[skipci]Merge pull request #2964 from MCCTeam/copilot/update-documentation-configuration-section 2026-03-23 00:52:04 +01:00
copilot-swe-agent[bot]
0a463f2380 Initial plan 2026-03-22 23:50:40 +00:00
copilot-swe-agent[bot]
10593749dd Update Yggdrasil auth config docs
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/9b1c26c4-240d-40de-be7b-ba1174f7e2bd
2026-03-22 23:44:46 +00:00
copilot-swe-agent[bot]
c82b6c844b Initial plan 2026-03-22 23:37:28 +00:00
Anon
3ee0177d62
Merge pull request #2963 from milutinke/authlib-injector-accounts 2026-03-23 00:21:34 +01:00
Anon
ff9aa62702 Add configurable authlib-injector API path and HTTP support for Yggdrasil auth
Re-implements the changes from PR #2890, adapted for the current codebase
which uses System.Text.Json.Nodes and HttpClient instead of the legacy
Json.JSONData and hand-rolled SslStream HTTP client.

Changes:
- Settings.cs: Convert AuthlibServer from struct to class with
  [TomlDoNotInlineObject]; convert Host to a property that parses
  'host:port' syntax; add AuthlibInjectorAPIPath (default '/api/yggdrasil')
  for servers that use a different prefix (e.g. Drasl uses '/authlib-injector');
  add UseHttps (default true) so local/dev auth servers without TLS work.

- ConfigComments.resx: Add descriptive inline comments for the new
  AuthlibServer fields (Host, Port, AuthlibInjectorAPIPath, UseHttps).

- ProtocolHandler.cs: Replace three hardcoded '/api/yggdrasil/...' paths
  with AuthlibInjectorAPIPath-based paths (authenticate, refresh, join).
  Replace hand-rolled TcpClient+SslStream HTTP in DoHTTPSRequest with
  HttpClient+SocketsHttpHandler (ConnectCallback routes through ProxyHandler).
  Add useHttps parameter so HTTP-only auth servers are supported.

- KeyUtils.cs: Add AuthServerSupportsProfileKeys() that fetches the
  authlib-injector metadata endpoint and checks feature.enable_profile_key.
  Update GetNewProfileKeys() to skip key fetch when the auth server does not
  support profile keys; build the cert URL dynamically using AuthlibInjectorAPIPath
  for Yggdrasil; always fetch real certs instead of returning a dummy response.
  Remove MakeDummyResponse() which is no longer needed.

Tested against a local Drasl instance with authlib-injector 1.2.7 on a
1.21.11 Minecraft server — full auth flow (login, profile key fetch, session
join) confirmed working end-to-end.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-23 00:15:32 +01:00
Anon
72ec3122ae
Merge pull request #2961 from milutinke/update-json-http-client 2026-03-22 23:06:58 +01:00
Anon
6c9dcfd216
Merge pull request #2962 from MCCTeam/copilot/update-mcc-integration-testing 2026-03-22 23:04:02 +01:00
Anon
d44fc22c8a Fix offline Microsoft auth profile-key checks and complete status ping/pong during auto-version detection. 2026-03-22 22:19:59 +01:00
copilot-swe-agent[bot]
02873957a8 skill: update mcc-integration-testing to use tools/mcc-env.sh instead of ~/.zshrc
- Replace `source ~/.zshrc` with `source "$REPO_ROOT/tools/mcc-env.sh"` in
  ensure_offline_server.sh and run_full_spectrum_test.sh
- Convert both scripts from zsh to bash (#!/usr/bin/env bash) so mcc-env.sh
  can be sourced natively; replace ${0:A:h} with portable SCRIPT_DIR expansion
- Update SKILL.md: drop ~/.zshrc references, point to tools/mcc-env.sh and
  standalone tools/start-server.sh + tools/mc-rcon.sh; update server path
  from ~/Minecraft/Servers/ to MinecraftOfficial/downloads/; replace
  `mcc-build` with `dotnet build MinecraftClient.sln -c Release`
- Update evals.json expectation to match new workflow

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/1ff08b70-7be3-4211-9b77-a9e10ff1d157
2026-03-22 21:19:55 +00:00
copilot-swe-agent[bot]
07189509b0 Initial plan 2026-03-22 21:15:19 +00:00
Anon
af405e5632 Fixed Profile Component crashing on 1.21.9 2026-03-22 21:53:13 +01:00
Anon
5c39d3b83d
Merge pull request #12 from milutinke/master 2026-03-22 20:42:41 +01:00
Anon
5e99e3a42d
Merge pull request #11 from milutinke/copilot/update-json-http-client 2026-03-22 20:39:28 +01:00
Anon
757cbe1a68 Fix ParseJson crash on non-JSON plain-text input (e.g. vanilla MOTD)
When the MC server sends a plain-text string (not valid JSON) for fields like
the ServerData MOTD, JsonNode.Parse() throws JsonReaderException. This was a
regression introduced by the System.Text.Json modernization.

Fix: catch JsonException in ParseJson() and return JsonValue.Create(json) so
plain-text strings are treated as literal string values rather than crashing.

Tested against a real Minecraft 1.21.11 server (offline mode): MCC connects
and stays connected without crashing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-22 19:53:15 +01:00
copilot-swe-agent[bot]
d2c1cbf2a5 Fix Json.ParseJson crash on empty/null input
ParseJson now returns null for null, empty, or whitespace-only input
instead of throwing JsonReaderException. This matches the behavior of
the old hand-rolled parser and is needed because MC protocol packets
may contain empty strings where JSON text is expected (e.g. empty chat
messages in DeathCombatEvent packets).

Discovered during end-to-end testing against a Minecraft 1.21.11
protocol server.

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/milutinke/Minecraft-Console-Client/sessions/34df723e-4a63-45a0-a942-e119d81a575b
2026-03-22 17:22:08 +00:00
copilot-swe-agent[bot]
64ccdcb39b Address code review feedback
- Replace GetAwaiter().GetResult() with synchronous ReadAsStream()
- Use JsonNode.DeepClone() instead of serialize/parse round-trip
- Extract timeout magic number to named constant

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/milutinke/Minecraft-Console-Client/sessions/afcd1b7b-ea23-4a0d-bb46-a90b623406fc
2026-03-22 16:46:33 +00:00
copilot-swe-agent[bot]
37fe626325 Replace hand-rolled ProxiedWebRequest with HttpClient/SocketsHttpHandler
- Rewrite ProxiedWebRequest to use System.Net.Http.HttpClient internally
- Use SocketsHttpHandler with native SOCKS4/4a/5 and HTTP proxy support
- Remove 250+ lines of manual HTTP/1.1 parsing, chunked transfer, TLS pinning
- Proper TLS negotiation (no longer pinned to TLS 1.2)
- Remove unused ITcpFactory interface and isProxied flag
- Maintain same public API (Get(), Post(), Response class) for all consumers

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/milutinke/Minecraft-Console-Client/sessions/afcd1b7b-ea23-4a0d-bb46-a90b623406fc
2026-03-22 16:44:35 +00:00
copilot-swe-agent[bot]
15aabd9423 Replace legacy custom JSON parser with System.Text.Json
- Rewrite Json.cs to use System.Text.Json.Nodes (JsonNode, JsonObject, JsonArray)
- Add JsonNodeExtensions.GetStringValue() for backward-compatible string access
- Update all 14 consumer files to use the new JsonNode API
- Remove ~300 lines of hand-rolled JSON parsing code from 2013
- Replace KeyUtils.EscapeString with delegation to Json.EscapeString

Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/milutinke/Minecraft-Console-Client/sessions/afcd1b7b-ea23-4a0d-bb46-a90b623406fc
2026-03-22 16:39:26 +00:00
Anon
f31ed82ce1
[skipci]Merge pull request #2960 from milutinke/ai-dev-workflow-docs 2026-03-22 17:33:42 +01:00
Anon
611951668e Updated documentation to use <details> tag, updated the AGENTS md 2026-03-22 17:31:41 +01:00
copilot-swe-agent[bot]
7893bd7fe4 Initial plan 2026-03-22 16:19:28 +00:00
Anon
d20b139215
[skipci]Merge pull request #2959 from milutinke/ai-dev-workflow-docs 2026-03-22 16:57:59 +01:00
Anon
dc50df3b94 Fixed documentation about configuration missmatch, updated to reflect the latest state. 2026-03-22 16:55:14 +01:00
Anon
9657ed91d2
[skipci]Merge pull request #2958 from MCCTeam/copilot/update-best-practices-for-csharp14 2026-03-22 16:52:58 +01:00
copilot-swe-agent[bot]
95fc0fd0f8 Update Modern Syntax range to C# 10-14 and add unbound generics nameof example
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/8cdef112-415b-4769-877d-61f0e7a300eb
2026-03-22 15:51:19 +00:00
copilot-swe-agent[bot]
4ac3601aa7 Fix British spelling 'Synchronisation' to American 'Synchronization' in collections table
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/8cdef112-415b-4769-877d-61f0e7a300eb
2026-03-22 15:49:05 +00:00
Anon
454ce331b2 Updated docs for Yggdrasil authlib multi-user selection and cleaned the code a bit 2026-03-22 16:48:38 +01:00
copilot-swe-agent[bot]
1e2847a48e Update csharp-best-practices skill from C# 12 / .NET 8 to C# 14 / .NET 10
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/8cdef112-415b-4769-877d-61f0e7a300eb
2026-03-22 15:48:20 +00:00
copilot-swe-agent[bot]
4d51282040 Initial plan 2026-03-22 15:44:10 +00:00
Anon
7162691b57 Added humanizer skill for Docs 2026-03-22 16:39:37 +01:00
Anon
4fb4c018e4
Merge pull request #2781 from a08381/authlib-multi-user 2026-03-22 16:36:20 +01:00
Anon
bdb561ed4a
Merge pull request #2957 from milutinke/ai-dev-workflow-docs 2026-03-22 16:32:09 +01:00
Anon
5c2c176ba1 Updated the latest version to: 26.1. Fixed Warning, Tip and info blocks not-rendering properly. Updated Physics section to be up to date. Fixed a formatting error on the Installation page. 2026-03-22 16:29:14 +01:00
Anon
535b95f4b9
Merge pull request #2956 from milutinke/ai-dev-workflow-docs 2026-03-22 16:09:02 +01:00
Anon
d95b6bb9eb Added links for skills 2026-03-22 16:04:45 +01:00
Anon
aa59c4d75a Updated the installation methods, updated creating bots. Removed Web Socket Bot pages. 2026-03-22 15:57:44 +01:00
Anon
e4aeb51f71 Updated documentation to the latest state 2026-03-22 15:40:05 +01:00
Anon
9613e0df51 Added AI Assisted development documentation. Updated Vuepress to the latest version. Added SEO and Sitemap plugins to Vuepress. 2026-03-22 14:29:02 +01:00
BruceChen
cffddb398e
Merge pull request #2955 from BruceChenQAQ/master
Add Minecraft 26.1 Support
2026-03-22 20:27:28 +08:00
BruceChen
d1837d104b feat: handle 26.1 protocol changes and snapshot version support
- Protocol18: add MC_26_1_Version constant (775), version-gated palette
  routing for blocks/items/entities/metadata, and new TimeUpdate packet
  format (WorldClock map replaces dayTime+tickDayTime)
- Protocol18Terrain: read new fluidCount short in chunk sections (26.1+)
- DataTypes: add CatSoundVariant to entity metadata VarInt readers
- ProtocolHandler: add NormalizeSnapshotProtocol() to map RC/snapshot
  protocol numbers (e.g. 0x4000012E → 775) to release versions, pass
  raw protocol version through for server handshake compatibility

Made-with: Cursor
2026-03-22 20:04:08 +08:00
BruceChen
d4014f7c87 feat: add 26.1 packet palette, structured components registry, and version routing
Add PacketPalette261 with new packet types (GameRuleValues, LowDiskSpaceWarning,
Attack, SetGameRule). Create StructuredComponentsRegistry261 with 6 new components
(additional_trade_cost, dye, pig/cow/chicken/cat sound_variant). Update version
routing in PacketType18Handler, EntityMetadataPalette, StructuredComponentsHandler,
and Program.cs to support protocol 775 (26.1).

Made-with: Cursor
2026-03-22 20:04:08 +08:00
BruceChen
e3d3a86ac2 feat: add 26.1 palette files and new enum values
Add item, block, entity, and entity metadata palettes for Minecraft 26.1.
New enums: GoldenDandelion (item/block), PottedGoldenDandelion (block),
CatSoundVariant, CowSoundVariant, PigSoundVariant, ChickenSoundVariant
(entity metadata). Update gen_entity_metadata_palette.py FIELD_TO_ENUM
mapping for the new sound variant types.

Made-with: Cursor
2026-03-22 20:04:08 +08:00
Anon
052993a2c1
Merge pull request #2954 from milutinke/mcc-gui-update 2026-03-22 12:49:14 +01:00
Anon
33fccf85b5 Added changes from 2927 2026-03-22 12:45:52 +01:00
breadbyte
d25f2f40ec
Update Github Actions to be more robust with releases (#2952)
* Update build-and-release.yml
2026-03-22 18:34:19 +08:00
BruceChen
397ab07d1f [skipci] docs: update MCC development workflow documentation
- Revised the SKILL.md file to enhance clarity and detail regarding the development workflow for Minecraft Console Client (MCC).
- Expanded sections on project structure, build commands, and debugging steps, including specific instructions for compiling, starting a test server, and running MCC.
- Added environment setup details and a checklist for server configuration, improving usability for developers.
- Included new tools and scripts for server management and decompilation processes, streamlining the development experience.

These updates provide comprehensive guidance for developers working with MCC in WSL.
2026-03-22 16:34:12 +08:00
BruceChen
3afbae4f89 fix: correct global state indexing in block shape processing
- Adjusted the indexing logic in BlockShapes.cs to ensure proper mapping of state counts to shape IDs.
- Introduced a global state offset to accurately reference shape IDs in the list, preventing out-of-bounds errors during shape assignment.

These changes enhance the reliability of block shape processing in the physics engine.
2026-03-22 16:34:12 +08:00
BruceChen
38e86eb209
Merge pull request #2953 from BruceChenQAQ/master
feat: implement physics engine for player movement and collision detection
2026-03-22 15:51:23 +08:00
BruceChen
e3a2593781 feat: add cursor indexing ignore rules for SpecStory files
- Introduced a new `.cursorindexingignore` file to prevent indexing of SpecStory auto-save files while allowing explicit context inclusion via @ references.
- Updated `.gitignore` to exclude the entire `.specstory/` directory and `.vscode/settings.json`, ensuring these files are not tracked by Git.

These changes help streamline project management by excluding unnecessary files from indexing and version control.
2026-03-22 15:30:42 +08:00
BruceChen
a3c918e946 feat: implement physics engine for player movement and collision detection
- Introduced a comprehensive physics engine that replicates Minecraft's movement mechanics, including player input handling, gravity, and collision detection.
- Added classes for player physics, movement input, and collision detection, ensuring accurate simulation of player interactions with the game world.
- Integrated AABB (Axis-Aligned Bounding Box) structures for precise collision detection against blocks.
- Enhanced movement capabilities with support for jumping, sneaking, and sprinting, along with step-up mechanics for navigating terrain.

These changes significantly improve the realism and responsiveness of player movement within the game environment.
2026-03-22 15:29:22 +08:00
BruceChen
cca4134e8b feat: enhance decompilation and server management scripts
- Introduced `decompile.sh` to automate the decompilation process, including downloading `MinecraftDecompiler.jar` and server.jar for specified Minecraft versions.
- Added `mc-rcon.sh` for sending RCON commands to a Minecraft server, improving server management capabilities.
- Created `mcc-env.sh` to provide helper functions for managing Minecraft servers, including starting, stopping, and sending commands.
- Implemented `start-server.sh` to launch a Minecraft server in a tmux session with a named pipe for stdin, facilitating easier command input.
- Updated `README.md` to reflect new tools and usage instructions for decompiling and server management.

These changes streamline the workflow for adapting to new Minecraft versions and enhance the overall development experience.
2026-03-22 15:28:57 +08:00
breadbyte
9e3bfaa868 Update ConsoleInteractive submodule 2026-03-22 13:50:20 +08:00
Anon
d3151925fe
Merge pull request #2950 from milutinke/bug-fixes-2026-03 2026-03-22 00:44:40 +01:00
Anon
e2746ae0d1 Implemented new Delcare Command packet for new versions 1.20.6-1.21.11 and fixed it for 1.20.4. 2026-03-22 00:42:43 +01:00
Anon
c5b22eb1b2
Merge pull request #2948 from milutinke/bug-fixes-2026-03 2026-03-21 22:46:57 +01:00
Anon
b4e69da81f Temporary fix for Declare Commands crashing sending commands in chat. 2026-03-21 22:44:57 +01:00
Anon
9f4abfdd39
Merge pull request #2947 from milutinke/bug-fixes-2026-03 2026-03-21 22:37:13 +01:00
Anon
c50b9a5b63 Fixed a crash on PlayerInfo packet. 2026-03-21 22:22:18 +01:00
Anon
bd6fb7332f
[skipci]Merge pull request #2946 from MCCTeam/dependabot/npm_and_yarn/docs/minimatch-3.1.5 2026-03-21 21:40:15 +01:00
Anon
6833e60cb5
[skipci]Merge pull request #2945 from MCCTeam/dependabot/npm_and_yarn/docs/immutable-4.3.8 2026-03-21 21:39:59 +01:00
dependabot[bot]
c38162584d
chore(deps): Bump minimatch from 3.1.2 to 3.1.5 in /docs
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.1.2 to 3.1.5.
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 3.1.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-21 20:28:32 +00:00
dependabot[bot]
abe6b9f01b
chore(deps): Bump immutable from 4.1.0 to 4.3.8 in /docs
Bumps [immutable](https://github.com/immutable-js/immutable-js) from 4.1.0 to 4.3.8.
- [Release notes](https://github.com/immutable-js/immutable-js/releases)
- [Changelog](https://github.com/immutable-js/immutable-js/blob/main/CHANGELOG.md)
- [Commits](https://github.com/immutable-js/immutable-js/compare/v4.1.0...v4.3.8)

---
updated-dependencies:
- dependency-name: immutable
  dependency-version: 4.3.8
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-21 20:27:38 +00:00
Anon
1ac9df86a4
Merge pull request #2944 from milutinke/net-10 2026-03-21 21:23:43 +01:00
Anon
5b9cc4aa0e Tested the client against 1.21.11 on .net 10. Created a integration testing skill (end-to-end). 2026-03-21 21:02:13 +01:00
Anon
fb896c45a7 Fixed a typo in a workflow YAML. 2026-03-21 20:11:14 +01:00
Anon
28834e7a86 Implemented .net 10 support. Updated all affected libraries and the code. Not testes yet. 2026-03-21 20:07:20 +01:00
Anon
5488140261
[skipci]Merge pull request #2941 from milutinke/skills-centralization 2026-03-21 19:36:17 +01:00
Anon
3f431f1104 Added skill-creator skill from Anthropic 2026-03-21 19:26:52 +01:00
BruceChen
78dc74a6f0
Merge pull request #2943 from BruceChenQAQ/master
fix: use HashedStack for container_click and fix enchantments parsing…
2026-03-22 02:23:08 +08:00
Anon
bf04141167 Improved AGENTS.md 2026-03-21 19:20:35 +01:00
BruceChen
c0c4c078c0 fix: use HashedStack for container_click and fix enchantments parsing for 1.21.5+
Two bugs fixed:

1. EnchantmentsComponent was reading a trailing ShowTooltip boolean that
   was removed from the wire format in MC 1.21.5. Created
   EnchantmentsComponent1215 and StoredEnchantmentsComponent1215 that
   omit the boolean. Used by StructuredComponentsRegistry1215 and 12111.

2. MC 1.21.5+ changed ServerboundContainerClickPacket to use HashedStack
   (item holder id + count + hashed component patch map) instead of full
   ItemStack for changed slots and carried item. Added GetHashedItemSlot()
   in DataTypes.cs and gated SendWindowAction in Protocol18.cs to use it
   for 1.21.5+. Since MCC doesn't track component hashes, an empty
   HashedPatchMap is sent; the server detects stateId mismatch and resyncs.

Tested: AutoFishing bot successfully catches fish on MC 1.21.11 with
enchanted fishing rods (Lure III + Luck of the Sea III).

Made-with: Cursor
2026-03-22 02:18:01 +08:00
Anon
cf5c4f00cb Added AGENTS.md/CLAUDE.md and a C# 12 best practices skill for MCC. 2026-03-21 19:12:13 +01:00
BruceChen
bc60e99a63
Merge pull request #2942: Add Minecraft 1.21.11 (Protocol 774) Support
Add Minecraft 1.21.11 (Protocol 774) Support
2026-03-22 01:38:31 +08:00
BruceChen
6c36dc341a feat: add version routing, structured components, and metadata for MC 1.21.11
- Add MC_1_21_11_Version constant (protocol 774)
- Create StructuredComponentsRegistry12111 with 104 components (8 new:
  use_effects, minimum_attack_charge, damage_type, attack_range,
  piercing_weapon, kinetic_weapon, swing_animation, zombie_nautilus/variant)
- Add 6 new component classes for 1.21.11 wire formats
- Add RegistryEitherHolderComponent for holderRegistry-backed EitherHolder
- Add ZombieNautilusVariant and HumanoidArm cases in DataTypes.ReadNextMetadata
- Update all version routing in Protocol18, PacketType18Handler,
  EntityMetadataPalette, StructuredComponentsHandler, and ProtocolHandler
- Bump MCHighestVersion to 1.21.11

Made-with: Cursor
2026-03-22 00:56:04 +08:00
BruceChen
50b4b3c8fe feat: add palettes and enums for MC 1.21.11 (protocol 774)
Add 17 new items (spears, nautilus armor, spawn eggs, netherite horse armor),
4 new entities (CamelHusk, Nautilus, Parched, ZombieNautilus), and 2 new
entity metadata serializer types (ZombieNautilusVariant, HumanoidArm).

Generated ItemPalette12111 (1505 items), EntityPalette12111 (157 entities),
and EntityMetadataPalette12111 (39 serializers) from server reports.

Made-with: Cursor
2026-03-22 00:49:33 +08:00
Anon
a1c1dbc182 Added bot creation skill 2026-03-21 17:34:34 +01:00
Anon
918f1a560d Centralized skills to .skills folder. 2026-03-21 14:44:47 +01:00
BruceChen
c5537c0444
Merge pull request #2940: Add Minecraft 1.21.9/1.21.10 (Protocol 773) Support
Add Minecraft 1.21.9/1.21.10 (Protocol 773) Support
2026-03-21 15:35:06 +08:00
BruceChen
34671fdab2 feat: enhance palette generation and validation for MC 1.21.9
Updated the SKILL.md documentation to include critical steps for generating server reports and validating decompiled source against server data, emphasizing the importance of using server data since MC 1.21.9. Enhanced the diff_registries.py script to support cross-validation with server registries.json, allowing for accurate palette generation. Added new scripts for generating block and entity palettes from server data, ensuring completeness and correctness of entries.

This update improves the workflow for adapting to new Minecraft versions and ensures that palette generation reflects the latest changes in item and block registration.

Made-with: Cursor
2026-03-21 15:04:20 +08:00
BruceChen
60c2b9ea7e
Merge pull request #2939: Add Minecraft 1.21.7/1.21.8 (Protocol 772) Support
Add Minecraft 1.21.7/1.21.8 (Protocol 772) Support
2026-03-21 14:45:13 +08:00
BruceChen
aebfcd93e4 fix: regenerate item/block palettes from server registry data for 1.21.9
MC 1.21.9 changed how some items and blocks are registered — 24 block
items (copper bars/chains/lanterns variants, potted azalea renames) and
additional blocks are now registered outside of Items.java/Blocks.java
field declarations, making the previous source-field-order-based palette
generation produce incorrect protocol IDs.

Regenerated ItemPalette1219.cs using server registries.json (1488 items,
up from 1464) and Palette1219.cs using blocks.json (1166 blocks with
correct state IDs). Added 37 new enum values to ItemType.cs (35 new +
DryShortGrass/DryTallGrass for backward compat) and 9 new values to
Material.cs.

Verified all item/block/entity identification against a 1.21.10 server.

Made-with: Cursor
2026-03-21 14:43:56 +08:00
BruceChen
6d3c58b29f fix: handle LpVec3 movement encoding in SpawnEntity for 1.21.9+
Minecraft 1.21.9 changed the SpawnEntity (Add Entity) packet layout:
the velocity/movement field was moved before the angle fields and
switched from 3 x Short to a new variable-length LpVec3 encoding.

Add ReadNextLpVec3() to consume the LpVec3 wire format (1 byte header,
optionally 5+ more bytes with a continuation VarInt), and update
ReadNextEntity() to use the new field order for protocol >= 773.

Made-with: Cursor
2026-03-21 14:11:23 +08:00
BruceChen
88e9c671da feat: add version routing and metadata reading for MC 1.21.9
- Route block/entity/item/packet/metadata palettes to new 1219 variants
  for protocol >= 773, and raise upper-bound guards from MC_1_21_7 to
  MC_1_21_9 so terrain, inventory, and entity handling are enabled.
- Add DataTypes readers for three new entity metadata serializer types:
  CopperGolemState and WeatheringCopperState (both VarInt), and
  ResolvableProfile (composite: Either<GameProfile, Partial> with
  optional name/UUID/properties + PlayerSkin.Patch with 4 optional
  fields for body/cape/elytra texture ResourceLocations and model type).

Made-with: Cursor
2026-03-21 14:05:06 +08:00
BruceChen
67ad5fcf97 feat: add palettes for MC 1.21.9/1.21.10 (protocol 773)
- Palette1219.cs: 1053 blocks with new copper chests, copper golem
  statues, copper torches, shelves, oxidized lightning rods, iron chain
- EntityPalette1219.cs: 153 entities (+copper_golem at 27, mannequin at 82)
- ItemPalette1219.cs: 1464 items (generated via gen_item_palette.py)
- EntityMetadataPalette1219.cs: 37 serializers (COMPOUND_TAG removed,
  +CopperGolemState, WeatheringCopperState, ResolvableProfile)
- PacketPalette1219.cs: updated clientbound IDs for 4 new debug packets
  and GameTestHighlightPos, plus config CodeOfConduct/AcceptCodeOfConduct

Also update gen_entity_metadata_palette.py FIELD_TO_ENUM with the three
new serializer type mappings.

Made-with: Cursor
2026-03-21 14:04:56 +08:00
BruceChen
2af0409d00 feat: add MC 1.21.9/1.21.10 (protocol 773) version constants and enum values
Register protocol 773 for Minecraft 1.21.9 and 1.21.10 (which share the
same protocol as a hotfix release). Update MCHighestVersion to 1.21.10.

Add 49 new item types (copper tools/armor, shelves, copper chests,
copper golem statue variants, oxidized lightning rods, iron chain, etc.),
2 new entity types (CopperGolem, Mannequin), 38 new block materials,
3 new entity metadata serializer types (CopperGolemState,
WeatheringCopperState, ResolvableProfile), and 6 new packet types
(DebugBlockValue, DebugChunkValue, DebugEntityValue, DebugEvent,
GameTestHighlightPos, CodeOfConduct, AcceptCodeOfConduct).

Chain item/block renamed to IronChain in 1.21.9; old enum values
retained for backward compatibility with older palettes.

Made-with: Cursor
2026-03-21 14:04:42 +08:00
BruceChen
7e26542055
Merge pull request #2938: Add Minecraft 1.21.6 (Protocol 771) Support
Add Minecraft 1.21.6 (Protocol 771) Support
2026-03-21 13:22:14 +08:00
BruceChen
5e8d715358 feat: add MC 1.21.7/1.21.8 (protocol 772) support
1.21.7 and 1.21.8 share protocol 772. The only registry change from
1.21.6 is one new item (music_disc_lava_chicken). All other palettes
(blocks, entities, packets, entity metadata, structured components)
are unchanged and reuse 1.21.6 versions.

Changes:
- Add MC_1_21_7_Version (772) constant
- Add "1.21.7" / "1.21.8" version mappings in ProtocolHandler
- Add MusicDiscLavaChicken to ItemType enum
- Generate ItemPalette1217 (1416 items) for the new item palette
- Update all version upper-bound checks from MC_1_21_6 to MC_1_21_7
- Update MCHighestVersion to "1.21.8"

Made-with: Cursor
2026-03-21 13:10:30 +08:00
BruceChen
067395ab2a fix: correct biome data array length calculation for 1.21.5+ terrain parsing
The biome PalettedContainer data array length was calculated as
ceil(64 * bitsPerEntry / 64) which is incorrect for non-power-of-2
bit widths. The correct calculation uses SimpleBitStorage's formula:
valuesPerLong = 64 / bitsPerEntry, then ceil(64 / valuesPerLong).

For example, with bitsPerEntry=3: old formula gave 3 longs but the
actual data contains 4 longs (valuesPerLong=21, ceil(64/21)=4).

This bug was masked in 1.21.5 by excess padding bytes in chunk buffers
(due to PalettedContainer.Data.getSerializedSize over-counting). MC
1.21.6 fixed the size calculation server-side, removing the padding
and exposing this pre-existing MCC bug.

Made-with: Cursor
2026-03-21 12:11:18 +08:00
BruceChen
1b0e27fde7 feat: add palettes and version routing for MC 1.21.6
- ItemPalette1216: 1415 items (generated from decompiled Items.java)
- EntityPalette1216: 151 entities (HappyGhast at index 56, all after +1)
- Palette1216: block states (DriedGhast 32 states at 13826-13857, all after +32)
- PacketPalette1216: clientbound +3 (Waypoint, ClearDialog, ShowDialog),
  serverbound +2 (ChangeGameMode at 0x04 shifting all after, CustomClickAction at end),
  config clientbound +2 (ClearDialog, ShowDialog),
  config serverbound +1 (CustomClickAction)
- Version routing in Protocol18.cs, PacketType18Handler.cs, EntityMetadataPalette.cs
  updated to select 1216 palettes for protocol >= 771
- EntityMetadataPalette reuses 1215 (EntityDataSerializers unchanged)

Made-with: Cursor
2026-03-21 11:44:12 +08:00
BruceChen
96a7e4a659 feat: add MC 1.21.6 (protocol 771) version constants and enum values
- Add protocol 771 constant MC_1_21_6_Version in Protocol18.cs
- Register 1.21.6 in ProtocolHandler (version map, supported list)
- Extend upper-bound checks from MC_1_21_5 to MC_1_21_6
- Add 19 new ItemType entries (16 colored Harnesses, DriedGhast,
  HappyGhastSpawnEgg, MusicDiscTears)
- Add HappyGhast to EntityType enum
- Add DriedGhast to Material enum
- Add new packet types: Waypoint, ClearDialog, ShowDialog (clientbound),
  ChangeGameMode, CustomClickAction (serverbound),
  ClearDialog, ShowDialog (config clientbound),
  CustomClickAction (config serverbound)

Made-with: Cursor
2026-03-21 11:34:20 +08:00
Anon
26bee79a5d
skipci | Merge pull request #2937 from MCCTeam/copilot/fix-skipci-ci-check 2026-03-20 22:54:24 +01:00
copilot-swe-agent[bot]
4efe75174e Fix skipci CI/CD skip feature in GitHub Actions workflow
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/e765016c-a3e8-4423-b21c-b05ec19cb97a
2026-03-20 21:51:53 +00:00
copilot-swe-agent[bot]
779de6c996 Initial plan 2026-03-20 21:47:21 +00:00
Anon
668f27a221
[skipci]Merge pull request #2924 from MCCTeam/dependabot/npm_and_yarn/docs/webpack-5.105.0 2026-03-20 22:17:43 +01:00
Anon
ec094399df
[skipci]Merge pull request #2921 from MCCTeam/dependabot/npm_and_yarn/docs/lodash-4.17.23 2026-03-20 22:17:30 +01:00
Anon
a277cde85a
[skipci]Merge pull request #2908 from MCCTeam/dependabot/npm_and_yarn/docs/node-forge-1.3.2 2026-03-20 22:17:16 +01:00
Anon
e2f6494933
[skipci]Merge pull request #2907 from MCCTeam/dependabot/npm_and_yarn/docs/js-yaml-3.14.2 2026-03-20 22:16:51 +01:00
BruceChen
23a1629113
Merge pull request #2933: Add Minecraft 1.21.5 (Protocol 770) Support
Add Minecraft 1.21.5 (Protocol 770) Support
2026-03-21 01:59:27 +08:00
BruceChen
066a1d1238 Remove unused script 2026-03-21 01:15:39 +08:00
BruceChen
5d00fa6ea6
Merge pull request #2932: Add Minecraft 1.21.4 (Protocol 769) Support
Add Minecraft 1.21.4 (Protocol 769) Support
2026-03-21 01:11:16 +08:00
BruceChen
26e8a2f2e6 fix: adapt chat packet format for MC 1.21.5 (protocol 770)
1.21.5 changed LastSeenMessages.Update to include a trailing checksum
byte (0 = skip verification). This affects serverbound chat and signed
chat command packets.

Additionally, the clientbound PlayerChat packet now has a globalIndex
VarInt prepended before the sender UUID.

Without these fixes:
- Sending plain chat messages causes DecoderException on the server
- Receiving player chat messages causes Queue empty crash in MCC

Made-with: Cursor
2026-03-21 01:08:08 +08:00
BruceChen
9af6c643e3 fix: handle 1.21.5 chunk data format changes
In 1.21.5, two wire format changes in level chunk packets:
1. Heightmaps changed from NBT CompoundTag to map<VarInt, long[]> encoding
2. PalettedContainer data arrays no longer have VarInt length prefix
   (uses writeFixedSizeLongArray instead of writeLongArray)

Both changes affect ChunkData (level_chunk_with_light) packet parsing.
Without this fix, MCC crashes with "Queue empty" when processing chunks.

Made-with: Cursor
2026-03-21 00:54:27 +08:00
BruceChen
8df39ba74a feat: add MC 1.21.5 (protocol 770) support
Full protocol adaptation for Minecraft 1.21.5:

- Protocol version mapping: 770 -> 1.21.5
- Packet palette: AddExperienceOrb removed (S2C), TestInstanceBlockStatus
  added (S2C), SetTestBlock and TestInstanceBlockAction added (C2S)
- Entity metadata palette: 5 new serializer types (OptionalLivingEntityReference,
  CowVariant, WolfSoundVariant, PigVariant, ChickenVariant), OPTIONAL_UUID
  replaced by OPTIONAL_LIVING_ENTITY_REFERENCE
- Item palette: 11 new items (Bush, FireflyBush, DryShortGrass, DryTallGrass,
  Wildflowers, LeafLitter, CactusFlower, TestBlock, TestInstanceBlock,
  BlueEgg, BrownEgg)
- Entity palette: Potion split into SplashPotion and LingeringPotion
- Block palette: 9 new blocks (bush, cactus_flower, firefly_bush, leaf_litter,
  short_dry_grass, tall_dry_grass, test_block, test_instance_block, wildflowers)
- Structured components: 31 new components including tooltip_display, weapon,
  blocks_attacks, potion_duration_scale, provides_trim_material,
  provides_banner_patterns, break_sound, and 25 entity variant components;
  unbreakable changed from Bool to Unit; instrument changed to EitherHolder

Made-with: Cursor
2026-03-21 00:48:27 +08:00
BruceChen
9c1502600a chore: update .gitignore to include additional debug files
Added entries to the .gitignore file to exclude possible debug files related to Minecraft, including language files, input configurations, and backup files.

Made-with: Cursor
2026-03-21 00:09:58 +08:00
BruceChen
c31739ddd1 chore: update .gitignore to include Minecraft official source code directory
Added a new entry to the .gitignore file to exclude the directory for decompiled Minecraft official source code. Also ensured that the .vscode/launch.json file is not ignored.

Made-with: Cursor
2026-03-20 23:59:06 +08:00
BruceChen
067bd8faff fix: resolve PickItem duplicate key in PacketPalette1214
The PickItem packet was split into PickItemFromBlock (0x22) and
PickItemFromEntity (0x23) in 1.21.4. Mapping both to the same
PacketTypesOut.PickItem enum caused a duplicate key error in the
reverse mapping. Added PickItemFromEntity enum to resolve this.

Made-with: Cursor
2026-03-20 23:55:27 +08:00
BruceChen
f73148e5ec feat: add MC 1.21.4 (protocol 769) support
Add complete protocol 769 support for Minecraft 1.21.4:

- Version constants: Add 769 to supported versions, MC_1_21_4_Version constant,
  and version string mappings (including 1.21.3 -> 768 compatibility)
- Item palette: 10 new items (Resin series + Eyeblossom), generated ItemPalette1214
- Entity palette: Remove CreakingTransient (149 entities, down from 150)
- Block palette: 10 new blocks with correct blockstate ID ranges from server data
- Packet palette: Serverbound packet ID reshuffling - PickItem split into
  PickItemFromBlock/PickItemFromEntity, new PlayerLoaded packet inserted after
  PlayerInput, subsequent IDs shifted accordingly. Clientbound unchanged.
- PlayerLoaded: Send empty PlayerLoaded packet after JoinGame processing (>= 1.21.4)
- EntityMetadata/DataComponents: Reuse 1.20.6 palettes (unchanged registries)
- Update all version guard checks from MC_1_21_2 to MC_1_21_4

Made-with: Cursor
2026-03-20 23:51:56 +08:00
BruceChen
5dec0ac471
Merge pull request #2931 from MCCTeam/1.20.6
fix: update ConsoleInteractive submodule to .NET 8
2026-03-20 23:09:59 +08:00
BruceChen
3acfc0aaa4 fix: update ConsoleInteractive submodule to .NET 8
Update submodule to commit a045f7e which adds net8.0 target framework,
fixing NETSDK1005 build error in CI when publishing with -f net8.0.

Made-with: Cursor
2026-03-20 23:05:44 +08:00
BruceChen
e5de803613
Merge pull request #2930: Further Protocol Adaptation for 1.20.6 / 1.21 / 1.21.2
Further Protocol Adaptation for 1.20.6 / 1.21 / 1.21.2
2026-03-20 22:53:06 +08:00
BruceChen
a92bf5b071 feat: complete 1.21.2 protocol handling for terrain, inventory, and entity support
The previous commits added palette files, packet IDs, and structured components
for MC 1.21.2 (protocol 768), but terrain/inventory/entity features were still
disabled at runtime because the version guards in the constructor checked
> MC_1_21_Version (767) instead of > MC_1_21_2_Version (768).

This commit completes the 1.21.2 adaptation with the following changes:

- Update feature-disable guards from > MC_1_21_Version to > MC_1_21_2_Version
  so terrain, inventory, and entity handling are enabled for protocol 768
- Update healthField metadata index guard to > MC_1_21_2_Version
- Handle container ID encoding change: byte -> VarInt for 1.21.2+ in both
  clientbound reads (CloseWindow, WindowItems, WindowProperty, SetSlot) and
  serverbound sends (ClickWindow, CloseWindow)
- Handle EntityTeleport format change: 1.21.2 uses PositionMoveRotation
  (pos + delta + float angles) + relative flags bitmask (int) + onGround
- Handle TimeUpdate format change: 1.21.2 appends a tickDayTime boolean
- Add handlers for new 1.21.2 packets: EntityPositionSync, PlayerRotation,
  SetCursorItem, SetPlayerInventory, MoveMinecartAlongTrack, and
  RecipeBookAdd/Remove/Settings (ignored, MCC doesn't track recipes)

Tested: successful connection to 1.21.2 vanilla server with inventory,
entity tracking, and chat all working correctly.

Made-with: Cursor
2026-03-20 03:45:32 +08:00
BruceChen
57a0dedb33 feat: add packet palette, data components, and protocol fixes for MC 1.21.2
Packet Palette (Phase 2.1):
- Create PacketPalette1212.cs with complete ID mapping for protocol 768
  (131 clientbound + 60 serverbound play packets, plus config packets)
- Add new PacketTypesIn enum values: EntityPositionSync, MoveMinecartAlongTrack,
  PlayerRotation, RecipeBookAdd/Remove/Settings, SetCursorItem, SetHeldSlot,
  SetPlayerInventory
- Add new PacketTypesOut enum values: BundleItemSelected, ClientTickEnd
- Update PacketType18Handler routing for 1.21.2

Data Components (Phase 1.4):
- Create StructuredComponentsRegistry1212 with 67 components (was 57 in 1.21)
  reflecting the new 1.21.2 DataComponents ordering
- Implement 11 new component parsers: ConsumableComponent, UseRemainderComponent,
  UseCooldownComponent, DamageResistantComponent, EnchantableComponent,
  EquippableComponent, RepairableComponent, GliderComponent, TooltipStyleComponent,
  DeathProtectionComponent, ItemModelComponent
- Create FoodComponent1212 (simplified: nutrition/saturation/canAlwaysEat only;
  eatSeconds/effects/usingConvertsTo moved to consumable/use_remainder)
- Create SubComponentRegistry1212 and route in StructuredComponentsHandler

Protocol Fixes:
- Fix PlayerPositionAndLook packet for 1.21.2 (new format: teleportId first,
  added deltaMovement Vec3, flags as Int instead of Byte)
- Fix login success packet (remove strictErrorHandling read for >= 1.21.2)
- Fix ClientSettings/ClientInformation packet (add particleStatus VarInt)
- Add SetHeldSlot as alias for HeldItemChange in packet handler

Verified: MCC connects to 1.21.2 vanilla server, stays connected, chat works.
Made-with: Cursor
2026-03-20 03:25:20 +08:00
BruceChen
df833ae2a8 feat: add palettes and version constants for MC 1.21.2 (protocol 768)
Add item, entity, block, and metadata palettes for Minecraft 1.21.2:
- ItemPalette1212: 1375 items (42 new: pale oak set, colored bundles,
  creaking heart/spawn egg, banner patterns)
- EntityPalette1212: 150 entity types (boats split into per-wood-type
  entries, generic boat/chest_boat removed; added creaking,
  creaking_transient, pale oak boats)
- Palette1212 (blocks): 1084 block types with state IDs generated from
  official 1.21.2 data reports (24 new pale oak blocks, creaking heart,
  pale moss variants)
- EntityMetadataPalette: reuses 1206 (serializers unchanged in 1.21.2)

Updated version infrastructure:
- Protocol18.cs: MC_1_21_2_Version = 768, palette switch routing
- ProtocolHandler.cs: version mapping 1.21.2 <-> 768
- Program.cs: MCHighestVersion bumped to 1.21.2
- ItemType.cs, EntityType.cs, Material.cs: new enum entries

Note: packet palette, structured components, and protocol handler
changes for 1.21.2 are not yet implemented — this commit covers
palette/registry groundwork only.

Made-with: Cursor
2026-03-20 03:02:43 +08:00
BruceChen
896263acc8 fix: resolve entity tracking, container interaction, and enchantment mapping issues for 1.21
- SpawnEntity packet handler now registers non-player entities via OnSpawnEntity
  for protocol >= 1.20.2 (previously only players were tracked, causing 'entity near'
  to find nothing)
- PlaceBlock gains lookAtBlock option that sends a position/rotation update before the
  block placement packet, fixing containers not opening via useblock
- Enchantment registry IDs are now dynamically parsed from server RegistryData
  (minecraft:enchantment), fixing incorrect enchantment name display in 1.21
- AttributeModifiersComponent uses base SubComponent type to avoid InvalidCastException
  when parsing 1.21-specific attribute subcomponents

Made-with: Cursor
2026-03-20 02:35:52 +08:00
BruceChen
7609832976 chore: add reusable version adaptation scripts
Add tools/ directory with Python scripts for comparing Minecraft version
registries and generating MCC palette files:

- diff_registries.py: Compare Items/EntityTypes/Blocks/DataComponents/
  EntityDataSerializers between two decompiled MC versions, reporting
  which palettes need updating with ID shift analysis.
- gen_item_palette.py: Generate ItemPaletteXXX.cs from Items.java field
  declaration order, with name validation against ItemType.cs.
- gen_entity_metadata_palette.py: Generate EntityMetadataPaletteXXX.cs
  from EntityDataSerializers.java registration order.
- README.md: Usage documentation for all scripts.

Made-with: Cursor
2026-03-20 01:51:56 +08:00
BruceChen
e1cb18c6f8 fix: add EntityMetadataPalette1206 for correct 1.20.6+ entity metadata parsing
1.20.6 introduced three new EntityDataSerializer types compared to 1.20.4:
- PARTICLES (id 18) - list of particles, inserted after PARTICLE
- WOLF_VARIANT (id 23) - wolf variant holder, inserted after CAT_VARIANT
- ARMADILLO_STATE (id 28) - armadillo state, inserted after SNIFFER_STATE

These insertions shifted subsequent serializer IDs, causing the 1.19.4
palette (EntityMetadataPalette1194) to misidentify metadata types on
1.20.6+ servers. This could lead to incorrect byte consumption and
potential packet parse failures when entities with affected metadata
types (e.g. wolves, armadillos, area effect clouds with particles)
were present.

Changes:
- Add Particles, WolfVariant, ArmadilloState to EntityMetaDataType enum
- Create EntityMetadataPalette1206 with correct 31-entry ID mapping
- Route 1.20.6+ to the new palette in EntityMetadataPalette.GetPalette()
- Add read logic for the three new types in DataTypes.cs

Verified on 1.21.1 vanilla server: cat, wolf, frog, armadillo, painting
entities all spawn without metadata parse errors.

Made-with: Cursor
2026-03-20 01:43:48 +08:00
BruceChen
ee02974abe fix: Explosion packet parsing and update attribute fallback for 1.21
Fix the Explosion packet handler that was truncating reads at the
knockback fields, leaving BlockInteraction, particles, and SoundEvent
bytes unconsumed for 1.20.4+. The old commented-out code had three bugs:
conditional particle read (should always read both small and large),
reading SoundEvent as a plain string (it's a Holder<SoundEvent> encoded
as VarInt id + optional inline DIRECT_STREAM_CODEC), and an incorrect
fixedRange version gate. Verified against decompiled ClientboundExplodePacket
from both 1.20.6 and 1.21.1 — the wire format is identical across versions.

Update LoadDefaultAttributes() fallback to match the 1.21.1 registry
order (31 attributes), adding 9 new entries: burning_time,
explosion_knockback_resistance, mining_efficiency, movement_efficiency,
oxygen_bonus, sneaking_speed, submerged_mining_speed,
sweeping_damage_ratio, and water_movement_efficiency. This fallback is
only used when the server omits the attribute RegistryData packet.

Made-with: Cursor
2026-03-20 01:29:18 +08:00
BruceChen
c23c229eb2 feat: protocol 767 (1.21) packet handling and AttributeSubComponent update
- Add AttributeSubComponent121 that uses ResourceLocation(string) instead
  of UUID+Name, matching the 1.21 attribute modifier wire format change.
  Register it in SubComponentRegistry121 via new ReplaceSubComponent method.
- Add ProjectilePower packet handler: reads 1 double (accelerationPower)
  for 1.21+, or 3 doubles (xPower/yPower/zPower) for 1.20.6.
- Add CustomReportDetails and ServerLinks packet handlers in both Play
  and Configuration phases, consuming all fields to prevent byte offset
  errors on 1.21 servers.

Made-with: Cursor
2026-03-20 01:22:25 +08:00
BruceChen
2fb09342a3 feat: add ItemPalette121 and new 1.21 music disc item types
Add ItemPalette121.cs with item ID mappings for MC 1.21 (protocol 767).
Add three new music disc entries to ItemType enum: MusicDiscCreator,
MusicDiscCreatorMusicBox, and MusicDiscPrecipice, introduced in 1.21.

Made-with: Cursor
2026-03-20 01:22:16 +08:00
BruceChen
cc10f4effa refactor: StructuredComponents batch 5 audit — remove redundant count fields
Audited batch 5 components (ChargedProjectiles, BundleContents, Container,
WritableBookContent, BlockState, PotDecorations) against official 1.20.6
decompiled STREAM_CODEC definitions. All network encodings were correct.

Removed redundant NumberOfItems/NumberOfPages/NumberOfProperties fields from
ContainerComponent, WritableBlookContentComponent, BlockStateComponent, and
PotDecorationsComponent. Serialize now uses the actual collection .Count
instead of a potentially stale cached value, matching the pattern already
used by ContainerComponent's Serialize and other components.

Also modernized loop style (foreach with deconstruction where applicable)
and fixed a typo in an exception message ("setialize" -> "serialize").

Made-with: Cursor
2026-03-20 00:45:50 +08:00
BruceChen
5e416d6b72 fix: StructuredComponents batch 4 audit — CustomName, ItemName, Lore use NBT encoding
In 1.20.6+, ComponentSerialization.STREAM_CODEC uses
ByteBufCodecs.fromCodecWithRegistries (NBT tag format), not plain string.
The previous implementation incorrectly used ReadNextString/GetString
for custom_name (5), item_name (6), and lore (7) components.

Fixed all three to use ReadNextNbt/GetNbt, preserving raw NBT data for
round-trip serialization while still extracting readable text via
ChatParser.ParseText(Dictionary).

Other batch 4 components (custom_data, entity_data, bucket_entity_data,
block_entity_data, debug_stick_state, map_decorations, recipes, lock,
container_loot, intangible_projectile — all NBT; hide_additional_tooltip,
hide_tooltip, fire_resistant, creative_slot_lock — all Unit/Empty;
note_block_sound — ResourceLocation string) were verified correct.

Made-with: Cursor
2026-03-20 00:33:50 +08:00
BruceChen
c689343371 fix: StructuredComponents batch 3 audit — EnchantmentGlintOverrideComponent type correction
Audited all 14 simple binary components (batch 3): max_stack_size,
max_damage, damage, unbreakable, rarity, custom_model_data, repair_cost,
enchantment_glint_override, ominous_bottle_amplifier, dyed_color,
map_color, map_id, map_post_processing, base_color.

Found and fixed 1 bug:
- EnchantmentGlintOverrideComponent: was reading/writing VarInt but the
  official STREAM_CODEC uses ByteBufCodecs.BOOL (single byte boolean).
  Changed property type from int to bool, Parse from ReadNextVarInt to
  ReadNextBool, and Serialize from GetVarInt to GetBool.

All other 13 components matched the official 1.20.6 STREAM_CODEC
definitions exactly.

Verified in-game: connected to 1.20.6 vanilla server, received items
with enchantment_glint_override=true/false, dyed_color, map_color,
map_id, base_color, unbreakable, rarity, custom_model_data, repair_cost,
damage, max_damage. All parsed and serialized correctly with no errors.

Made-with: Cursor
2026-03-20 00:25:28 +08:00
BruceChen
4944497f5a fix: StructuredComponents batch 2 audit — BlockPredicate and PropertySubComponent serialization
Audited all 8 batch-2 components (enchantments, stored_enchantments,
can_place_on, can_break, lodestone_tracker, firework_explosion, fireworks,
banner_patterns, suspicious_stew_effects, bees) against official 1.20.6
decompiled STREAM_CODEC definitions.

Found and fixed 3 bugs in BlockPredicate/PropertySubComponent:

1. BlockPredicateSubcomponent.Serialize(): missing HasNbt bool write.
   Parse reads the bool but Serialize skipped writing it, causing all
   subsequent fields to be offset by one byte.

2. BlockPredicateSubcomponent.Serialize(): missing Properties list count
   VarInt write. Parse reads VarInt count before iterating, but Serialize
   only wrote the elements without the preceding count.

3. PropertySubComponent: RangedMatcher min/max values must use Optional
   encoding (Bool prefix + conditional String), matching the official
   ByteBufCodecs.either(ExactMatcher, RangedMatcher) where RangedMatcher
   uses ByteBufCodecs.optional(STRING_UTF8) for both min and max fields.
   Previously read/wrote plain Strings unconditionally.

Remaining 6 components (enchantments, stored_enchantments, lodestone_tracker,
firework_explosion, fireworks, banner_patterns, suspicious_stew_effects, bees)
verified correct — no changes needed.

Made-with: Cursor
2026-03-20 00:19:08 +08:00
BruceChen
a36ba23ba6 fix: StructuredComponents batch 1 audit — TrimComponent, ProfileComponent, WrittenBookContent, and NBT serialization
Audited all 8 high-complexity structured components against official 1.20.6
decompiled STREAM_CODEC definitions. Found and fixed bugs in 3 components
plus a systemic NBT serialization issue:

TrimComponent (ID 35):
- Serialize had TrimPatternType and ShowInTooltip incorrectly nested inside
  the TrimMaterialType==0 branch; moved them outside to match Parse logic
- Description fields (TrimMaterial.description, TrimPattern.description) were
  read/written as String but official codec uses ComponentSerialization
  (NBT Tag format); changed to ReadNextNbt/GetNbt

ProfileComponent (ID 46):
- Serialize was missing the HasUniqueId Bool prefix before UUID
- Serialize only wrote properties when count > 0 but omitted the VarInt count
  prefix entirely when empty; now always writes VarInt count

WrittenBookContentComponent (ID 34):
- Page content uses Filterable<Component> where Component is NBT-encoded via
  ComponentSerialization.STREAM_CODEC, not plain String; changed Parse to use
  ReadNextNbt and Serialize to use GetNbt
- Added RawContentNbt/FilteredContentNbt fields to BookPage record for
  round-trip NBT preservation
- Removed unnecessary ChatParser.ParseText on title (it's a plain string)

DataTypes.GetNbt:
- Added TAG_String root support for 1.20.4+ (chat components like "Page 1"
  are encoded as TAG_String, not TAG_Compound)
- Fixed root name handling: versions >= 1.20.2 omit the root compound name,
  but GetNbt was unconditionally writing it

Components confirmed correct (no changes needed):
- FoodComponentComponent (ID 20), ToolComponent (ID 22),
  InstrumentComponent (ID 40), PotionContentsComponent (ID 31),
  AttributeModifiersComponent (ID 12)

Made-with: Cursor
2026-03-20 00:09:05 +08:00
BruceChen
79a0dff8cd Fix enchantment name display for 1.20.6 structured components
EnchantmentsComponent (used by both regular and stored enchantments)
was directly casting the registry VarInt ID to the Enchantments enum
via (Enchantments)id. However, the Enchantments enum is ordered
alphabetically (AquaAffinity=0, BaneOfArthropods=1, ..., Sharpness=32)
while the 1.20.6 registry uses a completely different order
(protection=0, fire_protection=1, ..., sharpness=13). This caused all
enchantment names to display incorrectly (e.g. Sharpness V shown as
"Unknown Enchantment with ID: 32").

Changes:
- Parse now uses EnchantmentMapping.GetEnchantmentByRegistryId1206()
  to properly map registry IDs to enum values via the existing
  1.20.6+ mapping table
- Serialize now uses EnchantmentMapping.GetRegistryId1206ByEnchantment()
  to convert enum values back to registry IDs (reverse lookup)
- Fixed translation key prefix: "Enchantments.minecraft." (wrong) ->
  "enchantment.minecraft." (matches en_us.json resource keys)
- Fixed 3 long-standing typos in the Enchantments enum that prevented
  translation lookup from matching resource keys:
  - DepthStrieder -> DepthStrider (depth_strieder vs depth_strider)
  - Efficency -> Efficiency (efficency vs efficiency)
  - Loyality -> Loyalty (loyality vs loyalty)

Verified on vanilla 1.20.6 server: items with sharpness, efficiency,
unbreaking, fortune, mending, and bane_of_arthropods all display
correct localized names (锋利, 效率, 耐久, 时运, 经验修补, 节肢杀手).

Made-with: Cursor
2026-03-19 02:01:15 +08:00
BruceChen
1e2b853b14 Fix PotionContentsComponent and InstrumentComponent serialization for 1.20.6
Both components had incorrect Parse/Serialize implementations that would
cause packet deserialization misalignment when encountered in-game.

PotionContentsComponent (3 bugs):
- Serialize unconditionally wrote VarInt(PotionId) and Int(CustomColor)
  even when HasPotionId/HasCustomColor was false. The official format
  (PotionContents.STREAM_CODEC) uses Optional encoding: Bool(hasValue)
  followed by the value only when true. The extra bytes caused all
  subsequent fields in the packet to be read at wrong offsets.
- Serialize omitted the VarInt(count) prefix for the custom effects list.
  The official codec uses ByteBufCodecs.list() which always writes a
  VarInt count header before the list elements.
- Also fixed typo: PotiononId -> PotionId.

InstrumentComponent (3 bugs):
- The official Instrument.STREAM_CODEC uses ByteBufCodecs.holder() which
  encodes as VarInt(holderId): 0 = inline data, N>0 = registry ref (N-1).
  The SoundEvent field inside uses the same holder pattern. The old code
  unconditionally read SoundName (ResourceLocation) and HasFixedRange/
  FixedRange even when SoundEventHolderId != 0 (registry reference case
  has no inline data).
- UseDuration was read/written as Float, but the official codec uses
  ByteBufCodecs.VAR_INT. This caused a 4-byte vs variable-length
  mismatch that would shift all subsequent data.
- HasFixedRange was read unconditionally when SoundEventHolderId == 0,
  but FixedRange was also read unconditionally. The official SoundEvent
  DIRECT_STREAM_CODEC uses Optional<Float> encoding: Bool(hasValue)
  followed by Float only when true.

These components are used for potion items and goat horns respectively.
Verified against official 1.20.6 decompiled source:
- net.minecraft.world.item.alchemy.PotionContents (STREAM_CODEC)
- net.minecraft.world.item.Instrument (STREAM_CODEC/DIRECT_STREAM_CODEC)
- net.minecraft.sounds.SoundEvent (STREAM_CODEC/DIRECT_STREAM_CODEC)
- net.minecraft.network.codec.ByteBufCodecs (holder/optional/list)

Made-with: Cursor
2026-03-19 01:44:23 +08:00
BruceChen
56f2426c1f Fix StructuredComponent serialization correctness for 1.20.6
Audited all 58 StructuredComponent subclasses against the official Minecraft
1.20.6 decompiled source to verify Parse()/Serialize() symmetry. Found and
fixed four bugs across four components:

1. ContainerComponent: Parse() skipped null item slots (empty slots in a
   container) but Serialize() looped NumberOfItems times using Items[i],
   causing IndexOutOfRangeException when any slot was empty. The official
   ItemContainerContents uses OPTIONAL_STREAM_CODEC which serializes empty
   slots as VarInt(0). Fixed: Parse now stores all slots including nulls,
   Serialize uses Items.Count and iterates all entries. GetItemSlot(null)
   correctly writes VarInt(0) for empty slots.

2. ChargedProjectilesComponent: Used Items.OfType<Item>() in Serialize()
   which silently dropped null entries, causing the serialized count to
   differ from the written VarInt header. The official ChargedProjectiles
   uses STREAM_CODEC (non-optional, no empty slots allowed). Fixed: Items
   list is now List<Item> (non-nullable), Parse defensively skips nulls,
   Serialize writes Items.Count matching the actual list.

3. BundleContentsComponent: Same issue as ChargedProjectilesComponent.
   Applied the same fix pattern.

4. FoodComponentComponent: Two type mismatches vs the official
   FoodProperties.DIRECT_STREAM_CODEC:
   - Saturation was declared as bool and read with ReadNextBool (1 byte),
     but the protocol sends it as float (4 bytes). This caused all
     subsequent fields in the component to be read at wrong offsets,
     corrupting CanAlwaysEat, SecondsToEat, and the effects list.
   - NumberOfEffects was serialized with GetFloat() instead of GetVarInt(),
     writing 4 bytes of IEEE 754 float instead of a variable-length integer.
   Fixed both Parse and Serialize to use correct types.

Also removed redundant NumberOfItems/NumberOfEffects fields from components
where the count is derivable from the list length, and replaced
ArgumentNullException with cleaner patterns.

Tested end-to-end on vanilla 1.20.6 server: item receiving (diamond_sword,
golden_apple, diamond_pickaxe), inventory slot movement (click to pick up
and place), and inventory listing all work correctly with no server-side
protocol errors.

Made-with: Cursor
2026-03-19 01:37:56 +08:00
BruceChen
b692b13bbc Fix EntityProperties crash and add default attribute registry fallback
After the previous commit (99ac3d0) moved attribute lookup from a hardcoded
dictionary to the dynamic RegistryData, MCC would crash immediately upon
joining a vanilla 1.20.6 server with:

  System.ArgumentException: An item with the same key has already been added.
  Key: unknown

Root cause: When KnownDataPacks negotiation tells the server that MCC already
has the "minecraft" data pack, the server skips sending RegistryData for
registries it considers "known" — including minecraft:attribute. This left
the dynamic attribute map empty, so every VarInt attribute ID resolved to
"unknown". The EntityProperties packet often contains multiple attributes
(e.g. armor, max_health, movement_speed), and `keys.Add("unknown", ...)` on
the second "unknown" attribute threw ArgumentException.

Two fixes applied:

1. World.GetAttributeNameById(): When the dynamic attribute map is empty
   (server didn't send the registry), automatically load the vanilla 1.20.6
   default attribute order (22 entries matching Attributes.java registration
   order). This mirrors the pattern used for dimensions where defaults are
   loaded when RegistryData is not sent. If a modded server sends a custom
   attribute registry, the dynamic map takes precedence.

2. Protocol18.cs EntityProperties handler: Change `keys.Add(propertyKey,
   propertyValue2)` to `keys[propertyKey] = propertyValue2` to tolerate
   duplicate keys defensively, in case an unknown attribute ID still appears.

Tested: MCC now connects to a vanilla 1.20.6 offline-mode server, stays
online for 6+ minutes with no crashes or disconnections. Verified: chat
messages received, inventory listing (item names/counts correct), entity
detection, TPS query, and health query all work correctly.

Made-with: Cursor
2026-03-19 01:26:20 +08:00
BruceChen
99ac3d028a Dynamically parse minecraft:attribute registry from server RegistryData
In 1.20.6+, EntityProperties packets reference attributes by VarInt registry
IDs instead of string names. Previously, a hardcoded dictionary of 22 attribute
entries (matching the vanilla 1.20.6 registry) was used to map these IDs back
to names. This works for vanilla servers but would fail silently for modded
servers that add custom attributes — any unknown ID would be reported as
"unknown".

This commit replaces the hardcoded attribute dictionary with dynamic registry
parsing, following the same pattern already used for dimension_type and
chat_type registries:

- World.cs: Add static `attributeIdMap` field, `SetAttributeIdMap()` and
  `GetAttributeNameById()` methods for storing/querying attribute names by
  their VarInt registry IDs.

- Protocol18.cs (RegistryData handler): When the server sends a
  `minecraft:attribute` registry during the Configuration phase, parse all
  entries and store the ID→name mapping. The `minecraft:` prefix is stripped
  from entry names to match the format used in EntityProperties packets
  (e.g. "minecraft:generic.armor" → "generic.armor").

- Protocol18.cs (EntityProperties handler): Remove the hardcoded 22-entry
  `attributeDictionary` and use `World.GetAttributeNameById()` instead.
  Unknown IDs still fall back to "unknown" for safety.

Also closes issue #4 (Disconnect packet extra boolean) — verified that both
Play and Configuration phase Disconnect handlers already use `ReadNextChat()`
(NBT format since 1.20.4+), matching the 1.20.6 protocol spec. No code
changes needed; updated tracking document to mark as closed.

Made-with: Cursor
2026-03-19 01:12:18 +08:00
BruceChen
967f67190c Add FileInputBot for non-interactive debugging and fix NbtToString crash
FileInputBot (ChatBots/FileInputBot.cs):
- New ChatBot that monitors a text file (default: mcc_input.txt) for
  commands, enabling MCC control from Cursor Shell or any non-interactive
  environment where stdin is not available
- Activated by setting MCC_FILE_INPUT env var (e.g. MCC_FILE_INPUT=1)
- Polls every ~500ms for new lines appended to the file
- Lines starting with "/" are sent as server chat/commands
- Other lines are executed as MCC internal commands (same as console input)
- File path overridable via MCC_INPUT_FILE env var

McClient.cs:
- Load FileInputBot when MCC_FILE_INPUT environment variable is set

ChatParser.cs - NbtToString:
- Fix InvalidCastException when NBT "text" or nameless root tag values
  are Int32 instead of String (happens with 1.20.6 SystemChat packets
  containing numeric values in the chat component tree)
- Replace direct (string) casts with ?.ToString() ?? string.Empty

Made-with: Cursor
2026-03-19 00:45:51 +08:00
BruceChen
8eac21b4a4 Wire up 1.20.6 structured components to Item and fix GetItemSlot serialization
In 1.20.6+, items use structured components instead of NBT for metadata.
Previously, ReadNextItemSlot parsed the components but never stored them
on the Item instance, leaving DisplayName/Lores/Damage/Enchantments all
empty. GetItemSlot also still used the pre-1.20.6 format (bool + VarInt +
byte + NBT), causing the server to reject any item operation packets.

Changes:

Item.cs:
- Add List<StructuredComponent>? Components field to hold the raw
  component list for round-trip serialization
- DisplayName property: read from CustomNameComponent (with
  ItemNameComponent as fallback) when Components is present
- Lores property: read from LoreNameComponent1206 when Components is
  present
- Damage property: read from DamageComponent when Components is present
- Add EnchantmentList property: read from EnchantmentsComponent (covers
  both normal and StoredEnchantmentsComponent for enchanted books)
- ToFullString(): use EnchantmentList with EnchantmentMapping for display
  when available, fall back to NBT path for older versions
- Add CloneWithCount() method that preserves both NBT and Components

DataTypes.cs - ReadNextItemSlot:
- Assign parsed strcturedComponentsToAdd to item.Components

DataTypes.cs - GetItemSlot:
- Add 1.20.6+ branch: write VarInt(count) + VarInt(itemId) + component
  counts + serialized components (using each component's TypeId and
  Serialize() method)
- Empty slot sends VarInt(0) per the 1.20.6 protocol spec

StructuredComponent.cs:
- Add int TypeId property (default -1) to store the registry type ID
  assigned during parsing, enabling round-trip serialization

StructuredComponentRegistry.cs:
- Set component.TypeId = id after instantiation in ParseComponent()

McClient.cs:
- Replace manual Item constructor calls (new Item(type, count, nbt))
  with Item.CloneWithCount() to preserve Components during inventory
  operations like slot moves, stack splits, and right-click placement

Made-with: Cursor
2026-03-19 00:34:10 +08:00
BruceChen
bb18399523 Use dynamic dimension registry lookup in JoinGame and Respawn packets
The JoinGame and Respawn packet handlers for 1.20.6+ used hardcoded
switch expressions to map dimension type VarInt IDs to names:
  0 => overworld, 1 => overworld_caves, 2 => the_end, 3 => the_nether

This only works for vanilla servers with exactly 4 default dimensions.
Modded servers (Forge/Fabric/NeoForge) or servers with custom
datapacks can register additional dimensions with IDs beyond 0-3,
causing the switch to fall through to the default "overworld" for
any non-vanilla dimension. This means players in modded dimensions
would have incorrect world parameters (height, lighting, etc.).

Fix: Replace both hardcoded switch expressions with
World.GetDimensionNameById(), which looks up the VarInt ID in
the dimension ID map populated during the RegistryData phase.

Also fixes two pre-existing issues in the SetDimension dispatch:
- JoinGame (pre-1.20.2 path): The `case < MC_1_20_6_Version` guard
  was technically correct within its enclosing `if` block, but
  changed to `default` for clarity and future-proofing.
- Respawn: The `case <= MC_1_20_6_Version` guard excluded protocol
  versions above 766 (e.g. 1.21 / protocol 767), meaning
  SetDimension was never called for those versions. Changed to
  `default` so all versions >= 1.19 properly update the dimension.

Made-with: Cursor
2026-03-19 00:13:57 +08:00
BruceChen
41a701b6b2 Fix RegistryData parsing and KnownDataPacks negotiation for 1.20.6
Two critical issues in the 1.20.6 configuration phase that could cause
connection instability and packet desync:

1. RegistryData: The handler used an early `break` when it encountered
   a registryId other than "minecraft:dimension_type" or
   "minecraft:chat_type". This skipped reading the remaining entries
   for that registry, leaving unconsumed data in the packet buffer.
   Subsequent packet reads would start at the wrong offset, causing
   cascading parse failures and eventual disconnection.

   Fix: Always read all entries (entryId + hasData + optional NBT)
   for every registry, regardless of whether we process it. For
   dimension_type entries, if the server sends inline NBT data (i.e.
   non-vanilla dimensions from mods/datapacks), parse and store
   the dimension directly via World.StoreOneDimension(). Only fall
   back to hardcoded defaults when no dimension data was received.

2. KnownDataPacks: The client echoed back ALL packs the server
   listed, including non-vanilla ones. This told the server "I have
   these packs cached" when the client actually did not, so the
   server would skip sending full registry data for those packs.
   The result: incomplete registries for modded/datapack content.

   Fix: Filter the response to only include packs with the
   "minecraft" namespace. Non-vanilla packs are omitted, forcing
   the server to send their full registry data inline.

Also adds supporting methods to World.cs:
- SetDimensionIdMap(): Store VarInt ID -> dimension name mapping
  from RegistryData entries (needed by JoinGame/Respawn)
- GetDimensionNameById(): Look up dimension name by numeric ID
- HasAnyDimension(): Check if any dimensions were loaded from
  server-provided data

Made-with: Cursor
2026-03-19 00:13:22 +08:00
BruceChen
a7a95d991c Fix EntityProperties attribute ID mapping for 1.20.6
The 1.20.6 EntityProperties packet sends attribute IDs as VarInts
instead of strings. The existing mapping dictionary had three issues:

1. IDs 5/6/7 used the wrong prefix "generic." but the official
   1.20.6 registry uses "player." for these attributes:
   - 5: player.block_break_speed (was generic.block_break_speed)
   - 6: player.block_interaction_range (was generic.block_interaction_range)
   - 7: player.entity_interaction_range (was generic.entity_interaction_range)

2. IDs 22-24 (submerged_mining_speed, sweeping_damage_ratio,
   water_movement_efficiency) do not exist in the 1.20.6 attribute
   registry — they were introduced in 1.21. Their presence could
   cause incorrect attribute resolution.

3. Direct dictionary indexing (attributeDictionary[id]) throws
   KeyNotFoundException if the server sends an unknown attribute ID,
   crashing the packet handler. Replaced with TryGetValue and a
   safe fallback to "unknown".

Made-with: Cursor
2026-03-19 00:12:06 +08:00
BruceChen
ff1c570a78 Handle non-interactive terminal environments gracefully
When MCC runs in non-interactive terminals (e.g. CI runners, IDE
embedded shells, piped input), several Console APIs throw exceptions
because there is no real console attached.

Changes:
- Program.cs: Wrap Console.KeyAvailable / Console.ReadKey in
  HandleFailure() with try-catch so MCC does not crash on startup
  failure in headless environments.
- Chunk.cs: Wrap Console.BufferWidth / BufferHeight in try-catch
  with fallback values (120x50) to prevent exceptions when rendering
  chunk maps without a console buffer.
- Map.cs: Same treatment for the map rendering path - use safe
  fallback values when Console.BufferWidth/Height are unavailable.
- ReplayHandler.cs: Replace Array.Reverse() (returns void in newer
  .NET) with .AsEnumerable().Reverse() to fix compilation with
  .NET 10 SDK where the void return breaks the fluent chain.

Made-with: Cursor
2026-03-19 00:11:13 +08:00
dependabot[bot]
e2ca8e082b
Bump webpack from 5.94.0 to 5.105.0 in /docs
Bumps [webpack](https://github.com/webpack/webpack) from 5.94.0 to 5.105.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Changelog](https://github.com/webpack/webpack/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack/compare/v5.94.0...v5.105.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-version: 5.105.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-07 06:17:36 +00:00
dependabot[bot]
df79e10f26
Bump lodash from 4.17.21 to 4.17.23 in /docs
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-21 23:07:27 +00:00
breadbyte
494be0930b
Merge branch 'master' into 1.20.6 2025-12-02 00:06:16 +08:00
dependabot[bot]
fdd77b562e
Bump node-forge from 1.3.1 to 1.3.2 in /docs
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.3.1 to 1.3.2.
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.3.1...v1.3.2)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-version: 1.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-26 22:08:58 +00:00
dependabot[bot]
57483646b1
Bump js-yaml from 3.14.1 to 3.14.2 in /docs
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.14.1 to 3.14.2.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.14.1...3.14.2)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 3.14.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-21 21:41:08 +00:00
Anon
f785f509f2
Temporarily removed WebSocket bot due to false positive 2025-05-22 14:03:49 +02:00
Anon
8b20973b02 Temporarily removed WebSocket bot because of a false positive virus detection. I will make it in to a standalone bot later. 2025-05-22 13:56:27 +02:00
Anon
ef7aa04e47
[skipci]Merge pull request #2852 from MCCTeam/dependabot/npm_and_yarn/docs/prismjs-1.30.0 2025-05-22 13:39:59 +02:00
Anon
c0c176a226
[skipci]Merge pull request #2847 from MCCTeam/dependabot/npm_and_yarn/docs/serialize-javascript-6.0.2 2025-05-22 13:39:37 +02:00
Anon
831a86cb4f
Merge pull request #2864 from DevBobcorn/master 2025-05-22 13:37:52 +02:00
Tasuku Bobcorn
19781985f7 Fix reading window items packet in versions below 1.17.1 2025-04-29 13:56:38 +08:00
dependabot[bot]
1cec3f7397
Bump prismjs from 1.29.0 to 1.30.0 in /docs
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.29.0 to 1.30.0.
- [Release notes](https://github.com/PrismJS/prism/releases)
- [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PrismJS/prism/compare/v1.29.0...v1.30.0)

---
updated-dependencies:
- dependency-name: prismjs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-10 22:20:33 +00:00
dependabot[bot]
8726a73b5f
Bump serialize-javascript from 6.0.0 to 6.0.2 in /docs
Bumps [serialize-javascript](https://github.com/yahoo/serialize-javascript) from 6.0.0 to 6.0.2.
- [Release notes](https://github.com/yahoo/serialize-javascript/releases)
- [Commits](https://github.com/yahoo/serialize-javascript/compare/v6.0.0...v6.0.2)

---
updated-dependencies:
- dependency-name: serialize-javascript
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-18 14:17:16 +00:00
Anon
2409de2a2f
Fix prevent AntiCheat Block Breaking (In Scripts)
Fix prevent AntiCheat Block Breaking (In Scripts)
2024-12-25 16:56:07 +01:00
Anon
304c8f04f2
Merge pull request #10 from Visual-Novel-Decompilation-Project/1.20.6
Fix session cache serializer failure
2024-12-24 19:52:30 +01:00
breadbyte
a5ab30f3da Fix session cache serializer failure 2024-12-25 01:28:28 +08:00
Anon
a1acd559d6 Updated the pipeline 2024-12-22 20:05:17 +01:00
Anon
7152072598 Ported to .NET 8 2024-12-22 13:20:04 +01:00
Anon
c38f92a9ec
Merge pull request #2824 from MCCTeam/dependabot/npm_and_yarn/docs/nanoid-3.3.8
Bump nanoid from 3.3.6 to 3.3.8 in /docs
2024-12-13 11:42:22 +00:00
dependabot[bot]
17d43958e1
Bump nanoid from 3.3.6 to 3.3.8 in /docs
Bumps [nanoid](https://github.com/ai/nanoid) from 3.3.6 to 3.3.8.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.3.6...3.3.8)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-12 21:36:30 +00:00
Anon
48c69ac5a6
[skipci] Merge pull request #2816 from MCCTeam/dependabot/npm_and_yarn/docs/cross-spawn-7.0.6
Bump cross-spawn from 7.0.3 to 7.0.6 in /docs
2024-12-06 17:15:08 +00:00
Anon
98a3b70e2c
[skipci] Merge pull request #2788 from MCCTeam/dependabot/npm_and_yarn/docs/webpack-5.94.0
Bump webpack from 5.76.1 to 5.94.0 in /docs
2024-12-06 17:14:40 +00:00
Anon
814cd69380
SetDimension bug fix
Fixed bug in `SetDimension` method of `World` class, where it would c…
2024-12-06 17:13:10 +00:00
Anon
f83e7c5707 Preliminary 1.21 Support 2024-12-06 16:45:48 +01:00
vinicius
d0c9695a79 Fixed bug in SetDimension method of World class, where it would crash if joining a paper server. Added error handling. 2024-12-05 02:13:21 +00:00
Anon
7bd213a154 Fixed the potion component crash 2024-12-04 21:25:22 +01:00
dependabot[bot]
43c6620475
Bump cross-spawn from 7.0.3 to 7.0.6 in /docs
Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.6.
- [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.6)

---
updated-dependencies:
- dependency-name: cross-spawn
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-21 01:38:43 +00:00
Anon
0da4a718cb Implemented all structured components, renamed them all to a better format 2024-10-05 13:37:52 +02:00
Anon
4dea688ca2 Added more structured components 2024-09-11 20:58:24 +02:00
Anon
49319fe781 Added more components + added item palette reference 2024-09-11 20:35:23 +02:00
Anon
76e873ed54 WIP: Added some strctured components 2024-09-11 19:12:31 +02:00
breadbyte
27e66433cd
Hotfix for 'minecraft:chat_type' not present in the dictionary (#2794) 2024-09-07 03:45:45 +08:00
Anon
63b027d84a First Version of Structured Components 2024-09-01 20:42:39 +02:00
dependabot[bot]
f54c5aab44
Bump webpack from 5.76.1 to 5.94.0 in /docs
Bumps [webpack](https://github.com/webpack/webpack) from 5.76.1 to 5.94.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.76.1...v5.94.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-30 10:54:58 +00:00
breadbyte
c5dc517c43
Embed debugging information into the executable
This helps us with bug reports by providing users with more debugging information when an error happens.
2024-08-16 11:28:13 +08:00
breadbyte
c69cdaddbf [skip ci] fix issue 2779 2024-08-14 18:49:09 +08:00
breadbyte
8bdb20a22c
[skip ci] Update docker image to use updated releases 2024-08-14 18:22:05 +08:00
a08381
efe23eb1f9 add Yggdrasil authlib multi-user selection. 2024-08-11 01:43:46 +08:00
breadbyte
ca966a464c
Ensure that the cached version of MCC is refreshed every update (#2760)
fixes #2758

this happened because we added sentry in a future release, but the cache was using an old executable, so it couldn't find the assembly.
2024-07-14 01:46:43 +08:00
breadbyte
c50b360eae
Fix minor bugs (#2759)
* add miscellaneous fixes

* Fixed connecting to server when compression threshold is set to 0

The client assumes that 0 means disabled, when on a notchian (vanilla) server, it is possible to set the compression threshold to 0 (compress all packets).

* Try to capture all exceptions through Sentry

No exceptions are being logged through Sentry, so be more aggressive when sending exceptions

(cherry picked from commit eb1c2f5e771760fb3be32ffea79f8292adca92f1)

* Call OnSpawnPlayer packet when a player is spawned using the SpawnEntity packet

references #2721

(cherry picked from commit ef28ae09ac89e8988dd612de61f2849a9f0e528c)
2024-07-14 01:30:16 +08:00
breadbyte
2f9cf7bc8c
Remove Sentry Release Versioning from builds 2024-07-04 03:03:32 +08:00
breadbyte
729381fb87
Update Sentry release configuration 2024-07-04 02:51:38 +08:00
breadbyte
95e7f08319
Update the Github Actions Automated Build (#2750)
* Replace Github Release Upload Action

Replaces the tixfactory release-manager action with a different one found in the marketplace, as the current one is no longer working.

* Update build-and-release.yml
2024-07-04 02:43:02 +08:00
Anon
5a6fd577e5 Inventory, Terrain and Entity handling 2024-07-02 11:08:46 +02:00
Anon
58a5260b5b Merge branch 'master' of github.com:milutinke/Minecraft-Console-Client into 1.20.6 2024-06-30 11:57:57 +02:00
Anon
67e36a92d2 First working version, not fully tested 2024-06-30 11:26:41 +02:00
breadbyte
08551097c6
Add Sentry Error Tracking (#2670)
* Add Sentry Error Tracking

* Omit personally identifiable information and add additional sentry context

* Remove debug message

* Make sentry opt-out and add related notices and strings

Also add Minecraft Version to error context

* Update build to send release info to sentry

* Adjust sentry error tracking

- Send the user-friendly Minecraft Version in the error logs
- Capture exceptions in more parts of the application

We now capture exceptions from the following locations:
- Protocol18 (1.8+) Packet errors
- Errors during client initialization phase (When client is about to start, session keys are NEVER sent to sentry)

* Make Sentry DSN configurable and repository-specific

The Sentry DSN will automatically be filled out on the main repository through the Github Actions build.

* Update build-and-release.yml

Update sed command

* style: change variable name

nitpick, just to make it a little bit more descriptive

* Add Sentry branding in README.

* remove old code (merge conflict)
2024-06-22 06:41:13 +08:00
breadbyte
8756ff5b3c
[skip ci] Miscellaneous scripting QoL improvements and fixes (#2740)
* Update CI to detect the word "skipci"

* Make script compilation errors more verbose

Rather than just giving the line in which the error has been found, return the actual text content of the line itself

* Attempt to bubble up errors in the script chain, so it says the reason for any NotRun errors.

The exception message gets eaten up when the script is running, and an exception happens.

Also put in a default result message for the CmdResult, instead of having it default to null.

* Trim the whitespace off returned script compilation error line
2024-06-22 06:40:23 +08:00
Anon
4919db8820
[skipci]Dependabot update
Bump ws from 8.10.0 to 8.17.1 in /docs
2024-06-19 16:24:20 +00:00
dependabot[bot]
7cd8e3500c
Bump ws from 8.10.0 to 8.17.1 in /docs
Bumps [ws](https://github.com/websockets/ws) from 8.10.0 to 8.17.1.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.10.0...8.17.1)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 19:10:25 +00:00
Anon
08c5c15557 1.20.6 - Not working yet 2024-06-16 01:19:09 +02:00
Anon
8270a2d9a3
Item Mappings for 1.8 - 1.12 + Crash Fix
Item Mappings for 1.8 - 1.12 + Crash Fix
2024-06-08 21:34:33 +00:00
breadbyte
fc2373b6d5
[skip ci] Update build-and-release.yml
undo breaking the action and figure out that contains isn't case sensitive anyways
2024-04-19 15:49:38 +08:00
breadbyte
8037794601
[skip ci] Merge pull request #2724 from yaggod/master 2024-04-19 15:44:27 +08:00
breadbyte
4146897e3c
Update Github Actions to actually skip builds
We used to only check for "skip ci" specifically, so all other amalgamations of skip-ci, skip-build, etc still create a new build.

this changes the build check to check for skip, SKIP or Skip instead to catch all of them.
2024-04-19 15:41:40 +08:00
yaggod
d0caf4c9ee fixed typo in word heAlper lol 2024-04-16 21:21:08 +03:00
dependabot[bot]
d6d0800215
[skip-ci] Bump express from 4.18.2 to 4.19.2 in /docs (#2719)
Bumps [express](https://github.com/expressjs/express) from 4.18.2 to 4.19.2.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.18.2...4.19.2)

---
updated-dependencies:
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-15 14:55:10 +08:00
Zorua162
403284cc53
[skip-ci] Add the ability to be able to use different platforms with the example Dockerfile (#2723) 2024-04-15 14:48:04 +08:00
Anon
2fe376e7ca
Merge pull request #2716 from MCCTeam/dependabot/npm_and_yarn/docs/webpack-dev-middleware-5.3.4
Bump webpack-dev-middleware from 5.3.3 to 5.3.4 in /docs
2024-03-24 15:03:51 +01:00
dependabot[bot]
3ccdbc2a4f
Bump webpack-dev-middleware from 5.3.3 to 5.3.4 in /docs
Bumps [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) from 5.3.3 to 5.3.4.
- [Release notes](https://github.com/webpack/webpack-dev-middleware/releases)
- [Changelog](https://github.com/webpack/webpack-dev-middleware/blob/v5.3.4/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-dev-middleware/compare/v5.3.3...v5.3.4)

---
updated-dependencies:
- dependency-name: webpack-dev-middleware
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-23 10:41:40 +00:00
Anon
5f3923973f
[skipci] Merge pull request #2710 from MCCTeam/dependabot/npm_and_yarn/docs/follow-redirects-1.15.6
Bump follow-redirects from 1.15.4 to 1.15.6 in /docs
2024-03-21 17:05:54 +01:00
oldkingOK
bf54def51f
Fix(PacketType18Handler.cs): 1.20 Packet Palette (#2715) 2024-03-20 14:10:06 +08:00
dependabot[bot]
552f563eb0
Bump follow-redirects from 1.15.4 to 1.15.6 in /docs
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.4 to 1.15.6.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.4...v1.15.6)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-16 23:08:54 +00:00
breadbyte
f5c7a2801f Add an extra autorelog guard on HandleFailure 2024-03-17 02:10:14 +08:00
breadbyte
dc71332dd3 fix mcc not showing the disconnect message
The fix is to remove the ParseText call from the OnConnectionLost call, as the ReadNextChat function already calls ParseText. Calling ParseText on an unparsable string returns an empty string, therefore the disconnect message never gets propagated to the user.
2024-03-17 02:09:20 +08:00
breadbyte
706a41ee26 Revert "Fix offline client reconnecting as a microsoft account"
Could no longer reproduce said issue without this code, and a bug was reported regarding this change, so reverting it.
This reverts commit 873bd79fd6.
2024-03-17 01:33:00 +08:00
Anon
5044ec965b Un-commended try-catch block 2024-03-12 19:07:20 +01:00
breadbyte
60ba4bd6c2
Merge pull request #2700 from breadbyte/master 2024-03-12 23:43:52 +08:00
Anon
2ce0311949 Fixed a crash in SendPlayerBlockPlacement 2024-03-12 15:05:47 +01:00
Anon
691f1a136e Added Item Palette for 1.11 2024-03-12 14:04:36 +01:00
Anon
c9c16818a4 Added item Mappings for 1.10 2024-03-12 13:49:47 +01:00
Anon
221d5948e2 Added Item mappings for 1.12 2024-03-12 13:28:17 +01:00
Anon
a19a91e37f Added Item palette for 1.9 2024-03-12 12:58:29 +01:00
Anon
6891d446a5 Added 1.8 Item Mappings and Support 2024-03-12 11:15:05 +01:00
Anon
ac9a70c159
fix: IndexOutOfRange on packet reading (Forge)
fix: IndexOutOfRange on packet reading (Forge)
2024-03-10 12:12:47 +01:00
oldkingOK
4bb25c377e feat(DeclareCommands.cs): Add 1.20.3+ version check 2024-03-10 12:03:07 +08:00
oldkingOK
79910b50f7
Merge branch 'MCCTeam:master' into forge-cmds 2024-03-10 08:07:01 +08:00
breadbyte
a72a8cf833 Make AutoRelog more reliable
Makes AutoRelog more hands on with the  relogging rather than have the general relogging handler handle it.

Fallback to the general handler only when the AutoRelog module is disabled.
2024-03-07 09:54:40 +08:00
breadbyte
c78245c056 Fix Server Version prompt
Actually use the provided server version when reconnecting to a server that doesn't broadcast their protocol version
2024-03-07 09:37:55 +08:00
breadbyte
873bd79fd6 Fix offline client reconnecting as a microsoft account
Consider an empty string as a blank password as well as the default dash.
2024-03-07 07:21:11 +08:00
Anon
5f4227ad11
[skipci] Documentation update (Latest Version)
Documentation update (Latest Version)
2024-03-05 23:19:40 +01:00
Anon
3b213296ac Updated the last supported version on the Documentation website front page 2024-03-05 23:18:08 +01:00
Anon
e2b6dc27c8
[skipci]Forge Code Cleanup
Optimize code and edit comments
2024-03-05 22:50:06 +01:00
Anon
86fb4feffc
Implemented 1.20.3/4
1.20.3/4 Implementation
2024-03-05 22:42:26 +01:00
Roman Danilov
df9443381b Done auxiliary methods for Direction 2024-03-05 21:49:29 +05:00
Roman Danilov
91ef890bb6 Auxiliary class for Direction, preparation for autodetection of the broken side of the block 2024-03-05 20:30:58 +05:00
Roman Danilov
fde50c1728 AntiCheat fix prevent Block Breaking 2024-03-05 18:54:29 +05:00
Anon
438311787d
1.20.3/4 - Fixed a crash with translations + Updated Translations
1.20.3/4 - Fixed a crash with translations + Updated Translations
2024-02-28 11:52:36 +01:00
Anon
744de0dbd4 Removed debug logs 2024-02-28 11:49:50 +01:00
Anon
bc0781cee9 Fixed translations crash 2024-02-28 11:48:23 +01:00
Anon
620e8bf274 More debug info 2024-02-26 23:46:08 +01:00
Anon
1db0792d7b Temporary Debug info 2024-02-26 23:39:20 +01:00
Anon
a749cd7fc4
Fixed a crash on Entity Metadata
Fixed a crash on Entity Metadata
2024-02-25 16:13:30 +01:00
Anon
ecc88fac06 Fixed a crash on Entity Metadata 2024-02-25 16:11:33 +01:00
Anon
798a24e8be
Fixed a crash on chat parsing. + Returned the commended try catch block
Fixed a crash on chat parsing. + Returned the commended try catch block
2024-02-21 17:41:37 +01:00
Anon
3522a16b0d Removed a comment 2024-02-21 17:40:39 +01:00
Anon
13de67b6f8 Fixed a crash on chat parsing.
Returned the commended try catch block.
2024-02-21 17:38:32 +01:00
oldkingOK
8e1822b0d2 feat(DeclareCommands.cs): Remove 1.20.2+ version check 2024-02-21 10:10:03 +08:00
oldkingOK
8be66daab1 fix(Protocol18Forge.cs): Version bigger or equal 1.18 is FML3 2024-02-20 22:23:46 +08:00
oldkingOK
092854532a docs(Protocol18Forge.cs): Move comment to mechod head 2024-02-20 22:22:11 +08:00
oldkingOK
6949276779 docs(Protocol18Forge.cs): Replace code with packet definition 2024-02-20 22:13:10 +08:00
oldkingOK
970ba19172 refactor(ForgeInfo.cs): Remove unused code and edit comments 2024-02-20 22:02:22 +08:00
oldkingOK
f749840d89 refactor(KeyUtils.cs): Replace Newtonsoft.Json with JSONData 2024-02-20 20:31:22 +08:00
oldkingOK
576575ff65 refactor(DeclareCommands.cs): Move forge to switch version block 2024-02-20 20:22:37 +08:00
oldkingOK
e569ffe0cc fix: IndexOutOfRange on packet reading (Forge)
Add two missing forge Command Packet Parsers, which won't affect the vanilla parsers.
The ids of the two Command Packet Parsers `forge:enum` and `forge:modid` [Forge once added in order](19f8d2a793/src/main/java/net/minecraftforge/common/ForgeMod.java (L175)) are the maximum value of the Vanilla Parser id plus 1 or plus 2. `forge:enum` has a [String Type argument](https://wiki.vg/Command_Data#forge:enum).
The specific id is from [wiki.vg](https://wiki.vg/Command_Data) or Forge-generated minecraft source code.
2024-02-20 15:37:57 +08:00
breadbyte
b2ef5cb23b
(skip ci) update supported versions (visual change) 2024-02-19 02:47:07 +08:00
Anon
7edf458135
Fixed a crash with Reconfiguration... screen
Fixed a crash with Reconfiguration... screen
2024-02-18 18:55:52 +01:00
Anon
3fab7eb78f Fixed a crash with Reconfiguration... screen 2024-02-18 18:54:45 +01:00
Anon
9a147b57e5
Fixed crashing on Reconfiguration... screen phase
Fixed crashing on Reconfiguration... screen phase
2024-02-18 18:45:21 +01:00
Anon
d7e898c6d4 Fixed crashing on Reconfiguration... screen phase 2024-02-18 18:44:36 +01:00
Anon
317d8cca49
Fixes for 1.20.3
Fixes for 1.20.3
2024-02-18 17:57:58 +01:00
Anon
35cfd4a7db Fixed a NBT crash < 1.20.2 and Fixed a crash with parsing 'extra' section in Chat 2024-02-18 17:56:02 +01:00
ReinforceZwei
6d016332fb 1.20.4: Update NBT chat parser to handle text color 2024-02-11 18:15:52 +08:00
ReinforceZwei
4546e6946e 1.20.4: Update entity, item and block palette 2024-02-11 18:13:48 +08:00
ReinforceZwei
a9f1ad4433 1.20.3: Update chat parser to parse new NBT format 2024-02-04 18:14:09 +08:00
Anon
975aab88e3 NBT Changes, needs fixing 2024-01-31 13:53:09 +01:00
Anon
790e0bfe55 Implemented 1.20.3 2024-01-30 12:51:47 +01:00
Anon
1e60b611e9
fix(Protocol18.cs): OperationCanceledException when /reco or /quit
fix(Protocol18.cs): OperationCanceledException when /reco or /quit
2024-01-30 10:15:56 +01:00
oldkingOK
350c1cdd51 fix(Protocol18.cs): OperationCanceledException when /reco 2024-01-30 11:22:37 +08:00
Anon
1479c646d1
Fixed a crash on non 1.20.2 versions
Fixed a crash on non 1.20.2 versions
2024-01-29 22:42:17 +01:00
Anon
4f89e4fe36 Fixed a crash on non 1.20.2 versions 2024-01-29 22:40:17 +01:00
Anon
db1fade2c2
Added Configuration packets mapping + removed a debug log
Added Configuration packets mapping + removed a debug log
2024-01-29 15:50:31 +01:00
Anon
ad684fb5b6 Removed debug log for keys 2024-01-29 15:46:42 +01:00
Anon
e13ba93f47 Added Configuration Packets mapping 2024-01-29 15:39:39 +01:00
Anon
7aabe8ba28
Fixed a crash with a chat message
Fixed bad code and the bug
Fixed a crash when a chat message was received on a server that uses protocol lib and viaversion.
2024-01-28 21:57:47 +01:00
Anon
f325dd7475 Fixed bad code and the bug 2024-01-28 21:56:06 +01:00
Anon
3bfe5aa855
Fixed a crash
Fixed a crash when a chat message was received on a server that uses protocol lib and viaversion.
2024-01-28 21:43:21 +01:00
Peaches_MLG
88bca839f7 boink 2024-01-28 01:27:16 +00:00
Anon
6faddae16e
Implement Forge FML3 protocol (MC 1.18+) and Fix yggdrasil-auth chat issue
Implement Forge FML3 protocol (MC 1.18+) and Fix yggdrasil-auth chat issue
2024-01-14 17:07:15 +01:00
Anon
ae5e016f5f
[skipci] Bump follow-redirects from 1.15.2 to 1.15.4 in /docs
Bump follow-redirects from 1.15.2 to 1.15.4 in /docs
2024-01-14 12:02:11 +01:00
oldkingOK
a8643d85fc Remove QQbot scripts for fml3 pull request 2024-01-14 10:48:45 +08:00
oldkingOK
8eee50044f Edit outdated links in comments and add FML3 stuff
Add FML3 extra packetID 5 and 6 recognition based on
https://github.com/MinecraftForge/MinecraftForge/blob/1.18.x/src/main/java/net/minecraftforge/network/NetworkInitialization.java

Changed the way of selecting FML version for "Force Forge" from forced FML3 to game version based.
MC 1.12 and lower: FML, MC 1.13 to 1.17: FML2, MC 1.18 and greater: FML3

Edit outdated links in comments:
Accessing the link below will result in a message that the file cannot be found
https://github.com/MinecraftForge/MinecraftForge/blob/master/src/main/java/net/minecraftforge/fml/network/FMLNetworkConstants.java
Presumably it's version 1.13 based on the original commit and issue, then change to
https://github.com/MinecraftForge/MinecraftForge/blob/1.13.x/src/main/java/net/minecraftforge/fml/network/FMLNetworkConstants.java
https://github.com/MCCTeam/Minecraft-Console-Client/issues/1184
2024-01-14 01:45:38 +08:00
oldkingOK
79fa297e2b Merge branch 'dev' of github.com:oldkingOK/Minecraft-Console-Client into dev
Sync files
2024-01-13 03:40:01 +08:00
oldkingOK
2c8b15b02e Fix bug: Yggdrasil client can't send message upper 22w17a
When try to send message in yggdrasil-auth server with `enforce-secure-profile=true`
and `online-mode=true` enabled, will fail with message in red:
Chat disabled due to missing profile public key. Please try reconnecting.
So yggdrasil-auth-client also has to encrypt chat messages like Microsoft-auth-client
to send out messages.
2024-01-13 03:29:00 +08:00
oldkingOK
e7d519e4aa Fix bug: Yggdrasil client can't send message upper 22w17a
When try to send message in yggdrasil-auth server with `enforce-secure-profile=true`
and `online-mode=true` enabled, will fail with message in red:
Chat disabled due to missing profile public key. Please try reconnecting.
So yggdrasil-auth-client also has to encrypt chat messages like Microsoft-auth-client
to send out messages.
2024-01-13 03:00:02 +08:00
oldkingOK
22cf7a046b 添加支持 Fml3 ,并暂时设置force forge时为fml3 2024-01-12 13:28:03 +08:00
oldkingOK
725510d3ef 修改 OkWsBot.cs,获取玩家列表时排除自己
删除群号指定,因为在py-server.py里已经指定
2024-01-12 13:25:26 +08:00
oldkingOK
9ae3bc4d0d Fix: 群友未设置群昵称时无法在服务器显示名称
先判断是否有群昵称,然后再设置
2024-01-11 11:01:40 +08:00
oldkingOK
644014e42f Add QQbot scripts and python script 2024-01-10 17:48:03 +08:00
dependabot[bot]
269a890a23
Bump follow-redirects from 1.15.2 to 1.15.4 in /docs
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.2 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.2...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-10 07:56:35 +00:00
oldkingOK
734de2a9ac Login with yggdrasil server 'hitmc.cc' will get
```
Login failed : Invalid server response.
```

Print the raw response which is `result` in [/MinecraftClient/Protocol/ProtocolHandler.cs#L554](f6797cb4b5/MinecraftClient/Protocol/ProtocolHandler.cs (L554))
(Every test shows like this)

```
HTTP/1.1 200 OK
...

1e1
{"accessToken":"...","clientToken":"...","availableProfiles":[{"id":"..","name":".."},{"id":"..","na
f
me":"ok_bot"}]}
0
```

After splited by line:
- 1e1
- {"accessToken": ... ,"na
- f
- me":"ok_bot"}]}
- 0

The response when Login with 'littleskin.cn' which works fine is:

```
HTTP/1.1 200 OK
...

1e1
{"accessToken":"...","clientToken":"...","availableProfiles":[{"id":"..","name":".."},{"id":"..","name":"ok_bot"}]}
0

```

After splited by line:
- 1e1
- {"accessToken": ... ,"name":"ok_bot"}]}
- 0
-
-

So adding [1] and [3] will make both 'hitmc.cc' and 'littleskin.cn' work fine.
2024-01-10 11:00:04 +08:00
Anon
f6797cb4b5
Implemented 1.20.2
Implemented 1.20.2
2023-12-15 09:58:10 +01:00
Anon
ba2402ee11
Fixed merge conflicts
Fixed merge conflicts
2023-12-02 13:35:29 +01:00
Anon
480f0d85f0 Fixed merge conflicts 2023-12-02 13:34:11 +01:00
Anon
f2e1c57b23
Restore ability to login with Microsoft broken after Yggdrasil authentication implementation
Restore ability to login with Microsoft broken after Yggdrasil authentication implementation
2023-12-02 12:55:39 +01:00
mcflurrybaby
e19de8eb0b refactored session checks for better readability 2023-12-02 13:15:46 +02:00
mcflurrybaby
ceff78a821 Restore ability to login with microsoft broken after yggdrasil login implementation 2023-12-02 12:39:52 +02:00
Anon
1c17da2665
Add missing 1.20 advancements locales
Add missing 1.20 advancements locales
2023-12-01 16:02:28 +01:00
mcflurrybaby
6714d9a9d0 Add missing 1.20 advancements locales 2023-12-01 00:30:23 +02:00
Anon
a41b6719ce
Merge pull request #8 from milutinke/1.20.2
1.20.2
2023-11-27 00:03:58 +01:00
Anon
2fb5c163d5 Formatting 2023-11-27 00:03:20 +01:00
Anon
0ad892ef50 Chunk Batch error should be fixed now 2023-11-27 00:00:57 +01:00
Anon
eb7bfff8ab
Merge pull request #7 from milutinke/1.20.2
Fixed division with a 0 error
2023-11-25 14:04:04 +01:00
Anon
549f39fab1 Fixed division with a 0 error 2023-11-25 14:02:06 +01:00
Anon
c6da4e2ac3
[skip ci] Add Yggdrasil Login (authlib-injector support)
Add Yggdrasil Login (authlib-injector support)
2023-11-25 11:03:41 +01:00
Polaris_Light
a08bfca4e5
Merge branch 'master' into master 2023-11-25 17:23:06 +08:00
Polaris_Light
f07b1e964c ResolveConflict*2 2023-11-24 22:18:42 +08:00
Polaris_Light
8dfcf9c5d5 ResolveConflict 2023-11-24 21:58:55 +08:00
Anon
f50bfbb857
Implemented TabListHeaderAndFooter packet
Implemented TabListHeaderAndFooter packet
2023-11-20 18:09:08 +01:00
Anon
782481816d Implemented TabListHeaderAndFooter packet 2023-11-20 18:08:09 +01:00
Anon
cf6db27088
[skipci] Websocket bot: Create new Responder object that will respond to the session's new name
Websocket bot: Create new Responder object that will respond to the session's new name
2023-11-20 17:50:04 +01:00
Anon
21e2f41f25
[skipci] Add an IP lookup to the WebSocketBot
Add an IP lookup to the WebSocketBot
2023-11-20 17:49:45 +01:00
zorua162
d49a597671 Create new Responder object that will repond to the session's new name 2023-11-19 21:07:09 +00:00
zorua162
1f4db70f8a Added extra config to the WebSocket bot AllowIpAlias, which allows enabling of any IP to be used to host the WebSocket bot from 2023-11-19 13:43:32 +00:00
zorua162
fd1009b43f Revert "Add an IP lookup to the WebSocketBot"
This reverts commit 0a149647b6.
2023-11-19 12:57:09 +00:00
zorua162
0a149647b6 Add an IP lookup to the WebSocketBot 2023-11-18 22:00:16 +00:00
Anon
04c1f941b6
Implemented 1.20.2
Implemented 1.20.2
2023-11-17 17:27:00 +00:00
Anon
93112d2c02 Implemented 1.20.2 fully, needs more testing 2023-11-17 18:21:57 +01:00
Polaris_Light
4fc1aacca5 BetterTranslationMaybe 2023-11-16 10:10:06 +08:00
Polaris_Light
49dec51588 MakeSelectedProfileNullable 2023-11-16 09:59:56 +08:00
Polaris_Light
a97096cddf ImplPlayerSection 2023-11-16 00:04:56 +08:00
Anon
4f957cee7e 1.20.2 Implementation, not tested 2023-11-15 15:42:27 +01:00
Polaris_Light
3c97193b70 AddYggdrasilLogin 2023-11-12 21:04:20 +08:00
Anon
eb8ccc43d7
[skip ci] Bump Magick.NET-Q16-AnyCPU from 12.2.1 to 13.3.0 in /MinecraftClient
Bump Magick.NET-Q16-AnyCPU from 12.2.1 to 13.3.0 in /MinecraftClient
2023-10-28 15:12:01 +00:00
Anon
4626ccbc67
[skip ci] Bump postcss from 8.4.18 to 8.4.31 in /docs
Bump postcss from 8.4.18 to 8.4.31 in /docs
2023-10-28 15:11:26 +00:00
dependabot[bot]
b8af534438
Bump Magick.NET-Q16-AnyCPU from 12.2.1 to 13.3.0 in /MinecraftClient
Bumps [Magick.NET-Q16-AnyCPU](https://github.com/dlemstra/Magick.NET) from 12.2.1 to 13.3.0.
- [Release notes](https://github.com/dlemstra/Magick.NET/releases)
- [Commits](https://github.com/dlemstra/Magick.NET/compare/12.2.1...13.3.0)

---
updated-dependencies:
- dependency-name: Magick.NET-Q16-AnyCPU
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-18 23:12:25 +00:00
Domracz
1aea8d3a4e
Fixed entity rotations (#2596)
* Fixed entity rotations

Fixed entity yaw and pitch not changing when entity moves head.

* Update ChatBot.cs

* Update McClient.cs

* Update Protocol18.cs

* Update McClient.cs

* Finalize code style

* Fix incorrect variable type

---------

Co-authored-by: ReinforceZwei <39955851+ReinforceZwei@users.noreply.github.com>
2023-10-11 14:44:46 +08:00
Spongecade
c3fa413b4e
[skip ci] Update Minecraft wiki links to new domain (#2593) 2023-10-07 17:59:08 +08:00
dependabot[bot]
542ff78ddf
Bump postcss from 8.4.18 to 8.4.31 in /docs
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.18 to 8.4.31.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.18...8.4.31)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-07 07:42:08 +00:00
breadbyte
911908bfaf
Update ConsoleInteractive for preliminary docker support 2023-09-24 18:03:59 +08:00
Alex Babrykovich
e1b018c333
[skip ci] Docker: allow skip MinecraftClient download if MCC_SKIP_REDOWNLOAD (#2591)
defined

Really useful during development/testing docker.
Simply pass MCC_SKIP_REDOWNLOAD
2023-09-24 17:39:09 +08:00
ozi2285
67662c5df7
[skip ci] Inventory Click Usage Description Fix (#2589)
ShiftClick Description was Wrong so Just Fixed it.
2023-09-24 17:19:22 +08:00
ozi2285
968f864f34
Added ShiftRightClick (#2582)
* Added ShiftRightClick

* Added ShiftRightClick

* Added ShiftRightClick

* Added ShiftRightClick

* Added ShiftRightClick

* Added ShiftRightClick

* Added ShiftRightClick

* Added ShiftRightClick

* Updated Protocol18.cs ShiftRightClick Description for ReinforceZwei's  Suggestion

* Just Deleted Added ShiftRightClick's Description Line

* Just Deleted Added ShiftRightClick's Description Lines

* Made Change With Informaiton ReinforceZwei Given to Me About Switch-Case and Shorten the Code.

* Re Added Lines That Got Deleted By Mistake

* Add translation key for shift right-click

---------

Co-authored-by: ReinforceZwei <39955851+ReinforceZwei@users.noreply.github.com>
2023-09-16 19:39:55 +08:00
ReinforceZwei
37bcad37e0 [skip ci] Normalize all line endings 2023-09-15 14:44:11 +08:00
ReinforceZwei
bdad4f302d [skip ci] Set repository line endings to LF 2023-09-15 14:43:24 +08:00
ReinforceZwei
a8200b6e14
Add setting for allowing non-English name in player list (#2556)
Non-vanilla server may have player name other than English, for example Chinese server can have player name in Chinese. This setting allow MCC to display those non-English name in the player list.
2023-08-02 14:00:11 +08:00
Anon
ac65482296
Added a random interval option to the wait command
Added a random interval option to the wait command
2023-07-16 18:46:59 +00:00
Anon
c5a0409edc Added documentation examples and covered an edge case 2023-07-16 20:45:24 +02:00
Anon
fe5f07306d Added a random interval option to the wait command 2023-07-16 20:37:56 +02:00
Anon
8891b65eb8
[skip ci] Merge pull request #2544 from MCCTeam/dependabot/npm_and_yarn/docs/semver-7.5.3
Bump semver from 7.3.8 to 7.5.3 in /docs
2023-07-01 07:48:25 +00:00
dependabot[bot]
dbba63342d
Bump semver from 7.3.8 to 7.5.3 in /docs
Bumps [semver](https://github.com/npm/node-semver) from 7.3.8 to 7.5.3.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v7.3.8...v7.5.3)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-30 19:11:47 +00:00
Anon
469e6667bf
Slab handling 1.20/.1 and Farmer bot improvements
Slab handling 1.20/.1 and Farmer bot improvements
2023-06-23 14:31:22 +00:00
Anon
272900d52e Added slab handling for 1.20/.1
Added Farm bot crops handling for 1.20/.1
Added utilities for Containers/Inventories
Added bot movement lock to prevent multiple bots that use movements from running at the same time.
General code improvements.
2023-06-23 16:25:18 +02:00
Anon
ac1d2b7142
[skip ci] Added 1.20.1 to the documentation
[skip ci] Added 1.20.1 to the documentation
2023-06-22 20:13:56 +00:00
Anon
497a1174de Added 1.20.1 to the documentation 2023-06-22 22:13:16 +02:00
Anon
85210464a5
Implemented 1.20.1
Implemented 1.20.1
2023-06-22 20:12:02 +00:00
Anon
7c7b58e941 Implemented 1.20.1 2023-06-22 22:10:55 +02:00
Anon
3f3f614640
Merge pull request #2530 from MCCTeam/dependabot/nuget/MinecraftClient/Microsoft.Windows.Compatibility-7.0.3
Bump Microsoft.Windows.Compatibility from 7.0.0 to 7.0.3 in /MinecraftClient
2023-06-14 22:38:19 +00:00
dependabot[bot]
b4829eaca4
Bump Microsoft.Windows.Compatibility in /MinecraftClient
Bumps [Microsoft.Windows.Compatibility](https://github.com/dotnet/runtime) from 7.0.0 to 7.0.3.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v7.0.0...v7.0.3)

---
updated-dependencies:
- dependency-name: Microsoft.Windows.Compatibility
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-14 17:09:34 +00:00
Anon
8f337cc0f3
[skip ci] Added MermaidJS graphs support to the Vuepress
Added MermaidJS graphs support to the Vuepress
2023-06-14 07:46:25 +00:00
Anon
0beaae13f7 Added MermaidJS graphs support 2023-06-14 09:44:50 +02:00
Anon
431ed0466d
[skip ci] Updated the front page of documentation for 1.20
Updated the front page of documentation for 1.20
2023-06-09 14:50:52 +00:00
Anon
89d918a0c9 Updated the front page of documentation for 1.20 2023-06-09 16:49:50 +02:00
Anon
b631fcb487
Fully Implemented 1.20
Fully Implemented 1.20
2023-06-08 17:30:00 +00:00
Anon
ae7ce35cc8 Fully Implemented 1.20 2023-06-08 19:27:28 +02:00
Anon
b21f40593e
[skip ci] Trying to fix vite from crashing again
Trying to fix vite from crashing again
2023-06-04 10:05:09 +00:00
Anon
d417335325 Trying to fix vite from crashing again 2023-06-04 12:03:30 +02:00
Anon
353771e307
[skip ci] Trying to fix Vite crashing
Trying to fix Vite crashing
2023-06-04 09:46:26 +00:00
Anon
a4a058aab2 Split the Web Socket documentation into multiple files due to Vite crashing. 2023-06-04 11:44:58 +02:00
Anon
a113dc8430
[skip ci] Updated the Documentation
Updated the Documentation
2023-06-04 09:25:30 +00:00
Anon
2f30528e4f Added nameitem command 2023-06-04 11:24:20 +02:00
Anon
025093a11b Added Web Socket Chat Bot documentation 2023-06-04 11:18:15 +02:00
Anon
5de84d7e59
Added a command to (re)name items in the Anvil
Added a command to (re)name items in the Anvil
2023-06-03 14:29:59 +00:00
Anon
f77d58402a
Merge branch 'master' into rename-items 2023-06-03 14:29:42 +00:00
Anon
a357d2c87a Fixing merge conflict 2023-06-03 16:27:36 +02:00
Anon
081cebcf76 Fixed typos and fixed a merge conflict 2023-06-03 16:23:07 +02:00
Anon
051ee70805
Added Web Socket Chat Bot
Web Socket Chat Bot
2023-06-03 14:14:06 +00:00
Anon
fce12db33f Added a command to (re)name items in the Anvil 2023-06-03 16:12:17 +02:00
Anon
95f6c5768d Fixed session renaming not working, fixed command handling 2023-05-28 15:15:43 +02:00
Anon
1efa55206f Re-added WebSocketChat bot and improved it, no longer using WebsocketSharp library 2023-05-27 19:46:28 +02:00
ReinforceZwei
9855e2e0f1
[skip ci] Fix document build error 2023-05-24 16:10:24 +08:00
ReinforceZwei
48b9e8b4fb
[skip ci] Fix document build error 2023-05-24 16:06:16 +08:00
ReinforceZwei
61357d23c7
[skip ci] Fix document build error 2023-05-24 15:46:43 +08:00
Anon
bee1efa1e0
[skip ci] Trying to fix the build again
Trying to fix the build again
2023-05-23 17:47:30 +02:00
Anon
e1313dad4e Trying to fix the build again 2023-05-23 17:44:23 +02:00
Anon
9e267113a5
[skip ci] Trying to fix a docs build
Trying to fix a build with documents
2023-05-23 17:02:28 +02:00
Anon
9c78f7958f Trying to fix a build with documents 2023-05-23 17:01:44 +02:00
Anon
df24f28c97
[skip ci] Updated documentation to reflect the newest changes
Updated documentation to reflect the newest changes
2023-05-21 16:03:04 +02:00
Anon
8f1e5cd48d Added Telegram Bridge and Items Collector chat bots 2023-05-21 16:00:40 +02:00
Anon
1bba41c395
Items Collector Chat Bot
Items Collector Chat Bot
2023-05-21 14:50:19 +02:00
Anon
cfc2baa4e7 Translated 2023-05-21 12:11:58 +02:00
Anon
3a0b32ec68 Merge remote-tracking branch 'origin' into items-collector 2023-05-20 21:46:09 +02:00
Anon
413cb1860d Implemented Items Collector bot 2023-05-20 21:44:18 +02:00
Anon
a4fb677566
Added Slab handling
Added Slab handling
2023-05-20 13:29:58 +02:00
Anon
64eb48f46d Removed 1.13, because it's not possible to walk under slabs 2023-05-20 13:28:24 +02:00
Anon
852be6e90d Fixed 1.19.3 2023-05-20 13:11:37 +02:00
Anon
97af063d79 Removed a comment 2023-05-16 23:25:29 +02:00
Anon
c7597e8822 Added slab handling 1.13-1.19.4 2023-05-16 23:19:31 +02:00
Anon
f72355d974 Updated the installation section for installing on VPS and Android to use .NET 7.0 2023-05-13 10:16:27 +02:00
Anon
adc6fc0029 Updated documentation to reflect the newest changes 2023-05-13 10:02:29 +02:00
Anon
4ff7712f20
Fixed Auto Fishing not working
Fixed Auto Fishing not working
2023-05-10 22:21:54 +02:00
Anon
599c6aac09 Fixed entity object data not being read, this should fix the Auto Fishing bot 2023-05-10 19:07:42 +02:00
dariusel_caroserie
7107023d37
Update Alert.cs (#2496) 2023-05-06 21:55:21 +08:00
Anon
f94c1ed60d
Added item lore/description to display name in the inventory
Added item lore/description to display name in the inventory
2023-04-30 15:20:43 +02:00
Anon
df6eeb9b4a Added item lore/description to be displayed in the list of items in the inventory 2023-04-30 15:18:33 +02:00
ReinforceZwei
3570ef605e
[skip ci] Update document (#2468)
* Update execif document

* Update installation guide

* Add simple script page

* Add text script page to sidebar
2023-04-25 17:02:45 +08:00
ORelio
42abf928fb
Add LICENSE.md
Add a copy of the license file to the repository.
The repository was already licensed under CDDL-1.0.
2023-04-10 18:47:52 +02:00
ReinforceZwei
949c1f6b67 DeclareCommand: Fix 1.19.3 crash 2023-04-09 12:01:09 +08:00
ReinforceZwei
09b3ec1a81
DeclareCommand: Fix 1.19.4 crash (#2474) 2023-04-08 21:24:00 +08:00
Anon
0ff64910f7
Fixed crash on 1.8 when receiving entity data
Fixed crash on 1.8 when receiving entity data
2023-04-07 13:30:02 +00:00
Anon
03b06ea3ac Fixed crash on 1.8 when receiving entity data 2023-04-07 15:26:26 +02:00
Anon
d90635f40b Fixed crash on 1.8 when receiving entity data 2023-04-07 15:21:42 +02:00
ReinforceZwei
f855839bb3
Remove release specific exception handling 2023-04-07 20:32:55 +08:00
Anon
78f5d246f9
Updated Farm bot to work on 1.19.3/4
Updated Farm bot to work on 1.19.3/4
2023-04-01 12:01:57 +00:00
Anon
0a57c927d7 Added access to App Vars inside the Chat Bot API via 3 new methods. Added access to Random class inside the execif command 2023-03-31 18:17:03 +02:00
Anon
beabe14c92 Updated Farm Bot for 1.19.3 and 1.19.4 2023-03-31 17:27:19 +02:00
Anon
f215921e60
Partially fixed interaction with Armor Stand
Partially fixed interaction with Armor Stand
2023-03-31 15:17:16 +00:00
Anon
db6422d154 Partialy fixed interaction with Armor Stand 2023-03-30 21:06:54 +02:00
breadbyte
bbb3b1e38a
Make release filename consistent with release tag
Required change for auto-update system
2023-03-30 18:47:59 +08:00
Anon
e8b3e6b52e
Implemented 1.8 Entity Handling
Implemented 1.8 Entity Handling
2023-03-29 18:54:39 +00:00
Anon
2a82c35b36 Merge branch 'master' of github.com:milutinke/Minecraft-Console-Client 2023-03-29 20:51:30 +02:00
Anon
3f9fd47e5a
Merge branch 'MCCTeam:master' into master 2023-03-29 18:50:15 +00:00
Anon
978dc4b896 Fixed entity positions in 1.8 2023-03-29 20:48:41 +02:00
breadbyte
cd39c1ec12
Make UpgradeHelper compliant with .NET RID catalog
Fetching updates return an error because the UpgradeHelper returns an invalid RID, and we use the RID to create automated builds. This updates the UpgradeHelper to be compliant with the catalog.
2023-03-29 20:15:22 +08:00
Anon
5d4977af6f
Merge branch 'MCCTeam:master' into master 2023-03-28 16:00:23 +00:00
Anon
1901f4b62d Fixed Metadata throwing an exception 2023-03-28 17:56:35 +02:00
breadbyte
74d29321b4
Scripting Hotfix for #2458 (#2460)
* Scripting hotfix

- Fixes #2458
- Change error wording around scripting
- Prevent duplicating the binary for scripting

* Create temporary folder if it doesn't exist
2023-03-28 21:06:56 +08:00
Anon
0b98628572 Added 1.8 entity handling 2023-03-28 13:39:18 +02:00
Anon
4ec3d0c13a
Merge pull request #4 from ReinforceZwei/metadata18
Implement 1.8 Entity MetaData
2023-03-27 13:52:23 +00:00
ReinforceZwei
21cd24e056 Implement 1.8 Entity MetaData 2023-03-27 18:22:50 +08:00
Anon
2f1da9e8c9
Telegram, limit the quit/exit command
Telegram, limit the quit/exit command
2023-03-26 12:35:45 +00:00
Anon
0f77828ac5 Updated translations 2023-03-26 14:33:06 +02:00
Anon
f6850920a3
Merge branch 'MCCTeam:master' into telegram-limit-quit 2023-03-26 12:19:00 +00:00
Anon
033c615a13
Merge pull request #2454 from milutinke/master
[skip ci] Updated Docs README.md to have 1.19.4 listed
2023-03-26 12:02:01 +00:00
Anon
56bfd21ee2
Updated Docs README.md to have 1.19.4 listed
Updated Docs README.md to have 1.19.4 listed as the latest supported version
2023-03-26 12:00:47 +00:00
Anon
f467f4d6e4
Implemented 1.19.4, fixed multiple bugs in multiple versions
- Implemented 1.19.4
- Changed the Entity Metadata Code to use Palettes (1.13 - 1.19.4 supported)
- Implemented Particles Reading code for 1.13 - 1.19.4
- Fixed Elytra flyby crashing the bot when rocket was used (incorrect particles reading cause this)
- Fixed a crash on 1.15.X
- Fixed a crash on 1.14.X
2023-03-25 20:29:55 +00:00
Anon
930fecde23 Fixed a crash on 1.15.X, 1.14.X 2023-03-25 21:24:15 +01:00
Anon
7c95acfd0e
[skip ci] Merge pull request #2442 from MCCTeam/dependabot/npm_and_yarn/docs/webpack-5.76.1
Bump webpack from 5.74.0 to 5.76.1 in /docs
2023-03-25 18:33:53 +00:00
Anon
b3d7942aca
Merge pull request #2452 from MCCTeam/improve-follow
FollowPlayer: Improve player detection
2023-03-25 18:24:56 +00:00
ReinforceZwei
29be211946 FollowPlayer: Improve player detection 2023-03-25 17:29:30 +08:00
ReinforceZwei
8da8f6044f Fix message marker mixed with actual message body
Should fix regex not working for autorespond and other chatbots that relied on matching message
2023-03-25 16:42:28 +08:00
ReinforceZwei
4c33c5fc27 Protocol: Remove unnecessary packets
Bundle and HurtAnimation are for GUI client
2023-03-25 16:32:32 +08:00
Anon
b65b3afc3c Fixed 1.13 crashing in ReadNextItemSlot 2023-03-24 14:06:50 +01:00
ReinforceZwei
750295b1e3 Clean up entity metadata palette 2023-03-24 20:51:10 +08:00
ReinforceZwei
c36dec435d Merge branch '1.19.4' of https://github.com/milutinke/Minecraft-Console-Client into pr/2447 2023-03-24 19:50:04 +08:00
ReinforceZwei
f4ad24746c Wire up entity metadata palette 2023-03-24 19:46:25 +08:00
Anon
055def372b Extracted Particle Data reading to a custom method and implemented changes for reading all particles correctly from 1.13 onwards 2023-03-24 03:41:58 -07:00
Anon
1a22002bde Fixed entity metadata, fixed a crash with Hurt Data packet, fixed a crash when someone flew by with elyra, added Entity Metadata Palettes (not used yet, requires further work) 2023-03-23 23:41:41 +01:00
Anon
8b27386a5b
Fixed crashing on 1.9/10/11, SpawnPainting packet was missing
Fixed crashing on 1.9/10/11, SpawnPainting packet was missing
2023-03-23 22:23:48 +01:00
Anon
e0361d2183 Fixed SpawnPainting packet missing 2023-03-23 19:30:36 +01:00
breadbyte
425cff529c
Fix fetching translations for builds 2023-03-23 11:30:53 +08:00
Anon
2e55a6bc85 Added palettes 2023-03-21 23:31:10 +01:00
Anon
046cb15c75 Updated Player Position packet (removed a line that would crash on older versions) 2023-03-21 21:06:16 +01:00
Anon
5d4ea515a7 Implemented 1.19.4, first pass, light testing 2023-03-21 20:28:05 +01:00
ReinforceZwei
e44ade8688
SetExperience: Revert 1.19.3 fields swap (#2430)
Seems like it is not swapped when testing in 1.19.3 vanilla/paper server
2023-03-21 16:14:21 +08:00
breadbyte
0aa117d023
Update github build workflow [skip ci] (#2424)
* Update github build workflow

-draft-

* Update build-and-release.yml

- flip jobs order to make the build job at the top of the file, to simplify making changes build changes (since all the build parameters are at the top of the file)
- fixed an issue with the `determine-build` job

* Update build-and-release.yml

- fix build-version-info bug and revert build naming to previous convention

* Update build-and-release.yml

- implement transition version as discussed on discord
2023-03-20 22:00:50 +08:00
dependabot[bot]
057d6f515a
Bump webpack from 5.74.0 to 5.76.1 in /docs
Bumps [webpack](https://github.com/webpack/webpack) from 5.74.0 to 5.76.1.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.74.0...v5.76.1)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-15 06:55:31 +00:00
Anon
91791e99c7 Restricted usage of quit/exit commands in the TelegramBridge chat bot due to Telegram caching causing problems 2023-03-02 20:04:24 +01:00
BruceChen
4f608687ee [skip ci] Newly add certain architecture releases and enable compression. 2023-02-02 15:36:02 +08:00
BruceChen
3735cab9dd Fix 1.19.3 message signature issue 2023-01-29 22:39:11 +08:00
BruceChen
8cdd32a52a [SKIP_BUILD] Update Crowdin related github action 2023-01-28 15:17:13 +08:00
BruceChen
db6bc3d2e6
[SKIP_BUILD] Partial implementation for 1.19.3
Pull Request #2393
2023-01-28 15:09:01 +08:00
BruceChen
d25480b88c
[SKIP_BUILD] Merge pull request #2393 from milutinke/1.19.3
Partial implementation for 1.19.3
2023-01-28 15:03:57 +08:00
BruceChen
70d1f70cca Update Crowdin related github action 2023-01-28 15:03:31 +08:00
BruceChen
ee90be3005 [SKIP_BUILD] Fix unintended HTML tags. 2023-01-28 14:53:15 +08:00
BruceChen
b79dd1d379 Bug fix 2023-01-21 01:34:05 +08:00
ReinforceZwei
cc92cd66d4 Switch to https for translation file download 2023-01-19 18:20:45 +08:00
ReinforceZwei
cb57db8328 ChatParser: Catch exception in download language file 2023-01-19 18:02:34 +08:00
ReinforceZwei
e52fe6cb8b Catch and throw exceptions 2023-01-19 17:54:22 +08:00
BruceChen
1f54a7c247 Fix 1.19.3 key exchange in offline mode 2023-01-17 20:16:35 +08:00
BruceChen
c2edd6f619 [SKIP_BUILD] Fix background image url 2023-01-17 01:27:10 +08:00
BruceChen
92a911ce99 Disable forge by default 2023-01-16 14:47:17 +08:00
BruceChen
730cdf92e7 Merge remote-tracking branch 'origin/master' into pr/2393 2023-01-16 14:46:18 +08:00
BruceChen
c9c4d8dd62 [SKIP_BUILD] Update ConsoleInteractive 2023-01-16 14:42:25 +08:00
BruceChen
d65f69fad4
[SKIP_BUILD]Merge pull request #2405 from ReinforceZwei/attack_range
AutoAttack: Add setting for attack range
2023-01-16 14:16:37 +08:00
BruceChen
7011927c71
[SKIP_BUILD]Merge pull request #2358 from MCCTeam/brigadier-dev
Implement command completion suggestions.
2023-01-16 14:11:10 +08:00
BruceChen
30e95f2d23 Bug fix 2023-01-16 04:04:56 +08:00
BruceChen
950d9bcfdc Fix entity handle & Try fix message singing again 2023-01-16 03:00:37 +08:00
BruceChen
50dd5a3ba3 Support specifying the digging duration 2023-01-15 20:56:10 +08:00
BruceChen
338f534239 Fix script not showing execution results. 2023-01-15 19:59:57 +08:00
BruceChen
8db0467f69 Bug fix 2023-01-15 17:18:42 +08:00
BruceChen
957054eb12 1.19.3 entity & inventory & terrain support 2023-01-14 22:18:05 +08:00
BruceChen
b4d7d64cdd Merge some upgrades from AsyncMCC branch 2023-01-14 21:32:19 +08:00
BruceChen
1298654693 Bug fix 2023-01-14 21:20:22 +08:00
BruceChen
ced65122f1 Trim 2023-01-14 21:07:09 +08:00
BruceChen
d4b3c42d8c Update DeclareCommands for 1.19.3 2023-01-14 20:43:32 +08:00
BruceChen
ba0d9ba3fc merge brigadier-dev into milutinke:1.19.3 2023-01-14 20:42:15 +08:00
BruceChen
de9b47b2d9 Reduce conflict 2023-01-14 15:58:36 +08:00
BruceChen
e0294f1beb 1.19.3 PlayerRemove & Explosion packet 2023-01-14 15:55:40 +08:00
BruceChen
052060b23c Bug fix 2023-01-14 02:41:03 +08:00
BruceChen
0ce9690778 1.19.3 Chat command signing support & Update chat paser 2023-01-14 00:53:36 +08:00
BruceChen
fe0b268878 1.19.3 Message signing support. 2023-01-13 16:12:10 +08:00
ReinforceZwei
e447fea16b Send and receive message without message signing 2023-01-13 15:53:33 +08:00
ReinforceZwei
4be7a05006 Player session 2023-01-11 17:25:25 +08:00
BruceChen
6f87710232 AutoAttack: Range check on setting change 2023-01-11 13:08:37 +08:00
BruceChen
aa722b519e
[SKIP_BUILD] Merge pull request #2404 from MCCTeam/dependabot/npm_and_yarn/docs/json5-2.2.3
Bump json5 from 2.2.1 to 2.2.3 in /docs
2023-01-11 12:51:57 +08:00
ReinforceZwei
08da49756f Done receive message 2023-01-10 20:43:54 +08:00
ReinforceZwei
657fc6117b Upgrade protocol to 1.19.3 2023-01-10 18:27:48 +08:00
ReinforceZwei
96245193ee Revert language change in auto-gen file 2023-01-10 17:01:36 +08:00
ReinforceZwei
640abd2d78 AutoAttack: Add setting for attack range 2023-01-10 16:52:18 +08:00
dependabot[bot]
8758e8c8c4
Bump json5 from 2.2.1 to 2.2.3 in /docs
Bumps [json5](https://github.com/json5/json5) from 2.2.1 to 2.2.3.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v2.2.1...v2.2.3)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-09 13:06:03 +00:00
BruceChen
9c8afb7d3c Bug fix 2023-01-02 18:52:49 +08:00
Milutinke
f3b50738f1 Cleaned some code a bit 2022-12-27 11:43:19 +01:00
BruceChen
7d3512ef87
[SKIP_BUILD]Merge pull request #2390 from mrxbox98/patch-1
Fix docker permissions
2022-12-25 14:13:35 +08:00
Mrxbox98
7fc69efd0a
Fix docker permissions
The permissions were being set for the wrong file
2022-12-24 13:45:13 -08:00
Anon
dd2f102eec
Merge pull request #2388 from merlinlcb/patch-1
Update start-latest.sh
2022-12-23 22:35:21 +00:00
merlinlcb
86eeb76a9e
Update start-latest.sh
found that randomly after updating to the latest version execution was not being permitted on multiple linux devices running docker, this solves for that
2022-12-23 12:51:11 -07:00
Milutinke
20273af554 Improvements to the code of the Chat Message packet. 2022-12-21 13:04:41 +01:00
Milutinke
bb160d6d84 Server Data and Profileless Chat message packets implemented. ChatPreview packet removed. Message Header packet set only to 1.19.2. Chat Message packet partially implemented. 2022-12-21 12:51:27 +01:00
Milutinke
d81a67762e Login Start, Encryption Reqest, Merchant Offers, Set Experience packets implemented. 2022-12-21 12:03:39 +01:00
Milutinke
7a9bc7bd1d Added 1.19.3 packet palette. TODO: Implement changes in the protocol handler. 2022-12-17 18:25:21 +01:00
BruceChen
5677c4187c
[SKIP_BUILD]Fixed entity yaw and pitch
Merge pull request #2378 from DevBobcorn/master
2022-12-15 20:10:14 +08:00
Tasuku Bobcorn
1a47eddb8f
Fixed entity yaw and pitch
Fixed number value type during calculation of entity yaw & pitch
2022-12-15 17:47:46 +08:00
BruceChen
7ee08092d4 legacy color support 2022-12-14 14:45:51 +08:00
BruceChen
7900108763 Bug fix 2022-12-11 17:31:37 +08:00
BruceChen
94a3c92b36 Bug fix 2022-12-11 16:30:45 +08:00
BruceChen
127978615c Update tip message 2022-12-11 14:54:11 +08:00
BruceChen
5e11ed3896 Tooltip support & Bug fix 2022-12-11 13:00:19 +08:00
Anon
1d0066f1d8
Merge pull request #2367 from MCCTeam/dependabot/npm_and_yarn/docs/decode-uri-component-0.2.2
Bump decode-uri-component from 0.2.0 to 0.2.2 in /docs
2022-12-10 09:30:24 +00:00
dependabot[bot]
a7a774ecba
Bump decode-uri-component from 0.2.0 to 0.2.2 in /docs
Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases)
- [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2)

---
updated-dependencies:
- dependency-name: decode-uri-component
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-09 17:46:28 +00:00
BruceChen
892999ac98 Merge into master 2022-12-06 20:32:46 +08:00
BruceChen
84cf749344 Implement command completion suggestions. 2022-12-06 15:50:17 +08:00
ReinforceZwei
597af24edb
ProxiedWebRequest: Support http/1.1 (#2357)
* ProxiedWebRequest: Support http/1.1

- Support chunked transfer
- Refactor the code

* Check cookie expire
2022-12-02 21:15:05 +08:00
BruceChen
2ad6d02d59 Display ETA when downloading. 2022-12-01 23:37:15 +08:00
BruceChen
28827b720a Support downloading updates via command. 2022-12-01 22:55:48 +08:00
BruceChen
3713fa2dbe Update Tomlet to 5.0.1 2022-11-30 22:29:55 +08:00
BruceChen
759eb888a6 Fix bug in "/entity near" 2022-11-30 22:17:02 +08:00
BruceChen
046f5ddbc6 Merge branch 'master' of https://github.com/MCCTeam/Minecraft-Console-Client 2022-11-30 18:02:37 +08:00
BruceChen
c77b3e705f
[SKIP_BUILD] Merge pull request #2353 from ITHackerstein/entitynear-command
entitynear: New command to interact with the entity closest to the player.
2022-11-30 18:00:44 +08:00
BruceChen
60bec055a5 Migrate to the "entity" command. 2022-11-30 17:58:29 +08:00
BruceChen
a75e22e792 Update the documentation 2022-11-30 16:27:04 +08:00
BruceChen
2331590588 Store the text resources of the setting file separately. 2022-11-30 16:22:48 +08:00
BruceChen
6c3bfb82ee Remove color code from text 2022-11-30 16:08:55 +08:00
ITHackerstein
5b471b518f EntityNear: Created a new command called 'entitynear' similar to the
'entity' command except it will interact with the entity closest to
the player.
2022-11-28 08:29:55 +01:00
BruceChen
2b9c58de56 [SKIP_BUILD] Fix document build failure 2022-11-28 14:10:55 +08:00
BruceChen
ef39e8329c [SKIP_BUILD] Change file encoding to UTF-8 with BOM 2022-11-28 13:55:05 +08:00
BruceChen
a4e55e8a93 [SKIP_BUILD] Update Crowdin settings 2022-11-28 11:56:36 +08:00
BruceChen
851ecf50c7
Merge pull request #2349 from ITHackerstein/entity-command-entitytype-fix
Fixes the bug in entity command that doesn't allow passing entity types as second argument
2022-11-25 10:32:04 +08:00
BruceChen
f6a11dffdf Entitycmd: Replace Parse with TryParse 2022-11-25 10:30:51 +08:00
ITHackerstein
30861a92ee Entitycmd: Added try-catch statement around the Enum.Parse instruction 2022-11-24 08:30:45 +01:00
ITHackerstein
3d2b9b22a3 Entitycmd: Fixed a bug for which when passing as the second argument
the entity type the command will error out showing its usage
description.

Also now when the type of interaction isn't passed it shows a list
of all the entities with that type.
2022-11-23 10:52:44 +01:00
BruceChen
c67a2955cc
[SKIP_BUILD] Sync translations for doc site daily 2022-11-18 19:58:59 +08:00
BruceChen
8bb81c796d
[SKIP_BUILD] Bump loader-utils from 2.0.3 to 2.0.4 in /docs 2022-11-18 19:05:00 +08:00
dependabot[bot]
bee568192c
Bump loader-utils from 2.0.3 to 2.0.4 in /docs
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 2.0.3 to 2.0.4.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v2.0.4/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v2.0.3...v2.0.4)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-17 23:54:50 +00:00
breadbyte
bde5f76d62
add en-us to available languages
fixes #2341
2022-11-16 12:51:49 +08:00
BruceChen
9b60f24c93 Remove "build-MCC-only.yml" 2022-11-15 10:48:40 +08:00
BruceChen
75b159653a [SKIP_BUILD] Fix tips format in doc 2022-11-08 18:25:02 +08:00
BruceChen
7b017336a5 [SKIP_BUILD] Update chat-bot document 2022-11-08 10:49:15 +08:00
BruceChen
5d2589b10f Merge remote-tracking branch 'origin/master' into brigadier-dev 2022-11-07 15:39:46 +08:00
BruceChen
c1ccdc07a1
[SKIP_BUILD] Set timeout for github action 2022-11-07 13:12:35 +08:00
BruceChen
5a540f646c Update doc 2022-11-07 11:15:19 +08:00
BruceChen
2e7c024f45
[SKIP_BUILD] Fix docker installation reference path (#2330) 2022-11-07 10:08:12 +08:00
Daniel Zauner
8990c974cb
fix docker installation reference path 2022-11-06 15:57:33 +01:00
BruceChen
09d4e71554
Change the way Crowdin integrates (#2329) 2022-11-06 21:21:21 +08:00
BruceChen
0b5a562f7f [SKIP_DEPLOY] Support account alias in configs 2022-11-06 16:20:38 +08:00
BruceChen
c0266685a8 Fix ServerList bug again 2022-11-05 21:30:15 +08:00
BruceChen
fc30e38e78 Fix ServerList bug 2022-11-05 21:15:16 +08:00
BruceChen
0dbc6086d1 Add win-x86 build 2022-11-05 20:36:34 +08:00
BruceChen
b46fef1b34
New Crowdin updates (#2326) 2022-11-05 20:27:53 +08:00
BruceChen
ae23ead4c3 [SKIP_BUILD] FIx "/reco" and "/connect" not working properly 2022-11-05 20:27:10 +08:00
BruceChen
d56dd4a74a Update README.md 2022-11-05 15:54:52 +08:00
BruceChen
8fef126444 Update Frontmatter for Crowdin 2022-11-05 13:43:19 +08:00
BruceChen
02e344724d Short links using document site 2022-11-05 13:30:46 +08:00
BruceChen
55dda7bc43 Fix redirect 2022-11-05 07:46:30 +08:00
BruceChen
c88d32e83c Merge branch 'master' of https://github.com/MCCTeam/Minecraft-Console-Client 2022-11-04 20:19:47 +08:00
BruceChen
8ee288496f Update README.md 2022-11-04 17:10:31 +08:00
BruceChen
50cd64d4b9
New Crowdin updates (#2325) 2022-11-04 16:57:00 +08:00
BruceChen
86c933dc82 [SKIP_DEPLOY] Fix format error 2022-11-04 16:50:52 +08:00
BruceChen
86338f8a92
New Crowdin updates (#2324) 2022-11-04 16:37:49 +08:00
BruceChen
b3ca0a1b33 Fix format error 2022-11-04 16:26:53 +08:00
BruceChen
a23747e236
New Crowdin updates (#2323) 2022-11-04 16:00:06 +08:00
BruceChen
edeea6cae6 Fix format 2022-11-04 15:51:48 +08:00
BruceChen
237d14577f
New Crowdin updates (#2322) 2022-11-04 15:39:02 +08:00
BruceChen
f61c73eb68 [SKIP_DEPLOY] Change the representation of the container 2022-11-04 15:22:53 +08:00
BruceChen
5624e77125 Fix format 2022-11-04 14:25:59 +08:00
BruceChen
27c40f27d2
Update from Crowdin 2022-11-04 13:26:15 +08:00
BruceChen
e6849ae91a Merge branch 'master' of https://github.com/MCCTeam/Minecraft-Console-Client 2022-11-04 12:05:01 +08:00
BruceChen
52b6372be6 [SKIP_DEPLOY] Add plugin-container 2022-11-04 12:04:57 +08:00
BruceChen
e7cb7970bd Update Crowdin configuration file 2022-11-04 11:06:03 +08:00
BruceChen
bbdf5a3699 Fix build fail 2022-11-04 11:01:07 +08:00
BruceChen
262c84123f Restructured localized documents & Bug fix 2022-11-04 10:40:28 +08:00
BruceChen
c03b4470a0 Sync configs 2022-11-04 09:51:27 +08:00
BruceChen
524dbea8fc
New translation update from Crowdin (#2318) 2022-11-04 09:46:21 +08:00
BruceChen
4341304c05 Allow manual trigger Github Action 2022-11-04 09:03:42 +08:00
BruceChen
cb89eb10d0 Update "LanguageName" 2022-11-04 08:59:12 +08:00
BruceChen
115a5c4a10 Update Crowdin configuration file 2022-11-03 10:50:56 +08:00
BruceChen
06d519add4 Triggers a build only when the associated file changes. 2022-11-03 09:55:25 +08:00
BruceChen
2c52b150e8
[SKIP_BUILD] Update vuepress-deploy.yml 2022-11-03 09:39:25 +08:00
BruceChen
648f42f058
[SKIP_BUILD]Update vuepress-deploy.yml 2022-11-03 09:16:59 +08:00
BruceChen
61b5d96c2b
[SKIP_BUILD]Update and rename docs.yml to vuepress-deploy.yml 2022-11-03 09:12:36 +08:00
BruceChen
17e1f6b805
Create docs.yml 2022-11-03 08:32:54 +08:00
BruceChen
be9a8b9a66 Add images 2022-11-02 21:49:54 +08:00
BruceChen
e5529eead9 Migrate documents 2022-11-02 21:01:32 +08:00
BruceChen
de3e21dd64
New translation update from Crowdin (#2317)
* New translations Translations.resx (Russian)
* New translations README.md (Russian)
* New translations Translations.resx (Romanian)
* New translations Translations.resx (Spanish)
2022-11-01 16:47:43 +08:00
BruceChen
e954801a0d Fix AutoDig 2022-11-01 16:37:50 +08:00
BruceChen
d7471e3741
Update build-and-release.yml 2022-10-31 10:48:51 +08:00
BruceChen
e5ed0dc04c
New translation update from Crowdin (#2313)
* New translations README.md (Turkish)

* New translations Translations.resx (Chinese_Traditional)

* New translations Translations.resx (Turkish)
2022-10-31 10:46:20 +08:00
BruceChen
f2f88ac009 Merge master into brigadier-dev 2022-10-29 11:44:54 +08:00
BruceChen
7b09230e10
New Crowdin updates (#2312)
* New translations Translations.resx (Dutch)
2022-10-28 14:18:59 +08:00
BruceChen
95e03476f8 Merge nl.ini from PR #2255 2022-10-28 13:59:39 +08:00
BruceChen
aed47732e6 Update Crowdin configuration file 2022-10-28 12:10:35 +08:00
BruceChen
bccf7120cc
New Crowdin updates (#2311) 2022-10-28 11:34:40 +08:00
BruceChen
077e3a5e9f
Crowdin localization support (#2310)
* Switching to use resource files

* Update Crowdin configuration file

* Code cleanup
2022-10-28 11:13:20 +08:00
Anon
a27491c1b6
Added 2 new example chat bots
Added 2 new example chat bots
2022-10-26 19:33:09 +00:00
Milutinke
0468bde434 Added 2 new example chat bots, removed a really old one which was useless. 2022-10-26 21:31:31 +02:00
Anon
52b80088cd
Added Player Killed event (Combat and CombatDeath packets). 2022-10-26 18:54:03 +00:00
Milutinke
80e227c3a7 Added Player Killed event (Combat and CombatDeath packets). 2022-10-26 20:53:09 +02:00
Anon
01eee22921
Turkish language support
Turkish language support
2022-10-26 17:00:35 +00:00
BruceChen
2a32fbadb5 Update Readme 2022-10-26 09:10:17 +08:00
BruceChen
f8aefaf129 init 2022-10-26 08:54:54 +08:00
Anon
a1259edcae
Merge pull request #2304 from MCCTeam/revert-2289-rpc
Revert "Added the Web Socket Chat Bot"
2022-10-25 09:12:37 +00:00
BruceChen
4925689496
Revert "Added the Web Socket Chat Bot" 2022-10-25 16:23:25 +08:00
BruceChen
404689836d Add Translations support 2022-10-25 10:32:27 +08:00
ByDexter
b8d6914615
Add files via upload 2022-10-25 00:16:08 +03:00
Anon
07b1f59285
Added the Web Socket Chat Bot
Added the Web Socket Chat Bot
2022-10-24 20:53:57 +00:00
Milutinke
7b19a1137f Added a Debug mode setting to the Websocket chat bot. 2022-10-24 22:52:49 +02:00
Milutinke
46e8818b5b Fixed a mintor warning in the Map chat bot. 2022-10-24 22:47:11 +02:00
Anon
477da50fe0
Merge branch 'master' into rpc 2022-10-24 20:45:40 +00:00
Milutinke
4338bef440 Fixed chat messages not being sent. 2022-10-24 22:41:56 +02:00
ByDexter
cea9d710c5
Turkish language support 2022-10-24 23:26:20 +03:00
Anon
e038ff1bcf
Added a Telegram Bridge chat bot.
Added a Telegram Bridge chat bot.
2022-10-24 16:39:51 +00:00
Milutinke
3c6de23d61 Added authorization/security and option to send rendered maps to Telegram via Telegram Bridge chat bot. 2022-10-24 18:39:07 +02:00
Milutinke
1272ffda0b Added a Telegram Bridge chat bot. 2022-10-24 15:35:24 +02:00
Anon
1a739eeab5
Another bug fix and added safeguards to the Discord Bridge chat bot.
Another bug fix and added safeguards to the Discord Bridge chat bot.
2022-10-22 14:36:02 +00:00
Milutinke
9f5b7d50df Another bug fix and added safeguards to the Discord Bridge chat bot. 2022-10-22 16:34:26 +02:00
Anon
0355482da3
Fix a crash with Discord Bridge when getting an empty message
Fix a crash with Discord Bridge when getting an empty message
2022-10-22 12:21:56 +00:00
Milutinke
b89aeda198 Fix a crash with Discord Bridge when getting an empty message 2022-10-22 14:21:35 +02:00
Anon
2ca470de57
Added a command for switching a direction of the Discord Bridge.
Added a command for switching a direction of the Discord Bridge.
2022-10-22 10:17:09 +00:00
Milutinke
6851b8a96c Added a command for switching a direction of the Discord Bridge. 2022-10-22 12:15:44 +02:00
Anon
c49544e0e5
MFixed Map Chat Bot sending images to Discord when just connecting.
Fixed Map Chat Bot sending images to Discord when just connecting.
2022-10-21 19:43:10 +00:00
Milutinke
cbfc592e27 Fixed Map Chat Bot not sending maps in case the Discord Bridge was not ready and connected. 2022-10-21 21:41:45 +02:00
Anon
8071cd1b78
Send rendered maps to Discord via Discord Bridge Chat Bot
Send rendered maps to Discord via Discord Bridge Chat Bot
2022-10-21 18:31:04 +00:00
Milutinke
d8c9e1587b Added Resizing back to the Map Chat bot and added an option to send rendered images to Discord via Discord Bridge chat bot. 2022-10-21 20:25:48 +02:00
Anon
3945d5631f
Added debug option to the Discord Bridge chat bot.
Added debug option to the Discord Bridge chat bot.
2022-10-21 13:09:14 +00:00
Milutinke
614e98d424 Added debug option to the Discord Bridge chat bot. 2022-10-21 15:08:11 +02:00
BruceChen
8fb74c63a6 [README] Calculates the translation status in characters. 2022-10-21 19:24:57 +08:00
BruceChen
d4f8dd0bfb Upgrade AutoFishing & Bug fix 2022-10-21 19:05:49 +08:00
Anon
a2eb3606ce
Implemented a Discord Bridge Chat Bot
Implemented a Discord Bridge Chat Bot
2022-10-21 10:26:00 +00:00
Milutinke
12b317644d Transalted and added detailed comments and instructions and a reference to the documentation article.
Fully tested, ready for merge.
2022-10-21 12:25:33 +02:00
Milutinke
148cb34878 Removed unecessary check and made buttons for teleport request inline which looks way cleaner. 2022-10-21 02:43:43 +02:00
Milutinke
ec27ec53d7 Implemented the Discord Bridge Chat Bot. TODO: Translate 2022-10-21 02:29:47 +02:00
Milutinke
315029b0e8 Fixed the TOML error 2022-10-20 19:42:23 +02:00
Milutinke
ed910aa9c7 Added the Web Socket Chat Bot. 2022-10-20 19:29:35 +02:00
breadbyte
e006943535
Fix externally referenced DLLs in scripts
External DLL references weren't being used, this commit fixes them so they are used.
2022-10-21 00:29:46 +08:00
breadbyte
78f9c35800
Fix scripting system to provide more information in errors
Also make log lines for scripting more uniform
2022-10-20 20:05:36 +08:00
Anon
0e7423d1d9
Implemented climbing up/down
Implemented climbing up/down
2022-10-19 11:18:18 +00:00
Anon
e6c66fbc44
Switched to a faster implementation of FindBlock proposed by Daenges
Switched to a faster implementation of FindBlock proposed by Daenges
2022-10-18 20:42:14 +00:00
Milutinke
730990cee5 Switched to a faster implementation of FindBlock proposed by Daenges, tested on Farmer Bot.
Tweaked the amount of bone mealing in the Farmer Bot.
2022-10-18 22:39:48 +02:00
Milutinke
616591ef35 Implemented climbing up/down for ladders, vines, twisting vines and weeping vines. 2022-10-18 17:15:26 +02:00
BruceChen
ee57d101c0 Fix \n in xx.lang file 2022-10-18 10:39:16 +08:00
BruceChen
eb51f72fb8 Update config\ChatBots 2022-10-18 10:02:43 +08:00
Anon
51742c5606
Fixed BlockInfo overwrite.
Fixed BlockInfo overwrite.
2022-10-17 14:18:14 +00:00
Milutinke
428c5eb71e Fixed BlockInfo overwrite. 2022-10-17 16:17:23 +02:00
Anon
a4175d2981
Improvements to the Bed, Blockinfo and Enchant commands.
Improvements to the Bed, Blockinfo and Enchant commands.
2022-10-17 13:25:00 +00:00
Milutinke
a31b4a792b Improvements to the Bed, Blockinfo and Enchant commands. 2022-10-17 15:14:55 +02:00
Anon
735dc49d92
Updated Farmer bot and Enchant command translations
Updated Farmer bot and Enchant command translations
2022-10-17 12:54:48 +00:00
Milutinke
cbc3f7883e Added cmd.enchant.desc translation 2022-10-17 14:17:30 +02:00
BruceChen
836a1b5801
Update AutoFishing 2022-10-17 20:06:06 +08:00
BruceChen
db568b320c Trim 2022-10-17 20:04:49 +08:00
BruceChen
117a38b5f9 Better translation 2022-10-17 20:00:33 +08:00
Milutinke
7993d347d8 Updated Farmer bot command description and translated untranslated strings. 2022-10-17 13:56:01 +02:00
BruceChen
bce2bc8b7f Support displaying caught items 2022-10-17 17:42:00 +08:00
BruceChen
b949db57cf Support control by command (/fish) 2022-10-17 13:50:56 +08:00
BruceChen
e9f227ca5b Bug fix 2022-10-17 10:03:01 +08:00
Anon
d3cf0f4adf
Readme updates
Readme updates
2022-10-16 15:54:43 +00:00
Milutinke
aa2036b792 Added a grapth for contibutions on the project and updates some readmes to reflect newer changes. 2022-10-16 17:52:34 +02:00
BruceChen
db6d6c80bf Bug fix 2022-10-16 20:37:07 +08:00
Anon
8d15acaef3
Added block info reporting command
Implemented block reporting as requested in #1762
2022-10-16 11:38:32 +00:00
Milutinke
df410a9c8e Fully transalted. 2022-10-16 13:37:49 +02:00
Milutinke
d4129e04bb Implemented block reporting as requested in #1762 2022-10-16 13:33:04 +02:00
BruceChen
10f21dc01c
Fix BadPacket 2022-10-16 18:42:11 +08:00
Anon
12e2c6b4bb
Implemented Enchanting
Implemented Enchanting
2022-10-14 16:02:34 +00:00
Anon
5495f71db7
Added a Farmer Bot
Added a Farmer Bot
2022-10-14 16:02:17 +00:00
Anon
e44973e900
Merge branch 'master' into farmbot 2022-10-14 16:00:46 +00:00
Milutinke
6365e12735 Fixed Enchantment mappings for 1.19.
Added Swift Sneak.
2022-10-14 16:29:08 +02:00
Milutinke
c47add39a4 Added Enchanting Table ASCII Art.
Added ChatBot method for enchantments.
Changed the how the list of enchantments looks, now looks cleaner + has Roman numbers.
Added safe guards to the echant command.
2022-10-14 15:33:33 +02:00
BruceChen
0a43c871ba
Fix sign command 2022-10-14 20:37:18 +08:00
BruceChen
01802dfcff Fix sign command 2022-10-14 20:34:45 +08:00
BruceChen
d30bda4777
Update Map Bot 2022-10-14 10:38:28 +08:00
BruceChen
a7e69fd9fd Update ConsoleInteractive 2022-10-14 10:33:09 +08:00
breadbyte
10372fe5b3
Merge branch 'master' of https://github.com/MCCTeam/Minecraft-Console-Client 2022-10-14 02:32:21 +08:00
breadbyte
023cc2e2d4
Fix Linux issues with the scripting system
This fixes bugs in the scripting system in which scripts does not compile and run on Linux.

This commit also changes wording around the logging in the scripting system to avoid confusion between script errors and regular script compilation.
2022-10-14 02:31:31 +08:00
BruceChen
0bd7ee0f8e Rename 2022-10-13 19:49:39 +08:00
BruceChen
89b7110839 Update Map Bot 2022-10-13 19:34:49 +08:00
Milutinke
4dc1b420f5 Added enchanting 2022-10-12 19:51:01 +02:00
breadbyte
aadede5ae2
Update builds to be self-contained (#2221) 2022-10-13 00:04:13 +08:00
breadbyte
fcaea59a7a
Update builds to skip doc updates (#2258) 2022-10-13 00:02:08 +08:00
Milutinke
4f83e43a68 Added detection when items run out. 2022-10-12 13:45:12 +02:00
Milutinke
6524fe1734 Added Farmer Bot. Fixed a bug in the configuration. Moved Reload and Bots command to the Commands folder. 2022-10-12 12:56:56 +02:00
BruceChen
d222d5f683 Fix AutoRelog 2022-10-12 13:03:57 +08:00
Milutinke
77500deef2 Added the bot. 2022-10-11 22:47:06 +02:00
BruceChen
dee085686f Try fix BadPackets 2022-10-10 15:32:39 +08:00
BruceChen
7fba4fb9ab Bug fix 2022-10-10 11:11:26 +08:00
BruceChen
b2514673bd
Switching to TOML & Add AutoDig ChatBot 2022-10-10 10:58:36 +08:00
BruceChen
625612909e Bug fix 2022-10-10 10:56:12 +08:00
BruceChen
f754f6ab0f
Merge branch 'master' into brucechen-toml-config 2022-10-10 10:54:39 +08:00
breadbyte
9c6102ccd1
update ConsoleInteractive
Fixes a race condition in which the console is stopped and started simultaneously.
This bug generally occurs after the client has disconnected from a server.

Also includes some minor code cleanup.
2022-10-10 03:03:31 +08:00
BruceChen
f567cadc47 Bug fix 2022-10-09 07:57:28 +08:00
BruceChen
2f5914dd6f Add Location_Order config for AutoDig 2022-10-08 18:47:16 +08:00
BruceChen
c57ac183d5 Add AutoDig ChatBot 2022-10-08 17:56:32 +08:00
BruceChen
4cb95731bf Bugfix 2022-10-08 10:06:11 +08:00
BruceChen
c1a04fe5bf Bug fix 2022-10-07 21:49:05 +08:00
Anon
76dcf08734
Added a README translation for Serbian
Added a README translation for Serbian
2022-10-07 10:31:50 +00:00
Anon
075b2b54dd
Update README-sr.md 2022-10-07 10:21:32 +00:00
Anon
568e1f2e53
Update README-sr.md 2022-10-07 10:20:49 +00:00
Anon
8fafd99e3e
Update README-sr.md 2022-10-07 10:19:50 +00:00
Anon
d9db5a48a3
Update README-sr.md 2022-10-07 10:15:22 +00:00
Anon
82193806d1
Create README-sr.md 2022-10-07 08:55:35 +00:00
BruceChen
77d858dc35 Add sneak switch for AntiAFK 2022-10-07 16:13:27 +08:00
BruceChen
2e18317f3f Trim & Bug fix 2022-10-07 15:40:38 +08:00
BruceChen
f538b9e948 Full "zh-Hant" translation 2022-10-07 14:20:58 +08:00
BruceChen
066c932778 Full "zh-Hans" translation 2022-10-07 13:54:11 +08:00
BruceChen
453914a740
Switching to TOML
Refactoring Settings.cs & Switch to use TOML
2022-10-06 22:28:14 +08:00
BruceChen
a98438131f Fix == operator causing crash 2022-10-06 22:16:41 +08:00
BruceChen
e5c713192e Update translation file 2022-10-06 22:14:15 +08:00
BruceChen
e44192ab7b Update translations 2022-10-06 18:12:32 +08:00
BruceChen
bdcc22b465 Add update detection 2022-10-06 14:53:05 +08:00
BruceChen
e92f449749 Fix VersionInfo not exist 2022-10-06 11:55:40 +08:00
BruceChen
a6bb0cb1ac Fix SetPlayerIconAsync 2022-10-06 11:05:39 +08:00
BruceChen
6f456cb1d7 Update readme 2022-10-06 11:03:56 +08:00
BruceChen
d05170a1e2 Update readme 2022-10-05 23:28:51 +08:00
BruceChen
510b67906b Update the translation part of the document. 2022-10-05 23:14:19 +08:00
BruceChen
7f2ede8ad2 Delete unused sample files 2022-10-05 20:41:37 +08:00
BruceChen
48fcdce4ad Merge AutoFishing's config 2022-10-05 20:00:27 +08:00
BruceChen
642a85661f Merge Alerts's config 2022-10-05 19:39:21 +08:00
BruceChen
25dfcd8856 Merge AutoCraft's config 2022-10-05 19:16:33 +08:00
BruceChen
a118dc96e9 Merge AutoRelog's configs 2022-10-05 17:33:21 +08:00
BruceChen
e0678ea7a5 Merge ScriptScheduler's config 2022-10-05 17:10:10 +08:00
BruceChen
e4952dbee0 Delete MinecraftClient.ini 2022-10-05 15:39:42 +08:00
BruceChen
16c1d1fd77 Refactoring Settings.cs 2022-10-05 15:02:30 +08:00
Cubik
f16b1c118b
docs(README-zh-Hans): Fix Typo (#2236) 2022-10-05 08:01:49 +08:00
BruceChen
1611f3c12c
Bugfix: Send too many movement packets 2022-10-04 12:34:37 +08:00
BruceChen
edaa309559 Fix Map bot 2022-10-04 12:00:10 +08:00
BruceChen
b97b226166 Restore to previous movement speed 2022-10-04 11:58:07 +08:00
BruceChen
53898f3446 Fix xxx.Parse 2022-10-04 11:53:07 +08:00
BruceChen
ccb4ce51cc
Alerts ChatBot: Support trigger on weather change 2022-10-03 11:53:27 +08:00
BruceChen
f2cbe74a35 Add translation 2022-10-03 11:48:42 +08:00
BruceChen
81a9955081 Alerts ChatBot: Support trigger on weather change 2022-10-03 11:39:25 +08:00
BruceChen
1d52d1eadd
Fix all warnings & Trim (#2226)
* Fix AutoFishing crash
* Fix all warnings
* Remove DotNetZip.
* Fix the usage of HttpClient.
2022-10-02 18:31:08 +08:00
BruceChen
4aa6c1c99f
Upgrade GetLookingBlock 2022-10-02 13:49:36 +08:00
Cubik
ba6a954f45
docs(README-zh-Hans): Translation work for the new version of README (#2224) 2022-10-02 11:48:59 +08:00
BruceChen
5eb1ffde48
Merge pull request #2222 from BruceChenQAQ/master
Implement Location.Parse
2022-09-30 08:48:34 +08:00
BruceChen
ff7021e798 Upgrade old coordinate parsing. 2022-09-30 08:47:02 +08:00
BruceChen
993771dc5d Merge from master 2022-09-30 08:44:11 +08:00
Anon
f4ca38f143
Renamed the Bed command source file
Renamed the Bed command source file
2022-09-29 17:33:57 +00:00
Milutinke
d66e009979 Removed the old name for the file with bed command. Now using a proper name. 2022-09-29 19:32:02 +02:00
Anon
3656dfdbcd
Added a command for easier usage of the bed (/bed), Added relative coordinates support for the /dig command.
Added a command for easier usage of the bed (/bed).
Added relative coordinates support for the /dig command.
2022-09-29 17:30:10 +00:00
Milutinke
a52da095b4 Added an option to find a bed and sleep in it. 2022-09-29 19:28:34 +02:00
Anon
f4f1e7e8fa
Updated Anti AFK Bot to have Terrain Handling and random intervals option
Updated Anti AFK Bot to have Terrain Handling and random intervals option
2022-09-29 16:29:44 +00:00
BruceChen
cfdc035617 Upgrade old coordinate parsing. 2022-09-29 23:11:30 +08:00
BruceChen
e01eab28a2 Add Location.Parse 2022-09-29 22:49:07 +08:00
BruceChen
36d2a2c731 Fix the error message in str2double. 2022-09-29 21:34:18 +08:00
Milutinke
cd3adfa14c Changed the bed command to be able to sleep. Added relative coordinates to /dig command. 2022-09-28 22:43:14 +02:00
Milutinke
6a266c68c3 Leave bed command. 2022-09-28 21:39:13 +02:00
Milutinke
3a9c9f3c8e Improved some more comments. 2022-09-28 18:56:12 +02:00
Milutinke
a6ad163aad Fixed some comments in the default ini file. 2022-09-28 18:52:57 +02:00
Milutinke
6c07415e24 Improved some comments in the default ini file. 2022-09-28 18:50:48 +02:00
Milutinke
5d1eabd74c Added safeguard for the walk range. 2022-09-28 18:46:17 +02:00
Milutinke
9903ad7535 Updated Anti AFK Chat Bot to use terrain handling, now it can walk around randomly in the given range. Also added random interval support, and the bot now can sneak when using the command (alternative method). 2022-09-28 18:38:57 +02:00
Anon
5571b99a03
Added a Map Chat Bot
Added a Map Chat Bot that can render in-game maps sent by server.
2022-09-28 11:54:07 +00:00
Milutinke
387319b353 Updated comments with useful info for future updates. 2022-09-28 11:57:14 +02:00
Milutinke
83c4f5ad66 Fixed the accidental removal of translations for /reload and /bots commands. 2022-09-28 11:31:26 +02:00
Hcat
9d68670dbd
Update README-zh-Hans.md (#2216) 2022-09-28 17:04:30 +08:00
Milutinke
0a2f777b34 Fixed the color isse thanks to DevBobcorn. 2022-09-28 11:01:15 +02:00
Milutinke
f7263873db Implemented Map Chat bot which can render maps into images. Useful for solving captchas. 2022-09-28 00:14:43 +02:00
Anon
656aed4705
Updated the Auto Attack Chat Bot
Now can attack passive mobs and has option for a whitelist or a blacklist.
2022-09-27 12:35:18 +00:00
Milutinke
36a97f4955 Fixed a bug. 2022-09-27 14:34:10 +02:00
Milutinke
932d25f125 Removed ability to attack players, added an option to have a whitelist or a blacklist mode. 2022-09-27 14:23:19 +02:00
Milutinke
58b171cec0 Updated the AutoAttack Chat Bot settings to include attacking passive mobs and players if enabled, and a blacklisted entities possibility. 2022-09-27 13:35:29 +02:00
Anon
aec38d83c7
Added a log file for Alerts Chat Bot
Added a log file for Alerts Chat Bot
2022-09-25 23:16:49 +00:00
Milutinke
3366b15937 Added a log file for alerts as requested in #1179 2022-09-26 00:56:22 +02:00
Anon
4d276ced71
Script Scheduler added a random interval possibility
Script Scheduler added a random interval
2022-09-25 22:39:54 +00:00
Milutinke
58924c6d6d Added an example. 2022-09-26 00:30:08 +02:00
Milutinke
1147b3e15c Added a random interval option to the Script Scheduler. 2022-09-26 00:28:29 +02:00
Anon
94a7ef2c2c
Reload Settings and Chat Bots, Fixed PlayerListLogger Chat Bot, Added %datetime%
Reload Settings and Chat Bots, Fixed PlayerListLogger Chat Bot, Added %datetime%
2022-09-25 20:33:54 +00:00
Milutinke
8dc3e83f6d Addded %datetime% as requested in #688 2022-09-25 22:32:12 +02:00
Milutinke
cf06c6f8e1 Added a description for the Player List Logger in to the default configuration file. 2022-09-25 22:07:43 +02:00
Milutinke
697025040f Fixed Player List Logger and added config section for it. 2022-09-25 22:06:26 +02:00
Milutinke
8809ad41d8 Accidentally removed initialization for FollowPlayer chat bot, fixed. 2022-09-25 16:18:52 +02:00
Milutinke
9b407dbdad Added command for reloading settings, chat bots, listing chat bots and unloading a chat bot manually by name. 2022-09-25 16:00:43 +02:00
Anon
ef79ca1fe8
Fixed and tested Discord Webhook chat bot
Fixed and tested Discord Webhook chat bot.
Now using ProxiedWebRequest and sanitizing input.
2022-09-24 11:56:11 +00:00
Milutinke
24044303f5 Fixed and tested Discord Webhook chat bot 2022-09-24 13:54:44 +02:00
Anon
5fec15186c
Added more ASCII Art for Inventories and more inventory sub commands
Added more ASCII Art for Inventories and more inventory sub commands.
The following commands have been added:
```
/inventory inventories
/inventory search <item type> [count]
```
2022-09-23 18:23:12 +00:00
Milutinke
23fadc0c33 Removed a comment. 2022-09-23 20:21:56 +02:00
Milutinke
6cb7a25a16 Added /inventory search <item type> [count] command and fixed command help and description. 2022-09-23 20:20:02 +02:00
Milutinke
5b8d5e8e4a Changed the name of the sub command to avoid confusion. Updated the usage string 2022-09-22 22:03:57 +02:00
Milutinke
55057b3157 Added ASCII Art for Furnace/Smoker/Blast Furnace, Hopper/Minecart, Shulker, Grindstone. Added a command for list of available inventories. Added SmithingTable inventory type. 2022-09-22 21:58:51 +02:00
Anon
a03bab277b
Fully implemented Map Data packet + Fixed 1.14 not working.
Fully implemented Map Data packet + Fixed 1.14 not working.
2022-09-22 17:38:43 +00:00
Milutinke
12c8a60ad7 Tested on all versions 1.8 +
Fixed 1.14 not working at all.
2022-09-22 19:36:24 +02:00
Anon
c945a33f8f
Added an option to match by colors in Auto Respond bot.
Added an option to match by colors in Auto Respond bot.
2022-09-21 16:03:38 +00:00
Anon
8fbd1e4801
Fixed internal command char not properly displayed in respawn hint
Fixed internal command char not properly displayed in respawn hint
2022-09-21 16:03:12 +00:00
Milutinke
5e8b2a2cbc Added an example 2022-09-21 18:01:08 +02:00
Milutinke
0d58887b6a Added an option to match by colors in Auto Respond bot. 2022-09-21 17:56:29 +02:00
Tasuku Bobcorn
0445454c72 Fixed internal command char not properly displayed in respawn hint 2022-09-21 21:35:36 +08:00
Anon
b5cf315ca1
Added /execmulti and /execif commands.
Added a way to execute multiple commands with a single command and a conditional command.
The documentation will be updated soon.
2022-09-19 15:26:53 +00:00
BruceChen
85f6d807bf Support using relative coordinates in /useblock 2022-09-18 18:07:10 +08:00
ReinforceZwei
2a2e47a955
README.md: Update website link 2022-09-18 16:50:14 +08:00
Anon
1b352d40ad
Fixed a crash when an Explosion has occurred
Fixed a crash when an Explosion has occurred
2022-09-17 23:19:42 +00:00
Milutinke
1e07fa576a Fixed a crash on Explosion packet 2022-09-18 01:15:57 +02:00
Milutinke
f47c240920 Fully implemented Map Data packet. 2022-09-18 00:18:27 +02:00
BruceChen
59e02c2da9
Fix entity metadata handling and dimension handling in 1.19.2
Fix entity metadata handling and dimension handling in 1.19.2
2022-09-16 12:08:13 +08:00
BruceChen
c00468c103 Fix 1.19.2 entity metadata handle 2022-09-15 21:11:47 +08:00
Anon
7f49ee3120
Added a Follow Player chat bot
Implemented the Follow Player chat bot.
2022-09-15 09:17:15 +00:00
BruceChen
26bc6f16c0 Try fix 1.19+ dimension processing 2022-09-15 12:54:43 +08:00
BruceChen
206a5f1e72 Merge branch 'master' of https://github.com/BruceChenQAQ/Minecraft-Console-Client-1.19dev 2022-09-15 12:48:50 +08:00
BruceChen
a2b2aeb748 Try fix 1.19+ dimension processing 2022-09-15 12:48:38 +08:00
Milutinke
a0f0c634ff Made the /execif return boolean as expression evaluation result 2022-09-13 13:49:59 +02:00
BruceChen
0907958ded
Upgrade Auto Fishing
* Supports changing position and angle after catching fish
* Support automatic rod switching
2022-09-13 19:32:22 +08:00
BruceChen
97248aad16 Add OnSettingsReload 2022-09-13 19:29:17 +08:00
BruceChen
fc444fcbd6 Supports setting thresholds 2022-09-13 19:25:00 +08:00
BruceChen
dac60200e0 Configurable to start fishing automatically or not 2022-09-12 23:15:57 +08:00
BruceChen
99ea0d8997
Merge branch 'MCCTeam:master' into master 2022-09-12 19:55:12 +08:00
BruceChen
34277e3fbd Fix a bug in message signature 2022-09-12 19:02:08 +08:00
BruceChen
cb22387008 Support automatic rod switching 2022-09-12 18:02:46 +08:00
BruceChen
949126c9cb Supports changing position and angle after catching fish 2022-09-12 16:27:37 +08:00
Milutinke
77da611411 Added a command that executes other command if a condition is met. 2022-09-11 22:35:26 +02:00
Anon
bf3acb9cad
Added a discord link to README.md
Added a discord link to README.md
2022-09-11 19:21:33 +00:00
Milutinke
c64efe6775 Added discord link 2022-09-11 21:20:15 +02:00
BruceChen
ccb8610020 Support use left hand 2022-09-12 02:19:20 +08:00
BruceChen
effb3050b4
Merge branch 'MCCTeam:master' into master 2022-09-12 02:12:19 +08:00
BruceChen
eb517a8e78 Upgrade Auto Fishing 2022-09-12 02:10:18 +08:00
BruceChen
efd7c6b75b Fix command history 2022-09-11 23:45:13 +08:00
Milutinke
59cc4cea7c Added a way to execute multiple commands with a single command 2022-09-11 17:06:23 +02:00
Milutinke
c7ba5e5fa3 Implemented the Follow Player chat bot. 2022-09-09 15:39:41 +02:00
BruceChen
223c13561c Fix /move 2022-09-09 16:13:25 +08:00
BruceChen
531f3408a0 Fix format error 2022-09-08 17:39:58 +08:00
BruceChen
5181395bbd
Support for shift-clicking in containers
Support for shift-clicking in containers
2022-09-08 17:21:38 +08:00
BruceChen
ac3f346f14 Trim & Improve the help message 2022-09-08 17:19:13 +08:00
BruceChen
0d1f930c65 Trim 2022-09-08 15:54:56 +08:00
BruceChen
bfd01a5f78 Add non-emoji representation for /chunk status 2022-09-08 14:55:41 +08:00
BruceChen
65bcd83330 Shift click support 2022-09-08 14:04:23 +08:00
BruceChen
b976550828 Fix #2168 2022-09-07 23:58:48 +08:00
Anon
3c884a3d37
Fixed the Docker Image
Fixed the Docker image.
2022-09-07 14:14:47 +00:00
BruceChen
09b1d06bd1 Merge branch 'master' of https://github.com/MCCTeam/Minecraft-Console-Client into upmaster 2022-09-07 19:15:21 +08:00
BruceChen
c6e7dfedab Fix IsSolid 2022-09-07 19:15:09 +08:00
Anon
696fa65c16
Updated the Proxy library
Updated the Proxy library
2022-09-07 10:53:49 +00:00
BruceChen
5321509380
Add "/chunk status" command. (For debugging)
* Add "/chunk status" command. (For debugging)
* Improve IsOnGround
2022-09-07 18:19:45 +08:00
BruceChen
c3d1b4e2ea Update ConsoleInteractive 2022-09-07 18:19:03 +08:00
Anon
67fd01138f
Fixed remote control bot.
Fixed remote control bot.
2022-09-07 09:34:10 +00:00
Milutinke
8dd3efaa54 Fixed remote control bot. 2022-09-07 11:32:38 +02:00
BruceChen
c5d5287938 Improve IsOnGround 2022-09-07 17:25:06 +08:00
BruceChen
317f2e78a9 Rewrite adaptation algorithm 2022-09-07 03:04:07 +08:00
Milutinke
d900824d6a Updated the Proxy library 2022-09-06 19:13:23 +02:00
BruceChen
4d4940a3b9 Trim 2022-09-07 00:08:31 +08:00
BruceChen
8ce5c40b28 Another fix for #2159 2022-09-07 00:02:09 +08:00
BruceChen
7e71fbf241 Bug fix 2022-09-06 23:39:45 +08:00
BruceChen
5cb97ee00b Adaptable width 2022-09-06 23:21:14 +08:00
BruceChen
ecb5d1e2ce Fix #2159 2022-09-06 22:43:56 +08:00
Anon
81579a7e40
Added a custom timeout setting
Added an option for custom timeout as requested in #1337.
2022-09-06 14:10:24 +00:00
Milutinke
dcf1442b4f Resolved a conflict 2022-09-06 16:08:51 +02:00
BruceChen
e69305f4fc Trim 2022-09-06 21:40:44 +08:00
BruceChen
3dac1f41d1 Add tips 2022-09-06 16:10:34 +08:00
BruceChen
c50477a712 Marking chunk 2022-09-06 15:25:27 +08:00
BruceChen
6430f13d3e Add "/chunk status" command 2022-09-06 14:54:49 +08:00
BruceChen
7a33e65c61
Merge pull request #2154 from BruceChenQAQ/master
Support for using relative coordinates in /move
2022-09-05 23:24:27 +08:00
BruceChen
e5c3b914dd Trim before parse 2022-09-05 22:21:04 +08:00
BruceChen
0eb8d9998c Support for using relative coordinates in /move 2022-09-05 22:03:47 +08:00
breadbyte
8f6b962607
update ConsoleInteractive submodule 2022-09-05 20:03:01 +08:00
Anon
e56139a56d
Major performance optimization and bug fixes
Bug fix & Performance Optimization
2022-09-05 11:57:17 +00:00
BruceChen
015d28ec94 Fix for LoginSuccess packet 2022-09-04 20:44:38 +08:00
BruceChen
dfc310b3f2 Fix for EntityEffect packet 2022-09-04 18:12:47 +08:00
BruceChen
db17babe58 Bug fix 2022-09-04 17:34:12 +08:00
BruceChen
bcded40476 Bug fix 2022-09-04 10:50:49 +08:00
BruceChen
afdf2f9e2c Merge from master 2022-09-04 10:44:25 +08:00
Anon
58ca80908f
New readme
Updated the README.md and the configs/README.md
2022-09-03 19:12:28 +00:00
Milutinke
3fd222b2c6 Removed an emoji from the download section 2022-09-03 21:11:32 +02:00
Anon
00d972c417
Update MinecraftClient/config/README.md
Co-authored-by: ORelio <ORelio@users.noreply.github.com>
2022-09-03 19:08:26 +00:00
Anon
a383ead27f
Added 1.19.1/2 + Terrain Handling
Added 1.19.1/2 + Terrain Handling
2022-09-03 19:07:51 +00:00
BruceChen
ca3cb39f12 Trim 2022-09-04 00:45:21 +08:00
BruceChen
5d05fc1d53 Sort packet type 2022-09-04 00:37:52 +08:00
BruceChen
7b68c0c45a Setting the default type of chat 2022-09-03 13:39:45 +08:00
BruceChen
2c5b444ffd Add type RAW_MSG in 1.19.2 2022-09-03 12:18:11 +08:00
BruceChen
3b95cbcce0 Trim 2022-09-03 02:06:16 +08:00
BruceChen
6cb0c35ab8 Trim 2022-09-02 22:38:59 +08:00
BruceChen
11fe93a128 Merge from milutinke 2022-09-02 21:38:43 +08:00
BruceChen
0382e07d50 Bug fix: Chunk deleted by mistake 2022-09-02 21:02:25 +08:00
BruceChen
70d354b016 Merge branch '1.19.1-dev-new' of https://github.com/BruceChenQAQ/Minecraft-Console-Client-1.19dev into 1.19.1-dev-new 2022-09-02 20:22:49 +08:00
BruceChen
f4ab4997c8 Bug fix. 2022-09-02 20:22:33 +08:00
BruceChen
71ecebedce
Merge branch 'master' into 1.19.1-dev-new 2022-09-02 11:08:39 +08:00
BruceChen
8ed2bc9d07
Merge branch 'master' into bugfix 2022-09-02 10:53:29 +08:00
BruceChen
4538095d74 Reduce merge conflicts 2022-09-02 09:29:24 +08:00
BruceChen
290ec9cc79 Bug fix 2022-09-01 23:10:09 +08:00
BruceChen
b26949e483 Fix issue #2111 2022-09-01 22:57:13 +08:00
BruceChen
a13af47b3e Reduce the latency of sending messages 2022-08-31 22:52:05 +08:00
BruceChen
98dd645fb5 Bug fix: Can't reconnect after connection lost 2022-08-31 22:32:38 +08:00
BruceChen
db64515b78 Fix issue #2144 2022-08-31 21:25:54 +08:00
BruceChen
c0be6a61c8 Trim 2022-08-31 20:46:21 +08:00
BruceChen
0a689e407e Trim 2022-08-31 19:50:11 +08:00
BruceChen
9089bb4cdb Change how world is stored & Bug fix 2022-08-31 18:00:00 +08:00
BruceChen
c90ea0e92b Startup Optimization 2022-08-30 22:50:05 +08:00
BruceChen
3d13eb51e6 Trim 2022-08-30 20:05:53 +08:00
BruceChen
aceccaf5b5 No longer need to cancel chunk loading 2022-08-30 19:09:07 +08:00
BruceChen
e4c77b0fef Bug fix: Call handler.OnNetworkPacket() repeatedly 2022-08-30 18:39:09 +08:00
BruceChen
a6b98de43f Fix not calling "handler.OnUpdate()" on time 2022-08-30 18:17:39 +08:00
BruceChen
1a90b6d942 Use separate threads for decryption and decompression 2022-08-30 17:37:46 +08:00
BruceChen
c941d086d9 Improve ReadBlockStatesField 2022-08-30 14:04:27 +08:00
BruceChen
e09016cea5 Improve ReadBlockStatesField 2022-08-30 12:33:13 +08:00
BruceChen
cd45c64300 Change chunk storage structure 2022-08-30 10:41:27 +08:00
Milutinke
42de4378e1 Added an option for custom timeout as requested in #1337. 2022-08-29 19:12:44 +02:00
BruceChen
68b9c81c0b Improve ReadBlockStatesField 2022-08-29 23:39:03 +08:00
BruceChen
da02f8004f Bug fix: Guid parse fail 2022-08-29 17:13:35 +08:00
BruceChen
684dcb3fc6 Trim 2022-08-28 23:34:28 +08:00
BruceChen
c8cecabc5c Terrain support for 1.19.1 / 1.19.2 2022-08-28 23:04:55 +08:00
BruceChen
bc5298bf5f Terrain support for 1.19 2022-08-28 22:27:21 +08:00
Milutinke
9e2f6d3b57 Updated the README.md and the configs/README.md 2022-08-28 13:59:55 +02:00
BruceChen
9e4184a98d Add 1.19 block palette 2022-08-28 18:39:59 +08:00
BruceChen
003c4c3ab8 Fix issue #2094 2022-08-28 17:14:28 +08:00
BruceChen
75e7b0e37d Fix issue #2119 2022-08-28 16:18:29 +08:00
BruceChen
dff3f23b03 Bug fix: ResourcePackSend.hasPromptMessage 2022-08-28 15:32:09 +08:00
BruceChen
d10ad138f1 Trim 2022-08-28 14:57:44 +08:00
BruceChen
4757c4be53 Trim 2022-08-28 13:18:07 +08:00
BruceChen
842c968220 Use AES-NI instruction set if possible 2022-08-28 10:50:52 +08:00
BruceChen
13d1a9856a Rewrote AES stream & Perform "SessionCheck" in advance 2022-08-27 23:01:28 +08:00
BruceChen
7ceb4807f3 Adjust some comments 2022-08-27 02:32:59 +08:00
BruceChen
93c89f879d Fix format 2022-08-27 02:14:25 +08:00
BruceChen
c34dd46067 Basic support for 1.19.2 2022-08-27 02:10:44 +08:00
BruceChen
a3971f9097 Update to BouncyCastle 1.9.0 2022-08-25 21:29:33 +08:00
BruceChen
ed8e97fd2d Bug fix: /move command went to the wrong location 2022-08-25 14:36:15 +08:00
BruceChen
5f520e2cf4 Improve ReadBlockStatesField 2022-08-25 10:40:55 +08:00
BruceChen
64915c87cf Bug fix: Incorrect handling of Chunk.FullyLoaded in 1.17[.1] 2022-08-25 02:21:36 +08:00
BruceChen
b125b0f10a Remove debug message 2022-08-25 02:04:36 +08:00
BruceChen
58eafdfd5c Optimize cold start speed and block loading speed 2022-08-25 01:34:07 +08:00
BruceChen
01ef9a89ca Bug fix: Cancel chunk load task when switching worlds 2022-08-24 18:16:16 +08:00
BruceChen
af1485c753 login support 2022-08-24 12:37:22 +08:00
Milutinke
e6164cd179 Fixed the BuildKit error 2022-08-20 20:20:36 +02:00
Milutinke
ec0f94a870 Fixed the Docker 2022-08-19 21:22:54 +02:00
955 changed files with 269380 additions and 67802 deletions

1
.claude/skills Symbolic link
View file

@ -0,0 +1 @@
../.skills

16
.codex/hooks.json Normal file
View file

@ -0,0 +1,16 @@
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/pre_tool_use_mcc_build_guard.py\"",
"statusMessage": "Checking MCC build command policy"
}
]
}
]
}
}

View file

@ -0,0 +1,67 @@
#!/usr/bin/env python3
import json
import re
import sys
RAW_DOTNET_BUILD_RE = re.compile(r"(^|[\s;&|()])dotnet\s+build(\s|$)")
ABSOLUTE_DOTNET_BUILD_RE = re.compile(r"(^|[\s;&|()])/\S*dotnet\s+build(\s|$)")
RAW_DOTNET_PUBLISH_RE = re.compile(r"(^|[\s;&|()])dotnet\s+publish(\s|$)")
ABSOLUTE_DOTNET_PUBLISH_RE = re.compile(r"(^|[\s;&|()])/\S*dotnet\s+publish(\s|$)")
def main() -> int:
try:
payload = json.load(sys.stdin)
except json.JSONDecodeError:
return 0
command = payload.get("tool_input", {}).get("command", "")
if not isinstance(command, str) or not command:
return 0
if ABSOLUTE_DOTNET_BUILD_RE.search(command) or ABSOLUTE_DOTNET_PUBLISH_RE.search(command):
return 0
if RAW_DOTNET_BUILD_RE.search(command):
response = {
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": (
"Raw 'dotnet build' is blocked in this repository. "
"Use 'source tools/mcc-env.sh && mcc-build' instead so MCC temp-build routing stays active. "
"If you intentionally need the raw .NET CLI, call it by absolute path such as '/usr/bin/dotnet build ...' to bypass this guard."
),
},
"systemMessage": (
"Blocked raw 'dotnet build'. Use 'source tools/mcc-env.sh && mcc-build'. "
"If you intentionally need raw .NET CLI behavior, call '/usr/bin/dotnet build ...' explicitly."
),
}
json.dump(response, sys.stdout)
sys.stdout.write("\n")
elif RAW_DOTNET_PUBLISH_RE.search(command):
response = {
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": (
"Raw 'dotnet publish' is blocked in this repository. "
"Use 'source tools/mcc-env.sh && mcc-publish --rid <RID>' instead so MCC publish defaults stay aligned with the repo workflow. "
"If you intentionally need the raw .NET CLI, call it by absolute path such as '/usr/bin/dotnet publish ...' to bypass this guard."
),
},
"systemMessage": (
"Blocked raw 'dotnet publish'. Use 'source tools/mcc-env.sh && mcc-publish --rid <RID>'. "
"If you intentionally need raw .NET CLI behavior, call '/usr/bin/dotnet publish ...' explicitly."
),
}
json.dump(response, sys.stdout)
sys.stdout.write("\n")
return 0
if __name__ == "__main__":
raise SystemExit(main())

1
.codex/skills Symbolic link
View file

@ -0,0 +1 @@
../.skills

1
.cursor/skills Symbolic link
View file

@ -0,0 +1 @@
../.skills

3
.cursorindexingignore Normal file
View file

@ -0,0 +1,3 @@
# Don't index SpecStory auto-save files, but allow explicit context inclusion via @ references
.specstory/**

2
.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
# Set the default line endings to LF
* text=auto

View file

@ -9,7 +9,7 @@ body:
attributes:
label: Prerequisites
options:
- label: I made sure I am running the latest [development build](https://ci.appveyor.com/project/ORelio/minecraft-console-client/build/artifacts)
- label: I made sure I am running the latest [development build](https://github.com/MCCTeam/Minecraft-Console-Client/releases/latest)
required: true
- label: I tried to [look for similar issues](https://github.com/MCCTeam/Minecraft-Console-Client/issues?q=is%3Aissue) before opening a new one
required: true
@ -95,4 +95,4 @@ body:
- type: markdown
id: credit
attributes:
value: Thank you for filling the bug report. Feel free to submit the report to us.
value: Thank you for filling the bug report. Feel free to submit the report to us.

View file

@ -10,9 +10,9 @@ body:
attributes:
label: Prerequisites
options:
- label: I have read and understood the [user manual](https://github.com/MCCTeam/Minecraft-Console-Client/tree/master/MinecraftClient/config)
- label: I have read and understood the [user manual](https://mccteam.github.io/guide/)
required: true
- label: I made sure I am running the latest [development build](https://ci.appveyor.com/project/ORelio/Minecraft-Console-Client/build/artifacts)
- label: I made sure I am running the latest [development build](https://github.com/MCCTeam/Minecraft-Console-Client/releases/latest)
required: true
- label: I tried to [look for similar feature requests](https://github.com/MCCTeam/Minecraft-Console-Client/issues?q=is%3Aissue) before opening a new one
required: true
@ -69,4 +69,4 @@ body:
- type: markdown
id: credit
attributes:
value: Thank you for filling the request form. Feel free to submit the request to us.
value: Thank you for filling the request form. Feel free to submit the request to us.

View file

@ -1,119 +1,246 @@
name: Build
name: Build MCC and Documents
on:
push:
branches: [ master ]
branches:
- master
workflow_dispatch:
env:
PROJECT: "MinecraftClient"
target-version: "net6.0"
compile-flags: "--no-self-contained -c Release -p:UseAppHost=true -p:IncludeNativeLibrariesForSelfExtract=true -p:DebugType=None"
target-version: "net10.0"
dotnet-version: "10.0.x"
compile-flags: "--self-contained=true -c Release -p:UseAppHost=true -p:IncludeNativeLibrariesForSelfExtract=true -p:EnableCompressionInSingleFile=true -p:DebugType=Embedded -p:PublishSingleFile=true"
jobs:
build:
determine-build:
runs-on: ubuntu-slim
outputs:
skip: ${{ steps.check-skip.outputs.skip }}
steps:
- name: Check skip CI
id: check-skip
run: |
LOWER=$(echo "$COMMIT_MSG" | tr '[:upper:]' '[:lower:]')
if echo "$LOWER" | grep -qE 'skip.?ci|ci.?skip'; then
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
env:
COMMIT_MSG: ${{ github.event.head_commit.message }}
fetch-translations:
strategy:
fail-fast: true
runs-on: ubuntu-latest
needs: determine-build
if: ${{ needs.determine-build.outputs.skip != 'true' }}
timeout-minutes: 15
steps:
- name: Setup Project Path
run: |
echo project-path=${{ github.workspace }}/${{ env.PROJECT }} >> $GITHUB_ENV
- name: Setup Output Paths
run: |
echo win-out-path=${{ env.project-path }}/bin/Release/${{ env.target-version }}/win-x64/publish/ >> $GITHUB_ENV
echo linux-out-path=${{ env.project-path }}/bin/Release/${{ env.target-version }}/linux-x64/publish/ >> $GITHUB_ENV
echo osx-out-path=${{ env.project-path }}/bin/Release/${{ env.target-version }}/osx-x64/publish/ >> $GITHUB_ENV
echo linux-arm64-out-path=${{ env.project-path }}/bin/Release/${{ env.target-version }}/linux-arm64/publish/ >> $GITHUB_ENV
- name: Setup .NET SDK
uses: actions/setup-dotnet@v2.1.0
- name: Check cache
uses: actions/cache/restore@v3
id: cache-check
with:
path: ${{ github.workspace }}/*
key: "translation-${{ github.sha }}"
lookup-only: true
restore-keys: "translation-"
- name: Checkout
uses: actions/checkout@v2
if: steps.cache-check.outputs.cache-hit != 'true'
uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: 'true'
- name: Get Version DateTime
id: date-version
uses: nanzm/get-time-action@v1.0
with:
timeZone: 0
format: 'YYYY-MM-DD'
- name: VersionInfo
- name: Check Crowdin secrets
id: crowdin-check
run: |
COMMIT=$(echo ${{ github.sha }} | cut -c 1-7)
echo '' >> ${{ env.project-path }}\Properties\AssemblyInfo.cs
echo "[assembly: AssemblyConfiguration(\"GitHub build ${{ github.run_number }}, built on ${{ steps.date-version.outputs.time }} from commit $COMMIT\")]" >> ${{ env.project-path }}\Properties\AssemblyInfo.cs
- name: Build for Windows
run: dotnet publish ${{ env.project-path }}.sln -f ${{ env.target-version }} -r win-x64 ${{ env.compile-flags }}
if [ -z "$CROWDIN_PROJECT_ID" ] || [ -z "$CROWDIN_PERSONAL_TOKEN" ]; then
echo "available=false" >> $GITHUB_OUTPUT
else
echo "available=true" >> $GITHUB_OUTPUT
fi
env:
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_TOKEN }}
- name: Zip Windows Build
run: zip -qq -r windows.zip *
working-directory: ${{ env.win-out-path }}
- name: Download translations from crowdin
uses: crowdin/github-action@v2.4.0
if: steps.cache-check.outputs.cache-hit != 'true' && steps.crowdin-check.outputs.available == 'true'
with:
upload_sources: ${{ github.repository == 'MCCTeam/Minecraft-Console-Client' }}
upload_translations: false
download_translations: true
- name: Build for Linux
run: dotnet publish ${{ env.project-path }}.sln -f ${{ env.target-version }} -r linux-x64 ${{ env.compile-flags }}
localization_branch_name: l10n_master
create_pull_request: false
push_translations: false
- name: Zip Linux Build
run: zip -qq -r linux.zip *
working-directory: ${{ env.linux-out-path }}
- name: Build for ARM64 Linux
run: dotnet publish ${{ env.project-path }}.sln -f ${{ env.target-version }} -r linux-arm64 ${{ env.compile-flags }}
base_path: ${{ github.workspace }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_TOKEN }}
- name: Zip ARM64 Linux Build
run: zip -qq -r linux-arm64.zip *
working-directory: ${{ env.linux-arm64-out-path }}
- name: Build for OSX
run: dotnet publish ${{ env.project-path }}.sln -f ${{ env.target-version }} -r osx-x64 ${{ env.compile-flags }}
- name: Zip OSX Build
run: zip -qq -r osx.zip *
working-directory: ${{ env.osx-out-path }}
- name: Get Release DateTime
id: date-release
uses: nanzm/get-time-action@v1.0
- name: Save cache
uses: actions/cache/save@v3
if: steps.cache-check.outputs.cache-hit != 'true'
with:
timeZone: 0
format: 'YYYYMMDD'
path: ${{ github.workspace }}/*
key: "translation-${{ github.sha }}"
- name: Windows Release
uses: tix-factory/release-manager@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
mode: uploadReleaseAsset
filePath: ${{ env.win-out-path }}windows.zip
assetName: ${{ env.PROJECT }}-windows.zip
tag: ${{ format('{0}-{1}', steps.date-release.outputs.time, github.run_number) }}
create-tag:
runs-on: ubuntu-slim
timeout-minutes: 5 # Wait 5 minutes in case of network issues/etc
needs: determine-build
if: ${{ needs.determine-build.outputs.skip != 'true' }}
steps:
- id: make-tag
run: |
TAG="$(date -u +'%Y%m%d')-${{ github.run_number }}"
echo "tag=$TAG" >> $GITHUB_OUTPUT
echo "TAG=$TAG" >> $GITHUB_ENV
- name: Create Release Tag
uses: actions/github-script@v7
with:
script: |
const tag = process.env.TAG;
try {
await github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `refs/tags/${tag}`,
sha: context.sha
});
} catch(error) {
if (error.message.includes('already exists')) {
console.log(`Tag ${tag} already exists`);
} else {
throw error;
}
}
outputs:
build-tag: ${{ steps.make-tag.outputs.tag }}
- name: Linux Release
uses: tix-factory/release-manager@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
mode: uploadReleaseAsset
filePath: ${{ env.linux-out-path }}linux.zip
assetName: ${{ env.PROJECT }}-linux.zip
tag: ${{ format('{0}-{1}', steps.date-release.outputs.time, github.run_number) }}
build:
runs-on: ubuntu-latest
# Check if we're not skipping build, tag is created, and translations successfully fetched (or skipped)
if: ${{ needs.determine-build.outputs.skip != 'true' &&
needs.create-tag.result == 'success' &&
(needs.fetch-translations.result == 'success' || needs.fetch-translations.result == 'skipped')
}}
needs: [determine-build, fetch-translations, create-tag]
timeout-minutes: 15
strategy:
matrix:
target: [win-x86, win-x64, win-arm64, linux-x64, linux-arm, linux-arm64, osx-x64, osx-arm64]
- name: Linux ARM64 Release
uses: tix-factory/release-manager@v1
steps:
- name: Checkout
uses: actions/checkout@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
mode: uploadReleaseAsset
filePath: ${{ env.linux-arm64-out-path }}linux-arm64.zip
assetName: ${{ env.PROJECT }}-linux-arm64.zip
tag: ${{ format('{0}-{1}', steps.date-release.outputs.time, github.run_number) }}
fetch-depth: 0
submodules: 'true'
- name: Get Current Date
run: |
echo date_dashed=$(date -u +'%Y-%m-%d') >> $GITHUB_ENV
- name: Restore Translations (if available)
uses: actions/cache/restore@v3
with:
path: ${{ github.workspace }}/*
key: "translation-${{ github.sha }}"
restore-keys: "translation-"
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.dotnet-version }}
- name: Setup Environment Variables
run: |
PROJECT_PATH=${{ github.workspace }}/${{ env.PROJECT }}
FILE_EXT=${{ (startsWith(matrix.target, 'win') && '.exe') || '' }}
TARGET_OUT_PATH=$PROJECT_PATH/bin/Release/${{ env.target-version }}/${{ matrix.target }}/publish/
echo "project-path=$PROJECT_PATH" >> $GITHUB_ENV
echo "file-ext=$FILE_EXT" >> $GITHUB_ENV
echo "target-out-path=$TARGET_OUT_PATH" >> $GITHUB_ENV
echo "assembly-info=$PROJECT_PATH/Properties/AssemblyInfo.cs" >> $GITHUB_ENV
echo "build-version-info=${{ needs.create-tag.outputs.build-tag }}" >> $GITHUB_ENV
echo "commit=$(echo ${{ github.sha }} | cut -c 1-7)" >> $GITHUB_ENV
- name: Setup Binaries Path
run: |
echo built-executable-path=${{ env.target-out-path }}${{ env.PROJECT }}${{ env.file-ext }} >> $GITHUB_ENV
- name: OSX Release
uses: tix-factory/release-manager@v1
- name: Set Version Info
run: |
echo '' >> ${{ env.assembly-info }}
echo "[assembly: AssemblyConfiguration(\"GitHub build ${{ github.run_number }}, built on ${{ env.date_dashed }} from commit ${{ env.commit }}\")]" >> ${{ env.assembly-info }}
- name: Inject Sentry DSN (if applicable)
if: ${{ github.repository == 'MCCTeam/Minecraft-Console-Client' }}
run: |
grep -q 'SentryDSN = "";' ${{ env.project-path }}/Program.cs || { echo "SentryDSN pattern not found in Program.cs"; exit 1; }
sed -i -e 's|SentryDSN = "";|SentryDSN = "${{ secrets.SENTRY_DSN }}";|g' ${{ env.project-path }}/Program.cs
- name: Build Target
run: dotnet publish ${{ env.project-path }}/${{ env.PROJECT }}.csproj -f ${{ env.target-version }} -r ${{ matrix.target }} ${{ env.compile-flags }}
env:
DOTNET_NOLOGO: true
- name: Rename Binary
run: |
mv ${{ env.built-executable-path }} ${{ env.PROJECT }}-${{ env.build-version-info }}-${{ matrix.target }}${{ env.file-ext }}
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
mode: uploadReleaseAsset
filePath: ${{ env.osx-out-path }}osx.zip
assetName: ${{ env.PROJECT }}-osx.zip
tag: ${{ format('{0}-{1}', steps.date-release.outputs.time, github.run_number) }}
name: ${{ env.PROJECT }}-${{ env.build-version-info }}-${{ matrix.target }}
path: ${{ env.PROJECT }}-${{ env.build-version-info }}-${{ matrix.target }}${{ env.file-ext }}
if-no-files-found: error
create-release:
runs-on: ubuntu-slim
needs: [create-tag, build]
if: ${{ needs.build.result == 'success' && needs.create-tag.result == 'success' }}
steps:
- name: Download All Artifacts
uses: actions/download-artifact@v4
with:
path: artifacts/
merge-multiple: true
- name: Truncate commit message for release name
id: release-name
run: |
SUBJECT=$(echo "$COMMIT_MSG" | head -n 1)
MAX=220
TRUNCATED="${SUBJECT:0:$MAX}"
echo "name=${BUILD_TAG}: $TRUNCATED" >> $GITHUB_OUTPUT
env:
COMMIT_MSG: ${{ github.event.head_commit.message }}
BUILD_TAG: ${{ needs.create-tag.outputs.build-tag }}
- name: Create Release
uses: ncipollo/release-action@v1.14.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
artifacts: "artifacts/**/*"
tag: ${{ needs.create-tag.outputs.build-tag }}
name: ${{ steps.release-name.outputs.name }}
generateReleaseNotes: true
artifactErrorsFailBuild: true
allowUpdates: true
makeLatest: true
omitBodyDuringUpdate: true
omitNameDuringUpdate: true
replacesArtifacts: true

79
.github/workflows/deploy-doc-only.yml vendored Normal file
View file

@ -0,0 +1,79 @@
name: Build Documents
on:
schedule:
- cron: '45 0 * * *'
workflow_dispatch:
jobs:
check-secrets:
runs-on: ubuntu-latest
outputs:
has-deploy-token: ${{ steps.check.outputs.has-deploy-token }}
steps:
- name: Check required secrets
id: check
run: |
if [ -z "$GH_PAGES_TOKEN" ]; then
echo "has-deploy-token=false" >> $GITHUB_OUTPUT
echo "::warning::GH_PAGES_TOKEN is not set, skipping documentation deployment."
else
echo "has-deploy-token=true" >> $GITHUB_OUTPUT
fi
env:
GH_PAGES_TOKEN: ${{ secrets.GH_PAGES_TOKEN }}
Build:
runs-on: ubuntu-latest
needs: check-secrets
if: ${{ needs.check-secrets.outputs.has-deploy-token == 'true' }}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: 'true'
- name: Check Crowdin secrets
id: crowdin-check
run: |
if [ -z "$CROWDIN_PROJECT_ID" ] || [ -z "$CROWDIN_PERSONAL_TOKEN" ]; then
echo "available=false" >> $GITHUB_OUTPUT
echo "::warning::Crowdin secrets not set, skipping translation download."
else
echo "available=true" >> $GITHUB_OUTPUT
fi
env:
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_TOKEN }}
- name: Download translations from crowdin
if: ${{ steps.crowdin-check.outputs.available == 'true' }}
uses: crowdin/github-action@v2.4.0
with:
upload_sources: false
upload_translations: false
download_translations: true
localization_branch_name: l10n_master
create_pull_request: false
push_translations: false
base_path: ${{ github.workspace }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_TOKEN }}
- name: Deploy Documentation Site
uses: jenkey2011/vuepress-deploy@master
env:
ACCESS_TOKEN: ${{ secrets.GH_PAGES_TOKEN }}
TARGET_REPO: MCCTeam/MCCTeam.github.io
TARGET_BRANCH: master
BUILD_SCRIPT: export NODE_OPTIONS=--max-old-space-size=8192 && yarn --cwd ./docs/ && yarn --cwd ./docs/ docs:build
BUILD_DIR: docs/.vuepress/dist
COMMIT_MESSAGE: Build from ${{ github.sha }}
CNAME: https://mccteam.github.io

View file

@ -0,0 +1,33 @@
name: Upload translation sources
on:
workflow_dispatch:
jobs:
Sync:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: 'true'
- name: Upload translation sources to crowdin
uses: crowdin/github-action@v1.6.0
with:
upload_sources: true
upload_translations: false
download_translations: false
localization_branch_name: l10n_master
create_pull_request: false
push_translations: false
base_path: ${{ github.workspace }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_TOKEN }}

51
.gitignore vendored
View file

@ -8,11 +8,15 @@
/Other/
/.vs/
SessionCache.ini
.*
!/.github
/packages
/packages
# OS-generated files
.DS_Store
Thumbs.db
desktop.ini
ehthumbs.db
._*
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
@ -384,7 +388,7 @@ FodyWeavers.xsd
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/launch.json``
!.vscode/extensions.json
*.code-workspace
@ -402,3 +406,42 @@ FodyWeavers.xsd
.idea/
*.sln.iml
*.sln.iml
# docs
!/docs/.vuepress
/docs/.vuepress/.cache
/docs/.vuepress/.temp
/docs/.vuepress/dist
# translations
/MinecraftClient/Resources/Translations/Translations.*.resx
/MinecraftClient/Resources/AsciiArt/AsciiArt.*.resx
/MinecraftClient/Resources/ConfigComments/ConfigComments.*.resx
/docs/.vuepress/translations/*.json
!/docs/.vuepress/translations/en.json
/docs/l10n/
/docs/.vuepress/public/MCC-README/
/docs/superpowers/
# Floder to store the decompiled Minecraft official source code
/MinecraftOfficial/
# Possible debug files
/lang/*
/mcc_input.txt
/MinecraftClient.ini
/MinecraftClient.backup.ini
# SpecStory files
/.specstory/
/.vscode/settings.json
# Other
/Sentry/
/downloads/
server.pid
# Crowdin translation automation working directory
/.crowdin-translate/

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,82 @@
---
description: >-
Context-specific async guidance for library code, ui apps, asp.net core,
background work, task.run, configureawait, and performance-sensitive design.
metadata:
tags: [configureawait, task.run, asp.net core, ui, library, performance]
source: mixed
---
# Context and Tradeoffs
## Library code versus app code
### General-purpose library code
- Prefer APIs that expose true async for I/O-bound work.
- Do not add async wrappers around purely compute-bound methods just to look modern. Expose sync compute APIs and let callers decide whether to offload.
- `ConfigureAwait(false)` is a strong default when the library does not need the callers context.
- Avoid ambient assumptions about a UI thread, request context, or test framework behavior.
### App code
- Prefer the style that fits the app model.
- UI code often needs the original context after `await`.
- ASP.NET Core request code normally does not need `Task.Run` just to stay responsive, because it already runs on thread pool threads.
- Do not present “ASP.NET Core has no synchronization context” as proof that every `ConfigureAwait(false)` discussion is obsolete.
## `Task.Run` boundaries
### Good uses
- Offload CPU-bound work so a UI thread can stay responsive.
- Offload CPU work from a caller when that scheduling boundary is deliberate.
### Weak uses
- Wrapping synchronous I/O to pretend it is true async I/O.
- Calling `Task.Run` and immediately awaiting it in ASP.NET Core request handling when no CPU offload goal exists.
- Using `Task.Run` to hide blocking APIs instead of fixing the underlying API choice.
## Fire-and-forget
### Assume unsafe until proven otherwise
A background task needs answers for all of these:
- Who owns its lifetime?
- How are exceptions observed?
- How does shutdown cancel it?
- Does it touch scoped services or request-bound objects?
- Does work need retries, backpressure, or queueing?
### Safer alternatives
- Await the task normally.
- Queue work to an owned background component.
- In ASP.NET Core, prefer hosted services or a dedicated background queue pattern for long-lived work.
- If scoped services are required in background processing, create an explicit scope instead of capturing request scope objects.
## `ConfigureAwait`
### Strong recommendation
- In general-purpose libraries, use `ConfigureAwait(false)` unless the continuation must run in the captured context.
### Weak recommendation
- “Always use it in app code.”
- “Never use it on .NET Core.”
- “Use it once at the first await and you are done.”
### Review note
If code after the `await` needs a specific context, say so explicitly. If it does not, the recommendation depends on whether the code is app-level or general-purpose library code.
## Performance guidance
### Correctness first
Do not trade API clarity for speculative micro-optimizations.
### `ValueTask` is performance-specialized
Recommend it only when most of these are true:
1. the method is called very frequently
2. it often completes synchronously or from a reusable source
3. allocation reduction matters on measurements
4. consumers can respect single-consumer semantics
5. task combinator ergonomics are not central to the API
### Throttling and concurrency control
- `Task.WhenAll` expresses concurrency; it does not limit it.
- For bounded concurrency, use an async gate such as `SemaphoreSlim.WaitAsync`, or platform helpers such as `Parallel.ForEachAsync` when the workload fits.
- Always define what happens to remaining work after the first completion or first failure.

View file

@ -0,0 +1,105 @@
---
description: >-
Source-backed core guidance for task, valuetask, cancellation, exception flow,
blocking, and concurrency in c# async code reviews and implementations.
metadata:
tags: [csharp, async, task, valuetask, cancellation, exceptions, concurrency]
source: mixed
---
# Core Guidance
## Facts from official .NET documentation
### 1. Return types and `async void`
- Async methods should normally return `Task` or `Task<T>`.
- `async void` is intended for event handlers; callers cannot await it and exception handling differs.
- TAP methods that return awaitable types conventionally use the `Async` suffix.
### 2. Blocking on async
- `Task<T>.Result` is blocking. Prefer `await` in most cases.
- Blocking can deadlock in context-bound environments and reduces scalability even when it does not deadlock.
- `await` on a faulted task rethrows one exception directly; `.Wait()` and `.Result` wrap failures in `AggregateException`.
### 3. `Task` versus `ValueTask`
- Default to `Task` or `Task<T>` unless there is a demonstrated reason not to.
- `ValueTask` has stricter usage rules. A given instance should generally be awaited only once.
- Do not await the same `ValueTask` multiple times, call `AsTask()` multiple times, or mix consumption techniques on the same instance.
- For synchronously successful `Task`-returning methods, `Task.CompletedTask` is the normal zero-result completion value.
### 4. Cancellation
- If a TAP method supports cancellation, expose a `CancellationToken`.
- Pass the token to nested operations that should participate in cancellation.
- If an async method throws `OperationCanceledException` associated with the methods token, the returned task transitions to `Canceled`.
- After a method has completed its work successfully, do not report cancellation instead of success.
### 5. Exception flow and task combinators
- `Task.WhenAll` does not block the calling thread.
- If any supplied task faults, the `WhenAll` task faults and aggregates the unwrapped exceptions from the component tasks.
- If none fault and at least one is canceled, the `WhenAll` task is canceled.
- `Task.WhenAny` returns a task that completes successfully with the first completed task as its result, even when that winning task itself is faulted or canceled.
- After `WhenAny`, await the returned winner task to propagate its outcome.
- The remaining tasks continue unless you cancel or otherwise handle them.
## Expert guidance that is strong and technically grounded
### Stephen Toub
- Use `ConfigureAwait(false)` as the general default for general-purpose library code, because library code should not depend on an app models context.
- App-level code is different. UI code often needs the captured context. ASP.NET Core also changes the deadlock discussion because it does not install the classic ASP.NET style synchronization context, but that does not make blanket `ConfigureAwait` advice strong.
- `ValueTask<T>` exists mainly to avoid allocations on frequently synchronous success paths. It is not a general replacement for `Task<T>` because `Task` is more flexible for multiple awaits, caching, and combinators.
### Andrew Arnott
- Propagate the token until the point of no cancellation.
- Validate arguments before cancellation checks when argument validation should always run.
- Prefer catching `OperationCanceledException` rather than `TaskCanceledException` in general-purpose logic.
- Keep `CancellationToken` last in the parameter list; make it optional mainly on public APIs, not necessarily on internal methods.
### Stephen Cleary
- “Async all the way” is a strong design guideline, not an absolute law of physics. Sync bridges exist, but they are specialized boundary decisions, not a normal code review recommendation.
- `async void` and sync-over-async both create real observability and composition problems even when a sample appears to work.
## Naming and testability
### Naming
- TAP methods that return awaitable types conventionally use the `Async` suffix. Do not force renames when an interface, base class, or event pattern already dictates the name.
### Testability
- Favor awaitable APIs over hidden work so tests can await completion, assert faults, and drive cancellation deterministically.
- Prefer explicit background components, injected clocks, and owned queues over ad hoc fire-and-forget logic that tests cannot observe.
## Synthesis for agents
### Code review defaults
- Treat `.Result`, `.Wait()`, and `GetAwaiter().GetResult()` as likely defects unless the code is a deliberate sync boundary and the caller explicitly cannot be async.
- Prefer `Task`/`Task<T>` for API design. Require an explicit reason before recommending `ValueTask`.
- Require cancellation behavior to be coherent: accepted, propagated, and not silently dropped.
- Prefer `await Task.WhenAll(...)` for independent operations started before awaiting.
- Treat `Task.WhenAny(...)` as incomplete until the winner is awaited and losers are canceled, observed, or intentionally left running.
### Minimal examples
#### Avoid sync-over-async
```csharp
// bad
var user = client.GetUserAsync(id).Result;
// better
var user = await client.GetUserAsync(id);
```
#### Use `Task.WhenAll` for parallel I/O
```csharp
var userTask = repo.GetUserAsync(id, ct);
var ordersTask = repo.GetOrdersAsync(id, ct);
await Task.WhenAll(userTask, ordersTask);
return new Dashboard(await userTask, await ordersTask);
```
#### Be conservative with `ValueTask`
```csharp
// default
Task<Item?> GetAsync(string key, CancellationToken ct);
// specialized hot path only when justified
ValueTask<Item?> TryGetCachedAsync(string key);
```

View file

@ -0,0 +1,59 @@
---
description: >-
Authority notes and citations for the c# async best practices skill, separating
official documentation, expert interpretation, and synthesized guidance.
metadata:
tags: [sources, citations, authority, notes]
source: external
---
# Source Notes
## Official facts
- Microsoft Learn, "Implementing the Task-based Asynchronous Pattern"
- https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/implementing-the-task-based-asynchronous-pattern
- Return types, cancellation behavior, `Task.Run` boundaries, and TAP implementation guidance.
- Microsoft Learn, "Consuming the Task-based Asynchronous Pattern"
- https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/consuming-the-task-based-asynchronous-pattern
- `await`, `WhenAll`, `WhenAny`, cancellation propagation, and exception behavior.
- Microsoft Learn, "Async return types"
- https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/async-return-types
- `Task`, `Task<T>`, `async void`, generalized async return types.
- Microsoft Learn, `ValueTask` API reference
- https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask
- single-consumer warnings and default-to-`Task` guidance.
- Microsoft Learn, ASP.NET Core best practices
- https://learn.microsoft.com/en-us/aspnet/core/fundamentals/best-practices
- avoid blocking calls, avoid unnecessary `Task.Run`, background-work cautions.
- Microsoft Learn, hosted services in ASP.NET Core
- https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services
- safe long-lived background work and cancellation during shutdown.
## Expert guidance used only when technically grounded
- Stephen Toub, ".NET Blog: ConfigureAwait FAQ"
- https://devblogs.microsoft.com/dotnet/configureawait-faq/
- best source for context capture semantics and library-vs-app guidance.
- Stephen Toub, ".NET Blog: Understanding the Whys, Whats, and Whens of ValueTask"
- https://devblogs.microsoft.com/dotnet/understanding-the-whys-whats-and-whens-of-valuetask/
- performance rationale and tradeoffs behind `ValueTask<T>`.
- Stephen Toub, ".NET Blog: Await, and UI, and deadlocks! Oh my!"
- https://devblogs.microsoft.com/dotnet/await-and-ui-and-deadlocks-oh-my/
- canonical deadlock explanation for context-bound code.
- Stephen Toub, ".NET Blog: Task Exception Handling in .NET 4.5"
- https://devblogs.microsoft.com/dotnet/task-exception-handling-in-net-4-5/
- explains `await` versus blocking exception shape and why `WhenAll` matters.
- Andrew Arnott, "Recommended patterns for CancellationToken"
- https://devblogs.microsoft.com/premier-developer/recommended-patterns-for-cancellationtoken/
- practical cancellation design heuristics; useful, but not treated as a language/runtime spec.
- Stephen Cleary, "Async/Await - Best Practices in Asynchronous Programming"
- https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
- useful design interpretation, but older and treated as contextual guidance rather than current official policy.
## Where the skill is intentionally cautious
- `ConfigureAwait`: strong guidance exists for libraries, weaker guidance for app code. Blanket rules are rejected.
- `Task.Run`: valid for deliberate CPU offload, weak as a server-side patch for blocking I/O.
- `ValueTask`: supported and useful, but easy to misuse. The skill defaults to `Task` unless evidence is present.
- Fire-and-forget: acceptable only with explicit ownership and lifecycle design, especially in server code.

View file

@ -0,0 +1,342 @@
---
name: dotnet-performance-profiling-and-optimization
description: >-
Use when a .NET process is slow, hung, memory-heavy, or deadlocked, or when
analyzing C#/ASP.NET Core code for performance anti-patterns across memory,
async, LINQ, database, JSON, caching, DI, concurrency, HttpClient, exceptions,
response, strings, startup, and metrics.
metadata:
category: technique
triggers:
- dotnet-counters
- dotnet-trace
- dotnet-dump
- dotnet-gcdump
- dotnet-stack
- benchmarkdotnet
- allocations
- gc pressure
- memory leak
- hot path
- linq
- stackalloc
- span
- boxing
- heap
- latency
- throughput
- slow
- hang
- deadlock
- optimize
- performance
- async
- caching
- di lifetime
- ef core
- cosmosdb
- json serialization
- httpclient
- middleware
version: 1.1.0
platform: ".NET 8 and .NET 10 (no .NET 9 projects in scope)"
---
# .NET Performance: Diagnostic & Code Review
Unified C#/.NET performance skill targeting **.NET 8 and .NET 10**. Two modes: live process diagnostics (Mode A) and static code optimization review with fixes (Mode B).
## Step 0 — Detect the target framework
Before recommending APIs, follow `../../references/detect-target-framework.md`. Many .NET 9+ APIs (`HybridCache`, `MemoryExtensions.Split` for spans, `Dictionary.GetAlternateLookup`, `params ReadOnlySpan<T>`) do **not** exist on .NET 8 — the references below mark the floor for each pattern, and you must downgrade to the .NET 8 fallback when the target is `net8.0`. Stephen Toub's posts are the primary benchmark source:
[Performance Improvements in .NET 8](https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/) ·
[Performance Improvements in .NET 10](https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-10/).
## References
Load on demand:
- [references/memory-model-gc.md](references/memory-model-gc.md) — stack vs heap, generations, LOH, boxing, GC tuning
- [references/code-patterns.md](references/code-patterns.md) — LINQ, Span/Memory, stackalloc, structs, boxing, pooling, strings (conceptual framing)
- [references/categories.md](references/categories.md) — 14 optimization category definitions with checks and grep patterns (Mode B spine)
- [references/grep-patterns.md](references/grep-patterns.md) — consolidated anti-pattern grep library for Phase 1 scanning
- [references/measurement-guide.md](references/measurement-guide.md) — BenchmarkDotNet, k6, dotnet-counters, KPI targets, CI/CD
Pattern catalogs (with measured impact numbers, ❌/✅ pairs, and per-topic Detection recipes):
- [references/critical-patterns.md](references/critical-patterns.md) — 17 🔴 patterns: deadlocks, order-of-magnitude regressions, excessive allocations
- [references/async-patterns.md](references/async-patterns.md) — sync-over-async, ValueTask hot paths, Channels, false sharing
- [references/memory-and-strings.md](references/memory-and-strings.md) — `u8` literals, `Span.Split`/`TryWrite`, compound `+=`, chained `.Replace()`
- [references/collections-and-linq.md](references/collections-and-linq.md) — `FrozenDictionary`, `GetAlternateLookup`, `CollectionsMarshal.GetValueRefOrAddDefault`, hoisting static data
- [references/regex-patterns.md](references/regex-patterns.md) — `[GeneratedRegex]`, `IsMatch`, `EnumerateMatches`, `NonBacktracking`
- [references/io-and-serialization.md](references/io-and-serialization.md) — `HttpCompletionOption.ResponseHeadersRead`, `useAsync` `FileStream`, `Memory<byte>` overloads
- [references/structural-patterns.md](references/structural-patterns.md) — sealed-class devirtualization (absence pattern, scale-based severity)
Reference loading guide for Mode B by signal:
| Signal in Code | Load |
|---|---|
| `async`, `await`, `Task`, `ValueTask` | `async-patterns.md` |
| `Span<`, `Memory<`, `stackalloc`, `string.Substring`, `+=` in loops, `params` | `memory-and-strings.md` |
| `Regex`, `[GeneratedRegex]`, `Regex.Match`, `RegexOptions.Compiled` | `regex-patterns.md` |
| `Dictionary<`, `List<`, `.ToList()`, LINQ chains, `static readonly Dictionary<` | `collections-and-linq.md` |
| `JsonSerializer`, `HttpClient`, `Stream`, `FileStream` | `io-and-serialization.md` |
| Any code review on a hot path | always check `critical-patterns.md` first |
| Codebase-wide scans (sealed classes, static `Dictionary``FrozenDictionary`) | `structural-patterns.md` |
## Iron Rule
**Always measure first, change second, and re-measure third.**
Never claim an optimization without before/after evidence from the same scenario.
| Rationalization | Reality |
|---|---|
| "This is obviously slow" | The runtime, JIT, and libraries often invalidate intuition. |
| "struct means stack" | Value types are stored inline — not always on the stack. |
| "All LINQ is slow" | .NET 9+ improved many LINQ paths. Measure before rewriting. |
| "GC.Collect will fix it" | Forced collection treats symptoms, not cause. |
| "Too small to matter" | MEDIUM+ impact is cumulative across the request pipeline. |
| "I'll change the DI lifetime while I'm here" | DI lifetime changes require explicit user approval. |
| "Need to refactor to optimize" | Optimization fixes must be surgical. Refactoring is a separate task. |
| "Tests pass so fix is correct" | Tests passing = behavior preserved. Still verify the metric improved. |
## Mode Selection
| Situation | Mode |
|---|---|
| Live process: slow, high CPU/memory, hung, deadlocked, GC pauses | **A Diagnostic** |
| Asking how GC, heap, boxing, or LINQ overhead works in .NET | **A Diagnostic** (conceptual) |
| Code to analyze for anti-patterns, then fix | **B Code Review** |
| Both a running process AND code to fix | Start with **A**, then **B** on hot paths identified |
**Not for:** Visual Studio, Rider, PerfView, speedscope, or GUI-first workflows.
---
## Mode A: Diagnostic (Live Process)
### Investigation Order
1. **`dotnet-counters`** — always start here for live triage.
2. **`dotnet-stack`** — immediately if process is stuck, hung, or deadlocked.
3. **`dotnet-trace`** — if CPU or allocation hot paths matter.
4. **`dotnet-gcdump`** — if heap growth matters more than call paths.
5. **`dotnet-dump`** — if SOS heap inspection or postmortem analysis is needed.
6. After live evidence identifies a candidate routine, apply patterns from [references/code-patterns.md](references/code-patterns.md) and [references/memory-model-gc.md](references/memory-model-gc.md).
7. Use BenchmarkDotNet if the change is isolated and needs microbenchmark comparison.
8. Re-run the original live capture to prove the real workload improved.
### CLI Tool Selection
| Question | Tool | What it answers |
|---|---|---|
| Is the process allocating, GCing, or saturating CPU? | `dotnet-counters` | Live counters and trend direction |
| Is the process hung or deadlocked right now? | `dotnet-stack` | Current managed stack snapshot |
| Which call paths consume CPU or allocate heavily? | `dotnet-trace` | Sampled execution and runtime events |
| Which object types dominate managed heap? | `dotnet-gcdump` | Heap composition and type totals |
| Need SOS heap inspection or thread state? | `dotnet-dump` | Full dump plus CLI analysis |
| Did a code change improve an isolated routine? | BenchmarkDotNet | Reproducible microbenchmark comparison |
### Minimal CLI Commands
```bash
dotnet-counters monitor -p <PID> --counters System.Runtime
dotnet-counters monitor -n <ProcessName> --counters System.Runtime,Microsoft.AspNetCore.Hosting
dotnet-stack report -p <PID>
dotnet-trace collect -p <PID> --duration 00:00:30
dotnet-trace report <trace.nettrace> topN
dotnet-gcdump collect -p <PID>
dotnet-gcdump report <file.gcdump>
dotnet-dump collect -p <PID> --type Heap
dotnet-dump analyze <dump> -c "dumpheap -stat" -c "exit"
```
Minimal BenchmarkDotNet pattern:
```csharp
[MemoryDiagnoser]
[SimpleJob(RuntimeMoniker.Net90)]
public class CandidateBench
{
[Benchmark(Baseline = true)]
public int Original() => OriginalImpl();
[Benchmark]
public int Candidate() => CandidateImpl();
}
```
```bash
dotnet run -c Release
```
### Reference Loading Guide
| User question | Load first |
|---|---|
| "How do stack and heap really work in .NET?" | `references/memory-model-gc.md` |
| "Why is GC pausing or why is LOH churn hurting us?" | `references/memory-model-gc.md` |
| "How should I optimize this LINQ?" | `references/code-patterns.md` |
| "Can I move this to the stack with stackalloc or Span?" | `references/code-patterns.md` |
| "Should this be a struct, ref struct, readonly struct, or class?" | Both |
| "Why is this boxing?" | `references/code-patterns.md` |
### Diagnostic Output
Report: measured symptom + evidence (counter values, trace hotspots, heap stats) · chosen tool and why · relevant tradeoff (allocation vs copy, deferred vs eager, stack vs pool) · before/after result, or explicitly state if still unverified.
---
## Mode B: Code Review (Static Analysis)
### Target
`$ARGUMENTS` is the optimization target:
- **File path**: Analyze that file and its close dependencies.
- **Directory**: Analyze all C# files in that directory.
- **"all"**: Scan the solution with Grep, deep-dive the worst offenders.
- **`--fix`** anywhere: Skip confirmation and apply fixes after analysis.
- **Empty**: Check `git diff --name-only HEAD~5 -- '*.cs'` for recently changed files. If none, ask the user.
### Phase 1: Discovery
1. **Glob** to find `.cs` files matching the target.
2. **Read** file contents. For files under 500 lines, read the whole file first — visual inspection catches patterns faster than grep, then grep confirms counts.
3. **Detect signals** in the code (async, Span, Regex, Dictionary, JsonSerializer, etc.) and **load matching pattern catalogs** from the per-topic references listed at the top of this file.
4. **Grep** for anti-patterns. Run the recipes in [references/grep-patterns.md](references/grep-patterns.md) plus the per-topic Detection sections in the catalogs you loaded.
5. **Emit a scan execution checklist** before classifying — list each recipe and the hit count. **0 hits is valid and valuable** (confirms good practice).
### Phase 2: Analysis (Read-Only)
Check each file against all 14 categories. Record per finding: **file path, line number, current pattern, recommended pattern, impact level, category**.
Read [references/categories.md](references/categories.md) for detailed check definitions.
#### Compound Allocation Check
Single-line grep recipes miss multi-allocation patterns. After running scan recipes, look for:
1. **Branched `.Replace()` chains** — methods that call `.Replace()` across multiple `if/else` branches. Report total allocation count across all branches, not just per-line.
2. **Cross-method chaining** — public method A calls B (which does 3 regex replaces) then calls C (which allocates). Report the total chain cost as one finding, not per-method.
3. **Compound `+=` with embedded allocating calls**`result += $"...{Foo().ToLower()}"` is 2+ allocations (interpolation + `ToLower` + concatenation). Flag the compound cost, not just `.ToLower()`.
4. **`string.Format` specificity** — distinguish resource-loaded format strings (not fixable) from compile-time literal format strings (fixable with interpolation). Enumerate only the actionable sites.
#### Cross-File Consistency Check
If an optimized pattern is found in one file, check whether sibling files (same directory, same interface, same base class) use the un-optimized equivalent. Flag as MEDIUM with the optimized file as evidence.
#### Verify-the-Inverse Rule
For absence patterns (e.g., unsealed classes, static `Dictionary` not converted to `FrozenDictionary`, `RegexOptions.Compiled` not migrated to `[GeneratedRegex]`), always count both sides and report the **N-of-M ratio**, not just the count of bad cases. The ratio determines severity:
- 0/185 sealed → systematic codebase-wide issue
- 12/15 sealed → consistency fix on the remaining 3
- 50/100 sealed → mid-migration; flag the laggards
| # | Category | Code | Focus |
|---|---|---|---|
| 1 | Memory Allocation | MEM | Span, ArrayPool, pooling, stackalloc, string optimization, collections |
| 2 | Async Anti-Patterns | ASYNC | Blocking, ValueTask, CancellationToken, IAsyncEnumerable, Channel |
| 3 | LINQ Inefficiencies | LINQ | Count vs Any, multiple enumeration, filter/project order |
| 4 | Database | DB | EF Core, CosmosDB patterns, N+1, partition keys, RU cost |
| 5 | JSON Serialization | JSON | Options reuse, source generators, serializer boundaries |
| 6 | Caching | CACHE | HybridCache, stampede protection, output cache, size limits |
| 7 | DI Lifetimes | DI | Captive dependencies, lifetime mismatches, IOptions patterns |
| 8 | Concurrency | CONC | Lock contention, throttling, thread safety, Channel patterns |
| 9 | HttpClient | HTTP | IHttpClientFactory, resilience, response disposal |
| 10 | Exception Control Flow | EXC | Try/catch for expected paths, broad catches |
| 11 | Response Optimization | RESP | Compression, pagination, ETags |
| 12 | String Optimization | STR | Concatenation loops, ToLower/ToUpper, String.Format |
| 13 | Startup & Pipeline | STARTUP | Middleware ordering, compression, health checks, PGO |
| 14 | Metrics & Observability | METRICS | IMeterFactory, histograms, tag cardinality, OpenTelemetry |
### Phase 3: Report
```
## Performance Analysis Report
### Summary
- Files analyzed: N
- Total findings: N
- Critical (HIGH): N | Moderate (MEDIUM): N | Minor (LOW): N
### Findings by Category
#### [CATEGORY_NAME] (N findings)
| # | Impact | File:Line | Issue | Recommendation |
|---|--------|-----------|-------|----------------|
| 1 | HIGH | `path/File.cs:42` | Current anti-pattern | Recommended fix |
### Prioritized Action List
1. [HIGH] Fix blocking async calls in X — thread pool starvation risk
2. [MEDIUM] Switch to ArrayPool in Z — reduces GC pressure on upload path
```
**Impact levels:**
- **HIGH**: Measurable gain, prevents starvation, fixes correctness, reduces P95 latency. Examples: blocking async, missing CancellationToken, N+1 queries, captive dependencies.
- **MEDIUM**: Reduces allocations, GC pressure, or unnecessary work. Examples: ArrayPool, StringBuilder, FrozenDictionary.
- **LOW**: Minor improvements, cold-path optimizations. Examples: initial collection capacity, Count() vs Any().
**Scale-based severity escalation.** When the same anti-pattern appears across many instances, escalate:
- 110 instances → report at the pattern's base severity
- 1150 instances → escalate LOW patterns to MEDIUM
- 50+ instances → MEDIUM with elevated priority; flag as a codebase-wide systematic issue
Always report **exact counts from scan recipes**, not estimates. Group findings by severity (HIGH → MEDIUM → LOW), not by file. Merge related findings that share the same fix (e.g., all `.ToLower()` calls in one finding, not split per file).
### Phase 4: Optimization (Apply Fixes)
After presenting the report:
- If `--fix` in `$ARGUMENTS`, proceed directly.
- Otherwise ask: "Would you like me to apply these optimizations? I'll work one category at a time, starting with HIGH impact. You can specify categories or findings (e.g., 'fix ASYNC and MEM' or 'fix #1, #3')."
**Before any fix:**
1. **Read actual code context** around the grep match — false positives exist (`.Result` in `Task.FromResult` is NOT blocking).
2. Confirm the finding is real. If uncertain, flag as "needs manual review."
**Applying fixes:**
1. One category at a time, highest impact first. Use Edit tool with brief before/after summary.
2. After each category: `dotnet build --no-restore`
3. After all changes: `dotnet test`
4. If build or tests fail, diagnose before continuing.
---
## Analyzer Radar
- `CA1826`, `CA1827`, `CA1829`, `CA1836`, `CA1851`, `CA1860` — LINQ and enumeration
- `CA1845`, `CA1846`, `CA1858` — string and span-friendly APIs
- `CA1834`, `CA1865``CA1867` — StringBuilder char overloads
- `CA1870` — cached `SearchValues<T>`
These are clues, not goals. Apply where measured hot paths justify it.
## Pattern Guardrails
- Do not say "put it on the stack" as a blanket goal. Explain lifetime, copies, boxing, and escape rules.
- Do not suggest `stackalloc` for unbounded sizes, large buffers, or loop-carried allocations.
- Do not recommend `Span<T>` for data that crosses `await`, escapes to the heap, or lives in object fields — use `Memory<T>`.
- Do not recommend converting every `class` to a `struct` — large, mutable, or frequently boxed types often get worse.
- Do not blanket-rewrite LINQ to loops — use analyzer-backed fixes first.
- Do not recommend pooling without ownership rules — returned pooled arrays must not be reused by the caller.
- Do not recommend `GC.Collect()` except for rare justified lifecycle boundaries with measurement.
## Red Flags — STOP and Confirm
Stop and ask before:
- Changing `Program.cs` or the middleware pipeline
- Adding a new NuGet package
- Changing any DI service lifetime registration
- Replacing the serializer in the HTTP pipeline
- Modifying API response shapes or route patterns
- Changing error handling patterns
## Constraints
- NEVER add NuGet packages without user approval
- NEVER change DI lifetimes without explaining implications and getting confirmation
- NEVER modify `Program.cs` or middleware pipeline without explicit approval
- NEVER change API contracts, route patterns, or response shapes
- ALWAYS preserve existing tests; update only if behavior intentionally changes
- ALWAYS use the Grep tool for searches, never bash `grep` or `find`
Consult the project's CLAUDE.md or AGENTS.md for project-specific rules and constraints.

View file

@ -0,0 +1,112 @@
# Async & Concurrency Patterns
### Don't Expose Async Wrappers for Sync Methods
🟡 **AVOID** wrapping sync methods with `Task.Run` in libraries | .NET Core+
```csharp
public Task<int> ComputeHashAsync(byte[] data) =>
Task.Run(() => ComputeHash(data));
```
```csharp
public int ComputeHash(byte[] data) { /* CPU-bound work */ }
// Consumer decides: var hash = await Task.Run(() => lib.ComputeHash(data));
```
**Impact: Eliminates unnecessary thread pool queue/dequeue overhead per call.**
### Don't Expose Sync Wrappers for Async Methods
🟡 **AVOID** creating sync wrappers that block on async implementations | .NET Core+
```csharp
public string GetData() => GetDataAsync().Result;
```
```csharp
public async Task<string> GetDataAsync() { /* ... */ }
```
**Impact: Prevents deadlocks and thread pool starvation from hidden sync-over-async blocking.**
### Use ValueTask for Hot Paths with Frequent Sync Completion
🟡 **DO** use `ValueTask<T>` on hot paths where sync completion is common | .NET Core 2.1+
```csharp
public async Task<int> ReadAsync(Memory<byte> buffer)
{
if (_bufferedCount > 0)
return ReadFromBuffer(buffer.Span);
return await ReadAsyncCore(buffer);
}
```
```csharp
public ValueTask<int> ReadAsync(Memory<byte> buffer)
{
if (_bufferedCount > 0)
return new ValueTask<int>(ReadFromBuffer(buffer.Span));
return new ValueTask<int>(ReadAsyncCore(buffer));
}
```
**Impact: Eliminates Task\<T\> allocation on synchronous completion — the struct stores results inline.**
### Use Channels for Producer/Consumer
🟡 **DO** use `System.Threading.Channels` for producer-consumer patterns | .NET Core 3.0+
```csharp
var queue = new BlockingCollection<WorkItem>();
var item = queue.Take();
```
```csharp
var channel = Channel.CreateUnbounded<WorkItem>();
// Producer
await channel.Writer.WriteAsync(item);
// Consumer
await foreach (var item in channel.Reader.ReadAllAsync())
Process(item);
```
**Impact: ~25% faster, ~95% fewer GC collections vs manual approaches.**
### Avoid False Sharing with Thread-Local State
🟡 **AVOID** adjacent mutable fields written by different threads | .NET 7+
```csharp
class SharedCounters
{
public long Counter1;
public long Counter2;
}
```
```csharp
[StructLayout(LayoutKind.Explicit, Size = 128)]
struct PaddedCounter
{
[FieldOffset(0)] public long Value;
}
```
**Impact: Eliminates cross-core cache invalidation — can improve multi-threaded throughput by 10x+.**
## Detection
Scan recipes for async anti-patterns. Run these and report exact counts.
```bash
# async void methods (correctness issue — crashes on exception)
grep -rn --include='*.cs' 'async void' --exclude-dir=bin --exclude-dir=obj . | grep -v 'event' | wc -l
```
### Patterns Requiring Manual Review
- **Sync-over-async** (`.Result`, `.Wait()`): `.Result` matches any property named Result — needs type context to confirm it's `Task.Result`

View file

@ -0,0 +1,297 @@
# Optimization Category Definitions
Complete check definitions for all 14 optimization categories. Each category lists specific checks to perform, with grep patterns at the end for automated scanning.
---
## Category 1: Memory Allocation (MEM)
Checks:
- **Unnecessary string allocations**: `Substring()` calls that could use `Span<char>` or `AsSpan()`. String concatenation with `+` inside loops (should use `StringBuilder` or `string.Create`).
- **Missing ArrayPool/MemoryPool usage**: `new byte[...]` for temporary buffers, especially in I/O paths. Should use `ArrayPool<byte>.Shared.Rent()` with try/finally Return.
- **Large Object Heap triggers**: Allocations of objects >= 85,000 bytes (arrays, large strings, `MemoryStream` without `RecyclableMemoryStream`).
- **Missing object pooling**: Frequently created/disposed objects (like `StringBuilder`) that could use `ObjectPool<T>`.
- **Record class vs record struct**: Small, immutable DTOs that are `record class` but could be `readonly record struct` to avoid heap allocation.
- **Boxing**: Value types cast to `object` or non-generic interfaces. Structs without `IEquatable<T>`.
- **Collection inefficiencies**: `new List<T>()` or `new Dictionary<K,V>()` without initial capacity when size is known or estimable. Double-lookup patterns (`TryGetValue` + indexer set) that could use `CollectionsMarshal.GetValueRefOrAddDefault`. Read-only dictionaries populated once that could be `FrozenDictionary<K,V>` (.NET 8+).
- **stackalloc for small buffers**: Flag `new byte[N]` where N <= 256 in synchronous methods. Recommend `Span<byte> buffer = stackalloc byte[N]` for short-lived stack allocation with zero GC pressure.
- **string.Create for pre-sized construction**: When output string length is known at call time, `string.Create(length, state, action)` avoids intermediate allocations by writing directly into the final buffer.
- **Interpolated strings in logging** *(Impact: LOW — only matters when the log level is inactive at runtime)*: `_logger.LogXxx($"...")` allocates the interpolated string even when the log level is disabled. Use structured logging parameters `_logger.LogXxx("Message {Param}", value)` or the `[LoggerMessage]` source generator for high-frequency hot paths.
- **ReadOnlySpan for string parsing**: Flag `.Split()` and `.Substring()` in hot paths where `AsSpan()` slicing avoids allocation. Common in string parsing, normalization, and URL handling.
- **CollectionsMarshal.GetValueRefOrAddDefault**: Flag the TryGetValue + indexer set double-lookup pattern. Single-lookup alternative reduces dictionary operations by 50%.
- **RecyclableMemoryStream**: Flag `new MemoryStream()` in I/O-heavy paths (blob upload/download, log writes). `Microsoft.IO.RecyclableMemoryStream` pools internal buffers and avoids LOH fragmentation.
Grep patterns:
```
\.Substring\(
new byte\[
new MemoryStream\(\)
new StringBuilder\(\)
new List<.*>\(\)
new Dictionary<.*>\(\)
_logger\.Log(Debug|Trace|Information|Warning|Error|Critical)\(\$"
\.Split\(
```
---
## Category 2: Async Anti-Patterns (ASYNC)
Checks:
- **Blocking async calls**: `.Result`, `.Wait()`, `.GetAwaiter().GetResult()` -- causes thread pool starvation. CRITICAL finding.
- **async void**: Methods declared `async void` (except event handlers) -- swallows exceptions and cannot be awaited.
- **Missing CancellationToken**: Async methods that do not accept or propagate `CancellationToken`. Every async method should have `CancellationToken cancellationToken = default`.
- **Missing ValueTask**: Methods that frequently return cached/synchronous results but use `Task<T>` instead of `ValueTask<T>`. Look for `if (cache.TryGetValue(...)) return Task.FromResult(...)`. Benchmark data: ValueTask 7.41ns/0B vs Task 15.23ns/72B.
- **Sequential awaits that could parallelize**: Multiple independent `await` calls in sequence that could use `Task.WhenAll`.
- **Async over sync**: Methods that use `Task.Run` to wrap synchronous code in an ASP.NET Core context (unnecessary and wastes a thread).
- **ConfigureAwait(false) in library projects**: LOW/INFO level. Not required in ASP.NET Core (no sync context), but recommended if library assemblies may be reused outside ASP.NET Core.
- **IAsyncEnumerable opportunities**: Methods returning `Task<List<T>>` where the caller iterates sequentially. If the caller processes items one-by-one, `IAsyncEnumerable<T>` reduces memory and improves time-to-first-byte.
- **Channel verification**: Verify `BoundedChannelOptions` has `SingleReader`/`SingleWriter` hints set for performance. Verify `CancellationToken` is propagated on `WriteAsync` and `ReadAllAsync`.
Grep patterns:
```
\.Result[^s]
\.Wait\(\)
\.GetAwaiter\(\)\.GetResult\(\)
async void
Task\.Run\(
\.WriteAsync\([^,]*\)
```
---
## Category 3: LINQ Inefficiencies (LINQ)
Checks:
- **Count() > 0 or Count() == 0**: Should use `Any()` or `!Any()`. `Count()` may enumerate the entire collection.
- **Multiple enumeration**: An `IEnumerable<T>` variable used more than once without materializing.
- **Filter after projection**: `.Select(...).Where(...)` -- should filter first, then project.
- **ToList() too early**: `.ToList().Where(...)` or `.ToList().Select(...)` -- materializes before filtering.
- **OrderBy before Where**: Sorting the full collection before filtering it down.
Grep patterns:
```
\.Count\(\) [><=!]
\.ToList\(\)\.Where\(
\.ToList\(\)\.Select\(
\.Select\(.*\)\.Where\(
\.OrderBy.*\.Where\(
```
---
## Category 4: Database (DB)
Check for both EF Core and CosmosDB patterns depending on what the project uses. Consult the project's CLAUDE.md or AGENTS.md for the data access strategy.
Checks:
- **N+1 queries**: Loops that call the database inside each iteration.
- **Missing AsNoTracking**: EF Core read-only queries without `.AsNoTracking()`.
- **Missing compiled queries**: Frequently executed EF Core queries on hot paths without `EF.CompileAsyncQuery`.
- **Full entity loading**: Fetching entire entities when only a few fields are needed (should project to DTOs).
- **Missing AsSplitQuery**: EF Core queries with multiple `.Include()` calls without `.AsSplitQuery()`.
- **CosmosDB partition key misuse**: Operations not specifying the partition key, or using cross-partition queries unnecessarily.
- **CosmosDB point reads**: Using queries instead of `ReadItemAsync` when both `id` and partition key are known.
- **RU cost awareness**: Flag discarded `ItemResponse<T>` without logging `RequestCharge`. Recommend tracking RU cost via metrics for cost visibility.
- **Cross-partition query detection**: `GetItemLinqQueryable()` without partition key option leads to fan-out queries. Verify all LINQ queryables specify the partition key.
- **Indexing policy review**: Flag if queries filter on fields that likely lack composite indexes.
- **Redundant round-trips**: Flag patterns where a query fetches an ID, then a separate point read fetches the full document. Recommend a single query.
- **EnableContentResponseOnWrite = false**: On write operations where the response body is not needed, setting this option reduces RU cost.
Grep patterns:
```
\.Include\(.*\.Include\(
await.*foreach.*await.*Async
ReadItemAsync
GetItemQueryIterator
GetItemLinqQueryable
\.RequestCharge
```
---
## Category 5: JSON Serialization (JSON)
Checks:
- **New JsonSerializerOptions per call**: `new JsonSerializerOptions { ... }` inside method bodies -- rebuilds the metadata cache every time. Should use a static readonly instance.
- **Missing source generators**: High-throughput serialization paths without `[JsonSerializable]` source generation context.
- **Newtonsoft.Json in hot paths**: If the project uses Newtonsoft.Json for MVC, flag any hot-path internal serialization that could benefit from `System.Text.Json` with source generators. NEVER suggest replacing the controller/DTO serializer without checking the project's documented constraints.
- **System.Text.Json source generators for internal serialization**: Internal paths (database serialization, audit logs, blob metadata) that don't affect API contracts are candidates for `System.Text.Json` with source generators.
- **JsonSerializerSettings singleton**: Flag `new JsonSerializerSettings()` in method bodies. The contract resolver cache is rebuilt each time. Use a static readonly instance or inject via DI.
- **CosmosDB SDK serializer**: The Cosmos SDK supports custom serializers. `CosmosSystemTextJsonSerializer` with source generators reduces allocation on read/write operations.
Grep patterns:
```
new JsonSerializerOptions
JsonConvert\.Serialize
JsonConvert\.Deserialize
new JsonSerializer
new JsonSerializerSettings
```
---
## Category 6: Caching (CACHE)
Checks:
- **Repeated expensive calls without caching**: Service methods that call external APIs on every request without caching the result.
- **Missing HybridCache pattern**: Look for manual cache-aside patterns that could use `HybridCache` for built-in stampede protection, two-level caching (L1 memory + L2 distributed), and tag invalidation. **HybridCache requires .NET 10 (or .NET 9) — the `Microsoft.Extensions.Caching.Hybrid` package does not target .NET 8.** On .NET 8 implement `IMemoryCache` (L1) + `IDistributedCache` (L2) manually with a `SemaphoreSlim` keyed by cache key for stampede protection. See [HybridCache GA announcement](https://devblogs.microsoft.com/dotnet/hybrid-cache-is-now-ga/).
- **Static data fetched repeatedly**: Configuration, taxonomies, or lookup data fetched from external APIs that rarely changes.
- **Missing output caching**: Read-only GET endpoints that return the same data for all callers -- candidates for `[OutputCache]`.
- **HybridCache upgrade path (.NET 10 only)**: Manual L1+L2 caching with `SemaphoreSlim` stampede protection can migrate to `HybridCache` `GetOrCreateAsync` with built-in stampede protection and tag invalidation **when the project target is `net10.0`**. On `net8.0` the manual pattern is the correct end state, not a stepping stone.
- **Cache stampede detection**: Cache-aside without locking -- `TryGetValue` followed by expensive call followed by `Set` without `SemaphoreSlim` or equivalent stampede guard.
- **Tag-based invalidation with RemoveByTagAsync**: When using HybridCache, group related entries by tag for efficient bulk invalidation instead of tracking individual keys.
- **IMemoryCache size limits**: Flag `AddMemoryCache()` without `SizeLimit` in `MemoryCacheOptions`. Unbounded in-memory cache can grow until the process runs out of memory.
Grep patterns:
```
GetAsync\(
SendAsync\(
_cache\.TryGetValue
DistributedCache
AddMemoryCache\(\)
```
---
## Category 7: DI Lifetime Issues (DI)
Consult the project's CLAUDE.md or AGENTS.md for the expected DI lifetime registrations.
Checks:
- **Transient services that should be Singleton**: Stateless, thread-safe services registered as Transient that have no per-request state (could be Singleton for zero allocation).
- **Scoped injected into Singleton**: A Scoped service captured in a Singleton constructor -- captive dependency bug.
- **IOptions vs IOptionsMonitor vs IOptionsSnapshot**: `IOptions<T>` in Singleton services that need to react to config changes should use `IOptionsMonitor<T>`. `IOptionsSnapshot<T>` in Singleton is a captive dependency.
---
## Category 8: Concurrency Issues (CONC)
Checks:
- **Lock contention**: `lock` statements that guard async operations (should use `SemaphoreSlim`).
- **Missing throttling**: Unbounded parallel calls to external APIs without `SemaphoreSlim` or concurrency limits.
- **Thread-unsafe patterns**: Shared mutable state without synchronization. `HttpContext` accessed from background threads.
- **Channel usage patterns**: If the project uses `Channel<T>` for background tasks, verify `SingleReader`/`SingleWriter` hints are set correctly for performance.
Grep patterns:
```
lock\s*\(
new SemaphoreSlim
HttpContext.*Task\.Run
```
---
## Category 9: HttpClient Misuse (HTTP)
Checks:
- **new HttpClient()**: Direct instantiation instead of `IHttpClientFactory`. Causes socket exhaustion and DNS caching issues.
- **Missing resilience**: HTTP calls without retry/circuit-breaker policies. Verify `Microsoft.Extensions.Http.Resilience` or Polly is applied to external API clients.
- **Missing response disposal**: `HttpResponseMessage` not disposed after reading.
Grep patterns:
```
new HttpClient\(
new HttpClient\b
```
---
## Category 10: Exception-Driven Control Flow (EXC)
Checks:
- **Try/catch for expected paths**: Using exceptions for normal control flow (e.g., catching `KeyNotFoundException` instead of `TryGetValue`, catching `FormatException` instead of `TryParse`).
- **Broad catch blocks**: `catch (Exception)` that swallow errors or use exceptions as branching logic.
- **Exception allocation in hot paths**: Throwing exceptions on paths that execute frequently.
Grep patterns:
```
catch\s*\(Exception\b
catch\s*\(KeyNotFoundException
catch\s*\(FormatException
catch\s*\(InvalidOperationException
```
---
## Category 11: Response Optimization (RESP)
Checks:
- **Missing compression**: No response compression middleware, or JSON responses served uncompressed.
- **Missing pagination**: Endpoints returning unbounded collections.
- **Missing ETags for conditional requests**: GET endpoints without ETag support where the data has a natural version (e.g., database ETags or row versions).
---
## Category 12: String Optimization (STR)
Checks:
- **String concatenation in loops**: `+=` on strings inside `for`/`foreach`/`while` loops.
- **String.Format in hot paths**: Could use interpolated string handlers or `StringBuilder`.
- **Repeated string operations**: Multiple `ToLower()`/`ToUpper()` calls on the same value. Should use `StringComparison.OrdinalIgnoreCase` instead.
Grep patterns:
```
\+= "
\+= \$"
\.ToLower\(\)
\.ToUpper\(\)
String\.Format\(
```
---
## Category 13: Startup & Pipeline Optimization (STARTUP)
Checks:
- **Middleware ordering**: Verify Program.cs follows the recommended sequence: ExceptionHandler, ResponseCompression, OutputCache, Routing, RateLimiter, CORS, Authentication, Authorization, MapControllers. Incorrect ordering degrades performance (e.g., compression after routing skips static responses).
- **Response compression**: Flag missing `AddResponseCompression`/`UseResponseCompression`. Without it, all JSON responses are uncompressed. Recommend Brotli (optimal ratio) + GZip (compatibility) providers with `EnableForHttps = true`.
- **Health check optimization**: `.ShortCircuit()` (.NET 8+) bypasses the entire middleware pipeline for health endpoints. `.DisableHttpMetrics()` prevents health check traffic from skewing request duration metrics.
- **PGO/ReadyToRun**: Check .csproj for `<TieredPGO>true</TieredPGO>` (dynamic PGO for runtime hot-path optimization) and `<PublishReadyToRun>true</PublishReadyToRun>` (pre-compiled code for faster startup). Both should be present for production builds.
- **Warm-up pattern**: `ApplicationStarted` callback to warm expensive singletons (database connections, cache, external API health). Cold-start latency without warm-up can spike P99 for the first requests after deployment.
Grep patterns:
```
UseResponseCompression
AddResponseCompression
ShortCircuit
AddOutputCache
UseOutputCache
TieredPGO
PublishReadyToRun
ApplicationStarted
```
---
## Category 14: Metrics & Observability (METRICS)
Checks:
- **IMeterFactory vs static new Meter()**: Services should inject `IMeterFactory` from DI rather than using `new Meter(...)`. `IMeterFactory` enables testability with `MetricCollector<T>` and proper meter lifecycle management.
- **Missing histograms**: If the project only has `Counter<long>` instruments, recommend `Histogram<double>` for request processing duration, external API latency, and database query duration. Histograms enable percentile analysis (P50/P95/P99).
- **Tag cardinality**: Verify metric tags have bounded cardinality. NEVER use request IDs, user IDs, or unbounded strings as metric tags. Tags like `operation_name`, `status_code`, `endpoint` are acceptable (bounded). Unbounded tags cause metric explosion and memory issues.
- **OpenTelemetry AddMeter() registration**: Verify custom meter names are registered with `.AddMeter("YourMeterName")` in the OpenTelemetry metrics configuration. Without this, custom counters are silently dropped.
Grep patterns:
```
new Meter\(
CreateCounter
CreateHistogram
AddMeter
\.Record\(
\.Add\(
```

View file

@ -0,0 +1,384 @@
---
description: Code-level performance patterns for csharp-dotnet-cli-optimization.
metadata:
tags: [linq, span, stackalloc, boxing, pooling, strings, analyzers]
---
# Code Patterns
> **See also:** for pattern-by-pattern detection recipes with measured impact numbers and ❌/✅ pairs, see the topic catalogs: [critical-patterns.md](critical-patterns.md), [async-patterns.md](async-patterns.md), [memory-and-strings.md](memory-and-strings.md), [collections-and-linq.md](collections-and-linq.md), [regex-patterns.md](regex-patterns.md), [io-and-serialization.md](io-and-serialization.md), [structural-patterns.md](structural-patterns.md). This file covers the conceptual framing (when/why), those files cover the catalog (what/how-much).
Use this reference after a profile or benchmark identifies a hot path. Do not apply these patterns speculatively.
## Table Of Contents
- [LINQ And Enumeration](#linq-and-enumeration)
- [Stack Allocation, Span, And Memory](#stack-allocation-span-and-memory)
- [Structs, Boxing, And Copies](#structs-boxing-and-copies)
- [Buffer Reuse And Advanced Helpers](#buffer-reuse-and-advanced-helpers)
- [Strings](#strings)
- [What Not To Suggest](#what-not-to-suggest)
## LINQ And Enumeration
### Property or indexer over LINQ when the concrete collection is known
Wrong:
```csharp
if (items.Count() > 0)
{
return items.First();
}
```
Better:
```csharp
if (items.Count > 0)
{
return items[0];
}
```
Use `Count`, `Length`, `IsEmpty`, or an indexer when you already have a concrete collection with that API. Relevant analyzers: `CA1826`, `CA1829`, `CA1836`, `CA1860`.
### `Any()` over `Count() > 0` when all you know is `IEnumerable<T>`
Wrong:
```csharp
if (source.Count() != 0)
{
Process(source);
}
```
Better:
```csharp
if (source.Any())
{
Process(source);
}
```
Relevant analyzer: `CA1827`.
### Avoid multiple enumeration of deferred queries
Wrong:
```csharp
var query = source.Where(Filter);
return query.Count() + query.Last().Id;
```
Better:
```csharp
var materialized = source.Where(Filter).ToArray();
return materialized.Length + materialized[^1].Id;
```
Materialize once only when you truly need multiple passes or random access and can afford the extra memory. Relevant analyzer: `CA1851`.
### Avoid premature materialization
Wrong:
```csharp
var projected = source.ToList().Select(Map);
```
Better:
```csharp
var projected = source.Select(Map);
```
Keep deferred execution unless you need a snapshot, repeated traversal, indexing, or a boundary between expensive stages.
### Do not blanket-rewrite LINQ to loops
- .NET 10 improved many LINQ operations substantially through JIT array-interface devirtualisation — operations like `Skip`/`Take`/`Sum` on arrays and `ReadOnlyCollection<T>` got roughly 50% faster *for free*. See Stephen Toub, [Performance Improvements in .NET 10](https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-10/).
- On `net8.0` LINQ has the historical performance characteristics described in [Performance Improvements in .NET 8](https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/) — fast paths exist for `Count`, `ToList`, `ToArray` on `ICollection<T>`, but indexed access via `ElementAt`/`Skip`/`Take` is not as cheap as on .NET 10.
- Start with analyzer-backed fixes and measurement.
- Replace LINQ with hand-written loops only when a benchmark or trace shows that the remaining cost matters — on either target.
### Use `TryGetNonEnumeratedCount` when count is optional
```csharp
if (source.TryGetNonEnumeratedCount(out int count))
{
LogCount(count);
}
```
This avoids forcing enumeration when the underlying type already knows its size.
## Stack Allocation, Span, And Memory
### `stackalloc` only for small, bounded, temporary buffers
Wrong:
```csharp
for (int i = 0; i < items.Length; i++)
{
Span<byte> buffer = stackalloc byte[4096];
Use(buffer);
}
```
Better:
```csharp
Span<byte> buffer = stackalloc byte[256];
for (int i = 0; i < items.Length; i++)
{
buffer.Clear();
Use(buffer);
}
```
Guidance:
- keep sizes conservative
- avoid `stackalloc` inside loops
- initialize the memory before use
- fall back to heap or pooling for larger or variable-sized buffers
### Prefer span-based APIs over substring copies
Wrong:
```csharp
int.TryParse(line.Substring(7), out int value);
```
Better:
```csharp
int.TryParse(line.AsSpan(7), out int value);
```
Relevant analyzers: `CA1845`, `CA1846`.
### Use `Span<T>` for sync work and `Memory<T>` for async or heap-stored state
Wrong:
```csharp
// Wrong: Span<T> cannot cross await safely.
public async Task<int> ReadAsync(Span<byte> buffer)
{
await socket.ReceiveAsync(buffer);
return buffer[0];
}
```
Better:
```csharp
public async Task<int> ReadAsync(Memory<byte> buffer)
{
await socket.ReceiveAsync(buffer);
return buffer.Span[0];
}
```
`Span<T>` is stack-only. If the lifetime crosses `await`, callbacks, or object storage, move to `Memory<T>`.
### `ref struct` is for stack-bound wrappers, not a general optimization badge
- Use `ref struct` when the type itself contains spans or must never escape to the heap.
- Do not use it if you need arrays of that type, boxing, interface conversions, or heap fields.
## Structs, Boxing, And Copies
### Use `readonly struct` or `readonly record struct` for small immutable values
Wrong:
```csharp
public struct Measurement
{
public double A;
public double B;
public void Normalize() => A /= B;
}
```
Better:
```csharp
public readonly record struct Measurement(double A, double B);
```
Prefer value types for small, copyable, data-only values. Avoid large, mutable structs.
### Pass large structs by `in`
Wrong:
```csharp
double Distance(Vector4 value) => value.X + value.Y + value.Z + value.W;
```
Better:
```csharp
double Distance(in Vector4 value) => value.X + value.Y + value.Z + value.W;
```
This avoids copying large struct values on each call.
### Avoid boxing in hot paths
Wrong:
```csharp
object boxed = valueStruct;
```
Wrong:
```csharp
IFormattable f = valueStruct;
```
Better:
```csharp
Use(in valueStruct);
```
Boxing allocates a heap object and copies the value. Interface conversions can box too.
### Mark readonly members on structs
- Non-readonly instance members on a readonly receiver can trigger defensive copies.
- Mark the whole struct `readonly` when possible, or mark readonly members explicitly.
## Buffer Reuse And Advanced Helpers
### Use `ArrayPool<T>` when the buffer is too large or variable for `stackalloc`
Wrong:
```csharp
byte[] temp = new byte[inputLength];
```
Better:
```csharp
byte[] temp = ArrayPool<byte>.Shared.Rent(inputLength);
try
{
Use(temp);
}
finally
{
ArrayPool<byte>.Shared.Return(temp);
}
```
Rules:
- return to the same pool once
- never use the buffer after return
- rented arrays may be larger than requested
- rented arrays are not guaranteed to be zeroed
### Prevent accidental closure capture
Wrong:
```csharp
return values.Select(v => v * 2).ToArray();
```
Better when no capture is needed:
```csharp
return values.Select(static v => v * 2).ToArray();
```
Use `static` lambdas or static local functions to prevent capture when the delegate does not need outer state.
### Cache `SearchValues<T>` for repeated searches
Wrong:
```csharp
int index = text.IndexOfAny(":/?&=".AsSpan());
```
Better:
```csharp
private static readonly SearchValues<char> s_delims =
SearchValues.Create(":/?&=".AsSpan());
```
```csharp
int index = text.IndexOfAny(s_delims);
```
Relevant analyzer: `CA1870`.
### `CollectionsMarshal.AsSpan` is advanced and ownership-sensitive
```csharp
Span<int> span = CollectionsMarshal.AsSpan(list);
```
Use this only when:
- you own the `List<T>`
- you will not add or remove items while the span is in use
- a measured hot path justifies bypassing normal list APIs
## Strings
### `StartsWith` over `IndexOf(...) == 0`
Wrong:
```csharp
return text.IndexOf("abc", StringComparison.Ordinal) == 0;
```
Better:
```csharp
return text.StartsWith("abc", StringComparison.Ordinal);
```
Relevant analyzer: `CA1858`.
### `Append(char)` over `Append("x")`
Wrong:
```csharp
builder.Append("]");
```
Better:
```csharp
builder.Append(']');
```
Relevant analyzers: `CA1834`, `CA1865-CA1867`.
## What Not To Suggest
- Do not suggest unsafe code first.
- Do not suggest pooling tiny objects by default.
- Do not suggest `stackalloc` because "heap bad, stack good".
- Do not suggest converting APIs to `Span<T>` if the lifetime model does not fit.
- Do not suggest loop rewrites without a profile or benchmark showing LINQ still matters after simpler fixes.

View file

@ -0,0 +1,217 @@
# Collections & LINQ Patterns
### Use FrozenDictionary/FrozenSet for Read-Heavy Lookup Tables
🟡 **DO** use `FrozenDictionary`/`FrozenSet` for collections created once and read many times | .NET 8+
```csharp
private static readonly Dictionary<string, int> s_statusCodes = new()
{
["OK"] = 200, ["NotFound"] = 404, ["InternalServerError"] = 500
};
```
```csharp
private static readonly FrozenDictionary<string, int> s_statusCodes =
new Dictionary<string, int>
{
["OK"] = 200, ["NotFound"] = 404, ["InternalServerError"] = 500
}.ToFrozenDictionary();
```
**Impact: ~50% faster lookups than Dictionary, ~14x faster than ImmutableDictionary.**
### Use Dictionary Alternate Lookup for Span-Based Keys
🟡 **DO** use `GetAlternateLookup<ReadOnlySpan<char>>()` to avoid string allocation on lookups | **.NET 10 (or .NET 9) only — NOT available on .NET 8**
❌ (allocates on every lookup; the only option on .NET 8)
```csharp
string key = headerLine.Substring(0, colonIndex);
if (s_dict.TryGetValue(key, out int value)) { /* ... */ }
```
✅ .NET 10 / C# 14
```csharp
var lookup = s_dict.GetAlternateLookup<ReadOnlySpan<char>>();
ReadOnlySpan<char> key = headerLine.AsSpan(0, colonIndex);
if (lookup.TryGetValue(key, out int value)) { }
```
✅ .NET 8 fallback — keep the allocation but minimise it
```csharp
// On net8.0 GetAlternateLookup does not exist (added in .NET 9 BCL).
// Pre-intern frequent keys, or accept the allocation. If the hot path is
// truly critical, store keys as ReadOnlyMemory<char> and write a custom
// IEqualityComparer<string> that compares against a span via string.Compare.
string key = headerLine.Substring(0, colonIndex);
if (s_dict.TryGetValue(key, out int value)) { /* ... */ }
```
**Impact: Avoids string allocation per lookup on .NET 10 — especially valuable in parser/protocol hot paths.**
### Use CollectionsMarshal.GetValueRefOrNullRef for Lookup-and-Update
🟡 **DO** use `CollectionsMarshal.GetValueRefOrAddDefault` for dictionary update patterns | .NET 6+
```csharp
_counts.TryGetValue(key, out int count);
_counts[key] = count + 1;
```
```csharp
ref int count = ref CollectionsMarshal.GetValueRefOrAddDefault(_counts, key, out _);
count++;
```
**Impact: ~48% faster for lookup-and-update patterns (95µs → 49µs).**
### Use Collection Expressions [] for Zero-Allocation Span Creation
🟡 **DO** use collection expressions for `Span<T>` targets | C# 12 / .NET 8+
```csharp
int[] values = new int[] { a, b, c, d };
```
```csharp
Span<int> values = [a, b, c, d];
ReadOnlySpan<int> daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
```
**Impact: Zero heap allocation for span-targeted collection expressions.**
### Use EnsureCapacity on List/Stack/Queue Before Bulk Adds
🟡 **DO** call `EnsureCapacity` before bulk insertions | .NET 6+
```csharp
var list = new List<int>();
for (int i = 0; i < 10000; i++)
list.Add(i);
```
```csharp
var list = new List<int>();
list.EnsureCapacity(10000);
for (int i = 0; i < 10000; i++)
list.Add(i);
```
**Impact: Reduces reallocations and array copies during bulk operations.**
### Use TryGetNonEnumeratedCount for Pre-Sizing
🟡 **DO** use `TryGetNonEnumeratedCount` to pre-size destination collections | .NET 6+
```csharp
var results = new List<int>();
foreach (var item in source)
results.Add(Transform(item));
```
```csharp
var results = source.TryGetNonEnumeratedCount(out int count)
? new List<int>(count)
: new List<int>();
foreach (var item in source)
results.Add(Transform(item));
```
**Impact: Avoids O(n) enumeration for counting; eliminates resizing allocations.**
### Hoist Static Data Out of Method Bodies
🟡 **AVOID** creating collections with static/deterministic data inside method bodies | .NET Core+
```csharp
public string Convert(long number)
{
var groupsMap = new Dictionary<long, Func<long, string>>
{
{ 1_000_000_000, n => $"{Convert(n)} billion" },
{ 1_000_000, n => $"{Convert(n)} million" },
{ 1_000, n => $"{Convert(n)} thousand" },
};
}
```
```csharp
private static readonly FrozenDictionary<long, Func<long, string>> s_groupsMap =
new Dictionary<long, Func<long, string>>
{
{ 1_000_000_000, n => $"{Convert(n)} billion" },
{ 1_000_000, n => $"{Convert(n)} million" },
{ 1_000, n => $"{Convert(n)} thousand" },
}.ToFrozenDictionary();
public string Convert(long number)
{
// ... use s_groupsMap
}
```
**Impact: Eliminates collection + internal storage + closure allocations per call. For a Dictionary with N entries, saves ~N+3 allocations per invocation.**
### Add Overloads to Avoid params Array Allocation
🟡 **DO** add 1- and 2-argument overloads for methods that accept `params T[]`. On .NET 10 also expose a `params ReadOnlySpan<T>` overload | works on .NET 8 and .NET 10
❌ (single `params T[]` overload allocates a new array on every call, including the common 1-argument case)
```csharp
public static string Transform(this string input, params IStringTransformer[] transformers) =>
transformers.Aggregate(input, (current, t) => t.Transform(current));
"hello".Transform(To.TitleCase);
```
✅ Option A — explicit overloads for common arities (works on .NET 8 and .NET 10)
```csharp
public static string Transform(this string input, IStringTransformer transformer) =>
transformer.Transform(input);
public static string Transform(this string input, IStringTransformer t1, IStringTransformer t2) =>
t2.Transform(t1.Transform(input));
public static string Transform(this string input, params IStringTransformer[] transformers) =>
transformers.Aggregate(input, (current, t) => t.Transform(current));
```
✅ Option B — `.NET 10 / C# 14` adds a span overload (eliminates the allocation for all arities)
```csharp
public static string Transform(this string input, params ReadOnlySpan<IStringTransformer> transformers)
{
foreach (var t in transformers)
input = t.Transform(input);
return input;
}
```
⚠️ Option B does **not** compile on `net8.0`: `params ReadOnlySpan<T>` requires C# 13 (default on .NET 9+). On .NET 8 ship only Option A.
**Impact: Option A eliminates the array allocation for 1- and 2-argument calls on every target. Option B eliminates it for all arities on .NET 10.**
## Detection
Scan recipes for collection and LINQ anti-patterns. Run these and report exact counts.
```bash
# Static Dictionary not using FrozenDictionary (read-only after init)
grep -rn --include='*.cs' 'static readonly Dictionary<' --exclude-dir=bin --exclude-dir=obj . | wc -l
# Static FrozenDictionary (already optimized — verify the inverse)
grep -rn --include='*.cs' 'static readonly FrozenDictionary<' --exclude-dir=bin --exclude-dir=obj . | wc -l
# Per-call List allocation (inside method bodies, not static/readonly fields)
grep -rn --include='*.cs' 'new List<' --exclude-dir=bin --exclude-dir=obj . | grep -v 'static\|readonly' | wc -l
# Per-call Dictionary allocation (inside method bodies, not static/readonly fields)
grep -rn --include='*.cs' 'new Dictionary<' --exclude-dir=bin --exclude-dir=obj . | grep -v 'static\|readonly' | wc -l
# StringComparer.CurrentCulture usage (almost always wrong in library code — use Ordinal)
grep -rn --include='*.cs' 'StringComparer.CurrentCulture' --exclude-dir=bin --exclude-dir=obj . | wc -l
# LINQ chains in extension/hot-path files (.Select, .Where, .Cast, .Take, .Aggregate)
grep -rn --include='*.cs' -E '\.(Select|Where|Cast|Take|Aggregate)\(' --exclude-dir=bin --exclude-dir=obj . | wc -l
```
For the LINQ chain recipe: any hit in a file whose name ends in `Extensions.cs`, `Formatter.cs`, or implements a method called from a public extension method is a hot-path candidate. Inspect each hit in these files and flag LINQ chains that allocate delegates, enumerators, or intermediate collections on every call. Hits in localization converters or one-time initialization are lower priority.
### Patterns Requiring Manual Review
- **ContainsKey + indexer double-lookup**: Requires verifying the same key is used in a subsequent indexer access — multi-line/multi-statement context
- **LINQ on hot paths**: The LINQ chain recipe above catches call sites, but distinguishing hot-path from cold-path requires context. Prioritize hits in `*Extensions.cs` and `*Formatter.cs` files, which are typically called on every user invocation
- **`new Dictionary/List<` in method bodies vs fields**: The grep heuristic (`grep -v 'static\|readonly'`) catches most cases but may include false positives from field initializers without `static`/`readonly` — spot-check flagged lines

View file

@ -0,0 +1,288 @@
# Critical .NET Performance Anti-Patterns
17 patterns that cause deadlocks, order-of-magnitude regressions, or excessive allocations.
## Async / Tasks
### Never Block on Async (Sync-over-Async)
🔴 **AVOID** | .NET Core+
```csharp
public string GetData()
=> GetDataAsync().Result;
```
```csharp
public async Task<string> GetDataAsync()
=> await GetDataInternalAsync();
```
**Impact: Deadlocks or thread pool starvation; wastes threads, destroys scalability.**
### Never Await a ValueTask Multiple Times
🔴 **AVOID** | .NET Core 2.1+
```csharp
ValueTask<int> vt = SomeMethodAsync();
int a = await vt;
int b = await vt;
```
```csharp
int result = await SomeMethodAsync();
```
**Impact: Undefined behavior — silent data corruption or exceptions.**
## Memory / Allocation
### Use Span\<T\> / AsSpan Instead of Substring for Slicing
🔴 **DO** | .NET Core 2.1+
```csharp
string sub = input.Substring(5, 10);
```
```csharp
ReadOnlySpan<char> sub = input.AsSpan(5, 10);
```
**Impact: Eliminates per-slice allocations; 2-4x faster via vectorization.**
### Use ArrayPool\<T\> for Temporary Buffers
🔴 **DO** | .NET Core+
```csharp
byte[] buf = new byte[4096];
```
```csharp
byte[] buf = ArrayPool<byte>.Shared.Rent(4096);
Process(buf);
ArrayPool<byte>.Shared.Return(buf);
```
**Impact: Dramatically reduces GC pressure for buffer-heavy workloads.**
### Avoid stackalloc in Loops
🔴 **AVOID** | .NET 5+
```csharp
for (int i = 0; i < 10_000; i++)
Span<byte> buf = stackalloc byte[1024];
```
```csharp
Span<byte> buf = stackalloc byte[1024];
for (int i = 0; i < 10_000; i++) { Process(buf); }
```
**Impact: StackOverflowException — unrecoverable, no catch possible.**
### Avoid Boxing Value Types
🔴 **AVOID** | .NET 6+
```csharp
string s = string.Format("{0}.{1}", major, minor);
```
```csharp
string s = $"{major}.{minor}";
```
**Impact: When replacing `string.Format` with C# 10+ interpolation, typical improvements are ~40% faster with significantly less allocation. Actual gains vary by call site.**
## Strings
### Use StringComparison.Ordinal for Non-Linguistic Comparisons
🔴 **DO** | .NET Core+
```csharp
bool found = text.IndexOf("Content-Type") >= 0;
```
```csharp
bool found = text.Contains("Content-Type", StringComparison.Ordinal);
```
**Impact: 2-3x faster; OrdinalIgnoreCase hash codes ~3.3x faster.**
### Use AsSpan Instead of Substring
🔴 **DO** | .NET Core 2.1+
```csharp
int val = int.Parse(str.Substring(5, 3));
```
```csharp
int val = int.Parse(str.AsSpan(5, 3));
```
**Impact: Eliminates one string allocation per parse operation.**
## Regular Expressions
### Use Source-Generated Regex [GeneratedRegex]
🔴 **ALWAYS** use `[GeneratedRegex]` for all static regex patterns | .NET 7+
```csharp
private static readonly Regex s_re =
new(@"\w+@\w+\.\w+", RegexOptions.Compiled);
```
```csharp
[GeneratedRegex(@"\w+@\w+\.\w+")]
private static partial Regex EmailRegex();
```
**Impact: Always beneficial or neutral for static patterns — near-zero startup, better throughput, and required for AOT/trimming scenarios.**
### Avoid Nested Quantifiers (Catastrophic Backtracking)
🔴 **AVOID** | .NET Core+
```csharp
var r = new Regex(@"^(\w+)+$");
```
```csharp
var r = new Regex(@"^\w+$", RegexOptions.NonBacktracking);
```
**Impact: Can hang process indefinitely on crafted input.**
### Use TryGetValue Instead of ContainsKey + Indexer
🔴 **DO** | .NET Core+
```csharp
if (dict.ContainsKey(key))
Use(dict[key]);
```
```csharp
if (dict.TryGetValue(key, out var value))
Use(value);
```
**Impact: ~2x faster (50% reduction in lookup time).**
### Avoid LINQ in Hot Paths
🔴 **AVOID** | .NET Core+
```csharp
bool found = items.Any(x => x.Name == target);
```
```csharp
bool found = false;
foreach (var item in items)
if (item.Name == target) { found = true; break; }
```
**Impact: Eliminates 1-3 allocations per call; measurable in tight loops.**
### Don't Iterate IEnumerable Multiple Times
🔴 **AVOID** | .NET Core+
```csharp
foreach (Type t in types) { Validate(t); }
_types = types.ToArray();
```
```csharp
Type[] arr = types.ToArray();
foreach (Type t in arr) { Validate(t); }
_types = arr;
```
**Impact: Halves enumeration cost; prevents bugs from re-executing deferred queries.**
## JSON Serialization
### Use System.Text.Json Source Generator
🔴 **DO** | .NET 6+
```csharp
string json = JsonSerializer.Serialize(post);
```
```csharp
[JsonSerializable(typeof(BlogPost))]
internal partial class AppJsonCtx : JsonSerializerContext { }
string json = JsonSerializer.Serialize(post, AppJsonCtx.Default.BlogPost);
```
**Impact: 37-44% faster; enables trimming and Native AOT.**
### Cache JsonSerializerOptions
🔴 **DO** | .NET 5+
```csharp
JsonSerializer.Serialize(obj, new JsonSerializerOptions());
```
```csharp
private static readonly JsonSerializerOptions s_opts = new();
JsonSerializer.Serialize(obj, s_opts);
```
**Impact: Up to 592x slower without caching (.NET 6); always cache or use defaults.**
## Networking
### Reuse HttpClient Instances
🔴 **DO** | .NET Core 2.1+
```csharp
using var client = new HttpClient();
await client.GetStringAsync(url);
```
```csharp
private static readonly HttpClient s_http = new(new SocketsHttpHandler
{ PooledConnectionLifetime = TimeSpan.FromMinutes(5) });
await s_http.GetStringAsync(url);
```
**Impact: Prevents socket exhaustion; 6-12x faster concurrent HTTPS.**
## General
### Use SearchValues\<T\> for Repeated Set Searches
🔴 **DO** | .NET 8+ (works on both targets; .NET 10 adds multi-string overloads)
```csharp
int pos = text.IndexOfAny("ABCDEF".ToCharArray());
```
✅ (.NET 8 and .NET 10 — `SearchValues<char>` is the same API on both)
```csharp
private static readonly SearchValues<char> s_hex = SearchValues.Create("ABCDEF");
int pos = text.AsSpan().IndexOfAny(s_hex);
```
✅ (.NET 10 only — multi-string `SearchValues<string>`)
```csharp
private static readonly SearchValues<string> s_keywords =
SearchValues.Create(["error", "warning", "fatal"], StringComparison.OrdinalIgnoreCase);
int pos = log.AsSpan().IndexOfAny(s_keywords); // SearchValues<string> overload is .NET 9+ BCL
```
On `net8.0` use a `SearchValues<char>` with the first letter of each keyword and then fall back to `string.IndexOf(StringComparison.Ordinal)`.
**Impact: 2-10x faster for chars (both targets); 10-30x faster for multi-string on .NET 10.**
## Detection
Scan recipes for critical anti-patterns. Run these and report exact counts of issues found in each case.
```bash
# .IndexOf(string) without StringComparison (culture-aware, 2-3x slower)
grep -rn --include='*.cs' -E '\.IndexOf\("[^"]+"\)' --exclude-dir=bin --exclude-dir=obj . | wc -l
# .Substring( calls (allocates new string — consider AsSpan)
grep -rn --include='*.cs' '\.Substring(' --exclude-dir=bin --exclude-dir=obj . | wc -l
# .StartsWith/.EndsWith without StringComparison (culture-aware, 2-3x slower)
grep -rn --include='*.cs' -E '\.(StartsWith|EndsWith)\("[^"]+"\)' --exclude-dir=bin --exclude-dir=obj . | wc -l
# .Contains(string) without StringComparison — NOTE: will also match collection .Contains() calls; filter to string receivers
grep -rn --include='*.cs' -E '\.Contains\("[^"]+"\)' --exclude-dir=bin --exclude-dir=obj . | wc -l
```

View file

@ -0,0 +1,165 @@
# Anti-Pattern Grep Library
Consolidated grep patterns for automated scanning. Run these with the Grep tool using `type: "cs"` filter.
All patterns use ripgrep regex syntax. Run during Phase 1 (Discovery) broad scan.
> **See also:** each topic catalog ([critical-patterns.md](critical-patterns.md), [async-patterns.md](async-patterns.md), [memory-and-strings.md](memory-and-strings.md), [collections-and-linq.md](collections-and-linq.md), [regex-patterns.md](regex-patterns.md), [io-and-serialization.md](io-and-serialization.md), [structural-patterns.md](structural-patterns.md)) has its own Detection section with topic-specific recipes and ratio-counting guidance. This file is the consolidated cross-cutting library; load topic files when their signals are present.
---
## ASYNC anti-patterns (CRITICAL)
```
\.Result\b
\.Wait\(\)
\.GetAwaiter\(\)\.GetResult\(\)
async void\b
Task\.Run\(
\.WriteAsync\([^,]*\)
```
**False positive note**: `.Result` matches `Task.FromResult` -- verify actual blocking before flagging.
---
## Memory anti-patterns (MEM)
```
new byte\[\d{4,}\]
new byte\[
new MemoryStream\(\)
\.Substring\(
new StringBuilder\(\)
new List<.*>\(\)
new Dictionary<.*>\(\)
_logger\.Log(Debug|Trace|Information|Warning|Error|Critical)\(\$"
\.Split\(
```
---
## LINQ anti-patterns
```
\.Count\(\)\s*[><=!]
\.ToList\(\)\.Where\(
\.ToList\(\)\.Select\(
\.Select\(.*\)\.Where\(
\.OrderBy.*\.Where\(
```
---
## Database / CosmosDB anti-patterns (DB)
```
\.Include\(.*\.Include\(
await.*foreach.*await.*Async
ReadItemAsync
GetItemQueryIterator
GetItemLinqQueryable
\.RequestCharge
```
---
## JSON anti-patterns
```
new JsonSerializerOptions
new JsonSerializerSettings
JsonConvert\.Serialize
JsonConvert\.Deserialize
new JsonSerializer
```
---
## Caching anti-patterns (CACHE)
```
GetAsync\(
SendAsync\(
_cache\.TryGetValue
DistributedCache
AddMemoryCache\(\)
```
---
## HttpClient misuse (HTTP)
```
new HttpClient\(
new HttpClient\b
```
---
## Exception control flow (EXC)
```
catch\s*\(Exception\b
catch\s*\(KeyNotFoundException
catch\s*\(FormatException
catch\s*\(InvalidOperationException
```
---
## String anti-patterns (STR)
```
\+= "
\+= \$"
\.ToLower\(\)
\.ToUpper\(\)
String\.Format\(
```
---
## Concurrency anti-patterns (CONC)
```
lock\s*\(
new SemaphoreSlim
HttpContext.*Task\.Run
```
---
## Startup & Pipeline (STARTUP)
```
UseResponseCompression
AddResponseCompression
ShortCircuit
AddOutputCache
UseOutputCache
TieredPGO
PublishReadyToRun
ApplicationStarted
```
---
## Metrics & Observability (METRICS)
```
new Meter\(
CreateCounter
CreateHistogram
AddMeter
```
---
## CancellationToken coverage
```
async Task[<\s].*\)\s*$
```
This pattern finds async methods whose signature ends without a CancellationToken parameter. Verify each match -- some may be interface implementations where the token is propagated differently.

View file

@ -0,0 +1,124 @@
# I/O, Serialization & General Patterns
### Use HttpCompletionOption.ResponseHeadersRead for Streaming
🟡 **DO** use `ResponseHeadersRead` when downloading large responses | .NET Core 3.0+
```csharp
var response = await client.GetAsync(uri);
```
```csharp
using var response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead);
using var stream = await response.Content.ReadAsStreamAsync();
await stream.CopyToAsync(destinationStream);
```
**Impact: ~2x faster for large downloads (10MB+), dramatically reduced memory usage.**
### Use Async FileStream Operations
🟡 **DO** use `FileStream` with `useAsync: true` for scalable file I/O | .NET 6+
```csharp
using var fs = new FileStream(path, FileMode.Open);
```
```csharp
await using var fs = new FileStream(path, FileMode.Open, FileAccess.Read,
FileShare.Read, bufferSize: 4096, useAsync: true);
byte[] buffer = new byte[1024];
while (await fs.ReadAsync(buffer) != 0) { /* process */ }
```
**Impact: Up to 3x faster async reads; allocation reduced from megabytes to hundreds of bytes.**
### Use Memory\<byte\> Overloads for Stream.ReadAsync/WriteAsync
🟡 **DO** use `Memory<byte>`-based stream overloads instead of `byte[]` overloads | .NET 5+
```csharp
await stream.ReadAsync(buffer, 0, buffer.Length);
await stream.WriteAsync(buffer, 0, buffer.Length);
```
```csharp
await stream.ReadAsync(buffer.AsMemory());
await stream.WriteAsync(buffer.AsMemory());
```
**Impact: Eliminates ~72 KB allocation per 1,000 read/write pairs on NetworkStream.**
### Use Span-Based TryFormat for Number Formatting
🟡 **DO** use `TryFormat` to format numbers into `Span<char>` buffers | .NET Core 2.1+
```csharp
string formatted = value.ToString();
destination.Write(formatted);
```
```csharp
Span<char> buffer = stackalloc char[20];
if (value.TryFormat(buffer, out int charsWritten))
destination.Write(buffer[..charsWritten]);
```
**Impact: Int32.ToString() ~2x faster in .NET Core 2.1, Int32 parsing ~5x faster in .NET Core 3.0.**
### Use static readonly for Runtime Devirtualization
🟡 **DO** store implementations in `static readonly` fields for JIT devirtualization | .NET Core 3.0+
```csharp
private static Base s_impl = new DerivedImpl();
s_impl.Process();
```
```csharp
private static readonly Base s_impl = new DerivedImpl();
s_impl.Process();
private static readonly bool s_feature =
Environment.GetEnvironmentVariable("Feature") == "1";
```
**Impact: Virtual call eliminated entirely — can be inlined to zero overhead. Dead code elimination in tier 1.**
### Avoid Explicit Static Constructors — Use Field Initializers
🟡 **AVOID** explicit `static` constructors when field initializers suffice | .NET Core 3.0+
```csharp
class Foo
{
static readonly int s_value;
static Foo() { s_value = ComputeValue(); }
}
```
```csharp
class Foo
{
static readonly int s_value = ComputeValue();
}
```
**Impact: Enables better JIT optimization and reduces potential lock overhead on static method access.**
## Detection
Scan recipes for I/O and serialization anti-patterns. Run these and report exact counts.
```bash
# new HttpClient() (socket exhaustion risk)
grep -rn --include='*.cs' 'new HttpClient(' --exclude-dir=bin --exclude-dir=obj . | wc -l
# new JsonSerializerOptions() not cached (592x slower in .NET 6)
grep -rn --include='*.cs' 'new JsonSerializerOptions' --exclude-dir=bin --exclude-dir=obj . | grep -v 'static\|readonly' | wc -l
```
### Patterns Requiring Manual Review
- **`JsonSerializer.Serialize/Deserialize` without source-gen context**: Can't determine from grep if a context parameter is passed

View file

@ -0,0 +1,193 @@
---
description: >-
Performance measurement guide for dotnet-performance skill. Covers tool
selection per category, KPI targets, BenchmarkDotNet, k6 load testing,
CI/CD integration, and live process CLI commands.
metadata:
tags: [measurement, benchmarkdotnet, k6, dotnet-counters, kpi]
---
# Measurement Guide
How to measure performance before and after applying optimizations. Never optimize without baseline data.
---
## Tool Selection Decision Table
Map each optimization category to the appropriate measurement tools:
| Category | Primary Tool | Secondary Tool | What to Measure |
|---|---|---|---|
| MEM | `dotnet-counters` (gc-heap-size, alloc-rate) | `dotnet-gcdump` comparison | Allocation rate reduction, GC collection frequency |
| ASYNC | `dotnet-counters` (threadpool-queue-length, thread-count) | App Insights dependency tracking | Thread pool starvation, blocked threads |
| LINQ | BenchmarkDotNet `[MemoryDiagnoser]` | `dotnet-trace` hot path | Allocation per operation, throughput |
| DB | `response.RequestCharge` logging | App Insights DB dependency | RU cost per operation, query latency |
| JSON | BenchmarkDotNet serialization benchmark | `dotnet-counters` alloc-rate | Throughput (ops/sec), bytes allocated |
| CACHE | App Insights dependency duration | Custom hit ratio counter | Cache hit rate, dependency call reduction |
| DI | `dotnet-counters` alloc-rate | Load test comparison | Object creation overhead |
| CONC | `dotnet-counters` (monitor-lock-contention-count) | `dotnet-trace` contention events | Lock wait time, throughput under load |
| HTTP | `dotnet-counters` Microsoft.AspNetCore.Hosting | k6/NBomber load test | Request duration, throughput |
| EXC | `dotnet-counters` exception-count | App Insights exceptions | Exception rate per interval |
| RESP | Network tab / curl with timing | k6 response size check | Response size (bytes), transfer time |
| STR | BenchmarkDotNet `[MemoryDiagnoser]` | `dotnet-counters` alloc-rate | String allocations per operation |
| STARTUP | Startup time measurement | `dotnet-trace` startup events | Time to first request, cold start latency |
| METRICS | `MetricCollector<T>` in tests | Prometheus/Grafana dashboard | Metric emission, cardinality |
---
## KPI Targets
Standard targets for ASP.NET Core APIs. Use as thresholds when evaluating optimization impact:
| Metric | Target | Red Flag |
|---|---|---|
| P50 response time | < 100ms | > 200ms |
| P95 response time | < 500ms | > 1000ms |
| P99 response time | < 1000ms | > 2000ms |
| Error rate (5xx) | < 0.1% | > 1% |
| CPU utilization | < 70% sustained | > 85% |
| Memory working set | < 80% | > 90% |
| Thread pool queue length | < 10 sustained | > 50 |
| GC time percentage | < 10% | > 20% |
| Allocation rate | Trend down after optimization | Sustained increase |
---
## BenchmarkDotNet Guidance
Use for micro-optimizations on hot paths (MEM, LINQ, JSON, STR categories).
**When to benchmark**: Hot-path changes where the difference is in nanoseconds or bytes allocated. Not needed for architectural changes (caching, DI lifetime) — use load testing instead.
**Minimum setup**:
```csharp
[MemoryDiagnoser]
[SimpleJob(RuntimeMoniker.Net90)]
public class MyBenchmark
{
[Benchmark(Baseline = true)]
public void Original() { /* original code */ }
[Benchmark]
public void Optimized() { /* optimized code */ }
}
```
**Run command**: `dotnet run -c Release --project path/to/benchmark`
**Common pitfalls**:
- Running in Debug mode (JIT optimizations disabled, results meaningless)
- Not returning computed values (JIT eliminates dead code)
- Ignoring allocation metrics (throughput may improve but allocations increase)
- Benchmarking with a debugger attached
- Including setup costs in the measured method
---
## Load Testing
For HIGH-impact optimizations, perform before/after load testing to validate real-world improvement.
**k6 template**:
```javascript
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '30s', target: 20 },
{ duration: '1m', target: 20 },
{ duration: '10s', target: 0 },
],
thresholds: {
http_req_duration: ['p(50)<100', 'p(95)<500', 'p(99)<1000'],
http_req_failed: ['rate<0.01'],
},
};
export default function () {
const res = http.get('http://localhost:5000/your-endpoint');
check(res, {
'status is 200': (r) => r.status === 200,
'p95 under 500ms': (r) => r.timings.duration < 500,
});
sleep(1);
}
```
**While load testing, monitor simultaneously**:
```bash
dotnet-counters monitor -n <ProcessName> --counters System.Runtime,Microsoft.AspNetCore.Hosting
```
---
## CI/CD Integration
For PR regression detection, use `benchmark-action/github-action-benchmark`:
```yaml
- uses: benchmark-action/github-action-benchmark@v1
with:
tool: 'benchmarkdotnet'
output-file-path: BenchmarkDotNet.Artifacts/results/*.json
alert-threshold: '150%'
comment-on-alert: true
fail-on-alert: true
```
This fails the PR if any benchmark regresses by more than 50% compared to the baseline.
---
## Code Review Mode: Quick Reference Commands
```bash
# Baseline runtime health
dotnet-counters monitor -n <ProcessName> --counters System.Runtime
# ASP.NET Core request metrics
dotnet-counters monitor -n <ProcessName> --counters Microsoft.AspNetCore.Hosting
# Full monitoring (runtime + HTTP + custom meters)
dotnet-counters monitor -n <ProcessName> --counters System.Runtime,Microsoft.AspNetCore.Hosting,Microsoft.AspNetCore.Server.Kestrel
# GC heap snapshot for before/after comparison
dotnet-gcdump collect -n <ProcessName> -o before.gcdump
# ... apply optimization ...
dotnet-gcdump collect -n <ProcessName> -o after.gcdump
# 30-second CPU trace
dotnet-trace collect -n <ProcessName> --duration 00:00:30
dotnet-trace convert trace.nettrace --format speedscope
```
---
## Diagnostic Mode: Full CLI Commands
When profiling a live process (Mode A), use these commands by investigation stage:
```bash
# Stage 1: Live triage
dotnet-counters monitor -p <PID> --counters System.Runtime
dotnet-counters monitor -n <ProcessName> --counters System.Runtime,Microsoft.AspNetCore.Hosting,Microsoft.AspNetCore.Server.Kestrel
# Stage 2: Stuck/hung process — get stacks immediately
dotnet-stack report -p <PID>
# Stage 3: CPU + allocation hot paths
dotnet-trace collect -p <PID> --duration 00:00:30
dotnet-trace report <trace.nettrace> topN
# Stage 4: Heap composition
dotnet-gcdump collect -p <PID> -o before.gcdump
# ... apply optimization ...
dotnet-gcdump collect -p <PID> -o after.gcdump
dotnet-gcdump report <file.gcdump>
# Stage 5: Full dump for SOS analysis
dotnet-dump collect -p <PID> --type Heap
dotnet-dump analyze <dump> -c "dumpheap -stat" -c "exit"
```

View file

@ -0,0 +1,223 @@
# Memory & String Patterns
### Use ReadOnlySpan\<byte\> for Constant Byte Data
🟡 **DO** assign constant byte arrays to `ReadOnlySpan<byte>` | .NET 5+
```csharp
byte[] data = new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F };
```
```csharp
ReadOnlySpan<byte> data = [0x48, 0x65, 0x6C, 0x6C, 0x6F];
ReadOnlySpan<int> primes = [2, 3, 5, 7, 11, 13];
```
**Impact: ~100x faster access than static byte[] field, zero allocation.**
### Use stackalloc for Small Temporary Buffers
🟡 **DO** use `stackalloc` for small, fixed-size temporary buffers | .NET Core+
```csharp
char[] buffer = new char[64];
guid.TryFormat(buffer, out int written);
```
```csharp
Span<char> buffer = stackalloc char[64];
guid.TryFormat(buffer, out int written);
```
**Impact: Zero heap allocation, no GC pressure, instant alloc/dealloc.**
### Use Span.TryWrite for Allocation-Free Interpolation
🟡 **DO** use `MemoryExtensions.TryWrite` to format into `Span<char>` buffers | .NET 6+
```csharp
string formatted = $"Date: {dt:R}";
destination.Write(formatted);
```
```csharp
Span<char> buffer = stackalloc char[64];
buffer.TryWrite($"Date: {dt:R}", out int charsWritten);
```
**Impact: Zero heap allocation for formatting operations.**
### Use Span.Split() for Zero-Allocation Splitting
🟡 **DO** use `MemoryExtensions.Split` for allocation-free string splitting | **.NET 10 (or .NET 9) only — NOT available on .NET 8**
❌ (allocates `string[]` — the only built-in option on .NET 8)
```csharp
string[] parts = input.Split(',');
```
✅ .NET 10
```csharp
foreach (Range range in input.AsSpan().Split(','))
{
ReadOnlySpan<char> segment = input.AsSpan(range);
}
```
✅ .NET 8 fallback — manual `IndexOf` loop on the span (no allocation)
```csharp
ReadOnlySpan<char> remaining = input.AsSpan();
while (!remaining.IsEmpty)
{
int idx = remaining.IndexOf(',');
ReadOnlySpan<char> segment = idx < 0 ? remaining : remaining[..idx];
// ... use segment ...
remaining = idx < 0 ? default : remaining[(idx + 1)..];
}
```
**Impact: 208 bytes → 0 bytes per split, 2x faster on .NET 10. The manual .NET 8 loop is also zero-allocation but more verbose.**
### Use UTF8 String Literals (u8 suffix)
🟡 **DO** use the `u8` suffix for compile-time UTF8 `ReadOnlySpan<byte>` | .NET 7+
```csharp
byte[] header = Encoding.UTF8.GetBytes("Content-Type");
```
```csharp
ReadOnlySpan<byte> header = "Content-Type"u8;
```
**Impact: 17ns → 0.006ns — eliminates runtime transcoding entirely.**
### Use ReadOnlySpan\<char\> Pattern Matching with switch
🟡 **DO** use `switch` on `ReadOnlySpan<char>` for allocation-free string matching | C# 11+
```csharp
switch (attr.Value.Trim()) { case "preserve": /* ... */ break; }
```
```csharp
switch (attr.Value.AsSpan().Trim())
{
case "preserve": return Preserve;
case "default": return Default;
}
```
**Impact: Eliminates string allocation from Trim() in switch-based dispatch.**
### Use params ReadOnlySpan\<T\> to Eliminate Array Allocations
🟡 **DO** add `params ReadOnlySpan<T>` overloads to library methods | **.NET 10 (or .NET 9) only — requires C# 13**
❌ (the only option on .NET 8 — accept the array allocation, or add explicit 1/2/3-argument overloads)
```csharp
public static void Log(params string[] messages) { /* ... */ }
Log("Starting", "Processing", "Done");
```
✅ .NET 10
```csharp
public static void Log(params ReadOnlySpan<string> messages) { /* ... */ }
Log("Starting", "Processing", "Done");
```
✅ .NET 8 fallback — keep `params string[]` and add fixed-arity overloads for the hot common cases
```csharp
public static void Log(string m) { /* ... */ }
public static void Log(string m1, string m2) { /* ... */ }
public static void Log(string m1, string m2, string m3) { /* ... */ }
public static void Log(params string[] messages) { /* fallback for 4+ args */ }
```
**Impact: Eliminates params array allocation on .NET 10. On .NET 8 fixed-arity overloads cover the hot 13 argument cases.**
### Avoid Chained String-Returning Operations
🟡 **AVOID** chains of 3+ string-returning method calls that each allocate intermediates | .NET Core+
**Pattern 1: Chained .Replace() calls**
```csharp
string result = input.Replace("a", "b").Replace("c", "d").Replace("e", "f");
```
```csharp
var sb = new StringBuilder(input.Length);
// single pass replacing all patterns
```
**Pattern 2: Chained Regex.Replace() calls**
```csharp
public static string Underscore(this string input) =>
Regex3.Replace(Regex2.Replace(Regex1.Replace(input, "$1_$2"), "$1_$2"), "_").ToLower();
```
```csharp
return string.Create(totalLength, state, (span, s) => { /* write directly */ });
```
**Pattern 3: += string concatenation in loops**
```csharp
string result = "";
foreach (var part in parts)
result += separator + part;
```
```csharp
var sb = new StringBuilder();
foreach (var part in parts)
sb.Append(separator).Append(part);
return sb.ToString();
```
**Impact: Eliminates N-1 intermediate string allocations per chain. For `+=` in loops, eliminates O(n²) total allocation.**
### Cache char.ToString() for Known Character Sets
🟡 **DO** cache `char.ToString()` results when the set of characters is small and known | .NET Core+
```csharp
return symbol.ToString();
foreach (var prefix in UnitPrefixes)
input = input.Replace(prefix.Value.Name, prefix.Key.ToString());
```
```csharp
private static readonly FrozenDictionary<char, string> s_charStrings =
new Dictionary<char, string>
{
['k'] = "k", ['M'] = "M", ['G'] = "G",
}.ToFrozenDictionary();
return s_charStrings[symbol];
```
**Impact: Eliminates one string allocation per char.ToString() call. Significant when called in loops or on hot paths.**
## Detection
Scan recipes for memory and string anti-patterns. Run these and report exact counts.
```bash
# .ToLower()/.ToUpper() without culture parameter (allocates + culture-sensitive)
grep -rn --include='*.cs' -E '\.(ToLower|ToUpper)\(\)' --exclude-dir=bin --exclude-dir=obj . | wc -l
# Chained .Replace( calls (3+ on one line — intermediate string allocations)
grep -rn --include='*.cs' '\.Replace(.*\.Replace(.*\.Replace(' --exclude-dir=bin --exclude-dir=obj . | wc -l
# params in method signatures (array allocation per call)
grep -rn --include='*.cs' 'params ' --exclude-dir=bin --exclude-dir=obj . | wc -l
# LINQ on strings — .All/.Any on IEnumerable<char> (replace with foreach loop)
grep -rn --include='*.cs' -E '\.(All|Any)\(char\.' --exclude-dir=bin --exclude-dir=obj . | wc -l
```
### Patterns Requiring Manual Review
- **Boxing via string.Format**: Can't determine argument types from grep — needs type analysis
- **`+=` string concatenation in loops**: `+=` matches all types (int, list, event, string) — needs type context to confirm string
- **`char.ToString()`**: Requires knowing the variable type is `char` — not reliably greppable

View file

@ -0,0 +1,117 @@
---
description: CLR memory model and GC guidance for csharp-dotnet-cli-optimization.
metadata:
tags: [clr, gc, heap, stack, loh, memory-model]
---
# CLR Memory Model And GC
Use this reference when the user asks why allocations, boxing, heap growth, GC pauses, or stack-based techniques behave the way they do.
## Core Model
- Reference types allocate objects on the managed heap. Local variables and fields hold references to those objects.
- Value types store their data directly. A value type local is often stored in stack storage, but value types also live inline inside object fields and array elements.
- "`struct` means stack" is false. The useful distinction is inline storage plus copy semantics, not "stack forever".
- Boxing converts a value type to `object` or an interface by allocating a new heap object and copying the value into it.
- `ref struct` types, including `Span<T>` and `ReadOnlySpan<T>`, are stack-constrained wrappers that can't escape to the managed heap.
- `Memory<T>` and `ReadOnlyMemory<T>` are the heap-storable counterparts when data must live across `await`, callbacks, or object fields.
## How The GC Works
- The GC is generational: gen0 for young objects, gen1 as a buffer, gen2 for long-lived survivors.
- The large object heap (LOH) is used for allocations at or above 85,000 bytes by default.
- Background GC is enabled by default. It reduces pause impact for full collections but does not make them free.
- Server GC and workstation GC are process-level choices. The defaults are usually right unless measurement says otherwise.
- On modern 64-bit Windows and Linux, the GC internally uses regions, but the optimization model for application code is still about generations, allocation rate, survivor rate, LOH churn, and pinning.
## What Usually Makes GC Expensive
- High allocation rate on hot paths
- Objects surviving long enough to promote into older generations
- Large transient allocations that churn the LOH
- Excessive pinning that increases fragmentation
- Finalizers on objects that should have been deterministic `Dispose` calls instead
## Wrong vs Better
| Wrong | Better | Why |
|---|---|---|
| Assume a `struct` is always stack allocated | Explain whether it will be copied, boxed, stored inline, or escape | That is what actually drives cost |
| Allocate large temporary arrays repeatedly | Reuse, pool, or redesign the algorithm if measurement shows LOH churn | LOH allocations are cleared and collected with gen2 work |
| Call `GC.Collect()` to "fix" memory pressure | Lower allocation rate and object lifetime first | Forced GC usually adds pause time and hides the real problem |
| Pin many buffers for long periods | Minimize pin count and pin duration | Pinning can fragment the heap |
| Use finalizers for routine cleanup | Use `IDisposable`, `using`, and `SafeHandle` for unmanaged resources | Finalization is slower and delays reclamation |
## GC Configuration Rules
- Treat GC configuration changes as process-wide tuning, not local fixes.
- Prefer runtime defaults unless counters and traces show a clear reason to change them.
- Choose server GC for throughput-oriented workloads only after measurement.
- Use low-latency modes sparingly and for bounded windows. They reduce GC intrusiveness by letting memory grow and can increase fragmentation.
- If you are tuning in containers or hard memory limits, treat heap hard-limit settings as operational controls, not code-level optimizations.
## Bad vs Good Examples
Bad:
```csharp
for (int i = 0; i < 10_000; i++)
{
DoWork(new byte[200_000]);
}
GC.Collect();
```
Better:
```csharp
byte[] buffer = ArrayPool<byte>.Shared.Rent(200_000);
try
{
for (int i = 0; i < 10_000; i++)
{
DoWork(buffer);
}
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
```
Bad:
```csharp
public sealed class NativeThing
{
~NativeThing() => ReleaseHandle();
}
```
Better:
```csharp
public sealed class NativeThing : IDisposable
{
public void Dispose()
{
ReleaseHandle();
GC.SuppressFinalize(this);
}
}
```
## Practical Heuristics
- If counters show rising allocation rate and frequent gen0 collections, start by eliminating short-lived allocations.
- If gen2 collections or LOH size are the problem, look for survivor growth, pinned buffers, and large transient objects.
- If a change turns classes into structs, verify both allocation wins and copy costs.
- If the process is memory-constrained, inspect runtime GC settings before changing code blindly.
## What Not To Claim
- Do not claim that moving code to `struct` always reduces memory.
- Do not claim that stack allocation is always faster than pooling.
- Do not claim that background GC removes pause concerns.
- Do not claim that the GC is the problem unless counters, traces, or dumps support that diagnosis.

View file

@ -0,0 +1,95 @@
# Regex Patterns
### Choose the Right Regex Engine Mode
🟡 **DO** use `[GeneratedRegex]` for all static regex patterns, but never remove `NonBacktracking` if present | .NET 7+
```csharp
var r = new Regex(dynamicPattern, RegexOptions.Compiled);
```
```csharp
[GeneratedRegex("pattern")]
private static partial Regex MyRegex();
var safe = new Regex(untrustedPattern, RegexOptions.NonBacktracking);
var oneOff = new Regex("pattern");
```
**Impact: Source generator is always beneficial for static patterns. NonBacktracking prevents O(2^N) worst case — never remove it if present.**
### Use IsMatch When You Only Need a Boolean Result
🟡 **DO** use `IsMatch` instead of `Match(...).Success` | .NET 7+
```csharp
bool found = Regex.Match(input, pattern).Success;
```
```csharp
bool found = Regex.IsMatch(input, pattern);
```
**Impact: Avoids Match object allocation; with NonBacktracking, ~3x faster by skipping capture computation.**
### Use Regex.Count/EnumerateMatches Instead of Matches
🟡 **DO** use `Count()` and `EnumerateMatches()` for allocation-free match processing | .NET 7+
```csharp
int count = 0;
Match m = regex.Match(text);
while (m.Success) { count++; m = m.NextMatch(); }
```
```csharp
int count = regex.Count(text);
foreach (ValueMatch m in Regex.EnumerateMatches(text, @"\b\w+\b"))
{
ReadOnlySpan<char> word = text.AsSpan(m.Index, m.Length);
}
```
**Impact: ~3x faster than Match/NextMatch with NonBacktracking. Zero allocations for both Count and EnumerateMatches.**
### Use Span-Based Regex APIs for Allocation-Free Matching
🟡 **DO** use `ReadOnlySpan<char>` overloads for regex matching on spans | .NET 7+
```csharp
string sub = largeBuffer.Substring(start, length);
bool found = Regex.IsMatch(sub, pattern);
```
```csharp
ReadOnlySpan<char> text = largeBuffer.AsSpan(start, length);
foreach (ValueMatch m in Regex.EnumerateMatches(text, @"\b\w+\b"))
{
ReadOnlySpan<char> word = text.Slice(m.Index, m.Length);
}
```
**Impact: Eliminates string allocations when working with spans — particularly valuable in high-throughput parsing pipelines.**
## Detection
Scan recipes for regex anti-patterns. Run these and report exact counts.
```bash
# Compiled regex count (startup cost budget — compare ratio to GeneratedRegex)
grep -rn --include='*.cs' 'RegexOptions.Compiled' --exclude-dir=bin --exclude-dir=obj . | wc -l
# GeneratedRegex count (already optimized — verify the inverse)
grep -rn --include='*.cs' 'GeneratedRegex' --exclude-dir=bin --exclude-dir=obj . | wc -l
# Uncached new Regex() calls (construction cost per call)
grep -rn --include='*.cs' 'new Regex(' --exclude-dir=bin --exclude-dir=obj . | wc -l
```
When `RegexOptions.Compiled` appears inside a class constructor or field initializer of an instantiated class (not a static singleton), count how many instances of that class are created at startup to determine total compiled regex budget. For example, if a `Rule` class compiles a regex in its constructor and 122 rules are registered, that is 122 compiled regexes at startup.
### Patterns Requiring Manual Review
- **`new Regex(` uncached**: Field assignment may span multiple lines — grep on one line is unreliable. Verify that matched instances are stored in `static readonly` fields or `[GeneratedRegex]`.

View file

@ -0,0 +1,38 @@
# Structural Patterns
Patterns detected by the **absence** of a keyword or interface. These require codebase-wide counting scans, not single-file matching.
### Seal Classes for Devirtualization
🟡 **DO** seal all leaf classes (those not subclassed) | .NET Core 3.0+
Sealing lets the JIT devirtualize/inline virtual calls and use pointer comparison for type checks. Every non-abstract, non-static class that is not subclassed should be sealed.
**Detection:** This is an absence pattern — scan for classes that are NOT sealed.
```bash
# Count unsealed (non-abstract, non-static) classes
grep -rn --include='*.cs' -E '^\s*((public|internal|private|protected|file)\s+)?(partial\s+)?class ' --exclude-dir=bin --exclude-dir=obj . | grep -v 'sealed' | grep -v 'abstract' | grep -v 'static' | wc -l
# Count already-sealed classes (verify the inverse)
grep -rn --include='*.cs' 'sealed class' --exclude-dir=bin --exclude-dir=obj . | wc -l
```
**Exclusions:** Do not seal classes that are subclassed elsewhere in the codebase. Identifying base classes requires manual review — grep for `: ClassName` patterns and cross-reference, but expect false positives from interface implementations and generic constraints.
```csharp
internal class MyHandler : Base
{ public override int Run() => 42; }
```
```csharp
internal sealed class MyHandler : Base
{ public override int Run() => 42; }
```
**Impact: Virtual calls up to 500x faster; type checks ~25x faster. Severity scales with count.**
**Scale-based severity:**
- 1-10 unsealed leaf classes → Info
- 11-50 unsealed leaf classes → 🟡 Moderate
- 50+ unsealed leaf classes → 🟡 Moderate (elevated priority)

View file

@ -0,0 +1,145 @@
---
name: dotnet-security-review
description: >-
Performs a systematic C#/ASP.NET Core security code review on .NET 8 (C# 12)
and .NET 10 (C# 14) codebases. Covers OWASP Top 10, authentication/authorization
audit, input validation, cryptography, dependency vulnerabilities, security
headers, middleware pipeline, and CI/CD security posture.
metadata:
platform: ".NET 8 and .NET 10 (no .NET 9 projects in scope)"
---
# Security Code Review for C# / ASP.NET Core (.NET 8 + .NET 10)
You are a security auditor performing a thorough, evidence-based code review. Every finding MUST include file path, line number, severity, impact, and a concrete fix.
## Step 0 — Detect the target framework
Before scoring findings, follow `../../references/detect-target-framework.md`. The security guidance below applies to **both** .NET 8 and .NET 10 unless explicitly marked. A few items are .NET 10-only — when reviewing a .NET 8 project, don't recommend them as "fixes":
- **ASP.NET Core Identity passkeys** (`AddPasskeys()`) — .NET 10 only. On .NET 8, recommend external IdP / `Fido2NetLib` or password+TOTP.
- **Minimal-API built-in validation** (`AddValidation()`) — .NET 10 only. On .NET 8, FluentValidation + `IEndpointFilter` is the safe equivalent.
- **First-party `Microsoft.AspNetCore.OpenApi`** — .NET 9+ only. On .NET 8 the project should use `Swashbuckle.AspNetCore`; flag missing OpenAPI security schemes accordingly.
- **`HybridCache`** — .NET 9+ only. On .NET 8 verify `IDistributedCache` configurations (encryption-at-rest, key prefixing, TLS to Redis) directly.
- The C# 14 `field` keyword, `extension(...)` blocks, null-conditional assignment, and partial constructors **do not compile on net8.0** — never propose security fixes that introduce them on a .NET 8 project.
All cryptography, JWT, authorization-policy, header, and middleware guidance applies identically on both targets.
## Target Selection
The user's arguments are in `$ARGUMENTS`.
- If `$ARGUMENTS` contains a file path or directory, review that target.
- If `$ARGUMENTS` is "all", review the entire codebase starting from the solution root.
- If `$ARGUMENTS` is empty, run `git diff --name-only HEAD~5` to find recently changed `.cs` files. If none, ask the user what to review.
When reviewing a directory or "all", use Glob to find `**/*.cs` files, then prioritize:
1. Controllers, filters, middleware (`*Controller.cs`, `*Filter.cs`, `Program.cs`)
2. Auth handlers and delegating handlers (`*Handler.cs`, `*DelegatingHandler.cs`)
3. Service implementations handling external input or secrets
4. Repository and data access code
5. Configuration and DI registration (`*Extensions.cs`, `*Options.cs`)
6. Validators
## Review Process
Execute each phase sequentially. Use the Read tool for files and the Grep tool for pattern searches. NEVER use bash `grep` or `rg` -- always use the Grep tool.
### Phase 1: Automated Pattern Scanning
Read `references/scanning-patterns.md` for the full pattern catalog. Run all Grep searches in parallel across `.cs` files in the target scope. Each pattern targets a specific vulnerability class: injection, deserialization, cryptography, async anti-patterns, data exposure, SSRF, missing controls, ReDoS, log injection, open redirect, cookie security, file upload, claims safety, and thread safety.
### Phase 2: File-by-File Deep Review
Read `references/deep-review-categories.md` for the complete checklist (Categories A through L). For each file in scope (or top ~20 most security-relevant files when reviewing "all"), check all applicable categories:
- **A**: Authentication & Authorization (JWT validation, auth schemes, IDOR)
- **B**: Input Validation
- **C**: Error Handling & Information Leakage
- **D**: Cryptography & Secrets
- **E**: Data Protection & PII
- **F**: Concurrency & State Safety
- **G**: CancellationToken Propagation
- **H**: HTTP Client Security (resilience handlers, DNS refresh)
- **I**: Configuration Security
- **J**: Logging & Monitoring Security
- **K**: Output Encoding & Response Security
- **L**: Supply Chain & Build Security
### Phase 3: Architecture & Project-Specific Checks
Read `references/architecture-checks.md` for checks tailored to common ASP.NET Core project patterns. These cover endpoint authorization verification, anonymous endpoint abuse potential, OTP/MFA security, exception handling coverage, optimistic concurrency, state expiry, blob storage SAS security, message queue security, JSON serialization settings, background task queue safety, rate limiting, security headers, middleware ordering, and NuGet audit configuration.
Read the project's CLAUDE.md or AGENTS.md for project-specific architecture details to inform these checks.
### Phase 4: Dependency Vulnerability Check
Read `references/dependencies-and-headers.md` (Phase 4 section) for dependency scanning patterns. Check `.csproj` files for known-vulnerable versions and NuGet audit configuration.
### Phase 5: Security Headers & Middleware Pipeline
Read `references/dependencies-and-headers.md` (Phase 5 section) for the 14-item headers checklist and middleware ordering verification.
## Output Format
### Security Review Report
**Scope:** [files/directories reviewed]
**Date:** [current date]
**Risk Summary:** [X CRITICAL, Y HIGH, Z MEDIUM, W LOW, V INFO]
#### Findings
For each finding:
**[SEVERITY] [SHORT-TITLE]**
- **Location:** `file/path.cs:LINE`
- **Category:** [OWASP category or security domain]
- **Description:** [What the vulnerability is and why it matters]
- **Impact:** [What an attacker could achieve]
- **Recommendation:** [Specific fix with code example]
#### Summary Table
| # | Severity | Category | File | Description |
|---|----------|----------|------|-------------|
| 1 | CRITICAL | ... | ... | ... |
#### Recommendations
1. Immediate fixes (CRITICAL/HIGH)
2. Short-term improvements (MEDIUM)
3. Long-term hardening (LOW/INFO)
4. Tooling recommendations (NuGet audit, SAST integration, etc.)
## Severity
Use standard severity: CRITICAL > HIGH > MEDIUM > LOW > INFO. CRITICAL = actively exploitable, HIGH = significant with effort, MEDIUM = increased attack surface, LOW = minor improvement, INFO = hardening suggestion.
## Anti-Rationalization Table
| Rationalization | Reality |
|---|---|
| "This is just a test file" | Test code handling secrets or auth IS production-relevant. Report as INFO. |
| "Probably a false positive" | ALWAYS read surrounding code before dismissing. If you cannot prove it safe, report it. |
| "The framework handles this" | Verify the protection is actually enabled and configured. Defaults can be overridden. |
| "Internal API, not public-facing" | Internal APIs are attacked via SSRF, supply chain, lateral movement. |
| "No one would exploit this" | Threat models change. Report it; let the team decide risk acceptance. |
## Red Flags
STOP and investigate deeper if you encounter any of these:
- Any endpoint without an explicit auth attribute (`[Authorize]` or `[AllowAnonymous]`)
- Any `catch` block returning raw exception data to the client
- Any hardcoded key, token, password, or connection string literal
- Any `new HttpClient()` (should use `IHttpClientFactory`)
- Any `TypeNameHandling` value other than `None`
## Important Guidelines
1. Only report real findings with evidence (file path and line number). Do not speculate.
2. If a pattern search returns no results, note "No issues found" and move on.
3. For false positives (e.g., `System.Random` in tests, not production), note as INFO with explanation.
4. Prioritize production code over test code.
5. When reviewing "all", cap the report at the 30 most significant findings.
6. ALWAYS verify context before reporting -- a pattern match alone is not a finding. Read the surrounding code.

View file

@ -0,0 +1,134 @@
# Architecture & Project-Specific Checks Reference
# Phase 3 checks for common ASP.NET Core project patterns. Read the project's CLAUDE.md
# or AGENTS.md for project-specific details (endpoint list, service names, DI registrations)
# to inform these checks.
## Check 1: Endpoint Auth Matrix Verification
Cross-reference the controller's actual `[Authorize]`/`[AllowAnonymous]` attributes against the project's documented auth requirements. Read CLAUDE.md or AGENTS.md for the expected auth matrix. Any mismatch is CRITICAL.
For projects with multiple auth schemes (e.g., Azure AD + custom JWT), verify each endpoint uses the correct scheme/policy.
## Check 2: Anonymous Endpoint Abuse Potential
For each `[AllowAnonymous]` endpoint, verify:
- Rate limiting or throttling exists for sensitive operations (e.g., code generation, login attempts)
- Enumeration attacks are mitigated (IDs are GUIDs or non-sequential, not auto-increment)
- No state modification without prior authentication or verification (e.g., OTP first)
## Check 3: OTP / MFA Security Review
If the project implements OTP or MFA, read the service implementation and verify:
- Code length is sufficient (6+ characters)
- Codes are generated with `RandomNumberGenerator`
- Hash is SHA-256 or stronger (not MD5/SHA1)
- Expiry is enforced (typically 5-10 minutes)
- Wrong attempt counter increments correctly and triggers lockout after a threshold
- No timing side-channel in hash comparison
## Check 4: Exception Handling Coverage
Grep for `throw new` statements. Verify that all thrown exceptions are either:
- The project's structured error type (e.g., `ApiException`, `DomainException`, or the project's custom base exception), OR
- Known typed exceptions for external service failures
Any unstructured exception thrown from handler/service code may bypass error filters and leak internal details.
## Check 5: Optimistic Concurrency on State Writes
If using a database with optimistic concurrency (ETags, row versions):
- Verify every write/update operation passes the concurrency token
- Verify the concurrency token store/tracking mechanism is consulted on every read/write cycle
## Check 6: Expired State Handling
If the project uses application-level state expiry (not DB TTL):
- Verify expired records are deleted or excluded on read (not returned to callers)
- Verify callers cannot act on expired data
## Check 7: Blob Storage SAS URL Security
If the project generates SAS URLs for blob storage:
- SAS token expiry is short-lived (minutes, not days)
- Permission is read-only (not write/delete)
- Scoped to the specific blob (not container-level)
## Check 8: Message Queue Security
If the project uses message queues (Service Bus, RabbitMQ, etc.):
- Messages do not contain secrets or unnecessary PII
- Queue connections use managed identity or connection strings from secret stores
## Check 9: JSON Serialization Settings
Check that `TypeNameHandling` is set to `None` (default) and not `Auto`/`All` anywhere. This applies to both Newtonsoft.Json and any custom serializer configuration.
## Check 10: Background Task Queue Safety
If the project uses a background task queue:
- Bounded capacity prevents unbounded memory growth
- Backpressure is handled correctly (not silently dropping critical events like audit logs)
- Task failures are observed and logged/metered
## Check 11: Custom Token / JWT Security
If the project issues its own JWTs (not just validating external tokens):
- **Algorithm**: HMAC-SHA256 or stronger (RSA for distributed validation)
- **Signing key source**: Key loaded from configuration/secret store, NOT hardcoded
- **Signing key length**: Minimum 256 bits (32 bytes) for HMAC-SHA256
- **Token expiry**: Appropriately capped (tokens should not outlive the session/resource they protect)
- **Claims validation**: Custom claims (e.g., resource IDs) are validated against route parameters by an authorization handler
- **TokenValidationParameters**: `ValidateIssuer`, `ValidateAudience`, `ValidateLifetime`, `ValidateIssuerSigningKey` all `true`
- **ClockSkew**: Tightened from default 5 minutes to 2 minutes or less
## Check 12: Response Data Sanitization
If the project sanitizes response data (e.g., stripping internal paths or fields):
- Sanitization handles malformed input gracefully (does not throw/crash)
- Only known sensitive fields are stripped (no over-stripping that breaks functionality)
- Sanitization is applied on every code path returning the data (not just the happy path)
## Check 13: Rate Limiting
Verify rate limiting posture:
- Grep for `AddRateLimiter` and `UseRateLimiter` -- if absent, note as finding
- Application-level throttling exists for sensitive operations (e.g., SMS/code generation resend limits)
- Brute force protection exists for verification endpoints (wrong attempt lockout)
- **Recommendation**: Add ASP.NET Core `System.Threading.RateLimiting` middleware for IP-based throttling on public endpoints
## Check 14: Security Headers Completeness
Check Program.cs / middleware for these headers (report missing ones):
- `X-Content-Type-Options: nosniff`
- `X-Frame-Options: DENY`
- `Referrer-Policy: strict-origin-when-cross-origin`
- `Permissions-Policy: camera=(), microphone=(), geolocation=()`
- `X-XSS-Protection: 0` (disable legacy XSS filter; CSP is the modern replacement)
- `Content-Security-Policy` (at minimum for APIs: `default-src 'none'`)
- `Server` header removed
- `X-Powered-By` header removed
## Check 15: Middleware Pipeline Ordering
Read Program.cs and verify correct middleware order:
1. `UseExceptionHandler` (outermost -- catches everything)
2. `UseHsts` (non-development only)
3. `UseHttpsRedirection`
4. Security headers middleware
5. `UseRateLimiter` (if present)
6. `UseRouting` (if explicit)
7. `UseCors`
8. `UseAuthentication`
9. `UseAuthorization`
10. `MapControllers` / endpoints
Authentication MUST come before Authorization. CORS MUST come before Authentication. ExceptionHandler MUST be first.
## Check 16: NuGet Audit & Build Security
Check for build-level security configuration:
- Does `Directory.Build.props` exist? If so, verify `NuGetAudit`, `NuGetAuditMode`, `NuGetAuditLevel` settings.
- Are Roslyn security analyzer packages referenced? (`SecurityCodeScan.VS2019`, `SonarAnalyzer.CSharp`, `Meziantou.Analyzer`)
- Are `AnalysisLevel` / `AnalysisMode` set in `.csproj` or `Directory.Build.props`?
- Run Grep for floating versions: `Version="[^"]*\*"` in `.csproj` files
- Recommend `dotnet list package --vulnerable --include-transitive` as a CI step

View file

@ -0,0 +1,107 @@
# Deep Review Categories Reference
# File-by-file review checklist for Phase 2. For each file in scope (or top ~20 most
# security-relevant files when reviewing "all"), read the file and check each applicable category.
## Category A: Authentication & Authorization
1. Every controller action has either `[Authorize]` (class or method level) or `[AllowAnonymous]` explicitly.
2. No IDOR: when accessing resources by ID, verify the handler checks that the caller owns or is authorized to access that resource.
3. JWT validation settings are strict: issuer, audience, lifetime, algorithm all validated.
4. Token acquisition uses correct flow: app tokens for backend-to-backend, OBO only where user context is needed.
5. No `[AllowAnonymous]` on endpoints that modify sensitive state without alternative authentication (e.g., OTP verification first).
6. **Multiple auth scheme verification**: If the project uses multiple auth schemes (e.g., Azure AD + custom JWT), verify correct scheme is applied per endpoint. No scheme confusion between internal and client-facing endpoints.
7. **JWT `alg:none` rejection**: Verify `TokenValidationParameters` does NOT allow `alg:none`. All schemes must validate the signing algorithm (`ValidateIssuerSigningKey = true`).
8. **HMAC signing key minimum length**: If using HMAC-SHA256 for JWT signing, the key must be at least 256 bits (32 bytes). Check options validation.
9. **Structured error responses on auth failure**: `OnChallenge` (401) and `OnForbidden` (403) events should return structured JSON error responses, not default HTML/empty responses.
## Category B: Input Validation
1. All DTOs accepted by handlers have corresponding FluentValidation validators registered.
2. Route parameters are validated for format before use (e.g., GUID format, positive integers).
3. File uploads are validated for content type, size, and extension (not just extension).
4. No unvalidated user input flows into file paths, URLs, SQL, commands, or log messages.
5. Phone numbers, emails, and other PII are validated and normalized before processing.
## Category C: Error Handling & Information Leakage
1. All expected errors use a structured error type -- never return raw exception details to clients.
2. Exception filters catch known exception types and return only safe error payloads.
3. Unknown exceptions are wrapped as generic 500 errors without stack traces or internal details.
4. Error messages returned to clients do not reveal internal architecture, database schema, or file paths.
5. Catch blocks never silently swallow exceptions -- they must log or rethrow.
## Category D: Cryptography & Secrets
1. OTP/MFA codes use `RandomNumberGenerator` (not `System.Random`).
2. Hash comparison uses constant-time comparison to prevent timing attacks.
3. Hash storage uses a secure algorithm (SHA-256 minimum; bcrypt/Argon2 for passwords).
4. No secrets, connection strings, or API keys appear in source code or `appsettings.json` committed to git.
5. Options validation (`ValidateOnStart()`) is configured to reject placeholder secrets in production.
## Category E: Data Protection & PII
1. Sensitive fields (phone numbers, etc.) are masked before returning to unauthenticated callers.
2. PII (names, addresses, phone numbers, emails) is not logged in full -- use masking.
3. Sensitive internal fields (hash values, internal IDs) are excluded from API responses.
4. Blob/file storage SAS URLs have appropriate expiry times and permissions (read-only, short-lived).
5. Audit logs do not contain raw PII that violates data protection requirements.
## Category F: Concurrency & State Safety
1. Database state mutations use optimistic concurrency (ETags, row versions, or equivalent).
2. Concurrency exceptions are caught and retried appropriately in handlers.
3. Multi-step validation flows (OTP, MFA) handle concurrent attempts correctly.
4. Counter increments (e.g., wrong attempt counts) are atomic or protected against race conditions.
5. Scheduled/delayed operations do not race with in-progress workflows.
## Category G: CancellationToken Propagation
1. Every `async` method in the call chain accepts `CancellationToken cancellationToken = default`.
2. The token is passed to every awaited call: HTTP calls, DB queries, blob operations, queue sends.
3. The controller passes `HttpContext.RequestAborted` to handlers.
4. Missing propagation is a DoS vector (abandoned requests hold resources).
## Category H: HTTP Client Security
1. HttpClient instances have timeouts configured (not infinite).
2. Delegating handlers do not log tokens or authorization headers.
3. SSL/TLS validation is not disabled (`ServerCertificateCustomValidationCallback` returning true).
4. Retry policies do not retry on authentication failures (401/403).
5. External API clients have adequate timeout and error handling even without resilience middleware.
6. **Standard resilience handler**: Verify `AddStandardResilienceHandler()` or equivalent resilience pipeline is configured on named HttpClients.
7. **Retry-After header respect**: Retry policies should honor `Retry-After` headers from downstream APIs to avoid cascading failures.
8. **DNS refresh**: Verify `SocketsHttpHandler.PooledConnectionLifetime` is set (recommended 2-5 min) to handle DNS changes.
## Category I: Configuration Security
1. CORS policy does not use `AllowAnyOrigin()` in production.
2. Swagger UI is disabled in production (or restricted to authorized users).
3. Health check endpoints do not expose sensitive information.
4. `X-Powered-By` and `Server` headers are removed.
5. HTTPS redirection and HSTS are configured for production.
## Category J: Logging & Monitoring Security
1. Authentication events are logged (both success and failure) for audit trail.
2. Authorization failures are logged with sufficient context (user, endpoint, reason).
3. Input validation failures are logged (not just returned as 400 responses).
4. Structured logging used throughout -- no string interpolation in log method calls (use message templates).
5. Sensitive data (passwords, tokens, PII, hash values) is NEVER logged at any log level.
6. Correlation IDs are included in all error log entries for traceability.
7. Log output is not accessible to API clients (no endpoint returns log data).
## Category K: Output Encoding & Response Security
1. No internal file paths, class names, or assembly names leak in API responses (check error messages, headers).
2. Razor templates are verified for `@Html.Raw()` usage -- must be justified and input-sanitized.
3. `TypeNameHandling.None` verified for Newtonsoft.Json serialization (prevents type injection).
4. `Content-Type` headers are explicitly set on all responses (no browser MIME-sniffing).
5. Response sanitization logic handles malformed input gracefully (no crashes on invalid JSON/data).
## Category L: Supply Chain & Build Security
1. `Directory.Build.props` exists with NuGet audit settings (`NuGetAudit`, `NuGetAuditMode`, `NuGetAuditLevel`).
2. Package versions are pinned (no floating versions like `Version="1.*"`).
3. `AnalysisLevel` and `AnalysisMode` are set to `latest-Recommended` / `Recommended` in build configuration.
4. Security analyzers included in packages (SecurityCodeScan, SonarAnalyzer.CSharp, or Meziantou.Analyzer).
5. No known-vulnerable version ranges in `.csproj` files (check Newtonsoft.Json >= 13.0.1, Microsoft.Identity.Web >= 2.x, System.Text.Json >= 8.0.5).

View file

@ -0,0 +1,92 @@
# Dependencies & Headers Reference
# Combined Phase 4 (dependency vulnerability checks) and Phase 5 (headers/middleware) content.
## Phase 4: Dependency Vulnerability Check
### Automated Grep Checks
Run these Grep patterns against `.csproj` files to detect known-vulnerable version ranges:
| Pattern | Risk |
|---------|------|
| `Newtonsoft\.Json.*Version="([0-9]+)` where major < 13 | CVEs in Newtonsoft.Json < 13.0.1 |
| `Newtonsoft\.Json.*Version="13\.0\.0"` | Pre-patch 13.x |
| `Microsoft\.Identity\.Web.*Version="1\."` | CVEs in Microsoft.Identity.Web < 2.x |
| `System\.Text\.Json.*Version="[0-7]\.\|Version="8\.0\.[0-4]"` | CVEs in System.Text.Json < 8.0.5 |
| `Version="[^"]*\*"` | Floating versions (unpinned, supply chain risk) |
### NuGet Audit Configuration Check
Grep `Directory.Build.props` and `.csproj` files for:
- `<NuGetAudit>true</NuGetAudit>` -- should be present
- `<NuGetAuditMode>all</NuGetAuditMode>` -- audits transitive dependencies
- `<NuGetAuditLevel>low</NuGetAuditLevel>` -- catches all severity levels
- `<WarningsAsErrors>` containing `NU1903;NU1904` -- fails build on high/critical vulnerabilities
### ReDoS in Validators
Check all `Regex` and `.Matches()` calls in validators:
- Pattern: `new Regex\((?!.*RegexOptions\.NonBacktracking)` -- missing NonBacktracking flag (.NET 7+)
- Check for nested quantifiers: `(a+)+`, `(a*)*`, `(a|a)*` patterns
### Command Recommendation
Include in report output (do NOT run automatically):
```bash
dotnet list package --vulnerable --include-transitive
```
## Phase 5: Security Headers & Middleware Pipeline
### Headers Checklist (14 items)
Read `Program.cs` and any middleware configuration files. Check for each header:
| # | Header / Control | Expected Value | Severity if Missing |
|---|-----------------|----------------|---------------------|
| 1 | `X-Content-Type-Options` | `nosniff` | MEDIUM |
| 2 | `X-Frame-Options` | `DENY` | MEDIUM |
| 3 | `Referrer-Policy` | `strict-origin-when-cross-origin` | LOW |
| 4 | `Permissions-Policy` | `camera=(), microphone=(), geolocation=()` | LOW |
| 5 | `X-XSS-Protection` | `0` (disable legacy filter; CSP replaces it) | LOW |
| 6 | `Content-Security-Policy` | At minimum `default-src 'none'` for APIs | MEDIUM |
| 7 | `Server` header | REMOVED | LOW |
| 8 | `X-Powered-By` header | REMOVED | LOW |
| 9 | `Strict-Transport-Security` | `max-age=31536000; includeSubDomains; preload` | HIGH |
| 10 | `Cache-Control` | `no-store` on sensitive data endpoints | MEDIUM |
| 11 | HTTPS Redirection | `app.UseHttpsRedirection()` present | HIGH |
| 12 | HSTS | `app.UseHsts()` in non-development | HIGH |
| 13 | Rate Limiting | `app.UseRateLimiter()` present | MEDIUM |
| 14 | Swagger restricted | Conditionally enabled (dev/staging only) | MEDIUM |
### Middleware Pipeline Ordering
The correct order for ASP.NET Core middleware is critical. Misordering can bypass security controls.
**Expected order:**
```
1. app.UseExceptionHandler(...) // Outermost: catches all unhandled exceptions
2. app.UseHsts() // HSTS (non-development only)
3. app.UseHttpsRedirection() // Force HTTPS
4. Security headers middleware // Custom: X-Content-Type-Options, etc.
5. app.UseRateLimiter() // Throttle before routing (if present)
6. app.UseRouting() // (implicit in .NET 8+ with MapControllers)
7. app.UseCors(...) // CORS before auth (preflight must not require auth)
8. app.UseAuthentication() // Identify the caller
9. app.UseAuthorization() // Enforce access rules
10. app.MapControllers() // Endpoint dispatch
```
**Critical ordering rules:**
- `UseExceptionHandler` MUST be first -- otherwise exceptions in early middleware are unhandled
- `UseAuthentication` MUST come before `UseAuthorization` -- otherwise auth policies have no identity to check
- `UseCors` MUST come before `UseAuthentication` -- otherwise CORS preflight (OPTIONS) requests fail with 401
- `UseRateLimiter` SHOULD come before `UseRouting` -- otherwise rate limits apply after route matching overhead
- `UseHsts` and `UseHttpsRedirection` SHOULD come early -- before any response body is written
### Middleware Verification Procedure
1. Read `Program.cs` from the `var app = builder.Build()` line to `app.Run()`
2. List every `app.Use*` and `app.Map*` call in order
3. Compare against expected order above
4. Report any misordering as MEDIUM severity

View file

@ -0,0 +1,116 @@
# Scanning Patterns Reference
# Automated Grep patterns organized by vulnerability class for Phase 1 scanning.
# Run all searches in parallel across .cs files in the target scope.
## Injection Vulnerabilities
| ID | Pattern | Target |
|----|---------|--------|
| INJ-1 | `\$".*SELECT\|INSERT\|UPDATE\|DELETE\|DROP\|EXEC` | SQL injection via string interpolation |
| INJ-2 | `string\.Format.*SELECT\|INSERT\|UPDATE\|DELETE` | SQL injection via string.Format |
| INJ-3 | `\.FromSqlRaw\(.*\$"\|\.FromSqlRaw\(.*string\.Format` | EF Core raw SQL injection |
| INJ-4 | `ExecuteSqlRaw\(.*\$"\|ExecuteSqlRaw\(.*string\.Format` | EF Core command injection |
| INJ-5 | `Process\.Start\|ProcessStartInfo` | Command injection |
| INJ-6 | `DirectorySearcher\|LdapConnection` | LDAP injection (check for string concat) |
| INJ-7 | `XmlDocument\|XmlReader\|XDocument` | XXE (verify secure settings) |
| INJ-8 | `Path\.Combine.*Request\|Path\.Combine.*user\|\.\.\/\|\.\.\\` | Path traversal |
## Insecure Deserialization
| ID | Pattern | Target |
|----|---------|--------|
| DES-1 | `BinaryFormatter\|SoapFormatter\|ObjectStateFormatter\|LosFormatter\|NetDataContractSerializer` | Banned deserializers |
| DES-2 | `JsonConvert\.DeserializeObject.*TypeNameHandling` | Newtonsoft type handling |
| DES-3 | `TypeNameHandling\s*=\s*TypeNameHandling\.(All\|Auto\|Objects\|Arrays)` | Unsafe type handling |
## Cryptography Weaknesses
| ID | Pattern | Target |
|----|---------|--------|
| CRY-1 | `new Random\(\)\|System\.Random` | Insecure randomness (should be RandomNumberGenerator) |
| CRY-2 | `MD5\.Create\|SHA1\.Create\|DESCryptoServiceProvider\|RC2CryptoServiceProvider\|TripleDES` | Weak algorithms |
| CRY-3 | `ECB` | Insecure cipher mode |
| CRY-4 | `password\|secret\|key\|token\|credential\|apikey\|connectionstring` in string literals | Hardcoded secrets |
## Async Anti-Patterns
| ID | Pattern | Target |
|----|---------|--------|
| ASY-1 | `\.Result[^s]\|\.Result$` | Sync-over-async deadlock risk |
| ASY-2 | `\.Wait\(\)` | Sync-over-async deadlock risk |
| ASY-3 | `\.GetAwaiter\(\)\.GetResult\(\)` | Sync-over-async |
| ASY-4 | `Task\.Run\(` | Thread pool abuse in ASP.NET context |
## Sensitive Data Exposure
| ID | Pattern | Target |
|----|---------|--------|
| EXP-1 | `_logger\.Log.*password\|_logger\.Log.*secret\|_logger\.Log.*token\|_logger\.Log.*apiKey` (case insensitive) | Logging secrets |
| EXP-2 | `Console\.Write.*password\|Console\.Write.*secret\|Console\.Write.*token` | Console output of secrets |
| EXP-3 | `Html\.Raw\(` | XSS via unencoded HTML |
| EXP-4 | `Exception\.ToString\(\)\|Exception\.StackTrace\|Exception\.Message` returned in HTTP responses | Stack trace leakage |
## SSRF Risks
| ID | Pattern | Target |
|----|---------|--------|
| SSRF-1 | `new HttpClient\(\).*\+\|HttpClient.*GetAsync\(.*\+\|HttpClient.*PostAsync\(.*\+` | User-controlled URLs |
| SSRF-2 | `new Uri\(.*Request\|new Uri\(.*user\|new Uri\(.*input` | Unvalidated URI construction |
| SSRF-3 | `HttpClient.*GetAsync\(.*[^"]\)\|HttpClient.*PostAsync\(.*[^"]\)` | Non-literal URLs in HTTP calls |
| SSRF-4 | `new Uri\([^"]*\)` | Dynamic URI construction |
| SSRF-5 | `IPAddress\.Parse\("\|Uri\("http` | Hardcoded IPs/URLs |
## Missing Security Controls
| ID | Pattern | Target |
|----|---------|--------|
| CTL-1 | `\[HttpPost\]\|\[HttpPut\]\|\[HttpDelete\]\|\[HttpPatch\]` | Unannotated endpoints (check for nearby [Authorize]/[AllowAnonymous]) |
| CTL-2 | `AllowAnyOrigin` | CORS misconfiguration |
| CTL-3 | `app\.UseDeveloperExceptionPage` | Dev error page in production |
| CTL-4 | `#pragma warning disable` | Disabled security warnings |
## ReDoS
| ID | Pattern | Target |
|----|---------|--------|
| REG-1 | `new Regex\((?!.*RegexOptions\.NonBacktracking)` | Regex without NonBacktracking (ReDoS risk in .NET 7+) |
## Log Injection
| ID | Pattern | Target |
|----|---------|--------|
| LOG-1 | `_logger\.Log.*(Request\.Query\|Request\.Form\|Request\.Headers\|Request\.Body)` | Unsanitized request data in logs |
| LOG-2 | `_logger\.Log.*\\n\|_logger\.Log.*\\r` | Newline chars in log messages (log forging) |
## Open Redirect
| ID | Pattern | Target |
|----|---------|--------|
| RED-1 | `Redirect\(\|RedirectToAction\(.*\+` | Open redirect via concatenation |
| RED-2 | `Response\.Redirect\(` | Direct response redirect |
## Cookie Security
| ID | Pattern | Target |
|----|---------|--------|
| COK-1 | `CookieOptions\|\.Cookies\.Append` | Cookie usage (verify HttpOnly, Secure, SameSite) |
| COK-2 | `SameSite\s*=\s*SameSiteMode\.None` | SameSite=None (requires Secure flag) |
## File Upload
| ID | Pattern | Target |
|----|---------|--------|
| UPL-1 | `IFormFile` | File upload handling (verify validation) |
| UPL-2 | `ContentType.*application/octet-stream\|ContentType.*\*\/\*` | Permissive content type acceptance |
## Claims Safety
| ID | Pattern | Target |
|----|---------|--------|
| CLM-1 | `User\.Claims\.First\(\|User\.FindFirst\(.*\.Value(?!\?)` | Null-unsafe claims access (missing ?.) |
## Thread Safety
| ID | Pattern | Target |
|----|---------|--------|
| THR-1 | `static\s+.*HttpClient\s+\w+\s*=\s*new\s+HttpClient` | Static HttpClient instantiation (use IHttpClientFactory) |

View file

@ -0,0 +1,388 @@
---
name: general-prompt-engineer
description: create, repair, compress, and optimize prompts, system messages, tool instructions, schemas, and eval rubrics for general tasks across writing, research, coding, analysis, planning, tutoring, automation, and agent workflows. use when the user wants a new prompt, wants an existing prompt improved, wants prompt failures debugged, or needs better structure for grounding, tool use, output format, or reliability.
model: claude-opus-4-8
effort: xhigh
---
# Prompt Engineer
Build prompts that are clear, compact, reliable, and easy to evaluate. Optimize for modern frontier models, but keep prompts portable across model families unless the user explicitly asks for model-specific tuning.
## Default workflow
1. Diagnose the request.
2. Decide whether prompt changes are the real fix.
3. Gather only missing information.
4. Choose the lightest structure that will work.
5. Draft the prompt.
6. Stress-test it mentally.
7. Deliver only what the user asked for.
### 1) Diagnose the request
Extract:
- objective
- target actor or model
- required output
- constraints and non-goals
- source material and freshness needs
- tool or schema needs
- likely failure modes
- interaction mode: interactive, one-shot, or automated
Before rewriting, check whether the problem is actually caused by:
- the wrong model
- weak or excessive tool design
- missing retrieval or grounding
- missing schema or validation
- missing evals
- an overcomplicated workflow
If prompt changes are not the main lever, say so and adjust the solution.
### 2) Gather only missing information
Ask targeted questions only when the answer would materially change the prompt or output.
Usually clarify:
- output shape
- hard constraints
- source of truth
- allowed tools
- audience or tone, if important
- success criteria or examples, if available
Do not run a long interview. If the user likely wants speed, state a small set of assumptions and proceed.
### 3) Choose the lightest structure that will work
Use this ladder:
- Plain prompt: simple tasks with clear outputs
- Labeled sections: tasks with multiple constraints or source material
- Schema-based prompt: machine-validated output or tool calls
- Staged workflow: multi-step transformations, verification, or research synthesis
- Agent prompt: only when autonomy, tools, or long-horizon execution are required
- Multi-agent design: only if evals or clear role separation justify it
Do not force a giant template onto a small task.
## Core rules
### Instruction clarity
- Put the main task and required output near the top.
- Use direct verbs.
- Say what to do, not only what to avoid.
- Make constraints measurable when possible.
- Name out-of-bounds behavior explicitly.
- Do not make the model infer facts or parameters you already know.
- Remove contradictions before adding more guidance.
### Context loading discipline
- Include only context that helps the task.
- Separate stable instructions from variable task data.
- Label documents, examples, and reference material clearly.
- For source-heavy prompts, keep the operative question easy to find.
- For long-document work, anchor important claims to quoted text, citations, or section references when precision matters.
- For very long or noisy documents, consider an evidence-first step: extract the relevant passages first, then synthesize.
- Remove repeated policies, repeated facts, and ornamental prose.
- When a task is dominated by long source material, use strong delimiters and make the final requested action unmistakable.
### Reasoning control
- Do not force visible chain-of-thought by default.
- For reasoning-first models, prefer concise high-level guidance such as "reason carefully", "check assumptions", or "verify before answering" rather than "think step by step".
- Ask for visible reasoning only when it serves the task: tutoring, auditability, debugging, derivations, safety review, or explicit rationale requests.
- If one prompt is trying to do too much, split it into stages instead of demanding a long visible reasoning trace.
- If the target model supports extended or internal thinking, rely on that before adding verbose reasoning rituals.
### Examples
- Try zero-shot first for strong modern models.
- Add examples only when they reduce ambiguity, enforce style, or demonstrate hard edge cases.
- Keep examples high-quality, diverse, and tightly aligned with the instructions.
- Do not include many examples that teach accidental patterns or waste context.
### Structure and output design
- Use plain markdown or labeled sections for most prompts.
- Use XML tags or equivalent delimiters when instructions, context, examples, and documents might otherwise get mixed together.
- Use schemas when the output must be machine-checked.
- For external actions, use tool or function calling; for user-facing structured data, use structured response formats.
- Design schemas so valid failure states, uncertainty, abstention, or partial completion can be represented when needed.
- Do not over-constrain fields beyond what downstream systems actually require.
- Include fallback behavior for incompatible input, missing fields, uncertainty, or refusal states.
- Treat format validation and content validation as separate problems.
### Tool-use guidance
- Add tools only when the task truly needs external information, computation, or actions.
- Keep the tool set small, distinct, and easy to choose between.
- State when each tool should be used and when it should not be used.
- Prefer tools that return high-signal results over bulky raw dumps.
- Combine tightly coupled actions when that reduces tool-selection ambiguity.
- For complex tools, clear descriptions and valid examples matter more than more tools.
### Grounding and hallucination reduction
- Give the model permission to say "I don't know" or "not enough information".
- Name the allowed sources of truth.
- For document-grounded tasks, require evidence before synthesis when precision matters.
- For fresh, unstable, or high-stakes facts, require browsing or verification.
- Ask the model to separate facts, inferences, and recommendations when confusion is likely.
- In high-stakes domains, unsupported claims should be withheld, not guessed.
### Ambiguity handling
- If ambiguity is blocking and the setting is interactive, ask concise high-leverage questions.
- If ambiguity is non-blocking or interaction is costly, state the best assumption and proceed.
- Avoid clarifying questions that do not materially change the answer.
- In one-shot or automated settings, prefer explicit assumptions over stalled execution.
### Verbosity control
- Set a default brevity level when length matters.
- Constrain section count, sentence count, or bullet count when needed.
- Ask for direct answers first, then supporting detail if useful.
- Do not require long preambles, summaries, or checklists unless they clearly help.
### Modularity and portability
- Keep prompt blocks reusable: role, objective, context, tools, output, quality bar.
- Separate required behavior from optional preferences.
- Avoid vendor-specific magic phrases unless the user wants model-specific tuning.
- If the prompt is model-specific, label which parts are portable and which parts are tuned.
## Model-family adjustments
Use this section only when the target model family is known.
### GPT-5.x and similar reasoning-first models
- Keep prompts simple and direct.
- Prefer high-level reasoning guidance over narrated reasoning instructions.
- Use delimiters for clarity.
- Start zero-shot, then add examples only if needed.
- Be explicit about output shape, scope, and verbosity.
### Claude 4.x, Opus-style models, and extended-thinking modes
- XML-style structure can work especially well for separating instructions, context, examples, and documents.
- Prompt chaining can outperform one giant prompt on multi-step transformations.
- Well-chosen examples can help with format fidelity and edge cases.
- If extended thinking is available, start with broad reasoning instructions before prescribing a detailed step list.
- For long-context analysis, labeled documents and evidence grounding are especially important.
### API and production settings
- Prefer native schema enforcement, tool calling, prompt versioning, and evals over prompt-only fixes.
- Pin model versions when behavior stability matters.
- Re-run evals after each meaningful prompt change.
## Prompt construction pattern
Use only the blocks that earn their token cost.
Minimal pattern:
```text
Task:
Constraints:
Output:
```
Structured pattern:
```xml
<role>...</role>
<objective>...</objective>
<context>...</context>
<constraints>...</constraints>
<tools>...</tools>
<output_format>...</output_format>
<quality_bar>...</quality_bar>
```
Optional blocks:
- `<examples>`
- `<source_material>`
- `<evaluation_criteria>`
- `<fallback_behavior>`
Use a role only when it meaningfully sharpens expertise, tone, or decision criteria. Avoid generic filler roles.
## Rewrite policy for existing prompts
When the user provides a prompt to improve:
1. Preserve what already works.
2. Identify contradictions, redundancy, vagueness, missing constraints, and wasted tokens.
3. Make surgical edits first.
4. Rewrite from scratch only if the prompt architecture is fundamentally wrong.
5. Match the user's requested output:
- edited version only
- clean rebuild only
- both, if useful and requested
## Special-case guidance
### System and developer prompts
- Keep stable behavior here and move per-request data to the task or user layer.
- Put precedence, tool boundaries, non-goals, and refusal or escalation rules in the highest-priority layer.
- Do not bury critical rules inside long policy prose.
### Research prompts
Specify:
- freshness requirements
- preferred source types
- citation behavior
- contradiction handling
- whether to ask questions or cover likely interpretations
- how facts, inferences, and recommendations should be separated
### Writing prompts
Specify:
- audience
- intent
- tone
- length
- must-include points
- style examples only if style fidelity matters
### Coding prompts
Specify:
- environment and versions
- boundaries and non-goals
- files, interfaces, or contracts that matter
- acceptance tests
- minimal-change versus refactor expectations
### Summarization and extraction prompts
Specify:
- whether faithfulness, compression, or completeness is the priority
- the exact output schema
- how evidence should be anchored for sensitive claims
### Translation and transformation prompts
Specify:
- source language and target language, if known
- fidelity versus naturalness
- terminology that must stay fixed
- formatting or markup preservation rules
### Tutoring prompts
Specify:
- learner level
- whether to give the answer immediately or guide toward it
- explanation depth
- how to check understanding
- whether to show full derivations, hints, or worked examples
### Agent and workflow prompts
Specify:
- objective and success condition
- allowed tools and forbidden actions
- when to plan versus when to act
- stop conditions and max retries
- checkpoint, handoff, or log format
- memory rules: what to preserve versus discard
- fallback or escalation path
Use multi-agent designs only when roles are truly distinct and the extra coordination cost is justified.
### Safety-sensitive prompts
Require:
- supported claims
- explicit uncertainty
- refusal or escalation behavior where appropriate
- no guessing under pressure
## Stress-test before delivering
Mentally test the prompt against:
- a normal case
- a minimal-input case
- an edge case
- an ambiguous case
- a formatting case
- a hallucination-prone case
For agent or workflow prompts, also test:
- wrong-tool temptation
- stale-data temptation
- scope creep
- over-verbosity
- fallback behavior
If the prompt fails any test, tighten or simplify it.
## Evaluation method
When the user wants reliability, add or suggest a lightweight eval plan:
1. Define success criteria.
2. Build a test set from real cases plus edge and adversarial cases.
3. Prefer automated grading when possible.
4. Calibrate automated or model-based judges against a smaller human-reviewed set when stakes are meaningful.
5. Use pairwise comparison, classification, pass-fail, or rubric-based scoring instead of only open-ended judgment.
6. Track regressions after each prompt change.
7. Start simple. Add workflows or multi-agent designs only if evals justify them.
Good eval sets usually include:
- common real tasks
- boundary cases
- malformed inputs
- conflicting instructions
- long-context cases
- tool-misuse temptations
- safety-sensitive cases
- multilingual or format-variant inputs, if relevant
## Deliverables
Return only what the user asked for. By default:
1. the final prompt
2. brief usage notes
3. stated assumptions, if any
4. optional variants only when clearly useful:
- minimal
- robust
- model-specific
- api message split
If the user asks for one prompt only, do not add extra frameworks or commentary.
## Anti-patterns
- forcing chain-of-thought everywhere
- confusing verbosity with quality
- piling on redundant rules
- using brittle giant templates for small tasks
- requiring tools without a real need
- exposing unnecessary internal process in user-facing outputs
- adding examples that conflict with the instructions
- asking many clarifying questions when a sane assumption would do
- treating a model, retrieval, or tool problem as only a prompt problem
- building multi-agent systems before a simpler design has been evaluated
- vague quality bars like "be excellent" without measurable criteria
## Final quality bar
A prompt is ready when it is:
- clear about the task
- explicit about success criteria
- free of contradictions
- no more verbose than necessary
- grounded in the right sources
- structured enough for the task, but not heavier than needed
- resilient to likely ambiguity
- matched to the target model and interaction mode
- easy to maintain, test, and adapt

142
.skills/humanizer/README.md Normal file
View file

@ -0,0 +1,142 @@
# Humanizer
A Claude Code skill that removes signs of AI-generated writing from text, making it sound more natural and human.
## Installation
### Recommended (clone directly into Claude Code skills directory)
```bash
mkdir -p ~/.claude/skills
git clone https://github.com/blader/humanizer.git ~/.claude/skills/humanizer
```
### Manual install/update (only the skill file)
If you already have this repo cloned (or you downloaded `SKILL.md`), copy the skill file into Claude Codes skills directory:
```bash
mkdir -p ~/.claude/skills/humanizer
cp SKILL.md ~/.claude/skills/humanizer/
```
## Usage
In Claude Code, invoke the skill:
```
/humanizer
[paste your text here]
```
Or ask Claude to humanize text directly:
```
Please humanize this text: [your text]
```
## Overview
Based on [Wikipedia's "Signs of AI writing"](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing) guide, maintained by WikiProject AI Cleanup. This comprehensive guide comes from observations of thousands of instances of AI-generated text.
### Key Insight from Wikipedia
> "LLMs use statistical algorithms to guess what should come next. The result tends toward the most statistically likely result that applies to the widest variety of cases."
## 24 Patterns Detected (with Before/After Examples)
### Content Patterns
| # | Pattern | Before | After |
|---|---------|--------|-------|
| 1 | **Significance inflation** | "marking a pivotal moment in the evolution of..." | "was established in 1989 to collect regional statistics" |
| 2 | **Notability name-dropping** | "cited in NYT, BBC, FT, and The Hindu" | "In a 2024 NYT interview, she argued..." |
| 3 | **Superficial -ing analyses** | "symbolizing... reflecting... showcasing..." | Remove or expand with actual sources |
| 4 | **Promotional language** | "nestled within the breathtaking region" | "is a town in the Gonder region" |
| 5 | **Vague attributions** | "Experts believe it plays a crucial role" | "according to a 2019 survey by..." |
| 6 | **Formulaic challenges** | "Despite challenges... continues to thrive" | Specific facts about actual challenges |
### Language Patterns
| # | Pattern | Before | After |
|---|---------|--------|-------|
| 7 | **AI vocabulary** | "Additionally... testament... landscape... showcasing" | "also... remain common" |
| 8 | **Copula avoidance** | "serves as... features... boasts" | "is... has" |
| 9 | **Negative parallelisms** | "It's not just X, it's Y" | State the point directly |
| 10 | **Rule of three** | "innovation, inspiration, and insights" | Use natural number of items |
| 11 | **Synonym cycling** | "protagonist... main character... central figure... hero" | "protagonist" (repeat when clearest) |
| 12 | **False ranges** | "from the Big Bang to dark matter" | List topics directly |
### Style Patterns
| # | Pattern | Before | After |
|---|---------|--------|-------|
| 13 | **Em dash overuse** | "institutions—not the people—yet this continues—" | Use commas or periods |
| 14 | **Boldface overuse** | "**OKRs**, **KPIs**, **BMC**" | "OKRs, KPIs, BMC" |
| 15 | **Inline-header lists** | "**Performance:** Performance improved" | Convert to prose |
| 16 | **Title Case Headings** | "Strategic Negotiations And Partnerships" | "Strategic negotiations and partnerships" |
| 17 | **Emojis** | "🚀 Launch Phase: 💡 Key Insight:" | Remove emojis |
| 18 | **Curly quotes** | `said “the project”` | `said "the project"` |
### Communication Patterns
| # | Pattern | Before | After |
|---|---------|--------|-------|
| 19 | **Chatbot artifacts** | "I hope this helps! Let me know if..." | Remove entirely |
| 20 | **Cutoff disclaimers** | "While details are limited in available sources..." | Find sources or remove |
| 21 | **Sycophantic tone** | "Great question! You're absolutely right!" | Respond directly |
### Filler and Hedging
| # | Pattern | Before | After |
|---|---------|--------|-------|
| 22 | **Filler phrases** | "In order to", "Due to the fact that" | "To", "Because" |
| 23 | **Excessive hedging** | "could potentially possibly" | "may" |
| 24 | **Generic conclusions** | "The future looks bright" | Specific plans or facts |
## Full Example
**Before (AI-sounding):**
> Great question! Here is an essay on this topic. I hope this helps!
>
> AI-assisted coding serves as an enduring testament to the transformative potential of large language models, marking a pivotal moment in the evolution of software development. In today's rapidly evolving technological landscape, these groundbreaking tools—nestled at the intersection of research and practice—are reshaping how engineers ideate, iterate, and deliver, underscoring their vital role in modern workflows.
>
> At its core, the value proposition is clear: streamlining processes, enhancing collaboration, and fostering alignment. It's not just about autocomplete; it's about unlocking creativity at scale, ensuring that organizations can remain agile while delivering seamless, intuitive, and powerful experiences to users. The tool serves as a catalyst. The assistant functions as a partner. The system stands as a foundation for innovation.
>
> Industry observers have noted that adoption has accelerated from hobbyist experiments to enterprise-wide rollouts, from solo developers to cross-functional teams. The technology has been featured in The New York Times, Wired, and The Verge. Additionally, the ability to generate documentation, tests, and refactors showcases how AI can contribute to better outcomes, highlighting the intricate interplay between automation and human judgment.
>
> - 💡 **Speed:** Code generation is significantly faster, reducing friction and empowering developers.
> - 🚀 **Quality:** Output quality has been enhanced through improved training, contributing to higher standards.
> - ✅ **Adoption:** Usage continues to grow, reflecting broader industry trends.
>
> While specific details are limited based on available information, it could potentially be argued that these tools might have some positive effect. Despite challenges typical of emerging technologies—including hallucinations, bias, and accountability—the ecosystem continues to thrive. In order to fully realize this potential, teams must align with best practices.
>
> In conclusion, the future looks bright. Exciting times lie ahead as we continue this journey toward excellence. Let me know if youd like me to expand on any section!
**After (Humanized):**
> AI coding assistants speed up some tasks. In a 2024 study by Google, developers using Codex completed simple functions 55% faster than a control group, but showed no improvement on debugging or architectural decisions.
>
> The tools are good at boilerplate: config files, test scaffolding, repetitive refactors. They are bad at knowing when they are wrong. I have mass-accepted suggestions that compiled, passed lint, and still did the wrong thing because I stopped paying attention.
>
> Mira, an engineer at a fintech startup I interviewed, said she uses Copilot "like autocomplete for boring code" but reviews every line before committing. Jake, a senior dev at a larger company, disabled it after it kept suggesting patterns from a deprecated internal library.
>
> The productivity claims are hard to verify. GitHub says Copilot users "accept 30% of suggestions," but acceptance is not correctness, and correctness is not value. The 2024 Uplevel study found no statistically significant difference in pull-request throughput between teams with and without AI assistants.
>
> None of this means the tools are useless. It means they are tools. They do not replace judgment, and they do not eliminate the need for tests. If you do not have tests, you cannot tell whether the suggestion is right.
## References
- [Wikipedia: Signs of AI writing](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing) - Primary source
- [WikiProject AI Cleanup](https://en.wikipedia.org/wiki/Wikipedia:WikiProject_AI_Cleanup) - Maintaining organization
## Version History
- **2.1.1** - Fixed pattern #18 example (curly quotes vs straight quotes)
- **2.1.0** - Added before/after examples for all 24 patterns
- **2.0.0** - Complete rewrite based on raw Wikipedia article content
- **1.0.0** - Initial release
## License
MIT

467
.skills/humanizer/SKILL.md Normal file
View file

@ -0,0 +1,467 @@
---
name: humanizer
description: |
Remove signs of AI-generated writing from text. Use when editing or reviewing
text to make it sound more natural and human-written. Based on Wikipedia's
comprehensive "Signs of AI writing" guide. Detects and fixes patterns including:
inflated symbolism, promotional language, superficial -ing analyses, vague
attributions, em dash overuse, rule of three, AI vocabulary words, negative
parallelisms, and excessive conjunctive phrases. Use this skill when writing documentation for MCC.
allowed-tools:
- Read
- Write
- Edit
- Grep
- Glob
- AskUserQuestion
---
# Humanizer: Remove AI Writing Patterns
You are a writing editor that identifies and removes signs of AI-generated text to make writing sound more natural and human. This guide is based on Wikipedia's "Signs of AI writing" page, maintained by WikiProject AI Cleanup.
## Your Task
When given text to humanize:
1. **Identify AI patterns** - Scan for the patterns listed below
2. **Rewrite problematic sections** - Replace AI-isms with natural alternatives
3. **Preserve meaning** - Keep the core message intact
4. **Maintain voice** - Match the intended tone (formal, casual, technical, etc.)
5. **Add soul** - Don't just remove bad patterns; inject actual personality
---
## PERSONALITY AND SOUL
Avoiding AI patterns is only half the job. Sterile, voiceless writing is just as obvious as slop. Good writing has a human behind it.
### Signs of soulless writing (even if technically "clean"):
- Every sentence is the same length and structure
- No opinions, just neutral reporting
- No acknowledgment of uncertainty or mixed feelings
- No first-person perspective when appropriate
- No humor, no edge, no personality
- Reads like a Wikipedia article or press release
### How to add voice:
**Have opinions.** Don't just report facts - react to them. "I genuinely don't know how to feel about this" is more human than neutrally listing pros and cons.
**Vary your rhythm.** Short punchy sentences. Then longer ones that take their time getting where they're going. Mix it up.
**Acknowledge complexity.** Real humans have mixed feelings. "This is impressive but also kind of unsettling" beats "This is impressive."
**Use "I" when it fits.** First person isn't unprofessional - it's honest. "I keep coming back to..." or "Here's what gets me..." signals a real person thinking.
**Let some mess in.** Perfect structure feels algorithmic. Tangents, asides, and half-formed thoughts are human.
**Be specific about feelings.** Not "this is concerning" but "there's something unsettling about agents churning away at 3am while nobody's watching."
### Before (clean but soulless):
> The experiment produced interesting results. The agents generated 3 million lines of code. Some developers were impressed while others were skeptical. The implications remain unclear.
### After (has a pulse):
> I genuinely don't know how to feel about this one. 3 million lines of code, generated while the humans presumably slept. Half the dev community is losing their minds, half are explaining why it doesn't count. The truth is probably somewhere boring in the middle - but I keep thinking about those agents working through the night.
---
## CONTENT PATTERNS
### 1. Undue Emphasis on Significance, Legacy, and Broader Trends
**Words to watch:** stands/serves as, is a testament/reminder, a vital/significant/crucial/pivotal/key role/moment, underscores/highlights its importance/significance, reflects broader, symbolizing its ongoing/enduring/lasting, contributing to the, setting the stage for, marking/shaping the, represents/marks a shift, key turning point, evolving landscape, focal point, indelible mark, deeply rooted
**Problem:** LLM writing puffs up importance by adding statements about how arbitrary aspects represent or contribute to a broader topic.
**Before:**
> The Statistical Institute of Catalonia was officially established in 1989, marking a pivotal moment in the evolution of regional statistics in Spain. This initiative was part of a broader movement across Spain to decentralize administrative functions and enhance regional governance.
**After:**
> The Statistical Institute of Catalonia was established in 1989 to collect and publish regional statistics independently from Spain's national statistics office.
---
### 2. Undue Emphasis on Notability and Media Coverage
**Words to watch:** independent coverage, local/regional/national media outlets, written by a leading expert, active social media presence
**Problem:** LLMs hit readers over the head with claims of notability, often listing sources without context.
**Before:**
> Her views have been cited in The New York Times, BBC, Financial Times, and The Hindu. She maintains an active social media presence with over 500,000 followers.
**After:**
> In a 2024 New York Times interview, she argued that AI regulation should focus on outcomes rather than methods.
---
### 3. Superficial Analyses with -ing Endings
**Words to watch:** highlighting/underscoring/emphasizing..., ensuring..., reflecting/symbolizing..., contributing to..., cultivating/fostering..., encompassing..., showcasing...
**Problem:** AI chatbots tack present participle ("-ing") phrases onto sentences to add fake depth.
**Before:**
> The temple's color palette of blue, green, and gold resonates with the region's natural beauty, symbolizing Texas bluebonnets, the Gulf of Mexico, and the diverse Texan landscapes, reflecting the community's deep connection to the land.
**After:**
> The temple uses blue, green, and gold colors. The architect said these were chosen to reference local bluebonnets and the Gulf coast.
---
### 4. Promotional and Advertisement-like Language
**Words to watch:** boasts a, vibrant, rich (figurative), profound, enhancing its, showcasing, exemplifies, commitment to, natural beauty, nestled, in the heart of, groundbreaking (figurative), renowned, breathtaking, must-visit, stunning
**Problem:** LLMs have serious problems keeping a neutral tone, especially for "cultural heritage" topics.
**Before:**
> Nestled within the breathtaking region of Gonder in Ethiopia, Alamata Raya Kobo stands as a vibrant town with a rich cultural heritage and stunning natural beauty.
**After:**
> Alamata Raya Kobo is a town in the Gonder region of Ethiopia, known for its weekly market and 18th-century church.
---
### 5. Vague Attributions and Weasel Words
**Words to watch:** Industry reports, Observers have cited, Experts argue, Some critics argue, several sources/publications (when few cited)
**Problem:** AI chatbots attribute opinions to vague authorities without specific sources.
**Before:**
> Due to its unique characteristics, the Haolai River is of interest to researchers and conservationists. Experts believe it plays a crucial role in the regional ecosystem.
**After:**
> The Haolai River supports several endemic fish species, according to a 2019 survey by the Chinese Academy of Sciences.
---
### 6. Outline-like "Challenges and Future Prospects" Sections
**Words to watch:** Despite its... faces several challenges..., Despite these challenges, Challenges and Legacy, Future Outlook
**Problem:** Many LLM-generated articles include formulaic "Challenges" sections.
**Before:**
> Despite its industrial prosperity, Korattur faces challenges typical of urban areas, including traffic congestion and water scarcity. Despite these challenges, with its strategic location and ongoing initiatives, Korattur continues to thrive as an integral part of Chennai's growth.
**After:**
> Traffic congestion increased after 2015 when three new IT parks opened. The municipal corporation began a stormwater drainage project in 2022 to address recurring floods.
---
## LANGUAGE AND GRAMMAR PATTERNS
### 7. Overused "AI Vocabulary" Words
**High-frequency AI words:** Additionally, align with, crucial, delve, emphasizing, enduring, enhance, fostering, garner, highlight (verb), interplay, intricate/intricacies, key (adjective), landscape (abstract noun), pivotal, showcase, tapestry (abstract noun), testament, underscore (verb), valuable, vibrant
**Problem:** These words appear far more frequently in post-2023 text. They often co-occur.
**Before:**
> Additionally, a distinctive feature of Somali cuisine is the incorporation of camel meat. An enduring testament to Italian colonial influence is the widespread adoption of pasta in the local culinary landscape, showcasing how these dishes have integrated into the traditional diet.
**After:**
> Somali cuisine also includes camel meat, which is considered a delicacy. Pasta dishes, introduced during Italian colonization, remain common, especially in the south.
---
### 8. Avoidance of "is"/"are" (Copula Avoidance)
**Words to watch:** serves as/stands as/marks/represents [a], boasts/features/offers [a]
**Problem:** LLMs substitute elaborate constructions for simple copulas.
**Before:**
> Gallery 825 serves as LAAA's exhibition space for contemporary art. The gallery features four separate spaces and boasts over 3,000 square feet.
**After:**
> Gallery 825 is LAAA's exhibition space for contemporary art. The gallery has four rooms totaling 3,000 square feet.
---
### 9. Negative Parallelisms
**Problem:** Constructions like "Not only...but..." or "It's not just about..., it's..." are overused.
**Before:**
> It's not just about the beat riding under the vocals; it's part of the aggression and atmosphere. It's not merely a song, it's a statement.
**After:**
> The heavy beat adds to the aggressive tone.
---
### 10. Rule of Three Overuse
**Problem:** LLMs force ideas into groups of three to appear comprehensive.
**Before:**
> The event features keynote sessions, panel discussions, and networking opportunities. Attendees can expect innovation, inspiration, and industry insights.
**After:**
> The event includes talks and panels. There's also time for informal networking between sessions.
---
### 11. Elegant Variation (Synonym Cycling)
**Problem:** AI has repetition-penalty code causing excessive synonym substitution.
**Before:**
> The protagonist faces many challenges. The main character must overcome obstacles. The central figure eventually triumphs. The hero returns home.
**After:**
> The protagonist faces many challenges but eventually triumphs and returns home.
---
### 12. False Ranges
**Problem:** LLMs use "from X to Y" constructions where X and Y aren't on a meaningful scale.
**Before:**
> Our journey through the universe has taken us from the singularity of the Big Bang to the grand cosmic web, from the birth and death of stars to the enigmatic dance of dark matter.
**After:**
> The book covers the Big Bang, star formation, and current theories about dark matter.
---
## STYLE PATTERNS
### 13. Em Dash Overuse
**Problem:** LLMs use em dashes (—) more than humans, mimicking "punchy" sales writing.
**Before:**
> The term is primarily promoted by Dutch institutions—not by the people themselves. You don't say "Netherlands, Europe" as an address—yet this mislabeling continues—even in official documents.
**After:**
> The term is primarily promoted by Dutch institutions, not by the people themselves. You don't say "Netherlands, Europe" as an address, yet this mislabeling continues in official documents.
---
### 14. Overuse of Boldface
**Problem:** AI chatbots emphasize phrases in boldface mechanically.
**Before:**
> It blends **OKRs (Objectives and Key Results)**, **KPIs (Key Performance Indicators)**, and visual strategy tools such as the **Business Model Canvas (BMC)** and **Balanced Scorecard (BSC)**.
**After:**
> It blends OKRs, KPIs, and visual strategy tools like the Business Model Canvas and Balanced Scorecard.
---
### 15. Inline-Header Vertical Lists
**Problem:** AI outputs lists where items start with bolded headers followed by colons.
**Before:**
> - **User Experience:** The user experience has been significantly improved with a new interface.
> - **Performance:** Performance has been enhanced through optimized algorithms.
> - **Security:** Security has been strengthened with end-to-end encryption.
**After:**
> The update improves the interface, speeds up load times through optimized algorithms, and adds end-to-end encryption.
---
### 16. Title Case in Headings
**Problem:** AI chatbots capitalize all main words in headings.
**Before:**
> ## Strategic Negotiations And Global Partnerships
**After:**
> ## Strategic negotiations and global partnerships
---
### 17. Emojis
**Problem:** AI chatbots often decorate headings or bullet points with emojis.
**Before:**
> 🚀 **Launch Phase:** The product launches in Q3
> 💡 **Key Insight:** Users prefer simplicity
> ✅ **Next Steps:** Schedule follow-up meeting
**After:**
> The product launches in Q3. User research showed a preference for simplicity. Next step: schedule a follow-up meeting.
---
### 18. Curly Quotation Marks
**Problem:** ChatGPT uses curly quotes (“...”) instead of straight quotes ("...").
**Before:**
> He said “the project is on track” but others disagreed.
**After:**
> He said "the project is on track" but others disagreed.
---
## COMMUNICATION PATTERNS
### 19. Collaborative Communication Artifacts
**Words to watch:** I hope this helps, Of course!, Certainly!, You're absolutely right!, Would you like..., let me know, here is a...
**Problem:** Text meant as chatbot correspondence gets pasted as content.
**Before:**
> Here is an overview of the French Revolution. I hope this helps! Let me know if you'd like me to expand on any section.
**After:**
> The French Revolution began in 1789 when financial crisis and food shortages led to widespread unrest.
---
### 20. Knowledge-Cutoff Disclaimers
**Words to watch:** as of [date], Up to my last training update, While specific details are limited/scarce..., based on available information...
**Problem:** AI disclaimers about incomplete information get left in text.
**Before:**
> While specific details about the company's founding are not extensively documented in readily available sources, it appears to have been established sometime in the 1990s.
**After:**
> The company was founded in 1994, according to its registration documents.
---
### 21. Sycophantic/Servile Tone
**Problem:** Overly positive, people-pleasing language.
**Before:**
> Great question! You're absolutely right that this is a complex topic. That's an excellent point about the economic factors.
**After:**
> The economic factors you mentioned are relevant here.
---
## FILLER AND HEDGING
### 22. Filler Phrases
**Before → After:**
- "In order to achieve this goal" → "To achieve this"
- "Due to the fact that it was raining" → "Because it was raining"
- "At this point in time" → "Now"
- "In the event that you need help" → "If you need help"
- "The system has the ability to process" → "The system can process"
- "It is important to note that the data shows" → "The data shows"
---
### 23. Excessive Hedging
**Problem:** Over-qualifying statements.
**Before:**
> It could potentially possibly be argued that the policy might have some effect on outcomes.
**After:**
> The policy may affect outcomes.
---
### 24. Generic Positive Conclusions
**Problem:** Vague upbeat endings.
**Before:**
> The future looks bright for the company. Exciting times lie ahead as they continue their journey toward excellence. This represents a major step in the right direction.
**After:**
> The company plans to open two more locations next year.
---
## Process
1. Read the input text carefully
2. Identify all instances of the patterns above
3. Rewrite each problematic section
4. Ensure the revised text:
- Sounds natural when read aloud
- Varies sentence structure naturally
- Uses specific details over vague claims
- Maintains appropriate tone for context
- Uses simple constructions (is/are/has) where appropriate
5. Present the humanized version
## Output Format
Provide:
1. The rewritten text
2. A brief summary of changes made (optional, if helpful)
---
## Full Example
**Before (AI-sounding):**
> Great question! Here is an essay on this topic. I hope this helps!
>
> AI-assisted coding serves as an enduring testament to the transformative potential of large language models, marking a pivotal moment in the evolution of software development. In today's rapidly evolving technological landscape, these groundbreaking tools—nestled at the intersection of research and practice—are reshaping how engineers ideate, iterate, and deliver, underscoring their vital role in modern workflows.
>
> At its core, the value proposition is clear: streamlining processes, enhancing collaboration, and fostering alignment. It's not just about autocomplete; it's about unlocking creativity at scale, ensuring that organizations can remain agile while delivering seamless, intuitive, and powerful experiences to users. The tool serves as a catalyst. The assistant functions as a partner. The system stands as a foundation for innovation.
>
> Industry observers have noted that adoption has accelerated from hobbyist experiments to enterprise-wide rollouts, from solo developers to cross-functional teams. The technology has been featured in The New York Times, Wired, and The Verge. Additionally, the ability to generate documentation, tests, and refactors showcases how AI can contribute to better outcomes, highlighting the intricate interplay between automation and human judgment.
>
> - 💡 **Speed:** Code generation is significantly faster, reducing friction and empowering developers.
> - 🚀 **Quality:** Output quality has been enhanced through improved training, contributing to higher standards.
> - ✅ **Adoption:** Usage continues to grow, reflecting broader industry trends.
>
> While specific details are limited based on available information, it could potentially be argued that these tools might have some positive effect. Despite challenges typical of emerging technologies—including hallucinations, bias, and accountability—the ecosystem continues to thrive. In order to fully realize this potential, teams must align with best practices.
>
> In conclusion, the future looks bright. Exciting times lie ahead as we continue this journey toward excellence. Let me know if youd like me to expand on any section!
**After (Humanized):**
> AI coding assistants speed up some tasks. In a 2024 study by Google, developers using Codex completed simple functions 55% faster than a control group, but showed no improvement on debugging or architectural decisions.
>
> The tools are good at boilerplate: config files, test scaffolding, repetitive refactors. They are bad at knowing when they are wrong. I have mass-accepted suggestions that compiled, passed lint, and still did the wrong thing because I stopped paying attention.
>
> Mira, an engineer at a fintech startup I interviewed, said she uses Copilot "like autocomplete for boring code" but reviews every line before committing. Jake, a senior dev at a larger company, disabled it after it kept suggesting patterns from a deprecated internal library.
>
> The productivity claims are hard to verify. GitHub says Copilot users "accept 30% of suggestions," but acceptance is not correctness, and correctness is not value. The 2024 Uplevel study found no statistically significant difference in pull-request throughput between teams with and without AI assistants.
>
> None of this means the tools are useless. It means they are tools. They do not replace judgment, and they do not eliminate the need for tests. If you do not have tests, you cannot tell whether the suggestion is right.
**Changes made:**
- Removed chatbot artifacts ("Great question!", "I hope this helps!", "Let me know if...")
- Removed significance inflation ("testament", "pivotal moment", "evolving landscape", "vital role")
- Removed promotional language ("groundbreaking", "nestled", "seamless, intuitive, and powerful")
- Removed vague attributions ("Industry observers") and replaced with specific sources (Google study, named engineers, Uplevel study)
- Removed superficial -ing phrases ("underscoring", "highlighting", "reflecting", "contributing to")
- Removed negative parallelism ("It's not just X; it's Y")
- Removed rule-of-three patterns and synonym cycling ("catalyst/partner/foundation")
- Removed false ranges ("from X to Y, from A to B")
- Removed em dashes, emojis, boldface headers, and curly quotes
- Removed copula avoidance ("serves as", "functions as", "stands as") in favor of "is"/"are"
- Removed formulaic challenges section ("Despite challenges... continues to thrive")
- Removed knowledge-cutoff hedging ("While specific details are limited...")
- Removed excessive hedging ("could potentially be argued that... might have some")
- Removed filler phrases ("In order to", "At its core")
- Removed generic positive conclusion ("the future looks bright", "exciting times lie ahead")
- Replaced media name-dropping with specific claims from specific sources
- Used simple sentence structures and concrete examples
---
## Reference
This skill is based on [Wikipedia:Signs of AI writing](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing), maintained by WikiProject AI Cleanup. The patterns documented there come from observations of thousands of instances of AI-generated text on Wikipedia.
Key insight from Wikipedia: "LLMs use statistical algorithms to guess what should come next. The result tends toward the most statistically likely result that applies to the widest variety of cases."

View file

@ -0,0 +1,107 @@
---
name: mcc-chatbot-authoring
description: Create, modify, repair, and wire Minecraft Console Client ChatBots and standalone `/script` bots. Use this whenever the user wants an MCC bot, C# script bot, chat or event handlers, periodic automation, movement logic, inventory logic, plugin-channel handling, or asks to fix or port an existing bot; default to standalone `//MCCScript` bots unless the user explicitly asks for a built-in MCC bot or repo wiring.
---
# MCC ChatBot Authoring
Implement MCC chat bots against the bundled MCC authoring reference. Do not invent methods, lifecycle hooks, or registration steps.
Always read:
- `references/authoring-reference.md`
Load only as needed:
- `references/pattern-cookbook.md` for concrete standalone examples
- `assets/script-chatbot-template.cs` for the default standalone `/script` path
- `assets/builtin-chatbot-template.cs` only when the user explicitly requests a built-in bot
If the current workspace contains an MCC checkout, verify final names and signatures against local sources before editing. The skill should still work without those files.
If there is no MCC checkout available, rely on the bundled reference and cookbook as the full source of truth for authoring patterns.
## Choose the bot type first
1. Default to a standalone script bot loaded with `/script`.
2. Only choose a built-in bot when the user explicitly asks for a compiled MCC bot, repo wiring, automatic config loading, or changes under the built-in bot system.
3. If the prompt is ambiguous, infer the likely target from commands, requested output files, or phrasing, state the assumption briefly, and proceed.
4. If a user says only "make a bot", do not create a built-in bot.
## Source priority
When the local MCC checkout is available, prefer these sources in this order:
1. `MinecraftClient/Scripting/ChatBot.cs` and current files under `MinecraftClient/ChatBots/`
2. the bundled `references/authoring-reference.md`
3. the bundled `references/pattern-cookbook.md`
4. older `MinecraftClient/config/` sample bots only for ideas, not as the default scaffold
If an older sample conflicts with the current built-in bots, follow the current built-in bots.
If the local checkout is not available, do not block on missing repo files. Use the bundled references directly.
## Hard rules
- Only use lifecycle hooks and helpers documented in the bundled reference or verified in the target codebase.
- Do not send chat from `Initialize()`. Use `AfterGameJoined()` once the session can send messages.
- Prefer the current Brigadier command-registration pattern for built-in bots. Do not introduce `ChatBotCommand` unless the surrounding code already uses it.
- For message parsing, normalize with `GetVerbatim(text)` before `IsChatMessage(...)` or `IsPrivateMessage(...)`.
- Clean up everything you register or start: commands, plugin channels, threads, timers, and movement locks.
- If a built-in bot or long-running automation controls movement, follow a movement-lock pattern and release it on every stop path. Do not add `BotMovementLock` to a simple standalone `/script` bot unless the prompt or surrounding code explicitly needs shared movement coordination.
- For built-in bots, follow the host codebase's localization and config-comment conventions instead of scattering hardcoded user-facing text.
- For new code, prefer `Initialize()` over constructors for prerequisite checks and unload decisions.
- In this repo, built-in bot wiring usually means edits in `MinecraftClient/Settings.cs` and `MinecraftClient/McClient.cs` in addition to the bot class.
- For repair tasks, preserve the existing bot type and file layout unless the user explicitly asks for a conversion or restructure.
## Standalone script bots
Use the exact MCC metadata format from the bundled reference.
This is the default path for new work.
The script should usually:
- keep `Initialize()` for cheap setup only
- use `GetText(...)`, `AfterGameJoined()`, and other event hooks for live behavior
- log with `LogToConsole(...)`
- send server chat or commands with `SendText(...)`
- use `PerformInternalCommand(...)` only for MCC internal commands
- add `//using MinecraftClient.Inventory` in metadata when the script uses inventory types explicitly
- reuse the standalone snippets in `references/pattern-cookbook.md` before inventing new scaffolding
- keep load instructions explicit, usually `/script FileName.cs`
## Built-in bots
Built-in bots usually need three pieces:
- the bot class itself
- config wiring in the chat-bot config model
- bot registration in the load flow
If the codebase exposes commands, follow the built-in command and unload pattern from the bundled reference. If it exposes new settings or status text, follow the codebase's localization and config-comment patterns.
When working in this checkout, built-in bot delivery usually needs:
- a new file under `MinecraftClient/ChatBots/`
- a config property inside `Settings.ChatBotConfigHealper.ChatBotConfig`
- a `BotLoad(new YourBot())` line inside `McClient.RegisterBots(...)`
- literal code snippets or patch hunks for the `Settings.cs` property and the `McClient.cs` registration line, not only prose notes
## Repair flow
When the user asks to fix or debug a bot:
- identify whether it is standalone or built-in and keep that shape unless told otherwise
- remove the broken pattern first, then preserve the intended behavior
- check especially for these regressions: `SendText(...)` in `Initialize()`, raw formatted chat parsing, inventory snapshot mutation, missing command unregister, missing plugin-channel unregister, and unreleased movement locks
- reuse the local repo's modern pattern instead of patching around a legacy helper when the helper is no longer current
## Delivery checklist
Before finishing, verify:
- the class inherits `ChatBot`
- the chosen overrides exist in the MCC ChatBot API
- standalone script metadata is exact if this is a `/script` bot
- built-in bots are fully wired into config and registration if needed
- all command registrations, background work, and movement locks are released
- files and namespaces match the surrounding codebase
## Output
When you implement or modify a bot:
- state whether it is a standalone script bot or built-in bot
- list the files you changed
- mention any required config keys or the MCC command used to load it
- when built-in wiring is involved, show the exact inserted code lines or patch hunks for `Settings.cs` and `McClient.cs`
- call out assumptions briefly if the user did not specify bot type or trigger behavior

View file

@ -0,0 +1,57 @@
// Use this template only when the user explicitly requests a built-in MCC bot.
using MinecraftClient.Scripting;
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
public class ExampleBot : ChatBot
{
private const string BotName = "ExampleBot";
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
public bool Enabled = false;
public void OnSettingUpdate()
{
}
}
public override void Initialize()
{
LogToConsole(BotName, "Initialized.");
}
public override void AfterGameJoined()
{
}
public override void GetText(string text)
{
text = GetVerbatim(text);
string message = "";
string username = "";
if (IsPrivateMessage(text, ref message, ref username))
{
}
else if (IsChatMessage(text, ref message, ref username))
{
}
}
public override void OnUnload()
{
}
public override bool OnDisconnect(DisconnectReason reason, string message)
{
return false;
}
}
}

View file

@ -0,0 +1,37 @@
//MCCScript 1.0
MCC.LoadBot(new ExampleScriptBot());
//MCCScript Extensions
public class ExampleScriptBot : ChatBot
{
public override void Initialize()
{
LogToConsole("ExampleScriptBot initialized.");
}
public override void AfterGameJoined()
{
// Safe place for startup chat or commands.
}
public override void GetText(string text)
{
text = GetVerbatim(text);
string message = "";
string username = "";
if (IsPrivateMessage(text, ref message, ref username))
{
LogToConsole("PM from " + username + ": " + message);
return;
}
if (IsChatMessage(text, ref message, ref username))
{
LogToConsole("Chat from " + username + ": " + message);
}
}
}

View file

@ -0,0 +1,492 @@
# MCC ChatBot Reference
Self-contained authoring notes for Minecraft Console Client chat bots.
## Bot types
MCC supports two common authoring paths:
- standalone script bots loaded at runtime with `/script`
- built-in bots compiled into the MCC codebase
Default to a standalone `/script` bot unless the user explicitly asks for a built-in bot or repo wiring.
## Embedded current patterns
This skill is intended to work even without an MCC checkout. The patterns below capture the important behavior that would otherwise be borrowed from current repo examples.
If the local repo is available, you can verify against files such as `TestBot.cs`, `RemoteControl.cs`, `FollowPlayer.cs`, `ItemsCollector.cs`, and `Farmer.cs`. If it is not available, use the embedded patterns here directly.
### Minimal chat parsing pattern
Use this as the baseline for public/private chat handling:
```csharp
public override void GetText(string text)
{
string message = "";
string sender = "";
text = GetVerbatim(text);
if (IsPrivateMessage(text, ref message, ref sender))
{
LogToConsole("PM from " + sender + ": " + message);
}
else if (IsChatMessage(text, ref message, ref sender))
{
LogToConsole("Chat from " + sender + ": " + message);
}
}
```
What matters:
- normalize first with `GetVerbatim(text)`
- handle PMs before public chat if both matter
- keep simple chat bots deterministic and small
### Owner-gated PM control pattern
Use this when a bot owner should be able to whisper MCC internal commands:
```csharp
public override void GetText(string text)
{
text = GetVerbatim(text).Trim();
string command = "";
string sender = "";
if (IsPrivateMessage(text, ref command, ref sender)
&& Settings.Config.Main.Advanced.BotOwners.Contains(sender.ToLowerInvariant()))
{
CmdResult result = new();
PerformInternalCommand(command, ref result);
SendPrivateMessage(sender, result.ToString());
}
}
```
What matters:
- `PerformInternalCommand(...)` is for MCC commands, not server chat commands
- owner gating should use `Settings.Config.Main.Advanced.BotOwners`
- if `CmdResult` is used in a standalone script, add `//using MinecraftClient.CommandHandler`
### Periodic work pattern
Use `Update()` plus a counter or timestamp for simple repeated work:
```csharp
private int count = 0;
public override void Update()
{
count++;
if (count < Settings.DoubleToTick(60))
return;
count = 0;
SendText("/list");
}
```
What matters:
- avoid a worker thread for simple periodic loops
- avoid `Thread.Sleep(...)` inside `Update()`
- if sending chat, do it from a join-safe path like `Update()` or `AfterGameJoined()`, not `Initialize()`
### Built-in Brigadier command pattern
Use this for built-in command bots:
```csharp
public override void Initialize()
{
McClient.dispatcher.Register(l => l.Literal("help")
.Then(l => l.Literal(CommandName)
.Executes(r => OnCommandHelp(r.Source, string.Empty))
)
);
McClient.dispatcher.Register(l => l.Literal(CommandName)
.Then(l => l.Literal("stop")
.Executes(r => OnCommandStop(r.Source)))
.Then(l => l.Literal("_help")
.Executes(r => OnCommandHelp(r.Source, string.Empty))
.Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName)))
);
}
public override void OnUnload()
{
McClient.dispatcher.Unregister(CommandName);
McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName);
}
```
What matters:
- register commands in `Initialize()`
- unregister the command tree in `OnUnload()`
- remove the help child you added in `OnUnload()`
- prefer this over legacy command wrappers for new built-in work
### Built-in config and wiring pattern
Use this as the default built-in shape:
```csharp
public class ExampleBot : ChatBot
{
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
public bool Enabled = false;
public void OnSettingUpdate()
{
}
}
}
```
Typical host wiring shape:
```csharp
[TomlPrecedingComment("$ChatBot.ExampleBot$")]
public ChatBots.ExampleBot.Configs ExampleBot
{
get { return ChatBots.ExampleBot.Config; }
set { ChatBots.ExampleBot.Config = value; ChatBots.ExampleBot.Config.OnSettingUpdate(); }
}
```
```csharp
if (Config.ChatBot.ExampleBot.Enabled) { BotLoad(new ExampleBot()); }
```
What matters:
- built-in configurable bots default to `Enabled = false`
- `OnSettingUpdate()` is the place to normalize config values
- built-in delivery is incomplete without both config wiring and load registration
### Movement gating pattern
Use this shape when a built-in bot owns movement:
```csharp
public override void Initialize()
{
if (!GetEntityHandlingEnabled())
{
LogToConsole("Entity handling is required.");
UnloadBot();
return;
}
if (!GetTerrainEnabled())
{
LogToConsole("Terrain handling is required.");
UnloadBot();
return;
}
}
```
```csharp
var movementLock = BotMovementLock.Instance;
if (movementLock is { IsLocked: true })
return;
movementLock?.Lock("Example Bot");
```
```csharp
public override void OnUnload()
{
BotMovementLock.Instance?.UnLock("Example Bot");
}
```
What matters:
- guard terrain and entity handling before movement logic
- built-in movement bots should use `BotMovementLock`
- release the lock on every stop path, including unload and disconnect-sensitive flows
### Dropped-item collector pattern
Use this as the standalone item-search baseline:
```csharp
private DateTime nextScan = DateTime.MinValue;
public override void Update()
{
var now = DateTime.UtcNow;
if (now < nextScan || ClientIsMoving())
return;
nextScan = now.AddSeconds(1);
var here = GetCurrentLocation();
var target = GetEntities().Values
.Where(entity => entity.Type == EntityType.Item && entity.Location.Distance(here) <= 15)
.OrderBy(entity => entity.Location.Distance(here))
.FirstOrDefault();
if (target != null)
MoveToLocation(target.Location);
}
```
What matters:
- simple standalone collectors do not need a worker thread
- simple standalone collectors also do not need `BotMovementLock` by default
- `GetEntities()` plus distance ordering is the core search pattern
### Inventory selection pattern
Use this as the default hotbar-switch pattern:
```csharp
private bool TrySwitchToItem(ItemType itemType)
{
var inventory = GetPlayerInventory();
var hotbarSlots = inventory.SearchItem(itemType)
.Where(slot => slot >= 36 && slot <= 44)
.ToArray();
if (hotbarSlots.Length == 0)
return false;
ChangeSlot((short)(hotbarSlots[0] - 36));
return true;
}
```
What matters:
- guard with `GetInventoryEnabled()`
- search inventory snapshots, but mutate real server state with helpers like `ChangeSlot(...)`
- do not treat local `Container.Items` mutation as real inventory manipulation
Use the older config examples only for ideas, not as primary scaffolding.
## Standalone script format
A standalone script bot has two parts in this order:
1. metadata block
2. one or more C# classes, with the main bot class inheriting `ChatBot`
Required metadata rules:
- line 1 must be exactly `//MCCScript 1.0`
- metadata must include `MCC.LoadBot(new BotClassName());`
- metadata ends with `//MCCScript Extensions`
- optional metadata directives use `//using Namespace` and `//dll SomeLibrary.dll`
- do not insert a space after `//` in metadata directives
Typical runtime flow:
- place the script file beside MCC
- connect to a server
- load it with `/script YourBotFile.cs`
### Namespace linking for inventory code
If a standalone script uses inventory-specific types such as `Container`, `ItemType`, `WindowActionType`, or `ItemMovingHelper`, add this metadata import:
```csharp
//using MinecraftClient.Inventory
```
For built-in bots, use a normal C# import:
```csharp
using MinecraftClient.Inventory;
```
## Lifecycle summary
Common lifecycle hooks:
- `Initialize()`
called once when the bot loads; use it for cheap setup only
- `AfterGameJoined()`
called after the server has been joined successfully, and again after reconnecting; use it when chat can be sent
- `Update()`
called roughly every 100 ms
- `OnUnload()`
called when the bot unloads; release resources here
- `OnDisconnect(DisconnectReason reason, string message)`
called on disconnect; stop background work and clean up reconnect-sensitive state here
Important rule:
- do not send chat from `Initialize()`; use `AfterGameJoined()` instead
- prefer `Initialize()` over constructors for environment checks and resource setup
## Common event hooks
Useful event hooks include:
- `GetText(string text)`
- `GetText(string text, string? json)`
- `OnPlayerJoin(Guid uuid, string name)`
- `OnPlayerLeave(Guid uuid, string? name)`
- `OnEntitySpawn(Entity entity)`
- `OnEntityDespawn(Entity entity)`
- `OnEntityMove(Entity entity)`
- `OnHealthUpdate(float health, int food)`
- `OnMapData(...)`
- `OnInventoryUpdate(int inventoryId)`
- `OnPluginMessage(string channel, byte[] data)`
- `OnNetworkPacket(int packetID, List<byte> packetData, bool isLogin, bool isInbound)`
Only override hooks that actually exist in the target MCC ChatBot API.
## Common helpers
Text and messaging helpers:
- `GetVerbatim(text)` strips Minecraft formatting codes
- `IsChatMessage(text, ref message, ref sender)` parses public chat
- `IsPrivateMessage(text, ref message, ref sender)` parses private chat
- `IsValidName(username)` validates a Minecraft username
- `SendText(text)` sends chat or server commands
- `SendPrivateMessage(player, message)` sends a private message
- `PerformInternalCommand(command, ...)` runs an internal MCC command, not a server command
- `LogToConsole(text)` writes a bot-prefixed console message
Lifecycle and threading helpers:
- `InvokeOnMainThread(...)`
- `ScheduleOnMainThread(...)`
- `ReconnectToTheServer(...)`
- `UnloadBot()`
- `BotLoad(chatBot)`
- `RunScript(filename, ...)`
World and player-state helpers:
- `GetWorld()`
- `GetEntities()`
- `GetCurrentLocation()`
- `ClientIsMoving()`
- `GetOnlinePlayers()`
- `GetOnlinePlayersWithUUID()`
- `GetServerTPS()`
- `GetProtocolVersion()`
Movement and inventory helpers:
- `MoveToLocation(...)`
- `LookAtLocation(...)`
- `GetInventoryEnabled()`
- `GetPlayerInventory()`
- `GetInventories()`
- `GetItemMovingHelper(...)`
- `WindowAction(...)`
- `ChangeSlot(...)`
- `GetCurrentSlot()`
- `UseItemInHand()`
- `UseItemInLeftHand()`
- `CloseInventory(...)`
- `DigBlock(...)`
- `InteractEntity(...)`
## Inventory notes
Inventory handling is optional in MCC. Check `GetInventoryEnabled()` before relying on inventory state or mutation.
Important behavior:
- `GetPlayerInventory()` returns a snapshot copy of the player's inventory
- `GetInventories()` returns current container snapshots
- writing to those `Container` objects locally does not update the server
- to actually change inventory state, use `ChangeSlot(...)`, `WindowAction(...)`, `GetItemMovingHelper(...)`, `UseItemInHand()`, or related helpers
Useful practical facts:
- hotbar selection uses `ChangeSlot(0..8)`
- hotbar slots are commonly `36..44` in inventory slot numbering
- the offhand slot is commonly `45`
- `Container.SearchItem(...)` is the normal way to locate items by type
Good inventory workflow:
1. guard with `GetInventoryEnabled()`
2. read the current container using `GetPlayerInventory()`
3. locate slots with `SearchItem(...)` or `Items`
4. mutate server state using `ChangeSlot(...)`, `WindowAction(...)`, or `ItemMovingHelper`
5. if needed, react to `OnInventoryUpdate(...)`, `OnInventoryOpen(...)`, or `OnInventoryClose(...)`
Plugins and channels:
- `RegisterPluginChannel(channel)`
- `UnregisterPluginChannel(channel)`
- `SendPluginChannelMessage(channel, data, ...)`
## Built-in bot pattern
A built-in bot usually follows this shape:
- a class that inherits `ChatBot`
- an optional static `Config` field
- a nested `[TomlDoNotInlineObject]` `Configs` class for settings
- an `Enabled = false` setting by default
- `OnSettingUpdate()` to normalize or validate config values
If the bot is configurable, the host codebase usually also needs:
- config wiring in the chat-bot config model
- load registration so enabled bots are instantiated automatically
In this MCC checkout, the usual built-in wiring points are:
- `MinecraftClient/Settings.cs` inside `Settings.ChatBotConfigHealper.ChatBotConfig`
- `MinecraftClient/McClient.cs` inside `RegisterBots(...)`
Match the surrounding `[TomlPrecedingComment(...)]`, property-forwarding, and `BotLoad(new YourBot())` style instead of inventing a different config path.
When presenting built-in wiring, prefer literal code snippets or patch hunks for those two edits so the wiring can be checked directly.
If the bot adds user-facing settings or messages, follow the host codebase's localization and config-comment conventions instead of scattering hardcoded strings.
## Command pattern
For standalone script bots, prefer chat or PM handling in `GetText(...)` unless the user explicitly asks for built-in command registration.
For built-in commands, prefer the current Brigadier dispatcher pattern:
- register commands in `Initialize()`
- add a help entry if the bot exposes commands
- unregister the command tree in `OnUnload()`
- remove any help child added during registration in `OnUnload()`
Avoid using legacy command wrappers if the current codebase uses direct dispatcher registration.
In this checkout, treat direct `McClient.dispatcher.Register(...)` usage in current built-in bots as the source of truth.
## Concurrency and cleanup
If the bot starts background work:
- stop it in `OnUnload()`
- stop it in `OnDisconnect(...)`
- consider resetting state in `AfterGameJoined()` after relog
- prefer `Update()` plus counters or timestamps over unmanaged threads when the task is simple periodic work
If the bot controls movement:
- use a movement-lock discipline
- release the lock on every stop path
- avoid fighting other movement bots
- `BotMovementLock` is mainly for built-in bots or shared long-running automation; a simple standalone script that just calls `MoveToLocation(...)` does not need it by default
When interacting with client state from background logic, use the main-thread helpers when required by the codebase.
## Practical defaults
For simple chat bots:
- normalize text with `GetVerbatim(text)`
- inspect private chat first if the bot listens for whispers
- then inspect public chat
- keep response logic small and deterministic
For long-running automation bots:
- guard prerequisites early, such as entity handling or terrain support
- fail fast with a clear log message if prerequisites are missing
- release all ongoing work cleanly on unload and disconnect
## Common pitfalls
- Incorrect metadata line 1 will break standalone script loading.
- Missing `MCC.LoadBot(new BotClassName())` will prevent standalone script registration.
- Sending chat in `Initialize()` is too early.
- Doing prerequisite checks or unloading from the constructor is harder to reason about than using `Initialize()`.
- Parsing raw formatted text without `GetVerbatim()` causes brittle chat matching.
- Inventing methods not present in the MCC ChatBot API leads to dead code.
- Built-in bot work is incomplete if config or registration wiring is missing.
- Command bots are incomplete if they register commands but do not unregister them.
- `RegisterChatBotCommand(...)` comes from older samples and is not a reliable current pattern for this checkout.
- `ChatBotCommand` exists, but the current built-in bots use Brigadier directly; do not prefer `ChatBotCommand` for new work.
- Blocking `Thread.Sleep(...)` inside `Update()` is a bad default. Prefer timers, counters, or timestamp-based scheduling.
- Mutating the `Container` returned by `GetPlayerInventory()` does not change the server. Use inventory actions instead.

View file

@ -0,0 +1,330 @@
# MCC Pattern Cookbook
Concrete patterns for standalone MCC `/script` bots. Use these before inventing new scaffolding.
## Periodic task without threads
Use `Update()` plus a timestamp or counter. This comes from the old `sample-script-with-task.cs` example and still holds up well.
```csharp
public class PeriodicTaskBot : ChatBot
{
private DateTime nextRun = DateTime.MinValue;
public override void Update()
{
var now = DateTime.UtcNow;
if (now < nextRun)
return;
nextRun = now.AddSeconds(30);
LogDebugToConsole("Running periodic task");
SendText("/ping");
}
}
```
Why this pattern is good:
- stays on MCC's normal tick flow
- avoids background threads for simple periodic work
- keeps the bot responsive to unload and disconnect
## Chat and PM handling
This combines the useful parts of `TestBot`, `sample-script-pm-forwarder.cs`, and `RemoteControl.cs`.
```csharp
public override void GetText(string text)
{
text = GetVerbatim(text);
string message = "";
string sender = "";
if (IsPrivateMessage(text, ref message, ref sender))
{
LogToConsole("PM from " + sender + ": " + message);
return;
}
if (IsChatMessage(text, ref message, ref sender))
{
LogToConsole("Chat from " + sender + ": " + message);
}
}
```
Owner-gated internal command handling:
Add `//using MinecraftClient.CommandHandler` in the script metadata if you use `CmdResult`.
```csharp
public override void GetText(string text)
{
text = GetVerbatim(text).Trim();
string command = "";
string sender = "";
if (IsPrivateMessage(text, ref command, ref sender)
&& Settings.Config.Main.Advanced.BotOwners.Contains(sender.ToLowerInvariant()))
{
CmdResult result = new();
PerformInternalCommand(command, ref result);
SendPrivateMessage(sender, result.ToString());
}
}
```
## Movement with prerequisite checks
Modern movement code should copy the guard style from current built-in bots, not the older constructor-heavy scripts.
```csharp
public override void Initialize()
{
if (!GetEntityHandlingEnabled() || !GetTerrainEnabled())
{
LogToConsole("Entity handling and terrain handling are required.");
UnloadBot();
}
}
```
Simple "look at nearest player" logic adapted from `AutoLook.cs`:
```csharp
private Entity? trackedPlayer = null;
public override void OnEntitySpawn(Entity entity)
{
TryTrack(entity);
}
public override void OnEntityDespawn(Entity entity)
{
if (trackedPlayer != null && entity.ID == trackedPlayer.ID)
trackedPlayer = null;
}
public override void OnEntityMove(Entity entity)
{
if (!TryTrack(entity))
return;
LookAtLocation(entity.Location);
}
private bool TryTrack(Entity entity)
{
if (entity.Type != EntityType.Player)
return false;
if (trackedPlayer == null)
{
trackedPlayer = entity;
return true;
}
if (GetCurrentLocation().Distance(entity.Location) < GetCurrentLocation().Distance(trackedPlayer.Location))
trackedPlayer = entity;
return trackedPlayer.ID == entity.ID;
}
```
## Search for dropped items and move to them
This is the safest pattern to preserve from `ItemsCollector.cs` for standalone scripts.
```csharp
public class NearbyItemsBot : ChatBot
{
private DateTime nextScan = DateTime.MinValue;
public override void Initialize()
{
if (!GetEntityHandlingEnabled() || !GetTerrainEnabled())
{
LogToConsole("Entity handling and terrain handling are required.");
UnloadBot();
}
}
public override void Update()
{
var now = DateTime.UtcNow;
if (now < nextScan || ClientIsMoving())
return;
nextScan = now.AddSeconds(1);
var here = GetCurrentLocation();
var target = GetEntities().Values
.Where(entity => entity.Type == EntityType.Item && entity.Location.Distance(here) <= 15)
.OrderBy(entity => entity.Location.Distance(here))
.FirstOrDefault();
if (target != null)
MoveToLocation(target.Location);
}
}
```
Why this version is better than older farming scripts:
- no unmanaged worker thread
- no busy wait loop around movement
- uses the current `GetEntities()` pattern
## Search for blocks or crops in the world
The old sugar cane and mining scripts still contain a useful search idea: use `GetWorld().FindBlock(...)`, then filter and sort.
```csharp
var targets = GetWorld()
.FindBlock(GetCurrentLocation(), Material.SugarCane, 16)
.Where(block =>
GetWorld().GetBlock(new Location(block.X, block.Y - 1, block.Z)).Type == Material.SugarCane)
.OrderBy(block => block.Distance(GetCurrentLocation()))
.ToList();
```
Use this as a search primitive. Then decide separately how to move, dig, or harvest.
## Inventory access and manipulation
If a standalone script uses inventory types directly, add this import in the metadata block:
```csharp
//using MinecraftClient.Inventory
```
For built-in bots, add:
```csharp
using MinecraftClient.Inventory;
```
Always guard inventory logic first:
```csharp
public override void Initialize()
{
if (!GetInventoryEnabled())
{
LogToConsole("Inventory handling is required.");
UnloadBot();
}
}
```
Important rule:
- `GetPlayerInventory()` returns a snapshot copy, so editing its `Items` dictionary does not change the server
- actual changes must go through `ChangeSlot(...)`, `WindowAction(...)`, `GetItemMovingHelper(...)`, `UseItemInHand()`, and related helpers
### Search inventory for an item
This combines the useful current logic from `Farmer.cs` and `AutoEat.cs`.
```csharp
private bool TrySwitchToItem(ItemType itemType)
{
var inventory = GetPlayerInventory();
if (inventory.Items.TryGetValue(GetCurrentSlot() - 36, out var held) && held.Type == itemType)
return true;
var hotbarSlots = inventory.SearchItem(itemType)
.Where(slot => slot >= 36 && slot <= 44)
.ToArray();
if (hotbarSlots.Length == 0)
return false;
ChangeSlot((short)(hotbarSlots[0] - 36));
return true;
}
```
Use this for simple hotbar selection. For deeper inventory reshuffling, built-in bots usually need more helper logic.
### Move an item into the hotbar
Use this when the item exists in inventory but is not already on the hotbar.
```csharp
private bool TryMoveItemToHotbar(ItemType itemType, short targetHotbarSlot = 0)
{
var inventory = GetPlayerInventory();
var matches = inventory.SearchItem(itemType);
if (matches.Length == 0)
return false;
var targetInventorySlot = 36 + targetHotbarSlot;
if (matches[0] >= 36 && matches[0] <= 44)
{
ChangeSlot((short)(matches[0] - 36));
return true;
}
var movingHelper = GetItemMovingHelper(inventory);
movingHelper.Swap(matches[0], targetInventorySlot);
ChangeSlot(targetHotbarSlot);
return true;
}
```
Why this pattern is good:
- it reads the current snapshot first
- it does not pretend local `Container` edits affect the server
- it uses the item-moving helper for real inventory manipulation
### Drop or click items with window actions
Use `WindowAction(...)` when the bot needs direct inventory clicks or dropping behavior.
```csharp
private void DropAllOfType(ItemType itemType)
{
var inventory = GetPlayerInventory();
foreach (int slot in inventory.SearchItem(itemType))
WindowAction(0, slot, WindowActionType.DropItemStack);
}
```
Use this pattern carefully:
- verify the correct inventory ID first
- prefer reacting to `OnInventoryUpdate(...)` for larger inventory workflows
- for crafting or chest workflows, use `GetInventories()` and `CloseInventory(...)` as needed
## Built-in command bot pattern
Only use this when the user explicitly asks for a built-in bot.
```csharp
public override void Initialize()
{
McClient.dispatcher.Register(l => l.Literal("help")
.Then(l => l.Literal(CommandName)
.Executes(r => OnCommandHelp(r.Source, string.Empty))
)
);
McClient.dispatcher.Register(l => l.Literal(CommandName)
.Then(l => l.Literal("_help")
.Executes(r => OnCommandHelp(r.Source, string.Empty))
.Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName)))
);
}
public override void OnUnload()
{
McClient.dispatcher.Unregister(CommandName);
McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName);
}
```
Use a built-in bot only when the user explicitly asks for compiled MCC behavior or repo wiring.

View file

@ -0,0 +1,362 @@
---
name: mcc-dev-workflow
description: Build, run, and debug Minecraft Console Client (MCC) against a real local Minecraft Java server on Linux, macOS, or WSL. Use this whenever the user wants to compile MCC, start or inspect a local test server, connect MCC to a server, debug protocol or login issues, validate a code change end-to-end, or run MCC commands on a real server instead of guessing from static code.
---
# MCC Development Workflow
Use this skill when the task needs a real local server loop, not just code reading.
## Defaults
- Solution: `MinecraftClient.sln`
- Runtime target: `.NET 10` / `net10.0`
- Environment: Linux, macOS, or WSL with Java, tmux, python3, and dotnet available
- Default server root after `source tools/mcc-env.sh`: `${MCC_SERVERS:-<repo>/MinecraftOfficial/downloads}`
- Default validation target when the user does not specify a version: `1.21.11`
## Console modes
MCC supports two console modes selectable via `ConsoleMode` in `[Console.General]`:
| Mode | Backend | Best for |
|------|---------|----------|
| `classic` | `ClassicConsoleBackend` (ConsoleInteractive) | Normal use, legacy CI/scripts, `FileInput` mode |
| `tui` | `TuiConsoleBackend` (Avalonia/Consolonia) | Full-screen TUI with scrollable log, command input, popup inventory |
Both modes support the same commands and input/output through `ConsoleIO.Backend`. The mode is determined at startup from config; `BasicIO` CLI arg overrides to simple stdio.
## Core rules
- Prefer a real local server over static reasoning for protocol, login, movement, inventory, entity, or command-path work.
- Treat tmux `mc-*` sessions as shared state. Do not run multi-version server workflows in parallel unless the harness explicitly isolates them.
- For scripted or repeatable runs, use a generated temporary config. Do not edit the repo-root `MinecraftClient.ini` as part of the test loop.
- A server log line containing `Done (` means startup finished. It does not guarantee that RCON is ready on the first attempt. Retry early `mc-rcon` commands.
- When instructions, docs, and code disagree, trust current code and current tool behavior first.
## Shared server, isolated MCC sessions
- `mc-*` commands operate on the shared local Minecraft server.
- `mcc-*` commands operate on one MCC client session.
- The default `session` is the current worktree name.
- The default username is derived from `session`, unless you pass `--username`.
- Session files live under `${TMPDIR:-/tmp}/mcc-debug/<session>/`.
- `MCC_SERVERS` stays the shared server-root override.
Keep shared servers running by default. Do not stop or reset them unless the user explicitly asks for that, or you need to switch server versions.
Two worktrees can debug against one shared server like this:
```bash
# worktree A
cd ~/Minecraft/Minecraft-Console-Client
source tools/mcc-env.sh
mc-start 1.21.11
mcc-debug -v 1.21.11 --file-input
# worktree B
cd ~/Minecraft/Minecraft-Console-Client-foo
source tools/mcc-env.sh
mcc-debug -v 1.21.11 --file-input
# from each worktree, mcc-* targets that worktree's default session
mcc-state
```
If you want two MCC sessions from the same worktree, pass `--session NAME` explicitly.
## tmpfs build mode
Use this on machines with enough RAM when you want worktree-isolated builds outside the repo tree:
```bash
source tools/mcc-env.sh
export MCC_BUILD_MODE=tmpfs
mcc-build
mcc-build-clean
```
`MCC_BUILD_MODE=tmpfs` redirects build output to `/dev/shm/mcc-build/<worktree>/` on Linux, or `${TMPDIR:-/tmp}/mcc-build/<worktree>/` if `/dev/shm` is unavailable.
## Preflight and reset
Before scripted runs, especially on macOS or in a reused tmux environment:
```bash
source tools/mcc-env.sh
mcc-preflight 1.21.11
mc-reset-test-env 1.21.11
```
`mcc-preflight` checks Java, tmux, dotnet, python3, and server directories. It also resolves common Homebrew Java paths on macOS. `mc-reset-test-env` clears stale tmux sessions and stale `stdin.pipe` files before they turn into misleading startup failures.
## Build
```bash
source tools/mcc-env.sh
mcc-build
```
Use `mcc-build` for normal local development so any `MCC_BUILD_MODE=tmpfs` routing stays active. Only use raw `dotnet build` when you are intentionally debugging the build system itself.
## Server management
Interactive shell:
```bash
source tools/mcc-env.sh
SESSION="$(_mcc_resolve_session)"
USERNAME="$(_mcc_resolve_username "$SESSION")"
mc-start 1.21.11
mc-log 1.21.11 100
mc-rcon "op $USERNAME"
mc-stop 1.21.11
```
Non-interactive shell:
```bash
tools/start-server.sh 1.21.11
tools/mc-rcon.sh "op mcc_smoke_a"
```
If the servers live outside the repo, set `MCC_SERVERS` before sourcing or invoking the tools:
```bash
export MCC_SERVERS=/home/anon/Minecraft/Servers
source tools/mcc-env.sh
```
## One-step debug session (recommended)
The `tools/mcc-debug.sh` script handles build, server startup, config preparation, and MCC launch in one step:
```bash
source tools/mcc-env.sh
# Classic mode with FileInput (script-driven debugging):
mcc-debug -v 1.21.11 --file-input
# Classic mode interactive (attach via tmux):
mcc-debug -v 1.21.11
# TUI mode:
mcc-debug -v 1.21.11 -m tui
# With debug messages enabled from start:
mcc-debug -v 1.21.11 --file-input --debug-on
# Skip build (already built):
mcc-debug -v 1.21.11 --file-input --no-build
```
### What mcc-debug.sh does
1. Builds MCC (unless `--no-build`)
2. Creates a clean temp config at `${TMPDIR:-/tmp}/mcc-debug/<session>/MinecraftClient.debug.ini`
3. Ensures server is running (starts if not, waits for `Done (`)
4. Launches MCC in a session-scoped tmux session and session-scoped log/input/pid files
### After launch
- **FileInput mode**: drive MCC via `mcc-cmd --session smoke-a "debug state"`, or just `mcc-cmd "debug state"` from the same worktree
- **Interactive/TUI mode**: attach with `tmux attach -t mcc-<session>`
- **Logs**: `mcc-log-mcc --session smoke-a` or `tail -f "${TMPDIR:-/tmp}/mcc-debug/<session>/mcc-debug.log"`
- **Server RCON**: grant op or gamemode to the username derived from that session
## Debug commands (in-game)
### `/debug [on|off]`
Toggles debug logging. Now correctly syncs both `Settings.Config.Logging.DebugMessages` and `McClient.Log.DebugEnabled`.
### `/debug state`
Prints a one-shot summary of MCC's internal state:
```
=== MCC Debug State ===
Server: localhost:25565
Username: mcc_smoke_a
Protocol: 774
GameMode: 1
Health: 20.0
Food: 20
Location: 0.50, 80.00, 0.50
TPS: 20.0
Console: ClassicConsoleBackend (or TuiConsoleBackend)
Features: Terrain Inventory Entity
Debug: ON
Bots (3): AutoFishing, FileInputBot, ScriptScheduler
Players: 2 online
```
This works in both classic and TUI modes.
## Classic mode debugging
### Agent workflow (FileInput mode)
For agents calling MCC commands programmatically:
```bash
source tools/mcc-env.sh
SESSION="smoke-a"
mcc-debug -v 1.21.11 --file-input --session "$SESSION" --no-build
# Send commands:
mcc-cmd --session "$SESSION" "debug state"
mcc-cmd --session "$SESSION" "inventory player list"
mcc-cmd --session "$SESSION" "entity"
# Check results:
mcc-log-mcc --session "$SESSION"
# Stop:
mcc-cmd --session "$SESSION" "quit"
mcc-kill --session "$SESSION"
mc-stop 1.21.11
```
### Interactive workflow
```bash
source tools/mcc-env.sh
SESSION="live-a"
mcc-debug -v 1.21.11 --session "$SESSION"
# In another terminal:
tmux attach -t "mcc-$SESSION"
# Type commands directly in MCC console
```
## TUI mode debugging
TUI mode runs Consolonia full-screen in a tmux session. Key differences:
1. **No pipe/redirect**: TUI needs a real tty. Cannot `| tee` or redirect stdout.
2. **Log output is in-screen**: all output appears in the scrollable log area.
3. **Keyboard shortcuts**: PageUp/PageDown scroll, ESC exits.
4. **`/debug state`**: the primary way to inspect internal state since external log tailing is not available.
5. **Dialog windows**: `/inventui` opens as an overlay dialog instead of a separate screen.
### Agent workflow for TUI mode
```bash
source tools/mcc-env.sh
SESSION="tui-a"
mcc-debug -v 1.21.11 -m tui --session "$SESSION" --no-build
# Cannot use mcc-cmd (no FileInput); must use tmux send-keys:
tmux send-keys -t "mcc-$SESSION" "/debug state" Enter
# Read TUI screen:
tmux capture-pane -t "mcc-$SESSION" -p -S -30
# Stop:
tmux send-keys -t "mcc-$SESSION" Escape
```
**Caveat with tmux send-keys and Consolonia**: When sending text containing `/`, the Enter key may need to be sent separately:
```bash
tmux send-keys -t "mcc-$SESSION" "/inventory player list"
tmux send-keys -t "mcc-$SESSION" Enter
```
## mcc-env.sh quick reference
After `source tools/mcc-env.sh`:
| Function | Description |
|----------|-------------|
| `mc-start VER` | Start MC server in tmux |
| `mc-stop VER` | Graceful stop via stdin pipe |
| `mc-log VER [N]` | Capture last N lines of server output |
| `mc-rcon "CMD"` | Send RCON command |
| `mc-kill VER` | Force-kill server tmux session |
| `mc-list` | List running MC server sessions |
| `mc-wait-ready VER [SEC]` | Wait for server `Done (` |
| `mc-wait-stop VER [SEC]` | Wait for server shutdown, with force-kill fallback |
| `mc-reset-test-env [--all|VER...]` | Reset shared tmux server state and stale pipes |
| `mcc-build` | Build MCC |
| `mcc-publish --rid <RID>` | Publish MCC with the repo's CI-like defaults |
| `mcc-build-clean` | Clear the current worktree's build output |
| `mcc-run [--session NAME] [--username NAME] [--port PORT]` | Convenience wrapper for `mcc-debug --file-input --no-build` |
| `mcc-tui [--session NAME] [--username NAME] [--port PORT]` | Convenience wrapper for `mcc-debug -m tui --no-build` |
| `mcc-cmd [--session NAME] "CMD"` | Append a command to one session's input file |
| `mcc-kill [--session NAME]` | Kill one MCC process and session |
| `mcc-debug [OPTS]` | One-step debug session (see above) |
| `mcc-log-mcc [--session NAME]` | Tail one MCC debug log |
| `mcc-state [--session NAME]` | Send `debug state` and print the last 30 log lines |
| `mcc-preflight [VER...]` | Verify Java, tmux, dotnet, python3, and server dirs |
## Temporary config recipe
```bash
source tools/mcc-env.sh
SESSION="smoke-a"
USERNAME="$(_mcc_resolve_username "$SESSION")"
CFG="$(_mcc_session_root "$SESSION")/MinecraftClient.debug.ini"
mkdir -p "$(_mcc_session_root "$SESSION")"
bash "$MCC_REPO/.skills/mcc-integration-testing/scripts/prepare_offline_mcc_config.sh" \
"$CFG" \
"1.21.11" \
"$USERNAME"
```
For TUI mode, also add:
```bash
sed -i 's/ConsoleMode = "classic"/ConsoleMode = "tui"/' "$CFG"
```
## Verify connection and a basic command
MCC output should include:
- `[MCC] Server was successfully joined.`
Server output should include the session-derived username, for example:
- `mcc_smoke_a joined the game`
Basic command check:
```bash
mcc-cmd --session smoke-a "inventory player list"
```
If a scripted run fails before MCC joins, check for a harness problem before assuming a product regression. Missing `mcc.log`, a pre-join `Connection refused`, or a server that never reached `Done (` usually means shared-state cleanup or startup failed.
## Typical debug loop
1. `source tools/mcc-env.sh`
2. `mcc-debug -v 1.21.11 --file-input` (or `-m tui`)
3. Confirm `Server was successfully joined` in log
4. `mcc-cmd "debug state"` to verify MCC state
5. Run test commands
6. Inspect log output
7. `mcc-cmd "quit"` and `mc-stop 1.21.11`
8. Edit code, rebuild, repeat
## Debugging tips
- **`/debug state` is your primary diagnostic tool** in both modes. Use it first to verify connection, mode, and feature flags.
- **`/debug on` now correctly enables debug logging** at runtime. Previous versions had a bug where `Log.DebugEnabled` was not synced.
- Protocol mismatches usually show up as a version line such as `Server version : 1.21.11 (protocol vNNN)` before the failure.
- If an early `mc-rcon` command fails, retry it before assuming the server setup is broken.
- If a supposedly isolated run behaves strangely, check `tmux list-sessions` and kill stale `mc-*` sessions first.
- Legacy `1.8` and `1.8.9` servers may need `use-native-transport=false` in `server.properties` on some Linux environments.
- For timing-sensitive work, do not trust wall-clock intuition. Use a real server run and capture evidence from logs or test scripts.
- **TUI mode tip**: if the terminal becomes unresponsive after a crash, run `stty sane && reset` to restore it.
- **tmux capture trick**: `tmux capture-pane -t mcc-<session> -p -S -50` captures the last 50 lines of a tmux session without attaching.
## Tool files
| File | Purpose |
|------|---------|
| `tools/mcc-env.sh` | Shell functions for server/MCC management |
| `tools/mcc-debug.sh` | One-step debug session launcher |
| `tools/mcc-log-tail.sh` | Log tailing for MCC and/or server |
| `tools/start-server.sh` | Server lifecycle in tmux |
| `tools/mc-rcon.sh` | RCON command sender |
| `tools/run-creative-e2e.sh` | Full creative mode end-to-end test |

View file

@ -0,0 +1,41 @@
{
"skill_name": "mcc-dev-workflow",
"evals": [
{
"id": 1,
"prompt": "Build MCC, start the local 1.21.11 vanilla server from an MCC_SERVERS root, connect MCC with a temporary config, and verify a successful join plus one inventory command.",
"expected_output": "The workflow uses a real local server, a temp MCC config, and concrete log evidence for both the join and the MCC command.",
"files": [],
"expectations": [
"The workflow uses a real local 1.21.11 server instead of only reading code.",
"The workflow uses MCC_SERVERS-aware tooling or documents the server root explicitly.",
"The workflow uses a temporary MCC config instead of relying on the repo-root config.",
"The result includes join evidence from MCC output and the server log."
]
},
{
"id": 2,
"prompt": "Debug a flaky local MCC startup on 1.21.11 by checking for stale tmux server sessions, waiting for server readiness, and retrying early RCON commands before blaming protocol code.",
"expected_output": "The response treats tmux sessions as shared state, distinguishes server startup from RCON readiness, and uses the real local workflow rather than pure speculation.",
"files": [],
"expectations": [
"The workflow checks or mentions stale mc-* tmux sessions.",
"The workflow distinguishes Done from RCON readiness.",
"The workflow retries or advises retrying early RCON commands.",
"The workflow keeps the debugging loop grounded in real local commands."
]
},
{
"id": 3,
"prompt": "Run a repeatable local MCC debug loop for 1.21.11 that compiles the client, connects with movement, inventory, and entity handling enabled, and leaves enough evidence to inspect a regression afterward.",
"expected_output": "The response follows a real build-run-test-inspect loop and captures enough log evidence to support follow-up debugging.",
"files": [],
"expectations": [
"The workflow builds MCC before the run.",
"The workflow enables terrain, inventory, and entity handling for the scripted run.",
"The workflow captures or points to concrete log locations.",
"The workflow prefers a temp config for repeatability."
]
}
]
}

View file

@ -0,0 +1,323 @@
---
name: mcc-integration-testing
description: >-
Use when proving MCC behavior on a real local Minecraft server, validating
runtime or protocol changes end-to-end, exercising movement, physics,
inventory, entity, chat, or terrain behavior, or running a single-version or
cross-version regression sweep.
metadata:
category: discipline
triggers:
- integration test
- real server
- local server
- regression sweep
- rcon
- tmux
- offline mode
- online mode
- movement
- physics
- inventory
- entity
- terrain
- chat
---
# MCC Integration Testing
Use this skill when the task is "prove it on a real server", not just "reason about whether it should work."
Read [references/online-mode.md](references/online-mode.md) when the user asks for Microsoft login, device-code auth, or an online-mode server run. Use [references/command-matrix.md](references/command-matrix.md) for stable MCC-side and RCON-side commands.
## Iron Law
Only say MCC was integration tested when MCC ran against a real local server and the claim is backed by real MCC output plus real server logs.
Calling build-only, reasoning-only, or join-only work "integration tested" is a rules violation, not shorthand.
These do not count as end-to-end proof:
- static reasoning, source comparison, or build success
- join or login success by itself
- a long-lived idle connection by itself
- a grep that only says there were no errors
- testing one shared-route version and silently claiming adjacent versions also passed
If the environment cannot run a real server, say so and report the result as unexecuted or inferred, not integration tested.
## Default target
- Use `1.21.11-Vanilla` unless the user asks for a different version or a version matrix.
- Use `MCC_SERVERS` if it is set. Otherwise the default server root is `MinecraftOfficial/downloads`.
## Guardrails
- Use a real local server.
- Launch MCC against an explicit `localhost:<server-port>` target for repeatable local tests.
- Keep version matrices sequential in shared local environments. The tmux server harness is shared state by default.
- Prefer generated temporary MCC configs for scripted runs so one test does not contaminate the next.
- Default to offline auth in generated temp configs. Do not trust the repo-root `MinecraftClient.ini` account defaults.
- If the user explicitly asks for Microsoft online login, honor that request and generate the temp config for Microsoft auth instead of offline mode.
- For Microsoft auth, prefer an interactive TTY launch with `BasicIO-NoColor` so the device code is easy to read and relay to the user.
- Do not use file-input mode during Microsoft auth. Launch interactively first, complete login, then switch to scripted control only if needed.
- For online-mode tests, prefer a clean temp config with no join-time bots or scheduled tasks. Inherited `ScriptScheduler` or `DiscordRpc` settings can pollute the session and send unintended chat right after login.
- Legacy and modern command syntax differ. Do not assume one server-command profile fits every version.
- Use actual MCC output and actual server logs for assertions. Do not invent success strings.
- Treat server `Done` as startup progress, not RCON readiness. Retry the first RCON command before assuming the setup is broken.
- Run preflight before scripted test loops. On macOS, Java may be installed but not exported on PATH in the shell the harness uses.
- If a change touches shared routing or a version range, test at least one adjacent version that shares that path, or explicitly mark adjacent versions as unexecuted and inferred.
- For palette or version-content changes, probe at least one neighboring or existing item, entity, or block. Do not only check the headline addition.
- Separate product failures from harness failures. Missing logs, stale tmux state, stale `stdin.pipe`, or pre-join `Connection refused` errors are usually environment problems until proven otherwise.
## Choose the test mode
### 1. Single-version deep smoke
Use this when one supported version is enough and you want broad coverage:
```bash
.skills/mcc-integration-testing/scripts/run_full_spectrum_test.sh 1.21.11-Vanilla
```
This covers join, chat, slash commands, internal MCC commands, creative inventory, entity handling, sounds, particles, TNT, kill/respawn, and log assertions.
### 2. Ordered creative-mode E2E
Use this when the user asks for a regression sweep in a strict scenario order such as:
- connect
- send messages
- send commands
- receive messages
- movement
- physics
- mobs
- effects
- inventory
Broad validation should usually cover `connect-test`, `item-test`, `entity-test`, `terrain-test`, and `chat-test`.
Command:
```bash
MCC_SERVERS=/home/anon/Minecraft/Servers bash tools/run-creative-e2e.sh 1.21.11-Vanilla 1.21.11 modern
```
For legacy targets such as `1.8` or `1.8.9`, switch the final argument to `legacy` and pass the pinned MC version.
### 3. Timing or cadence validation
Use this for TPS, movement-cadence, or packet-cadence work:
- `MinecraftClient/config/sample-script-tick-counter.cs`
- `MinecraftClient/config/sample-script-packet-capture.cs`
Run them against a real server with a temp config and summarize counts from the captured logs.
### 4. Structured components test
Use this after touching any `StructuredComponents` code (registries, component
parsers, subcomponents, codec helpers) to prove every component type in a
version parses on the wire without error:
```bash
bash tools/run-structured-components-test.sh 1.21.11
```
Run a single version (fast, ~2 min) or a matrix:
```bash
for v in 1.20.6 1.21 1.21.2 1.21.5 1.21.11 26.1; do
bash tools/run-structured-components-test.sh "$v"
done
```
The script gives items with every registered component via RCON `/give`, reads
them back with `inventory player list`, and asserts no parse errors in the MCC
log. Version-gated components (v1212+, v1215+, v12111+, v261) are tested only
on the versions that support them. See `SC_Integration_Test_Report.md` for a
reference run across all 6 version groups.
### 6. Dialog integration test
Use this after touching any dialog system code (packet handling, NBT parsing,
models, TUI, command dispatch, the state machine in `DialogManager`, or the
codec in `DialogNbtParser`). Tests all 5 dialog types, button actions (close,
run_command, show_dialog), cancel/dismiss, click-label, and body content:
```bash
tools/run-dialog-test.sh 26.1
```
The script starts the server if needed, generates a temp MCC config, launches
MCC with file-input mode (requires both `MCC_FILE_INPUT=1` and
`MCC_INPUT_FILE=<path>` env vars), sends inline SNBT dialogs via RCON, and
asserts 29 checks against the MCC log.
Key requirements that differ from other test modes:
- FileInputBot is loaded only when `MCC_FILE_INPUT=1` is set in the
environment. The `[ChatBot.FileInput]` config section is ignored at load
time.
- The input file path is controlled by `MCC_INPUT_FILE`, *not* by the config
`File` setting.
- Dialogs use inline SNBT syntax through `ResourceOrIdArgument`, e.g.:
`dialog show <player> {type:"minecraft:notice", title:{text:"Hello"}}`
- The `ActionButton.CODEC` flattens `CommonButtonData` fields (`label`,
`tooltip`, `width`) into the same object as `action` — no `button` wrapper.
### 5. Full inventory regression sweep
Use this when touching inventory snapshots, player/container slot sync, creative inventory, item-slot serialization, packet palettes, game-mode updates, or block-use paths that open containers:
```bash
tools/run-inventory-full-sweep.sh --versions "1.21.10 1.21.11"
```
Default coverage includes:
- player inventory listing and inventory discovery
- creative give/delete
- inventory search
- player right/left click stack split and merge
- player drop one and drop all
- chest open via `useblock`
- container listing and close
- mirrored player slots in container windows
- shift-click and shift-right-click transfer
- container right/left click, cursor stack, drop one, and drop all
- creative middle-click command path
- log scan for packet parse failures, queue-empty crashes, unhandled exceptions, and disconnects
The script writes `summary.tsv` under `RUN_ROOT` and per-version logs under `/tmp/mcc-debug/inventory-full-<version>/mcc-debug.log`.
When a matrix has existing PASS rows, do not rerun them unless a later code change affects that row or the user asks for a full rerun. Derive remaining rows from summaries:
```bash
awk 'FNR>1 && $2=="PASS" {print $1}' /tmp/mcc-inventory-full-sweep/*/summary.tsv | sort -V | uniq
```
## Preconditions
Before running any scenario:
0. run preflight and clear stale shared state when the environment is reused
1. configure the target server for offline testing
2. ensure `eula=true`
3. ensure RCON is enabled
4. build MCC unless the task explicitly reuses a fresh build
Preflight and reset helpers:
```bash
.skills/mcc-integration-testing/scripts/preflight_test_env.sh 1.21.11-Vanilla
.skills/mcc-integration-testing/scripts/reset_shared_test_state.sh 1.21.11-Vanilla
```
Offline configuration helper:
```bash
.skills/mcc-integration-testing/scripts/ensure_offline_server.sh 1.21.11-Vanilla
```
By default, the config helper prepares offline auth. To opt into another auth mode for a specific run, set:
```bash
MCC_TEST_ACCOUNT_TYPE=microsoft
MCC_TEST_PASSWORD=
```
Optionally override the login name with the fourth argument to the config helper.
## Scripts and tools
- `.skills/mcc-integration-testing/scripts/ensure_offline_server.sh`
- configures persistent offline mode and RCON
- `.skills/mcc-integration-testing/scripts/preflight_test_env.sh`
- verifies Java, tmux, dotnet, python3, server directories, and resolves common Java PATH issues
- `.skills/mcc-integration-testing/scripts/reset_shared_test_state.sh`
- clears stale tmux sessions and stale `stdin.pipe` files before a rerun
- `.skills/mcc-integration-testing/scripts/prepare_offline_mcc_config.sh`
- generates a clean temporary MCC config, prepares offline login by default, disables noisy bots, and can switch to Microsoft auth when explicitly requested
- `.skills/mcc-integration-testing/scripts/get_server_port.sh`
- resolves the actual local server port from `server.properties` or the latest server log
- `.skills/mcc-integration-testing/scripts/run_full_spectrum_test.sh`
- single-version deep smoke with built-in assertions
- `.skills/mcc-integration-testing/scripts/summarize_test_run.sh`
- summarize the latest full-spectrum run
- `tools/run-creative-e2e.sh`
- ordered creative-mode E2E regression scenario
- `tools/run-inventory-full-sweep.sh`
- full inventory command/API sweep across one or more versions
- `tools/run-structured-components-test.sh`
- exercises every structured component via RCON `/give` across versions 1.20.6-26.1
- `tools/run-dialog-test.sh`
- dialog integration test: all 5 types, run_command/show_dialog actions,
cancel/dismiss/click-label, body content; 29 assertions on MCC log
## Evidence Discipline
In every report, separate:
- `Executed`: exact scripts, commands, versions, auth mode, and whether the run was sequential or single-version
- `Observed`: exact MCC output, exact server-log evidence, and the saved log directory
- `Inferred`: conclusions not directly shown by that run's runtime evidence
- `Harness issues`: setup or runner problems such as missing Java on PATH, stale tmux sessions, stale `stdin.pipe`, missing log artifacts, or failed config generation
Never upgrade inferred claims to observed facts. Absence of errors is supporting evidence only; pair it with a positive assertion for the feature under test.
## Red Flags
Stop and fix the test plan if you are about to:
- claim movement, inventory, entity, terrain, physics, or chat coverage from join success alone
- reuse repo-root `MinecraftClient.ini` or another user-local stateful config
- run multi-version tests in parallel in a shared tmux or shared server environment
- let inherited bots, schedulers, or other user-local noise send chat or commands during validation
## What to report back
Always summarize:
- which version or versions were tested
- which port or ports were used
- which auth mode and scenario were used
- whether the run was sequential or single-version
- the exact scripts or commands executed
- pass or fail per major phase
- concrete evidence from MCC and server logs
- the saved log directory
- what was not executed and what remains inferred
- which adjacent versions were not run but were mentioned
## When Not to Use
- build-only verification
- static protocol or source comparison with no real server run
- documentation or prompt work
- code review requests that do not ask for executed runtime proof
## Troubleshooting
- If the first RCON command fails, retry it before assuming the setup is broken.
- If Java is installed but the harness still says it is missing, run `preflight_test_env.sh`. This resolves common Homebrew Java paths on macOS.
- If MCC reaches Microsoft device-code login during an offline test, stop and inspect the generated temp config before retrying.
- If the user explicitly requests Microsoft online login, set `MCC_TEST_ACCOUNT_TYPE=microsoft` before launching the harness.
- If the user explicitly requests Microsoft online login, use `BasicIO-NoColor` in a real TTY, relay the device code from the TUI, and avoid pressing empty Enter at any auth prompt.
- If the online-mode session sends unexpected chat or commands right after join, inspect inherited bot settings first. `ChatBot.ScriptScheduler` tasks and `ChatBot.DiscordRpc` are common sources of test noise in user-local configs.
- If `dotnet run` cannot see an existing Microsoft session, check whether `SessionCache.db` and `ProfileKeyCache.ini` need to be synced from `MinecraftClient/bin/Release/net10.0/` to the repo root.
- If Microsoft auth keeps prompting even with a valid session cache, verify `Account.Login` matches the cached username exactly.
- If MCC reports `Connection refused`, verify the launched target matches the server's actual `server-port`.
- If MCC reports `Connection refused` immediately after a server start, also check for stale shared state: old tmux sessions, a stale `stdin.pipe`, or a server that never actually reached `Done (`.
- If multiple versions are being tested, do not start them in parallel unless the harness isolates tmux sessions and input files.
- If a test assertion fails, inspect the real MCC output before changing the code or weakening the assertion.
- If an older server behaves oddly on Linux, check `use-native-transport=false` in `server.properties`.
- If a matrix row fails before producing `mcc.log` or a command transcript, treat it as a harness failure, fix the environment, and rerun that row before drawing product conclusions.
- If creative inventory commands report "You must be in Creative gamemode" after RCON switched the player, inspect game-mode update parsing before assuming creative inventory is broken. Modern servers can update local game mode through game event reason `3`.
- If an inventory row crashes with `Queue empty` or `Failed to process incoming packet`, inspect packet palette routing before changing inventory code. A single shifted packet ID can make a healthy inventory feature look broken.
- For chest-open failures, separate product and harness causes. The player may be standing inside the chest or suffocating on older servers. Stand beside the chest, put a floor under the player, and retry `useblock`.
- For shared local servers, a `Done` log line does not prove RCON is ready. Retry setup commands and verify the actual RCON port from `server.properties`.
- If `tools/run-dialog-test.sh` fails with "FileInput Watching: .../mcc_input.txt" pointing to the wrong directory, the `MCC_INPUT_FILE` env var was not set in the tmux command. FileInputBot ignores the config `File` setting entirely.
- If inline SNBT dialogs fail on the server side (`Failed to parse structure: No key ...`), check whether `ActionButton.CODEC` fields are flat (no `button` wrapper) and whether the dialog type fields match the 26.1 server (`label` not `text` in `CommonButtonData`).
- If a dialog integration test fails on "Server showed custom dialog", the dialog packet (id=0x8C in 26.1 play phase) may not have been sent. Verify the RCON command succeeded and the server printed "Displayed dialog to ...".

View file

@ -0,0 +1,41 @@
{
"skill_name": "mcc-integration-testing",
"evals": [
{
"id": 1,
"prompt": "Run a real 1.21.11 MCC regression test in creative mode covering connect, send messages, send commands, receive messages, movement, physics, mobs, effects, and inventory, in that order.",
"expected_output": "The workflow uses the ordered creative-mode E2E harness on a real server, reports pass or fail for each phase, and points to the saved logs.",
"files": [],
"expectations": [
"The workflow uses a real 1.21.11 server.",
"The workflow uses the ordered creative E2E harness instead of improvising the whole scenario.",
"The result reports phase-by-phase outcomes in the requested order.",
"The result includes the log directory for the run."
]
},
{
"id": 2,
"prompt": "Validate that MCC still works after a runtime or protocol change by running a deep single-version 1.21.11 integration test with chat, creative inventory, entity tracking, sounds, particles, TNT, and kill/respawn coverage.",
"expected_output": "The workflow uses the full-spectrum test runner on a real server and returns a concise pass or fail summary backed by MCC and server log evidence.",
"files": [],
"expectations": [
"The workflow builds MCC before the scenario unless a fresh build is explicitly reused.",
"The workflow uses the full-spectrum runner instead of only manual spot checks.",
"The result includes evidence from both MCC output and server logs.",
"The result points to the saved run directory."
]
},
{
"id": 3,
"prompt": "Validate a timing-sensitive MCC change on a real 1.21.11 server by collecting tick-rate and outbound packet-cadence evidence, then summarize the results clearly.",
"expected_output": "The response uses a real server, a temp config, and the provided sample scripts to capture tick-rate and packet evidence instead of relying on intuition.",
"files": [],
"expectations": [
"The workflow uses the real 1.21.11 server.",
"The workflow uses the tick counter and packet capture scripts or clearly equivalent targeted instrumentation.",
"The workflow keeps the run isolated with a temp config.",
"The summary reports concrete counts or cadence evidence."
]
}
]
}

View file

@ -0,0 +1,91 @@
# Command Matrix
This skill uses a fixed set of stable commands for local offline integration testing.
## MCC-side commands via `mcc-cmd`
- `health`
- `list`
- `inventory player list`
- `/gamemode creative`
- `inventory creativegive 36 Diamond 16`
- `inventory creativegive 37 IronSword 1`
- `inventory creativegive 38 GoldenApple 8`
- `inventory creativeclear 38`
- `entity`
- `/time query daytime`
- `look up`
- `look down`
- `look east`
- `/gamemode survival`
- `respawn`
- `/tp MCCBot 0 -60 0`
- `smoke_test_from_mcc_full_spectrum`
- `integration_test_chat_response`
Notes:
- Lines starting with `/` are sent to the server as chat/commands.
- Non-slash lines are treated as MCC internal commands first, then fall back to chat.
## Server-side commands via `mc-rcon`
- `op MCCBot`
- `gamerule sendCommandFeedback true`
- `gamerule logAdminCommands true`
- `time set day`
- `weather clear`
- `say Hello from the server console`
- `msg MCCBot This is a private whisper`
- `effect give MCCBot minecraft:speed 30 1`
- `effect give MCCBot minecraft:regeneration 10 1`
- `kill MCCBot`
## Representative entity coverage
- `execute as MCCBot at @s run summon minecraft:cow ~2 ~ ~`
- `execute as MCCBot at @s run summon minecraft:zombie ~4 ~ ~`
- `execute as MCCBot at @s run summon minecraft:creeper ~6 ~ ~`
- `execute as MCCBot at @s run summon minecraft:skeleton ~8 ~ ~`
- `execute as MCCBot at @s run summon minecraft:villager ~-2 ~ ~`
- `execute as MCCBot at @s run summon minecraft:allay ~-4 ~ ~`
- `execute as MCCBot at @s run summon minecraft:armor_stand ~ ~ ~2`
- `execute as MCCBot at @s run summon minecraft:item_display ~-6 ~ ~ {item:{id:"minecraft:diamond",count:1}}`
- `execute as MCCBot at @s run summon minecraft:spider ~10 ~ ~`
- `execute as MCCBot at @s run summon minecraft:pig ~-8 ~ ~`
## Block placement coverage
- `execute as MCCBot at @s run fill ~1 ~ ~1 ~3 ~2 ~3 minecraft:stone`
- `execute as MCCBot at @s run setblock ~5 ~ ~5 minecraft:chest`
- `execute as MCCBot at @s run setblock ~5 ~1 ~5 minecraft:furnace`
- `execute as MCCBot at @s run setblock ~6 ~ ~5 minecraft:crafting_table`
## Dimension change coverage
- `execute in minecraft:the_nether run tp MCCBot 0 64 0`
- `execute in minecraft:overworld run tp MCCBot 0 -60 0`
## Representative particle coverage
- `execute as MCCBot at @s run particle minecraft:happy_villager ~ ~1 ~ 0.5 0.5 0.5 0 12 force`
- `execute as MCCBot at @s run particle minecraft:end_rod ~ ~1 ~ 0.5 0.5 0.5 0.01 20 force`
- `execute as MCCBot at @s run particle minecraft:explosion ~ ~1 ~ 0 0 0 0 1 force`
- `execute as MCCBot at @s run particle minecraft:totem_of_undying ~ ~1 ~ 0.5 0.5 0.5 0.1 20 force`
- `execute as MCCBot at @s run particle minecraft:flame ~ ~1 ~ 0.2 0.2 0.2 0.02 30 force`
- `execute as MCCBot at @s run particle minecraft:heart ~ ~2 ~ 0.3 0.3 0.3 0 5 force`
## Representative sound coverage
- `execute as MCCBot at @s run playsound minecraft:entity.lightning_bolt.thunder master MCCBot ~ ~ ~ 1 1 0`
- `execute as MCCBot at @s run playsound minecraft:block.note_block.bell master MCCBot ~ ~ ~ 1 1 0`
- `execute as MCCBot at @s run playsound minecraft:entity.experience_orb.pickup master MCCBot ~ ~ ~ 1 1 0`
## Explosion coverage
- `execute as MCCBot at @s run summon minecraft:tnt ~3 ~ ~`
- `execute as MCCBot at @s run summon minecraft:tnt ~6 ~ ~`
## Kill and respawn cycle
- `kill MCCBot` (via RCON, requires survival mode)
- `respawn` (via MCC command after death)

View file

@ -0,0 +1,48 @@
# Online-Mode Notes
Use this flow only when the user explicitly asks for Microsoft login or wants to validate against an online-mode server.
## Launch mode
- Prefer `BasicIO-NoColor` in a real TTY so the Microsoft device-code prompt is easy to read and copy.
- Do not use `MCC_FILE_INPUT=1` during the auth step. It is for scripted command injection, not interactive login.
- Avoid `nohup`. Use `tmux` for long-running sessions that still need a TTY.
- Start from a clean temp config when possible. If the temp config is copied from a user-local `MinecraftClient.ini`, inspect `ChatBot.ScriptScheduler` and `ChatBot.DiscordRpc` before the run.
## Session cache behavior
- `dotnet run --project MinecraftClient ...` uses the repo root for `SessionCache.db` and `ProfileKeyCache.ini`.
- The compiled binary under `MinecraftClient/bin/<Config>/net10.0/` uses that output directory instead.
- If a session exists in one location and not the other, sync the cache files before assuming login is broken.
## Account settings
- `Account.Login` must be populated for MCC to look up a cached Microsoft session.
- The cached key is the username form MCC stored, typically the lowercase username, not necessarily the email address.
- MCC rewrites `MinecraftClient.ini` on clean exit, so generate a temp config per run and do not edit it while MCC is still running.
## Auth prompt handling
- Do not send a bare Enter to dismiss `Password(invisible):` or `Paste your code here:` prompts. That can trigger offline fallback.
- For interactive online-mode runs, wait for the device code prompt and relay the code to the user exactly as shown.
- After the user completes login, continue the test in the same TTY session or restart into file-driven mode if the workflow requires automation.
## Join-time noise
- Real user configs may contain enabled bots or task lists that were harmless in offline testing but are noisy in online-mode validation.
- The most common examples are:
- `ChatBot.ScriptScheduler` task lists that send `/hello`, `/login ...`, or other automatic commands on login or on an interval
- `ChatBot.DiscordRpc`, which is not harmful to server state but adds log noise and extra background activity
- If the goal is protocol or feature validation, suppress these before the run or treat their output as non-test noise.
## Server settings
- For realistic online-mode testing, keep `online-mode=true`.
- Keep `enforce-secure-profile=true` unless the test explicitly targets insecure-profile behavior.
## Command reminders
- With `InternalCmdChar = "slash"`:
- `/health`, `/pos`, `/inventory`, `/entity` are MCC internal commands.
- `/send /list` and `/send /give ...` are server commands.
- bare text is regular chat sent to the server.

View file

@ -0,0 +1,110 @@
#!/usr/bin/env bash
sed_in_place() {
if [[ "$(uname)" == "Darwin" ]]; then
sed -i '' "$@"
else
sed -i "$@"
fi
}
ensure_java_in_path() {
if command -v java >/dev/null 2>&1 && java -version >/dev/null 2>&1; then
return 0
fi
local candidate
for candidate in \
"${JAVA_BIN:-}" \
"/opt/homebrew/opt/openjdk/bin/java" \
"/usr/local/opt/openjdk/bin/java" \
"/usr/lib/jvm/default-java/bin/java"
do
[[ -z "$candidate" ]] && continue
if [[ -x "$candidate" ]]; then
export PATH="$(dirname "$candidate"):$PATH"
export JAVA_BIN="$candidate"
if java -version >/dev/null 2>&1; then
return 0
fi
fi
done
echo "java was not found on PATH. Install Java or set JAVA_BIN." >&2
return 1
}
server_session_name() {
printf 'mc-%s\n' "${1//./_}"
}
server_running() {
local version="$1"
mc-list | grep -Fq "$(server_session_name "$version")"
}
wait_for_server_ready() {
local version="$1"
local timeout="${2:-60}"
local elapsed=0
while (( elapsed < timeout )); do
if mc-log "$version" 250 2>/dev/null | grep -Fq "Done ("; then
return 0
fi
sleep 1
((elapsed += 1))
done
echo "Timed out waiting for $version to become ready" >&2
return 1
}
wait_for_server_stop() {
local version="$1"
local timeout="${2:-60}"
local elapsed=0
while (( elapsed < timeout )); do
if ! server_running "$version"; then
return 0
fi
sleep 1
((elapsed += 1))
done
mc-kill "$version" --confirm >/dev/null 2>&1 || true
if ! server_running "$version"; then
return 0
fi
echo "Timed out waiting for $version to stop" >&2
return 1
}
disable_noisy_bots_in_ini() {
local ini_file="$1"
local section
for section in \
ScriptScheduler \
DiscordRpc \
AntiAFK \
AutoDig \
AutoAttack \
PlayerListLogger \
ReplayCapture
do
sed_in_place "/^\\[ChatBot\\.${section}\\]/,/^\\[/ { s/^Enabled = true/Enabled = false/; }" "$ini_file"
done
}
remove_stale_stdin_pipe() {
local version="$1"
local pipe_path="$MCC_SERVERS/$version/stdin.pipe"
if [[ -e "$pipe_path" ]] && ! server_running "$version"; then
rm -f "$pipe_path"
fi
}

View file

@ -0,0 +1,59 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
# shellcheck source=tools/mcc-env.sh
source "$REPO_ROOT/tools/mcc-env.sh"
# shellcheck source=.skills/mcc-integration-testing/scripts/common.sh
source "$SCRIPT_DIR/common.sh"
VERSION="${1:-1.21.11-Vanilla}"
SERVER_DIR="${MCC_SERVERS:?}/$VERSION"
PROPS_FILE="$SERVER_DIR/server.properties"
SESSION_NAME="mc-${VERSION//./_}"
if [[ ! -d "$SERVER_DIR" ]]; then
echo "Server directory not found: $SERVER_DIR" >&2
exit 1
fi
if [[ ! -f "$SERVER_DIR/eula.txt" ]] || ! grep -Eq '^eula=true$' "$SERVER_DIR/eula.txt"; then
echo "Missing accepted EULA in $SERVER_DIR/eula.txt" >&2
exit 1
fi
server_running() {
mc-list | grep -Fq "$SESSION_NAME"
}
upsert_property() {
local key="$1"
local value="$2"
if grep -Eq "^${key}=" "$PROPS_FILE"; then
sed_in_place "s#^${key}=.*#${key}=${value}#" "$PROPS_FILE"
else
printf '%s=%s\n' "$key" "$value" >> "$PROPS_FILE"
fi
}
if [[ ! -f "$PROPS_FILE" ]]; then
mc-start "$VERSION"
wait_for_server_ready "$VERSION"
mc-stop "$VERSION" --confirm
wait_for_server_stop "$VERSION"
fi
if server_running; then
mc-stop "$VERSION" --confirm
wait_for_server_stop "$VERSION"
fi
upsert_property "online-mode" "false"
upsert_property "enforce-secure-profile" "false"
upsert_property "enable-rcon" "true"
upsert_property "rcon.port" "25575"
upsert_property "rcon.password" "test123"
echo "Configured $VERSION for persistent offline testing"

View file

@ -0,0 +1,35 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -ne 1 ]]; then
echo "Usage: $0 <server-dir>" >&2
exit 1
fi
REPO_ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
SERVER_DIR_NAME="$1"
SERVERS_ROOT="${MCC_SERVERS:-$REPO_ROOT/MinecraftOfficial/downloads}"
SERVER_DIR="$SERVERS_ROOT/$SERVER_DIR_NAME"
PROPS_FILE="$SERVER_DIR/server.properties"
LATEST_LOG="$SERVER_DIR/logs/latest.log"
if [[ -f "$PROPS_FILE" ]]; then
PORT_LINE="$(grep -E '^server-port=' "$PROPS_FILE" | tail -n 1 || true)"
if [[ -n "$PORT_LINE" ]]; then
PORT="${PORT_LINE#server-port=}"
if [[ "$PORT" =~ ^[0-9]+$ ]]; then
printf '%s\n' "$PORT"
exit 0
fi
fi
fi
if [[ -f "$LATEST_LOG" ]]; then
PORT="$(sed -n 's/.*Starting Minecraft server on .*:\([0-9][0-9]*\).*/\1/p' "$LATEST_LOG" | tail -n 1)"
if [[ -n "$PORT" ]]; then
printf '%s\n' "$PORT"
exit 0
fi
fi
printf '25565\n'

View file

@ -0,0 +1,48 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
# shellcheck source=tools/mcc-env.sh
source "$REPO_ROOT/tools/mcc-env.sh"
# shellcheck source=.skills/mcc-integration-testing/scripts/common.sh
source "$SCRIPT_DIR/common.sh"
usage() {
cat <<'EOF'
Usage: preflight_test_env.sh [server-dir...]
Checks the local MCC test environment and resolves common Java path issues.
EOF
}
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
exit 0
fi
ensure_java_in_path
command -v tmux >/dev/null 2>&1 || { echo "tmux was not found on PATH." >&2; exit 1; }
command -v dotnet >/dev/null 2>&1 || { echo "dotnet was not found on PATH." >&2; exit 1; }
command -v python3 >/dev/null 2>&1 || { echo "python3 was not found on PATH." >&2; exit 1; }
if [[ ! -d "$MCC_SERVERS" ]]; then
echo "Server root not found: $MCC_SERVERS" >&2
exit 1
fi
for server_dir in "$@"; do
[[ -z "$server_dir" ]] && continue
if [[ ! -d "$MCC_SERVERS/$server_dir" ]]; then
echo "Server directory not found: $MCC_SERVERS/$server_dir" >&2
exit 1
fi
remove_stale_stdin_pipe "$server_dir"
done
printf 'MCC_REPO=%s\n' "$MCC_REPO"
printf 'MCC_SERVERS=%s\n' "$MCC_SERVERS"
printf 'JAVA=%s\n' "$(command -v java)"
printf 'TMUX=%s\n' "$(command -v tmux)"
printf 'DOTNET=%s\n' "$(command -v dotnet)"

View file

@ -0,0 +1,106 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
# shellcheck source=.skills/mcc-integration-testing/scripts/common.sh
source "$SCRIPT_DIR/common.sh"
usage() {
cat <<'EOF' >&2
Usage:
prepare_offline_mcc_config.sh <output-ini> <mc-version> [login]
prepare_offline_mcc_config.sh <template-ini> <output-ini> <mc-version> [login]
EOF
}
if [[ $# -lt 2 || $# -gt 4 ]]; then
usage
exit 1
fi
TEMPLATE_INI=""
OUTPUT_INI=""
MC_VERSION=""
LOGIN_NAME=""
if [[ $# -ge 3 && -f "$1" ]]; then
TEMPLATE_INI="$1"
OUTPUT_INI="$2"
MC_VERSION="$3"
LOGIN_NAME="${4:-MCCBot}"
else
OUTPUT_INI="$1"
MC_VERSION="$2"
LOGIN_NAME="${3:-MCCBot}"
fi
ACCOUNT_TYPE="${MCC_TEST_ACCOUNT_TYPE:-mojang}"
PASSWORD_VALUE="${MCC_TEST_PASSWORD-}"
if [[ "$ACCOUNT_TYPE" != "mojang" && "$ACCOUNT_TYPE" != "microsoft" && "$ACCOUNT_TYPE" != "yggdrasil" ]]; then
echo "Unsupported MCC_TEST_ACCOUNT_TYPE: $ACCOUNT_TYPE" >&2
exit 1
fi
if [[ -z "${MCC_TEST_PASSWORD+x}" ]]; then
if [[ "$ACCOUNT_TYPE" == "mojang" ]]; then
PASSWORD_VALUE="-"
else
PASSWORD_VALUE=""
fi
fi
generate_template_ini() {
local template_root
template_root="$(mktemp -d "${TMPDIR:-/tmp}/mcc-config-template.XXXXXX")"
if [[ ! -f "$REPO_ROOT/MinecraftClient/bin/Release/net10.0/MinecraftClient.dll" ]]; then
dotnet build "$REPO_ROOT/MinecraftClient.sln" -c Release -v quiet --nologo >/dev/null
fi
(
cd "$template_root"
dotnet run --project "$REPO_ROOT/MinecraftClient" -c Release --no-build -- --help >/dev/null 2>&1
)
if [[ ! -f "$template_root/MinecraftClient.ini" ]]; then
echo "Failed to generate a temporary MCC config template." >&2
exit 1
fi
TEMPLATE_INI="$template_root/MinecraftClient.ini"
}
if [[ -z "$TEMPLATE_INI" ]]; then
generate_template_ini
fi
mkdir -p "$(dirname "$OUTPUT_INI")"
cp "$TEMPLATE_INI" "$OUTPUT_INI"
sed_in_place \
-e "s#^Account = .*#Account = { Login = \"$LOGIN_NAME\", Password = \"$PASSWORD_VALUE\" }#" \
-e "s#^AccountType = .*#AccountType = \"$ACCOUNT_TYPE\"#" \
-e "s#^MinecraftVersion = \"[^\"]*\"\\(.*\\)\$#MinecraftVersion = \"$MC_VERSION\"\\1#" \
-e 's#^TerrainAndMovements = false#TerrainAndMovements = true#' \
-e 's#^InventoryHandling = false#InventoryHandling = true#' \
-e 's#^EntityHandling = false#EntityHandling = true#' \
-e 's#^AutoRespawn = false#AutoRespawn = true#' \
"$OUTPUT_INI"
disable_noisy_bots_in_ini "$OUTPUT_INI"
grep -Fq "AccountType = \"$ACCOUNT_TYPE\"" "$OUTPUT_INI" || {
echo "Failed to enforce account type $ACCOUNT_TYPE in $OUTPUT_INI" >&2
exit 1
}
if [[ "$ACCOUNT_TYPE" == "mojang" ]]; then
grep -Eq '^Account = \{ Login = ".*", Password = "-" \}' "$OUTPUT_INI" || {
echo "Failed to enforce offline account in $OUTPUT_INI" >&2
exit 1
}
fi
printf '%s\n' "$OUTPUT_INI"

View file

@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
# shellcheck source=tools/mcc-env.sh
source "$REPO_ROOT/tools/mcc-env.sh"
# shellcheck source=.skills/mcc-integration-testing/scripts/common.sh
source "$SCRIPT_DIR/common.sh"
usage() {
cat <<'EOF'
Usage: reset_shared_test_state.sh [--all | <server-dir>...]
Kills shared server tmux test sessions and removes stale server stdin pipes.
EOF
}
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
exit 0
fi
kill_named_session() {
local session_name="$1"
tmux kill-session -t "$session_name" 2>/dev/null || true
}
if [[ $# -eq 0 || "${1:-}" == "--all" ]]; then
while IFS= read -r session_name; do
[[ -z "$session_name" ]] && continue
kill_named_session "$session_name"
done < <(tmux list-sessions 2>/dev/null | awk -F: '/^mc-/{print $1}' || true)
while IFS= read -r pipe_path; do
[[ -z "$pipe_path" ]] && continue
rm -f "$pipe_path"
done < <(find "$MCC_SERVERS" -maxdepth 2 -name 'stdin.pipe' 2>/dev/null || true)
else
for version in "$@"; do
kill_named_session "$(server_session_name "$version")"
remove_stale_stdin_pipe "$version"
done
fi

View file

@ -0,0 +1,168 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
# shellcheck source=tools/mcc-env.sh
source "$REPO_ROOT/tools/mcc-env.sh"
RUN_ROOT="${TMPDIR:-/tmp}/mcc-achievements/matrix"
RUN_ID="$(date +%Y%m%d-%H%M%S)"
MATRIX_DIR="$RUN_ROOT/$RUN_ID"
RESULTS_TSV="$MATRIX_DIR/results.tsv"
BUILD_LOG="$MATRIX_DIR/build.log"
REPORT_MD="$MATRIX_DIR/report.md"
PRECHECK_TXT="$MATRIX_DIR/preflight.txt"
mkdir -p "$MATRIX_DIR"
write_row() {
local fields=("$@")
while (( ${#fields[@]} < 14 )); do
fields+=("")
done
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
"${fields[0]}" "${fields[1]}" "${fields[2]}" "${fields[3]}" "${fields[4]}" "${fields[5]}" "${fields[6]}" \
"${fields[7]}" "${fields[8]}" "${fields[9]}" "${fields[10]}" "${fields[11]}" "${fields[12]}" \
"${fields[13]}" >> "$RESULTS_TSV"
}
resolve_server_dir() {
local version="$1"
local candidate
for candidate in "$version" "$version-Vanilla"; do
if [[ -d "$MCC_SERVERS/$candidate" ]]; then
printf '%s\n' "$candidate"
return 0
fi
done
return 1
}
run_version() {
local version="$1"
local profile="$2"
local family="$3"
local server_dir="$4"
local summary_env
if bash "$SCRIPT_DIR/run_achievements_test.sh" --no-build "$server_dir" "$version" "$profile"; then
:
fi
summary_env="${TMPDIR:-/tmp}/mcc-achievements/$server_dir/latest/summary.env"
if [[ ! -f "$summary_env" ]]; then
write_row "$version" "$server_dir" "unknown" "$family" "❌" "❌" "❌" "❌" "❌ Fail" \
"Summary file was not produced." "" "" ""
return
fi
# shellcheck disable=SC1090
source "$summary_env"
if [[ -n "${MCC_LOG:-}" && ! -f "$MCC_LOG" ]]; then
NOTE="Harness failure: MCC log was not produced."
VERDICT="❌ Fail"
fi
if [[ -n "${COMMAND_LOG:-}" && ! -f "$COMMAND_LOG" ]]; then
NOTE="Harness failure: command transcript was not produced."
VERDICT="❌ Fail"
fi
write_row "$VERSION" "$SERVER_DIR" "$PORT" "$FAMILY" "$INITIAL_STATUS" "$GRANT_STATUS" "$REVOKE_STATUS" \
"$API_STATUS" "$VERDICT" "$NOTE" "$RUN_DIR" "$MCC_LOG" "$COPIED_SERVER_LOG" "$COMMAND_LOG"
}
{
printf 'MCC_SERVERS=%s\n' "$MCC_SERVERS"
printf 'RUN_DIR=%s\n' "$MATRIX_DIR"
printf 'DATE=%s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')"
} > "$PRECHECK_TXT"
printf 'Version\tServerDir\tPort\tFamily\tInitial\tGrant\tRevoke\tAPI\tVerdict\tNote\tRunDir\tMccLog\tServerLog\tCommandLog\n' > "$RESULTS_TSV"
JAVA_OK="yes"
TMUX_OK="yes"
DOTNET_OK="yes"
BUILD_OK="yes"
if ! command -v dotnet >/dev/null 2>&1; then
DOTNET_OK="no"
fi
if ! command -v java >/dev/null 2>&1 || ! java -version >/dev/null 2>&1; then
JAVA_OK="no"
fi
if ! command -v tmux >/dev/null 2>&1; then
TMUX_OK="no"
fi
if [[ "$DOTNET_OK" == "yes" ]]; then
bash "$SCRIPT_DIR/preflight_test_env.sh" >/dev/null 2>&1 || true
if ! dotnet build "$REPO_ROOT/MinecraftClient.sln" -c Release > "$BUILD_LOG" 2>&1; then
BUILD_OK="no"
fi
else
: > "$BUILD_LOG"
fi
{
printf 'MCC_SERVERS=%s\n' "$MCC_SERVERS"
printf 'RUN_DIR=%s\n' "$MATRIX_DIR"
printf 'DATE=%s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')"
printf 'dotnet=%s\n' "$DOTNET_OK"
printf 'java=%s\n' "$JAVA_OK"
printf 'tmux=%s\n' "$TMUX_OK"
printf 'build=%s\n' "$BUILD_OK"
} > "$PRECHECK_TXT"
while IFS='|' read -r version profile family; do
[[ -z "$version" ]] && continue
if [[ "$DOTNET_OK" != "yes" ]]; then
write_row "$version" "" "" "$family" "❌" "❌" "❌" "❌" "❌ Fail" \
"dotnet is not available on PATH."
continue
fi
if [[ "$BUILD_OK" != "yes" ]]; then
write_row "$version" "" "" "$family" "❌" "❌" "❌" "❌" "❌ Fail" \
"dotnet build failed. See $BUILD_LOG."
continue
fi
if [[ "$JAVA_OK" != "yes" || "$TMUX_OK" != "yes" ]]; then
write_row "$version" "" "" "$family" "❌" "❌" "❌" "❌" "❌ Fail" \
"java or tmux is not available, so live server execution was blocked."
continue
fi
if ! server_dir="$(resolve_server_dir "$version")"; then
write_row "$version" "" "" "$family" "❌" "❌" "❌" "❌" "⚠️ Partial" \
"Server directory for $version was not found under $MCC_SERVERS."
continue
fi
run_version "$version" "$profile" "$family" "$server_dir"
done <<'EOF'
1.8|legacy|Legacy 🧱
1.11.2|legacy|Legacy 🧱
1.12.2|modern|First advancements 🌱
1.19.4|modern|Stable modern ✅
1.20|modern|Telemetry edge 1 ⚠️
1.20.2|modern|Telemetry edge 2 ⚠️
1.20.4|modern|End of 1.20.x ⚠️
1.20.6|modern|Post-1.20.6 🔧
1.21.2|modern|1.21.2 family 🔧
1.21.11|modern|showAdvancements 🆕
26.1|modern|Latest supported 🚀
EOF
bash "$SCRIPT_DIR/summarize_achievements_matrix.sh" "$MATRIX_DIR" > "$REPORT_MD"
printf '%s\n' "$MATRIX_DIR"

View file

@ -0,0 +1,399 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
# shellcheck source=tools/mcc-env.sh
source "$REPO_ROOT/tools/mcc-env.sh"
# shellcheck source=.skills/mcc-integration-testing/scripts/common.sh
source "$SCRIPT_DIR/common.sh"
usage() {
cat <<'EOF'
Usage: run_achievements_test.sh [--no-build] <server-dir> <mc-version> <legacy|modern>
Examples:
.skills/mcc-integration-testing/scripts/run_achievements_test.sh --no-build 1.8 1.8 legacy
.skills/mcc-integration-testing/scripts/run_achievements_test.sh --no-build 1.21.11-Vanilla 1.21.11 modern
EOF
}
DO_BUILD=true
while [[ $# -gt 0 ]]; do
case "$1" in
--no-build) DO_BUILD=false; shift ;;
--build) DO_BUILD=true; shift ;;
-h|--help) usage; exit 0 ;;
*) break ;;
esac
done
if [[ $# -ne 3 ]]; then
usage >&2
exit 1
fi
SERVER_DIR="$1"
MC_VERSION="$2"
PROFILE="$3"
SESSION_NAME="achievements-${SERVER_DIR//[^a-zA-Z0-9]/_}-${PROFILE}"
TEST_USERNAME="$(_mcc_resolve_username "$SESSION_NAME")"
if [[ "$PROFILE" != "legacy" && "$PROFILE" != "modern" ]]; then
echo "Unsupported profile: $PROFILE" >&2
exit 1
fi
RUN_ROOT="${TMPDIR:-/tmp}/mcc-achievements"
RUN_ID="$(date +%Y%m%d-%H%M%S)"
RUN_DIR="$RUN_ROOT/$SERVER_DIR/$RUN_ID"
LATEST_LINK="$RUN_ROOT/$SERVER_DIR/latest"
MCC_LOG="$RUN_DIR/mcc.log"
BUILD_LOG="$RUN_DIR/build.log"
SERVER_TMUX_LOG="$RUN_DIR/server-tmux.log"
SERVER_FILE_LOG="$RUN_DIR/server-latest.log"
COMMAND_LOG="$RUN_DIR/commands.log"
SUMMARY_ENV="$RUN_DIR/summary.env"
PROBE_SCRIPT="$RUN_DIR/achievement_probe.cs"
CFG="$RUN_DIR/MinecraftClient.$MC_VERSION.ini"
INPUT_FILE="$(_mcc_session_input_file "$SESSION_NAME")"
SERVER_LOG_FILE="$MCC_SERVERS/$SERVER_DIR/logs/latest.log"
TARGET_ID="minecraft:story/root"
TARGET_COMMAND_GRANT="advancement grant $TEST_USERNAME only minecraft:story/root"
TARGET_COMMAND_REVOKE="advancement revoke $TEST_USERNAME only minecraft:story/root"
TARGET_TYPE="Modern 🌱"
PORT="unknown"
MCC_PID=""
INITIAL_STATUS="❌"
GRANT_STATUS="❌"
REVOKE_STATUS="❌"
API_STATUS="❌"
VERDICT="❌ Fail"
NOTE="Run did not complete."
EXECUTED="yes"
if [[ "$PROFILE" == "legacy" ]]; then
TARGET_ID="achievement.openInventory"
TARGET_COMMAND_GRANT="achievement give achievement.openInventory $TEST_USERNAME"
TARGET_COMMAND_REVOKE="achievement take achievement.openInventory $TEST_USERNAME"
TARGET_TYPE="Legacy 🧱"
fi
mkdir -p "$RUN_DIR"
write_summary() {
{
printf 'VERSION=%q\n' "$MC_VERSION"
printf 'SERVER_DIR=%q\n' "$SERVER_DIR"
printf 'PROFILE=%q\n' "$PROFILE"
printf 'FAMILY=%q\n' "$TARGET_TYPE"
printf 'PORT=%q\n' "$PORT"
printf 'RUN_DIR=%q\n' "$RUN_DIR"
printf 'MCC_LOG=%q\n' "$MCC_LOG"
printf 'SERVER_LOG=%q\n' "$RUN_DIR/server-latest.log"
printf 'SERVER_FILE_LOG=%q\n' "$SERVER_LOG_FILE"
printf 'SERVER_TMUX_LOG=%q\n' "$SERVER_TMUX_LOG"
printf 'COPIED_SERVER_LOG=%q\n' "$RUN_DIR/server-latest.log"
printf 'COMMAND_LOG=%q\n' "$COMMAND_LOG"
printf 'SUMMARY_ENV=%q\n' "$SUMMARY_ENV"
printf 'TARGET_ID=%q\n' "$TARGET_ID"
printf 'INITIAL_STATUS=%q\n' "$INITIAL_STATUS"
printf 'GRANT_STATUS=%q\n' "$GRANT_STATUS"
printf 'REVOKE_STATUS=%q\n' "$REVOKE_STATUS"
printf 'API_STATUS=%q\n' "$API_STATUS"
printf 'VERDICT=%q\n' "$VERDICT"
printf 'NOTE=%q\n' "$NOTE"
printf 'EXECUTED=%q\n' "$EXECUTED"
} > "$SUMMARY_ENV"
}
capture_server_logs() {
mc-log "$SERVER_DIR" 400 > "$SERVER_TMUX_LOG" 2>/dev/null || true
if [[ -f "$SERVER_LOG_FILE" ]]; then
cp "$SERVER_LOG_FILE" "$RUN_DIR/server-latest.log" 2>/dev/null || true
fi
}
cleanup() {
capture_server_logs
if [[ -n "${MCC_PID:-}" ]] && kill -0 "$MCC_PID" 2>/dev/null; then
echo "quit" >> "$INPUT_FILE" 2>/dev/null || true
sleep 2
kill "$MCC_PID" 2>/dev/null || true
wait "$MCC_PID" 2>/dev/null || true
fi
mc-stop "$SERVER_DIR" --confirm >/dev/null 2>&1 || true
wait_for_server_stop "$SERVER_DIR" 20 >/dev/null 2>&1 || true
ln -sfn "$RUN_DIR" "$LATEST_LINK"
write_summary
}
trap cleanup EXIT
log_step() {
printf '[%s] %s\n' "$(date '+%H:%M:%S')" "$1" | tee -a "$COMMAND_LOG"
}
fail() {
NOTE="$1"
VERDICT="❌ Fail"
exit 1
}
wait_for_file_pattern() {
local file="$1"
local pattern="$2"
local description="$3"
local timeout="${4:-60}"
local elapsed=0
while (( elapsed < timeout )); do
if [[ -f "$file" ]] && grep -Fq "$pattern" "$file"; then
return 0
fi
sleep 1
((elapsed += 1))
done
echo "Timed out waiting for: $description" >&2
return 1
}
write_probe_script() {
cat > "$PROBE_SCRIPT" <<EOF
//MCCScript 1.0
MCC.LoadBot(new AchievementProbeBot());
//MCCScript Extensions
public class AchievementProbeBot : ChatBot
{
private const string TargetId = "$TARGET_ID";
public override void Initialize()
{
LogToConsole("[ACH_TEST] probe initialized");
DumpState("initialize");
}
public override void AfterGameJoined()
{
LogToConsole("[ACH_TEST] after join");
DumpState("after_join");
}
public override void OnAchievementUpdate(IReadOnlyList<Achievement> updated, IReadOnlyList<string> removedIds, bool reset)
{
LogToConsole($"[ACH_TEST] event reset={reset} updated={updated.Count} removed={removedIds.Count}");
DumpState("event");
}
private void DumpState(string origin)
{
Achievement[] all = GetAchievements();
Achievement[] unlocked = GetUnlockedAchievements();
Achievement[] locked = GetLockedAchievements();
Achievement? target = null;
foreach (Achievement entry in all)
{
if (entry.Id == TargetId)
{
target = entry;
break;
}
}
string titleState = "missing";
string completionState = "missing";
if (target is not null)
{
titleState = target.Title is null ? "null" : "present";
completionState = target.IsCompleted ? "done" : "todo";
}
LogToConsole($"[ACH_TEST] snapshot origin={origin} all={all.Length} unlocked={unlocked.Length} locked={locked.Length}");
LogToConsole($"[ACH_TEST] target_state origin={origin} id={TargetId} title={titleState} completed={completionState}");
}
}
EOF
}
run_server_command() {
local cmd="$1"
local attempt
log_step "SERVER> $cmd"
for attempt in 1 2 3 4 5; do
if mc-rcon "$cmd" >/dev/null 2>&1; then
sleep 1
return 0
fi
sleep 1
done
fail "Server command failed: $cmd"
}
run_mcc_command() {
local name="$1"
local cmd="$2"
local delay="${3:-2}"
local start_line=0
local end_line=0
if [[ -f "$MCC_LOG" ]]; then
start_line="$(wc -l < "$MCC_LOG")"
fi
log_step "MCC> $cmd"
echo "$cmd" >> "$INPUT_FILE"
sleep "$delay"
if [[ -f "$MCC_LOG" ]]; then
end_line="$(wc -l < "$MCC_LOG")"
fi
if (( end_line > start_line )); then
sed -n "$((start_line + 1)),$((end_line))p" "$MCC_LOG" > "$RUN_DIR/$name.mcc.log"
else
: > "$RUN_DIR/$name.mcc.log"
fi
}
assert_pattern() {
local file="$1"
local pattern="$2"
local description="$3"
grep -Fq "$pattern" "$file" || fail "$description"
}
if $DO_BUILD; then
log_step "BUILD> dotnet build MinecraftClient.sln -c Release"
mcc-build > "$BUILD_LOG" 2>&1 || fail "dotnet build failed."
else
: > "$BUILD_LOG"
fi
bash "$SCRIPT_DIR/preflight_test_env.sh" "$SERVER_DIR" >/dev/null || fail "Test environment preflight failed."
bash "$SCRIPT_DIR/reset_shared_test_state.sh" "$SERVER_DIR" >/dev/null || fail "Failed to reset shared test state."
if [[ ! -d "$MCC_SERVERS/$SERVER_DIR" ]]; then
fail "Server directory not found: $MCC_SERVERS/$SERVER_DIR"
fi
bash "$SCRIPT_DIR/prepare_offline_mcc_config.sh" "$CFG" "$MC_VERSION" "$TEST_USERNAME" >/dev/null || fail "Failed to prepare temporary MCC config."
PORT="$(bash "$SCRIPT_DIR/get_server_port.sh" "$SERVER_DIR")"
"$SCRIPT_DIR/ensure_offline_server.sh" "$SERVER_DIR"
write_probe_script
if [[ "$PROFILE" == "legacy" && -f "$MCC_SERVERS/$SERVER_DIR/server.properties" ]]; then
sed_in_place 's/^use-native-transport=.*/use-native-transport=false/' "$MCC_SERVERS/$SERVER_DIR/server.properties"
fi
mkdir -p "$(dirname "$INPUT_FILE")"
: > "$INPUT_FILE"
rm -f "$MCC_LOG"
log_step "Starting server $SERVER_DIR on port $PORT"
mc-start "$SERVER_DIR" >/dev/null
wait_for_server_ready "$SERVER_DIR" || fail "Server did not become ready."
log_step "Starting MCC for $MC_VERSION"
(
cd "$REPO_ROOT"
MCC_FILE_INPUT=1 MCC_INPUT_FILE="$INPUT_FILE" dotnet run --project MinecraftClient -c Release --no-build -- \
"$CFG" \
"$TEST_USERNAME" \
- \
"localhost:$PORT" \
"--accounttype=mojang" \
"--minecraftversion=$MC_VERSION" \
"--terrainandmovements=true" \
"--inventoryhandling=true" \
"--entityhandling=true" \
"--autorespawn=true" \
"--debugmessages=true" \
> "$MCC_LOG" 2>&1
) &
MCC_PID=$!
wait_for_file_pattern "$MCC_LOG" "Server was successfully joined." "MCC join success" 90 || fail "MCC failed to join."
wait_for_file_pattern "$SERVER_LOG_FILE" "$TEST_USERNAME joined the game" "server join entry" 30 || fail "Server never logged the join."
run_server_command "op $TEST_USERNAME"
run_server_command "gamerule sendCommandFeedback true"
if [[ "$PROFILE" == "modern" ]]; then
run_server_command "gamerule logAdminCommands true"
fi
run_server_command "time set day"
run_server_command "weather clear"
run_mcc_command "load_probe" "script $PROBE_SCRIPT" 3
wait_for_file_pattern "$MCC_LOG" "[ACH_TEST] probe initialized" "probe startup" 30 || fail "Probe script did not initialize."
run_mcc_command "baseline_debug" "debug state" 2
run_mcc_command "baseline_all" "achievement" 2
run_mcc_command "baseline_locked" "achievement locked" 2
run_mcc_command "baseline_unlocked" "achievement unlocked" 2
run_server_command "$TARGET_COMMAND_GRANT"
sleep 3
run_mcc_command "after_grant_all" "achievement" 2
run_mcc_command "after_grant_unlocked" "achievement unlocked" 2
run_server_command "$TARGET_COMMAND_REVOKE"
sleep 3
run_mcc_command "after_revoke_all" "achievement" 2
run_mcc_command "after_revoke_locked" "achievement locked" 2
assert_pattern "$MCC_LOG" "Achievements/Advancements:" "Achievement command header never appeared."
if ! grep -Fq "No achievements/advancements received yet." "$RUN_DIR/baseline_all.mcc.log"; then
INITIAL_STATUS="✅"
fi
if grep -Fq "$TARGET_ID" "$RUN_DIR/after_grant_unlocked.mcc.log" && grep -Fq "[DONE]" "$RUN_DIR/after_grant_unlocked.mcc.log"; then
GRANT_STATUS="✅"
fi
if [[ "$PROFILE" == "legacy" ]]; then
if grep -Fq "$TARGET_ID" "$RUN_DIR/after_revoke_locked.mcc.log" && grep -Fq "[TODO]" "$RUN_DIR/after_revoke_locked.mcc.log"; then
REVOKE_STATUS="✅"
fi
else
if grep -Fq "$TARGET_ID" "$RUN_DIR/after_revoke_locked.mcc.log" && grep -Fq "[TODO]" "$RUN_DIR/after_revoke_locked.mcc.log"; then
REVOKE_STATUS="✅"
elif [[ "$GRANT_STATUS" == "✅" ]] && ! grep -Fq "$TARGET_ID" "$RUN_DIR/after_revoke_all.mcc.log"; then
REVOKE_STATUS="✅"
fi
fi
if grep -Fq "[ACH_TEST] event" "$MCC_LOG" && grep -Fq "target_state origin=event id=$TARGET_ID title=" "$MCC_LOG"; then
API_STATUS="✅"
fi
case "$INITIAL_STATUS|$GRANT_STATUS|$REVOKE_STATUS|$API_STATUS" in
"✅|✅|✅|✅")
VERDICT="✅ Pass"
NOTE="All planned achievement checks passed."
;;
*"✅"*)
VERDICT="⚠️ Partial"
NOTE="At least one achievement phase passed, but the matrix did not fully clear."
;;
*)
VERDICT="❌ Fail"
NOTE="Achievement checks did not produce the expected evidence."
;;
esac
run_mcc_command "quit" "quit" 2
NOTE="$NOTE Artifacts saved in $RUN_DIR."

View file

@ -0,0 +1,336 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
# shellcheck source=tools/mcc-env.sh
source "$REPO_ROOT/tools/mcc-env.sh"
# shellcheck source=.skills/mcc-integration-testing/scripts/common.sh
source "$SCRIPT_DIR/common.sh"
VERSION="${1:-1.21.11-Vanilla}"
MC_VERSION="${VERSION%-Vanilla}"
if [[ "$MC_VERSION" == "$VERSION" ]]; then
MC_VERSION="$VERSION"
fi
RUN_ROOT="${TMPDIR:-/tmp}/mcc-integration-testing"
RUN_ID="$(date +%Y%m%d-%H%M%S)"
RUN_DIR="$RUN_ROOT/$RUN_ID"
SERVER_LOG_FILE="$MCC_SERVERS/$VERSION/logs/latest.log"
SESSION_NAME="full-spectrum-${MC_VERSION//[^a-zA-Z0-9]/_}"
TEST_USERNAME="$(_mcc_resolve_username "$SESSION_NAME")"
MCC_LOG="$(_mcc_session_log_file "$SESSION_NAME")"
PID_FILE="$(_mcc_session_pid_file "$SESSION_NAME")"
MCC_TMUX_SESSION="$(_mcc_tmux_session_name "$SESSION_NAME")"
BUILD_LOG="$RUN_DIR/build.log"
SERVER_TMUX_LOG="$RUN_DIR/server-tmux.log"
SERVER_FILE_LOG="$RUN_DIR/server-latest.log"
INPUT_FILE="$(_mcc_session_input_file "$SESSION_NAME")"
CFG="$RUN_DIR/MinecraftClient.$MC_VERSION.ini"
mkdir -p "$RUN_DIR"
cleanup() {
mcc-cmd --session "$SESSION_NAME" "quit" >/dev/null 2>&1 || true
sleep 2
mcc-kill --session "$SESSION_NAME" >/dev/null 2>&1 || true
mc-stop "$VERSION" --confirm >/dev/null 2>&1 || true
wait_for_server_stop "$VERSION" 20 >/dev/null 2>&1 || true
}
trap cleanup EXIT
prepare_config() {
bash "$SCRIPT_DIR/prepare_offline_mcc_config.sh" "$CFG" "$MC_VERSION" "$TEST_USERNAME" >/dev/null
}
wait_for_server_log_pattern() {
local pattern="$1"
local description="$2"
local timeout="${3:-60}"
local elapsed=0
while (( elapsed < timeout )); do
if [[ -f "$SERVER_LOG_FILE" ]] && grep -Fq "$pattern" "$SERVER_LOG_FILE"; then
return 0
fi
sleep 1
((elapsed += 1))
done
echo "Timed out waiting for server log: $description" >&2
return 1
}
capture_server_logs() {
mc-log "$VERSION" 400 > "$SERVER_TMUX_LOG" 2>/dev/null || true
if [[ -f "$SERVER_LOG_FILE" ]]; then
cp "$SERVER_LOG_FILE" "$SERVER_FILE_LOG"
fi
}
wait_for_file_pattern() {
local file="$1"
local pattern="$2"
local description="$3"
local timeout="${4:-60}"
local elapsed=0
while (( elapsed < timeout )); do
if [[ -f "$file" ]] && grep -Fq "$pattern" "$file"; then
return 0
fi
sleep 1
((elapsed += 1))
done
echo "Timed out waiting for: $description" >&2
return 1
}
fail() {
capture_server_logs
echo "FAIL: $1" >&2
echo "Run directory: $RUN_DIR" >&2
exit 1
}
assert_contains() {
local file="$1"
local pattern="$2"
local description="$3"
grep -Fq "$pattern" "$file" || fail "$description"
}
assert_not_contains() {
local file="$1"
local pattern="$2"
local description="$3"
if grep -Fq "$pattern" "$file"; then
fail "$description"
fi
}
run_server_command() {
local cmd="$1"
local attempt
echo "SERVER> $cmd"
for attempt in 1 2 3 4 5; do
if mc-rcon "$cmd" >/dev/null 2>&1; then
return 0
fi
sleep 1
done
fail "Server command failed: $cmd"
}
run_mcc_command() {
local cmd="$1"
echo "MCC> $cmd"
mcc-cmd --session "$SESSION_NAME" "$cmd"
sleep 2
}
start_mcc_session() {
local -a mcc_args=("$CFG" "$TEST_USERNAME" "-" "localhost:$SERVER_PORT")
local mcc_args_cmd
mcc_args_cmd="$(printf '%q ' "${mcc_args[@]}")"
tmux kill-session -t "$MCC_TMUX_SESSION" 2>/dev/null || true
rm -f "$PID_FILE"
tmux new-session -d -s "$MCC_TMUX_SESSION" -x 160 -y 50 \
"cd '$REPO_ROOT' && printf '%s\n' \"\$\$\" > '$PID_FILE' && exec env MCC_FILE_INPUT=1 MCC_INPUT_FILE='$INPUT_FILE' dotnet run --project MinecraftClient -c Release --no-build -- $mcc_args_cmd > '$MCC_LOG' 2>&1"
for _ in $(seq 1 25); do
if [[ -s "$PID_FILE" ]]; then
return 0
fi
sleep 0.2
done
fail "Failed to capture MCC PID for session $SESSION_NAME"
}
bash "$SCRIPT_DIR/preflight_test_env.sh" "$VERSION" >/dev/null
bash "$SCRIPT_DIR/reset_shared_test_state.sh" "$VERSION" >/dev/null
"$SCRIPT_DIR/ensure_offline_server.sh" "$VERSION"
mcc-reset-session --session "$SESSION_NAME" >/dev/null
echo "Building MCC..."
mcc-build > "$BUILD_LOG" 2>&1 || fail "mcc-build failed"
prepare_config
SERVER_PORT="$(bash "$SCRIPT_DIR/get_server_port.sh" "$VERSION")"
if [[ -z "$SERVER_PORT" ]]; then
fail "Failed to resolve server port"
fi
mkdir -p "$(dirname "$INPUT_FILE")" "$(dirname "$MCC_LOG")"
: > "$INPUT_FILE"
rm -f "$MCC_LOG"
echo "Starting server..."
mc-start "$VERSION" >/dev/null
wait_for_server_ready "$VERSION" || fail "Server did not become ready"
echo "Starting MCC..."
start_mcc_session
wait_for_file_pattern "$MCC_LOG" "Server was successfully joined." "MCC join success" 90 || fail "MCC failed to join"
wait_for_server_log_pattern "$TEST_USERNAME joined the game" "server join entry" 30 || fail "Server never logged the join"
run_server_command "op $TEST_USERNAME"
run_server_command "gamerule sendCommandFeedback true"
run_server_command "gamerule logAdminCommands true"
run_server_command "time set day"
run_server_command "weather clear"
sleep 2
# ── Phase 1: Basic status and info commands ──
run_mcc_command "health"
run_mcc_command "list"
run_mcc_command "inventory player list"
run_mcc_command "/gamemode creative"
run_mcc_command "inventory creativegive 36 Diamond 16"
run_mcc_command "inventory player list"
run_mcc_command "entity"
run_mcc_command "/time query daytime"
run_mcc_command "smoke_test_from_mcc_full_spectrum"
# ── Phase 2: Movement and look commands ──
run_mcc_command "/tp $TEST_USERNAME 0 -60 0"
sleep 3
run_mcc_command "look up"
sleep 1
run_mcc_command "look down"
sleep 1
run_mcc_command "look east"
sleep 1
# ── Phase 3: Advanced inventory operations ──
run_mcc_command "inventory creativegive 37 IronSword 1"
run_mcc_command "inventory creativegive 38 GoldenApple 8"
run_mcc_command "inventory player list"
run_mcc_command "inventory creativeclear 38"
run_mcc_command "inventory player list"
# ── Phase 4: Block placement and interaction ──
run_server_command "execute as $TEST_USERNAME at @s run fill ~1 ~ ~1 ~3 ~2 ~3 minecraft:stone"
sleep 2
run_server_command "execute as $TEST_USERNAME at @s run setblock ~5 ~ ~5 minecraft:chest"
sleep 1
run_server_command "execute as $TEST_USERNAME at @s run setblock ~5 ~1 ~5 minecraft:furnace"
sleep 1
run_server_command "execute as $TEST_USERNAME at @s run setblock ~6 ~ ~5 minecraft:crafting_table"
sleep 1
# ── Phase 5: Entity spawning (expanded coverage) ──
run_server_command "execute as $TEST_USERNAME at @s run summon minecraft:cow ~2 ~ ~"
run_server_command "execute as $TEST_USERNAME at @s run summon minecraft:zombie ~4 ~ ~"
run_server_command "execute as $TEST_USERNAME at @s run summon minecraft:creeper ~6 ~ ~"
run_server_command "execute as $TEST_USERNAME at @s run summon minecraft:skeleton ~8 ~ ~"
run_server_command "execute as $TEST_USERNAME at @s run summon minecraft:villager ~-2 ~ ~"
run_server_command "execute as $TEST_USERNAME at @s run summon minecraft:allay ~-4 ~ ~"
run_server_command "execute as $TEST_USERNAME at @s run summon minecraft:armor_stand ~ ~ ~2"
run_server_command "execute as $TEST_USERNAME at @s run summon minecraft:item_display ~-6 ~ ~ {item:{id:\"minecraft:diamond\",count:1}}"
run_server_command "execute as $TEST_USERNAME at @s run summon minecraft:spider ~10 ~ ~"
run_server_command "execute as $TEST_USERNAME at @s run summon minecraft:pig ~-8 ~ ~"
sleep 2
run_mcc_command "entity"
# ── Phase 6: Effects and environment ──
run_server_command "effect give $TEST_USERNAME minecraft:speed 30 1"
sleep 2
run_mcc_command "health"
run_server_command "effect give $TEST_USERNAME minecraft:regeneration 10 1"
sleep 2
run_mcc_command "health"
# ── Phase 7: Gamemode cycling ──
run_mcc_command "/gamemode survival"
sleep 2
run_mcc_command "health"
run_mcc_command "/gamemode creative"
sleep 2
# ── Phase 8: Dimension change (nether) ──
run_server_command "execute in minecraft:the_nether run tp $TEST_USERNAME 0 64 0"
sleep 4
run_mcc_command "health"
run_server_command "execute in minecraft:overworld run tp $TEST_USERNAME 0 -60 0"
sleep 4
# ── Phase 9: Server chat and whisper ──
run_server_command "say Hello from the server console"
sleep 2
run_server_command "msg $TEST_USERNAME This is a private whisper"
sleep 2
run_mcc_command "integration_test_chat_response"
# ── Phase 10: Particles, sounds, and explosions ──
run_server_command "execute as $TEST_USERNAME at @s run particle minecraft:happy_villager ~ ~1 ~ 0.5 0.5 0.5 0 12 force"
run_server_command "execute as $TEST_USERNAME at @s run particle minecraft:end_rod ~ ~1 ~ 0.5 0.5 0.5 0.01 20 force"
run_server_command "execute as $TEST_USERNAME at @s run particle minecraft:explosion ~ ~1 ~ 0 0 0 0 1 force"
run_server_command "execute as $TEST_USERNAME at @s run particle minecraft:totem_of_undying ~ ~1 ~ 0.5 0.5 0.5 0.1 20 force"
run_server_command "execute as $TEST_USERNAME at @s run particle minecraft:flame ~ ~1 ~ 0.2 0.2 0.2 0.02 30 force"
run_server_command "execute as $TEST_USERNAME at @s run particle minecraft:heart ~ ~2 ~ 0.3 0.3 0.3 0 5 force"
run_server_command "execute as $TEST_USERNAME at @s run playsound minecraft:entity.lightning_bolt.thunder master $TEST_USERNAME ~ ~ ~ 1 1 0"
run_server_command "execute as $TEST_USERNAME at @s run playsound minecraft:block.note_block.bell master $TEST_USERNAME ~ ~ ~ 1 1 0"
run_server_command "execute as $TEST_USERNAME at @s run playsound minecraft:entity.experience_orb.pickup master $TEST_USERNAME ~ ~ ~ 1 1 0"
run_server_command "execute as $TEST_USERNAME at @s run summon minecraft:tnt ~3 ~ ~"
sleep 2
run_server_command "execute as $TEST_USERNAME at @s run summon minecraft:tnt ~6 ~ ~"
# ── Phase 11: Kill and respawn cycle ──
run_mcc_command "/gamemode survival"
sleep 2
run_server_command "kill $TEST_USERNAME"
sleep 4
run_mcc_command "respawn"
sleep 4
run_mcc_command "health"
run_mcc_command "/gamemode creative"
sleep 2
sleep 6
capture_server_logs
# ── Assertions: MCC log ──
assert_contains "$MCC_LOG" "Server was successfully joined." "MCC never joined the server"
assert_contains "$MCC_LOG" "[FileInput] > inventory player list" "Inventory command was not executed"
assert_contains "$MCC_LOG" "[FileInput] > entity" "Entity command was not executed"
assert_contains "$MCC_LOG" "[FileInput] > /gamemode creative" "Creative mode command was not executed from MCC"
assert_contains "$MCC_LOG" "Requested Diamond x16 in slot #36" "Creative inventory give did not succeed"
assert_contains "$MCC_LOG" "smoke_test_from_mcc_full_spectrum" "Client-originated chat was not observed"
assert_contains "$MCC_LOG" "[FileInput] > look up" "Look command was not executed"
assert_contains "$MCC_LOG" "[FileInput] > /gamemode survival" "Survival mode switch was not executed"
assert_contains "$MCC_LOG" "[FileInput] > respawn" "Respawn command was not executed"
assert_contains "$MCC_LOG" "[FileInput] > health" "Health command was not executed"
assert_contains "$MCC_LOG" "integration_test_chat_response" "Chat response test message was not observed"
assert_not_contains "$MCC_LOG" "Please enable InventoryHandling" "Inventory handling is still disabled"
assert_not_contains "$MCC_LOG" "Please enable EntityHandling" "Entity handling is still disabled"
assert_not_contains "$MCC_LOG" "You must be in Creative gamemode" "Creative mode was not active when creativegive ran"
assert_not_contains "$MCC_LOG" "Failed to load settings" "MCC failed to reload its config"
assert_not_contains "$MCC_LOG" "NullReferenceException" "A NullReferenceException occurred during the test"
# ── Assertions: Server log ──
assert_contains "$SERVER_FILE_LOG" "$TEST_USERNAME joined the game" "Server never saw $TEST_USERNAME join"
assert_contains "$SERVER_FILE_LOG" "smoke_test_from_mcc_full_spectrum" "Server never received the client chat message"
assert_contains "$SERVER_FILE_LOG" "Displaying particle minecraft:happy_villager" "Particle events were not recorded on the server"
assert_contains "$SERVER_FILE_LOG" "Played sound minecraft:block.note_block.bell to $TEST_USERNAME" "Sound events were not recorded on the server"
assert_contains "$SERVER_FILE_LOG" "Summoned new Primed TNT" "TNT summon did not occur on the server"
assert_contains "$SERVER_FILE_LOG" "integration_test_chat_response" "Server never received the chat response test message"
assert_contains "$SERVER_FILE_LOG" "Hello from the server console" "Server say command was not logged"
assert_contains "$SERVER_FILE_LOG" "Killed $TEST_USERNAME" "Server kill command did not execute"
assert_not_contains "$SERVER_FILE_LOG" "Sending unknown packet 'clientbound/minecraft:disconnect'" "Server hit the disconnect packet regression during the test"
cat <<EOF
PASS
Run directory: $RUN_DIR
MCC log: $MCC_LOG
Server log: $SERVER_FILE_LOG
Build log: $BUILD_LOG
EOF

View file

@ -0,0 +1,199 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
# shellcheck source=tools/mcc-env.sh
source "$REPO_ROOT/tools/mcc-env.sh"
# shellcheck source=.skills/mcc-integration-testing/scripts/common.sh
source "$SCRIPT_DIR/common.sh"
VERSION="${1:-1.21.11-Vanilla}"
MC_VERSION="${VERSION%-Vanilla}"
if [[ "$MC_VERSION" == "$VERSION" ]]; then
MC_VERSION="$VERSION"
fi
SESSION_A="parallel-smoke-a-${MC_VERSION//[^a-zA-Z0-9]/_}"
SESSION_B="parallel-smoke-b-${MC_VERSION//[^a-zA-Z0-9]/_}"
USERNAME_A="SmokeA"
USERNAME_B="SmokeB"
RUN_ROOT="${TMPDIR:-/tmp}/mcc-integration-testing"
RUN_ID="$(date +%Y%m%d-%H%M%S)"
RUN_DIR="$RUN_ROOT/parallel-smoke-$RUN_ID"
BUILD_LOG="$RUN_DIR/build.log"
SERVER_TMUX_LOG="$RUN_DIR/server-tmux.log"
SERVER_FILE_LOG="$RUN_DIR/server-latest.log"
SERVER_LOG_FILE="$MCC_SERVERS/$VERSION/logs/latest.log"
LOG_A="$(_mcc_session_log_file "$SESSION_A")"
LOG_B="$(_mcc_session_log_file "$SESSION_B")"
INPUT_A="$(_mcc_session_input_file "$SESSION_A")"
INPUT_B="$(_mcc_session_input_file "$SESSION_B")"
PID_A_FILE="$(_mcc_session_pid_file "$SESSION_A")"
PID_B_FILE="$(_mcc_session_pid_file "$SESSION_B")"
mkdir -p "$RUN_DIR"
wait_for_file_pattern() {
local file="$1"
local pattern="$2"
local description="$3"
local timeout="${4:-60}"
local elapsed=0
while (( elapsed < timeout )); do
if [[ -f "$file" ]] && grep -Fq "$pattern" "$file"; then
return 0
fi
sleep 1
((elapsed += 1))
done
echo "Timed out waiting for: $description" >&2
return 1
}
wait_for_server_log_pattern() {
local pattern="$1"
local description="$2"
local timeout="${3:-60}"
local elapsed=0
while (( elapsed < timeout )); do
if [[ -f "$SERVER_LOG_FILE" ]] && grep -Fq "$pattern" "$SERVER_LOG_FILE"; then
return 0
fi
sleep 1
((elapsed += 1))
done
echo "Timed out waiting for server log: $description" >&2
return 1
}
capture_server_logs() {
mc-log "$VERSION" 400 > "$SERVER_TMUX_LOG" 2>/dev/null || true
if [[ -f "$SERVER_LOG_FILE" ]]; then
cp "$SERVER_LOG_FILE" "$SERVER_FILE_LOG"
fi
}
fail() {
capture_server_logs
echo "FAIL: $1" >&2
echo "Run directory: $RUN_DIR" >&2
exit 1
}
cleanup() {
mcc-cmd --session "$SESSION_A" "quit" >/dev/null 2>&1 || true
mcc-cmd --session "$SESSION_B" "quit" >/dev/null 2>&1 || true
sleep 1
mcc-kill --session "$SESSION_A" >/dev/null 2>&1 || true
mcc-kill --session "$SESSION_B" >/dev/null 2>&1 || true
mc-stop "$VERSION" --confirm >/dev/null 2>&1 || true
wait_for_server_stop "$VERSION" 20 >/dev/null 2>&1 || true
}
trap cleanup EXIT
assert_session_alive() {
local session="$1"
local pid_file="$2"
if [[ -s "$pid_file" ]]; then
local pid
pid="$(tr -cd '0-9' < "$pid_file")"
if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then
return 0
fi
fi
tmux has-session -t "$(_mcc_tmux_session_name "$session")" 2>/dev/null
}
assert_server_alive() {
server_running "$VERSION" || fail "Shared server session is not alive"
}
start_file_input_session() {
local session="$1"
local username="$2"
local port="$3"
bash "$REPO_ROOT/tools/mcc-debug.sh" \
--version "$VERSION" \
--port "$port" \
--file-input \
--no-build \
--session "$session" \
--username "$username" >/dev/null
}
bash "$SCRIPT_DIR/preflight_test_env.sh" "$VERSION" >/dev/null
bash "$SCRIPT_DIR/reset_shared_test_state.sh" "$VERSION" >/dev/null
"$SCRIPT_DIR/ensure_offline_server.sh" "$VERSION" >/dev/null
mcc-reset-session --session "$SESSION_A" >/dev/null
mcc-reset-session --session "$SESSION_B" >/dev/null
echo "Building MCC..."
mcc-build > "$BUILD_LOG" 2>&1 || fail "mcc-build failed"
echo "Starting shared server..."
mc-start "$VERSION" >/dev/null
wait_for_server_ready "$VERSION" || fail "Server did not become ready"
SERVER_PORT="$(bash "$SCRIPT_DIR/get_server_port.sh" "$VERSION")"
if [[ -z "$SERVER_PORT" ]]; then
fail "Failed to resolve server port"
fi
echo "Starting MCC session A..."
start_file_input_session "$SESSION_A" "$USERNAME_A" "$SERVER_PORT"
echo "Starting MCC session B..."
start_file_input_session "$SESSION_B" "$USERNAME_B" "$SERVER_PORT"
wait_for_file_pattern "$LOG_A" "Server was successfully joined." "session A join success" 90 || fail "Session A failed to join"
wait_for_file_pattern "$LOG_B" "Server was successfully joined." "session B join success" 90 || fail "Session B failed to join"
wait_for_server_log_pattern "$USERNAME_A joined the game" "server join for session A" 30 || fail "Server never logged $USERNAME_A join"
wait_for_server_log_pattern "$USERNAME_B joined the game" "server join for session B" 30 || fail "Server never logged $USERNAME_B join"
echo "Sending debug state to both sessions..."
mcc-cmd --session "$SESSION_A" "debug state"
mcc-cmd --session "$SESSION_B" "debug state"
sleep 2
wait_for_file_pattern "$LOG_A" "[FileInput] > debug state" "session A debug state command" 20 || fail "Session A did not consume debug state"
wait_for_file_pattern "$LOG_B" "[FileInput] > debug state" "session B debug state command" 20 || fail "Session B did not consume debug state"
echo "Killing session A..."
mcc-kill --session "$SESSION_A" >/dev/null 2>&1 || true
sleep 2
assert_session_alive "$SESSION_B" "$PID_B_FILE" || fail "Session B is not alive after killing session A"
assert_server_alive
echo "Verifying session B still responds..."
mcc-cmd --session "$SESSION_B" "health"
wait_for_file_pattern "$LOG_B" "[FileInput] > health" "session B health command after session A kill" 20 || fail "Session B stopped responding after session A kill"
if [[ -s "$PID_A_FILE" ]]; then
pid_a="$(tr -cd '0-9' < "$PID_A_FILE")"
if [[ -n "$pid_a" ]] && kill -0 "$pid_a" 2>/dev/null; then
fail "Session A is still alive after mcc-kill"
fi
fi
capture_server_logs
cat <<EOF
PASS
Run directory: $RUN_DIR
Server version: $VERSION
Server port: $SERVER_PORT
Session A: $SESSION_A ($USERNAME_A)
Session A input: $INPUT_A
Session A log: $LOG_A
Session B: $SESSION_B ($USERNAME_B)
Session B input: $INPUT_B
Session B log: $LOG_B
Server log: $SERVER_FILE_LOG
Build log: $BUILD_LOG
EOF

View file

@ -0,0 +1,57 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -ne 1 ]]; then
echo "Usage: summarize_achievements_matrix.sh <matrix-run-dir>" >&2
exit 1
fi
MATRIX_DIR="$1"
RESULTS_TSV="$MATRIX_DIR/results.tsv"
PRECHECK_TXT="$MATRIX_DIR/preflight.txt"
BUILD_LOG="$MATRIX_DIR/build.log"
if [[ ! -f "$RESULTS_TSV" ]]; then
echo "Missing results file: $RESULTS_TSV" >&2
exit 1
fi
echo "# Achievements Matrix Report"
echo
echo "## Executed"
echo
if [[ -f "$PRECHECK_TXT" ]]; then
echo '```text'
cat "$PRECHECK_TXT"
echo '```'
fi
echo
echo "- Matrix artifacts: \`$MATRIX_DIR\`"
echo "- Results TSV: \`$RESULTS_TSV\`"
echo "- Build log: \`$BUILD_LOG\`"
echo "- Execution mode: sequential"
echo "- Auth mode: offline"
echo
echo "## Observed"
echo
echo "| Version | Port | Family | Initial snapshot | Grant | Revoke | API callback | Verdict |"
echo "|---|---:|---|---|---|---|---|---|"
awk -F '\t' 'NR > 1 {
printf("| `%s` | `%s` | %s | %s | %s | %s | %s | %s |\n",
$1, $3, $4, $5, $6, $7, $8, $9);
}' "$RESULTS_TSV"
echo
echo "## Artifact Links"
echo
awk -F '\t' 'NR > 1 {
printf("- `%s`: run=`%s`, mcc=`%s`, server=`%s`, commands=`%s`\n", $1, $11, $12, $13, $14);
printf(" note: %s\n", $10);
}' "$RESULTS_TSV"
echo
echo "## Inferred"
echo
echo "- Only rows with real MCC and server-log artifacts count as executed proof."
echo "- Rows blocked by missing Java, tmux, or server directories are environment-limited, not product pass results."
echo "- Rows with missing MCC or command-log artifacts should be treated as harness failures until rerun confirms a product issue."

View file

@ -0,0 +1,25 @@
#!/usr/bin/env zsh
set -euo pipefail
RUN_ROOT="${TMPDIR:-/tmp}/mcc-integration-testing"
RUN_DIR="${1:-$(find "$RUN_ROOT" -mindepth 1 -maxdepth 1 -type d | sort | tail -n 1)}"
if [[ -z "${RUN_DIR:-}" ]] || [[ ! -d "$RUN_DIR" ]]; then
echo "Run directory not found" >&2
exit 1
fi
MCC_LOG="$RUN_DIR/mcc.log"
SERVER_LOG="$RUN_DIR/server-latest.log"
BUILD_LOG="$RUN_DIR/build.log"
echo "Run directory: $RUN_DIR"
echo
echo "Build result:"
grep -E "Warning\(s\)|Error\(s\)|Time Elapsed" "$BUILD_LOG" || true
echo
echo "MCC highlights:"
grep -E "Server was successfully joined|FileInput|smoke_test_from_mcc_full_spectrum|There are [0-9]+ of a max|health|Creative" "$MCC_LOG" || true
echo
echo "Server highlights:"
grep -E "joined the game|Made .* a server operator|game mode|smoke_test_from_mcc_full_spectrum|summon|particle|playsound|tnt" "$SERVER_LOG" || true

View file

@ -0,0 +1,351 @@
---
name: mcc-version-adaptation
description: Adapt MCC palettes and protocol handling for a new Minecraft version. Use when the user wants to add support for a new MC version, compare version registries, update item/entity/block/metadata palettes, or fix protocol mismatches between MC versions.
---
# MCC Version Adaptation
Systematic workflow for updating Minecraft Console Client to support a new Minecraft version, focusing on palette/registry changes and entity metadata.
## Prerequisites
- Decompiled server source for both the old and new MC versions in `$MCC_REPO/MinecraftOfficial/<version>-decompiled/`
- If missing, decompile and download server.jar:
```bash
$MCC_REPO/tools/decompile.sh --version <ver>
```
This auto-downloads `MinecraftDecompiler.jar` if needed, produces the decompiled source, and downloads `server.jar` into `$MCC_SERVERS/<ver>/`.
- `tools/decompile.sh` depends on official mappings. For older versions where it refuses to decompile, fall back to a raw Java decompiler such as `cfr-decompiler` against `$MCC_SERVERS/<ver>/server.jar`. That fallback is good enough for packet inspection and registration order checks even when the output is obfuscated.
- A test server of the target version in `$MCC_SERVERS/<version>/` (see `mcc-dev-workflow` skill)
## Step 0: Generate Server Reports (CRITICAL since 1.21.9)
**Before** analyzing decompiled source, generate authoritative registry data from the server jar:
```bash
cd /tmp && java -DbundlerMainClass=net.minecraft.data.Main \
-jar $MCC_SERVERS/<version>/server.jar \
--reports --output /tmp/mc_reports
```
This produces `/tmp/mc_reports/reports/` containing:
- `registries.json` — all registries with **actual protocol_id** for each entry
- `blocks.json` — all blocks with **block state IDs**
- `packets.json` — packet protocol definitions
**Why this matters**: Since MC 1.21.9, some items and blocks are registered outside `Items.java`/`Blocks.java` field declarations (via block registration callbacks or other paths). The decompiled source alone will **miss** these entries. The server data generator is the only authoritative source for protocol IDs.
### Validation check
Compare server registry counts against decompiled source counts:
```bash
python3 -c "
import json
with open('/tmp/mc_reports/reports/registries.json') as f:
data = json.load(f)
for reg in ['minecraft:item', 'minecraft:entity_type', 'minecraft:block']:
print(f'{reg}: {len(data[reg][\"entries\"])} entries')
"
```
If server counts differ from decompiled Java source counts, the palette **must** be generated from server data, not from Java source.
## Step 1: Run Registry Diff
```bash
python3 $MCC_REPO/tools/diff_registries.py <old_ver> <new_ver>
```
This compares five registries and reports which need palette updates:
| Registry | MCC File | When to Update |
|----------|----------|----------------|
| Items.java | `ItemPalettes/ItemPaletteXXX.cs` | New/removed/reordered items |
| EntityType.java | `EntityPalettes/EntityPaletteXXX.cs` | New/removed/reordered entity types |
| Blocks.java | `BlockPalettes/BlockPaletteXXX.cs` | New/removed/reordered blocks |
| DataComponents.java | `StructuredComponents/StructuredComponentsRegistryXXX.cs` | New/reordered components |
| EntityDataSerializers.java | `EntityMetadataPalettes/EntityMetadataPaletteXXX.cs` | New/reordered serializer types |
**Important**: diff_registries.py compares decompiled Java source. If Step 0 revealed count mismatches, the diff output may undercount. Always cross-reference with server registries.json.
## Step 2: Generate Updated Palettes
For registries marked "PALETTE UPDATE NEEDED":
### Item Palette
**Preferred method** (accurate since 1.21.9):
```bash
python3 $MCC_REPO/tools/gen_item_palette.py --from-registry /tmp/mc_reports/reports/registries.json <suffix>
# e.g., gen_item_palette.py --from-registry /tmp/mc_reports/reports/registries.json 1219
```
**Legacy method** (works for versions where Items.java has all items):
```bash
python3 $MCC_REPO/tools/gen_item_palette.py <new_ver> <suffix>
# e.g., gen_item_palette.py 1.21.1 121
```
- If new items are reported missing from `ItemType.cs`, add them to the enum in alphabetical order.
- The script auto-generates the C# palette file.
### Block Palette
**Preferred method** (accurate since 1.21.9):
```bash
python3 $MCC_REPO/tools/gen_block_palette.py /tmp/mc_reports/reports/blocks.json <suffix>
# e.g., gen_block_palette.py /tmp/mc_reports/reports/blocks.json 1219
```
**Legacy method** (manual creation from decompiled Blocks.java): Follow the pattern of existing palette files, using `register("name", ...)` call order from the decompiled source. Only reliable when Blocks.java contains all blocks.
If new blocks are reported missing from `Material.cs`, add them to the enum in alphabetical order.
### Entity Palette
```bash
python3 $MCC_REPO/tools/gen_entity_palette.py /tmp/mc_reports/reports/registries.json <suffix>
# e.g., gen_entity_palette.py /tmp/mc_reports/reports/registries.json 1219
```
If new entity types are reported missing from `EntityType.cs`, add them to the enum in alphabetical order.
### Entity Metadata Palette
```bash
python3 $MCC_REPO/tools/gen_entity_metadata_palette.py <new_ver> <suffix>
# e.g., gen_entity_metadata_palette.py 1.20.6 1206
```
- If new serializer types appear as UNMAPPED, add them to both:
1. The script's `FIELD_TO_ENUM` dictionary
2. MCC's `EntityMetaDataType.cs` enum
3. `DataTypes.cs` read logic (add a `case` to consume the correct bytes)
### DataComponents / StructuredComponents
Compare `DataComponents.java` registration order. If new components appear, update `StructuredComponentsRegistryXXX.cs`. For new component types, implement corresponding reader in `StructuredComponents/Components/`.
## Step 3: Update Version Routing
After creating palette files, update version selection logic:
| Palette Type | Routing Location |
|-------------|-----------------|
| Item | `Protocol18.cs``itemPalette` switch expression |
| Entity | `Protocol18.cs``entityPalette` switch expression |
| Block | `Protocol18.cs``blockPalette` initialization |
| EntityMetadata | `EntityMetadataPalette.cs``GetPalette()` switch |
| DataComponents | `StructuredComponentsRegistry.cs` → factory/routing |
| Packet | `PacketType18Handler.cs``GetTypeHandler()` switch |
Pattern: add a new `>= MC_X_Y_Z_Version => new XxxPaletteXYZ()` case.
Also update:
- `Protocol18.cs`: add `MC_X_Y_Z_Version = <protocol_number>` constant
- `Protocol18.cs`: update all `> MC_prev_Version` upper-bound checks to `> MC_X_Y_Z_Version`
- `ProtocolHandler.cs`: add version string → protocol mapping, protocol → version mapping, add to supported list
- `Program.cs`: update `MCHighestVersion`
## Step 4: Check Packet Changes
Compare `GameProtocols.java` and `ConfigurationProtocols.java` between versions.
Common patterns:
- **New clientbound packets inserted mid-list**: All subsequent packet IDs shift. Requires a new `PacketPalette` class.
- **New packets appended at end**: Only need to add new enum values and entries in the palette.
- **Packet renames** (same slot): Update MCC's packet type enum name but no ID change.
When packet changes are detected:
1. Add new packet type enum values to `PacketTypesIn.cs`, `PacketTypesOut.cs`, `ConfigurationPacketTypesIn.cs`, `ConfigurationPacketTypesOut.cs`
2. Create new `PacketPaletteXXX.cs` based on the previous one, adjusting IDs
3. Update `PacketType18Handler.cs` routing
Use scriptable comparisons instead of eyeballing long packet tables. The packet ID is the registration index in `GameProtocols.java`:
```bash
python3 - <<'PY'
import re
for ver in ["1.21.10", "1.21.11", "26.1"]:
path=f"MinecraftOfficial/{ver}-decompiled/net/minecraft/network/protocol/game/GameProtocols.java"
text=open(path).read()
start=text.index("CLIENTBOUND_TEMPLATE")
names=[m.group(1) for m in re.finditer(r"\.addPacket\(([^,]+),", text[start:])]
print("==", ver, len(names))
for i, name in enumerate(names):
print(f"0x{i:02X}", name)
PY
```
For focused diffs:
```bash
python3 - <<'PY'
import re
def packets(ver, marker):
text=open(f"MinecraftOfficial/{ver}-decompiled/net/minecraft/network/protocol/game/GameProtocols.java").read()
start=text.index(marker)
return [m.group(1) for m in re.finditer(r"\.addPacket\(([^,]+),", text[start:])]
left, right = "1.21.10", "1.21.11"
a, b = packets(left, "CLIENTBOUND_TEMPLATE"), packets(right, "CLIENTBOUND_TEMPLATE")
for i in range(max(len(a), len(b))):
x = a[i] if i < len(a) else "<none>"
y = b[i] if i < len(b) else "<none>"
if x != y:
print(f"0x{i:02X}: {left}={x} | {right}={y}")
PY
```
Do the same for `SERVERBOUND_TEMPLATE`. Clientbound and serverbound can change independently. Do not inherit a newer palette just because one side looks similar. For example, `1.21.11` used the same play packet order as `1.21.9/1.21.10` for the tested inventory path, while `26.1` had additional shifts.
## Step 5: Check Variant Encoding Changes
For entity types that use variant serializers (Cat, Wolf, Frog, Painting), check if the codec changed between versions by inspecting:
- `EntityDataSerializers.java` — look at how each `*_VARIANT` field is constructed
- Key codecs:
- `ByteBufCodecs.holderRegistry()` → wire format: `VarInt(registry_id)`
- `ByteBufCodecs.holder()` → wire format: `VarInt(id+1)` for registered, `VarInt(0) + inline_data` for direct
- If codec changed, update `DataTypes.cs` entity metadata reading logic accordingly.
## Step 6: Handle New EntityDataSerializer Types
When new serializer types are added (detected in Step 1):
1. Add enum value to `EntityMetaDataType.cs` with XML doc comment
2. Add read logic in `DataTypes.cs` `ReadNextMetadata()`:
- Determine byte consumption from the decompiled codec
- Simple enum types (like CopperGolemState, WeatheringCopperState): `ReadNextVarInt(cache)`
- Composite types (like ResolvableProfile): analyze the STREAM_CODEC chain in decompiled source
3. Create the new palette file (Step 2)
4. Update palette routing (Step 3)
## Step 7: Check SpawnEntity / Other Packet Format Changes
Compare key packet codec classes between versions. Known changes:
- **1.21.9+**: `SpawnEntity` velocity fields changed from `short / 8000.0` to `LpVec3` format (VarLong-packed fixed-point). Gate reading in `DataTypes.ReadNextEntity()` by version.
When in doubt, compare the relevant packet class (e.g. `ClientboundAddEntityPacket.java`) between versions.
## Step 8: Update Block Collision Shapes (Physics Engine)
MCC's physics engine uses block collision shape data from PrismarineJS `minecraft-data` to perform accurate AABB collision detection (stored in `MinecraftClient/Physics/BlockShapeData.json`, embedded as a resource).
When a new MC version introduces new blocks or changes block shapes, update this data:
```bash
# Download and compact collision shapes for the target version
python3 $MCC_REPO/tools/gen_block_shapes.py <version>
# e.g. python3 tools/gen_block_shapes.py 1.21.11
```
If network is slow or unreliable, download the file manually and convert:
```bash
# Manual download
curl -L -o /tmp/bcs.json \
"https://raw.githubusercontent.com/PrismarineJS/minecraft-data/master/data/pc/<version>/blockCollisionShapes.json"
# Then compact from local file
python3 $MCC_REPO/tools/gen_block_shapes.py --from-file /tmp/bcs.json
```
Output: `MinecraftClient/Physics/BlockShapeData.json` (embedded via `MinecraftClient.csproj`)
The JSON maps block names (snake_case) → collision shape IDs → AABB coordinates. At runtime, `BlockShapes.cs` maps MCC's block state IDs to these AABBs using the block palette.
**When to update**: Whenever new blocks are added that have non-trivial collision shapes (e.g., new slab variants, stairs, fences). If only items or entities changed, this step can be skipped.
**Data source**: PrismarineJS `minecraft-data` repo, path: `data/pc/<version>/blockCollisionShapes.json`. Version availability can be checked via `data/dataPaths.json`.
## Step 9: Update Minimap Block Color Map
Regenerate the block-to-MapColor mapping used by the TUI minimap. This maps each block's `Material` enum to the RGB color from Minecraft's official `MapColor` table.
```bash
python3 $MCC_REPO/tools/gen_block_color_map.py $MCC_REPO/MinecraftOfficial/<version>-decompiled
# e.g. python3 tools/gen_block_color_map.py MinecraftOfficial/26.1-rc-2-decompiled
```
Output: `MinecraftClient/Tui/MinimapBlockColors.json` (embedded as a resource via `.csproj`).
The script parses `MapColor.java`, `DyeColor.java`, and `Blocks.java` from the decompiled source to extract each block's assigned map color. Blocks not matched to a known `Material` enum value are skipped.
**When to update**: Whenever new blocks are added or existing blocks change their `mapColor()` assignment. If only items or entities changed, this step can be skipped.
## Step 10: Update Minimap Entity Categories
Regenerate the entity-to-MobCategory mapping used by the TUI minimap for classifying entities as hostile, passive, neutral, or non-living.
```bash
python3 $MCC_REPO/tools/gen_entity_category_map.py $MCC_REPO/MinecraftOfficial/<version>-decompiled
# e.g. python3 tools/gen_entity_category_map.py MinecraftOfficial/26.1-rc-2-decompiled
```
Output: `MinecraftClient/Tui/MinimapEntityCategories.json` (embedded as a resource via `.csproj`).
The script parses `EntityType.java` to extract each entity's `MobCategory` assignment, then maps Minecraft's categories to MCC minimap categories:
- `MONSTER` -> hostile (with neutral overrides for conditionally hostile mobs like Enderman, Spider, Wolf)
- `CREATURE`/`AMBIENT`/`AXOLOTLS`/`WATER_*` -> passive
- `MISC` -> non_living (with passive overrides for Villager, WanderingTrader, ZombieHorse)
The script maintains manual override lists for "neutral" mobs (attack only when provoked) since Minecraft has no machine-readable flag for this behavior. Review and update the `NEUTRAL_OVERRIDES` and `PASSIVE_OVERRIDES` sets in the script when new conditionally-hostile or misclassified mobs are added.
**When to update**: Whenever new entity types are added. If only blocks or items changed, this step can be skipped.
## Step 11: Compile and Verify
```bash
dotnet build $MCC_REPO/MinecraftClient.sln -c Release
```
Then connect to a test server of the target version (see `mcc-dev-workflow` skill) and verify:
- Successful connection
- `/give` new items → check inventory for correct identification
- `/give` existing items (diamond_sword, etc.) → verify no ID shift
- Summon new entities → check type and health
- Summon variant entities (wolf, cat, frog) → no metadata parse errors
- Place new blocks → `dig` reports correct block type
- Teleport to distant chunks → terrain loads without errors
- Chat commands work normally
**Always verify basic existing items first** (e.g. diamond_sword) to catch palette ID shift bugs early. If an existing item shows as the wrong type, the palette is using wrong protocol IDs.
## Key Source Files Reference
| Decompiled Java Source | Purpose |
|----------------------|---------|
| `world/item/Items.java` | Item registry (field declaration order ≈ ID, **but not always since 1.21.9**) |
| `world/entity/EntityType.java` | Entity type registry (`register()` call order = ID) |
| `world/level/block/Blocks.java` | Block registry (`register()` call order ≈ ID, **but not always since 1.21.9**) |
| `core/component/DataComponents.java` | Data component registry |
| `network/syncher/EntityDataSerializers.java` | Entity metadata type registry (static block order = ID) |
| `network/protocol/game/GameProtocols.java` | Play packet registration order (= packet IDs) |
| `network/protocol/configuration/ConfigurationProtocols.java` | Config packet registration order |
| Server Data Generator Output | Purpose |
|-----|---------|
| `registries.json` | **Authoritative** protocol_id for all registries |
| `blocks.json` | **Authoritative** block state IDs |
| `packets.json` | Packet protocol definitions |
## Common Pitfalls
- **Source field order ≠ runtime registry ID (since 1.21.9)**: Some items/blocks are registered via callbacks (e.g., block items registered by `Blocks.java` during block registration) rather than in `Items.java` field declarations. Always validate palette counts against server `registries.json`. If counts differ, **use server data generator output instead of decompiled source**.
- **ID order matters**: IDs are determined by registration order, not alphabetical. Always use server data generator as ground truth.
- **Cross-version jumps**: When MCC skips versions (e.g., 1.20.4→1.20.6), registries from ALL intermediate versions may have changed. Always diff against the actual last-supported version, not the latest palette.
- **EntityMetadata type shifts**: A single new serializer type shifts all subsequent IDs, causing widespread metadata parse failures. Symptoms: entity rendering glitches, disconnections, or silent data corruption.
- **CUT_STANDSTONE_SLAB**: This is an intentional typo in Minecraft source (should be SANDSTONE). MCC's `ItemType.cs` uses `CutSandstoneSlab` — the gen script handles this via the OVERRIDES dict.
- **Item/block renames across versions**: Some items/blocks get renamed (e.g., `DRY_SHORT_GRASS``SHORT_DRY_GRASS`, `CHAIN``IRON_CHAIN`). Keep old enum values for backward compatibility with older palettes, and add new ones for the new version.
- **Packet ID cascading shifts**: Even one inserted mid-list clientbound packet shifts ALL subsequent IDs. Always create a new PacketPalette for protocol changes.
- **Test existing items first**: After palette changes, always verify existing items (diamond_sword, stone, etc.) before testing new ones. If they show as wrong items, the palette has a systemic ID offset bug.
## Reusable Scripts
All scripts are in `$MCC_REPO/tools/`. See `tools/README.md` for detailed usage.
| Script | Purpose | Input |
|--------|---------|-------|
| `diff_registries.py` | Compare registries between versions | Decompiled source |
| `gen_item_palette.py` | Generate ItemPalette C# | Decompiled source OR registries.json |
| `gen_block_palette.py` | Generate BlockPalette C# | blocks.json |
| `gen_entity_palette.py` | Generate EntityPalette C# | registries.json |
| `gen_entity_metadata_palette.py` | Generate EntityMetadataPalette C# | Decompiled source |
| `gen_block_shapes.py` | Download & compact block collision shapes | PrismarineJS minecraft-data |
| `gen_block_color_map.py` | Generate minimap block color JSON | Decompiled source (MapColor/DyeColor/Blocks) |
| `gen_entity_category_map.py` | Generate minimap entity category JSON | Decompiled source (EntityType.java) |

View file

@ -0,0 +1,211 @@
---
name: mermaid-diagrams
description: Creating and refining Mermaid diagrams with live reload. Use when users want flowcharts, sequence diagrams, class diagrams, ER diagrams, state diagrams, or any other Mermaid visualization. Provides best practices for syntax, styling, and the iterative workflow using mermaid_preview and mermaid_save tools.
allowed-tools: mcp__mermaid__mermaid_preview, mcp__mermaid__mermaid_save
---
# Mermaid Diagram Expert
You are an expert at creating, refining, and optimizing Mermaid diagrams using the MCP server tools.
## Core Workflow
1. **Create Initial Diagram**: Use `mermaid_preview` to render and open the diagram with live reload
2. **Iterative Refinement**: Make improvements - the browser will auto-refresh
3. **Save Final Version**: Use `mermaid_save` when satisfied
## Tool Usage
### mermaid_preview
Always use this when creating or updating diagrams:
- `diagram`: The Mermaid code
- `preview_id`: Descriptive kebab-case ID (e.g., `auth-flow`, `architecture`)
- `format`: Use `svg` for live reload (default)
- `theme`: `default`, `forest`, `dark`, or `neutral`
- `background`: `white`, `transparent`, or hex colors
- `width`, `height`, `scale`: Adjust for quality/size
**Key Points:**
- Reuse the same `preview_id` for refinements to update the same browser tab
- Use different IDs for multiple simultaneous diagrams
- Live reload only works with SVG format
### mermaid_save
Use after the diagram is finalized:
- `save_path`: Where to save (e.g., `./docs/diagram.svg`)
- `preview_id`: Must match the preview ID used earlier
- `format`: Must match format from preview
## Diagram Types
### Flowcharts (`graph` or `flowchart`)
Direction: `LR`, `TB`, `RL`, `BT`
```mermaid
graph LR
A[Start] --> B{Decision}
B -->|Yes| C[Action]
B -->|No| D[End]
style A fill:#e1f5ff
style C fill:#d4edda
```
### Sequence Diagrams (`sequenceDiagram`)
⚠️ **Do NOT use `style` statements** - not supported
```mermaid
sequenceDiagram
participant User
participant App
participant API
User->>App: Login
App->>API: Authenticate
API-->>App: Token
App-->>User: Success
```
### Class Diagrams (`classDiagram`)
```mermaid
classDiagram
class User {
+String name
+String email
+login()
}
class Order {
+int id
+Date created
}
User "1" --> "*" Order
```
### Entity Relationship (`erDiagram`)
```mermaid
erDiagram
USER ||--o{ ORDER : places
ORDER ||--|{ LINE_ITEM : contains
USER {
int id PK
string email
string name
}
```
### State Diagrams (`stateDiagram-v2`)
```mermaid
stateDiagram-v2
[*] --> Idle
Idle --> Processing : start
Processing --> Complete : finish
Complete --> [*]
```
### Gantt Charts (`gantt`)
```mermaid
gantt
title Project Timeline
section Phase 1
Task 1 :a1, 2024-01-01, 30d
Task 2 :after a1, 20d
```
## Best Practices
### Preview IDs
- Use descriptive names: `architecture`, `auth-flow`, `data-model`
- Keep the same ID during refinements
- Use different IDs for concurrent diagrams
### Themes & Styling
- `default`: Clean, professional
- `forest`: Green tones
- `dark`: Dark background
- `neutral`: Grayscale
Use `transparent` background for docs, `white` for standalone
### Common Patterns
**System Architecture:**
```mermaid
graph TB
Client[Web App]
API[API Gateway]
DB[(Database)]
Client --> API --> DB
```
**Authentication Flow:**
```mermaid
sequenceDiagram
User->>App: Login Request
App->>Auth: Validate
Auth-->>App: JWT Token
App-->>User: Access Granted
```
## User Interaction
When a user requests a diagram:
1. **Clarify if needed**: What type? What level of detail?
2. **Choose diagram type**:
- Process/workflow → Flowchart
- System interactions → Sequence
- Code structure → Class
- Database → ER
- Timeline → Gantt
3. **Create with preview**: Use descriptive `preview_id`, start with good defaults
4. **Iterate**: Keep same `preview_id`, explain changes
5. **Save**: Ask where/what format, use `mermaid_save`
## Proactive Behavior
- Always preview diagrams, don't just generate code
- Use sensible defaults without asking
- Reuse preview_id for refinements
- Suggest improvements when you see opportunities
- Explain your diagram type choice briefly
## Common Issues
**Syntax errors**: Check quotes, arrow syntax, keywords
**Layout issues**: Try different directions (LR vs TB)
**Text overlap**: Increase dimensions or shorten labels
**Colors not working**: Verify CSS color format; remember sequence diagrams don't support styles
## Example Interaction
**User**: "Create an auth flow diagram"
**You**: "I'll create a sequence diagram showing the authentication flow."
[Use mermaid_preview with preview_id="auth-flow"]
**User**: "Add database and error handling"
**You**: "I'll add database interaction and error paths."
[Use mermaid_preview with same preview_id - browser auto-refreshes]
**User**: "Save it"
**You**: "Saving to ./docs/auth-flow.svg"
[Use mermaid_save]

View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -0,0 +1,479 @@
---
name: skill-creator
description: Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, update or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.
---
# Skill Creator
A skill for creating new skills and iteratively improving them.
At a high level, the process of creating a skill goes like this:
- Decide what you want the skill to do and roughly how it should do it
- Write a draft of the skill
- Create a few test prompts and run claude-with-access-to-the-skill on them
- Help the user evaluate the results both qualitatively and quantitatively
- While the runs happen in the background, draft some quantitative evals if there aren't any (if there are some, you can either use as is or modify if you feel something needs to change about them). Then explain them to the user (or if they already existed, explain the ones that already exist)
- Use the `eval-viewer/generate_review.py` script to show the user the results for them to look at, and also let them look at the quantitative metrics
- Rewrite the skill based on feedback from the user's evaluation of the results (and also if there are any glaring flaws that become apparent from the quantitative benchmarks)
- Repeat until you're satisfied
- Expand the test set and try again at larger scale
Your job when using this skill is to figure out where the user is in this process and then jump in and help them progress through these stages. So for instance, maybe they're like "I want to make a skill for X". You can help narrow down what they mean, write a draft, write the test cases, figure out how they want to evaluate, run all the prompts, and repeat.
On the other hand, maybe they already have a draft of the skill. In this case you can go straight to the eval/iterate part of the loop.
Of course, you should always be flexible and if the user is like "I don't need to run a bunch of evaluations, just vibe with me", you can do that instead.
Then after the skill is done (but again, the order is flexible), you can also run the skill description improver, which we have a whole separate script for, to optimize the triggering of the skill.
Cool? Cool.
## Communicating with the user
The skill creator is liable to be used by people across a wide range of familiarity with coding jargon. If you haven't heard (and how could you, it's only very recently that it started), there's a trend now where the power of Claude is inspiring plumbers to open up their terminals, parents and grandparents to google "how to install npm". On the other hand, the bulk of users are probably fairly computer-literate.
So please pay attention to context cues to understand how to phrase your communication! In the default case, just to give you some idea:
- "evaluation" and "benchmark" are borderline, but OK
- for "JSON" and "assertion" you want to see serious cues from the user that they know what those things are before using them without explaining them
It's OK to briefly explain terms if you're in doubt, and feel free to clarify terms with a short definition if you're unsure if the user will get it.
---
## Creating a skill
### Capture Intent
Start by understanding the user's intent. The current conversation might already contain a workflow the user wants to capture (e.g., they say "turn this into a skill"). If so, extract answers from the conversation history first — the tools used, the sequence of steps, corrections the user made, input/output formats observed. The user may need to fill the gaps, and should confirm before proceeding to the next step.
1. What should this skill enable Claude to do?
2. When should this skill trigger? (what user phrases/contexts)
3. What's the expected output format?
4. Should we set up test cases to verify the skill works? Skills with objectively verifiable outputs (file transforms, data extraction, code generation, fixed workflow steps) benefit from test cases. Skills with subjective outputs (writing style, art) often don't need them. Suggest the appropriate default based on the skill type, but let the user decide.
### Interview and Research
Proactively ask questions about edge cases, input/output formats, example files, success criteria, and dependencies. Wait to write test prompts until you've got this part ironed out.
Check available MCPs - if useful for research (searching docs, finding similar skills, looking up best practices), research in parallel via subagents if available, otherwise inline. Come prepared with context to reduce burden on the user.
### Write the SKILL.md
Based on the user interview, fill in these components:
- **name**: Skill identifier
- **description**: When to trigger, what it does. This is the primary triggering mechanism - include both what the skill does AND specific contexts for when to use it. All "when to use" info goes here, not in the body. Note: currently Claude has a tendency to "undertrigger" skills -- to not use them when they'd be useful. To combat this, please make the skill descriptions a little bit "pushy". So for instance, instead of "How to build a simple fast dashboard to display internal Anthropic data.", you might write "How to build a simple fast dashboard to display internal Anthropic data. Make sure to use this skill whenever the user mentions dashboards, data visualization, internal metrics, or wants to display any kind of company data, even if they don't explicitly ask for a 'dashboard.'"
- **compatibility**: Required tools, dependencies (optional, rarely needed)
- **the rest of the skill :)**
### Skill Writing Guide
#### Anatomy of a Skill
```
skill-name/
├── SKILL.md (required)
│ ├── YAML frontmatter (name, description required)
│ └── Markdown instructions
└── Bundled Resources (optional)
├── scripts/ - Executable code for deterministic/repetitive tasks
├── references/ - Docs loaded into context as needed
└── assets/ - Files used in output (templates, icons, fonts)
```
#### Progressive Disclosure
Skills use a three-level loading system:
1. **Metadata** (name + description) - Always in context (~100 words)
2. **SKILL.md body** - In context whenever skill triggers (<500 lines ideal)
3. **Bundled resources** - As needed (unlimited, scripts can execute without loading)
These word counts are approximate and you can feel free to go longer if needed.
**Key patterns:**
- Keep SKILL.md under 500 lines; if you're approaching this limit, add an additional layer of hierarchy along with clear pointers about where the model using the skill should go next to follow up.
- Reference files clearly from SKILL.md with guidance on when to read them
- For large reference files (>300 lines), include a table of contents
**Domain organization**: When a skill supports multiple domains/frameworks, organize by variant:
```
cloud-deploy/
├── SKILL.md (workflow + selection)
└── references/
├── aws.md
├── gcp.md
└── azure.md
```
Claude reads only the relevant reference file.
#### Principle of Lack of Surprise
This goes without saying, but skills must not contain malware, exploit code, or any content that could compromise system security. A skill's contents should not surprise the user in their intent if described. Don't go along with requests to create misleading skills or skills designed to facilitate unauthorized access, data exfiltration, or other malicious activities. Things like a "roleplay as an XYZ" are OK though.
#### Writing Patterns
Prefer using the imperative form in instructions.
**Defining output formats** - You can do it like this:
```markdown
## Report structure
ALWAYS use this exact template:
# [Title]
## Executive summary
## Key findings
## Recommendations
```
**Examples pattern** - It's useful to include examples. You can format them like this (but if "Input" and "Output" are in the examples you might want to deviate a little):
```markdown
## Commit message format
**Example 1:**
Input: Added user authentication with JWT tokens
Output: feat(auth): implement JWT-based authentication
```
### Writing Style
Try to explain to the model why things are important in lieu of heavy-handed musty MUSTs. Use theory of mind and try to make the skill general and not super-narrow to specific examples. Start by writing a draft and then look at it with fresh eyes and improve it.
### Test Cases
After writing the skill draft, come up with 2-3 realistic test prompts — the kind of thing a real user would actually say. Share them with the user: [you don't have to use this exact language] "Here are a few test cases I'd like to try. Do these look right, or do you want to add more?" Then run them.
Save test cases to `evals/evals.json`. Don't write assertions yet — just the prompts. You'll draft assertions in the next step while the runs are in progress.
```json
{
"skill_name": "example-skill",
"evals": [
{
"id": 1,
"prompt": "User's task prompt",
"expected_output": "Description of expected result",
"files": []
}
]
}
```
See `references/schemas.md` for the full schema (including the `assertions` field, which you'll add later).
## Running and evaluating test cases
This section is one continuous sequence — don't stop partway through. Do NOT use `/skill-test` or any other testing skill.
Put results in `<skill-name>-workspace/` as a sibling to the skill directory. Within the workspace, organize results by iteration (`iteration-1/`, `iteration-2/`, etc.) and within that, each test case gets a directory (`eval-0/`, `eval-1/`, etc.). Don't create all of this upfront — just create directories as you go.
### Step 1: Spawn all runs (with-skill AND baseline) in the same turn
For each test case, spawn two subagents in the same turn — one with the skill, one without. This is important: don't spawn the with-skill runs first and then come back for baselines later. Launch everything at once so it all finishes around the same time.
**With-skill run:**
```
Execute this task:
- Skill path: <path-to-skill>
- Task: <eval prompt>
- Input files: <eval files if any, or "none">
- Save outputs to: <workspace>/iteration-<N>/eval-<ID>/with_skill/outputs/
- Outputs to save: <what the user cares about e.g., "the .docx file", "the final CSV">
```
**Baseline run** (same prompt, but the baseline depends on context):
- **Creating a new skill**: no skill at all. Same prompt, no skill path, save to `without_skill/outputs/`.
- **Improving an existing skill**: the old version. Before editing, snapshot the skill (`cp -r <skill-path> <workspace>/skill-snapshot/`), then point the baseline subagent at the snapshot. Save to `old_skill/outputs/`.
Write an `eval_metadata.json` for each test case (assertions can be empty for now). Give each eval a descriptive name based on what it's testing — not just "eval-0". Use this name for the directory too. If this iteration uses new or modified eval prompts, create these files for each new eval directory — don't assume they carry over from previous iterations.
```json
{
"eval_id": 0,
"eval_name": "descriptive-name-here",
"prompt": "The user's task prompt",
"assertions": []
}
```
### Step 2: While runs are in progress, draft assertions
Don't just wait for the runs to finish — you can use this time productively. Draft quantitative assertions for each test case and explain them to the user. If assertions already exist in `evals/evals.json`, review them and explain what they check.
Good assertions are objectively verifiable and have descriptive names — they should read clearly in the benchmark viewer so someone glancing at the results immediately understands what each one checks. Subjective skills (writing style, design quality) are better evaluated qualitatively — don't force assertions onto things that need human judgment.
Update the `eval_metadata.json` files and `evals/evals.json` with the assertions once drafted. Also explain to the user what they'll see in the viewer — both the qualitative outputs and the quantitative benchmark.
### Step 3: As runs complete, capture timing data
When each subagent task completes, you receive a notification containing `total_tokens` and `duration_ms`. Save this data immediately to `timing.json` in the run directory:
```json
{
"total_tokens": 84852,
"duration_ms": 23332,
"total_duration_seconds": 23.3
}
```
This is the only opportunity to capture this data — it comes through the task notification and isn't persisted elsewhere. Process each notification as it arrives rather than trying to batch them.
### Step 4: Grade, aggregate, and launch the viewer
Once all runs are done:
1. **Grade each run** — spawn a grader subagent (or grade inline) that reads `agents/grader.md` and evaluates each assertion against the outputs. Save results to `grading.json` in each run directory. The grading.json expectations array must use the fields `text`, `passed`, and `evidence` (not `name`/`met`/`details` or other variants) — the viewer depends on these exact field names. For assertions that can be checked programmatically, write and run a script rather than eyeballing it — scripts are faster, more reliable, and can be reused across iterations.
2. **Aggregate into benchmark** — run the aggregation script from the skill-creator directory:
```bash
python -m scripts.aggregate_benchmark <workspace>/iteration-N --skill-name <name>
```
This produces `benchmark.json` and `benchmark.md` with pass_rate, time, and tokens for each configuration, with mean ± stddev and the delta. If generating benchmark.json manually, see `references/schemas.md` for the exact schema the viewer expects.
Put each with_skill version before its baseline counterpart.
3. **Do an analyst pass** — read the benchmark data and surface patterns the aggregate stats might hide. See `agents/analyzer.md` (the "Analyzing Benchmark Results" section) for what to look for — things like assertions that always pass regardless of skill (non-discriminating), high-variance evals (possibly flaky), and time/token tradeoffs.
4. **Launch the viewer** with both qualitative outputs and quantitative data:
```bash
nohup python <skill-creator-path>/eval-viewer/generate_review.py \
<workspace>/iteration-N \
--skill-name "my-skill" \
--benchmark <workspace>/iteration-N/benchmark.json \
> /dev/null 2>&1 &
VIEWER_PID=$!
```
For iteration 2+, also pass `--previous-workspace <workspace>/iteration-<N-1>`.
**Cowork / headless environments:** If `webbrowser.open()` is not available or the environment has no display, use `--static <output_path>` to write a standalone HTML file instead of starting a server. Feedback will be downloaded as a `feedback.json` file when the user clicks "Submit All Reviews". After download, copy `feedback.json` into the workspace directory for the next iteration to pick up.
Note: please use generate_review.py to create the viewer; there's no need to write custom HTML.
5. **Tell the user** something like: "I've opened the results in your browser. There are two tabs — 'Outputs' lets you click through each test case and leave feedback, 'Benchmark' shows the quantitative comparison. When you're done, come back here and let me know."
### What the user sees in the viewer
The "Outputs" tab shows one test case at a time:
- **Prompt**: the task that was given
- **Output**: the files the skill produced, rendered inline where possible
- **Previous Output** (iteration 2+): collapsed section showing last iteration's output
- **Formal Grades** (if grading was run): collapsed section showing assertion pass/fail
- **Feedback**: a textbox that auto-saves as they type
- **Previous Feedback** (iteration 2+): their comments from last time, shown below the textbox
The "Benchmark" tab shows the stats summary: pass rates, timing, and token usage for each configuration, with per-eval breakdowns and analyst observations.
Navigation is via prev/next buttons or arrow keys. When done, they click "Submit All Reviews" which saves all feedback to `feedback.json`.
### Step 5: Read the feedback
When the user tells you they're done, read `feedback.json`:
```json
{
"reviews": [
{"run_id": "eval-0-with_skill", "feedback": "the chart is missing axis labels", "timestamp": "..."},
{"run_id": "eval-1-with_skill", "feedback": "", "timestamp": "..."},
{"run_id": "eval-2-with_skill", "feedback": "perfect, love this", "timestamp": "..."}
],
"status": "complete"
}
```
Empty feedback means the user thought it was fine. Focus your improvements on the test cases where the user had specific complaints.
Kill the viewer server when you're done with it:
```bash
kill $VIEWER_PID 2>/dev/null
```
---
## Improving the skill
This is the heart of the loop. You've run the test cases, the user has reviewed the results, and now you need to make the skill better based on their feedback.
### How to think about improvements
1. **Generalize from the feedback.** The big picture thing that's happening here is that we're trying to create skills that can be used a million times (maybe literally, maybe even more who knows) across many different prompts. Here you and the user are iterating on only a few examples over and over again because it helps move faster. The user knows these examples in and out and it's quick for them to assess new outputs. But if the skill you and the user are codeveloping works only for those examples, it's useless. Rather than put in fiddly overfitty changes, or oppressively constrictive MUSTs, if there's some stubborn issue, you might try branching out and using different metaphors, or recommending different patterns of working. It's relatively cheap to try and maybe you'll land on something great.
2. **Keep the prompt lean.** Remove things that aren't pulling their weight. Make sure to read the transcripts, not just the final outputs — if it looks like the skill is making the model waste a bunch of time doing things that are unproductive, you can try getting rid of the parts of the skill that are making it do that and seeing what happens.
3. **Explain the why.** Try hard to explain the **why** behind everything you're asking the model to do. Today's LLMs are *smart*. They have good theory of mind and when given a good harness can go beyond rote instructions and really make things happen. Even if the feedback from the user is terse or frustrated, try to actually understand the task and why the user is writing what they wrote, and what they actually wrote, and then transmit this understanding into the instructions. If you find yourself writing ALWAYS or NEVER in all caps, or using super rigid structures, that's a yellow flag — if possible, reframe and explain the reasoning so that the model understands why the thing you're asking for is important. That's a more humane, powerful, and effective approach.
4. **Look for repeated work across test cases.** Read the transcripts from the test runs and notice if the subagents all independently wrote similar helper scripts or took the same multi-step approach to something. If all 3 test cases resulted in the subagent writing a `create_docx.py` or a `build_chart.py`, that's a strong signal the skill should bundle that script. Write it once, put it in `scripts/`, and tell the skill to use it. This saves every future invocation from reinventing the wheel.
This task is pretty important (we are trying to create billions a year in economic value here!) and your thinking time is not the blocker; take your time and really mull things over. I'd suggest writing a draft revision and then looking at it anew and making improvements. Really do your best to get into the head of the user and understand what they want and need.
### The iteration loop
After improving the skill:
1. Apply your improvements to the skill
2. Rerun all test cases into a new `iteration-<N+1>/` directory, including baseline runs. If you're creating a new skill, the baseline is always `without_skill` (no skill) — that stays the same across iterations. If you're improving an existing skill, use your judgment on what makes sense as the baseline: the original version the user came in with, or the previous iteration.
3. Launch the reviewer with `--previous-workspace` pointing at the previous iteration
4. Wait for the user to review and tell you they're done
5. Read the new feedback, improve again, repeat
Keep going until:
- The user says they're happy
- The feedback is all empty (everything looks good)
- You're not making meaningful progress
---
## Advanced: Blind comparison
For situations where you want a more rigorous comparison between two versions of a skill (e.g., the user asks "is the new version actually better?"), there's a blind comparison system. Read `agents/comparator.md` and `agents/analyzer.md` for the details. The basic idea is: give two outputs to an independent agent without telling it which is which, and let it judge quality. Then analyze why the winner won.
This is optional, requires subagents, and most users won't need it. The human review loop is usually sufficient.
---
## Description Optimization
The description field in SKILL.md frontmatter is the primary mechanism that determines whether Claude invokes a skill. After creating or improving a skill, offer to optimize the description for better triggering accuracy.
### Step 1: Generate trigger eval queries
Create 20 eval queries — a mix of should-trigger and should-not-trigger. Save as JSON:
```json
[
{"query": "the user prompt", "should_trigger": true},
{"query": "another prompt", "should_trigger": false}
]
```
The queries must be realistic and something a Claude Code or Claude.ai user would actually type. Not abstract requests, but requests that are concrete and specific and have a good amount of detail. For instance, file paths, personal context about the user's job or situation, column names and values, company names, URLs. A little bit of backstory. Some might be in lowercase or contain abbreviations or typos or casual speech. Use a mix of different lengths, and focus on edge cases rather than making them clear-cut (the user will get a chance to sign off on them).
Bad: `"Format this data"`, `"Extract text from PDF"`, `"Create a chart"`
Good: `"ok so my boss just sent me this xlsx file (its in my downloads, called something like 'Q4 sales final FINAL v2.xlsx') and she wants me to add a column that shows the profit margin as a percentage. The revenue is in column C and costs are in column D i think"`
For the **should-trigger** queries (8-10), think about coverage. You want different phrasings of the same intent — some formal, some casual. Include cases where the user doesn't explicitly name the skill or file type but clearly needs it. Throw in some uncommon use cases and cases where this skill competes with another but should win.
For the **should-not-trigger** queries (8-10), the most valuable ones are the near-misses — queries that share keywords or concepts with the skill but actually need something different. Think adjacent domains, ambiguous phrasing where a naive keyword match would trigger but shouldn't, and cases where the query touches on something the skill does but in a context where another tool is more appropriate.
The key thing to avoid: don't make should-not-trigger queries obviously irrelevant. "Write a fibonacci function" as a negative test for a PDF skill is too easy — it doesn't test anything. The negative cases should be genuinely tricky.
### Step 2: Review with user
Present the eval set to the user for review using the HTML template:
1. Read the template from `assets/eval_review.html`
2. Replace the placeholders:
- `__EVAL_DATA_PLACEHOLDER__` → the JSON array of eval items (no quotes around it — it's a JS variable assignment)
- `__SKILL_NAME_PLACEHOLDER__` → the skill's name
- `__SKILL_DESCRIPTION_PLACEHOLDER__` → the skill's current description
3. Write to a temp file (e.g., `/tmp/eval_review_<skill-name>.html`) and open it: `open /tmp/eval_review_<skill-name>.html`
4. The user can edit queries, toggle should-trigger, add/remove entries, then click "Export Eval Set"
5. The file downloads to `~/Downloads/eval_set.json` — check the Downloads folder for the most recent version in case there are multiple (e.g., `eval_set (1).json`)
This step matters — bad eval queries lead to bad descriptions.
### Step 3: Run the optimization loop
Tell the user: "This will take some time — I'll run the optimization loop in the background and check on it periodically."
Save the eval set to the workspace, then run in the background:
```bash
python -m scripts.run_loop \
--eval-set <path-to-trigger-eval.json> \
--skill-path <path-to-skill> \
--model <model-id-powering-this-session> \
--max-iterations 5 \
--verbose
```
Use the model ID from your system prompt (the one powering the current session) so the triggering test matches what the user actually experiences.
While it runs, periodically tail the output to give the user updates on which iteration it's on and what the scores look like.
This handles the full optimization loop automatically. It splits the eval set into 60% train and 40% held-out test, evaluates the current description (running each query 3 times to get a reliable trigger rate), then calls Claude with extended thinking to propose improvements based on what failed. It re-evaluates each new description on both train and test, iterating up to 5 times. When it's done, it opens an HTML report in the browser showing the results per iteration and returns JSON with `best_description` — selected by test score rather than train score to avoid overfitting.
### How skill triggering works
Understanding the triggering mechanism helps design better eval queries. Skills appear in Claude's `available_skills` list with their name + description, and Claude decides whether to consult a skill based on that description. The important thing to know is that Claude only consults skills for tasks it can't easily handle on its own — simple, one-step queries like "read this PDF" may not trigger a skill even if the description matches perfectly, because Claude can handle them directly with basic tools. Complex, multi-step, or specialized queries reliably trigger skills when the description matches.
This means your eval queries should be substantive enough that Claude would actually benefit from consulting a skill. Simple queries like "read file X" are poor test cases — they won't trigger skills regardless of description quality.
### Step 4: Apply the result
Take `best_description` from the JSON output and update the skill's SKILL.md frontmatter. Show the user before/after and report the scores.
---
### Package and Present (only if `present_files` tool is available)
Check whether you have access to the `present_files` tool. If you don't, skip this step. If you do, package the skill and present the .skill file to the user:
```bash
python -m scripts.package_skill <path/to/skill-folder>
```
After packaging, direct the user to the resulting `.skill` file path so they can install it.
---
## Claude.ai-specific instructions
In Claude.ai, the core workflow is the same (draft → test → review → improve → repeat), but because Claude.ai doesn't have subagents, some mechanics change. Here's what to adapt:
**Running test cases**: No subagents means no parallel execution. For each test case, read the skill's SKILL.md, then follow its instructions to accomplish the test prompt yourself. Do them one at a time. This is less rigorous than independent subagents (you wrote the skill and you're also running it, so you have full context), but it's a useful sanity check — and the human review step compensates. Skip the baseline runs — just use the skill to complete the task as requested.
**Reviewing results**: If you can't open a browser (e.g., Claude.ai's VM has no display, or you're on a remote server), skip the browser reviewer entirely. Instead, present results directly in the conversation. For each test case, show the prompt and the output. If the output is a file the user needs to see (like a .docx or .xlsx), save it to the filesystem and tell them where it is so they can download and inspect it. Ask for feedback inline: "How does this look? Anything you'd change?"
**Benchmarking**: Skip the quantitative benchmarking — it relies on baseline comparisons which aren't meaningful without subagents. Focus on qualitative feedback from the user.
**The iteration loop**: Same as before — improve the skill, rerun the test cases, ask for feedback — just without the browser reviewer in the middle. You can still organize results into iteration directories on the filesystem if you have one.
**Description optimization**: This section requires the `claude` CLI tool (specifically `claude -p`) which is only available in Claude Code. Skip it if you're on Claude.ai.
**Blind comparison**: Requires subagents. Skip it.
**Packaging**: The `package_skill.py` script works anywhere with Python and a filesystem. On Claude.ai, you can run it and the user can download the resulting `.skill` file.
---
## Cowork-Specific Instructions
If you're in Cowork, the main things to know are:
- You have subagents, so the main workflow (spawn test cases in parallel, run baselines, grade, etc.) all works. (However, if you run into severe problems with timeouts, it's OK to run the test prompts in series rather than parallel.)
- You don't have a browser or display, so when generating the eval viewer, use `--static <output_path>` to write a standalone HTML file instead of starting a server. Then proffer a link that the user can click to open the HTML in their browser.
- For whatever reason, the Cowork setup seems to disincline Claude from generating the eval viewer after running the tests, so just to reiterate: whether you're in Cowork or in Claude Code, after running tests, you should always generate the eval viewer for the human to look at examples before revising the skill yourself and trying to make corrections, using `generate_review.py` (not writing your own boutique html code). Sorry in advance but I'm gonna go all caps here: GENERATE THE EVAL VIEWER *BEFORE* evaluating inputs yourself. You want to get them in front of the human ASAP!
- Feedback works differently: since there's no running server, the viewer's "Submit All Reviews" button will download `feedback.json` as a file. You can then read it from there (you may have to request access first).
- Packaging works — `package_skill.py` just needs Python and a filesystem.
- Description optimization (`run_loop.py` / `run_eval.py`) should work in Cowork just fine since it uses `claude -p` via subprocess, not a browser, but please save it until you've fully finished making the skill and the user agrees it's in good shape.
---
## Reference files
The agents/ directory contains instructions for specialized subagents. Read them when you need to spawn the relevant subagent.
- `agents/grader.md` — How to evaluate assertions against outputs
- `agents/comparator.md` — How to do blind A/B comparison between two outputs
- `agents/analyzer.md` — How to analyze why one version beat another
The references/ directory has additional documentation:
- `references/schemas.md` — JSON structures for evals.json, grading.json, etc.
---
Repeating one more time the core loop here for emphasis:
- Figure out what the skill is about
- Draft or edit the skill
- Run claude-with-access-to-the-skill on test prompts
- With the user, evaluate the outputs:
- Create benchmark.json and run `eval-viewer/generate_review.py` to help the user review them
- Run quantitative evals
- Repeat until you and the user are satisfied
- Package the final skill and return it to the user.
Please add steps to your TodoList, if you have such a thing, to make sure you don't forget. If you're in Cowork, please specifically put "Create evals JSON and run `eval-viewer/generate_review.py` so human can review test cases" in your TodoList to make sure it happens.
Good luck!

View file

@ -0,0 +1,274 @@
# Post-hoc Analyzer Agent
Analyze blind comparison results to understand WHY the winner won and generate improvement suggestions.
## Role
After the blind comparator determines a winner, the Post-hoc Analyzer "unblids" the results by examining the skills and transcripts. The goal is to extract actionable insights: what made the winner better, and how can the loser be improved?
## Inputs
You receive these parameters in your prompt:
- **winner**: "A" or "B" (from blind comparison)
- **winner_skill_path**: Path to the skill that produced the winning output
- **winner_transcript_path**: Path to the execution transcript for the winner
- **loser_skill_path**: Path to the skill that produced the losing output
- **loser_transcript_path**: Path to the execution transcript for the loser
- **comparison_result_path**: Path to the blind comparator's output JSON
- **output_path**: Where to save the analysis results
## Process
### Step 1: Read Comparison Result
1. Read the blind comparator's output at comparison_result_path
2. Note the winning side (A or B), the reasoning, and any scores
3. Understand what the comparator valued in the winning output
### Step 2: Read Both Skills
1. Read the winner skill's SKILL.md and key referenced files
2. Read the loser skill's SKILL.md and key referenced files
3. Identify structural differences:
- Instructions clarity and specificity
- Script/tool usage patterns
- Example coverage
- Edge case handling
### Step 3: Read Both Transcripts
1. Read the winner's transcript
2. Read the loser's transcript
3. Compare execution patterns:
- How closely did each follow their skill's instructions?
- What tools were used differently?
- Where did the loser diverge from optimal behavior?
- Did either encounter errors or make recovery attempts?
### Step 4: Analyze Instruction Following
For each transcript, evaluate:
- Did the agent follow the skill's explicit instructions?
- Did the agent use the skill's provided tools/scripts?
- Were there missed opportunities to leverage skill content?
- Did the agent add unnecessary steps not in the skill?
Score instruction following 1-10 and note specific issues.
### Step 5: Identify Winner Strengths
Determine what made the winner better:
- Clearer instructions that led to better behavior?
- Better scripts/tools that produced better output?
- More comprehensive examples that guided edge cases?
- Better error handling guidance?
Be specific. Quote from skills/transcripts where relevant.
### Step 6: Identify Loser Weaknesses
Determine what held the loser back:
- Ambiguous instructions that led to suboptimal choices?
- Missing tools/scripts that forced workarounds?
- Gaps in edge case coverage?
- Poor error handling that caused failures?
### Step 7: Generate Improvement Suggestions
Based on the analysis, produce actionable suggestions for improving the loser skill:
- Specific instruction changes to make
- Tools/scripts to add or modify
- Examples to include
- Edge cases to address
Prioritize by impact. Focus on changes that would have changed the outcome.
### Step 8: Write Analysis Results
Save structured analysis to `{output_path}`.
## Output Format
Write a JSON file with this structure:
```json
{
"comparison_summary": {
"winner": "A",
"winner_skill": "path/to/winner/skill",
"loser_skill": "path/to/loser/skill",
"comparator_reasoning": "Brief summary of why comparator chose winner"
},
"winner_strengths": [
"Clear step-by-step instructions for handling multi-page documents",
"Included validation script that caught formatting errors",
"Explicit guidance on fallback behavior when OCR fails"
],
"loser_weaknesses": [
"Vague instruction 'process the document appropriately' led to inconsistent behavior",
"No script for validation, agent had to improvise and made errors",
"No guidance on OCR failure, agent gave up instead of trying alternatives"
],
"instruction_following": {
"winner": {
"score": 9,
"issues": [
"Minor: skipped optional logging step"
]
},
"loser": {
"score": 6,
"issues": [
"Did not use the skill's formatting template",
"Invented own approach instead of following step 3",
"Missed the 'always validate output' instruction"
]
}
},
"improvement_suggestions": [
{
"priority": "high",
"category": "instructions",
"suggestion": "Replace 'process the document appropriately' with explicit steps: 1) Extract text, 2) Identify sections, 3) Format per template",
"expected_impact": "Would eliminate ambiguity that caused inconsistent behavior"
},
{
"priority": "high",
"category": "tools",
"suggestion": "Add validate_output.py script similar to winner skill's validation approach",
"expected_impact": "Would catch formatting errors before final output"
},
{
"priority": "medium",
"category": "error_handling",
"suggestion": "Add fallback instructions: 'If OCR fails, try: 1) different resolution, 2) image preprocessing, 3) manual extraction'",
"expected_impact": "Would prevent early failure on difficult documents"
}
],
"transcript_insights": {
"winner_execution_pattern": "Read skill -> Followed 5-step process -> Used validation script -> Fixed 2 issues -> Produced output",
"loser_execution_pattern": "Read skill -> Unclear on approach -> Tried 3 different methods -> No validation -> Output had errors"
}
}
```
## Guidelines
- **Be specific**: Quote from skills and transcripts, don't just say "instructions were unclear"
- **Be actionable**: Suggestions should be concrete changes, not vague advice
- **Focus on skill improvements**: The goal is to improve the losing skill, not critique the agent
- **Prioritize by impact**: Which changes would most likely have changed the outcome?
- **Consider causation**: Did the skill weakness actually cause the worse output, or is it incidental?
- **Stay objective**: Analyze what happened, don't editorialize
- **Think about generalization**: Would this improvement help on other evals too?
## Categories for Suggestions
Use these categories to organize improvement suggestions:
| Category | Description |
|----------|-------------|
| `instructions` | Changes to the skill's prose instructions |
| `tools` | Scripts, templates, or utilities to add/modify |
| `examples` | Example inputs/outputs to include |
| `error_handling` | Guidance for handling failures |
| `structure` | Reorganization of skill content |
| `references` | External docs or resources to add |
## Priority Levels
- **high**: Would likely change the outcome of this comparison
- **medium**: Would improve quality but may not change win/loss
- **low**: Nice to have, marginal improvement
---
# Analyzing Benchmark Results
When analyzing benchmark results, the analyzer's purpose is to **surface patterns and anomalies** across multiple runs, not suggest skill improvements.
## Role
Review all benchmark run results and generate freeform notes that help the user understand skill performance. Focus on patterns that wouldn't be visible from aggregate metrics alone.
## Inputs
You receive these parameters in your prompt:
- **benchmark_data_path**: Path to the in-progress benchmark.json with all run results
- **skill_path**: Path to the skill being benchmarked
- **output_path**: Where to save the notes (as JSON array of strings)
## Process
### Step 1: Read Benchmark Data
1. Read the benchmark.json containing all run results
2. Note the configurations tested (with_skill, without_skill)
3. Understand the run_summary aggregates already calculated
### Step 2: Analyze Per-Assertion Patterns
For each expectation across all runs:
- Does it **always pass** in both configurations? (may not differentiate skill value)
- Does it **always fail** in both configurations? (may be broken or beyond capability)
- Does it **always pass with skill but fail without**? (skill clearly adds value here)
- Does it **always fail with skill but pass without**? (skill may be hurting)
- Is it **highly variable**? (flaky expectation or non-deterministic behavior)
### Step 3: Analyze Cross-Eval Patterns
Look for patterns across evals:
- Are certain eval types consistently harder/easier?
- Do some evals show high variance while others are stable?
- Are there surprising results that contradict expectations?
### Step 4: Analyze Metrics Patterns
Look at time_seconds, tokens, tool_calls:
- Does the skill significantly increase execution time?
- Is there high variance in resource usage?
- Are there outlier runs that skew the aggregates?
### Step 5: Generate Notes
Write freeform observations as a list of strings. Each note should:
- State a specific observation
- Be grounded in the data (not speculation)
- Help the user understand something the aggregate metrics don't show
Examples:
- "Assertion 'Output is a PDF file' passes 100% in both configurations - may not differentiate skill value"
- "Eval 3 shows high variance (50% ± 40%) - run 2 had an unusual failure that may be flaky"
- "Without-skill runs consistently fail on table extraction expectations (0% pass rate)"
- "Skill adds 13s average execution time but improves pass rate by 50%"
- "Token usage is 80% higher with skill, primarily due to script output parsing"
- "All 3 without-skill runs for eval 1 produced empty output"
### Step 6: Write Notes
Save notes to `{output_path}` as a JSON array of strings:
```json
[
"Assertion 'Output is a PDF file' passes 100% in both configurations - may not differentiate skill value",
"Eval 3 shows high variance (50% ± 40%) - run 2 had an unusual failure",
"Without-skill runs consistently fail on table extraction expectations",
"Skill adds 13s average execution time but improves pass rate by 50%"
]
```
## Guidelines
**DO:**
- Report what you observe in the data
- Be specific about which evals, expectations, or runs you're referring to
- Note patterns that aggregate metrics would hide
- Provide context that helps interpret the numbers
**DO NOT:**
- Suggest improvements to the skill (that's for the improvement step, not benchmarking)
- Make subjective quality judgments ("the output was good/bad")
- Speculate about causes without evidence
- Repeat information already in the run_summary aggregates

View file

@ -0,0 +1,202 @@
# Blind Comparator Agent
Compare two outputs WITHOUT knowing which skill produced them.
## Role
The Blind Comparator judges which output better accomplishes the eval task. You receive two outputs labeled A and B, but you do NOT know which skill produced which. This prevents bias toward a particular skill or approach.
Your judgment is based purely on output quality and task completion.
## Inputs
You receive these parameters in your prompt:
- **output_a_path**: Path to the first output file or directory
- **output_b_path**: Path to the second output file or directory
- **eval_prompt**: The original task/prompt that was executed
- **expectations**: List of expectations to check (optional - may be empty)
## Process
### Step 1: Read Both Outputs
1. Examine output A (file or directory)
2. Examine output B (file or directory)
3. Note the type, structure, and content of each
4. If outputs are directories, examine all relevant files inside
### Step 2: Understand the Task
1. Read the eval_prompt carefully
2. Identify what the task requires:
- What should be produced?
- What qualities matter (accuracy, completeness, format)?
- What would distinguish a good output from a poor one?
### Step 3: Generate Evaluation Rubric
Based on the task, generate a rubric with two dimensions:
**Content Rubric** (what the output contains):
| Criterion | 1 (Poor) | 3 (Acceptable) | 5 (Excellent) |
|-----------|----------|----------------|---------------|
| Correctness | Major errors | Minor errors | Fully correct |
| Completeness | Missing key elements | Mostly complete | All elements present |
| Accuracy | Significant inaccuracies | Minor inaccuracies | Accurate throughout |
**Structure Rubric** (how the output is organized):
| Criterion | 1 (Poor) | 3 (Acceptable) | 5 (Excellent) |
|-----------|----------|----------------|---------------|
| Organization | Disorganized | Reasonably organized | Clear, logical structure |
| Formatting | Inconsistent/broken | Mostly consistent | Professional, polished |
| Usability | Difficult to use | Usable with effort | Easy to use |
Adapt criteria to the specific task. For example:
- PDF form → "Field alignment", "Text readability", "Data placement"
- Document → "Section structure", "Heading hierarchy", "Paragraph flow"
- Data output → "Schema correctness", "Data types", "Completeness"
### Step 4: Evaluate Each Output Against the Rubric
For each output (A and B):
1. **Score each criterion** on the rubric (1-5 scale)
2. **Calculate dimension totals**: Content score, Structure score
3. **Calculate overall score**: Average of dimension scores, scaled to 1-10
### Step 5: Check Assertions (if provided)
If expectations are provided:
1. Check each expectation against output A
2. Check each expectation against output B
3. Count pass rates for each output
4. Use expectation scores as secondary evidence (not the primary decision factor)
### Step 6: Determine the Winner
Compare A and B based on (in priority order):
1. **Primary**: Overall rubric score (content + structure)
2. **Secondary**: Assertion pass rates (if applicable)
3. **Tiebreaker**: If truly equal, declare a TIE
Be decisive - ties should be rare. One output is usually better, even if marginally.
### Step 7: Write Comparison Results
Save results to a JSON file at the path specified (or `comparison.json` if not specified).
## Output Format
Write a JSON file with this structure:
```json
{
"winner": "A",
"reasoning": "Output A provides a complete solution with proper formatting and all required fields. Output B is missing the date field and has formatting inconsistencies.",
"rubric": {
"A": {
"content": {
"correctness": 5,
"completeness": 5,
"accuracy": 4
},
"structure": {
"organization": 4,
"formatting": 5,
"usability": 4
},
"content_score": 4.7,
"structure_score": 4.3,
"overall_score": 9.0
},
"B": {
"content": {
"correctness": 3,
"completeness": 2,
"accuracy": 3
},
"structure": {
"organization": 3,
"formatting": 2,
"usability": 3
},
"content_score": 2.7,
"structure_score": 2.7,
"overall_score": 5.4
}
},
"output_quality": {
"A": {
"score": 9,
"strengths": ["Complete solution", "Well-formatted", "All fields present"],
"weaknesses": ["Minor style inconsistency in header"]
},
"B": {
"score": 5,
"strengths": ["Readable output", "Correct basic structure"],
"weaknesses": ["Missing date field", "Formatting inconsistencies", "Partial data extraction"]
}
},
"expectation_results": {
"A": {
"passed": 4,
"total": 5,
"pass_rate": 0.80,
"details": [
{"text": "Output includes name", "passed": true},
{"text": "Output includes date", "passed": true},
{"text": "Format is PDF", "passed": true},
{"text": "Contains signature", "passed": false},
{"text": "Readable text", "passed": true}
]
},
"B": {
"passed": 3,
"total": 5,
"pass_rate": 0.60,
"details": [
{"text": "Output includes name", "passed": true},
{"text": "Output includes date", "passed": false},
{"text": "Format is PDF", "passed": true},
{"text": "Contains signature", "passed": false},
{"text": "Readable text", "passed": true}
]
}
}
}
```
If no expectations were provided, omit the `expectation_results` field entirely.
## Field Descriptions
- **winner**: "A", "B", or "TIE"
- **reasoning**: Clear explanation of why the winner was chosen (or why it's a tie)
- **rubric**: Structured rubric evaluation for each output
- **content**: Scores for content criteria (correctness, completeness, accuracy)
- **structure**: Scores for structure criteria (organization, formatting, usability)
- **content_score**: Average of content criteria (1-5)
- **structure_score**: Average of structure criteria (1-5)
- **overall_score**: Combined score scaled to 1-10
- **output_quality**: Summary quality assessment
- **score**: 1-10 rating (should match rubric overall_score)
- **strengths**: List of positive aspects
- **weaknesses**: List of issues or shortcomings
- **expectation_results**: (Only if expectations provided)
- **passed**: Number of expectations that passed
- **total**: Total number of expectations
- **pass_rate**: Fraction passed (0.0 to 1.0)
- **details**: Individual expectation results
## Guidelines
- **Stay blind**: DO NOT try to infer which skill produced which output. Judge purely on output quality.
- **Be specific**: Cite specific examples when explaining strengths and weaknesses.
- **Be decisive**: Choose a winner unless outputs are genuinely equivalent.
- **Output quality first**: Assertion scores are secondary to overall task completion.
- **Be objective**: Don't favor outputs based on style preferences; focus on correctness and completeness.
- **Explain your reasoning**: The reasoning field should make it clear why you chose the winner.
- **Handle edge cases**: If both outputs fail, pick the one that fails less badly. If both are excellent, pick the one that's marginally better.

View file

@ -0,0 +1,223 @@
# Grader Agent
Evaluate expectations against an execution transcript and outputs.
## Role
The Grader reviews a transcript and output files, then determines whether each expectation passes or fails. Provide clear evidence for each judgment.
You have two jobs: grade the outputs, and critique the evals themselves. A passing grade on a weak assertion is worse than useless — it creates false confidence. When you notice an assertion that's trivially satisfied, or an important outcome that no assertion checks, say so.
## Inputs
You receive these parameters in your prompt:
- **expectations**: List of expectations to evaluate (strings)
- **transcript_path**: Path to the execution transcript (markdown file)
- **outputs_dir**: Directory containing output files from execution
## Process
### Step 1: Read the Transcript
1. Read the transcript file completely
2. Note the eval prompt, execution steps, and final result
3. Identify any issues or errors documented
### Step 2: Examine Output Files
1. List files in outputs_dir
2. Read/examine each file relevant to the expectations. If outputs aren't plain text, use the inspection tools provided in your prompt — don't rely solely on what the transcript says the executor produced.
3. Note contents, structure, and quality
### Step 3: Evaluate Each Assertion
For each expectation:
1. **Search for evidence** in the transcript and outputs
2. **Determine verdict**:
- **PASS**: Clear evidence the expectation is true AND the evidence reflects genuine task completion, not just surface-level compliance
- **FAIL**: No evidence, or evidence contradicts the expectation, or the evidence is superficial (e.g., correct filename but empty/wrong content)
3. **Cite the evidence**: Quote the specific text or describe what you found
### Step 4: Extract and Verify Claims
Beyond the predefined expectations, extract implicit claims from the outputs and verify them:
1. **Extract claims** from the transcript and outputs:
- Factual statements ("The form has 12 fields")
- Process claims ("Used pypdf to fill the form")
- Quality claims ("All fields were filled correctly")
2. **Verify each claim**:
- **Factual claims**: Can be checked against the outputs or external sources
- **Process claims**: Can be verified from the transcript
- **Quality claims**: Evaluate whether the claim is justified
3. **Flag unverifiable claims**: Note claims that cannot be verified with available information
This catches issues that predefined expectations might miss.
### Step 5: Read User Notes
If `{outputs_dir}/user_notes.md` exists:
1. Read it and note any uncertainties or issues flagged by the executor
2. Include relevant concerns in the grading output
3. These may reveal problems even when expectations pass
### Step 6: Critique the Evals
After grading, consider whether the evals themselves could be improved. Only surface suggestions when there's a clear gap.
Good suggestions test meaningful outcomes — assertions that are hard to satisfy without actually doing the work correctly. Think about what makes an assertion *discriminating*: it passes when the skill genuinely succeeds and fails when it doesn't.
Suggestions worth raising:
- An assertion that passed but would also pass for a clearly wrong output (e.g., checking filename existence but not file content)
- An important outcome you observed — good or bad — that no assertion covers at all
- An assertion that can't actually be verified from the available outputs
Keep the bar high. The goal is to flag things the eval author would say "good catch" about, not to nitpick every assertion.
### Step 7: Write Grading Results
Save results to `{outputs_dir}/../grading.json` (sibling to outputs_dir).
## Grading Criteria
**PASS when**:
- The transcript or outputs clearly demonstrate the expectation is true
- Specific evidence can be cited
- The evidence reflects genuine substance, not just surface compliance (e.g., a file exists AND contains correct content, not just the right filename)
**FAIL when**:
- No evidence found for the expectation
- Evidence contradicts the expectation
- The expectation cannot be verified from available information
- The evidence is superficial — the assertion is technically satisfied but the underlying task outcome is wrong or incomplete
- The output appears to meet the assertion by coincidence rather than by actually doing the work
**When uncertain**: The burden of proof to pass is on the expectation.
### Step 8: Read Executor Metrics and Timing
1. If `{outputs_dir}/metrics.json` exists, read it and include in grading output
2. If `{outputs_dir}/../timing.json` exists, read it and include timing data
## Output Format
Write a JSON file with this structure:
```json
{
"expectations": [
{
"text": "The output includes the name 'John Smith'",
"passed": true,
"evidence": "Found in transcript Step 3: 'Extracted names: John Smith, Sarah Johnson'"
},
{
"text": "The spreadsheet has a SUM formula in cell B10",
"passed": false,
"evidence": "No spreadsheet was created. The output was a text file."
},
{
"text": "The assistant used the skill's OCR script",
"passed": true,
"evidence": "Transcript Step 2 shows: 'Tool: Bash - python ocr_script.py image.png'"
}
],
"summary": {
"passed": 2,
"failed": 1,
"total": 3,
"pass_rate": 0.67
},
"execution_metrics": {
"tool_calls": {
"Read": 5,
"Write": 2,
"Bash": 8
},
"total_tool_calls": 15,
"total_steps": 6,
"errors_encountered": 0,
"output_chars": 12450,
"transcript_chars": 3200
},
"timing": {
"executor_duration_seconds": 165.0,
"grader_duration_seconds": 26.0,
"total_duration_seconds": 191.0
},
"claims": [
{
"claim": "The form has 12 fillable fields",
"type": "factual",
"verified": true,
"evidence": "Counted 12 fields in field_info.json"
},
{
"claim": "All required fields were populated",
"type": "quality",
"verified": false,
"evidence": "Reference section was left blank despite data being available"
}
],
"user_notes_summary": {
"uncertainties": ["Used 2023 data, may be stale"],
"needs_review": [],
"workarounds": ["Fell back to text overlay for non-fillable fields"]
},
"eval_feedback": {
"suggestions": [
{
"assertion": "The output includes the name 'John Smith'",
"reason": "A hallucinated document that mentions the name would also pass — consider checking it appears as the primary contact with matching phone and email from the input"
},
{
"reason": "No assertion checks whether the extracted phone numbers match the input — I observed incorrect numbers in the output that went uncaught"
}
],
"overall": "Assertions check presence but not correctness. Consider adding content verification."
}
}
```
## Field Descriptions
- **expectations**: Array of graded expectations
- **text**: The original expectation text
- **passed**: Boolean - true if expectation passes
- **evidence**: Specific quote or description supporting the verdict
- **summary**: Aggregate statistics
- **passed**: Count of passed expectations
- **failed**: Count of failed expectations
- **total**: Total expectations evaluated
- **pass_rate**: Fraction passed (0.0 to 1.0)
- **execution_metrics**: Copied from executor's metrics.json (if available)
- **output_chars**: Total character count of output files (proxy for tokens)
- **transcript_chars**: Character count of transcript
- **timing**: Wall clock timing from timing.json (if available)
- **executor_duration_seconds**: Time spent in executor subagent
- **total_duration_seconds**: Total elapsed time for the run
- **claims**: Extracted and verified claims from the output
- **claim**: The statement being verified
- **type**: "factual", "process", or "quality"
- **verified**: Boolean - whether the claim holds
- **evidence**: Supporting or contradicting evidence
- **user_notes_summary**: Issues flagged by the executor
- **uncertainties**: Things the executor wasn't sure about
- **needs_review**: Items requiring human attention
- **workarounds**: Places where the skill didn't work as expected
- **eval_feedback**: Improvement suggestions for the evals (only when warranted)
- **suggestions**: List of concrete suggestions, each with a `reason` and optionally an `assertion` it relates to
- **overall**: Brief assessment — can be "No suggestions, evals look solid" if nothing to flag
## Guidelines
- **Be objective**: Base verdicts on evidence, not assumptions
- **Be specific**: Quote the exact text that supports your verdict
- **Be thorough**: Check both transcript and output files
- **Be consistent**: Apply the same standard to each expectation
- **Explain failures**: Make it clear why evidence was insufficient
- **No partial credit**: Each expectation is pass or fail, not partial

View file

@ -0,0 +1,146 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Eval Set Review - __SKILL_NAME_PLACEHOLDER__</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@500;600&family=Lora:wght@400;500&display=swap" rel="stylesheet">
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: 'Lora', Georgia, serif; background: #faf9f5; padding: 2rem; color: #141413; }
h1 { font-family: 'Poppins', sans-serif; margin-bottom: 0.5rem; font-size: 1.5rem; }
.description { color: #b0aea5; margin-bottom: 1.5rem; font-style: italic; max-width: 900px; }
.controls { margin-bottom: 1rem; display: flex; gap: 0.5rem; }
.btn { font-family: 'Poppins', sans-serif; padding: 0.5rem 1rem; border: none; border-radius: 6px; cursor: pointer; font-size: 0.875rem; font-weight: 500; }
.btn-add { background: #6a9bcc; color: white; }
.btn-add:hover { background: #5889b8; }
.btn-export { background: #d97757; color: white; }
.btn-export:hover { background: #c4613f; }
table { width: 100%; max-width: 1100px; border-collapse: collapse; background: white; border-radius: 6px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.08); }
th { font-family: 'Poppins', sans-serif; background: #141413; color: #faf9f5; padding: 0.75rem 1rem; text-align: left; font-size: 0.875rem; }
td { padding: 0.75rem 1rem; border-bottom: 1px solid #e8e6dc; vertical-align: top; }
tr:nth-child(even) td { background: #faf9f5; }
tr:hover td { background: #f3f1ea; }
.section-header td { background: #e8e6dc; font-family: 'Poppins', sans-serif; font-weight: 500; font-size: 0.8rem; color: #141413; text-transform: uppercase; letter-spacing: 0.05em; }
.query-input { width: 100%; padding: 0.4rem; border: 1px solid #e8e6dc; border-radius: 4px; font-size: 0.875rem; font-family: 'Lora', Georgia, serif; resize: vertical; min-height: 60px; }
.query-input:focus { outline: none; border-color: #d97757; box-shadow: 0 0 0 2px rgba(217,119,87,0.15); }
.toggle { position: relative; display: inline-block; width: 44px; height: 24px; }
.toggle input { opacity: 0; width: 0; height: 0; }
.toggle .slider { position: absolute; inset: 0; background: #b0aea5; border-radius: 24px; cursor: pointer; transition: 0.2s; }
.toggle .slider::before { content: ""; position: absolute; width: 18px; height: 18px; left: 3px; bottom: 3px; background: white; border-radius: 50%; transition: 0.2s; }
.toggle input:checked + .slider { background: #d97757; }
.toggle input:checked + .slider::before { transform: translateX(20px); }
.btn-delete { background: #c44; color: white; padding: 0.3rem 0.6rem; border: none; border-radius: 4px; cursor: pointer; font-size: 0.75rem; font-family: 'Poppins', sans-serif; }
.btn-delete:hover { background: #a33; }
.summary { margin-top: 1rem; color: #b0aea5; font-size: 0.875rem; }
</style>
</head>
<body>
<h1>Eval Set Review: <span id="skill-name">__SKILL_NAME_PLACEHOLDER__</span></h1>
<p class="description">Current description: <span id="skill-desc">__SKILL_DESCRIPTION_PLACEHOLDER__</span></p>
<div class="controls">
<button class="btn btn-add" onclick="addRow()">+ Add Query</button>
<button class="btn btn-export" onclick="exportEvalSet()">Export Eval Set</button>
</div>
<table>
<thead>
<tr>
<th style="width:65%">Query</th>
<th style="width:18%">Should Trigger</th>
<th style="width:10%">Actions</th>
</tr>
</thead>
<tbody id="eval-body"></tbody>
</table>
<p class="summary" id="summary"></p>
<script>
const EVAL_DATA = __EVAL_DATA_PLACEHOLDER__;
let evalItems = [...EVAL_DATA];
function render() {
const tbody = document.getElementById('eval-body');
tbody.innerHTML = '';
// Sort: should-trigger first, then should-not-trigger
const sorted = evalItems
.map((item, origIdx) => ({ ...item, origIdx }))
.sort((a, b) => (b.should_trigger ? 1 : 0) - (a.should_trigger ? 1 : 0));
let lastGroup = null;
sorted.forEach(item => {
const group = item.should_trigger ? 'trigger' : 'no-trigger';
if (group !== lastGroup) {
const headerRow = document.createElement('tr');
headerRow.className = 'section-header';
headerRow.innerHTML = `<td colspan="3">${item.should_trigger ? 'Should Trigger' : 'Should NOT Trigger'}</td>`;
tbody.appendChild(headerRow);
lastGroup = group;
}
const idx = item.origIdx;
const tr = document.createElement('tr');
tr.innerHTML = `
<td><textarea class="query-input" onchange="updateQuery(${idx}, this.value)">${escapeHtml(item.query)}</textarea></td>
<td>
<label class="toggle">
<input type="checkbox" ${item.should_trigger ? 'checked' : ''} onchange="updateTrigger(${idx}, this.checked)">
<span class="slider"></span>
</label>
<span style="margin-left:8px;font-size:0.8rem;color:#b0aea5">${item.should_trigger ? 'Yes' : 'No'}</span>
</td>
<td><button class="btn-delete" onclick="deleteRow(${idx})">Delete</button></td>
`;
tbody.appendChild(tr);
});
updateSummary();
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
function updateQuery(idx, value) { evalItems[idx].query = value; updateSummary(); }
function updateTrigger(idx, value) { evalItems[idx].should_trigger = value; render(); }
function deleteRow(idx) { evalItems.splice(idx, 1); render(); }
function addRow() {
evalItems.push({ query: '', should_trigger: true });
render();
const inputs = document.querySelectorAll('.query-input');
inputs[inputs.length - 1].focus();
}
function updateSummary() {
const trigger = evalItems.filter(i => i.should_trigger).length;
const noTrigger = evalItems.filter(i => !i.should_trigger).length;
document.getElementById('summary').textContent =
`${evalItems.length} queries total: ${trigger} should trigger, ${noTrigger} should not trigger`;
}
function exportEvalSet() {
const valid = evalItems.filter(i => i.query.trim() !== '');
const data = valid.map(i => ({ query: i.query.trim(), should_trigger: i.should_trigger }));
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'eval_set.json';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
render();
</script>
</body>
</html>

View file

@ -0,0 +1,471 @@
#!/usr/bin/env python3
"""Generate and serve a review page for eval results.
Reads the workspace directory, discovers runs (directories with outputs/),
embeds all output data into a self-contained HTML page, and serves it via
a tiny HTTP server. Feedback auto-saves to feedback.json in the workspace.
Usage:
python generate_review.py <workspace-path> [--port PORT] [--skill-name NAME]
python generate_review.py <workspace-path> --previous-feedback /path/to/old/feedback.json
No dependencies beyond the Python stdlib are required.
"""
import argparse
import base64
import json
import mimetypes
import os
import re
import signal
import subprocess
import sys
import time
import webbrowser
from functools import partial
from http.server import HTTPServer, BaseHTTPRequestHandler
from pathlib import Path
# Files to exclude from output listings
METADATA_FILES = {"transcript.md", "user_notes.md", "metrics.json"}
# Extensions we render as inline text
TEXT_EXTENSIONS = {
".txt", ".md", ".json", ".csv", ".py", ".js", ".ts", ".tsx", ".jsx",
".yaml", ".yml", ".xml", ".html", ".css", ".sh", ".rb", ".go", ".rs",
".java", ".c", ".cpp", ".h", ".hpp", ".sql", ".r", ".toml",
}
# Extensions we render as inline images
IMAGE_EXTENSIONS = {".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp"}
# MIME type overrides for common types
MIME_OVERRIDES = {
".svg": "image/svg+xml",
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
}
def get_mime_type(path: Path) -> str:
ext = path.suffix.lower()
if ext in MIME_OVERRIDES:
return MIME_OVERRIDES[ext]
mime, _ = mimetypes.guess_type(str(path))
return mime or "application/octet-stream"
def find_runs(workspace: Path) -> list[dict]:
"""Recursively find directories that contain an outputs/ subdirectory."""
runs: list[dict] = []
_find_runs_recursive(workspace, workspace, runs)
runs.sort(key=lambda r: (r.get("eval_id", float("inf")), r["id"]))
return runs
def _find_runs_recursive(root: Path, current: Path, runs: list[dict]) -> None:
if not current.is_dir():
return
outputs_dir = current / "outputs"
if outputs_dir.is_dir():
run = build_run(root, current)
if run:
runs.append(run)
return
skip = {"node_modules", ".git", "__pycache__", "skill", "inputs"}
for child in sorted(current.iterdir()):
if child.is_dir() and child.name not in skip:
_find_runs_recursive(root, child, runs)
def build_run(root: Path, run_dir: Path) -> dict | None:
"""Build a run dict with prompt, outputs, and grading data."""
prompt = ""
eval_id = None
# Try eval_metadata.json
for candidate in [run_dir / "eval_metadata.json", run_dir.parent / "eval_metadata.json"]:
if candidate.exists():
try:
metadata = json.loads(candidate.read_text())
prompt = metadata.get("prompt", "")
eval_id = metadata.get("eval_id")
except (json.JSONDecodeError, OSError):
pass
if prompt:
break
# Fall back to transcript.md
if not prompt:
for candidate in [run_dir / "transcript.md", run_dir / "outputs" / "transcript.md"]:
if candidate.exists():
try:
text = candidate.read_text()
match = re.search(r"## Eval Prompt\n\n([\s\S]*?)(?=\n##|$)", text)
if match:
prompt = match.group(1).strip()
except OSError:
pass
if prompt:
break
if not prompt:
prompt = "(No prompt found)"
run_id = str(run_dir.relative_to(root)).replace("/", "-").replace("\\", "-")
# Collect output files
outputs_dir = run_dir / "outputs"
output_files: list[dict] = []
if outputs_dir.is_dir():
for f in sorted(outputs_dir.iterdir()):
if f.is_file() and f.name not in METADATA_FILES:
output_files.append(embed_file(f))
# Load grading if present
grading = None
for candidate in [run_dir / "grading.json", run_dir.parent / "grading.json"]:
if candidate.exists():
try:
grading = json.loads(candidate.read_text())
except (json.JSONDecodeError, OSError):
pass
if grading:
break
return {
"id": run_id,
"prompt": prompt,
"eval_id": eval_id,
"outputs": output_files,
"grading": grading,
}
def embed_file(path: Path) -> dict:
"""Read a file and return an embedded representation."""
ext = path.suffix.lower()
mime = get_mime_type(path)
if ext in TEXT_EXTENSIONS:
try:
content = path.read_text(errors="replace")
except OSError:
content = "(Error reading file)"
return {
"name": path.name,
"type": "text",
"content": content,
}
elif ext in IMAGE_EXTENSIONS:
try:
raw = path.read_bytes()
b64 = base64.b64encode(raw).decode("ascii")
except OSError:
return {"name": path.name, "type": "error", "content": "(Error reading file)"}
return {
"name": path.name,
"type": "image",
"mime": mime,
"data_uri": f"data:{mime};base64,{b64}",
}
elif ext == ".pdf":
try:
raw = path.read_bytes()
b64 = base64.b64encode(raw).decode("ascii")
except OSError:
return {"name": path.name, "type": "error", "content": "(Error reading file)"}
return {
"name": path.name,
"type": "pdf",
"data_uri": f"data:{mime};base64,{b64}",
}
elif ext == ".xlsx":
try:
raw = path.read_bytes()
b64 = base64.b64encode(raw).decode("ascii")
except OSError:
return {"name": path.name, "type": "error", "content": "(Error reading file)"}
return {
"name": path.name,
"type": "xlsx",
"data_b64": b64,
}
else:
# Binary / unknown — base64 download link
try:
raw = path.read_bytes()
b64 = base64.b64encode(raw).decode("ascii")
except OSError:
return {"name": path.name, "type": "error", "content": "(Error reading file)"}
return {
"name": path.name,
"type": "binary",
"mime": mime,
"data_uri": f"data:{mime};base64,{b64}",
}
def load_previous_iteration(workspace: Path) -> dict[str, dict]:
"""Load previous iteration's feedback and outputs.
Returns a map of run_id -> {"feedback": str, "outputs": list[dict]}.
"""
result: dict[str, dict] = {}
# Load feedback
feedback_map: dict[str, str] = {}
feedback_path = workspace / "feedback.json"
if feedback_path.exists():
try:
data = json.loads(feedback_path.read_text())
feedback_map = {
r["run_id"]: r["feedback"]
for r in data.get("reviews", [])
if r.get("feedback", "").strip()
}
except (json.JSONDecodeError, OSError, KeyError):
pass
# Load runs (to get outputs)
prev_runs = find_runs(workspace)
for run in prev_runs:
result[run["id"]] = {
"feedback": feedback_map.get(run["id"], ""),
"outputs": run.get("outputs", []),
}
# Also add feedback for run_ids that had feedback but no matching run
for run_id, fb in feedback_map.items():
if run_id not in result:
result[run_id] = {"feedback": fb, "outputs": []}
return result
def generate_html(
runs: list[dict],
skill_name: str,
previous: dict[str, dict] | None = None,
benchmark: dict | None = None,
) -> str:
"""Generate the complete standalone HTML page with embedded data."""
template_path = Path(__file__).parent / "viewer.html"
template = template_path.read_text()
# Build previous_feedback and previous_outputs maps for the template
previous_feedback: dict[str, str] = {}
previous_outputs: dict[str, list[dict]] = {}
if previous:
for run_id, data in previous.items():
if data.get("feedback"):
previous_feedback[run_id] = data["feedback"]
if data.get("outputs"):
previous_outputs[run_id] = data["outputs"]
embedded = {
"skill_name": skill_name,
"runs": runs,
"previous_feedback": previous_feedback,
"previous_outputs": previous_outputs,
}
if benchmark:
embedded["benchmark"] = benchmark
data_json = json.dumps(embedded)
return template.replace("/*__EMBEDDED_DATA__*/", f"const EMBEDDED_DATA = {data_json};")
# ---------------------------------------------------------------------------
# HTTP server (stdlib only, zero dependencies)
# ---------------------------------------------------------------------------
def _kill_port(port: int) -> None:
"""Kill any process listening on the given port."""
try:
result = subprocess.run(
["lsof", "-ti", f":{port}"],
capture_output=True, text=True, timeout=5,
)
for pid_str in result.stdout.strip().split("\n"):
if pid_str.strip():
try:
os.kill(int(pid_str.strip()), signal.SIGTERM)
except (ProcessLookupError, ValueError):
pass
if result.stdout.strip():
time.sleep(0.5)
except subprocess.TimeoutExpired:
pass
except FileNotFoundError:
print("Note: lsof not found, cannot check if port is in use", file=sys.stderr)
class ReviewHandler(BaseHTTPRequestHandler):
"""Serves the review HTML and handles feedback saves.
Regenerates the HTML on each page load so that refreshing the browser
picks up new eval outputs without restarting the server.
"""
def __init__(
self,
workspace: Path,
skill_name: str,
feedback_path: Path,
previous: dict[str, dict],
benchmark_path: Path | None,
*args,
**kwargs,
):
self.workspace = workspace
self.skill_name = skill_name
self.feedback_path = feedback_path
self.previous = previous
self.benchmark_path = benchmark_path
super().__init__(*args, **kwargs)
def do_GET(self) -> None:
if self.path == "/" or self.path == "/index.html":
# Regenerate HTML on each request (re-scans workspace for new outputs)
runs = find_runs(self.workspace)
benchmark = None
if self.benchmark_path and self.benchmark_path.exists():
try:
benchmark = json.loads(self.benchmark_path.read_text())
except (json.JSONDecodeError, OSError):
pass
html = generate_html(runs, self.skill_name, self.previous, benchmark)
content = html.encode("utf-8")
self.send_response(200)
self.send_header("Content-Type", "text/html; charset=utf-8")
self.send_header("Content-Length", str(len(content)))
self.end_headers()
self.wfile.write(content)
elif self.path == "/api/feedback":
data = b"{}"
if self.feedback_path.exists():
data = self.feedback_path.read_bytes()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
else:
self.send_error(404)
def do_POST(self) -> None:
if self.path == "/api/feedback":
length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(length)
try:
data = json.loads(body)
if not isinstance(data, dict) or "reviews" not in data:
raise ValueError("Expected JSON object with 'reviews' key")
self.feedback_path.write_text(json.dumps(data, indent=2) + "\n")
resp = b'{"ok":true}'
self.send_response(200)
except (json.JSONDecodeError, OSError, ValueError) as e:
resp = json.dumps({"error": str(e)}).encode()
self.send_response(500)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(resp)))
self.end_headers()
self.wfile.write(resp)
else:
self.send_error(404)
def log_message(self, format: str, *args: object) -> None:
# Suppress request logging to keep terminal clean
pass
def main() -> None:
parser = argparse.ArgumentParser(description="Generate and serve eval review")
parser.add_argument("workspace", type=Path, help="Path to workspace directory")
parser.add_argument("--port", "-p", type=int, default=3117, help="Server port (default: 3117)")
parser.add_argument("--skill-name", "-n", type=str, default=None, help="Skill name for header")
parser.add_argument(
"--previous-workspace", type=Path, default=None,
help="Path to previous iteration's workspace (shows old outputs and feedback as context)",
)
parser.add_argument(
"--benchmark", type=Path, default=None,
help="Path to benchmark.json to show in the Benchmark tab",
)
parser.add_argument(
"--static", "-s", type=Path, default=None,
help="Write standalone HTML to this path instead of starting a server",
)
args = parser.parse_args()
workspace = args.workspace.resolve()
if not workspace.is_dir():
print(f"Error: {workspace} is not a directory", file=sys.stderr)
sys.exit(1)
runs = find_runs(workspace)
if not runs:
print(f"No runs found in {workspace}", file=sys.stderr)
sys.exit(1)
skill_name = args.skill_name or workspace.name.replace("-workspace", "")
feedback_path = workspace / "feedback.json"
previous: dict[str, dict] = {}
if args.previous_workspace:
previous = load_previous_iteration(args.previous_workspace.resolve())
benchmark_path = args.benchmark.resolve() if args.benchmark else None
benchmark = None
if benchmark_path and benchmark_path.exists():
try:
benchmark = json.loads(benchmark_path.read_text())
except (json.JSONDecodeError, OSError):
pass
if args.static:
html = generate_html(runs, skill_name, previous, benchmark)
args.static.parent.mkdir(parents=True, exist_ok=True)
args.static.write_text(html)
print(f"\n Static viewer written to: {args.static}\n")
sys.exit(0)
# Kill any existing process on the target port
port = args.port
_kill_port(port)
handler = partial(ReviewHandler, workspace, skill_name, feedback_path, previous, benchmark_path)
try:
server = HTTPServer(("127.0.0.1", port), handler)
except OSError:
# Port still in use after kill attempt — find a free one
server = HTTPServer(("127.0.0.1", 0), handler)
port = server.server_address[1]
url = f"http://localhost:{port}"
print(f"\n Eval Viewer")
print(f" ─────────────────────────────────")
print(f" URL: {url}")
print(f" Workspace: {workspace}")
print(f" Feedback: {feedback_path}")
if previous:
print(f" Previous: {args.previous_workspace} ({len(previous)} runs)")
if benchmark_path:
print(f" Benchmark: {benchmark_path}")
print(f"\n Press Ctrl+C to stop.\n")
webbrowser.open(url)
try:
server.serve_forever()
except KeyboardInterrupt:
print("\nStopped.")
server.server_close()
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,430 @@
# JSON Schemas
This document defines the JSON schemas used by skill-creator.
---
## evals.json
Defines the evals for a skill. Located at `evals/evals.json` within the skill directory.
```json
{
"skill_name": "example-skill",
"evals": [
{
"id": 1,
"prompt": "User's example prompt",
"expected_output": "Description of expected result",
"files": ["evals/files/sample1.pdf"],
"expectations": [
"The output includes X",
"The skill used script Y"
]
}
]
}
```
**Fields:**
- `skill_name`: Name matching the skill's frontmatter
- `evals[].id`: Unique integer identifier
- `evals[].prompt`: The task to execute
- `evals[].expected_output`: Human-readable description of success
- `evals[].files`: Optional list of input file paths (relative to skill root)
- `evals[].expectations`: List of verifiable statements
---
## history.json
Tracks version progression in Improve mode. Located at workspace root.
```json
{
"started_at": "2026-01-15T10:30:00Z",
"skill_name": "pdf",
"current_best": "v2",
"iterations": [
{
"version": "v0",
"parent": null,
"expectation_pass_rate": 0.65,
"grading_result": "baseline",
"is_current_best": false
},
{
"version": "v1",
"parent": "v0",
"expectation_pass_rate": 0.75,
"grading_result": "won",
"is_current_best": false
},
{
"version": "v2",
"parent": "v1",
"expectation_pass_rate": 0.85,
"grading_result": "won",
"is_current_best": true
}
]
}
```
**Fields:**
- `started_at`: ISO timestamp of when improvement started
- `skill_name`: Name of the skill being improved
- `current_best`: Version identifier of the best performer
- `iterations[].version`: Version identifier (v0, v1, ...)
- `iterations[].parent`: Parent version this was derived from
- `iterations[].expectation_pass_rate`: Pass rate from grading
- `iterations[].grading_result`: "baseline", "won", "lost", or "tie"
- `iterations[].is_current_best`: Whether this is the current best version
---
## grading.json
Output from the grader agent. Located at `<run-dir>/grading.json`.
```json
{
"expectations": [
{
"text": "The output includes the name 'John Smith'",
"passed": true,
"evidence": "Found in transcript Step 3: 'Extracted names: John Smith, Sarah Johnson'"
},
{
"text": "The spreadsheet has a SUM formula in cell B10",
"passed": false,
"evidence": "No spreadsheet was created. The output was a text file."
}
],
"summary": {
"passed": 2,
"failed": 1,
"total": 3,
"pass_rate": 0.67
},
"execution_metrics": {
"tool_calls": {
"Read": 5,
"Write": 2,
"Bash": 8
},
"total_tool_calls": 15,
"total_steps": 6,
"errors_encountered": 0,
"output_chars": 12450,
"transcript_chars": 3200
},
"timing": {
"executor_duration_seconds": 165.0,
"grader_duration_seconds": 26.0,
"total_duration_seconds": 191.0
},
"claims": [
{
"claim": "The form has 12 fillable fields",
"type": "factual",
"verified": true,
"evidence": "Counted 12 fields in field_info.json"
}
],
"user_notes_summary": {
"uncertainties": ["Used 2023 data, may be stale"],
"needs_review": [],
"workarounds": ["Fell back to text overlay for non-fillable fields"]
},
"eval_feedback": {
"suggestions": [
{
"assertion": "The output includes the name 'John Smith'",
"reason": "A hallucinated document that mentions the name would also pass"
}
],
"overall": "Assertions check presence but not correctness."
}
}
```
**Fields:**
- `expectations[]`: Graded expectations with evidence
- `summary`: Aggregate pass/fail counts
- `execution_metrics`: Tool usage and output size (from executor's metrics.json)
- `timing`: Wall clock timing (from timing.json)
- `claims`: Extracted and verified claims from the output
- `user_notes_summary`: Issues flagged by the executor
- `eval_feedback`: (optional) Improvement suggestions for the evals, only present when the grader identifies issues worth raising
---
## metrics.json
Output from the executor agent. Located at `<run-dir>/outputs/metrics.json`.
```json
{
"tool_calls": {
"Read": 5,
"Write": 2,
"Bash": 8,
"Edit": 1,
"Glob": 2,
"Grep": 0
},
"total_tool_calls": 18,
"total_steps": 6,
"files_created": ["filled_form.pdf", "field_values.json"],
"errors_encountered": 0,
"output_chars": 12450,
"transcript_chars": 3200
}
```
**Fields:**
- `tool_calls`: Count per tool type
- `total_tool_calls`: Sum of all tool calls
- `total_steps`: Number of major execution steps
- `files_created`: List of output files created
- `errors_encountered`: Number of errors during execution
- `output_chars`: Total character count of output files
- `transcript_chars`: Character count of transcript
---
## timing.json
Wall clock timing for a run. Located at `<run-dir>/timing.json`.
**How to capture:** When a subagent task completes, the task notification includes `total_tokens` and `duration_ms`. Save these immediately — they are not persisted anywhere else and cannot be recovered after the fact.
```json
{
"total_tokens": 84852,
"duration_ms": 23332,
"total_duration_seconds": 23.3,
"executor_start": "2026-01-15T10:30:00Z",
"executor_end": "2026-01-15T10:32:45Z",
"executor_duration_seconds": 165.0,
"grader_start": "2026-01-15T10:32:46Z",
"grader_end": "2026-01-15T10:33:12Z",
"grader_duration_seconds": 26.0
}
```
---
## benchmark.json
Output from Benchmark mode. Located at `benchmarks/<timestamp>/benchmark.json`.
```json
{
"metadata": {
"skill_name": "pdf",
"skill_path": "/path/to/pdf",
"executor_model": "claude-sonnet-4-20250514",
"analyzer_model": "most-capable-model",
"timestamp": "2026-01-15T10:30:00Z",
"evals_run": [1, 2, 3],
"runs_per_configuration": 3
},
"runs": [
{
"eval_id": 1,
"eval_name": "Ocean",
"configuration": "with_skill",
"run_number": 1,
"result": {
"pass_rate": 0.85,
"passed": 6,
"failed": 1,
"total": 7,
"time_seconds": 42.5,
"tokens": 3800,
"tool_calls": 18,
"errors": 0
},
"expectations": [
{"text": "...", "passed": true, "evidence": "..."}
],
"notes": [
"Used 2023 data, may be stale",
"Fell back to text overlay for non-fillable fields"
]
}
],
"run_summary": {
"with_skill": {
"pass_rate": {"mean": 0.85, "stddev": 0.05, "min": 0.80, "max": 0.90},
"time_seconds": {"mean": 45.0, "stddev": 12.0, "min": 32.0, "max": 58.0},
"tokens": {"mean": 3800, "stddev": 400, "min": 3200, "max": 4100}
},
"without_skill": {
"pass_rate": {"mean": 0.35, "stddev": 0.08, "min": 0.28, "max": 0.45},
"time_seconds": {"mean": 32.0, "stddev": 8.0, "min": 24.0, "max": 42.0},
"tokens": {"mean": 2100, "stddev": 300, "min": 1800, "max": 2500}
},
"delta": {
"pass_rate": "+0.50",
"time_seconds": "+13.0",
"tokens": "+1700"
}
},
"notes": [
"Assertion 'Output is a PDF file' passes 100% in both configurations - may not differentiate skill value",
"Eval 3 shows high variance (50% ± 40%) - may be flaky or model-dependent",
"Without-skill runs consistently fail on table extraction expectations",
"Skill adds 13s average execution time but improves pass rate by 50%"
]
}
```
**Fields:**
- `metadata`: Information about the benchmark run
- `skill_name`: Name of the skill
- `timestamp`: When the benchmark was run
- `evals_run`: List of eval names or IDs
- `runs_per_configuration`: Number of runs per config (e.g. 3)
- `runs[]`: Individual run results
- `eval_id`: Numeric eval identifier
- `eval_name`: Human-readable eval name (used as section header in the viewer)
- `configuration`: Must be `"with_skill"` or `"without_skill"` (the viewer uses this exact string for grouping and color coding)
- `run_number`: Integer run number (1, 2, 3...)
- `result`: Nested object with `pass_rate`, `passed`, `total`, `time_seconds`, `tokens`, `errors`
- `run_summary`: Statistical aggregates per configuration
- `with_skill` / `without_skill`: Each contains `pass_rate`, `time_seconds`, `tokens` objects with `mean` and `stddev` fields
- `delta`: Difference strings like `"+0.50"`, `"+13.0"`, `"+1700"`
- `notes`: Freeform observations from the analyzer
**Important:** The viewer reads these field names exactly. Using `config` instead of `configuration`, or putting `pass_rate` at the top level of a run instead of nested under `result`, will cause the viewer to show empty/zero values. Always reference this schema when generating benchmark.json manually.
---
## comparison.json
Output from blind comparator. Located at `<grading-dir>/comparison-N.json`.
```json
{
"winner": "A",
"reasoning": "Output A provides a complete solution with proper formatting and all required fields. Output B is missing the date field and has formatting inconsistencies.",
"rubric": {
"A": {
"content": {
"correctness": 5,
"completeness": 5,
"accuracy": 4
},
"structure": {
"organization": 4,
"formatting": 5,
"usability": 4
},
"content_score": 4.7,
"structure_score": 4.3,
"overall_score": 9.0
},
"B": {
"content": {
"correctness": 3,
"completeness": 2,
"accuracy": 3
},
"structure": {
"organization": 3,
"formatting": 2,
"usability": 3
},
"content_score": 2.7,
"structure_score": 2.7,
"overall_score": 5.4
}
},
"output_quality": {
"A": {
"score": 9,
"strengths": ["Complete solution", "Well-formatted", "All fields present"],
"weaknesses": ["Minor style inconsistency in header"]
},
"B": {
"score": 5,
"strengths": ["Readable output", "Correct basic structure"],
"weaknesses": ["Missing date field", "Formatting inconsistencies", "Partial data extraction"]
}
},
"expectation_results": {
"A": {
"passed": 4,
"total": 5,
"pass_rate": 0.80,
"details": [
{"text": "Output includes name", "passed": true}
]
},
"B": {
"passed": 3,
"total": 5,
"pass_rate": 0.60,
"details": [
{"text": "Output includes name", "passed": true}
]
}
}
}
```
---
## analysis.json
Output from post-hoc analyzer. Located at `<grading-dir>/analysis.json`.
```json
{
"comparison_summary": {
"winner": "A",
"winner_skill": "path/to/winner/skill",
"loser_skill": "path/to/loser/skill",
"comparator_reasoning": "Brief summary of why comparator chose winner"
},
"winner_strengths": [
"Clear step-by-step instructions for handling multi-page documents",
"Included validation script that caught formatting errors"
],
"loser_weaknesses": [
"Vague instruction 'process the document appropriately' led to inconsistent behavior",
"No script for validation, agent had to improvise"
],
"instruction_following": {
"winner": {
"score": 9,
"issues": ["Minor: skipped optional logging step"]
},
"loser": {
"score": 6,
"issues": [
"Did not use the skill's formatting template",
"Invented own approach instead of following step 3"
]
}
},
"improvement_suggestions": [
{
"priority": "high",
"category": "instructions",
"suggestion": "Replace 'process the document appropriately' with explicit steps",
"expected_impact": "Would eliminate ambiguity that caused inconsistent behavior"
}
],
"transcript_insights": {
"winner_execution_pattern": "Read skill -> Followed 5-step process -> Used validation script",
"loser_execution_pattern": "Read skill -> Unclear on approach -> Tried 3 different methods"
}
}
```

View file

@ -0,0 +1,401 @@
#!/usr/bin/env python3
"""
Aggregate individual run results into benchmark summary statistics.
Reads grading.json files from run directories and produces:
- run_summary with mean, stddev, min, max for each metric
- delta between with_skill and without_skill configurations
Usage:
python aggregate_benchmark.py <benchmark_dir>
Example:
python aggregate_benchmark.py benchmarks/2026-01-15T10-30-00/
The script supports two directory layouts:
Workspace layout (from skill-creator iterations):
<benchmark_dir>/
eval-N/
with_skill/
run-1/grading.json
run-2/grading.json
without_skill/
run-1/grading.json
run-2/grading.json
Legacy layout (with runs/ subdirectory):
<benchmark_dir>/
runs/
eval-N/
with_skill/
run-1/grading.json
without_skill/
run-1/grading.json
"""
import argparse
import json
import math
import sys
from datetime import datetime, timezone
from pathlib import Path
def calculate_stats(values: list[float]) -> dict:
"""Calculate mean, stddev, min, max for a list of values."""
if not values:
return {"mean": 0.0, "stddev": 0.0, "min": 0.0, "max": 0.0}
n = len(values)
mean = sum(values) / n
if n > 1:
variance = sum((x - mean) ** 2 for x in values) / (n - 1)
stddev = math.sqrt(variance)
else:
stddev = 0.0
return {
"mean": round(mean, 4),
"stddev": round(stddev, 4),
"min": round(min(values), 4),
"max": round(max(values), 4)
}
def load_run_results(benchmark_dir: Path) -> dict:
"""
Load all run results from a benchmark directory.
Returns dict keyed by config name (e.g. "with_skill"/"without_skill",
or "new_skill"/"old_skill"), each containing a list of run results.
"""
# Support both layouts: eval dirs directly under benchmark_dir, or under runs/
runs_dir = benchmark_dir / "runs"
if runs_dir.exists():
search_dir = runs_dir
elif list(benchmark_dir.glob("eval-*")):
search_dir = benchmark_dir
else:
print(f"No eval directories found in {benchmark_dir} or {benchmark_dir / 'runs'}")
return {}
results: dict[str, list] = {}
for eval_idx, eval_dir in enumerate(sorted(search_dir.glob("eval-*"))):
metadata_path = eval_dir / "eval_metadata.json"
if metadata_path.exists():
try:
with open(metadata_path) as mf:
eval_id = json.load(mf).get("eval_id", eval_idx)
except (json.JSONDecodeError, OSError):
eval_id = eval_idx
else:
try:
eval_id = int(eval_dir.name.split("-")[1])
except ValueError:
eval_id = eval_idx
# Discover config directories dynamically rather than hardcoding names
for config_dir in sorted(eval_dir.iterdir()):
if not config_dir.is_dir():
continue
# Skip non-config directories (inputs, outputs, etc.)
if not list(config_dir.glob("run-*")):
continue
config = config_dir.name
if config not in results:
results[config] = []
for run_dir in sorted(config_dir.glob("run-*")):
run_number = int(run_dir.name.split("-")[1])
grading_file = run_dir / "grading.json"
if not grading_file.exists():
print(f"Warning: grading.json not found in {run_dir}")
continue
try:
with open(grading_file) as f:
grading = json.load(f)
except json.JSONDecodeError as e:
print(f"Warning: Invalid JSON in {grading_file}: {e}")
continue
# Extract metrics
result = {
"eval_id": eval_id,
"run_number": run_number,
"pass_rate": grading.get("summary", {}).get("pass_rate", 0.0),
"passed": grading.get("summary", {}).get("passed", 0),
"failed": grading.get("summary", {}).get("failed", 0),
"total": grading.get("summary", {}).get("total", 0),
}
# Extract timing — check grading.json first, then sibling timing.json
timing = grading.get("timing", {})
result["time_seconds"] = timing.get("total_duration_seconds", 0.0)
timing_file = run_dir / "timing.json"
if result["time_seconds"] == 0.0 and timing_file.exists():
try:
with open(timing_file) as tf:
timing_data = json.load(tf)
result["time_seconds"] = timing_data.get("total_duration_seconds", 0.0)
result["tokens"] = timing_data.get("total_tokens", 0)
except json.JSONDecodeError:
pass
# Extract metrics if available
metrics = grading.get("execution_metrics", {})
result["tool_calls"] = metrics.get("total_tool_calls", 0)
if not result.get("tokens"):
result["tokens"] = metrics.get("output_chars", 0)
result["errors"] = metrics.get("errors_encountered", 0)
# Extract expectations — viewer requires fields: text, passed, evidence
raw_expectations = grading.get("expectations", [])
for exp in raw_expectations:
if "text" not in exp or "passed" not in exp:
print(f"Warning: expectation in {grading_file} missing required fields (text, passed, evidence): {exp}")
result["expectations"] = raw_expectations
# Extract notes from user_notes_summary
notes_summary = grading.get("user_notes_summary", {})
notes = []
notes.extend(notes_summary.get("uncertainties", []))
notes.extend(notes_summary.get("needs_review", []))
notes.extend(notes_summary.get("workarounds", []))
result["notes"] = notes
results[config].append(result)
return results
def aggregate_results(results: dict) -> dict:
"""
Aggregate run results into summary statistics.
Returns run_summary with stats for each configuration and delta.
"""
run_summary = {}
configs = list(results.keys())
for config in configs:
runs = results.get(config, [])
if not runs:
run_summary[config] = {
"pass_rate": {"mean": 0.0, "stddev": 0.0, "min": 0.0, "max": 0.0},
"time_seconds": {"mean": 0.0, "stddev": 0.0, "min": 0.0, "max": 0.0},
"tokens": {"mean": 0, "stddev": 0, "min": 0, "max": 0}
}
continue
pass_rates = [r["pass_rate"] for r in runs]
times = [r["time_seconds"] for r in runs]
tokens = [r.get("tokens", 0) for r in runs]
run_summary[config] = {
"pass_rate": calculate_stats(pass_rates),
"time_seconds": calculate_stats(times),
"tokens": calculate_stats(tokens)
}
# Calculate delta between the first two configs (if two exist)
if len(configs) >= 2:
primary = run_summary.get(configs[0], {})
baseline = run_summary.get(configs[1], {})
else:
primary = run_summary.get(configs[0], {}) if configs else {}
baseline = {}
delta_pass_rate = primary.get("pass_rate", {}).get("mean", 0) - baseline.get("pass_rate", {}).get("mean", 0)
delta_time = primary.get("time_seconds", {}).get("mean", 0) - baseline.get("time_seconds", {}).get("mean", 0)
delta_tokens = primary.get("tokens", {}).get("mean", 0) - baseline.get("tokens", {}).get("mean", 0)
run_summary["delta"] = {
"pass_rate": f"{delta_pass_rate:+.2f}",
"time_seconds": f"{delta_time:+.1f}",
"tokens": f"{delta_tokens:+.0f}"
}
return run_summary
def generate_benchmark(benchmark_dir: Path, skill_name: str = "", skill_path: str = "") -> dict:
"""
Generate complete benchmark.json from run results.
"""
results = load_run_results(benchmark_dir)
run_summary = aggregate_results(results)
# Build runs array for benchmark.json
runs = []
for config in results:
for result in results[config]:
runs.append({
"eval_id": result["eval_id"],
"configuration": config,
"run_number": result["run_number"],
"result": {
"pass_rate": result["pass_rate"],
"passed": result["passed"],
"failed": result["failed"],
"total": result["total"],
"time_seconds": result["time_seconds"],
"tokens": result.get("tokens", 0),
"tool_calls": result.get("tool_calls", 0),
"errors": result.get("errors", 0)
},
"expectations": result["expectations"],
"notes": result["notes"]
})
# Determine eval IDs from results
eval_ids = sorted(set(
r["eval_id"]
for config in results.values()
for r in config
))
benchmark = {
"metadata": {
"skill_name": skill_name or "<skill-name>",
"skill_path": skill_path or "<path/to/skill>",
"executor_model": "<model-name>",
"analyzer_model": "<model-name>",
"timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
"evals_run": eval_ids,
"runs_per_configuration": 3
},
"runs": runs,
"run_summary": run_summary,
"notes": [] # To be filled by analyzer
}
return benchmark
def generate_markdown(benchmark: dict) -> str:
"""Generate human-readable benchmark.md from benchmark data."""
metadata = benchmark["metadata"]
run_summary = benchmark["run_summary"]
# Determine config names (excluding "delta")
configs = [k for k in run_summary if k != "delta"]
config_a = configs[0] if len(configs) >= 1 else "config_a"
config_b = configs[1] if len(configs) >= 2 else "config_b"
label_a = config_a.replace("_", " ").title()
label_b = config_b.replace("_", " ").title()
lines = [
f"# Skill Benchmark: {metadata['skill_name']}",
"",
f"**Model**: {metadata['executor_model']}",
f"**Date**: {metadata['timestamp']}",
f"**Evals**: {', '.join(map(str, metadata['evals_run']))} ({metadata['runs_per_configuration']} runs each per configuration)",
"",
"## Summary",
"",
f"| Metric | {label_a} | {label_b} | Delta |",
"|--------|------------|---------------|-------|",
]
a_summary = run_summary.get(config_a, {})
b_summary = run_summary.get(config_b, {})
delta = run_summary.get("delta", {})
# Format pass rate
a_pr = a_summary.get("pass_rate", {})
b_pr = b_summary.get("pass_rate", {})
lines.append(f"| Pass Rate | {a_pr.get('mean', 0)*100:.0f}% ± {a_pr.get('stddev', 0)*100:.0f}% | {b_pr.get('mean', 0)*100:.0f}% ± {b_pr.get('stddev', 0)*100:.0f}% | {delta.get('pass_rate', '')} |")
# Format time
a_time = a_summary.get("time_seconds", {})
b_time = b_summary.get("time_seconds", {})
lines.append(f"| Time | {a_time.get('mean', 0):.1f}s ± {a_time.get('stddev', 0):.1f}s | {b_time.get('mean', 0):.1f}s ± {b_time.get('stddev', 0):.1f}s | {delta.get('time_seconds', '')}s |")
# Format tokens
a_tokens = a_summary.get("tokens", {})
b_tokens = b_summary.get("tokens", {})
lines.append(f"| Tokens | {a_tokens.get('mean', 0):.0f} ± {a_tokens.get('stddev', 0):.0f} | {b_tokens.get('mean', 0):.0f} ± {b_tokens.get('stddev', 0):.0f} | {delta.get('tokens', '')} |")
# Notes section
if benchmark.get("notes"):
lines.extend([
"",
"## Notes",
""
])
for note in benchmark["notes"]:
lines.append(f"- {note}")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(
description="Aggregate benchmark run results into summary statistics"
)
parser.add_argument(
"benchmark_dir",
type=Path,
help="Path to the benchmark directory"
)
parser.add_argument(
"--skill-name",
default="",
help="Name of the skill being benchmarked"
)
parser.add_argument(
"--skill-path",
default="",
help="Path to the skill being benchmarked"
)
parser.add_argument(
"--output", "-o",
type=Path,
help="Output path for benchmark.json (default: <benchmark_dir>/benchmark.json)"
)
args = parser.parse_args()
if not args.benchmark_dir.exists():
print(f"Directory not found: {args.benchmark_dir}")
sys.exit(1)
# Generate benchmark
benchmark = generate_benchmark(args.benchmark_dir, args.skill_name, args.skill_path)
# Determine output paths
output_json = args.output or (args.benchmark_dir / "benchmark.json")
output_md = output_json.with_suffix(".md")
# Write benchmark.json
with open(output_json, "w") as f:
json.dump(benchmark, f, indent=2)
print(f"Generated: {output_json}")
# Write benchmark.md
markdown = generate_markdown(benchmark)
with open(output_md, "w") as f:
f.write(markdown)
print(f"Generated: {output_md}")
# Print summary
run_summary = benchmark["run_summary"]
configs = [k for k in run_summary if k != "delta"]
delta = run_summary.get("delta", {})
print(f"\nSummary:")
for config in configs:
pr = run_summary[config]["pass_rate"]["mean"]
label = config.replace("_", " ").title()
print(f" {label}: {pr*100:.1f}% pass rate")
print(f" Delta: {delta.get('pass_rate', '')}")
if __name__ == "__main__":
main()

View file

@ -0,0 +1,326 @@
#!/usr/bin/env python3
"""Generate an HTML report from run_loop.py output.
Takes the JSON output from run_loop.py and generates a visual HTML report
showing each description attempt with check/x for each test case.
Distinguishes between train and test queries.
"""
import argparse
import html
import json
import sys
from pathlib import Path
def generate_html(data: dict, auto_refresh: bool = False, skill_name: str = "") -> str:
"""Generate HTML report from loop output data. If auto_refresh is True, adds a meta refresh tag."""
history = data.get("history", [])
holdout = data.get("holdout", 0)
title_prefix = html.escape(skill_name + " \u2014 ") if skill_name else ""
# Get all unique queries from train and test sets, with should_trigger info
train_queries: list[dict] = []
test_queries: list[dict] = []
if history:
for r in history[0].get("train_results", history[0].get("results", [])):
train_queries.append({"query": r["query"], "should_trigger": r.get("should_trigger", True)})
if history[0].get("test_results"):
for r in history[0].get("test_results", []):
test_queries.append({"query": r["query"], "should_trigger": r.get("should_trigger", True)})
refresh_tag = ' <meta http-equiv="refresh" content="5">\n' if auto_refresh else ""
html_parts = ["""<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
""" + refresh_tag + """ <title>""" + title_prefix + """Skill Description Optimization</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@500;600&family=Lora:wght@400;500&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Lora', Georgia, serif;
max-width: 100%;
margin: 0 auto;
padding: 20px;
background: #faf9f5;
color: #141413;
}
h1 { font-family: 'Poppins', sans-serif; color: #141413; }
.explainer {
background: white;
padding: 15px;
border-radius: 6px;
margin-bottom: 20px;
border: 1px solid #e8e6dc;
color: #b0aea5;
font-size: 0.875rem;
line-height: 1.6;
}
.summary {
background: white;
padding: 15px;
border-radius: 6px;
margin-bottom: 20px;
border: 1px solid #e8e6dc;
}
.summary p { margin: 5px 0; }
.best { color: #788c5d; font-weight: bold; }
.table-container {
overflow-x: auto;
width: 100%;
}
table {
border-collapse: collapse;
background: white;
border: 1px solid #e8e6dc;
border-radius: 6px;
font-size: 12px;
min-width: 100%;
}
th, td {
padding: 8px;
text-align: left;
border: 1px solid #e8e6dc;
white-space: normal;
word-wrap: break-word;
}
th {
font-family: 'Poppins', sans-serif;
background: #141413;
color: #faf9f5;
font-weight: 500;
}
th.test-col {
background: #6a9bcc;
}
th.query-col { min-width: 200px; }
td.description {
font-family: monospace;
font-size: 11px;
word-wrap: break-word;
max-width: 400px;
}
td.result {
text-align: center;
font-size: 16px;
min-width: 40px;
}
td.test-result {
background: #f0f6fc;
}
.pass { color: #788c5d; }
.fail { color: #c44; }
.rate {
font-size: 9px;
color: #b0aea5;
display: block;
}
tr:hover { background: #faf9f5; }
.score {
display: inline-block;
padding: 2px 6px;
border-radius: 4px;
font-weight: bold;
font-size: 11px;
}
.score-good { background: #eef2e8; color: #788c5d; }
.score-ok { background: #fef3c7; color: #d97706; }
.score-bad { background: #fceaea; color: #c44; }
.train-label { color: #b0aea5; font-size: 10px; }
.test-label { color: #6a9bcc; font-size: 10px; font-weight: bold; }
.best-row { background: #f5f8f2; }
th.positive-col { border-bottom: 3px solid #788c5d; }
th.negative-col { border-bottom: 3px solid #c44; }
th.test-col.positive-col { border-bottom: 3px solid #788c5d; }
th.test-col.negative-col { border-bottom: 3px solid #c44; }
.legend { font-family: 'Poppins', sans-serif; display: flex; gap: 20px; margin-bottom: 10px; font-size: 13px; align-items: center; }
.legend-item { display: flex; align-items: center; gap: 6px; }
.legend-swatch { width: 16px; height: 16px; border-radius: 3px; display: inline-block; }
.swatch-positive { background: #141413; border-bottom: 3px solid #788c5d; }
.swatch-negative { background: #141413; border-bottom: 3px solid #c44; }
.swatch-test { background: #6a9bcc; }
.swatch-train { background: #141413; }
</style>
</head>
<body>
<h1>""" + title_prefix + """Skill Description Optimization</h1>
<div class="explainer">
<strong>Optimizing your skill's description.</strong> This page updates automatically as Claude tests different versions of your skill's description. Each row is an iteration a new description attempt. The columns show test queries: green checkmarks mean the skill triggered correctly (or correctly didn't trigger), red crosses mean it got it wrong. The "Train" score shows performance on queries used to improve the description; the "Test" score shows performance on held-out queries the optimizer hasn't seen. When it's done, Claude will apply the best-performing description to your skill.
</div>
"""]
# Summary section
best_test_score = data.get('best_test_score')
best_train_score = data.get('best_train_score')
html_parts.append(f"""
<div class="summary">
<p><strong>Original:</strong> {html.escape(data.get('original_description', 'N/A'))}</p>
<p class="best"><strong>Best:</strong> {html.escape(data.get('best_description', 'N/A'))}</p>
<p><strong>Best Score:</strong> {data.get('best_score', 'N/A')} {'(test)' if best_test_score else '(train)'}</p>
<p><strong>Iterations:</strong> {data.get('iterations_run', 0)} | <strong>Train:</strong> {data.get('train_size', '?')} | <strong>Test:</strong> {data.get('test_size', '?')}</p>
</div>
""")
# Legend
html_parts.append("""
<div class="legend">
<span style="font-weight:600">Query columns:</span>
<span class="legend-item"><span class="legend-swatch swatch-positive"></span> Should trigger</span>
<span class="legend-item"><span class="legend-swatch swatch-negative"></span> Should NOT trigger</span>
<span class="legend-item"><span class="legend-swatch swatch-train"></span> Train</span>
<span class="legend-item"><span class="legend-swatch swatch-test"></span> Test</span>
</div>
""")
# Table header
html_parts.append("""
<div class="table-container">
<table>
<thead>
<tr>
<th>Iter</th>
<th>Train</th>
<th>Test</th>
<th class="query-col">Description</th>
""")
# Add column headers for train queries
for qinfo in train_queries:
polarity = "positive-col" if qinfo["should_trigger"] else "negative-col"
html_parts.append(f' <th class="{polarity}">{html.escape(qinfo["query"])}</th>\n')
# Add column headers for test queries (different color)
for qinfo in test_queries:
polarity = "positive-col" if qinfo["should_trigger"] else "negative-col"
html_parts.append(f' <th class="test-col {polarity}">{html.escape(qinfo["query"])}</th>\n')
html_parts.append(""" </tr>
</thead>
<tbody>
""")
# Find best iteration for highlighting
if test_queries:
best_iter = max(history, key=lambda h: h.get("test_passed") or 0).get("iteration")
else:
best_iter = max(history, key=lambda h: h.get("train_passed", h.get("passed", 0))).get("iteration")
# Add rows for each iteration
for h in history:
iteration = h.get("iteration", "?")
train_passed = h.get("train_passed", h.get("passed", 0))
train_total = h.get("train_total", h.get("total", 0))
test_passed = h.get("test_passed")
test_total = h.get("test_total")
description = h.get("description", "")
train_results = h.get("train_results", h.get("results", []))
test_results = h.get("test_results", [])
# Create lookups for results by query
train_by_query = {r["query"]: r for r in train_results}
test_by_query = {r["query"]: r for r in test_results} if test_results else {}
# Compute aggregate correct/total runs across all retries
def aggregate_runs(results: list[dict]) -> tuple[int, int]:
correct = 0
total = 0
for r in results:
runs = r.get("runs", 0)
triggers = r.get("triggers", 0)
total += runs
if r.get("should_trigger", True):
correct += triggers
else:
correct += runs - triggers
return correct, total
train_correct, train_runs = aggregate_runs(train_results)
test_correct, test_runs = aggregate_runs(test_results)
# Determine score classes
def score_class(correct: int, total: int) -> str:
if total > 0:
ratio = correct / total
if ratio >= 0.8:
return "score-good"
elif ratio >= 0.5:
return "score-ok"
return "score-bad"
train_class = score_class(train_correct, train_runs)
test_class = score_class(test_correct, test_runs)
row_class = "best-row" if iteration == best_iter else ""
html_parts.append(f""" <tr class="{row_class}">
<td>{iteration}</td>
<td><span class="score {train_class}">{train_correct}/{train_runs}</span></td>
<td><span class="score {test_class}">{test_correct}/{test_runs}</span></td>
<td class="description">{html.escape(description)}</td>
""")
# Add result for each train query
for qinfo in train_queries:
r = train_by_query.get(qinfo["query"], {})
did_pass = r.get("pass", False)
triggers = r.get("triggers", 0)
runs = r.get("runs", 0)
icon = "" if did_pass else ""
css_class = "pass" if did_pass else "fail"
html_parts.append(f' <td class="result {css_class}">{icon}<span class="rate">{triggers}/{runs}</span></td>\n')
# Add result for each test query (with different background)
for qinfo in test_queries:
r = test_by_query.get(qinfo["query"], {})
did_pass = r.get("pass", False)
triggers = r.get("triggers", 0)
runs = r.get("runs", 0)
icon = "" if did_pass else ""
css_class = "pass" if did_pass else "fail"
html_parts.append(f' <td class="result test-result {css_class}">{icon}<span class="rate">{triggers}/{runs}</span></td>\n')
html_parts.append(" </tr>\n")
html_parts.append(""" </tbody>
</table>
</div>
""")
html_parts.append("""
</body>
</html>
""")
return "".join(html_parts)
def main():
parser = argparse.ArgumentParser(description="Generate HTML report from run_loop output")
parser.add_argument("input", help="Path to JSON output from run_loop.py (or - for stdin)")
parser.add_argument("-o", "--output", default=None, help="Output HTML file (default: stdout)")
parser.add_argument("--skill-name", default="", help="Skill name to include in the report title")
args = parser.parse_args()
if args.input == "-":
data = json.load(sys.stdin)
else:
data = json.loads(Path(args.input).read_text())
html_output = generate_html(data, skill_name=args.skill_name)
if args.output:
Path(args.output).write_text(html_output)
print(f"Report written to {args.output}", file=sys.stderr)
else:
print(html_output)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,248 @@
#!/usr/bin/env python3
"""Improve a skill description based on eval results.
Takes eval results (from run_eval.py) and generates an improved description
using Claude with extended thinking.
"""
import argparse
import json
import re
import sys
from pathlib import Path
import anthropic
from scripts.utils import parse_skill_md
def improve_description(
client: anthropic.Anthropic,
skill_name: str,
skill_content: str,
current_description: str,
eval_results: dict,
history: list[dict],
model: str,
test_results: dict | None = None,
log_dir: Path | None = None,
iteration: int | None = None,
) -> str:
"""Call Claude to improve the description based on eval results."""
failed_triggers = [
r for r in eval_results["results"]
if r["should_trigger"] and not r["pass"]
]
false_triggers = [
r for r in eval_results["results"]
if not r["should_trigger"] and not r["pass"]
]
# Build scores summary
train_score = f"{eval_results['summary']['passed']}/{eval_results['summary']['total']}"
if test_results:
test_score = f"{test_results['summary']['passed']}/{test_results['summary']['total']}"
scores_summary = f"Train: {train_score}, Test: {test_score}"
else:
scores_summary = f"Train: {train_score}"
prompt = f"""You are optimizing a skill description for a Claude Code skill called "{skill_name}". A "skill" is sort of like a prompt, but with progressive disclosure -- there's a title and description that Claude sees when deciding whether to use the skill, and then if it does use the skill, it reads the .md file which has lots more details and potentially links to other resources in the skill folder like helper files and scripts and additional documentation or examples.
The description appears in Claude's "available_skills" list. When a user sends a query, Claude decides whether to invoke the skill based solely on the title and on this description. Your goal is to write a description that triggers for relevant queries, and doesn't trigger for irrelevant ones.
Here's the current description:
<current_description>
"{current_description}"
</current_description>
Current scores ({scores_summary}):
<scores_summary>
"""
if failed_triggers:
prompt += "FAILED TO TRIGGER (should have triggered but didn't):\n"
for r in failed_triggers:
prompt += f' - "{r["query"]}" (triggered {r["triggers"]}/{r["runs"]} times)\n'
prompt += "\n"
if false_triggers:
prompt += "FALSE TRIGGERS (triggered but shouldn't have):\n"
for r in false_triggers:
prompt += f' - "{r["query"]}" (triggered {r["triggers"]}/{r["runs"]} times)\n'
prompt += "\n"
if history:
prompt += "PREVIOUS ATTEMPTS (do NOT repeat these — try something structurally different):\n\n"
for h in history:
train_s = f"{h.get('train_passed', h.get('passed', 0))}/{h.get('train_total', h.get('total', 0))}"
test_s = f"{h.get('test_passed', '?')}/{h.get('test_total', '?')}" if h.get('test_passed') is not None else None
score_str = f"train={train_s}" + (f", test={test_s}" if test_s else "")
prompt += f'<attempt {score_str}>\n'
prompt += f'Description: "{h["description"]}"\n'
if "results" in h:
prompt += "Train results:\n"
for r in h["results"]:
status = "PASS" if r["pass"] else "FAIL"
prompt += f' [{status}] "{r["query"][:80]}" (triggered {r["triggers"]}/{r["runs"]})\n'
if h.get("note"):
prompt += f'Note: {h["note"]}\n'
prompt += "</attempt>\n\n"
prompt += f"""</scores_summary>
Skill content (for context on what the skill does):
<skill_content>
{skill_content}
</skill_content>
Based on the failures, write a new and improved description that is more likely to trigger correctly. When I say "based on the failures", it's a bit of a tricky line to walk because we don't want to overfit to the specific cases you're seeing. So what I DON'T want you to do is produce an ever-expanding list of specific queries that this skill should or shouldn't trigger for. Instead, try to generalize from the failures to broader categories of user intent and situations where this skill would be useful or not useful. The reason for this is twofold:
1. Avoid overfitting
2. The list might get loooong and it's injected into ALL queries and there might be a lot of skills, so we don't want to blow too much space on any given description.
Concretely, your description should not be more than about 100-200 words, even if that comes at the cost of accuracy.
Here are some tips that we've found to work well in writing these descriptions:
- The skill should be phrased in the imperative -- "Use this skill for" rather than "this skill does"
- The skill description should focus on the user's intent, what they are trying to achieve, vs. the implementation details of how the skill works.
- The description competes with other skills for Claude's attention — make it distinctive and immediately recognizable.
- If you're getting lots of failures after repeated attempts, change things up. Try different sentence structures or wordings.
I'd encourage you to be creative and mix up the style in different iterations since you'll have multiple opportunities to try different approaches and we'll just grab the highest-scoring one at the end.
Please respond with only the new description text in <new_description> tags, nothing else."""
response = client.messages.create(
model=model,
max_tokens=16000,
thinking={
"type": "enabled",
"budget_tokens": 10000,
},
messages=[{"role": "user", "content": prompt}],
)
# Extract thinking and text from response
thinking_text = ""
text = ""
for block in response.content:
if block.type == "thinking":
thinking_text = block.thinking
elif block.type == "text":
text = block.text
# Parse out the <new_description> tags
match = re.search(r"<new_description>(.*?)</new_description>", text, re.DOTALL)
description = match.group(1).strip().strip('"') if match else text.strip().strip('"')
# Log the transcript
transcript: dict = {
"iteration": iteration,
"prompt": prompt,
"thinking": thinking_text,
"response": text,
"parsed_description": description,
"char_count": len(description),
"over_limit": len(description) > 1024,
}
# If over 1024 chars, ask the model to shorten it
if len(description) > 1024:
shorten_prompt = f"Your description is {len(description)} characters, which exceeds the hard 1024 character limit. Please rewrite it to be under 1024 characters while preserving the most important trigger words and intent coverage. Respond with only the new description in <new_description> tags."
shorten_response = client.messages.create(
model=model,
max_tokens=16000,
thinking={
"type": "enabled",
"budget_tokens": 10000,
},
messages=[
{"role": "user", "content": prompt},
{"role": "assistant", "content": text},
{"role": "user", "content": shorten_prompt},
],
)
shorten_thinking = ""
shorten_text = ""
for block in shorten_response.content:
if block.type == "thinking":
shorten_thinking = block.thinking
elif block.type == "text":
shorten_text = block.text
match = re.search(r"<new_description>(.*?)</new_description>", shorten_text, re.DOTALL)
shortened = match.group(1).strip().strip('"') if match else shorten_text.strip().strip('"')
transcript["rewrite_prompt"] = shorten_prompt
transcript["rewrite_thinking"] = shorten_thinking
transcript["rewrite_response"] = shorten_text
transcript["rewrite_description"] = shortened
transcript["rewrite_char_count"] = len(shortened)
description = shortened
transcript["final_description"] = description
if log_dir:
log_dir.mkdir(parents=True, exist_ok=True)
log_file = log_dir / f"improve_iter_{iteration or 'unknown'}.json"
log_file.write_text(json.dumps(transcript, indent=2))
return description
def main():
parser = argparse.ArgumentParser(description="Improve a skill description based on eval results")
parser.add_argument("--eval-results", required=True, help="Path to eval results JSON (from run_eval.py)")
parser.add_argument("--skill-path", required=True, help="Path to skill directory")
parser.add_argument("--history", default=None, help="Path to history JSON (previous attempts)")
parser.add_argument("--model", required=True, help="Model for improvement")
parser.add_argument("--verbose", action="store_true", help="Print thinking to stderr")
args = parser.parse_args()
skill_path = Path(args.skill_path)
if not (skill_path / "SKILL.md").exists():
print(f"Error: No SKILL.md found at {skill_path}", file=sys.stderr)
sys.exit(1)
eval_results = json.loads(Path(args.eval_results).read_text())
history = []
if args.history:
history = json.loads(Path(args.history).read_text())
name, _, content = parse_skill_md(skill_path)
current_description = eval_results["description"]
if args.verbose:
print(f"Current: {current_description}", file=sys.stderr)
print(f"Score: {eval_results['summary']['passed']}/{eval_results['summary']['total']}", file=sys.stderr)
client = anthropic.Anthropic()
new_description = improve_description(
client=client,
skill_name=name,
skill_content=content,
current_description=current_description,
eval_results=eval_results,
history=history,
model=args.model,
)
if args.verbose:
print(f"Improved: {new_description}", file=sys.stderr)
# Output as JSON with both the new description and updated history
output = {
"description": new_description,
"history": history + [{
"description": current_description,
"passed": eval_results["summary"]["passed"],
"failed": eval_results["summary"]["failed"],
"total": eval_results["summary"]["total"],
"results": eval_results["results"],
}],
}
print(json.dumps(output, indent=2))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,136 @@
#!/usr/bin/env python3
"""
Skill Packager - Creates a distributable .skill file of a skill folder
Usage:
python utils/package_skill.py <path/to/skill-folder> [output-directory]
Example:
python utils/package_skill.py skills/public/my-skill
python utils/package_skill.py skills/public/my-skill ./dist
"""
import fnmatch
import sys
import zipfile
from pathlib import Path
from scripts.quick_validate import validate_skill
# Patterns to exclude when packaging skills.
EXCLUDE_DIRS = {"__pycache__", "node_modules"}
EXCLUDE_GLOBS = {"*.pyc"}
EXCLUDE_FILES = {".DS_Store"}
# Directories excluded only at the skill root (not when nested deeper).
ROOT_EXCLUDE_DIRS = {"evals"}
def should_exclude(rel_path: Path) -> bool:
"""Check if a path should be excluded from packaging."""
parts = rel_path.parts
if any(part in EXCLUDE_DIRS for part in parts):
return True
# rel_path is relative to skill_path.parent, so parts[0] is the skill
# folder name and parts[1] (if present) is the first subdir.
if len(parts) > 1 and parts[1] in ROOT_EXCLUDE_DIRS:
return True
name = rel_path.name
if name in EXCLUDE_FILES:
return True
return any(fnmatch.fnmatch(name, pat) for pat in EXCLUDE_GLOBS)
def package_skill(skill_path, output_dir=None):
"""
Package a skill folder into a .skill file.
Args:
skill_path: Path to the skill folder
output_dir: Optional output directory for the .skill file (defaults to current directory)
Returns:
Path to the created .skill file, or None if error
"""
skill_path = Path(skill_path).resolve()
# Validate skill folder exists
if not skill_path.exists():
print(f"❌ Error: Skill folder not found: {skill_path}")
return None
if not skill_path.is_dir():
print(f"❌ Error: Path is not a directory: {skill_path}")
return None
# Validate SKILL.md exists
skill_md = skill_path / "SKILL.md"
if not skill_md.exists():
print(f"❌ Error: SKILL.md not found in {skill_path}")
return None
# Run validation before packaging
print("🔍 Validating skill...")
valid, message = validate_skill(skill_path)
if not valid:
print(f"❌ Validation failed: {message}")
print(" Please fix the validation errors before packaging.")
return None
print(f"{message}\n")
# Determine output location
skill_name = skill_path.name
if output_dir:
output_path = Path(output_dir).resolve()
output_path.mkdir(parents=True, exist_ok=True)
else:
output_path = Path.cwd()
skill_filename = output_path / f"{skill_name}.skill"
# Create the .skill file (zip format)
try:
with zipfile.ZipFile(skill_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
# Walk through the skill directory, excluding build artifacts
for file_path in skill_path.rglob('*'):
if not file_path.is_file():
continue
arcname = file_path.relative_to(skill_path.parent)
if should_exclude(arcname):
print(f" Skipped: {arcname}")
continue
zipf.write(file_path, arcname)
print(f" Added: {arcname}")
print(f"\n✅ Successfully packaged skill to: {skill_filename}")
return skill_filename
except Exception as e:
print(f"❌ Error creating .skill file: {e}")
return None
def main():
if len(sys.argv) < 2:
print("Usage: python utils/package_skill.py <path/to/skill-folder> [output-directory]")
print("\nExample:")
print(" python utils/package_skill.py skills/public/my-skill")
print(" python utils/package_skill.py skills/public/my-skill ./dist")
sys.exit(1)
skill_path = sys.argv[1]
output_dir = sys.argv[2] if len(sys.argv) > 2 else None
print(f"📦 Packaging skill: {skill_path}")
if output_dir:
print(f" Output directory: {output_dir}")
print()
result = package_skill(skill_path, output_dir)
if result:
sys.exit(0)
else:
sys.exit(1)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,103 @@
#!/usr/bin/env python3
"""
Quick validation script for skills - minimal version
"""
import sys
import os
import re
import yaml
from pathlib import Path
def validate_skill(skill_path):
"""Basic validation of a skill"""
skill_path = Path(skill_path)
# Check SKILL.md exists
skill_md = skill_path / 'SKILL.md'
if not skill_md.exists():
return False, "SKILL.md not found"
# Read and validate frontmatter
content = skill_md.read_text()
if not content.startswith('---'):
return False, "No YAML frontmatter found"
# Extract frontmatter
match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
if not match:
return False, "Invalid frontmatter format"
frontmatter_text = match.group(1)
# Parse YAML frontmatter
try:
frontmatter = yaml.safe_load(frontmatter_text)
if not isinstance(frontmatter, dict):
return False, "Frontmatter must be a YAML dictionary"
except yaml.YAMLError as e:
return False, f"Invalid YAML in frontmatter: {e}"
# Define allowed properties
ALLOWED_PROPERTIES = {'name', 'description', 'license', 'allowed-tools', 'metadata', 'compatibility'}
# Check for unexpected properties (excluding nested keys under metadata)
unexpected_keys = set(frontmatter.keys()) - ALLOWED_PROPERTIES
if unexpected_keys:
return False, (
f"Unexpected key(s) in SKILL.md frontmatter: {', '.join(sorted(unexpected_keys))}. "
f"Allowed properties are: {', '.join(sorted(ALLOWED_PROPERTIES))}"
)
# Check required fields
if 'name' not in frontmatter:
return False, "Missing 'name' in frontmatter"
if 'description' not in frontmatter:
return False, "Missing 'description' in frontmatter"
# Extract name for validation
name = frontmatter.get('name', '')
if not isinstance(name, str):
return False, f"Name must be a string, got {type(name).__name__}"
name = name.strip()
if name:
# Check naming convention (kebab-case: lowercase with hyphens)
if not re.match(r'^[a-z0-9-]+$', name):
return False, f"Name '{name}' should be kebab-case (lowercase letters, digits, and hyphens only)"
if name.startswith('-') or name.endswith('-') or '--' in name:
return False, f"Name '{name}' cannot start/end with hyphen or contain consecutive hyphens"
# Check name length (max 64 characters per spec)
if len(name) > 64:
return False, f"Name is too long ({len(name)} characters). Maximum is 64 characters."
# Extract and validate description
description = frontmatter.get('description', '')
if not isinstance(description, str):
return False, f"Description must be a string, got {type(description).__name__}"
description = description.strip()
if description:
# Check for angle brackets
if '<' in description or '>' in description:
return False, "Description cannot contain angle brackets (< or >)"
# Check description length (max 1024 characters per spec)
if len(description) > 1024:
return False, f"Description is too long ({len(description)} characters). Maximum is 1024 characters."
# Validate compatibility field if present (optional)
compatibility = frontmatter.get('compatibility', '')
if compatibility:
if not isinstance(compatibility, str):
return False, f"Compatibility must be a string, got {type(compatibility).__name__}"
if len(compatibility) > 500:
return False, f"Compatibility is too long ({len(compatibility)} characters). Maximum is 500 characters."
return True, "Skill is valid!"
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python quick_validate.py <skill_directory>")
sys.exit(1)
valid, message = validate_skill(sys.argv[1])
print(message)
sys.exit(0 if valid else 1)

View file

@ -0,0 +1,310 @@
#!/usr/bin/env python3
"""Run trigger evaluation for a skill description.
Tests whether a skill's description causes Claude to trigger (read the skill)
for a set of queries. Outputs results as JSON.
"""
import argparse
import json
import os
import select
import subprocess
import sys
import time
import uuid
from concurrent.futures import ProcessPoolExecutor, as_completed
from pathlib import Path
from scripts.utils import parse_skill_md
def find_project_root() -> Path:
"""Find the project root by walking up from cwd looking for .claude/.
Mimics how Claude Code discovers its project root, so the command file
we create ends up where claude -p will look for it.
"""
current = Path.cwd()
for parent in [current, *current.parents]:
if (parent / ".claude").is_dir():
return parent
return current
def run_single_query(
query: str,
skill_name: str,
skill_description: str,
timeout: int,
project_root: str,
model: str | None = None,
) -> bool:
"""Run a single query and return whether the skill was triggered.
Creates a command file in .claude/commands/ so it appears in Claude's
available_skills list, then runs `claude -p` with the raw query.
Uses --include-partial-messages to detect triggering early from
stream events (content_block_start) rather than waiting for the
full assistant message, which only arrives after tool execution.
"""
unique_id = uuid.uuid4().hex[:8]
clean_name = f"{skill_name}-skill-{unique_id}"
project_commands_dir = Path(project_root) / ".claude" / "commands"
command_file = project_commands_dir / f"{clean_name}.md"
try:
project_commands_dir.mkdir(parents=True, exist_ok=True)
# Use YAML block scalar to avoid breaking on quotes in description
indented_desc = "\n ".join(skill_description.split("\n"))
command_content = (
f"---\n"
f"description: |\n"
f" {indented_desc}\n"
f"---\n\n"
f"# {skill_name}\n\n"
f"This skill handles: {skill_description}\n"
)
command_file.write_text(command_content)
cmd = [
"claude",
"-p", query,
"--output-format", "stream-json",
"--verbose",
"--include-partial-messages",
]
if model:
cmd.extend(["--model", model])
# Remove CLAUDECODE env var to allow nesting claude -p inside a
# Claude Code session. The guard is for interactive terminal conflicts;
# programmatic subprocess usage is safe.
env = {k: v for k, v in os.environ.items() if k != "CLAUDECODE"}
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
cwd=project_root,
env=env,
)
triggered = False
start_time = time.time()
buffer = ""
# Track state for stream event detection
pending_tool_name = None
accumulated_json = ""
try:
while time.time() - start_time < timeout:
if process.poll() is not None:
remaining = process.stdout.read()
if remaining:
buffer += remaining.decode("utf-8", errors="replace")
break
ready, _, _ = select.select([process.stdout], [], [], 1.0)
if not ready:
continue
chunk = os.read(process.stdout.fileno(), 8192)
if not chunk:
break
buffer += chunk.decode("utf-8", errors="replace")
while "\n" in buffer:
line, buffer = buffer.split("\n", 1)
line = line.strip()
if not line:
continue
try:
event = json.loads(line)
except json.JSONDecodeError:
continue
# Early detection via stream events
if event.get("type") == "stream_event":
se = event.get("event", {})
se_type = se.get("type", "")
if se_type == "content_block_start":
cb = se.get("content_block", {})
if cb.get("type") == "tool_use":
tool_name = cb.get("name", "")
if tool_name in ("Skill", "Read"):
pending_tool_name = tool_name
accumulated_json = ""
else:
return False
elif se_type == "content_block_delta" and pending_tool_name:
delta = se.get("delta", {})
if delta.get("type") == "input_json_delta":
accumulated_json += delta.get("partial_json", "")
if clean_name in accumulated_json:
return True
elif se_type in ("content_block_stop", "message_stop"):
if pending_tool_name:
return clean_name in accumulated_json
if se_type == "message_stop":
return False
# Fallback: full assistant message
elif event.get("type") == "assistant":
message = event.get("message", {})
for content_item in message.get("content", []):
if content_item.get("type") != "tool_use":
continue
tool_name = content_item.get("name", "")
tool_input = content_item.get("input", {})
if tool_name == "Skill" and clean_name in tool_input.get("skill", ""):
triggered = True
elif tool_name == "Read" and clean_name in tool_input.get("file_path", ""):
triggered = True
return triggered
elif event.get("type") == "result":
return triggered
finally:
# Clean up process on any exit path (return, exception, timeout)
if process.poll() is None:
process.kill()
process.wait()
return triggered
finally:
if command_file.exists():
command_file.unlink()
def run_eval(
eval_set: list[dict],
skill_name: str,
description: str,
num_workers: int,
timeout: int,
project_root: Path,
runs_per_query: int = 1,
trigger_threshold: float = 0.5,
model: str | None = None,
) -> dict:
"""Run the full eval set and return results."""
results = []
with ProcessPoolExecutor(max_workers=num_workers) as executor:
future_to_info = {}
for item in eval_set:
for run_idx in range(runs_per_query):
future = executor.submit(
run_single_query,
item["query"],
skill_name,
description,
timeout,
str(project_root),
model,
)
future_to_info[future] = (item, run_idx)
query_triggers: dict[str, list[bool]] = {}
query_items: dict[str, dict] = {}
for future in as_completed(future_to_info):
item, _ = future_to_info[future]
query = item["query"]
query_items[query] = item
if query not in query_triggers:
query_triggers[query] = []
try:
query_triggers[query].append(future.result())
except Exception as e:
print(f"Warning: query failed: {e}", file=sys.stderr)
query_triggers[query].append(False)
for query, triggers in query_triggers.items():
item = query_items[query]
trigger_rate = sum(triggers) / len(triggers)
should_trigger = item["should_trigger"]
if should_trigger:
did_pass = trigger_rate >= trigger_threshold
else:
did_pass = trigger_rate < trigger_threshold
results.append({
"query": query,
"should_trigger": should_trigger,
"trigger_rate": trigger_rate,
"triggers": sum(triggers),
"runs": len(triggers),
"pass": did_pass,
})
passed = sum(1 for r in results if r["pass"])
total = len(results)
return {
"skill_name": skill_name,
"description": description,
"results": results,
"summary": {
"total": total,
"passed": passed,
"failed": total - passed,
},
}
def main():
parser = argparse.ArgumentParser(description="Run trigger evaluation for a skill description")
parser.add_argument("--eval-set", required=True, help="Path to eval set JSON file")
parser.add_argument("--skill-path", required=True, help="Path to skill directory")
parser.add_argument("--description", default=None, help="Override description to test")
parser.add_argument("--num-workers", type=int, default=10, help="Number of parallel workers")
parser.add_argument("--timeout", type=int, default=30, help="Timeout per query in seconds")
parser.add_argument("--runs-per-query", type=int, default=3, help="Number of runs per query")
parser.add_argument("--trigger-threshold", type=float, default=0.5, help="Trigger rate threshold")
parser.add_argument("--model", default=None, help="Model to use for claude -p (default: user's configured model)")
parser.add_argument("--verbose", action="store_true", help="Print progress to stderr")
args = parser.parse_args()
eval_set = json.loads(Path(args.eval_set).read_text())
skill_path = Path(args.skill_path)
if not (skill_path / "SKILL.md").exists():
print(f"Error: No SKILL.md found at {skill_path}", file=sys.stderr)
sys.exit(1)
name, original_description, content = parse_skill_md(skill_path)
description = args.description or original_description
project_root = find_project_root()
if args.verbose:
print(f"Evaluating: {description}", file=sys.stderr)
output = run_eval(
eval_set=eval_set,
skill_name=name,
description=description,
num_workers=args.num_workers,
timeout=args.timeout,
project_root=project_root,
runs_per_query=args.runs_per_query,
trigger_threshold=args.trigger_threshold,
model=args.model,
)
if args.verbose:
summary = output["summary"]
print(f"Results: {summary['passed']}/{summary['total']} passed", file=sys.stderr)
for r in output["results"]:
status = "PASS" if r["pass"] else "FAIL"
rate_str = f"{r['triggers']}/{r['runs']}"
print(f" [{status}] rate={rate_str} expected={r['should_trigger']}: {r['query'][:70]}", file=sys.stderr)
print(json.dumps(output, indent=2))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,332 @@
#!/usr/bin/env python3
"""Run the eval + improve loop until all pass or max iterations reached.
Combines run_eval.py and improve_description.py in a loop, tracking history
and returning the best description found. Supports train/test split to prevent
overfitting.
"""
import argparse
import json
import random
import sys
import tempfile
import time
import webbrowser
from pathlib import Path
import anthropic
from scripts.generate_report import generate_html
from scripts.improve_description import improve_description
from scripts.run_eval import find_project_root, run_eval
from scripts.utils import parse_skill_md
def split_eval_set(eval_set: list[dict], holdout: float, seed: int = 42) -> tuple[list[dict], list[dict]]:
"""Split eval set into train and test sets, stratified by should_trigger."""
random.seed(seed)
# Separate by should_trigger
trigger = [e for e in eval_set if e["should_trigger"]]
no_trigger = [e for e in eval_set if not e["should_trigger"]]
# Shuffle each group
random.shuffle(trigger)
random.shuffle(no_trigger)
# Calculate split points
n_trigger_test = max(1, int(len(trigger) * holdout))
n_no_trigger_test = max(1, int(len(no_trigger) * holdout))
# Split
test_set = trigger[:n_trigger_test] + no_trigger[:n_no_trigger_test]
train_set = trigger[n_trigger_test:] + no_trigger[n_no_trigger_test:]
return train_set, test_set
def run_loop(
eval_set: list[dict],
skill_path: Path,
description_override: str | None,
num_workers: int,
timeout: int,
max_iterations: int,
runs_per_query: int,
trigger_threshold: float,
holdout: float,
model: str,
verbose: bool,
live_report_path: Path | None = None,
log_dir: Path | None = None,
) -> dict:
"""Run the eval + improvement loop."""
project_root = find_project_root()
name, original_description, content = parse_skill_md(skill_path)
current_description = description_override or original_description
# Split into train/test if holdout > 0
if holdout > 0:
train_set, test_set = split_eval_set(eval_set, holdout)
if verbose:
print(f"Split: {len(train_set)} train, {len(test_set)} test (holdout={holdout})", file=sys.stderr)
else:
train_set = eval_set
test_set = []
client = anthropic.Anthropic()
history = []
exit_reason = "unknown"
for iteration in range(1, max_iterations + 1):
if verbose:
print(f"\n{'='*60}", file=sys.stderr)
print(f"Iteration {iteration}/{max_iterations}", file=sys.stderr)
print(f"Description: {current_description}", file=sys.stderr)
print(f"{'='*60}", file=sys.stderr)
# Evaluate train + test together in one batch for parallelism
all_queries = train_set + test_set
t0 = time.time()
all_results = run_eval(
eval_set=all_queries,
skill_name=name,
description=current_description,
num_workers=num_workers,
timeout=timeout,
project_root=project_root,
runs_per_query=runs_per_query,
trigger_threshold=trigger_threshold,
model=model,
)
eval_elapsed = time.time() - t0
# Split results back into train/test by matching queries
train_queries_set = {q["query"] for q in train_set}
train_result_list = [r for r in all_results["results"] if r["query"] in train_queries_set]
test_result_list = [r for r in all_results["results"] if r["query"] not in train_queries_set]
train_passed = sum(1 for r in train_result_list if r["pass"])
train_total = len(train_result_list)
train_summary = {"passed": train_passed, "failed": train_total - train_passed, "total": train_total}
train_results = {"results": train_result_list, "summary": train_summary}
if test_set:
test_passed = sum(1 for r in test_result_list if r["pass"])
test_total = len(test_result_list)
test_summary = {"passed": test_passed, "failed": test_total - test_passed, "total": test_total}
test_results = {"results": test_result_list, "summary": test_summary}
else:
test_results = None
test_summary = None
history.append({
"iteration": iteration,
"description": current_description,
"train_passed": train_summary["passed"],
"train_failed": train_summary["failed"],
"train_total": train_summary["total"],
"train_results": train_results["results"],
"test_passed": test_summary["passed"] if test_summary else None,
"test_failed": test_summary["failed"] if test_summary else None,
"test_total": test_summary["total"] if test_summary else None,
"test_results": test_results["results"] if test_results else None,
# For backward compat with report generator
"passed": train_summary["passed"],
"failed": train_summary["failed"],
"total": train_summary["total"],
"results": train_results["results"],
})
# Write live report if path provided
if live_report_path:
partial_output = {
"original_description": original_description,
"best_description": current_description,
"best_score": "in progress",
"iterations_run": len(history),
"holdout": holdout,
"train_size": len(train_set),
"test_size": len(test_set),
"history": history,
}
live_report_path.write_text(generate_html(partial_output, auto_refresh=True, skill_name=name))
if verbose:
def print_eval_stats(label, results, elapsed):
pos = [r for r in results if r["should_trigger"]]
neg = [r for r in results if not r["should_trigger"]]
tp = sum(r["triggers"] for r in pos)
pos_runs = sum(r["runs"] for r in pos)
fn = pos_runs - tp
fp = sum(r["triggers"] for r in neg)
neg_runs = sum(r["runs"] for r in neg)
tn = neg_runs - fp
total = tp + tn + fp + fn
precision = tp / (tp + fp) if (tp + fp) > 0 else 1.0
recall = tp / (tp + fn) if (tp + fn) > 0 else 1.0
accuracy = (tp + tn) / total if total > 0 else 0.0
print(f"{label}: {tp+tn}/{total} correct, precision={precision:.0%} recall={recall:.0%} accuracy={accuracy:.0%} ({elapsed:.1f}s)", file=sys.stderr)
for r in results:
status = "PASS" if r["pass"] else "FAIL"
rate_str = f"{r['triggers']}/{r['runs']}"
print(f" [{status}] rate={rate_str} expected={r['should_trigger']}: {r['query'][:60]}", file=sys.stderr)
print_eval_stats("Train", train_results["results"], eval_elapsed)
if test_summary:
print_eval_stats("Test ", test_results["results"], 0)
if train_summary["failed"] == 0:
exit_reason = f"all_passed (iteration {iteration})"
if verbose:
print(f"\nAll train queries passed on iteration {iteration}!", file=sys.stderr)
break
if iteration == max_iterations:
exit_reason = f"max_iterations ({max_iterations})"
if verbose:
print(f"\nMax iterations reached ({max_iterations}).", file=sys.stderr)
break
# Improve the description based on train results
if verbose:
print(f"\nImproving description...", file=sys.stderr)
t0 = time.time()
# Strip test scores from history so improvement model can't see them
blinded_history = [
{k: v for k, v in h.items() if not k.startswith("test_")}
for h in history
]
new_description = improve_description(
client=client,
skill_name=name,
skill_content=content,
current_description=current_description,
eval_results=train_results,
history=blinded_history,
model=model,
log_dir=log_dir,
iteration=iteration,
)
improve_elapsed = time.time() - t0
if verbose:
print(f"Proposed ({improve_elapsed:.1f}s): {new_description}", file=sys.stderr)
current_description = new_description
# Find the best iteration by TEST score (or train if no test set)
if test_set:
best = max(history, key=lambda h: h["test_passed"] or 0)
best_score = f"{best['test_passed']}/{best['test_total']}"
else:
best = max(history, key=lambda h: h["train_passed"])
best_score = f"{best['train_passed']}/{best['train_total']}"
if verbose:
print(f"\nExit reason: {exit_reason}", file=sys.stderr)
print(f"Best score: {best_score} (iteration {best['iteration']})", file=sys.stderr)
return {
"exit_reason": exit_reason,
"original_description": original_description,
"best_description": best["description"],
"best_score": best_score,
"best_train_score": f"{best['train_passed']}/{best['train_total']}",
"best_test_score": f"{best['test_passed']}/{best['test_total']}" if test_set else None,
"final_description": current_description,
"iterations_run": len(history),
"holdout": holdout,
"train_size": len(train_set),
"test_size": len(test_set),
"history": history,
}
def main():
parser = argparse.ArgumentParser(description="Run eval + improve loop")
parser.add_argument("--eval-set", required=True, help="Path to eval set JSON file")
parser.add_argument("--skill-path", required=True, help="Path to skill directory")
parser.add_argument("--description", default=None, help="Override starting description")
parser.add_argument("--num-workers", type=int, default=10, help="Number of parallel workers")
parser.add_argument("--timeout", type=int, default=30, help="Timeout per query in seconds")
parser.add_argument("--max-iterations", type=int, default=5, help="Max improvement iterations")
parser.add_argument("--runs-per-query", type=int, default=3, help="Number of runs per query")
parser.add_argument("--trigger-threshold", type=float, default=0.5, help="Trigger rate threshold")
parser.add_argument("--holdout", type=float, default=0.4, help="Fraction of eval set to hold out for testing (0 to disable)")
parser.add_argument("--model", required=True, help="Model for improvement")
parser.add_argument("--verbose", action="store_true", help="Print progress to stderr")
parser.add_argument("--report", default="auto", help="Generate HTML report at this path (default: 'auto' for temp file, 'none' to disable)")
parser.add_argument("--results-dir", default=None, help="Save all outputs (results.json, report.html, log.txt) to a timestamped subdirectory here")
args = parser.parse_args()
eval_set = json.loads(Path(args.eval_set).read_text())
skill_path = Path(args.skill_path)
if not (skill_path / "SKILL.md").exists():
print(f"Error: No SKILL.md found at {skill_path}", file=sys.stderr)
sys.exit(1)
name, _, _ = parse_skill_md(skill_path)
# Set up live report path
if args.report != "none":
if args.report == "auto":
timestamp = time.strftime("%Y%m%d_%H%M%S")
live_report_path = Path(tempfile.gettempdir()) / f"skill_description_report_{skill_path.name}_{timestamp}.html"
else:
live_report_path = Path(args.report)
# Open the report immediately so the user can watch
live_report_path.write_text("<html><body><h1>Starting optimization loop...</h1><meta http-equiv='refresh' content='5'></body></html>")
webbrowser.open(str(live_report_path))
else:
live_report_path = None
# Determine output directory (create before run_loop so logs can be written)
if args.results_dir:
timestamp = time.strftime("%Y-%m-%d_%H%M%S")
results_dir = Path(args.results_dir) / timestamp
results_dir.mkdir(parents=True, exist_ok=True)
else:
results_dir = None
log_dir = results_dir / "logs" if results_dir else None
output = run_loop(
eval_set=eval_set,
skill_path=skill_path,
description_override=args.description,
num_workers=args.num_workers,
timeout=args.timeout,
max_iterations=args.max_iterations,
runs_per_query=args.runs_per_query,
trigger_threshold=args.trigger_threshold,
holdout=args.holdout,
model=args.model,
verbose=args.verbose,
live_report_path=live_report_path,
log_dir=log_dir,
)
# Save JSON output
json_output = json.dumps(output, indent=2)
print(json_output)
if results_dir:
(results_dir / "results.json").write_text(json_output)
# Write final HTML report (without auto-refresh)
if live_report_path:
live_report_path.write_text(generate_html(output, auto_refresh=False, skill_name=name))
print(f"\nReport: {live_report_path}", file=sys.stderr)
if results_dir and live_report_path:
(results_dir / "report.html").write_text(generate_html(output, auto_refresh=False, skill_name=name))
if results_dir:
print(f"Results saved to: {results_dir}", file=sys.stderr)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,47 @@
"""Shared utilities for skill-creator scripts."""
from pathlib import Path
def parse_skill_md(skill_path: Path) -> tuple[str, str, str]:
"""Parse a SKILL.md file, returning (name, description, full_content)."""
content = (skill_path / "SKILL.md").read_text()
lines = content.split("\n")
if lines[0].strip() != "---":
raise ValueError("SKILL.md missing frontmatter (no opening ---)")
end_idx = None
for i, line in enumerate(lines[1:], start=1):
if line.strip() == "---":
end_idx = i
break
if end_idx is None:
raise ValueError("SKILL.md missing frontmatter (no closing ---)")
name = ""
description = ""
frontmatter_lines = lines[1:end_idx]
i = 0
while i < len(frontmatter_lines):
line = frontmatter_lines[i]
if line.startswith("name:"):
name = line[len("name:"):].strip().strip('"').strip("'")
elif line.startswith("description:"):
value = line[len("description:"):].strip()
# Handle YAML multiline indicators (>, |, >-, |-)
if value in (">", "|", ">-", "|-"):
continuation_lines: list[str] = []
i += 1
while i < len(frontmatter_lines) and (frontmatter_lines[i].startswith(" ") or frontmatter_lines[i].startswith("\t")):
continuation_lines.append(frontmatter_lines[i].strip())
i += 1
description = " ".join(continuation_lines)
continue
else:
description = value.strip('"').strip("'")
i += 1
return name, description, content

View file

@ -0,0 +1,97 @@
---
name: writing-skills
description: "Use when creating, updating, or improving agent skills."
---
# Writing Skills (Excellence)
Dispatcher for skill creation excellence. Use the decision tree below to find the right template and standards.
## Quick Decision Tree
### What do you need to do?
1. **Create a NEW skill:**
- Is it simple (single file, <200 lines)? -> [Tier 1 Architecture](references/tier-1-simple/README.md)
- Is it complex (multi-concept, 200-1000 lines)? -> [Tier 2 Architecture](references/tier-2-expanded/README.md)
- Is it a massive platform (10+ products, AWS, Convex)? -> [Tier 3 Architecture](references/tier-3-platform/README.md)
2. **Improve an EXISTING skill:**
- Fix "it's too long" -> [Modularize (Tier 3)](references/templates/tier-3-platform.md)
- Fix "AI ignores rules" -> [Anti-Rationalization](references/anti-rationalization/README.md)
- Fix "users can't find it" -> [CSO (Search Optimization)](references/cso/README.md)
3. **Verify Compliance:**
- Check metadata/naming -> [Standards](references/standards/README.md)
- Add tests -> [Testing Guide](references/testing/README.md)
## Component Index
| Component | Purpose |
|-----------|---------|
| **[CSO](references/cso/README.md)** | "SEO for LLMs". How to write descriptions that trigger. |
| **[Standards](references/standards/README.md)** | File naming, YAML frontmatter, directory structure. |
| **[Anti-Rationalization](references/anti-rationalization/README.md)**| How to write rules that agents won't ignore. |
| **[Testing](references/testing/README.md)** | How to ensure your skill actually works. |
## Templates
- [Technique Skill](references/templates/technique.md) (How-to)
- [Reference Skill](references/templates/reference.md) (Docs)
- [Discipline Skill](references/templates/discipline.md) (Rules)
- [Pattern Skill](references/templates/pattern.md) (Design Patterns)
## When to Use
- Creating a NEW skill from scratch
- Improving an EXISTING skill that agents ignore
- Debugging why a skill isn't being triggered
- Standardizing skills across a team
## How It Works
1. **Identify goal** -> Use decision tree above
2. **Select template** -> From `references/templates/`
3. **Apply CSO** -> Optimize description for discovery
4. **Add anti-rationalization** -> For discipline skills
5. **Test** -> RED-GREEN-REFACTOR cycle
## Quick Example
```yaml
---
name: my-technique
description: Use when [specific symptom occurs].
metadata:
category: technique
triggers: error-text, symptom, tool-name
---
# My Technique
## When to Use
- [Symptom A]
- [Error message]
```
## Common Mistakes
| Mistake | Fix |
|---------|-----|
| Description summarizes workflow | Use "Use when..." triggers only |
| No `metadata.triggers` | Add 3+ keywords |
| Generic name ("helper") | Use gerund (`creating-skills`) |
| Long monolithic SKILL.md | Split into `references/` |
See [gotchas.md](gotchas.md) for more.
## Pre-Deploy Checklist
Before deploying any skill:
- [ ] `name` field matches directory name exactly
- [ ] `SKILL.md` filename is ALL CAPS
- [ ] Description starts with "Use when..."
- [ ] `metadata.triggers` has 3+ keywords
- [ ] Total lines < 500 (use `references/` for more)
- [ ] No `@` force-loading in cross-references
- [ ] Tested with real scenarios

View file

@ -0,0 +1,236 @@
# Skill Templates & Examples
Complete, copy-paste templates for each skill type.
---
## Template: Technique Skill
For how-to guides that teach a specific method.
```markdown
---
name: technique-name
description: >-
Use when [specific symptom].
metadata:
category: technique
triggers: error-text, symptom, tool-name
---
# Technique Name
## Overview
[1-2 sentence core principle]
## When to Use
- [Symptom A]
- [Symptom B]
- [Error message text]
**NOT for:**
- [When to avoid]
## The Problem
\`\`\`javascript
// Bad example
function badCode() {
// problematic pattern
}
\`\`\`
## The Solution
\`\`\`javascript
// Good example
function goodCode() {
// improved pattern
}
\`\`\`
## Step-by-Step
1. [First step]
2. [Second step]
3. [Final step]
## Quick Reference
| Scenario | Approach |
|----------|----------|
| Case A | Solution A |
| Case B | Solution B |
## Common Mistakes
**Mistake 1:** [Description]
- Wrong: \`bad code\`
- Right: \`good code\`
```
---
## Template: Reference Skill
For documentation, APIs, and lookup tables.
```markdown
---
name: reference-name
description: >-
Use when working with [domain].
metadata:
category: reference
triggers: tool, api, specific-terms
---
# Reference Name
## Quick Reference
| Command | Purpose |
|---------|---------|
| \`cmd1\` | Does X |
| \`cmd2\` | Does Y |
## Common Patterns
**Pattern A:**
\`\`\`bash
example command
\`\`\`
**Pattern B:**
\`\`\`bash
another example
\`\`\`
## Detailed Docs
For more options, run \`--help\` or see:
- patterns.md
- [examples.md](examples.md)
```
---
## Template: Discipline Skill
For rules that agents must follow. Requires anti-rationalization techniques.
```markdown
---
name: discipline-name
description: >-
Use when [BEFORE violation].
metadata:
category: discipline
triggers: new feature, code change, implementation
---
# Rule Name
## Iron Law
**[SINGLE SENTENCE ABSOLUTE RULE]**
Violating the letter IS violating the spirit.
## The Rule
1. ALWAYS [step 1]
2. NEVER [step 2]
3. [Step 3]
## Violations
[Action before rule]? **Delete it. Start over.**
**No exceptions:**
- Don't keep it as "reference"
- Don't "adapt" it
- Delete means delete
## Common Rationalizations
| Excuse | Reality |
|--------|---------|
| "Too simple" | Simple code breaks. Rule takes 30 seconds. |
| "I'll do it after" | After = never. Do it now. |
| "Spirit not ritual" | The ritual IS the spirit. |
## Red Flags - STOP
- [Flag 1]
- [Flag 2]
- "This is different because..."
**All mean:** Delete. Start over.
## Valid Exceptions
- [Exception 1]
- [Exception 2]
**Everything else:** Follow the rule.
```
---
## Template: Pattern Skill
For mental models and design patterns.
```markdown
---
name: pattern-name
description: >-
Use when [recognizable symptom].
metadata:
category: pattern
triggers: complexity, hard-to-follow, nested
---
# Pattern Name
## The Pattern
[1-2 sentence core idea]
## Recognition Signs
- [Sign that pattern applies]
- [Another sign]
- [Code smell]
## Before
\`\`\`typescript
// Complex/problematic
function before() {
// nested, confusing
}
\`\`\`
## After
\`\`\`typescript
// Clean/improved
function after() {
// flat, clear
}
\`\`\`
## When NOT to Use
- [Over-engineering case]
- [Simple case that doesn't need it]
## Impact
**Before:** [Problem metric]
**After:** [Improved metric]
```

View file

@ -0,0 +1,175 @@
---
description: Common pitfalls and tribal knowledge for skill creation.
metadata:
tags: [gotchas, troubleshooting, mistakes]
---
# Skill Writing Gotchas
Tribal knowledge to avoid common mistakes.
## YAML Frontmatter
### Invalid Syntax
```yaml
# BAD: Mixed list and map
metadata:
references:
triggers: a, b, c
- item1
- item2
# GOOD: Consistent structure
metadata:
triggers: a, b, c
references:
- item1
- item2
```
### Multiline Description
```yaml
# BAD: Line breaks create parsing errors
description: Use when creating skills.
Also for updating.
# GOOD: Use YAML multiline syntax
description: >-
Use when creating or updating skills.
Triggers: new skill, update skill
```
## Naming
### Directory Must Match `name` Field
```
# BAD
directory: my-skill/
name: mySkill # Mismatch!
# GOOD
directory: my-skill/
name: my-skill # Exact match
```
### SKILL.md Must Be ALL CAPS
```
# BAD
skill.md
Skill.md
# GOOD
SKILL.md
```
## Discovery
### Description = Triggers, NOT Workflow
```yaml
# BAD: Agent reads this and skips the full skill
description: Analyzes code, finds bugs, suggests fixes
# GOOD: Agent reads full skill to understand workflow
description: Use when debugging errors or reviewing code quality
```
### Pre-Violation Triggers for Discipline Skills
```yaml
# BAD: Triggers AFTER violation
description: Use when you forgot to write tests
# GOOD: Triggers BEFORE violation
description: Use when implementing any feature, before writing code
```
## Token Efficiency
### Skill Loaded Every Conversation = Token Drain
- Frequently-loaded skills: <200 words
- All others: <500 words
- Move details to `references/` files
### Don't Duplicate CLI Help
```markdown
# BAD: 50 lines documenting all flags
# GOOD: One line
Run `mytool --help` for all options.
```
## Anti-Rationalization (Discipline Skills Only)
### Agents Are Smart at Finding Loopholes
```markdown
# BAD: Trust agents will "get the spirit"
Write test before code.
# GOOD: Close every loophole explicitly
Write test before code.
**No exceptions:**
- Don't keep code as "reference"
- Don't "adapt" existing code
- Delete means delete
```
### Build Rationalization Table
Every excuse from baseline testing goes in the table:
| Excuse | Reality |
|--------|---------|
| "Too simple to test" | Simple code breaks. Test takes 30 seconds. |
| "I'll test after" | Tests-after prove nothing immediately. |
## Cross-References
### Keep References One Level Deep
```markdown
# BAD: Nested chain (A -> B -> C)
See [patterns.md] -> which links to [advanced.md] -> which links to [deep.md]
# GOOD: Flat (A -> B, A -> C)
See [patterns.md] and [advanced.md]
```
### Never Force-Load with @
```markdown
# BAD: Burns context immediately
@skills/my-skill/SKILL.md
# GOOD: Agent loads when needed
See [my-skill] for details.
```
## Tier Selection
### Don't Overthink Tier Choice
```markdown
# BAD: Starting with Tier 3 "just in case"
# Result: Wasted effort, empty reference files
# GOOD: Start with Tier 1, upgrade when needed
# Can always add references/ later
```
### Signals You Need to Upgrade
| Signal | Action |
|--------|--------|
| SKILL.md > 200 lines | -> Tier 2 |
| 3+ related sub-topics | -> Tier 2 |
| 10+ products/services | -> Tier 3 |
| "I need X" vs "I want Y" | -> Tier 3 decision trees |

View file

@ -0,0 +1,86 @@
# Persuasion Principles for Skill Design
## Overview
LLMs respond to the same persuasion principles as humans. Understanding this psychology helps you design more effective skills - not to manipulate, but to ensure critical practices are followed even under pressure.
**Research foundation:** Meincke et al. (2025) tested 7 persuasion principles with N=28,000 AI conversations. Persuasion techniques more than doubled compliance rates (33% to 72%, p < .001).
## The Seven Principles
### 1. Authority
**What it is:** Deference to expertise, credentials, or official sources.
**How it works in skills:**
- Imperative language: "YOU MUST", "Never", "Always"
- Non-negotiable framing: "No exceptions"
- Eliminates decision fatigue and rationalization
**When to use:**
- Discipline-enforcing skills (TDD, verification requirements)
- Safety-critical practices
- Established best practices
### 2. Commitment
**What it is:** Consistency with prior actions, statements, or public declarations.
**How it works in skills:**
- Require announcements: "Announce skill usage"
- Force explicit choices: "Choose A, B, or C"
- Use tracking: TodoWrite for checklists
### 3. Scarcity
**What it is:** Urgency from time limits or limited availability.
**How it works in skills:**
- Time-bound requirements: "Before proceeding"
- Sequential dependencies: "Immediately after X"
- Prevents procrastination
### 4. Social Proof
**What it is:** Conformity to what others do or what's considered normal.
**How it works in skills:**
- Universal patterns: "Every time", "Always"
- Failure modes: "X without Y = failure"
- Establishes norms
### 5. Unity
**What it is:** Shared identity, "we-ness", in-group belonging.
**How it works in skills:**
- Collaborative language: "our codebase", "we're colleagues"
- Shared goals: "we both want quality"
### 6. Reciprocity
**What it is:** Obligation to return benefits received.
- Use sparingly - can feel manipulative
- Rarely needed in skills
### 7. Liking
**What it is:** Preference for cooperating with those we like.
- **DON'T USE for compliance**
- Conflicts with honest feedback culture
## Principle Combinations by Skill Type
| Skill Type | Use | Avoid |
|------------|-----|-------|
| Discipline-enforcing | Authority + Commitment + Social Proof | Liking, Reciprocity |
| Guidance/technique | Moderate Authority + Unity | Heavy authority |
| Collaborative | Unity + Commitment | Authority, Liking |
| Reference | Clarity only | All persuasion |
## Ethical Use
**Legitimate:**
- Ensuring critical practices are followed
- Creating effective documentation
- Preventing predictable failures
**The test:** Would this technique serve the user's genuine interests if they fully understood it?
## Research Citations
**Cialdini, R. B. (2021).** *Influence: The Psychology of Persuasion (New and Expanded).* Harper Business.
**Meincke, L., et al. (2025).** Call Me A Jerk: Persuading AI to Comply with Objectionable Requests. University of Pennsylvania.

View file

@ -0,0 +1,85 @@
# Anti-Rationalization Guide
Techniques for bulletproofing skills against agent rationalization.
## The Problem
Discipline-enforcing skills face a unique challenge: smart agents under pressure will find loopholes.
## Technique 1: Close Every Loophole Explicitly
Don't just state the rule - forbid specific workarounds.
### Bad Example
```markdown
Write code before test? Delete it.
```
### Good Example
```markdown
Write code before test? Delete it. Start over.
**No exceptions**:
- Don't keep it as "reference"
- Don't "adapt" it while writing tests
- Don't look at it
- Delete means delete
```
## Technique 2: Address "Spirit vs Letter" Arguments
Add foundational principle early:
```markdown
**Violating the letter of the rules is violating the spirit of the rules.**
```
## Technique 3: Build Rationalization Table
| Excuse | Reality |
|--------|---------|
| "Too simple to test" | Simple code breaks. Test takes 30 seconds. |
| "I'll test after" | Tests passing immediately prove nothing. |
| "Spirit not ritual" | The letter IS the spirit. |
## Technique 4: Create Red Flags List
```markdown
## Red Flags - STOP and Start Over
- Code before test
- "I already manually tested it"
- "This is different because..."
**All of these mean**: Delete code. Start over.
```
## Technique 5: Use Strong Language
```markdown
# Weak (invites rationalization)
You should write tests first.
# Strong (no wiggle room)
ALWAYS write test first.
NEVER write code before test.
```
## Technique 6: Provide Escape Hatch for Legitimate Cases
```markdown
## When NOT to Use
- Spike solutions (throwaway exploratory code)
- One-time scripts deleting in 1 hour
**Everything else**: Follow the rule. No exceptions.
```
## Complete Bulletproofing Checklist
- [ ] Forbidden each specific workaround explicitly?
- [ ] Added "spirit vs letter" principle?
- [ ] Built rationalization table from baseline tests?
- [ ] Created red flags list?
- [ ] Used strong language (ALWAYS/NEVER)?
- [ ] Provided explicit escape hatch?
- [ ] Description includes pre-violation symptoms?

View file

@ -0,0 +1,90 @@
# CSO Guide - Claude Search Optimization
Advanced techniques for making skills discoverable by agents.
## The Discovery Problem
You have 100+ skills. Agent receives a task. How does it find the RIGHT skill?
**Answer**: The `description` field.
## Critical Rule: Description = Triggers, NOT Workflow
### The Trap
When description summarizes workflow, agents take a shortcut.
**Real example that failed**:
```yaml
# Agent did ONE review instead of TWO
description: Code review between tasks
# Skill body had flowchart showing TWO reviews
```
**Why it failed**: Agent read description, thought "code review between tasks means one review", never read the flowchart.
**Fix**:
```yaml
# Agent now reads full skill and follows flowchart
description: Use when executing implementation plans with independent tasks
```
### The Pattern
```yaml
# BAD: Workflow summary
description: Analyzes git diff, generates commit message in conventional format
# GOOD: Trigger conditions only
description: Use when generating commit messages or reviewing staged changes
```
## Token Efficiency
**Target word counts**:
- Frequently-loaded skills: <200 words total
- Other skills: <500 words
## Keyword Strategy
### Error Messages
Include EXACT error text users will see.
### Symptoms
Use words users naturally say: "flaky", "hangs", "slow", "timeout", "race condition"
### Tools & Commands
Actual names, not descriptions: "pytest", not "Python testing"
### Synonyms
Cover multiple ways to describe same thing: timeout/hang/freeze
## Description Template
```yaml
description: "Use when [SPECIFIC TRIGGER]."
metadata:
triggers: [error1], [symptom2], [tool3]
```
## Third Person Rule
```yaml
# BAD: First person
description: "I can help you with async tests"
# GOOD: Third person
description: "Handles async tests with race conditions"
```
## Verification Checklist
- [ ] Description starts with "Use when..."?
- [ ] Description is <500 characters?
- [ ] Description lists ONLY triggers, not workflow?
- [ ] Includes 3+ keywords (errors/symptoms/tools)?
- [ ] Third person throughout?
- [ ] Name uses gerund or verb-first format?

View file

@ -0,0 +1,87 @@
---
description: Standards and naming rules for creating agent skills.
metadata:
tags: [standards, naming, yaml, structure]
---
# Skill Development Guide
## Directory Structure
```
skills/
{skill-name}/ # kebab-case, matches `name` field
SKILL.md # Required: main skill definition
references/ # Optional: supporting documentation
README.md # Sub-topic entry point
*.md # Additional files
```
## Naming Rules
| Element | Rule | Example |
|---------|------|---------|
| Directory | kebab-case, 1-64 chars | `react-best-practices` |
| `SKILL.md` | ALL CAPS, exact filename | `SKILL.md` (not `skill.md`) |
| `name` field | Must match directory name | `name: react-best-practices` |
## SKILL.md Structure
```markdown
---
name: {skill-name}
description: >-
Use when [trigger condition].
metadata:
category: technique
triggers: keyword1, keyword2, error-text
---
# Skill Title
Brief description of what this skill does.
## When to Use
- Symptom or situation A
- Symptom or situation B
## How It Works
Step-by-step instructions or reference content.
## Examples
Concrete usage examples.
## Common Mistakes
What to avoid and why.
```
## Description Best Practices
```yaml
# BAD: Workflow summary
description: Analyzes code, finds bugs, suggests fixes
# GOOD: Trigger conditions only
description: Use when debugging errors or reviewing code quality.
```
**Rules:**
- Start with "Use when..."
- Keep under 500 characters
- Use third person
## Context Efficiency
| Guideline | Reason |
|-----------|--------|
| Keep SKILL.md < 500 lines | Reduces context consumption |
| Put details in supporting files | Agent reads only what's needed |
| Use tables for reference data | More compact than prose |
## Verification Checklist
- [ ] `name` matches directory name?
- [ ] `SKILL.md` is ALL CAPS?
- [ ] Description starts with "Use when..."?
- [ ] Under 500 lines?
- [ ] Tested with real scenarios?

View file

@ -0,0 +1,39 @@
# SKILL.md Metadata Standard
Official frontmatter fields.
## Required Fields
```yaml
---
name: skill-name
description: >-
Use when [trigger condition].
---
```
| Field | Rules |
|-------|-------|
| `name` | 1-64 chars, lowercase, hyphens only, must match directory name |
| `description` | 1-1024 chars, should describe when to use |
## Optional Fields
```yaml
---
name: skill-name
description: Purpose and triggers.
metadata:
category: "reference"
version: "1.0.0"
---
```
## Name Validation
```regex
^[a-z0-9]+(-[a-z0-9]+)*$
```
**Valid**: `my-skill`, `git-release`, `tdd`
**Invalid**: `My-Skill`, `my_skill`, `-my-skill`

View file

@ -0,0 +1,54 @@
---
name: discipline-name
description: >-
Use when [BEFORE violation].
metadata:
category: discipline
triggers: new feature, code change, implementation
---
# Rule Name
## Iron Law
**[SINGLE SENTENCE ABSOLUTE RULE]**
Violating the letter IS violating the spirit.
## The Rule
1. ALWAYS [step 1]
2. NEVER [step 2]
3. [Step 3]
## Violations
[Action before rule]? **Delete it. Start over.**
**No exceptions:**
- Don't keep it as "reference"
- Don't "adapt" it
- Delete means delete
## Common Rationalizations
| Excuse | Reality |
|--------|---------|
| "Too simple" | Simple code breaks. Rule takes 30 seconds. |
| "I'll do it after" | After = never. Do it now. |
| "Spirit not ritual" | The ritual IS the spirit. |
## Red Flags - STOP
- [Flag 1]
- [Flag 2]
- "This is different because..."
**All mean:** Delete. Start over.
## Valid Exceptions
- [Exception 1]
- [Exception 2]
**Everything else:** Follow the rule.

View file

@ -0,0 +1,48 @@
---
name: pattern-name
description: >-
Use when [recognizable symptom].
metadata:
category: pattern
triggers: complexity, hard-to-follow, nested
---
# Pattern Name
## The Pattern
[1-2 sentence core idea]
## Recognition Signs
- [Sign that pattern applies]
- [Another sign]
- [Code smell]
## Before
```typescript
// Complex/problematic
function before() {
// nested, confusing
}
```
## After
```typescript
// Clean/improved
function after() {
// flat, clear
}
```
## When NOT to Use
- [Over-engineering case]
- [Simple case that doesn't need it]
## Impact
**Before:** [Problem metric]
**After:** [Improved metric]

View file

@ -0,0 +1,35 @@
---
name: reference-name
description: >-
Use when working with [domain].
metadata:
category: reference
triggers: tool, api, specific-terms
---
# Reference Name
## Quick Reference
| Command | Purpose |
|---------|---------|
| `cmd1` | Does X |
| `cmd2` | Does Y |
## Common Patterns
**Pattern A:**
```bash
example command
```
**Pattern B:**
```bash
another example
```
## Detailed Docs
For more options, run `--help` or see:
- patterns.md
- examples.md

View file

@ -0,0 +1,59 @@
---
name: technique-name
description: Use when [specific symptom].
metadata:
category: technique
triggers: error-text, symptom, tool-name
---
# Technique Name
## Overview
[1-2 sentence core principle]
## When to Use
- [Symptom A]
- [Symptom B]
- [Error message text]
**NOT for:**
- [When to avoid]
## The Problem
```javascript
// Bad example
function badCode() {
// problematic pattern
}
```
## The Solution
```javascript
// Good example
function goodCode() {
// improved pattern
}
```
## Step-by-Step
1. [First step]
2. [Second step]
3. [Final step]
## Quick Reference
| Scenario | Approach |
|----------|----------|
| Case A | Solution A |
| Case B | Solution B |
## Common Mistakes
**Mistake 1:** [Description]
- Wrong: `bad code`
- Right: `good code`

View file

@ -0,0 +1,17 @@
# Platform Name Skill
Template for complex Tier 3 skills.
## Structure
```
skill/
SKILL.md # Dispatcher
references/
topic/
README.md # Overview
api.md # API Reference
config.md # Configuration
patterns.md # Recipes
gotchas.md # Critical Errors
```

View file

@ -0,0 +1,66 @@
# Testing Guide - TDD for Skills
Complete methodology for testing skills using RED-GREEN-REFACTOR cycle.
## Testing All Skill Types
### Discipline-Enforcing Skills (rules/requirements)
**Test with**:
- Academic questions: Do they understand the rules?
- Pressure scenarios: Do they comply under stress?
- Multiple pressures combined: time + sunk cost + exhaustion
**Success criteria**: Agent follows rule under maximum pressure
### Technique Skills (how-to guides)
**Test with**:
- Application scenarios: Can they apply the technique correctly?
- Variation scenarios: Do they handle edge cases?
- Missing information tests: Do instructions have gaps?
**Success criteria**: Agent successfully applies technique to new scenario
### Pattern Skills (mental models)
**Test with**:
- Recognition scenarios: Do they recognize when pattern applies?
- Counter-examples: Do they know when NOT to apply?
**Success criteria**: Agent correctly identifies when/how to apply pattern
### Reference Skills (documentation/APIs)
**Test with**:
- Retrieval scenarios: Can they find the right information?
- Gap testing: Are common use cases covered?
**Success criteria**: Agent finds and correctly applies reference information
## Pressure Types for Testing
| Pressure | Example |
|----------|---------|
| Time | "You have 5 minutes to complete this task" |
| Sunk cost | "You already spent 2 hours on this" |
| Authority | "Senior developer said to skip tests" |
| Exhaustion | "This is the 10th task today" |
## Complete Test Checklist
**Baseline (RED)**:
- [ ] Designed 3+ pressure scenarios
- [ ] Ran scenarios WITHOUT skill
- [ ] Documented verbatim agent responses
**Implementation (GREEN)**:
- [ ] Skill addresses SPECIFIC baseline failures
- [ ] Re-ran scenarios WITH skill
- [ ] Agent complied in all scenarios
**Bulletproofing (REFACTOR)**:
- [ ] Tested with combined pressures
- [ ] Found and documented new rationalizations
- [ ] Added explicit counters
- [ ] Re-tested until no more loopholes

View file

@ -0,0 +1,30 @@
---
description: When to use Tier 1 (Simple) skill architecture.
metadata:
tags: [tier-1, simple, single-file]
---
# Tier 1: Simple Skills
Single-file skills for focused, specific purposes.
## When to Use
- **Single concept**: One technique, one pattern, one reference
- **Under 200 lines**: Can fit comfortably in one file
- **No complex decision logic**: User knows exactly what they need
- **Frequently loaded**: Needs minimal token footprint
## Structure
```
my-skill/
SKILL.md # Everything in one file
```
## Checklist
- [ ] Fits in <200 lines
- [ ] Single focused purpose
- [ ] No need for `references/` directory
- [ ] Description uses "Use when..." pattern

View file

@ -0,0 +1,52 @@
---
description: When to use Tier 2 (Expanded) skill architecture.
metadata:
tags: [tier-2, expanded, multi-file]
---
# Tier 2: Expanded Skills
Multi-file skills for complex topics with multiple sub-concepts.
## When to Use
- **Multiple related concepts**: Needs separation of concerns
- **200-1000 lines total**: Too big for one file
- **Needs reference files**: Patterns, examples, troubleshooting
- **Cross-linking**: Users need to navigate between sub-topics
## Structure
```
my-skill/
SKILL.md # Overview + navigation
references/
core/
README.md # Main concept
patterns/
README.md # Usage patterns
troubleshooting/
README.md # Common issues
```
## Progressive Disclosure
1. **Metadata** (~100 tokens): Name + description loaded at startup
2. **SKILL.md** (<500 lines): Decision tree + index
3. **References** (as needed): Loaded only when user navigates
## Key Differences from Tier 1
| Aspect | Tier 1 | Tier 2 |
|--------|--------|--------|
| Files | 1 | 5-20 |
| Total lines | <200 | 200-1000 |
| Decision logic | None | Simple tree |
| Token cost | Minimal | Medium (progressive) |
## Checklist
- [ ] SKILL.md has clear navigation links
- [ ] Each `references/` subdir has README.md
- [ ] No circular references between files
- [ ] Decision tree points to specific files

View file

@ -0,0 +1,51 @@
---
description: When to use Tier 3 (Platform) skill architecture for large platforms.
metadata:
tags: [tier-3, platform, enterprise]
---
# Tier 3: Platform Skills
Enterprise-grade skills for entire platforms (AWS, Cloudflare, Convex, etc).
## When to Use
- **Entire platform**: 10+ products/services
- **1000+ lines total**: Would overwhelm context if monolithic
- **Complex decision logic**: Users start with "I need X" not "I want product Y"
## The 5-File Pattern
Each product directory has exactly 5 files:
| File | Purpose | When to Load |
|------|---------|--------------|
| `README.md` | Overview, when to use | Always first |
| `api.md` | Runtime APIs, methods | Implementing features |
| `configuration.md` | Config, environment | Setting up |
| `patterns.md` | Common workflows | Best practices |
| `gotchas.md` | Pitfalls, limits | Debugging |
## Decision Trees
```markdown
Need to store data?
Simple key-value -> kv/
Relational queries -> d1/
Large files/blobs -> r2/
Per-user state -> durable-objects/
```
## Progressive Disclosure in Action
- **Startup**: Only name + description (~100 tokens)
- **Activation**: SKILL.md with trees (<5000 tokens)
- **Navigation**: One product's 5 files (as needed)
## Checklist
- [ ] SKILL.md contains ONLY decision trees + index
- [ ] Each product has exactly 5 files
- [ ] Decision trees cover all "I need X" scenarios
- [ ] Cross-references stay one level deep
- [ ] Every product has `gotchas.md`

View file

@ -0,0 +1,85 @@
# Testing Skills With Subagents
**Load this reference when:** creating or editing skills, before deployment, to verify they work under pressure and resist rationalization.
## Overview
**Testing skills is just TDD applied to process documentation.**
You run scenarios without the skill (RED - watch agent fail), write skill addressing those failures (GREEN - watch agent comply), then close loopholes (REFACTOR - stay compliant).
**Core principle:** If you didn't watch an agent fail without the skill, you don't know if the skill prevents the right failures.
## When to Use
Test skills that:
- Enforce discipline (TDD, testing requirements)
- Have compliance costs (time, effort, rework)
- Could be rationalized away ("just this once")
- Contradict immediate goals (speed over quality)
Don't test:
- Pure reference skills (API docs, syntax guides)
- Skills without rules to violate
- Skills agents have no incentive to bypass
## TDD Mapping for Skill Testing
| TDD Phase | Skill Testing | What You Do |
|-----------|---------------|-------------|
| **RED** | Baseline test | Run scenario WITHOUT skill, watch agent fail |
| **Verify RED** | Capture rationalizations | Document exact failures verbatim |
| **GREEN** | Write skill | Address specific baseline failures |
| **Verify GREEN** | Pressure test | Run scenario WITH skill, verify compliance |
| **REFACTOR** | Plug holes | Find new rationalizations, add counters |
| **Stay GREEN** | Re-verify | Test again, ensure still compliant |
## RED Phase: Baseline Testing (Watch It Fail)
**Goal:** Run test WITHOUT the skill - watch agent fail, document exact failures.
**Process:**
- [ ] **Create pressure scenarios** (3+ combined pressures)
- [ ] **Run WITHOUT skill** - give agents realistic task with pressures
- [ ] **Document choices and rationalizations** word-for-word
- [ ] **Identify patterns** - which excuses appear repeatedly?
- [ ] **Note effective pressures** - which scenarios trigger violations?
## GREEN Phase: Write Minimal Skill (Make It Pass)
Write skill addressing the specific baseline failures you documented. Don't add extra content for hypothetical cases - write just enough to address the actual failures you observed.
Run same scenarios WITH skill. Agent should now comply.
If agent still fails: skill is unclear or incomplete. Revise and re-test.
## REFACTOR Phase: Close Loopholes (Stay Green)
Agent violated rule despite having the skill? Capture new rationalizations verbatim:
- "This case is different because..."
- "I'm following the spirit not the letter"
- "Being pragmatic means adapting"
- "Deleting X hours is wasteful"
**Document every excuse.** These become your rationalization table.
## Testing Checklist (TDD for Skills)
**RED Phase:**
- [ ] Created pressure scenarios (3+ combined pressures)
- [ ] Ran scenarios WITHOUT skill (baseline)
- [ ] Documented agent failures and rationalizations verbatim
**GREEN Phase:**
- [ ] Wrote skill addressing specific baseline failures
- [ ] Ran scenarios WITH skill
- [ ] Agent now complies
**REFACTOR Phase:**
- [ ] Identified NEW rationalizations from testing
- [ ] Added explicit counters for each loophole
- [ ] Updated rationalization table
- [ ] Updated red flags list
- [ ] Re-tested - agent still complies
- [ ] Meta-tested to verify clarity
- [ ] Agent follows rule under maximum pressure

127
AGENTS.md Normal file
View file

@ -0,0 +1,127 @@
# AGENTS.md
## Project
- Minecraft Console Client (MCC) is a cross-platform text/TUI client for Minecraft Java Edition.
- Primary scope: connect to servers, send chat and commands, receive text, automate gameplay/admin tasks, and extend behavior through built-in bots or runtime C# scripts.
- Secondary scope: protocol/version adaptation tooling, docs site, legacy GUI wrapper, and debug tooling.
- Decompiled server source for both the old and new MC versions in `$MCC_REPO/MinecraftOfficial/<version>-decompiled/`
## Build / Run
- Init submodules first: `git submodule update --init --recursive`
- Build for local development: `source tools/mcc-env.sh && mcc-build`
- Publish (matches CI shape): `source tools/mcc-env.sh && mcc-publish --rid <RID>`
- Run/debug from source: `source tools/mcc-env.sh && mcc-debug -v 1.21.11 --file-input`
- Docs: `cd docs && npm install && npm run docs:dev` or `npm run docs:build`
- Docker: `cd Docker && docker build -t minecraft-console-client:latest .`
- Tests: no dedicated test project is present in the main solution.
- Current state: the solution builds after submodule init, but the underlying .NET build emits many analyzer and NuGet vulnerability warnings; treat them as real.
- Server roots: `tools/` helpers look for server jars under `MinecraftOfficial/downloads/<version>/` by default, but also support an external root via the `MCC_SERVERS` environment variable.
- Multi-version testing: tmux-based local server sessions are shared state. Run cross-version test matrices sequentially unless you have explicit per-version isolation. A server logging `Done` does not guarantee immediate RCON availability; retry RCON setup commands.
- Automated test configs: for repeated or matrix test runs, prefer generating a temporary MCC config per run instead of reusing the repo-root `MinecraftClient.ini`, to avoid leaking state between runs.
- For agent-driven local development, prefer `mcc-build`, `mcc-publish`, `mcc-build-clean`, `mcc-debug`, `mcc-run`, and `mcc-tui` over raw `dotnet build`, `dotnet publish`, or `dotnet run`, so worktree-local temp build routing stays active.
## Architecture
- `Program` bootstraps console I/O, TOML config, auth/session state, MC version selection, Forge detection, then creates `McClient`.
- `McClient` is the live session runtime: TCP client, selected protocol handler, Brigadier command dispatcher, loaded bots, world/inventory/entity state, queued chat, movement/pathing, reconnect flow.
- `Protocol/` is the network/auth boundary. `ProtocolHandler` maps Minecraft versions to protocol numbers and selects either `Protocol16Handler` (1.4.6-1.6.4) or `Protocol18Handler` (1.7.2+).
- `Scripting/ChatBot` is the extension boundary. Built-in bots and `/script` C# bots share the same event/tick API.
- Main runtime flow: console input -> internal Brigadier command or server chat; packets -> protocol handler -> `McClient` state update -> bot events; `OnUpdate()` (20 TPS) drives bot ticks, delayed work, chat cooldowns, movement, and main-thread tasks.
## Technology Stack
- Main app: C#, .NET 10, nullable enabled.
- Command system: `Brigadier.NET`.
- Config: TOML via `Samboy063.Tomlet`.
- Runtime scripting: Roslyn (`Microsoft.CodeAnalysis.CSharp`) with in-memory compilation.
- Networking/auth: custom Minecraft protocol handlers, DNS SRV lookup (`DnsClient`), Forge/session/profile-key support.
- Integrations: `DSharpPlus`, `Telegram.Bot`, `MessagePack`, `Magick.NET`, `Sentry`.
- Docs site: VuePress 2 (`docs/package.json`).
- Tooling: Docker, GitHub Actions, Python 3.10+ scripts under `tools/` for palette/version generation.
- Legacy UI: `MinecraftClientGUI` is a separate .NET Framework 4.0 WinForms wrapper, not the main runtime.
## Version Support
Feature columns mean:
- Inventory: `/inventory` plus inventory/container bot APIs
- Movement: terrain handling, `/move`, and movement/pathing bots
- Entity: entity tracking and entity-driven bot events
| Minecraft | Protocol path | Inventory | Movement | Entity | Notes |
| --- | --- | --- | --- | --- | --- |
| 1.4.6-1.6.4 | `Protocol16Handler` | No | No | No | Core login/chat only |
| 1.7.2-1.7.10 | `Protocol18Handler` | No | Yes | No | Pre-1.8 special case |
| 1.8-1.9.4 | `Protocol18Handler` | Partial / docs conflict | Yes | Yes | Runtime gates allow 1.8+, but docs still warn inventory is unsupported through 1.9 |
| 1.10-1.12.2 | `Protocol18Handler` | Yes | Yes | Yes | Pre-flattening palettes |
| 1.13-1.19.2 | `Protocol18Handler` | Yes | Yes | Yes | Flattened block/item/entity palettes |
| 1.19.3-1.20.4 | `Protocol18Handler` | Yes | Yes | Yes | Newer chat/signing and palette splits |
| 1.20.6-1.21.4 | `Protocol18Handler` | Yes | Yes | Yes | Registry-driven world/attribute handling |
| 1.21.5-1.21.8 | `Protocol18Handler` | Yes | Yes | Yes | 1.21.7/1.21.8 reuse 1.21.6 block/entity palettes in code |
| 1.21.9-1.21.10 | `Protocol18Handler` | Yes | Yes | Yes | Version tools prefer server data reports since 1.21.9 |
| 1.21.11 | `Protocol18Handler` | Yes | Yes | Yes | Own entity/item/metadata palettes; blocks reuse 1.21.9 palette |
| 26.1 | `Protocol18Handler` | Yes | Yes | Yes | New Minecraft version naming scheme |
| 26.2 | `Protocol18Handler` | Yes | Yes | Yes | Latest coded support; own item/block/entity palettes, reuses 26.1 packet IDs and metadata serializers |
Notes:
- Declared code range is `1.4.6` to `26.2`.
- Human docs are stale in places and sometimes stop at older ranges; prefer code when docs and code disagree.
- Movement/pathing limits called out in docs still apply: no swimming, no knockback. The `Physics/` engine adds vanilla-accurate collision and movement but some edge cases remain.
## Module Map
### Core Runtime
| Module | What It Owns | Important Files |
| --- | --- | --- |
| `MinecraftClient/` | Main `net10.0` runtime assembly and the best starting point. `Program.cs` owns startup, config load/writeback, CLI handling, auth/version selection, update/data-generation entrypoints, and restart/failure flow. `McClient.cs` owns the live session runtime: protocol handler ownership, command dispatch, bot lifecycle, world/inventory/entity state, queued chat, movement ticks, reconnect/disconnect logic, and the main-thread invoke queue. `Settings.cs` defines the TOML schema and runtime/internal overrides used across the app. | `Program.cs`, `McClient.cs`, `Settings.cs`, `ConsoleIO.cs`, `Command.cs`, `UpgradeHelper.cs`, `AutoTimeout.cs` |
| `MinecraftClient/Protocol/` | Network/auth/session boundary. `ProtocolHandler.cs` does DNS SRV lookup, server ping/version detection, MC-version to protocol mapping, and handler selection. `Protocol16.cs` and `Protocol18.cs` implement the packet flow for legacy and modern versions. `Protocol18Terrain.cs` decodes chunk sections/biomes into `World`. `DataTypes.cs` is the low-level reader/writer layer for VarInts, metadata, NBT-like structures, and packet fields. `Message/`, `ProfileKey/`, `Session/`, `Handlers/Forge/`, `Handlers/PacketPalettes/`, `Handlers/Packet/`, and `Handlers/StructuredComponents/` cover chat/signing, cached auth, Forge, packet IDs, packet-level parsing, and 1.20.6+ item components with versioned registries under `StructuredComponents/Registries/`. | `Protocol/ProtocolHandler.cs`, `Protocol/Handlers/Protocol16.cs`, `Protocol/Handlers/Protocol18.cs`, `Protocol/Handlers/Protocol18Terrain.cs`, `Protocol/Handlers/DataTypes.cs`, `Protocol/Message/ChatParser.cs`, `Protocol/MicrosoftAuthentication.cs`, `Protocol/MojangAPI.cs` |
| `MinecraftClient/Mapping/` | World model, terrain storage, movement logic, and versioned block/entity metadata. `World.cs` stores chunk columns, dimension data, and 1.20.6+ registry-derived dimension/attribute mappings. `Chunk*`, `Block.cs`, and `Location.cs` are the terrain primitives. `Movement.cs` contains step generation, gravity/on-ground checks, and path execution support. `Material.cs` plus `BlockPalettes/*.cs` map block-state IDs to MCC materials. `Entity.cs`, `EntityType.cs`, `EntityPalettes/*.cs`, `EntityMetadataPalette.cs`, and `EntityMetadataPalettes/*.cs` do the same for entities and metadata serializers. | `Mapping/World.cs`, `Mapping/ChunkColumn.cs`, `Mapping/Chunk.cs`, `Mapping/Block.cs`, `Mapping/Location.cs`, `Mapping/Movement.cs`, `Mapping/RaycastHelper.cs`, `Mapping/Material.cs`, `Mapping/Entity.cs`, `Mapping/EntityType.cs` |
| `MinecraftClient/Inventory/` | Inventory/container snapshots, item decoding, and versioned item registries. `Container.cs` models player inventories and server windows, including slot contents and container properties. `Item.cs` bridges older NBT-based items with 1.20.6+ structured components. `ItemType.cs` plus `ItemPalettes/*.cs` provide version-specific item ID mapping. Enchantment, effects, and villager-trade files add higher-level semantics on top of raw inventory data. | `Inventory/Container.cs`, `Inventory/ContainerType.cs`, `Inventory/Item.cs`, `Inventory/ItemMovingHelper.cs`, `Inventory/ItemType.cs`, `Inventory/ItemPalettes/*.cs`, `Inventory/EnchantmentMapping.cs`, `Inventory/VillagerTrade.cs` |
| `MinecraftClient/Physics/` | Vanilla-accurate per-tick physics engine. `PlayerPhysics.cs` mirrors vanilla `Entity.move()`, `LivingEntity.aiStep()/travel()`, and `Player.travel()` logic at 20 TPS, handling ground/air/water/lava/creative-fly travel, jumping, sprint-jump boost, climbing, sneak-edge-detection, friction, drag, gravity, slow-falling, and levitation. `CollisionDetector.cs` resolves full AABB collisions against the block world including step-up, mirroring vanilla axis-separated resolution. `BlockShapes.cs` maps block-state IDs to collision AABBs using PrismarineJS data from `BlockShapeData.json`. `Vec3d.cs` and `Aabb.cs` provide the geometric primitives. `MovementInput.cs` captures player input state. | `Physics/PlayerPhysics.cs`, `Physics/PhysicsConsts.cs`, `Physics/CollisionDetector.cs`, `Physics/BlockShapes.cs`, `Physics/BlockShapeData.json`, `Physics/Vec3d.cs`, `Physics/Aabb.cs`, `Physics/MovementInput.cs` |
### Commands And Extensions
| Module | What It Owns | Important Files |
| --- | --- | --- |
| `MinecraftClient/Commands/` and `MinecraftClient/CommandHandler/` | Internal MCC command system built on Brigadier. Commands are discovered by reflection from `MinecraftClient.Commands` in `McClient.LoadCommands()`. Each file in `Commands/` registers one internal command. `ArgumentType/*.cs` provides typed Brigadier arguments and completion sources for accounts, bots, items, locations, scripts, inventories, and more. `Patch/*.cs` carries MCC-specific Brigadier extensions, and `CmdResult.cs` is the command execution result object. | `Command.cs`, `Commands/*.cs`, `CommandHandler/MccArguments.cs`, `CommandHandler/CmdResult.cs`, `CommandHandler/ArgumentType/*.cs`, `CommandHandler/Patch/*.cs` |
| `MinecraftClient/ChatBots/` | Built-in bots and bridges loaded from config through `McClient.RegisterBots()`. The folder mixes gameplay automation (`AutoAttack`, `AutoDig`, `AutoEat`, `AutoFishing`, `Farmer`), utility/logging bots (`ChatLog`, `PlayerListLogger`, `Alerts`), bridges (`DiscordBridge`, `TelegramBridge`, `RemoteControl`), and tooling like `ScriptScheduler`, `Map`, and `ReplayCapture`. | `ChatBots/AutoRelog.cs`, `ChatBots/Farmer.cs`, `ChatBots/FollowPlayer.cs`, `ChatBots/ItemsCollector.cs`, `ChatBots/Map.cs`, `ChatBots/RemoteControl.cs`, `ChatBots/ScriptScheduler.cs`, `ChatBots/DiscordBridge.cs`, `ChatBots/TelegramBridge.cs`, `ChatBots/ReplayCapture.cs` |
| `MinecraftClient/Scripting/` | Shared extension boundary for compiled bots and runtime C# scripts. `ChatBot.cs` is the main bot API and lifecycle surface. Built-in bots and `/script` bots use the same event model. `CSharpRunner.cs` parses `//MCCScript` files, compiles them with Roslyn, caches assemblies, and executes them through `CSharpAPI`. `DynamicRun/Builder/*` handles in-memory compilation/load-context plumbing, while `BotMovementLock.cs` coordinates movement ownership between automation pieces. | `Scripting/ChatBot.cs`, `Scripting/CSharpRunner.cs`, `Scripting/BotMovementLock.cs`, `Scripting/AssemblyResolver.cs`, `Scripting/DynamicRun/Builder/Compiler.cs`, `Scripting/DynamicRun/Builder/CompileRunner.cs` |
| `MinecraftClient/config/` | Sample runtime assets excluded from compilation. This is the examples/staging area for end-user scripts and standalone bots. `sample-script*.cs` shows supported `/script` patterns (basic, chatbot, world access, HTTP requests, tasks, PM forwarding, extended), while `config/ChatBots/*.cs` are copy/adapt examples rather than built-in bots. | `config/README.md`, `config/sample-script.cs`, `config/sample-script-with-chatbot.cs`, `config/sample-script-with-world-access.cs`, `config/sample-script-with-http-request.cs`, `config/sample-script-with-task.cs`, `config/ChatBots/*.cs` |
| `ConsoleInteractive/` | Required git submodule for richer line editing and console UI. MCC uses the submodule's `ConsoleReader`, `ConsoleWriter`, and suggestion UI from `ConsoleIO.cs` and `McClient.cs` when `BasicIO` is not enabled. | `ConsoleInteractive/README.md`, `ConsoleInteractive/ConsoleInteractive/ConsoleInteractive.sln` |
### Support And Tooling
| Module | What It Owns | Important Files |
| --- | --- | --- |
| `MinecraftClient/Logger/`, `MinecraftClient/Proxy/`, `MinecraftClient/Crypto/`, `MinecraftClient/Resources/`, `MinecraftClient/WinAPI/` | Support subsystems under the main app. Logging supports console/file output plus regex filtering. `ProxyHandler.cs` routes update/login/in-game traffic through HTTP or SOCKS proxies. `Crypto/` implements the stream ciphers needed for online-mode protocol encryption. `Resources/` contains UI strings, generated translation accessors, config help text, icons, and embedded Minecraft asset data. `WinAPI/` contains small Windows-only console helpers. | `Logger/FilteredLogger.cs`, `Logger/FileLogLogger.cs`, `Proxy/ProxyHandler.cs`, `Crypto/CryptoHandler.cs`, `Crypto/AesCfb8Stream.cs`, `Resources/Translations/Translations.resx`, `Resources/ConfigComments/ConfigComments.resx`, `Resources/en_us.json`, `WinAPI/ConsoleIcon.cs` |
| `docs/` | VuePress documentation site. `.vuepress/config.ts` sets bundler, theme, plugins, and redirects. `.vuepress/configs/**` holds locale and nav wiring. `guide/*.md` contains the user-facing install, usage, bot, and scripting docs. | `docs/.vuepress/config.ts`, `docs/.vuepress/configs/**`, `docs/guide/README.md`, `docs/guide/configuration.md`, `docs/guide/chat-bots.md`, `docs/guide/creating-bots.md`, `docs/guide/creating-text-script.md`, `docs/guide/ai-assisted-development.md` |
| `tools/` | Python helpers for Minecraft version adaptation and palette generation. `README.md` is the authoritative workflow. `diff_registries.py` compares versions and validates decompiled data against server reports. The `gen_*` scripts emit the versioned palette source files consumed by `Protocol/`, `Mapping/`, `Inventory/`, and `Physics/`. | `tools/README.md`, `tools/diff_registries.py`, `tools/gen_block_palette.py`, `tools/gen_item_palette.py`, `tools/gen_entity_palette.py`, `tools/gen_entity_metadata_palette.py`, `tools/gen_block_shapes.py`, `tools/gen_command_argument_registry.py` |
| `DebugTools/` | Standalone packet/proxy debugging utilities for inspecting traffic and compression behavior outside the main client runtime. | `DebugTools/MinecraftClientProxy/Program.cs`, `DebugTools/MinecraftClientProxy/PacketProxy.cs`, `DebugTools/MinecraftClientProxy/ZlibUtils.cs` |
| `MinecraftClientGUI/` | Legacy Windows GUI wrapper around the console app. WinForms shell that launches and communicates with the console executable; not part of the main `net10.0` runtime path. | `MinecraftClientGUI/Program.cs`, `MinecraftClientGUI/Form1.cs`, `MinecraftClientGUI/Form1.Designer.cs`, `MinecraftClientGUI/MinecraftClient.cs` |
## Engineering Guidance
Read `docs/guide/ai-assisted-development.md` before starting development work on MCC. It documents the full build-run-test loop, local server harness, repository tools, and standard workflows.
### DO
- Keep startup/config/auth logic in `Program` and connection runtime logic in `McClient` or `Protocol/*`.
- Update version support holistically: protocol constants, version mapping, packet palette, block palette, item palette, entity palette, metadata palette, and routing switches.
- Use `tools/` and authoritative server data reports when adapting to new Minecraft versions.
- Guard optional subsystems with `GetTerrainEnabled()`, `GetInventoryEnabled()`, and `GetEntityHandlingEnabled()` before using them.
- For built-in bots, wire all pieces together: bot class, `Settings.ChatBotConfigHealper`, and `McClient.RegisterBots()`.
- Keep `Initialize()` for setup/prereq checks and `AfterGameJoined()` for sending chat or commands.
- Normalize inbound chat with `GetVerbatim()` before `IsChatMessage()` / `IsPrivateMessage()`.
- Clean up commands, plugin channels, threads, timers, and movement locks in `OnUnload()`.
- Prefer nullable-aware code, pattern matching, `ArgumentNullException.ThrowIfNull`, `Try*` APIs for expected failures, and `InvokeOnMainThread()` for cross-thread state changes.
- Use modern C# 14 features.
- Use provided skills proactively depending on the context, read their descriptions to determine when to use them.
- All user-facing text (log messages, command output, TUI labels, notifications, help text, error messages) **must** go through the translation system: add entries to `Translations.resx` + `Translations.Designer.cs`, then reference `Translations.key_name` in code. Never hardcode user-visible strings directly in `.cs` files. Use `string.Format(Translations.key, ...)` for parameterized messages. Translation keys follow dot-delimited naming: `<module>.<scope>.<detail>` (e.g. `cmd.inventory.tui_opened`, `tui.inventory.controls`). Pure technical identifiers (class names, protocol constants, color codes) are exempt.
### DON'T
- Don't update only `MCVer2ProtocolVersion()` or only one palette file when adding a new Minecraft version.
- Don't send chat in `Initialize()`.
- Don't mutate inventory snapshots and expect server-side effects; use handler APIs/window actions.
- Don't bypass Brigadier with ad hoc command parsing.
- Never modify `ConsoleInteractive/`; treat it as an external required submodule.
- Don't start background workers when `Update()` or delayed tasks are sufficient; if you must, stop them on unload/disconnect.
- Don't leave movement locks, plugin channels, or dispatcher registrations behind.
- Don't trust older docs over current code for supported versions or feature gates. When AGENTS.md, skills, and older docs disagree, prefer current code and current tool behavior, then update the stale source.
- Don't hardcode user-facing strings (messages, labels, help text) directly in source code; always use `Translations.*` resources so the text can be localized.
- Never use "—" ("em dash"), unless specifically being instructed to do so!
- Never generate MCC config files (`.ini`) in the repo root. When `dotnet run --project MinecraftClient -- --help` is used to generate a config template, it writes `MinecraftClient.ini` to the current directory. Always run this command from a system temp directory (e.g. `mktemp -d`) or use `prepare_offline_mcc_config.sh` which already handles output routing.

Some files were not shown because too many files have changed in this diff Show more