ppsspp-dfx-mcp 0.1.2__tar.gz

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.
Files changed (337) hide show
  1. ppsspp_dfx_mcp-0.1.2/.github/workflows/ci.yml +53 -0
  2. ppsspp_dfx_mcp-0.1.2/.github/workflows/pypi-publish.yml +84 -0
  3. ppsspp_dfx_mcp-0.1.2/.gitignore +28 -0
  4. ppsspp_dfx_mcp-0.1.2/.mcp.json +15 -0
  5. ppsspp_dfx_mcp-0.1.2/CHANGELOG.md +54 -0
  6. ppsspp_dfx_mcp-0.1.2/CONTRIBUTING.md +138 -0
  7. ppsspp_dfx_mcp-0.1.2/LICENSE +21 -0
  8. ppsspp_dfx_mcp-0.1.2/PKG-INFO +347 -0
  9. ppsspp_dfx_mcp-0.1.2/README.md +319 -0
  10. ppsspp_dfx_mcp-0.1.2/SECURITY.md +35 -0
  11. ppsspp_dfx_mcp-0.1.2/docs/SCOPE.md +55 -0
  12. ppsspp_dfx_mcp-0.1.2/evals/.gitignore +4 -0
  13. ppsspp_dfx_mcp-0.1.2/evals/README.md +48 -0
  14. ppsspp_dfx_mcp-0.1.2/evals/config.yaml +18 -0
  15. ppsspp_dfx_mcp-0.1.2/evals/gates.py +384 -0
  16. ppsspp_dfx_mcp-0.1.2/evals/judge_prompt.md +34 -0
  17. ppsspp_dfx_mcp-0.1.2/evals/report.py +248 -0
  18. ppsspp_dfx_mcp-0.1.2/evals/rescore.py +59 -0
  19. ppsspp_dfx_mcp-0.1.2/evals/runner.py +617 -0
  20. ppsspp_dfx_mcp-0.1.2/evals/scenarios.yaml +378 -0
  21. ppsspp_dfx_mcp-0.1.2/evals/test_b2_skill.py +90 -0
  22. ppsspp_dfx_mcp-0.1.2/evals/test_gates.py +321 -0
  23. ppsspp_dfx_mcp-0.1.2/examples/addresses.yaml +51 -0
  24. ppsspp_dfx_mcp-0.1.2/examples/project.yaml +23 -0
  25. ppsspp_dfx_mcp-0.1.2/examples/scripts.manifest.yaml +42 -0
  26. ppsspp_dfx_mcp-0.1.2/pyproject.toml +74 -0
  27. ppsspp_dfx_mcp-0.1.2/scripts/_wire.py +243 -0
  28. ppsspp_dfx_mcp-0.1.2/scripts/audit_test_modules.py +112 -0
  29. ppsspp_dfx_mcp-0.1.2/scripts/check_env.py +265 -0
  30. ppsspp_dfx_mcp-0.1.2/scripts/dump_tool_surface.py +122 -0
  31. ppsspp_dfx_mcp-0.1.2/scripts/harness_latency_baseline.json +39 -0
  32. ppsspp_dfx_mcp-0.1.2/scripts/probe_boundary_matrix.py +1089 -0
  33. ppsspp_dfx_mcp-0.1.2/scripts/record_fixtures.py +269 -0
  34. ppsspp_dfx_mcp-0.1.2/scripts/report_schema_surface.py +240 -0
  35. ppsspp_dfx_mcp-0.1.2/scripts/verify_real_mcp.py +2001 -0
  36. ppsspp_dfx_mcp-0.1.2/scripts/verify_tool_layering_probes.py +171 -0
  37. ppsspp_dfx_mcp-0.1.2/skills/ppsspp-dfx/SKILL.md +94 -0
  38. ppsspp_dfx_mcp-0.1.2/skills/ppsspp-dfx/assets/ppsspp.ini.template +23 -0
  39. ppsspp_dfx_mcp-0.1.2/skills/ppsspp-dfx/references/architecture.md +84 -0
  40. ppsspp_dfx_mcp-0.1.2/skills/ppsspp-dfx/references/cpu-state-contract.md +121 -0
  41. ppsspp_dfx_mcp-0.1.2/skills/ppsspp-dfx/references/error-codes.md +75 -0
  42. ppsspp_dfx_mcp-0.1.2/skills/ppsspp-dfx/references/playbook/common/batch_automation.md +83 -0
  43. ppsspp_dfx_mcp-0.1.2/skills/ppsspp-dfx/references/playbook/common/crash_analysis.md +61 -0
  44. ppsspp_dfx_mcp-0.1.2/skills/ppsspp-dfx/references/playbook/common/gameplay_loop.md +107 -0
  45. ppsspp_dfx_mcp-0.1.2/skills/ppsspp-dfx/references/playbook/common/replay_recording.md +81 -0
  46. ppsspp_dfx_mcp-0.1.2/skills/ppsspp-dfx/references/playbook/common/screenshot.md +56 -0
  47. ppsspp_dfx_mcp-0.1.2/skills/ppsspp-dfx/references/playbook/common/smoke_test.md +58 -0
  48. ppsspp_dfx_mcp-0.1.2/skills/ppsspp-dfx/references/ppsspp-constraints.md +132 -0
  49. ppsspp_dfx_mcp-0.1.2/skills/ppsspp-dfx/references/tool-surface.md +135 -0
  50. ppsspp_dfx_mcp-0.1.2/skills/ppsspp-dfx/scripts/addr_convert.py +96 -0
  51. ppsspp_dfx_mcp-0.1.2/skills/ppsspp-dfx/scripts/decode_text.py +102 -0
  52. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/__init__.py +12 -0
  53. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/__main__.py +68 -0
  54. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/address.py +169 -0
  55. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/completions.py +140 -0
  56. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/config.py +239 -0
  57. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/core/__init__.py +1 -0
  58. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/core/batch_jobs.py +274 -0
  59. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/core/error_codes.py +77 -0
  60. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/core/game_state_observer.py +747 -0
  61. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/core/launcher.py +560 -0
  62. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/core/primitives.py +20 -0
  63. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/core/proc.py +78 -0
  64. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/core/registers.py +83 -0
  65. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/core/stepping.py +429 -0
  66. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/core/transport.py +479 -0
  67. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/core/ws_contract.py +1136 -0
  68. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/errors.py +738 -0
  69. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/instructions.py +83 -0
  70. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/logging.py +109 -0
  71. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/middleware.py +155 -0
  72. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/__init__.py +5 -0
  73. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/analyze.py +54 -0
  74. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/assemble.py +29 -0
  75. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/batch_step.py +149 -0
  76. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/breakpoint.py +29 -0
  77. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/evaluate.py +27 -0
  78. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/gpu_record.py +65 -0
  79. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/gpu_stats.py +81 -0
  80. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/input.py +55 -0
  81. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/memory.py +65 -0
  82. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/memory_info_search.py +53 -0
  83. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/memory_map.py +24 -0
  84. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/query.py +34 -0
  85. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/replay.py +230 -0
  86. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/screenshot.py +57 -0
  87. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/search_disasm.py +31 -0
  88. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/session.py +110 -0
  89. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/smoke.py +33 -0
  90. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/state_observer.py +93 -0
  91. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/step.py +39 -0
  92. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/workflow.py +87 -0
  93. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/models/write_register.py +26 -0
  94. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/prompts.py +167 -0
  95. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/recipes/__init__.py +7 -0
  96. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/resources.py +101 -0
  97. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/scripts/__init__.py +7 -0
  98. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/scripts/record_fixtures.py +154 -0
  99. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/server.py +641 -0
  100. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/service/__init__.py +11 -0
  101. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/service/capture.py +686 -0
  102. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/service/debug_client.py +1816 -0
  103. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/service/memory_protection.py +73 -0
  104. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/session/__init__.py +14 -0
  105. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/session/client_helper.py +433 -0
  106. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/session/safe_boot.py +170 -0
  107. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/session/session_manager.py +1312 -0
  108. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/spec/__init__.py +1 -0
  109. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/spec/script_manifest.py +356 -0
  110. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/__init__.py +8 -0
  111. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/_common.py +265 -0
  112. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/analyze.py +314 -0
  113. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/assemble.py +221 -0
  114. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/batch_step.py +710 -0
  115. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/breakpoint.py +422 -0
  116. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/evaluate.py +127 -0
  117. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/gpu_record.py +120 -0
  118. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/gpu_stats.py +89 -0
  119. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/input.py +415 -0
  120. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/introspect.py +124 -0
  121. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/list_addresses.py +150 -0
  122. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/memory.py +797 -0
  123. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/memory_info_search.py +141 -0
  124. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/memory_map.py +85 -0
  125. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/query.py +344 -0
  126. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/replay.py +519 -0
  127. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/screenshot.py +451 -0
  128. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/script.py +554 -0
  129. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/search_disasm.py +259 -0
  130. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/session.py +313 -0
  131. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/smoke.py +168 -0
  132. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/state_observer.py +410 -0
  133. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/step.py +211 -0
  134. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/workflows.py +565 -0
  135. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/tools/write_register.py +113 -0
  136. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/__init__.py +5 -0
  137. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/_base.py +52 -0
  138. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/_contract.py +145 -0
  139. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/analyze.py +65 -0
  140. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/assemble.py +84 -0
  141. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/batch_step.py +169 -0
  142. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/breakpoint.py +47 -0
  143. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/evaluate.py +50 -0
  144. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/gpu_record.py +82 -0
  145. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/gpu_stats.py +77 -0
  146. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/input.py +58 -0
  147. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/introspect.py +38 -0
  148. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/memory.py +198 -0
  149. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/memory_info_search.py +70 -0
  150. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/memory_map.py +79 -0
  151. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/query.py +125 -0
  152. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/replay.py +99 -0
  153. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/screenshot.py +93 -0
  154. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/script.py +173 -0
  155. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/search_disasm.py +69 -0
  156. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/session.py +152 -0
  157. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/smoke.py +39 -0
  158. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/state_observer.py +127 -0
  159. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/step.py +64 -0
  160. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/workflow.py +175 -0
  161. ppsspp_dfx_mcp-0.1.2/src/ppsspp_dfx_mcp/views/write_register.py +41 -0
  162. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/cpu.breakpoint.add.json +16 -0
  163. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/cpu.breakpoint.list.json +24 -0
  164. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/cpu.breakpoint.remove.json +15 -0
  165. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/cpu.getAllRegs.json +630 -0
  166. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/cpu.status.json +17 -0
  167. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/cpu.stepping.json +31 -0
  168. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/game.status.json +19 -0
  169. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/hle.func.add.json +19 -0
  170. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/hle.func.list.json +34685 -0
  171. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/hle.module.list.json +21 -0
  172. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/hle.thread.list.json +165 -0
  173. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/memory.base.json +14 -0
  174. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/memory.disasm.json +189 -0
  175. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/memory.mapping.json +127 -0
  176. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/memory.read.json +17 -0
  177. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/memory.readString.json +16 -0
  178. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/memory.read_u32.json +16 -0
  179. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/memory.searchDisasm.json +17 -0
  180. ppsspp_dfx_mcp-0.1.2/tests/cassettes/fixtures/version.json +15 -0
  181. ppsspp_dfx_mcp-0.1.2/tests/cassettes/real_ppsspp.jsonl +23 -0
  182. ppsspp_dfx_mcp-0.1.2/tests/conftest.py +93 -0
  183. ppsspp_dfx_mcp-0.1.2/tests/contract_recorder/__init__.py +201 -0
  184. ppsspp_dfx_mcp-0.1.2/tests/contract_recorder/fixture_loader.py +133 -0
  185. ppsspp_dfx_mcp-0.1.2/tests/contract_recorder/test_fixture_loader.py +238 -0
  186. ppsspp_dfx_mcp-0.1.2/tests/fake_transport/__init__.py +3 -0
  187. ppsspp_dfx_mcp-0.1.2/tests/fake_transport/fake_transport.py +306 -0
  188. ppsspp_dfx_mcp-0.1.2/tests/fake_transport/test_fake_transport.py +379 -0
  189. ppsspp_dfx_mcp-0.1.2/tests/fake_transport/test_write_overlay.py +69 -0
  190. ppsspp_dfx_mcp-0.1.2/tests/integration/__init__.py +0 -0
  191. ppsspp_dfx_mcp-0.1.2/tests/integration/conftest.py +625 -0
  192. ppsspp_dfx_mcp-0.1.2/tests/integration/test_check_cpu_state_rewire.py +257 -0
  193. ppsspp_dfx_mcp-0.1.2/tests/integration/test_game_state_observer_integration.py +796 -0
  194. ppsspp_dfx_mcp-0.1.2/tests/integration/test_lifespan_integration.py +212 -0
  195. ppsspp_dfx_mcp-0.1.2/tests/integration/test_mcp_inspector_e2e.py +312 -0
  196. ppsspp_dfx_mcp-0.1.2/tests/integration/test_mem_bp_range_watch.py +41 -0
  197. ppsspp_dfx_mcp-0.1.2/tests/integration/test_real_mcp_matrix.py +126 -0
  198. ppsspp_dfx_mcp-0.1.2/tests/integration/test_real_ppsspp_e2e.py +324 -0
  199. ppsspp_dfx_mcp-0.1.2/tests/integration/test_record_replay_roundtrip.py +319 -0
  200. ppsspp_dfx_mcp-0.1.2/tests/integration/test_script_exposure_sync.py +436 -0
  201. ppsspp_dfx_mcp-0.1.2/tests/integration/test_script_manifest_integration.py +223 -0
  202. ppsspp_dfx_mcp-0.1.2/tests/integration/test_session_lifecycle_integration.py +275 -0
  203. ppsspp_dfx_mcp-0.1.2/tests/mcp_inspector/__init__.py +15 -0
  204. ppsspp_dfx_mcp-0.1.2/tests/mcp_inspector/conftest.py +206 -0
  205. ppsspp_dfx_mcp-0.1.2/tests/mcp_inspector/test_protocol_surface.py +119 -0
  206. ppsspp_dfx_mcp-0.1.2/tests/mcp_inspector/test_resources_prompts.py +66 -0
  207. ppsspp_dfx_mcp-0.1.2/tests/mcp_inspector/test_server_lifecycle.py +124 -0
  208. ppsspp_dfx_mcp-0.1.2/tests/mcp_inspector/test_tools_call.py +119 -0
  209. ppsspp_dfx_mcp-0.1.2/tests/mcp_inspector/test_tools_call_unknown.py +66 -0
  210. ppsspp_dfx_mcp-0.1.2/tests/mcp_inspector/test_tools_list.py +122 -0
  211. ppsspp_dfx_mcp-0.1.2/tests/record_replay/__init__.py +40 -0
  212. ppsspp_dfx_mcp-0.1.2/tests/record_replay/cassette.py +146 -0
  213. ppsspp_dfx_mcp-0.1.2/tests/record_replay/recording_transport.py +213 -0
  214. ppsspp_dfx_mcp-0.1.2/tests/record_replay/replay_transport.py +330 -0
  215. ppsspp_dfx_mcp-0.1.2/tests/record_replay/test_cassette_format.py +280 -0
  216. ppsspp_dfx_mcp-0.1.2/tests/record_replay/test_recording_transport.py +250 -0
  217. ppsspp_dfx_mcp-0.1.2/tests/record_replay/test_replay_transport.py +450 -0
  218. ppsspp_dfx_mcp-0.1.2/tests/unit/core/__init__.py +0 -0
  219. ppsspp_dfx_mcp-0.1.2/tests/unit/core/test_address.py +333 -0
  220. ppsspp_dfx_mcp-0.1.2/tests/unit/core/test_config_validate.py +54 -0
  221. ppsspp_dfx_mcp-0.1.2/tests/unit/core/test_launcher.py +767 -0
  222. ppsspp_dfx_mcp-0.1.2/tests/unit/core/test_registers_normalize.py +41 -0
  223. ppsspp_dfx_mcp-0.1.2/tests/unit/l1_contract/__init__.py +0 -0
  224. ppsspp_dfx_mcp-0.1.2/tests/unit/l1_contract/conftest.py +100 -0
  225. ppsspp_dfx_mcp-0.1.2/tests/unit/l1_contract/test_breakpoint_calls.py +169 -0
  226. ppsspp_dfx_mcp-0.1.2/tests/unit/l1_contract/test_contract_param_shapes.py +227 -0
  227. ppsspp_dfx_mcp-0.1.2/tests/unit/l1_contract/test_cpu_calls.py +130 -0
  228. ppsspp_dfx_mcp-0.1.2/tests/unit/l1_contract/test_disasm_calls.py +90 -0
  229. ppsspp_dfx_mcp-0.1.2/tests/unit/l1_contract/test_gpu_calls.py +322 -0
  230. ppsspp_dfx_mcp-0.1.2/tests/unit/l1_contract/test_hle_calls.py +107 -0
  231. ppsspp_dfx_mcp-0.1.2/tests/unit/l1_contract/test_input_calls.py +110 -0
  232. ppsspp_dfx_mcp-0.1.2/tests/unit/l1_contract/test_memory_calls.py +211 -0
  233. ppsspp_dfx_mcp-0.1.2/tests/unit/l1_contract/test_r15_error_code_prefix.py +66 -0
  234. ppsspp_dfx_mcp-0.1.2/tests/unit/l1_contract/test_replay_calls.py +212 -0
  235. ppsspp_dfx_mcp-0.1.2/tests/unit/l1_contract/test_step_calls.py +123 -0
  236. ppsspp_dfx_mcp-0.1.2/tests/unit/l1_contract/test_system_calls.py +95 -0
  237. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/__init__.py +0 -0
  238. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/conftest.py +71 -0
  239. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_address_param_type_contract.py +214 -0
  240. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_ai_usability_schema_contract.py +76 -0
  241. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_boundary_fullstack.py +259 -0
  242. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_boundary_semantics.py +121 -0
  243. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_capabilities_contract.py +121 -0
  244. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_completion_contract.py +197 -0
  245. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_defect_regression_locks.py +145 -0
  246. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_error_code_contract.py +164 -0
  247. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_error_contract.py +126 -0
  248. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_exposed_wrapper_structured.py +71 -0
  249. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_health_response_contract.py +151 -0
  250. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_instructions_contract.py +209 -0
  251. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_layering_tripwire.py +73 -0
  252. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_lock_contract_tripwire.py +177 -0
  253. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_memory_protection.py +108 -0
  254. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_output_schema_contract.py +425 -0
  255. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_query_top_n_default.py +62 -0
  256. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_reload_scripts_notification_contract.py +207 -0
  257. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_replay_registry.py +200 -0
  258. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_resources_prompts_contract.py +145 -0
  259. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_response_shape.py +79 -0
  260. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_schema_runtime_consistency.py +80 -0
  261. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_tool_annotations_contract.py +200 -0
  262. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_tool_registry_contract.py +311 -0
  263. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_tool_signature_contract.py +132 -0
  264. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_tool_surface_baseline.py +159 -0
  265. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_view_address_field_type_contract.py +336 -0
  266. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/test_ws_contract_coverage.py +127 -0
  267. ppsspp_dfx_mcp-0.1.2/tests/unit/l2_mcp_contract/tool_surface_baseline.json +837 -0
  268. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/__init__.py +0 -0
  269. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/conftest.py +120 -0
  270. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_capability_extensions.py +161 -0
  271. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_capture_service_orchestration.py +344 -0
  272. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_confirm_step_orchestration.py +270 -0
  273. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_error_translation_batch5.py +266 -0
  274. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_extract_pc_contract.py +299 -0
  275. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_image_tools_persistence.py +212 -0
  276. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_memory_protocol_adapter.py +366 -0
  277. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_output_governance_batch3.py +555 -0
  278. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_ppsspp_log_mirror.py +109 -0
  279. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_queue_consumer_exclusivity.py +120 -0
  280. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_read_output_modes.py +164 -0
  281. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_reconnect_handshake.py +121 -0
  282. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_resilient_start.py +294 -0
  283. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_resolve_session_id.py +101 -0
  284. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_resume_stale_broadcast.py +85 -0
  285. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_s1_scan_pattern_cap.py +125 -0
  286. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_s1_step_broadcast_routing.py +208 -0
  287. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_safety_guards_batch4.py +756 -0
  288. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_scan_memory_orchestration.py +434 -0
  289. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_search_disasm_protocol_adapter.py +226 -0
  290. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_session_manager_orchestration.py +1392 -0
  291. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_session_restored_flag.py +99 -0
  292. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_session_serialization.py +166 -0
  293. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_session_start_wait_ready.py +110 -0
  294. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_session_transport_robustness.py +212 -0
  295. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_state_sync_batch6.py +350 -0
  296. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_step_pause_pc_orchestration.py +211 -0
  297. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_stepping_fanout.py +193 -0
  298. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_transport_orchestration.py +796 -0
  299. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_transport_resilience.py +116 -0
  300. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_trust_level_decisions.py +207 -0
  301. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_wait_ready_probe.py +136 -0
  302. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_with_stepping_orchestration.py +469 -0
  303. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_workflows_tools.py +410 -0
  304. ppsspp_dfx_mcp-0.1.2/tests/unit/l3_orchestration/test_ws_protocol_fidelity.py +210 -0
  305. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/__init__.py +0 -0
  306. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/conftest.py +63 -0
  307. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_batch_background.py +683 -0
  308. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_batch_step_invariants.py +371 -0
  309. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_capture_encapsulation.py +176 -0
  310. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_clut_params.py +97 -0
  311. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_confirm_step_broadcast.py +410 -0
  312. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_confirm_step_single_poll.py +135 -0
  313. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_disasm_no_disasm_fallback.py +86 -0
  314. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_freeze_misjudgment_fix.py +718 -0
  315. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_func_remove_no_name.py +70 -0
  316. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_gpu_record_dump_uri.py +88 -0
  317. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_impl_spec_consistency.py +206 -0
  318. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_mem_bp_add_change.py +102 -0
  319. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_mem_bp_always_send_bools.py +157 -0
  320. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_mem_bp_size.py +95 -0
  321. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_memory_info_search_extent.py +80 -0
  322. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_memory_map_no_mapping_wrapper.py +140 -0
  323. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_no_silent_exception.py +154 -0
  324. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_optional_params_exposed.py +312 -0
  325. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_output_screenshot_alpha_stackwidth.py +134 -0
  326. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_press_button_duration_default.py +75 -0
  327. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_read_bytes_no_data_fallback.py +86 -0
  328. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_read_string_signature.py +94 -0
  329. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_replay_invariants.py +587 -0
  330. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_replay_p1_file_io.py +678 -0
  331. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_replay_r2r3r4.py +244 -0
  332. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_spec_protocol_consistency.py +128 -0
  333. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_state_observer_invariants.py +372 -0
  334. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_step_stale_broadcast_filter.py +373 -0
  335. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_texture_params.py +101 -0
  336. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_thread_param_passthrough.py +202 -0
  337. ppsspp_dfx_mcp-0.1.2/tests/unit/l4_regression/test_tool_debugclient_consistency.py +148 -0
@@ -0,0 +1,53 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ test:
12
+ name: pytest (${{ matrix.os }}, py${{ matrix.python-version }})
13
+ runs-on: ${{ matrix.os }}
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ os: [ubuntu-latest, windows-latest, macos-latest]
18
+ # 单版本策略:SDK v2 导入路径依赖 3.14 新特性(见 pyproject
19
+ # requires-python)。放宽到矩阵多版本前先解除该耦合。
20
+ python-version: ["3.14"]
21
+
22
+ steps:
23
+ - uses: actions/checkout@v5
24
+
25
+ - name: Setup Python ${{ matrix.python-version }}
26
+ uses: actions/setup-python@v5
27
+ with:
28
+ python-version: ${{ matrix.python-version }}
29
+
30
+ - name: Install (editable, with dev extras)
31
+ run: pip install -e .[dev]
32
+
33
+ - name: Sanity — entry point importable
34
+ run: python -c "import ppsspp_dfx_mcp; print('import ok')"
35
+
36
+ # 集成测试中需要真实 PPSSPP / ISO 的用例按设计自动 skip;
37
+ # 其余(单元 + 契约 + fixture 化集成)必须三平台全绿。
38
+ - name: Run test suite
39
+ run: python -m pytest tests -q
40
+
41
+ ci-ok:
42
+ name: ci-ok
43
+ needs: test
44
+ runs-on: ubuntu-latest
45
+ if: ${{ always() }}
46
+ steps:
47
+ - name: Verify all matrix legs passed
48
+ run: |
49
+ if [ "${{ needs.test.result }}" != "success" ]; then
50
+ echo "matrix did not fully succeed: ${{ needs.test.result }}"
51
+ exit 1
52
+ fi
53
+ echo "all matrix legs passed"
@@ -0,0 +1,84 @@
1
+ name: Publish to PyPI
2
+
3
+ # 两段式发布:
4
+ # 阶段一 push tag v* → 构建 + 试发布到 TestPyPI,验证无误后再进阶段二
5
+ # 阶段二 GitHub Release 发布 → 同一 tag 重新构建 + 正式发布到 pypi.org
6
+ # 两阶段共用本文件:两平台 Trusted Publisher 注册均为
7
+ # workflow 文件名 = pypi-publish.yml / environment = pypi(OIDC,不用 API token)。
8
+ # 人工门禁 = 阶段二的 Release 发布按钮;因此不要在 GitHub 的 pypi 环境
9
+ # 上加 Required reviewers,否则阶段一也会被卡。
10
+
11
+ on:
12
+ push:
13
+ tags:
14
+ - "v*"
15
+ release:
16
+ types: [published]
17
+
18
+ permissions:
19
+ contents: read
20
+ id-token: write
21
+
22
+ jobs:
23
+ publish-testpypi:
24
+ name: build & publish → test.pypi.org
25
+ if: github.event_name == 'push'
26
+ runs-on: ubuntu-latest
27
+ environment: pypi
28
+ steps:
29
+ - uses: actions/checkout@v5
30
+
31
+ - name: Setup Python
32
+ uses: actions/setup-python@v5
33
+ with:
34
+ python-version: "3.14"
35
+
36
+ - name: Guard — tag 与 pyproject 版本一致
37
+ run: |
38
+ TAG="${GITHUB_REF_NAME#v}"
39
+ FILE=$(python -c "import tomllib;print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
40
+ if [ "$TAG" != "$FILE" ]; then
41
+ echo "::error::tag v$TAG 与 pyproject.toml 版本 $FILE 不一致"
42
+ exit 1
43
+ fi
44
+
45
+ - name: Build sdist & wheel
46
+ run: |
47
+ pip install build
48
+ python -m build
49
+
50
+ - name: Publish to TestPyPI
51
+ uses: pypa/gh-action-pypi-publish@release/v1
52
+ with:
53
+ # 缺省时该 action 上传到正式 PyPI;TestPyPI 必须显式指定。
54
+ repository-url: https://test.pypi.org/legacy/
55
+
56
+ publish-pypi:
57
+ name: build & publish → pypi.org
58
+ if: github.event_name == 'release'
59
+ runs-on: ubuntu-latest
60
+ environment: pypi
61
+ steps:
62
+ - uses: actions/checkout@v5
63
+
64
+ - name: Setup Python
65
+ uses: actions/setup-python@v5
66
+ with:
67
+ python-version: "3.14"
68
+
69
+ - name: Guard — tag 与 pyproject 版本一致
70
+ run: |
71
+ TAG="${GITHUB_REF_NAME#v}"
72
+ FILE=$(python -c "import tomllib;print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
73
+ if [ "$TAG" != "$FILE" ]; then
74
+ echo "::error::tag v$TAG 与 pyproject.toml 版本 $FILE 不一致"
75
+ exit 1
76
+ fi
77
+
78
+ - name: Build sdist & wheel
79
+ run: |
80
+ pip install build
81
+ python -m build
82
+
83
+ - name: Publish to PyPI
84
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,28 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+
8
+ # Tooling caches
9
+ .mypy_cache/
10
+ .pytest_cache/
11
+ .ruff_cache/
12
+ .coverage
13
+ htmlcov/
14
+
15
+ # Virtual environments
16
+ .venv/
17
+ venv/
18
+
19
+ # Local secrets (evals LLM endpoint config — never commit)
20
+ evals/llm_api.json
21
+
22
+ # Runtime output of the debug toolchain
23
+ .ppsspp-dfx/
24
+
25
+ # Editor / OS
26
+ .vscode/
27
+ .idea/
28
+ .DS_Store
@@ -0,0 +1,15 @@
1
+ {
2
+ "mcpServers": {
3
+ "ppsspp-dfx": {
4
+ "command": ".venv/ppsspp-dfx-mcp/Scripts/python.exe",
5
+ "args": [
6
+ "-m",
7
+ "ppsspp_dfx_mcp"
8
+ ],
9
+ "cwd": "${CLAUDE_PROJECT_DIR}",
10
+ "env": {
11
+ "PPSSPP_DFX_LOG_LEVEL": "INFO"
12
+ }
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,54 @@
1
+ # 更新日志
2
+
3
+ 本项目的所有显著变更将记录在此文件。
4
+
5
+ 格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
6
+ 版本遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.2] - 2026-09-17
11
+
12
+ ### Fixed
13
+
14
+ - MCP 握手的 serverInfo 版本改为从包元数据读取(`importlib.metadata`),
15
+ 消除 `__init__.py` 中与 pyproject 脱节的硬编码副本——0.1.1 曾在协议层
16
+ 自报 0.1.0。
17
+ - README:Windows 的 venv 创建命令更正为 `py -3.14`
18
+ (`python3.14` 别名在 Windows 上通常不存在)。
19
+
20
+ ## [0.1.1] - 2026-09-17
21
+
22
+ ### Added
23
+
24
+ - **配置模板三件套**(`examples/`):`project.yaml` / `addresses.yaml` /
25
+ `scripts.manifest.yaml` 可拷贝模板,PLACEHOLDER 标注 + 逐字段语义注释,
26
+ 独立部署时 `mkdir -p .ppsspp-dfx/config && cp examples/*.yaml
27
+ .ppsspp-dfx/config/` 即可起步。
28
+ - **预置 `.mcp.json`**:独立 checkout 的开箱即用 MCP 客户端注册。
29
+ - `check_env.py --check` 对 `scripts.manifest.yaml` 缺失显式告警(非阻断)
30
+ 并给出 examples 修复路径——此前缺失会导致 `ppsspp_script_*` 工具静默消失。
31
+ - **README 新增「故障排查速查表」与「已知限制」**:错误码体系的症状级
32
+ 索引 + 协议面边界的诚实汇总。
33
+ - **`docs/SCOPE.md`**:PPSSPP WS 事件 → 工具映射的人读版 + 刻意未工具化
34
+ 事件清单(机器可读真相源仍为 `ws_contract.py`)。
35
+ - 随包 `.github/workflows/`:三平台测试矩阵(CI)与两段式发布工作流——
36
+ push tag `v*` 构建并试发布(内部验证),确认后发布 GitHub Release 正式
37
+ 上架 PyPI;两阶段均为 trusted publishing(OIDC),内置 tag/版本一致性 Guard。
38
+
39
+ ### Changed
40
+
41
+ - README 定位为中文社区发布;代码注释与工具 docstring 保持英文
42
+ (协议面被工具面基线锁定)。
43
+ - README 参考 deepseek-harness 的官方 README 结构重构为发布版形态:
44
+ PyPI 安装为主路径(含安装后的 `.mcp.json` 与命令示例),新增项目状态、
45
+ 致谢与引用节。
46
+
47
+ ## [0.1.0] - 2026-09-16
48
+
49
+ ### Added
50
+
51
+ - 首个开源发布版本:41 个静态 MCP 工具(全结构化 inputSchema/outputSchema)、
52
+ 动态诊断脚本工具(manifest 驱动)、多会话管理与楔死自愈、后台批处理、
53
+ 原生 replay 录制回放、GPU 缓冲/纹素/CLUT 转储、HLE 内省、盲测评估体系
54
+ (21 场景卡 + 确定性门禁)。
@@ -0,0 +1,138 @@
1
+ # Contributing to ppsspp-dfx-mcp
2
+
3
+ Thanks for your interest in improving the project. This document defines the
4
+ documentation and comment conventions every source file must follow, plus the
5
+ practical notes for getting a development environment running.
6
+
7
+ ## Development setup
8
+
9
+ The server requires an isolated venv: it imports MCP SDK v2
10
+ (`mcp.server.mcpserver`), which cannot coexist with the 1.x `mcp` package that
11
+ many other MCP servers pin.
12
+
13
+ ```bash
14
+ # From the repository root — creates .venv/ppsspp-dfx-mcp and installs
15
+ # (editable, with dev extras):
16
+ python scripts/check_env.py --bootstrap
17
+
18
+ # Verify interpreter / SDK version / package import:
19
+ python scripts/check_env.py --check
20
+
21
+ # Run the test suite:
22
+ .venv/ppsspp-dfx-mcp/Scripts/python -m pytest tests -q # Windows
23
+ .venv/ppsspp-dfx-mcp/bin/python -m pytest tests -q # POSIX
24
+ ```
25
+
26
+ ## Module docstrings (file headers)
27
+
28
+ Every module opens with a short docstring that answers **what this is, why it
29
+ exists (only if non-obvious), and the key contract or invariant** a reader
30
+ must know before changing it. Rules:
31
+
32
+ 1. **Length**: aim for ≤ 10 lines. A header that needs more than that usually
33
+ means the module is doing too much.
34
+ 2. **No history.** Never reference when or why a change happened, no dates,
35
+ no change IDs (`W1 fix`, `D-19`, `R15`, `建议3`, `review issue #N`,
36
+ `spike U2`, `acceptance 7`, `Phase 2`, `A1/A2`…). That information lives in
37
+ version control.
38
+ 3. **No dead links.** Reference only documentation that ships with the
39
+ project (this file, `tests/`, tool docstrings). Do not link to workspace
40
+ planning/analysis documents — if the underlying fact matters, state the
41
+ fact itself in one line instead.
42
+ 4. **Tool modules** list the tools they expose with one line each.
43
+
44
+ Example:
45
+
46
+ ```python
47
+ """Memory tool wrappers.
48
+
49
+ 3 tools exposed:
50
+ - ppsspp_read_memory(action, ...) — aggregate read (bytes/u32/string/scan)
51
+ - ppsspp_write_memory(address, data, format?) — write u32 or bytes
52
+ - ppsspp_disassemble(address, count?) — disassemble N instructions
53
+
54
+ Reads and writes go through the session's debug client; protected ranges
55
+ (kernel, top.prx code) reject writes unless force=True.
56
+ """
57
+ ```
58
+
59
+ ## Inline comments
60
+
61
+ A comment earns its place only when it states a constraint the code cannot
62
+ show: a non-obvious invariant, a race condition, a protocol quirk, an order of
63
+ operations that must not change.
64
+
65
+ 1. **No changelog comments.** Same rule as headers — no fix IDs, no dates, no
66
+ issue numbers, no "this used to be X". If the old behaviour matters, the
67
+ constraint it produced is what you write down.
68
+ 2. **Explain why, not what.** `# increment retry counter` is noise;
69
+ `# the probe must run before the handshake or PPSSPP answers with an
70
+ empty frame` is a comment.
71
+ 3. Placement: own line above the code it governs.
72
+
73
+ ## Tool docstrings are protocol surface
74
+
75
+ The docstring of each tool function in `src/ppsspp_dfx_mcp/tools/` is the
76
+ description the MCP client shows to models. It follows the
77
+ PURPOSE / USAGE / BEHAVIOR / RETURNS convention and is locked by a contract
78
+ test against a committed baseline. **Do not reword tool docstrings** in
79
+ refactors: changing them changes the tool surface every client sees. Treat
80
+ them like a public API.
81
+
82
+ ## Tests
83
+
84
+ - New behaviour needs a test next to the layer it belongs to
85
+ (`tests/unit/…` mirroring `src/`, contract tests in
86
+ `tests/unit/l2_mcp_contract/`).
87
+ - Test names describe the behaviour they lock in; the module docstring may
88
+ summarise what a test file locks in, under the same no-history rules.
89
+
90
+ ## Pull requests
91
+
92
+ - Keep the change surgical: every line should trace back to the purpose of
93
+ the PR.
94
+ - Run the full test suite before pushing.
95
+ - If a change touches tool signatures, descriptions, or output contracts,
96
+ regenerate the tool-surface baseline
97
+ (`scripts/dump_tool_surface.py`) **in the same commit** and say so in the
98
+ description.
99
+
100
+ ## File naming
101
+
102
+ - `scripts/` executables: verb-first snake_case — `<verb>_<object>.py`
103
+ (`dump_tool_surface.py`, `check_env.py`, `record_fixtures.py`).
104
+ Private helpers take a leading underscore (`_wire.py`); data files keep a
105
+ descriptive name with their real extension.
106
+ - `evals/` modules: snake_case, one purpose per module; tests follow
107
+ `test_<subject>.py`.
108
+ - Evaluation reports are development-process artifacts and are NOT
109
+ committed to this repository: `report-<topic>-<YYYYMMDD>.md`.
110
+
111
+ ## Test layers
112
+
113
+ `tests/unit` is organized in four layers — place a new test by what it
114
+ locks, not by where similar-looking code lives:
115
+
116
+ | Layer | Locks | A test belongs here when… |
117
+ |---|---|---|
118
+ | `unit/core` | Domain primitives | The pure function/class under `core/` (parsers, address math, path resolution) |
119
+ | `unit/l1_contract` | PPSSPP wire contract | The shape/semantics of a WS event as the transport sees it |
120
+ | `unit/l2_mcp_contract` | MCP tool surface | Tool signatures, descriptions, schemas, error codes, annotations |
121
+ | `unit/l3_orchestration` | Session/transport orchestration | Multi-component behaviour across session manager, client helper, observers |
122
+ | `unit/l4_regression` | One historical defect per file | A specific shipped bug must never reappear |
123
+
124
+ `tests/integration/` requires a real PPSSPP + ISO (auto-skips when absent);
125
+ its modules are marked `integration` + `real_ppsspp`.
126
+
127
+ ## Testing conventions
128
+
129
+ - **Does-not-raise tests**: calling the function bare is accepted, but if it
130
+ returns a value, assert it (`assert fn(...) is None`). A bare call cannot
131
+ distinguish "returned None" from "returned garbage".
132
+ - **Patching `is_pid_alive`**: production reads it as
133
+ `proc.is_pid_alive(...)` (module attribute) — patch
134
+ `ppsspp_dfx_mcp.core.proc.is_pid_alive`, never a stale re-export.
135
+ - **Tool-surface baseline**: `tests/unit/l2_mcp_contract/tool_surface_baseline.json`
136
+ snapshots the *static* registry (41 tools). Manifest scripts add dynamic
137
+ `ppsspp_script_*` tools at runtime, so a live server's `tool_count` is
138
+ baseline + manifest count.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ppsspp-dfx-mcp contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.