nexforge-cli 0.4.1__tar.gz → 0.7.0__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 (344) hide show
  1. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/PKG-INFO +9 -8
  2. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/README.md +9 -8
  3. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/config.example.toml +26 -0
  4. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/doc//351/241/271/347/233/256/346/200/273/347/233/221/345/276/252/347/216/257-/345/274/200/345/217/221/350/256/241/345/210/222.md +187 -172
  5. nexforge_cli-0.7.0/docs/decisions/2026-09-12-/347/233/256/346/240/207/346/250/241/345/274/217/345/244/261/350/264/245/345/217/257/350/247/201/344/270/216/345/216/206/345/217/262/344/277/235/345/205/250.md +176 -0
  6. nexforge_cli-0.7.0/docs/decisions/2026-09-12-/347/255/211/345/276/205/345/267/245/345/205/267/344/270/216/350/266/205/346/227/266/345/217/257/350/261/201/345/205/215.md +127 -0
  7. nexforge_cli-0.7.0/docs/decisions/2026-09-12-/350/277/233/347/250/213/346/240/221/347/273/210/346/255/242.md +65 -0
  8. nexforge_cli-0.7.0/docs/decisions/2026-09-13-MCP/346/216/245/345/205/245.md +74 -0
  9. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/decisions/README.md +5 -1
  10. nexforge_cli-0.7.0/docs/evidence/release-0.4.1.log +48 -0
  11. nexforge_cli-0.7.0/docs/evidence/release-0.5.0.log +76 -0
  12. nexforge_cli-0.7.0/docs/evidence/wait-tool.log +144 -0
  13. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/submission/README-/346/212/225/347/250/277/350/257/264/346/230/216.md +1 -1
  14. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/submission/nexforge.zh-CN.md +1 -1
  15. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/manual/01-/345/256/211/350/243/205/344/270/216/351/205/215/347/275/256.md +1 -1
  16. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/manual/02-/347/225/214/351/235/242/344/270/216/345/277/253/346/215/267/351/224/256.md +4 -2
  17. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/manual/04-/345/267/245/345/205/267/345/217/202/350/200/203.md +21 -2
  18. nexforge_cli-0.7.0/manual/06-/346/235/203/351/231/220/344/270/216/346/250/241/345/274/217.md +104 -0
  19. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/manual/08-/350/207/252/345/256/232/344/271/211/351/205/215/347/275/256.md +3 -1
  20. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/manual/09-/345/270/270/350/247/201/351/227/256/351/242/230.md +26 -0
  21. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/manual/10-/346/217/222/344/273/266/345/274/200/345/217/221.md +10 -1
  22. nexforge_cli-0.7.0/manual/12-MCP/346/216/245/345/205/245.md +107 -0
  23. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/manual/README.md +4 -3
  24. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/manual//351/231/204/345/275/225-/345/257/271/346/257/224/345/210/206/346/236/220.md +1 -1
  25. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_speech_summary/speech_summary.py +328 -15
  26. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/pyproject.toml +11 -1
  27. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/gates/registry_consistency.py +2 -0
  28. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/__init__.py +1 -1
  29. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/config.py +132 -3
  30. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/agent.py +77 -8
  31. nexforge_cli-0.7.0/src/nexforge/core/goal_manager.py +405 -0
  32. nexforge_cli-0.7.0/src/nexforge/core/jobs.py +200 -0
  33. nexforge_cli-0.7.0/src/nexforge/core/model_window.py +324 -0
  34. nexforge_cli-0.7.0/src/nexforge/core/permissions.py +108 -0
  35. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/session.py +2 -0
  36. nexforge_cli-0.7.0/src/nexforge/core/summarizer.py +219 -0
  37. nexforge_cli-0.7.0/src/nexforge/core/waits.py +78 -0
  38. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/features/mode_features.py +541 -64
  39. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/features/session_feature.py +5 -0
  40. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/i18n.py +40 -0
  41. nexforge_cli-0.7.0/src/nexforge/mcp/__init__.py +336 -0
  42. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/store/session_store.py +56 -15
  43. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/background.py +127 -111
  44. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/base.py +12 -0
  45. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/registry.py +3 -0
  46. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/screenshot_tools.py +9 -0
  47. nexforge_cli-0.7.0/src/nexforge/tools/wait_tools.py +379 -0
  48. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/screens/chat.py +274 -27
  49. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/screens/chat_actions.py +36 -6
  50. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/slash_handler.py +121 -2
  51. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/messages.py +39 -0
  52. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/web/server.py +7 -0
  53. nexforge_cli-0.7.0/tests/fixtures/fake_mcp_server.py +59 -0
  54. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_archive_integrity.py +67 -0
  55. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_config.py +37 -0
  56. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_cross_platform.py +2 -0
  57. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_director_loop.py +6 -3
  58. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_file_browser.py +4 -2
  59. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_goal_confirm.py +10 -0
  60. nexforge_cli-0.7.0/tests/test_goal_stability.py +1294 -0
  61. nexforge_cli-0.7.0/tests/test_jobs_lifecycle.py +84 -0
  62. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_manual_consistency.py +4 -2
  63. nexforge_cli-0.7.0/tests/test_mcp_integration.py +210 -0
  64. nexforge_cli-0.7.0/tests/test_mcp_lifecycle.py +114 -0
  65. nexforge_cli-0.7.0/tests/test_model_window.py +358 -0
  66. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_plugin_example_tts.py +176 -10
  67. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_session_store.py +101 -0
  68. nexforge_cli-0.7.0/tests/test_tool_iters.py +75 -0
  69. nexforge_cli-0.7.0/tests/test_wait_tools.py +489 -0
  70. nexforge_cli-0.4.1/manual/06-/346/235/203/351/231/220/344/270/216/346/250/241/345/274/217.md +0 -71
  71. nexforge_cli-0.4.1/src/nexforge/core/goal_manager.py +0 -171
  72. nexforge_cli-0.4.1/src/nexforge/core/jobs.py +0 -120
  73. nexforge_cli-0.4.1/src/nexforge/core/permissions.py +0 -73
  74. nexforge_cli-0.4.1/src/nexforge/core/summarizer.py +0 -134
  75. nexforge_cli-0.4.1/src/nexforge/mcp/__init__.py +0 -168
  76. nexforge_cli-0.4.1/tests/test_tool_iters.py +0 -55
  77. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/.gitignore +0 -0
  78. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/INSTALL.md +0 -0
  79. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/STATS_API.md +0 -0
  80. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/assets/icons/agent.svg +0 -0
  81. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/assets/icons/cost.svg +0 -0
  82. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/assets/icons/edit.svg +0 -0
  83. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/assets/icons/err.svg +0 -0
  84. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/assets/icons/file.svg +0 -0
  85. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/assets/icons/model.svg +0 -0
  86. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/assets/icons/ok.svg +0 -0
  87. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/assets/icons/read.svg +0 -0
  88. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/assets/icons/running.svg +0 -0
  89. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/assets/icons/search.svg +0 -0
  90. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/assets/icons/shell.svg +0 -0
  91. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/assets/icons/thinking.svg +0 -0
  92. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/assets/icons/web.svg +0 -0
  93. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/assets/icons/write.svg +0 -0
  94. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/devlog/2026-07-07.md +0 -0
  95. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/doc//344/273/243/347/240/201/344/274/230/345/214/226/350/256/241/345/210/222.md" +0 -0
  96. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/doc//347/211/271/346/200/247/346/250/241/345/235/227/346/263/250/345/206/214/345/210/266-/345/256/236/346/226/275/350/256/241/345/210/222.md" +0 -0
  97. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/decisions/2026-09-10-fails-loud/345/210/206/347/272/247.md" +0 -0
  98. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/decisions/2026-09-10-/344/274/232/350/257/235/344/270/215/345/217/230/351/207/217.md" +0 -0
  99. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/decisions/2026-09-10-/344/276/235/350/265/226/344/270/200/350/207/264/346/200/247.md" +0 -0
  100. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/decisions/2026-09-10-/345/233/236/346/224/276/350/214/203/345/233/264/351/207/215/345/256/232/344/271/211.md" +0 -0
  101. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/decisions/2026-09-10-/345/256/241/350/256/241/344/273/245/350/260/203/347/224/250/351/223/276/344/270/272/345/207/206.md" +0 -0
  102. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/decisions/2026-09-10-/350/203/275/345/212/233/345/217/257/347/224/250/346/200/247/344/270/212/346/212/245.md" +0 -0
  103. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/decisions/2026-09-10-/350/264/250/351/207/217gate/344/275/223/347/263/273.md" +0 -0
  104. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/decisions/2026-09-11-deepseek/346/241/243/344/275/215/347/256/200/345/214/226.md" +0 -0
  105. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/decisions/2026-09-11-/346/241/243/344/275/215/347/256/200/345/214/226/344/270/272/345/215/225/346/241/243flash.md" +0 -0
  106. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/decisions/2026-09-11-/347/273/210/347/253/257/347/212/266/346/200/201/345/205/234/345/272/225/346/201/242/345/244/215.md" +0 -0
  107. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/decisions/2026-09-11-/351/205/215/347/275/256/346/256/213/347/225/231/345/200/274/346/262/273/347/220/206.md" +0 -0
  108. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/decisions/2026-09-11-/351/207/215/350/257/225/345/275/222/344/270/200/345/261/202.md" +0 -0
  109. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/decisions/2026-09-12-/345/206/205/345/256/271/351/207/214/347/232/204/346/240/207/350/256/260/344/270/215/345/276/227/345/275/223/346/210/220/346/266/210/346/201/257/350/276/271/347/225/214.md" +0 -0
  110. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D10_acceptance.log +0 -0
  111. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D10_full_test.log +0 -0
  112. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D11_a4.log +0 -0
  113. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D11_full_test.log +0 -0
  114. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D12_audit.md +0 -0
  115. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D12_gap.log +0 -0
  116. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D13_break.log +0 -0
  117. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D13_e2e.log +0 -0
  118. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D13_full_test.log +0 -0
  119. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D13_gaps.log +0 -0
  120. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D14_audit.md +0 -0
  121. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D14_full_test.log +0 -0
  122. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D14_recheck.log +0 -0
  123. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D15_audit.md +0 -0
  124. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D4_fast.log +0 -0
  125. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D4_full_test.log +0 -0
  126. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D4_hook.log +0 -0
  127. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D4_scene_c.log +0 -0
  128. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D4_scene_d.log +0 -0
  129. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D4_scene_e.log +0 -0
  130. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D5_audit.md +0 -0
  131. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D5_b2_plugin.log +0 -0
  132. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D5_full_test.log +0 -0
  133. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D6_b3_a.log +0 -0
  134. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D6_b3_b.log +0 -0
  135. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D6_b3_c.log +0 -0
  136. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D6_b4_provider.log +0 -0
  137. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D6_full_test.log +0 -0
  138. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D7_dedup.log +0 -0
  139. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D7_full_test.log +0 -0
  140. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D8_audit.md +0 -0
  141. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D8_invariant.log +0 -0
  142. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D9_after.log +0 -0
  143. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D9_before.log +0 -0
  144. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D9_decision.md +0 -0
  145. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D9_full_test.log +0 -0
  146. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/D9_rebuild.log +0 -0
  147. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/E_cap_fulltest.log +0 -0
  148. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/E_capabilities.log +0 -0
  149. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/E_engines.log +0 -0
  150. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/E_engines_fulltest.log +0 -0
  151. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/E_tts_availability.log +0 -0
  152. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/E_tts_fulltest.log +0 -0
  153. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/E_tts_installer.log +0 -0
  154. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/E_vision_channels.log +0 -0
  155. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/E_vision_fulltest.log +0 -0
  156. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/F_decisions_fulltest.log +0 -0
  157. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/deps_fulltest.log +0 -0
  158. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/deps_reverse.log +0 -0
  159. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/exit-cost.log +0 -0
  160. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/final_check_fulltest.log +0 -0
  161. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/final_check_pypi.log +0 -0
  162. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/final_check_report.log +0 -0
  163. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/fix_fulltest.log +0 -0
  164. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/health_fulltest.log +0 -0
  165. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/health_report.md +0 -0
  166. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/health_scan.log +0 -0
  167. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/model-sidebar-dot.log +0 -0
  168. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/model_rename_check.log +0 -0
  169. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/provider-family-check.log +0 -0
  170. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/release-0.3.0.log +0 -0
  171. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/release-0.4.0.log +0 -0
  172. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/release_0218_fulltest.log +0 -0
  173. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/release_0218_pypi.log +0 -0
  174. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/session-marker-boundary.log +0 -0
  175. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/session-marker-boundary_fulltest.log +0 -0
  176. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/session-marker-boundary_live.log +0 -0
  177. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/session-marker-boundary_report.md +0 -0
  178. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/simplify_tier_fulltest.log +0 -0
  179. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/evidence/terminal-leak-conditions.log +0 -0
  180. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/session-invariant.md +0 -0
  181. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/docs/submission/nexforge.md +0 -0
  182. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/manual/03-/346/250/241/345/236/213/351/205/215/347/275/256.md" +0 -0
  183. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/manual/05-/346/225/260/346/215/256/344/270/216/346/220/234/347/264/242.md" +0 -0
  184. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/manual/07-/344/274/232/350/257/235/344/270/216/350/256/260/345/277/206.md" +0 -0
  185. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/manual/11-/345/274/200/345/217/221/346/240/241/351/252/214.md" +0 -0
  186. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_gui_auto/README.md +0 -0
  187. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_gui_auto/guiauto/__init__.py +0 -0
  188. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_gui_auto/guiauto/action.py +0 -0
  189. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_gui_auto/guiauto/base.py +0 -0
  190. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_gui_auto/guiauto/tools.py +0 -0
  191. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_gui_auto/guiauto/vision.py +0 -0
  192. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_gui_auto/guiauto/window.py +0 -0
  193. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_gui_auto/install_plugin.py +0 -0
  194. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_gui_auto/requirements.txt +0 -0
  195. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_gui_auto/smoke_safe.py +0 -0
  196. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_gui_auto/verify_final.py +0 -0
  197. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_gui_auto/verify_host.py +0 -0
  198. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_gui_auto/verify_plugin.py +0 -0
  199. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_speech_summary/README.md +0 -0
  200. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/plugin_speech_summary/install_plugin.py +0 -0
  201. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/__init__.py +0 -0
  202. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/check.py +0 -0
  203. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/exit_cost_probe.py +0 -0
  204. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/exit_smoke.py +0 -0
  205. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/gates/__init__.py +0 -0
  206. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/gates/base.py +0 -0
  207. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/gates/eof_newline.py +0 -0
  208. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/gates/example_config.py +0 -0
  209. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/gates/hygiene.py +0 -0
  210. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/gates/manual_consistency.py +0 -0
  211. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/gates/version_sync.py +0 -0
  212. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/install_hooks.py +0 -0
  213. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/publish.sh +0 -0
  214. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/smoke_provider.py +0 -0
  215. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/scripts/smoke_tui.py +0 -0
  216. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/__main__.py +0 -0
  217. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/app.py +0 -0
  218. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/cli.py +0 -0
  219. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/__init__.py +0 -0
  220. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/capability.py +0 -0
  221. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/context.py +0 -0
  222. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/federation.py +0 -0
  223. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/knowledge_base.py +0 -0
  224. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/memory_engine.py +0 -0
  225. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/model_catalog.py +0 -0
  226. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/plugin.py +0 -0
  227. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/project_mapper.py +0 -0
  228. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/provider.py +0 -0
  229. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/system_inject.py +0 -0
  230. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/tool_manifest.py +0 -0
  231. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/types.py +0 -0
  232. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/core/update_check.py +0 -0
  233. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/features/__init__.py +0 -0
  234. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/features/auto_skills.py +0 -0
  235. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/features/base.py +0 -0
  236. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/features/federation_feature.py +0 -0
  237. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/features/kb_feature.py +0 -0
  238. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/features/map_feature.py +0 -0
  239. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/features/memory_feature.py +0 -0
  240. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/features/plan_feature.py +0 -0
  241. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/features/registry.py +0 -0
  242. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/features/slash_feature.py +0 -0
  243. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/features/stats_feature.py +0 -0
  244. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/features/tool_manifest_feature.py +0 -0
  245. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/icons.py +0 -0
  246. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/provider/__init__.py +0 -0
  247. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/provider/_retry.py +0 -0
  248. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/provider/anthropic.py +0 -0
  249. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/provider/balance.py +0 -0
  250. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/provider/deepseek.py +0 -0
  251. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/provider/openai.py +0 -0
  252. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/provider/qianwen.py +0 -0
  253. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/skills/loader.py +0 -0
  254. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/stats/__init__.py +0 -0
  255. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/stats/heartbeat.py +0 -0
  256. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/store/__init__.py +0 -0
  257. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/store/director_store.py +0 -0
  258. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/store/plan_store.py +0 -0
  259. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/terminal_guard.py +0 -0
  260. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/theme.tcss +0 -0
  261. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/__init__.py +0 -0
  262. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/_paths.py +0 -0
  263. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/data_tools.py +0 -0
  264. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/edit_file.py +0 -0
  265. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/federation.py +0 -0
  266. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/fs_ops.py +0 -0
  267. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/git.py +0 -0
  268. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/image_tools.py +0 -0
  269. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/kb_tools.py +0 -0
  270. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/list_dir.py +0 -0
  271. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/multi_edit.py +0 -0
  272. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/ops_tools.py +0 -0
  273. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/read_file.py +0 -0
  274. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/search.py +0 -0
  275. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/search_content.py +0 -0
  276. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/search_files.py +0 -0
  277. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/shell.py +0 -0
  278. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/web.py +0 -0
  279. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/tools/write_file.py +0 -0
  280. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/__init__.py +0 -0
  281. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/clipboard_image.py +0 -0
  282. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/screen_api.py +0 -0
  283. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/screens/__init__.py +0 -0
  284. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/screens/splash.py +0 -0
  285. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/__init__.py +0 -0
  286. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/apikey_modal.py +0 -0
  287. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/banner.py +0 -0
  288. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/confirm_modal.py +0 -0
  289. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/diff_modal.py +0 -0
  290. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/file_browser.py +0 -0
  291. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/file_menu.py +0 -0
  292. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/image_sidebar.py +0 -0
  293. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/mode_warning.py +0 -0
  294. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/model_sidebar.py +0 -0
  295. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/multiline_modal.py +0 -0
  296. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/multiline_prompt.py +0 -0
  297. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/plan_sidebar.py +0 -0
  298. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/sidebar.py +0 -0
  299. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/ui/widgets/statusbar.py +0 -0
  300. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/utils/__init__.py +0 -0
  301. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/utils/logging.py +0 -0
  302. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/web/__init__.py +0 -0
  303. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/src/nexforge/web/static/index.html +0 -0
  304. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/conftest.py +0 -0
  305. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_app_mouse.py +0 -0
  306. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_approval.py +0 -0
  307. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_capability.py +0 -0
  308. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_check_gates.py +0 -0
  309. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_deepseek_provider.py +0 -0
  310. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_deps.py +0 -0
  311. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_director_store.py +0 -0
  312. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_dual_panel.py +0 -0
  313. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_exit_smoke.py +0 -0
  314. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_federation.py +0 -0
  315. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_i18n.py +0 -0
  316. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_icons.py +0 -0
  317. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_lang_cmd.py +0 -0
  318. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_m2_tools.py +0 -0
  319. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_model_catalog.py +0 -0
  320. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_model_sidebar_dot.py +0 -0
  321. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_p2_core.py +0 -0
  322. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_plugin.py +0 -0
  323. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_project_map_prune.py +0 -0
  324. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_provider_errors.py +0 -0
  325. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_quit_paths.py +0 -0
  326. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_retry_policy.py +0 -0
  327. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_sanitize.py +0 -0
  328. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_screenshot_tools.py +0 -0
  329. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_session_invariant.py +0 -0
  330. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_session_repair.py +0 -0
  331. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_session_save_safety.py +0 -0
  332. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_sidebar.py +0 -0
  333. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_sidebar_actions.py +0 -0
  334. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_sidebar_align.py +0 -0
  335. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_splash_modal.py +0 -0
  336. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_statusbar.py +0 -0
  337. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_system_inject.py +0 -0
  338. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_terminal_guard.py +0 -0
  339. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_tools.py +0 -0
  340. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_tui.py +0 -0
  341. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_update_check.py +0 -0
  342. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_vision_capability.py +0 -0
  343. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_vision_model.py +0 -0
  344. {nexforge_cli-0.4.1 → nexforge_cli-0.7.0}/tests/test_vision_tool_retention.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: nexforge-cli
3
- Version: 0.4.1
3
+ Version: 0.7.0
4
4
  Summary: NexForgeCLI — 一个面向 DeepSeek V4 的终端智能体(TUI + CLI 双模式)
5
5
  Project-URL: Homepage, https://gitee.com/Lighthorn/nexforgecli
6
6
  Author: NexForge
@@ -51,14 +51,15 @@ Description-Content-Type: text/markdown
51
51
 
52
52
  NexForgeCLI 是一个运行在终端里的智能体助手,既支持 DeepSeek/千问等多模型,也是**插件宿主**(plugins 目录即插即用)。既能作为全屏 TUI 交互式对话/编码,也能作为 one-shot 命令行工具嵌进脚本和管道。
53
53
 
54
- > 当前版本:**v0.4.1** · PyPI: `pip install nexforge-cli`
54
+ > 当前版本:**v0.7.0** · PyPI: `pip install nexforge-cli`
55
55
 
56
- **v0.4.1 要点(重要修复)**:会话重建时,**内容里出现的 `<!-- nf-msg -->` 不再被当成消息边界**。
57
- 此前若工具结果 dump 过会话文件(或粘贴过会话内容),加载时那些标记会被解码成额外消息、
58
- 插进工具块中间,导致**每轮请求 400、项目再也打不开**。
59
- 修法:读侧标记识别改为**行首锚定**,写侧对内容里的标记前缀做转义;同时把工具序列修复
60
- 从"只修尾部"升级为"修全序列"(中段违规也能纠正)。
61
- 另含 0.4.0 推出的:本机 TTS 优先/回退、模型随 nf 常驻、`/voice full|brief`、配置残留值自动收敛。
56
+ **v0.7.0 要点(MCP 外部工具接入)**:可以用 `[[mcp.servers]]` 挂载 MCP server,
57
+ 把第三方工具(文件系统/GitHub/数据库等)接进 AI 工具箱。外部工具统一注册为
58
+ `mcp__<server>__<tool>` —— **无法覆盖内置工具**(外部进程不能改写能力面), 也便于按来源授权;
59
+ 默认需审批(`require_approval`), 并提供 `/mcp` 查看连接状态与失败原因。工具数有闸门
60
+ (`[mcp] max_tools` + server 级 `tools` 白名单), 防止上下文被几十个外部工具挤爆。
61
+ (上一版 0.6.0 要点: 新增 `wait` / `wait_until` 精确等待与条件轮询, 并按参数豁免 60 秒
62
+ 单工具超时上限; `stop_job` 与退出清理改为终止整个进程树; 内置工具 39 → 41。)
62
63
 
63
64
  ---
64
65
 
@@ -8,14 +8,15 @@
8
8
 
9
9
  NexForgeCLI 是一个运行在终端里的智能体助手,既支持 DeepSeek/千问等多模型,也是**插件宿主**(plugins 目录即插即用)。既能作为全屏 TUI 交互式对话/编码,也能作为 one-shot 命令行工具嵌进脚本和管道。
10
10
 
11
- > 当前版本:**v0.4.1** · PyPI: `pip install nexforge-cli`
12
-
13
- **v0.4.1 要点(重要修复)**:会话重建时,**内容里出现的 `<!-- nf-msg -->` 不再被当成消息边界**。
14
- 此前若工具结果 dump 过会话文件(或粘贴过会话内容),加载时那些标记会被解码成额外消息、
15
- 插进工具块中间,导致**每轮请求 400、项目再也打不开**。
16
- 修法:读侧标记识别改为**行首锚定**,写侧对内容里的标记前缀做转义;同时把工具序列修复
17
- 从"只修尾部"升级为"修全序列"(中段违规也能纠正)。
18
- 另含 0.4.0 推出的:本机 TTS 优先/回退、模型随 nf 常驻、`/voice full|brief`、配置残留值自动收敛。
11
+ > 当前版本:**v0.7.0** · PyPI: `pip install nexforge-cli`
12
+
13
+ **v0.7.0 要点(MCP 外部工具接入)**:可以用 `[[mcp.servers]]` 挂载 MCP server,
14
+ 把第三方工具(文件系统/GitHub/数据库等)接进 AI 工具箱。外部工具统一注册为
15
+ `mcp__<server>__<tool>` —— **无法覆盖内置工具**(外部进程不能改写能力面), 也便于按来源授权;
16
+ 默认需审批(`require_approval`), 并提供 `/mcp` 查看连接状态与失败原因。工具数有闸门
17
+ (`[mcp] max_tools` + server 级 `tools` 白名单), 防止上下文被几十个外部工具挤爆。
18
+ (上一版 0.6.0 要点: 新增 `wait` / `wait_until` 精确等待与条件轮询, 并按参数豁免 60 秒
19
+ 单工具超时上限; `stop_job` 与退出清理改为终止整个进程树; 内置工具 39 → 41。)
19
20
 
20
21
  ---
21
22
 
@@ -16,6 +16,14 @@ thinking = true # 思考模式,默认开
16
16
  reasoning_effort = "high" # high | max
17
17
  max_output_tokens = 32768 # 含思考 token; 别写 8192(思考会吃满 → 正文截断秒停)
18
18
 
19
+ # 上下文窗口(压缩预算的依据)。**默认不写 = 自动跟随当前模型**:
20
+ # 用户声明(models.toml 的本项 / config.toml 的 context_window)> 实测学习
21
+ # (上游报错里的窗口数字 / 失败请求体量 / 成功响应的 prompt_tokens)> 内置表
22
+ # > 未知模型兜底(1,000,000)。
23
+ # 只有需要**强制覆盖**自动判断时才在这里写(>0 即视为声明, 优先级最高;
24
+ # 但上游若用报错证明窗口更小, 实测值仍会压低它 —— 物理事实优先)。
25
+ # context_window = 1000000
26
+
19
27
  # 定价(每百万 token,USD)—— 已核实
20
28
  [models.pricing.flash]
21
29
  input_cache_hit = 0.0028
@@ -37,5 +45,23 @@ cosyvoice_url = "http://127.0.0.1:9880" # 本机 CosyVoice 常驻服务(其 l
37
45
  cosyvoice_voice = "default" # 本机服务音色 id
38
46
  cosyvoice_timeout_s = 90 # 冷启动约 20s, 留足余量
39
47
  cosyvoice_resident = true # nf 在跑就让模型常驻显存; nf 全退出后由服务立即卸载
48
+ stream = true # 流式播报(首块约 2s 就开口); false = 整句合成完再播
49
+ instruct = "" # 风格指令(如 "用自然亲切的语气说"); 空 = 不用指令
40
50
  max_chars = 0 # 播报文本上限(0=不限; 配合下面的 mode)
41
51
  mode = "full" # 播报范围: full=全量播报最终报告(默认) | brief=只播第一段(/voice 切换)
52
+
53
+ # MCP 外部工具服务(默认不启用)。下面是配置模板, 取消注释并按需修改;
54
+ # 完整说明(命名/权限/排错/成本)见 manual/12-MCP接入.md。
55
+ #
56
+ # [[mcp.servers]]
57
+ # name = "filesystem" # 唯一标识, 同时是工具名前缀(mcp__<name>__<tool>)
58
+ # command = "npx" # stdio: 可执行文件(当前仅支持 stdio)
59
+ # args = ["-y", "@modelcontextprotocol/server-filesystem", "D:/work"]
60
+ # env = { SOME_TOKEN = "..." } # 可选: 追加环境变量
61
+ # tools = ["read_file", "list_directory"] # 可选: 工具白名单(空 = 该 server 的全部工具)
62
+ # require_approval = true # 默认 true: 每次调用需审批(外部进程与 run_background 同级)
63
+ # enabled = true
64
+ #
65
+ # [mcp]
66
+ # max_tools = 40 # 注入工具 schema 的 MCP 工具总数上限(超出截断并提示)
67
+ # connect_timeout = 15.0 # 单个 server 连接/握手超时(秒)
@@ -1,172 +1,187 @@
1
- # 项目总监循环 开发计划
2
-
3
- > 版本: v1.0 · 创建: 2026-07-16 · 状态: 设计完成,待实现
4
-
5
- ---
6
-
7
- ## 概述
8
-
9
- 在目标模式(`/goal`)下,引入"项目总监 + 开发者"双角色架构。项目总监负责制定计划、审核进展、分发任务;开发者负责具体执行。目标是让 AI 能够自主完成复杂的多轮开发任务,同时保证质量和可追溯性。
10
-
11
- ---
12
-
13
- ## 角色定义
14
-
15
- ### 项目总监 (Director)
16
-
17
- - **职责**:审核开发者报告 → 判断进展 → 发布下一条指令
18
- - **审核维度**:代码质量、性能瓶颈、稳定性、用户体验、逻辑流程
19
- - **防僵局策略**:当开发者反复说"任务完成"时,从以下方向主动寻找新工作:
20
- - 边界情况覆盖
21
- - 测试补充
22
- - 性能优化
23
- - 文档/代码注释
24
- - 代码重构整理
25
- - 是否真正满足核心需求
26
- - **停止判断**:若目标已达成,回复 `GOAL_ACHIEVED` 关键词
27
-
28
- ### 开发者 (Developer)
29
-
30
- - **职责**:执行项目总监的指令 → 完成后提交总结报告
31
- - **行为约束**:专注执行指令,不做多余的事
32
-
33
- ---
34
-
35
- ## 启动流程 (二步确认)
36
-
37
- ```
38
- 用户输入 /goal
39
- → Step 1: 弹出风险警告弹窗(GoalModeModal)
40
- → Step 2: 弹出多行输入框,用户输入目标描述
41
- → Step 3: 显示目标预览,提示"回复确认开始"
42
- → Step 4: 用户回复"确认"/"开始"/"ok"/"yes"
43
- → Step 5: 正式启动
44
- ```
45
-
46
- ### 启动时操作
47
- 1. `self.config.ui.goal_mode = True`
48
- 2. `self.config.ui.mode = "auto"` (强制全自动)
49
- 3. 保存到项目级 `config.toml`
50
- 4. 创建 `.nexforge/goal/nfgoal.md` (记录最终目标)
51
- 5. 发送首轮指令给 AI:"[项目总监] 制定开发计划并发布第一条指令"
52
-
53
- ---
54
-
55
- ## 循环流程
56
-
57
- ```
58
- 每个 AI 回合结束 (TURN_DONE)
59
- → 如果 goal_mode == True:
60
- → 调用 _goal_cycle_continue(last_response)
61
- → 检查停止条件
62
- → 显示项目总监金色消息
63
- → 构造总监 prompt(包含目标+计划+开发者报告)
64
- → 启动下一轮 AI
65
- ```
66
-
67
- ### 停止条件 (任一满足即停止)
68
-
69
- | 条件 | 检测方式 | 操作 |
70
- |------|---------|------|
71
- | 余额耗尽 | `_balance == "0.00"` | 显示"账户余额耗尽",退出目标模式 |
72
- | 总监判断达成 | `last_response` 含 `GOAL_ACHIEVED` | 显示"项目总监判断目标达成" |
73
- | 达到最大轮数 | `current >= max_rounds` (默认 100,可通过 `/max N` 设置) | 显示"达到最大轮数" |
74
-
75
- ---
76
-
77
- ## UI 显示
78
-
79
- ### 项目总监消息 (金色)
80
- ```python
81
- class DirectorNote(Static):
82
- """👔 项目总监: 消息内容 (金色 #FFD700 加粗)"""
83
- ```
84
-
85
- - 每轮开始前在聊天区显示金色提示条
86
- - 格式:`第 N/M 轮:项目总监审核`
87
-
88
- ### 状态栏
89
- - 目标模式开启时显示 `🎯 目标`
90
- - 运维模式开启时显示 `🔧 运维`
91
-
92
- ---
93
-
94
- ## 快捷键
95
-
96
- | 快捷键 | 功能 |
97
- |--------|------|
98
- | F7 | 切换运维模式 |
99
- | F8 | 切换目标模式(开启时强制全自动) |
100
- | Esc | 目标模式三级停止:停总监 → 停开发者 → 退出 |
101
-
102
- ### Esc 三级停止逻辑
103
- ```
104
- Esc 第1次:停止项目总监(goal_mode=False,开发者继续当前工作)
105
- Esc 第2次:取消开发者 worker
106
- Esc 第3次:弹出退出确认
107
- ```
108
-
109
- ---
110
-
111
- ## 文件体系 (项目隔离,仅目标模式)
112
-
113
- ```
114
- <项目>/.nexforge/goal/
115
- ├── nfgoal.md ← 最终目标
116
- ├── plan.md ← 项目总监编写的计划
117
- └── rounds/
118
- ├── 001.md ← 第1轮:开发者报告 + 总监审核
119
- ├── 002.md ← 第2轮
120
- └── ...
121
- ```
122
-
123
- - 非目标模式不创建此目录
124
- - 离开目标模式后不自动清理(保留历史)
125
-
126
- ---
127
-
128
- ## 配置项
129
-
130
- | 配置 | 默认 | 说明 |
131
- |------|------|------|
132
- | `ui.goal_mode` | `false` | 是否处于目标模式 |
133
- | `ui.ops_mode` | `false` | 是否处于运维模式 |
134
- | `ui.max_rounds` | `100` | 目标模式最大轮数,通过 `/max N` 修改 |
135
- | `ui.mode` | `review` | 审批模式(review/auto) |
136
-
137
- ---
138
-
139
- ## 涉及文件
140
-
141
- | 文件 | 改动 |
142
- |------|------|
143
- | `src/nexforge/core/goal_manager.py` | **已创建** — GoalManager 类 |
144
- | `src/nexforge/ui/screens/chat.py` | 加 `_start_goal_mode`、`_confirm_goal_start`、`_goal_cycle_continue` |
145
- | `src/nexforge/ui/widgets/messages.py` | **已创建** — DirectorNote 金色组件 |
146
- | `src/nexforge/ui/widgets/mode_warning.py` | 已有 GoalModeModal、OpsModeModal |
147
- | `src/nexforge/config.py` | goal_mode/ops_mode/max_rounds 字段 |
148
- | `src/nexforge/store/session_store.py` | 会话保存过滤系统消息(已实现) |
149
-
150
- ---
151
-
152
- ## 实现注意事项
153
-
154
- 1. **不要用 heredoc/多行字符串替换编辑 chat.py**——该文件已因反复编辑损坏多次
155
- 2. **使用 `edit_file` 工具逐个精准替换**,每次编辑后编译验证
156
- 3. **`_goal_cycle_continue` 必须独立为类方法**,不能嵌入其他方法中
157
- 4. **字符串拼接用 `+` 而非 f-string 跨行**,避免语法错误
158
- 5. **`save_config` 按项目保存**(`<cwd>/.nexforge/config.toml`),不污染全局
159
- 6. **系统消息不保存到会话文件**(已在 session_store.py 实现)
160
-
161
- ---
162
-
163
- ## 测试验证
164
-
165
- - [ ] `/goal` → 弹窗 → 输入目标 → "确认" → 项目总监启动
166
- - [ ] F8 一键切换目标模式
167
- - [ ] F7 一键切换运维模式
168
- - [ ] Esc 三级停止(目标模式)
169
- - [ ] `GOAL_ACHIEVED` 自动停止
170
- - [ ] `/max 50` 修改轮数上限
171
- - [ ] 不同项目独立模式状态
172
- - [ ] 余额耗尽自动停止
1
+ # 项目总监循环 开发计划
2
+
3
+ > 版本: v1.0 · 创建: 2026-07-16 · 状态: 设计完成,待实现
4
+
5
+ ---
6
+
7
+ ## 概述
8
+
9
+ 在目标模式(`/goal`)下,引入"项目总监 + 开发者"双角色架构。项目总监负责制定计划、审核进展、分发任务;开发者负责具体执行。目标是让 AI 能够自主完成复杂的多轮开发任务,同时保证质量和可追溯性。
10
+
11
+ ---
12
+
13
+ ## 角色定义
14
+
15
+ ### 项目总监 (Director)
16
+
17
+ - **职责**:审核开发者报告 → 判断进展 → 发布下一条指令
18
+ - **审核维度**:代码质量、性能瓶颈、稳定性、用户体验、逻辑流程
19
+ - **防僵局策略**:当开发者反复说"任务完成"时,从以下方向主动寻找新工作:
20
+ - 边界情况覆盖
21
+ - 测试补充
22
+ - 性能优化
23
+ - 文档/代码注释
24
+ - 代码重构整理
25
+ - 是否真正满足核心需求
26
+ - **停止判断**:若目标已达成,回复 `GOAL_ACHIEVED` 关键词
27
+
28
+ ### 开发者 (Developer)
29
+
30
+ - **职责**:执行项目总监的指令 → 完成后提交总结报告
31
+ - **行为约束**:专注执行指令,不做多余的事
32
+
33
+ ---
34
+
35
+ ## 启动流程 (二步确认)
36
+
37
+ ```
38
+ 用户输入 /goal
39
+ → Step 1: 弹出风险警告弹窗(GoalModeModal)
40
+ → Step 2: 弹出多行输入框,用户输入目标描述
41
+ → Step 3: 显示目标预览,提示"回复确认开始"
42
+ → Step 4: 用户回复"确认"/"开始"/"ok"/"yes"
43
+ → Step 5: 正式启动
44
+ ```
45
+
46
+ ### 启动时操作
47
+ 1. `self.config.ui.goal_mode = True`
48
+ 2. `self.config.ui.mode = "auto"` (强制全自动)
49
+ 3. 保存到项目级 `config.toml`
50
+ 4. 创建 `.nexforge/goal/nfgoal.md` (记录最终目标)
51
+ 5. 发送首轮指令给 AI:"[项目总监] 制定开发计划并发布第一条指令"
52
+
53
+ ---
54
+
55
+ ## 循环流程
56
+
57
+ ```
58
+ 每个 AI 回合结束 (TURN_DONE)
59
+ → 如果 goal_mode == True:
60
+ → 调用 _goal_cycle_continue(last_response)
61
+ → 检查停止条件
62
+ → 显示项目总监金色消息
63
+ → 构造总监 prompt(包含目标+计划+开发者报告)
64
+ → 启动下一轮 AI
65
+ ```
66
+
67
+ ### 停止条件 (任一满足即停止)
68
+
69
+ | 条件 | 检测方式 | 操作 |
70
+ |------|---------|------|
71
+ | 余额耗尽 | `_balance == "0.00"` | 显示"账户余额耗尽",退出目标模式 |
72
+ | 总监判断达成 | `last_response` 含 `GOAL_ACHIEVED` | 显示"项目总监判断目标达成" |
73
+ | 达到最大轮数 | `current >= max_rounds` (默认 100,可通过 `/max N` 设置) | 显示"达到最大轮数" |
74
+
75
+ ---
76
+
77
+ ## UI 显示
78
+
79
+ ### 项目总监消息 (金色)
80
+ ```python
81
+ class DirectorNote(Static):
82
+ """👔 项目总监: 消息内容 (金色 #FFD700 加粗)"""
83
+ ```
84
+
85
+ - 每轮开始前在聊天区显示金色提示条
86
+ - 格式:`第 N/M 轮:项目总监审核`
87
+
88
+ ### 状态栏
89
+ - 目标模式开启时显示 `🎯 目标`
90
+ - 运维模式开启时显示 `🔧 运维`
91
+
92
+ ---
93
+
94
+ ## 快捷键
95
+
96
+ | 快捷键 | 功能 |
97
+ |--------|------|
98
+ | F7 | 切换运维模式 |
99
+ | F8 | 切换目标模式(开启时强制全自动) |
100
+ | Esc | 目标模式三级停止:停总监 → 停开发者 → 退出 |
101
+
102
+ ### Esc 三级停止逻辑
103
+ ```
104
+ Esc 第1次:停止项目总监(goal_mode=False,开发者继续当前工作)
105
+ Esc 第2次:取消开发者 worker
106
+ Esc 第3次:弹出退出确认
107
+ ```
108
+
109
+ ---
110
+
111
+ ## 文件体系 (项目隔离,仅目标模式)
112
+
113
+ ```
114
+ <项目>/.nexforge/goal/
115
+ ├── nfgoal.md ← 最终目标
116
+ ├── plan.md ← 项目总监编写的计划
117
+ └── rounds/
118
+ ├── 001.md ← 第1轮:开发者报告 + 总监审核
119
+ ├── 002.md ← 第2轮
120
+ └── ...
121
+ ```
122
+
123
+ - 非目标模式不创建此目录
124
+ - 离开目标模式后不自动清理(保留历史)
125
+
126
+ ---
127
+
128
+ ## 配置项
129
+
130
+ | 配置 | 默认 | 说明 |
131
+ |------|------|------|
132
+ | `ui.goal_mode` | `false` | 是否处于目标模式 |
133
+ | `ui.ops_mode` | `false` | 是否处于运维模式 |
134
+ | `ui.max_rounds` | `100` | 目标模式最大轮数,通过 `/max N` 修改 |
135
+ | `ui.mode` | `review` | 审批模式(review/auto) |
136
+
137
+ ---
138
+
139
+ ## 涉及文件
140
+
141
+ | 文件 | 改动 |
142
+ |------|------|
143
+ | `src/nexforge/core/goal_manager.py` | **已创建** — GoalManager 类 |
144
+ | `src/nexforge/ui/screens/chat.py` | 加 `_start_goal_mode`、`_confirm_goal_start`、`_goal_cycle_continue` |
145
+ | `src/nexforge/ui/widgets/messages.py` | **已创建** — DirectorNote 金色组件 |
146
+ | `src/nexforge/ui/widgets/mode_warning.py` | 已有 GoalModeModal、OpsModeModal |
147
+ | `src/nexforge/config.py` | goal_mode/ops_mode/max_rounds 字段 |
148
+ | `src/nexforge/store/session_store.py` | 会话保存过滤系统消息(已实现) |
149
+
150
+ ---
151
+
152
+ ## 实现注意事项
153
+
154
+ 1. **不要用 heredoc/多行字符串替换编辑 chat.py**——该文件已因反复编辑损坏多次
155
+ 2. **使用 `edit_file` 工具逐个精准替换**,每次编辑后编译验证
156
+ 3. **`_goal_cycle_continue` 必须独立为类方法**,不能嵌入其他方法中
157
+ 4. **字符串拼接用 `+` 而非 f-string 跨行**,避免语法错误
158
+ 5. **`save_config` 按项目保存**(`<cwd>/.nexforge/config.toml`),不污染全局
159
+ 6. **系统消息不保存到会话文件**(已在 session_store.py 实现)
160
+
161
+ ---
162
+
163
+ ## 测试验证
164
+
165
+ - [ ] `/goal` → 弹窗 → 输入目标 → "确认" → 项目总监启动
166
+ - [ ] F8 一键切换目标模式
167
+ - [ ] F7 一键切换运维模式
168
+ - [ ] Esc 三级停止(目标模式)
169
+ - [ ] `GOAL_ACHIEVED` 自动停止
170
+ - [ ] `/max 50` 修改轮数上限
171
+ - [ ] 不同项目独立模式状态
172
+ - [ ] 余额耗尽自动停止
173
+
174
+ ---
175
+
176
+ ## 实现现状补充(2026-09-12)
177
+
178
+ 本节记录与上面设计稿**不一致**的最终实现,避免后来者按设计稿误判代码。
179
+
180
+ | 设计稿 | 实现现状 | 原因 |
181
+ |------|---------|------|
182
+ | Esc 三级停止(停总监 → 停开发者 → 退出) | **一次 Esc 停整个目标模式**(停总监循环 + 取消开发者 worker + 关双栏 + 关 goal_mode);空闲时才是退出确认 | 三级停止需记"第几次 Esc"状态,实际使用中用户按第一次没停住会反复按;一次停干净更可预期 |
183
+ | 离开目标模式不自动清理(保留历史) | 停止/关闭/切换时把现场**归档**到 `.nexforge/goal_archive/<时间戳>-<标签>/`,现场清空 | "保留现场"会让下次开启把旧目标误判为"插话"(note_20260825_214722);归档同时满足可回看与不误判 |
184
+ | 余额耗尽检测 `_balance == "0.00"` | `parse_balance()` 数值化,`<=0` 才算耗尽;解析不出则不停止 | 子串匹配会把 `¥100.00`/`¥20.00`/`¥1,000.00` 误判为耗尽 |
185
+ | 总监/开发者回合失败无约定 | 失败必可见:开发者异常结束补"失败回执"交总监决策;总监回合失败重试一次后**暂停**(保留现场,回一句话即续跑) | 失败没有回执通道时,循环停在 `await _wake_event.wait()`,用户看到的是"AI 不动了" |
186
+
187
+ 详见 ADR `docs/decisions/2026-09-12-目标模式失败可见与历史保全.md`。
@@ -0,0 +1,176 @@
1
+ # 决策:目标模式的失败必须可见,历史必须保全
2
+
3
+ > 日期:2026-09-12 · 状态:生效
4
+
5
+ ## 背景
6
+
7
+ 目标模式(总监 + 开发者双角色循环)在"正常路径"上已经跑通,但**失败路径**有三类
8
+ 用户侧完全看不见的故障,且所有停止路径都会把历史记录删掉。
9
+
10
+ 1. **开发者回合异常结束 → 总监循环静默挂起**。开发者的"完成"信号只有一条通道:
11
+ `TURN_DONE` → `on_turn_done`(`ui/screens/chat.py`)。而 `ProviderError` 只 yield
12
+ `ERROR`(`core/agent.py:189`)、单轮超时走 `asyncio.timeout`、worker 被取消(切会话/
13
+ Esc/退出)都没有该事件 → `_dev_done_flag` 永远为 False → 循环停在
14
+ `await self._wake_event.wait()`(`features/mode_features.py`)。用户看到的是"AI 不动了,
15
+ 也没有任何提示",只有再插一句话才可能被唤醒(而插话只是响应,不会重新派发任务)。
16
+ 2. **总监回合失败 → 同款静默挂起**。`_run_director_safe` 只接 `TimeoutError`;其它异常
17
+ 冒泡到 `_director_loop` 最外层,提示一句"已跳过"后循环继续 `await`,而已经没有人
18
+ 会再派发任务。
19
+ 3. **余额耗尽判定是子串匹配**。`"0.00" in _balance`,而余额文案是 `f"¥{v:,.2f}"`
20
+ (`provider/balance.py`)—— 整元余额 `¥100.00` / `¥20.00` / `¥1,000.00` 都含子串
21
+ `"0.00"`(实测),于是开发者回合刚结束就被判"余额耗尽",**并连带清掉全部轮次存档**。
22
+ 4. **所有停止路径都 `rmtree` 目标目录**(完成 / 失败 / 会话切换 / Esc / F8),轮次复盘
23
+ 记录永久消失。这与 `doc/项目总监循环-开发计划.md`("离开目标模式后不自动清理,保留
24
+ 历史")相矛盾;但反过来"直接保留现场"又会让下次开启时旧目标被误判为"插话"
25
+ (知识库 note_20260825_214722 实测过)。
26
+
27
+ ## 决策
28
+
29
+ **失败路径**(三层:回执 → 重试 → 暂停,逐级兜底):
30
+
31
+ 1. **失败回执通道**:`GoalModeFeature.notify_dev_turn_aborted(reason)`,由
32
+ `ChatScreen._run_agent` 的 `finally` 触发(仅当 `dev_log=True` 且 `_dev_busy` 仍为 True,
33
+ 即"确实在跑开发者、且没走正常完成回调")。语义是"本轮没有产出报告",交总监按审核框架
34
+ 决定重试/换策略/结束。连续 `DEV_FAIL_LIMIT=3` 轮无报告(上游持续故障)→ 停止目标模式并
35
+ 明确告知,避免无限派发空转烧 token。
36
+ 2. **总监回合**:异常在 `_run_director_safe` 统一收口为 `None` → 退避重试一次
37
+ (`DIRECTOR_RETRY_DELAY`)→ 仍失败则 `_pause_director(stage)`:**暂停循环但不关闭
38
+ `goal_mode`、不删目标/方案/轮次**,给出含原因的可见提示。用户下一句话即从暂停点续跑
39
+ (`_resume_from_pause` → `_director_loop(resume=stage)`;`review` 阶段用保留的报告重跑
40
+ 复盘,不重新分解)。用户插话失败时消息**放回队首**,不静默丢弃。
41
+ 3. **余额**:`parse_balance()` 数值化解析;解析出 `<= 0` 才算耗尽,解析不出(如
42
+ "(无法获取)"、"(千问: 控制台查看)")一律视为不确定、**不得据此停止**。
43
+
44
+ **历史**:归档替代删除。
45
+
46
+ 4. `GoalManager.archive(label)` 把现场(`nfgoal.md`/`plan.md`/`rounds/`)移动到
47
+ `.nexforge/goal_archive/<YYYYmmdd-HHMMSS>-<label>/`;现场清空 → 下次开启不会被旧目标
48
+ 误判。`archive_rounds()` 只归档轮次(保留目标/方案现场),用于"重启后恢复重跑"——
49
+ 否则新的 `001.md` 会**覆盖**旧轮次(静默丢内容)。
50
+ 5. 待确认态下输入分流:`is_plan_question()` 判为提问 → `ask_about_plan()` 只答疑
51
+ (不动目标、不重新规划、不动工);其余仍走 `amend_plan()`。
52
+
53
+ ## 理由
54
+
55
+ - **只做"失败就停模式"不够**:会清掉用户刚输入的长目标(误伤),且上游抖动本可自愈。
56
+ - **只做"无限重试"不够**:上游持续故障时无法收敛,用户看不到进展,token 白烧。
57
+ - **否决"保留现场、停止时不清理"**:会让下次开启把旧目标当成插话(note_20260825_214722)。
58
+ 归档同时满足"历史可查"与"现场干净"。
59
+ - **否决继续用子串判余额**:整元金额必然误判(实测三例),且误判会连带删档。
60
+ - **否决"解析不出余额就当作 0"**:平台不支持余额查询(千问)时会立刻误停 —— 误停代价
61
+ 远高于多跑一轮。
62
+ - **提问判据取保守**:误判成提问会让真正的修改意见被当闲聊(用户以为改了、实际没改,
63
+ 且无任何迹象);误判成意见只是多展开一轮重规划。两者代价不对称,故只认"明显疑问"
64
+ (疑问符号 / 疑问尾词 / 疑问开头词)。
65
+ - **暂停后按阶段续跑而非重新分解**:复盘失败时现场有报告和已完成的轮次,重新分解等于
66
+ 让之前的轮次白跑。
67
+
68
+ ## 代价与边界
69
+
70
+ - 余额查不到(平台无余额 API、网络失败)时,失去"耗尽自动停止"保护 —— 有意取舍。
71
+ - 归档目录随使用增长(每场目标一次),需用户自行清理;不参与会话不变量,也不自动清理。
72
+ - `_dev_fail_streak` / `_director_paused` 是内存态,重启后清零。
73
+ - 暂停恢复是"按阶段续跑",不重放历史上下文;分解阶段(rounds=0)失败恢复会重新分解
74
+ (此时无已完成轮次,无损失)。
75
+ - 归档是"移动",不是"复制":若用户在同一秒内连续开关目标模式,序号后缀避免覆盖
76
+ (`-1`/`-2`)。
77
+ - **多进程**:目标文件写入已原子化(读不到半截),但**没有跨进程互斥** —— 同一项目
78
+ 同时跑两个目标模式会互相覆盖 goal/plan/rounds。属于已知边界:目标模式语义本就
79
+ "一个项目一个目标",需要时再评估加锁(Windows 无 fcntl,需锁文件方案)。
80
+
81
+ ## 追加(同日):开发者角色约定与总监上下文治理
82
+
83
+ 同一轮打磨里还修了两处"目标模式跑久了自己坏掉"的隐患:
84
+
85
+ 1. **开发者角色约定**:`DEV_PROMPT`(执行报告格式 / `[BLOCKED]` / `[DUPLICATE]`)
86
+ 此前是死代码 —— 总监复盘 prompt 要求"按报告框架审核",开发者却从未被告知报告
87
+ 格式,总监拿不到结构化报告就容易误判"未完成"并重复派发。现在随每轮开发者指令
88
+ 注入(`_dispatch_dev` 前置 DEV_PROMPT)。
89
+ 2. **总监会话治理**:总监会话只写不读、从未压缩,长目标模式下必然超出上下文窗口 →
90
+ 之后每轮总监回合都失败(进入"暂停"),整体停摆。现在 `trim_director_history()`
91
+ 在每轮 `add_user` 前折叠更早的沟通:保留 system + 最近 30 条 + 一条可见说明
92
+ (省略了多少条)。可以直接丢早期原文的理由:每轮 ctx 已自带目标/计划/开发者报告。
93
+
94
+ ## 追加(同日):P2 一致性小项
95
+
96
+ 3. **停止标记必须独立成行**:`_check_director_stop` 原本是**全文搜索** —— 总监提示词里
97
+ 就写着判定词,复盘时复述规则("尚未达到 GOAL_ACHIEVED 的条件")会被误判为停止。
98
+ 现在 `_stop_marker()` 只认**行首**标记(容忍 `#`/`-`/`>` 等装饰符),与
99
+ `2026-09-12-内容里的标记不得当成消息边界` 同源。总监答复用户时也用同一判据收束
100
+ (避免"嘴上说完成、模式不结束")。
101
+ 4. **轮次展示与判定统一**:`_mx_label()`(0 → `∞`,修掉界面与提示词里的"第1/0轮")、
102
+ `_round_limit_hit()`(统一 `round_count() >= max_r` 判定,去掉两处易误读的条件表达式)。
103
+ 5. **与 plan/json 模式互斥**:开目标模式时自动关闭 `plan_mode`(API 层 `tool_choice=none`
104
+ + 只读白名单 → 开发者改不了文件,空转)与 `json_mode`(强制 `response_format=json_object`
105
+ → 报告/指令/停止标记全变成 JSON 字段),并在界面提示。
106
+ 6. **目标文件原子写**:`set_goal` / `set_plan` / `save_round` 改走 `_atomic_write`
107
+ (临时文件 + `os.replace`)—— 同一项目多进程时读方不会读到半截文件(判据
108
+ "目标非空/方案非空"不再瞬时误判)。跨进程**互斥锁**仍未做(见"代价与边界")。
109
+ 7. **验收客观证据**:复盘前自动采集工作区改动摘要附到总监 ctx,并明确"与开发者报告
110
+ 冲突时以客观证据为准"。此前总监只能看开发者的**自述报告**(可虚报/漏报)。
111
+ 证据采集走 `asyncio.to_thread`(子进程/树扫描不得阻塞事件循环),失败静默降级为空串。
112
+
113
+ 实测校准(2026-09-12 真实目标模式运行,被测项目 12 轮 / 12 个里程碑):
114
+ - **只靠 git 不够**:被测项目**根本不是 git 仓库**(AI 从零创建的项目常无 git init),
115
+ `git status/diff` 恒为空 → "以客观证据为准"成空话(会话里"客观证据"出现 38 次,
116
+ 全是规则文本,没有一次真实证据)。**决策:证据源 = git + 文件树快照**——
117
+ `_snapshot_tree()` 扫描项目树(排除 `.nexforge`/`__pycache__`/`logs`/`node_modules` 等噪音),
118
+ 每轮复盘 diff 出"新增/修改/删除"清单;git 可用时再叠加"未提交改动 + 最近一次提交"
119
+ (开发者若规范地每轮 commit,只有 `git log -1 --stat` 有信息)。
120
+ - **总监会话按条数裁剪是无效设计**:该会话 28 条消息 = **请求体量 11.4 万字符**
121
+ (总监的复盘/指令单条最长 3.8 万字符);实测 `DIRECTOR_HISTORY_LIMIT=30` 从未触发
122
+ (28 < 31)。**决策:改为"条数 + 体量"双约束**(`DIRECTOR_CHAR_BUDGET = 60_000` 字符,
123
+ 最新 ctx 无论如何必须完整保留)。真实数据验证:该会话 28 条/11.4 万 → 16 条/6.1 万。
124
+
125
+ > 注:会话文件显示 53.2 万字符是**人读格式里结构标记 base64 负载**造成的膨胀,
126
+ > 不等于发给模型的大小 —— 判据要落到"请求体量"(`director_load` 实测),不要看文件字节数。
127
+ 8. **总监只读工具**(`[ui] director_tools`,默认开):总监回合从 `provider.complete`
128
+ 改为 `AgentLoop.run_turn`,带 `tool_filter=DIRECTOR_READONLY_TOOLS`(9 个只读工具:
129
+ read_file / list_dir / search_content / search_files / git_status / git_diff /
130
+ inspect_text / read_csv / query_sqlite)与 `max_iters=8`(核验不是通读仓库)。
131
+ 理由:总监此前只能看开发者自述 + 预采证据,无法"自己看一眼"就下判断。
132
+ 硬边界(不靠提示词自律):目标模式是 auto 免审批 → 写/删/执行类工具**在 API 层
133
+ 不下发**(顺带把工具 schema 从 39 个压到 9 个,省约 7.7k tokens/次)。
134
+ 代价与开关:每用一次工具就多一轮往返、工具结果进上下文(成本上升),因此留开关;
135
+ **`tool_filter=set()`(空集)= 一个工具都不给,`None` = 不限制** —— 关开关时传空集,
136
+ 避免把全部工具连同写权限放开(这是实现时真实踩到的坑,已用测试钉住)。
137
+ 9. **`max_iters` 不得被目标模式放大**:目标模式会把普通工具轮数上限提到 500,
138
+ 受限角色显式传入的 `max_iters` 优先(`AgentLoop._iter_limit()`),否则一次核验
139
+ 可能把整个仓库读完。
140
+ 10. **会话分段容量 200 → 500 行,切分改用真实行数**(`_SEGMENT_MAX_LINES`、
141
+ `_msg_line_count` 精确化):
142
+ - 实测(2026-09-12 目标模式会话):943 条消息 / 21,141 行 → 200 行/段 =
143
+ **111 个文件/会话**(现场观测 121 个),而每次保存都全量重写它们;改成 500 行后
144
+ **43 个**(-61%)。旧会话无需迁移:下次保存即按新容量重写并 prune 多余段。
145
+ - 连带修掉一个真问题:`_msg_line_count` 原为**估算**(漏算标题行、思考折叠标签、
146
+ 工具调用块、结构标记行与空行)→ 按"≤500 行"切出的段实际可达 **744 行**,
147
+ 容量约束形同虚设。改成直接量 `_format_message()` 的真实行数(切分本来就要
148
+ 格式化,总成本不变)。
149
+ - 否决"增量写分段":收益只是省 IO(3MB 写入在 SSD 上是几十毫秒),代价是要处理
150
+ 压缩导致的段前缀变化、旧段被手改等失败模式 —— 复杂度/风险不成比例。真痛点是
151
+ **文件数**(会话列表、孤儿清理、备份都要扫它们),故只解决它。
152
+ 11. **归档查看/清理入口**(`/goal archive`、`/goal archive clean [N]`):归档只增不减
153
+ (每场目标一次,实测 12 轮 ≈ 75KB),需要"看得见、能决定删哪些"的入口。
154
+ `GoalManager.list_archives()` 按目录名(时间戳+标签,同秒带序号)降序 → 新的在前,
155
+ 并统计轮数与体积;`clean_archives(keep)` 保留最近 keep 场(0 = 全删)。
156
+ **删除必须过确认弹窗**:归档是轮次复盘记录的唯一副本,不可逆 —— 与"不允许无声
157
+ 丢失"同一条纪律(不禁止删除,但必须由用户明确确认)。keep 大于实际场数时一个
158
+ 都不删(参数越界不得造成误删,测试钉住)。
159
+
160
+ > 完整的"总监只读工具"(总监自己调 read_file/git_status 等)**未做**:
161
+ > 需要给 `AgentLoop` 加工具白名单并让总监回合走工具循环,会改变 token 消耗与
162
+ > 行为,需真机验证后再上。当前用"预采证"拿同等价值的信息,零行为风险。
163
+
164
+ ## 关联
165
+
166
+ - 模块:`features/mode_features.py`(回执/重试/暂停/恢复/提问/开发者约定)、
167
+ `ui/screens/chat.py`(`_run_agent` finally 回执、待确认态分流、总监会话裁剪)、
168
+ `ui/screens/chat_actions.py`(Esc 停止改为归档)、
169
+ `core/goal_manager.py`(`parse_balance` / `archive` / `archive_rounds` /
170
+ `trim_director_history`)
171
+ - 文档:`manual/06-权限与模式.md`(目标模式一节)、`doc/项目总监循环-开发计划.md`
172
+ - 测试:`tests/test_goal_stability.py`(28 例:余额判据 / 失败回执 / 暂停恢复 / 归档 /
173
+ 提问分流 / 开发者角色约定 / 总监会话裁剪)、
174
+ `tests/test_goal_confirm.py`(Esc 归档断言)、`tests/test_director_loop.py`(停止归档断言)
175
+ - 知识库:note_20260824_124256(P1 常驻循环)、note_20260825_214722 / note_20260825_215306、
176
+ note_20260907_025446