romdevtools 0.22.0 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ All notable changes to `romdevtools`. Dates are release dates.
4
4
  (Published as `romdev-mcp` through 0.11.0; renamed to `romdevtools` in 0.13.0 —
5
5
  the `romdev-mcp` bin is kept as an alias.)
6
6
 
7
+ ## 0.22.1
8
+
9
+ Doc-only follow-up to 0.22.0's movement-analysis feedback: the `pressDuring`
10
+ schema on `watch` and `breakpoint` now states that entries with OVERLAPPING
11
+ windows on the same port are OR'd into a chord (e.g. `b`+`right` held while `a`
12
+ fires mid-window), not overwritten. The driver already behaved this way; this
13
+ documents the guarantee so it doesn't have to be confirmed empirically.
14
+
7
15
  ## 0.22.0
8
16
 
9
17
  **Transparency + correctness pass: every tool failure is actionable, dangerous
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "romdevtools",
3
- "version": "0.22.0",
3
+ "version": "0.22.1",
4
4
  "description": "Tool server giving coding agents full control of homebrew ROM development AND reverse-engineering/romhacking across 14 retro platforms (NES, SNES, GB, Genesis, Atari, C64, PC Engine, MSX, ...) via WASM toolchains + emulator cores. Use over plain HTTP, as an Agent Skill, or as an MCP server.",
5
5
  "type": "module",
6
6
  "main": "src/mcp/server.js",
@@ -761,7 +761,7 @@ export function registerWatchMemoryTools(server, z, sessionKey) {
761
761
  button: z.string(),
762
762
  port: z.number().int().min(0).max(3).default(0),
763
763
  holdFrames: z.number().int().min(1).default(2),
764
- })).optional().describe("Schedule input while waiting (drive the game to the state that triggers the condition). If OMITTED, this run inherits whatever input({op:'set'}) last held — same as frame({op:'step'}). If GIVEN, the schedule OWNS the pad for the whole run (a prior input({op:'set'}) is ignored); use it to drive the watched window itself."),
764
+ })).optional().describe("Schedule input while waiting (drive the game to the state that triggers the condition). If OMITTED, this run inherits whatever input({op:'set'}) last held — same as frame({op:'step'}). If GIVEN, the schedule OWNS the pad for the whole run (a prior input({op:'set'}) is ignored); use it to drive the watched window itself. Entries with OVERLAPPING windows on the same port are OR'd into a chord (e.g. b+right held while a fires mid-window), not overwritten."),
765
765
  abortIf: z.array(z.object({
766
766
  region: z.enum(MEMORY_REGIONS).optional().describe("memory region (default system_ram)"),
767
767
  offset: z.number().int().min(0).describe("byte offset within the region"),
@@ -1040,7 +1040,7 @@ export function registerWatchMemoryTools(server, z, sessionKey) {
1040
1040
  button: z.string(),
1041
1041
  port: z.number().int().min(0).max(3).default(0),
1042
1042
  holdFrames: z.number().int().min(1).default(2),
1043
- })).optional().describe("Schedule input while watching (drive the game to the state that touches the watched bytes/range, or uploads the graphic for on:'dma'). If OMITTED, this run inherits whatever input({op:'set'}) last held — same as frame({op:'step'}). If GIVEN, the schedule OWNS the pad for the whole run (a prior input({op:'set'}) is ignored)."),
1043
+ })).optional().describe("Schedule input while watching (drive the game to the state that touches the watched bytes/range, or uploads the graphic for on:'dma'). If OMITTED, this run inherits whatever input({op:'set'}) last held — same as frame({op:'step'}). If GIVEN, the schedule OWNS the pad for the whole run (a prior input({op:'set'}) is ignored). Entries with OVERLAPPING windows on the same port are OR'd into a chord (e.g. b+right held while a fires mid-window), not overwritten."),
1044
1044
  fromState: z.string().optional().describe("on:'range'/'pc' — restore an in-memory savestate SLOT (from state({op:'save', name})) BEFORE tracing, so the log runs from a known moment (jump to the boss fight, then see what writes HP). Deterministic + repeatable."),
1045
1045
  fromStatePath: z.string().optional().describe("on:'range'/'pc' — like fromState but restore from a savestate FILE on disk (state({op:'save', path})). Relative path resolves against the loaded ROM's dir."),
1046
1046
  },