nexforge-cli 0.2.17__tar.gz → 0.2.18__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.
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/.gitignore +38 -30
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/PKG-INFO +6 -2
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/README.md +5 -1
- nexforge_cli-0.2.18/docs/decisions/2026-09-10-fails-loud/345/210/206/347/272/247.md +41 -0
- nexforge_cli-0.2.18/docs/decisions/2026-09-10-/344/274/232/350/257/235/344/270/215/345/217/230/351/207/217.md +40 -0
- nexforge_cli-0.2.18/docs/decisions/2026-09-10-/344/276/235/350/265/226/344/270/200/350/207/264/346/200/247.md +46 -0
- nexforge_cli-0.2.18/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 +46 -0
- nexforge_cli-0.2.18/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 +38 -0
- nexforge_cli-0.2.18/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 +43 -0
- nexforge_cli-0.2.18/docs/decisions/2026-09-10-/350/264/250/351/207/217gate/344/275/223/347/263/273.md +33 -0
- nexforge_cli-0.2.18/docs/decisions/README.md +63 -0
- nexforge_cli-0.2.18/docs/evidence/D10_acceptance.log +17 -0
- nexforge_cli-0.2.18/docs/evidence/D10_full_test.log +44 -0
- nexforge_cli-0.2.18/docs/evidence/D11_a4.log +36 -0
- nexforge_cli-0.2.18/docs/evidence/D11_full_test.log +45 -0
- nexforge_cli-0.2.18/docs/evidence/D12_audit.md +60 -0
- nexforge_cli-0.2.18/docs/evidence/D12_gap.log +12 -0
- nexforge_cli-0.2.18/docs/evidence/D13_break.log +6 -0
- nexforge_cli-0.2.18/docs/evidence/D13_e2e.log +13 -0
- nexforge_cli-0.2.18/docs/evidence/D13_full_test.log +36 -0
- nexforge_cli-0.2.18/docs/evidence/D13_gaps.log +9 -0
- nexforge_cli-0.2.18/docs/evidence/D14_audit.md +64 -0
- nexforge_cli-0.2.18/docs/evidence/D14_full_test.log +24 -0
- nexforge_cli-0.2.18/docs/evidence/D14_recheck.log +29 -0
- nexforge_cli-0.2.18/docs/evidence/D15_audit.md +105 -0
- nexforge_cli-0.2.18/docs/evidence/D4_fast.log +10 -0
- nexforge_cli-0.2.18/docs/evidence/D4_full_test.log +43 -0
- nexforge_cli-0.2.18/docs/evidence/D4_hook.log +21 -0
- nexforge_cli-0.2.18/docs/evidence/D4_scene_c.log +22 -0
- nexforge_cli-0.2.18/docs/evidence/D4_scene_d.log +24 -0
- nexforge_cli-0.2.18/docs/evidence/D4_scene_e.log +10 -0
- nexforge_cli-0.2.18/docs/evidence/D5_audit.md +83 -0
- nexforge_cli-0.2.18/docs/evidence/D5_b2_plugin.log +11 -0
- nexforge_cli-0.2.18/docs/evidence/D5_full_test.log +44 -0
- nexforge_cli-0.2.18/docs/evidence/D6_b3_a.log +10 -0
- nexforge_cli-0.2.18/docs/evidence/D6_b3_b.log +8 -0
- nexforge_cli-0.2.18/docs/evidence/D6_b3_c.log +4 -0
- nexforge_cli-0.2.18/docs/evidence/D6_b4_provider.log +10 -0
- nexforge_cli-0.2.18/docs/evidence/D6_full_test.log +45 -0
- nexforge_cli-0.2.18/docs/evidence/D7_dedup.log +24 -0
- nexforge_cli-0.2.18/docs/evidence/D7_full_test.log +45 -0
- nexforge_cli-0.2.18/docs/evidence/D8_audit.md +93 -0
- nexforge_cli-0.2.18/docs/evidence/D8_invariant.log +22 -0
- nexforge_cli-0.2.18/docs/evidence/D9_after.log +3 -0
- nexforge_cli-0.2.18/docs/evidence/D9_before.log +22 -0
- nexforge_cli-0.2.18/docs/evidence/D9_decision.md +62 -0
- nexforge_cli-0.2.18/docs/evidence/D9_full_test.log +45 -0
- nexforge_cli-0.2.18/docs/evidence/D9_rebuild.log +16 -0
- nexforge_cli-0.2.18/docs/evidence/E_cap_fulltest.log +7 -0
- nexforge_cli-0.2.18/docs/evidence/E_capabilities.log +12 -0
- nexforge_cli-0.2.18/docs/evidence/E_engines.log +19 -0
- nexforge_cli-0.2.18/docs/evidence/E_engines_fulltest.log +7 -0
- nexforge_cli-0.2.18/docs/evidence/E_tts_availability.log +12 -0
- nexforge_cli-0.2.18/docs/evidence/E_tts_fulltest.log +7 -0
- nexforge_cli-0.2.18/docs/evidence/E_tts_installer.log +9 -0
- nexforge_cli-0.2.18/docs/evidence/E_vision_channels.log +14 -0
- nexforge_cli-0.2.18/docs/evidence/E_vision_fulltest.log +7 -0
- nexforge_cli-0.2.18/docs/evidence/F_decisions_fulltest.log +7 -0
- nexforge_cli-0.2.18/docs/evidence/deps_fulltest.log +7 -0
- nexforge_cli-0.2.18/docs/evidence/deps_reverse.log +13 -0
- nexforge_cli-0.2.18/docs/evidence/fix_fulltest.log +7 -0
- nexforge_cli-0.2.18/docs/evidence/health_fulltest.log +7 -0
- nexforge_cli-0.2.18/docs/evidence/health_report.md +93 -0
- nexforge_cli-0.2.18/docs/evidence/health_scan.log +113 -0
- nexforge_cli-0.2.18/docs/evidence/release_0218_fulltest.log +7 -0
- nexforge_cli-0.2.18/docs/session-invariant.md +103 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/manual/01-/345/256/211/350/243/205/344/270/216/351/205/215/347/275/256.md +1 -1
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/manual/02-/347/225/214/351/235/242/344/270/216/345/277/253/346/215/267/351/224/256.md +1 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/manual/10-/346/217/222/344/273/266/345/274/200/345/217/221.md +6 -1
- nexforge_cli-0.2.18/manual/11-/345/274/200/345/217/221/346/240/241/351/252/214.md +95 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/manual/README.md +3 -1
- nexforge_cli-0.2.18/plugin_speech_summary/README.md +68 -0
- nexforge_cli-0.2.18/plugin_speech_summary/install_plugin.py +109 -0
- nexforge_cli-0.2.18/plugin_speech_summary/speech_summary.py +374 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/pyproject.toml +1 -1
- nexforge_cli-0.2.18/scripts/__init__.py +4 -0
- nexforge_cli-0.2.18/scripts/check.py +139 -0
- nexforge_cli-0.2.18/scripts/gates/__init__.py +35 -0
- nexforge_cli-0.2.18/scripts/gates/base.py +49 -0
- nexforge_cli-0.2.18/scripts/gates/hygiene.py +235 -0
- nexforge_cli-0.2.18/scripts/gates/manual_consistency.py +107 -0
- nexforge_cli-0.2.18/scripts/gates/registry_consistency.py +184 -0
- nexforge_cli-0.2.18/scripts/gates/version_sync.py +100 -0
- nexforge_cli-0.2.18/scripts/install_hooks.py +159 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/__init__.py +1 -1
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/cli.py +9 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/config.py +185 -43
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/agent.py +2 -0
- nexforge_cli-0.2.18/src/nexforge/core/capability.py +90 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/federation.py +11 -6
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/plugin.py +60 -7
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/session.py +8 -1
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/features/auto_skills.py +6 -1
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/features/federation_feature.py +11 -3
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/i18n.py +2 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/provider/anthropic.py +2 -1
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/provider/openai.py +2 -1
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/store/session_store.py +168 -8
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/image_tools.py +112 -35
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/screenshot_tools.py +4 -1
- nexforge_cli-0.2.18/src/nexforge/tools/search.py +325 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/screens/chat.py +23 -4
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/slash_handler.py +21 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/file_browser.py +27 -13
- nexforge_cli-0.2.18/tests/test_capability.py +223 -0
- nexforge_cli-0.2.18/tests/test_check_gates.py +361 -0
- nexforge_cli-0.2.18/tests/test_config.py +275 -0
- nexforge_cli-0.2.18/tests/test_deps.py +101 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_director_loop.py +173 -2
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_federation.py +47 -1
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_file_browser.py +57 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_goal_confirm.py +77 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_manual_consistency.py +34 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_plugin.py +69 -0
- nexforge_cli-0.2.18/tests/test_plugin_example_tts.py +144 -0
- nexforge_cli-0.2.18/tests/test_provider_errors.py +90 -0
- nexforge_cli-0.2.18/tests/test_session_invariant.py +158 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_session_store.py +172 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_vision_tool_retention.py +37 -2
- nexforge_cli-0.2.17/src/nexforge/tools/search.py +0 -210
- nexforge_cli-0.2.17/tests/test_config.py +0 -117
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/INSTALL.md +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/STATS_API.md +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/assets/icons/agent.svg +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/assets/icons/cost.svg +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/assets/icons/edit.svg +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/assets/icons/err.svg +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/assets/icons/file.svg +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/assets/icons/model.svg +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/assets/icons/ok.svg +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/assets/icons/read.svg +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/assets/icons/running.svg +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/assets/icons/search.svg +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/assets/icons/shell.svg +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/assets/icons/thinking.svg +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/assets/icons/web.svg +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/assets/icons/write.svg +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/config.example.toml +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/devlog/2026-07-07.md +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/doc//344/273/243/347/240/201/344/274/230/345/214/226/350/256/241/345/210/222.md" +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/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
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/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" +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/docs/submission/README-/346/212/225/347/250/277/350/257/264/346/230/216.md" +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/docs/submission/nexforge.md +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/docs/submission/nexforge.zh-CN.md +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/manual/03-/346/250/241/345/236/213/351/205/215/347/275/256.md" +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/manual/04-/345/267/245/345/205/267/345/217/202/350/200/203.md" +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/manual/05-/346/225/260/346/215/256/344/270/216/346/220/234/347/264/242.md" +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/manual/06-/346/235/203/351/231/220/344/270/216/346/250/241/345/274/217.md" +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/manual/07-/344/274/232/350/257/235/344/270/216/350/256/260/345/277/206.md" +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/manual/08-/350/207/252/345/256/232/344/271/211/351/205/215/347/275/256.md" +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/manual/09-/345/270/270/350/247/201/351/227/256/351/242/230.md" +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/manual//351/231/204/345/275/225-/345/257/271/346/257/224/345/210/206/346/236/220.md" +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/plugin_gui_auto/README.md +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/plugin_gui_auto/guiauto/__init__.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/plugin_gui_auto/guiauto/action.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/plugin_gui_auto/guiauto/base.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/plugin_gui_auto/guiauto/tools.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/plugin_gui_auto/guiauto/vision.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/plugin_gui_auto/guiauto/window.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/plugin_gui_auto/install_plugin.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/plugin_gui_auto/requirements.txt +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/plugin_gui_auto/smoke_safe.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/plugin_gui_auto/verify_final.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/plugin_gui_auto/verify_host.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/plugin_gui_auto/verify_plugin.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/scripts/publish.sh +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/scripts/smoke_provider.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/scripts/smoke_tui.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/__main__.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/app.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/__init__.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/context.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/goal_manager.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/jobs.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/knowledge_base.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/memory_engine.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/model_catalog.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/permissions.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/project_mapper.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/provider.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/router.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/summarizer.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/system_inject.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/tool_manifest.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/types.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/core/update_check.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/features/__init__.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/features/base.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/features/kb_feature.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/features/map_feature.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/features/memory_feature.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/features/mode_features.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/features/plan_feature.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/features/registry.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/features/session_feature.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/features/slash_feature.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/features/stats_feature.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/features/tool_manifest_feature.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/icons.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/mcp/__init__.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/provider/__init__.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/provider/_retry.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/provider/balance.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/provider/deepseek.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/provider/qianwen.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/skills/loader.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/stats/__init__.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/stats/heartbeat.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/store/__init__.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/store/director_store.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/store/plan_store.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/theme.tcss +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/__init__.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/_paths.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/background.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/base.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/data_tools.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/edit_file.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/federation.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/fs_ops.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/git.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/kb_tools.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/list_dir.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/multi_edit.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/ops_tools.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/read_file.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/registry.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/search_content.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/search_files.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/shell.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/web.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/tools/write_file.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/__init__.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/clipboard_image.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/screen_api.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/screens/__init__.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/screens/chat_actions.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/screens/splash.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/__init__.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/apikey_modal.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/banner.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/confirm_modal.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/diff_modal.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/file_menu.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/image_sidebar.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/messages.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/mode_warning.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/model_sidebar.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/multiline_modal.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/multiline_prompt.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/plan_sidebar.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/sidebar.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/ui/widgets/statusbar.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/utils/__init__.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/utils/logging.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/web/__init__.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/web/server.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/src/nexforge/web/static/index.html +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/conftest.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_app_mouse.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_approval.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_cross_platform.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_deepseek_provider.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_director_store.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_dual_panel.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_i18n.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_icons.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_lang_cmd.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_m2_tools.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_model_catalog.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_p2_core.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_project_map_prune.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_sanitize.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_screenshot_tools.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_session_repair.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_sidebar.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_sidebar_actions.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_splash_modal.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_statusbar.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_system_inject.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_tool_iters.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_tools.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_tui.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_update_check.py +0 -0
- {nexforge_cli-0.2.17 → nexforge_cli-0.2.18}/tests/test_vision_model.py +0 -0
|
@@ -1,30 +1,38 @@
|
|
|
1
|
-
# Python
|
|
2
|
-
__pycache__/
|
|
3
|
-
*.py[cod]
|
|
4
|
-
*.egg-info/
|
|
5
|
-
build/
|
|
6
|
-
dist/
|
|
7
|
-
.eggs/
|
|
8
|
-
|
|
9
|
-
# venv
|
|
10
|
-
.venv/
|
|
11
|
-
venv/
|
|
12
|
-
env/
|
|
13
|
-
|
|
14
|
-
# 测试 / 缓存
|
|
15
|
-
.pytest_cache/
|
|
16
|
-
.mypy_cache/
|
|
17
|
-
.ruff_cache/
|
|
18
|
-
|
|
19
|
-
# 会话与本地配置(不入库)
|
|
20
|
-
.nexforge/
|
|
21
|
-
*.jsonl
|
|
22
|
-
|
|
23
|
-
# 生成的图标位图
|
|
24
|
-
assets/icons/*.png
|
|
25
|
-
|
|
26
|
-
# IDE / OS
|
|
27
|
-
.idea/
|
|
28
|
-
.vscode/
|
|
29
|
-
.DS_Store
|
|
30
|
-
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
.eggs/
|
|
8
|
+
|
|
9
|
+
# venv
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
env/
|
|
13
|
+
|
|
14
|
+
# 测试 / 缓存
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
|
|
19
|
+
# 会话与本地配置(不入库)
|
|
20
|
+
.nexforge/
|
|
21
|
+
*.jsonl
|
|
22
|
+
|
|
23
|
+
# 生成的图标位图
|
|
24
|
+
assets/icons/*.png
|
|
25
|
+
|
|
26
|
+
# IDE / OS
|
|
27
|
+
.idea/
|
|
28
|
+
.vscode/
|
|
29
|
+
.DS_Store
|
|
30
|
+
|
|
31
|
+
# 凭据 / 恢复码(永不入库)
|
|
32
|
+
PyPI-*.txt
|
|
33
|
+
*recovery-code*
|
|
34
|
+
*recovery_code*
|
|
35
|
+
credentials*.env
|
|
36
|
+
*.pem
|
|
37
|
+
id_rsa*
|
|
38
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: nexforge-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.18
|
|
4
4
|
Summary: NexForgeCLI — 一个面向 DeepSeek V4 的终端智能体(TUI + CLI 双模式)
|
|
5
5
|
Project-URL: Homepage, https://gitee.com/Lighthorn/nexforgecli
|
|
6
6
|
Author: NexForge
|
|
@@ -51,7 +51,11 @@ Description-Content-Type: text/markdown
|
|
|
51
51
|
|
|
52
52
|
NexForgeCLI 是一个运行在终端里的智能体助手,既支持 DeepSeek/千问等多模型,也是**插件宿主**(plugins 目录即插即用)。既能作为全屏 TUI 交互式对话/编码,也能作为 one-shot 命令行工具嵌进脚本和管道。
|
|
53
53
|
|
|
54
|
-
> 当前版本:**v0.2.
|
|
54
|
+
> 当前版本:**v0.2.18** · PyPI: `pip install nexforge-cli`
|
|
55
|
+
|
|
56
|
+
**v0.2.18 要点**:新增 `/capabilities`(一眼看清各能力是否可用、为何不可用);
|
|
57
|
+
会话可重建(恢复/切换后模型看到的历史与当初一致,工具链不再丢失);
|
|
58
|
+
插件与配置的静默失败治理(出错必可见);敏感文件硬拦截;push 前质量门禁。
|
|
55
59
|
|
|
56
60
|
---
|
|
57
61
|
|
|
@@ -8,7 +8,11 @@
|
|
|
8
8
|
|
|
9
9
|
NexForgeCLI 是一个运行在终端里的智能体助手,既支持 DeepSeek/千问等多模型,也是**插件宿主**(plugins 目录即插即用)。既能作为全屏 TUI 交互式对话/编码,也能作为 one-shot 命令行工具嵌进脚本和管道。
|
|
10
10
|
|
|
11
|
-
> 当前版本:**v0.2.
|
|
11
|
+
> 当前版本:**v0.2.18** · PyPI: `pip install nexforge-cli`
|
|
12
|
+
|
|
13
|
+
**v0.2.18 要点**:新增 `/capabilities`(一眼看清各能力是否可用、为何不可用);
|
|
14
|
+
会话可重建(恢复/切换后模型看到的历史与当初一致,工具链不再丢失);
|
|
15
|
+
插件与配置的静默失败治理(出错必可见);敏感文件硬拦截;push 前质量门禁。
|
|
12
16
|
|
|
13
17
|
---
|
|
14
18
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# 决策:Fails Loud 分级(危险不得降级为警告)
|
|
2
|
+
|
|
3
|
+
> 日期:2026-09-10 · 状态:生效
|
|
4
|
+
|
|
5
|
+
## 背景
|
|
6
|
+
|
|
7
|
+
项目的病根是"静默失败 / 危险降级":
|
|
8
|
+
|
|
9
|
+
- 插件目录消失 → **一声不吭**(用户遇到"语音播报凭空没了",完全无从排查)
|
|
10
|
+
- 配置写错字段名 → Pydantic 默认忽略 → **静默无效果**
|
|
11
|
+
- `config.py` 有 4 处 `except Exception: pass` → **吞掉校验错误**,静默回退默认值
|
|
12
|
+
|
|
13
|
+
更具讽刺意味的是:修复过程中,`hygiene` gate 自己把"敏感凭据躺在工作区"降级成**不拦人的提示**——
|
|
14
|
+
gate 自己干了它要根治的事。
|
|
15
|
+
|
|
16
|
+
## 决策
|
|
17
|
+
|
|
18
|
+
1. **危险项默认失败**:敏感文件、残留目录、配置校验失败 → `[FAIL]` + 非 0 退出。
|
|
19
|
+
2. **例外只能走显式 allowlist**(`.hygiene-allow`),且**每次放行必须在输出中可见**。
|
|
20
|
+
3. **禁止"默认静默降级为警告"的路径**。
|
|
21
|
+
4. **能力缺失时**:要么报错(含修复指引),要么显式声明"降级/跳过"并可见。
|
|
22
|
+
5. **容错可以保留,但必须留痕**:如配置读失败 → 保留原文件 + 明确警告(而非覆盖)。
|
|
23
|
+
|
|
24
|
+
## 理由
|
|
25
|
+
|
|
26
|
+
- 危险与错误**必须可见**,且**不允许被降级为提示**——降级等于没检查。
|
|
27
|
+
- **否决"敏感文件只警告"**:那正是要根治的"看见了风险却放行"。
|
|
28
|
+
- **否决"用空 dict 覆盖损坏的配置"**:会丢失用户手写的注释与字段(数据丢失 > 启动失败)。
|
|
29
|
+
- **否决"能力缺失静默跳过"**:用户无法区分"没配"与"坏了"。
|
|
30
|
+
|
|
31
|
+
## 代价与边界
|
|
32
|
+
|
|
33
|
+
- 失败必须**可定位**(文件:行、期望 vs 实际),否则等于没报。
|
|
34
|
+
- 分级要克制:只有"用户期待的功能失败"才必须可见;清理/关闭类失败保持静默是合理的
|
|
35
|
+
(源码中仍有约 101 处 `except: pass`,经分类后判定多为合理防御)。
|
|
36
|
+
- 单点探测异常不得中断整体(如能力列举、插件加载)。
|
|
37
|
+
|
|
38
|
+
## 关联
|
|
39
|
+
|
|
40
|
+
`scripts/gates/hygiene.py`、`config.py`(ConfigIssue)、`core/plugin.py`、`core/capability.py`、
|
|
41
|
+
`plugin_speech_summary/`、`docs/session-invariant.md`
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# 决策:会话不变量(model-visible ⟺ logged)
|
|
2
|
+
|
|
3
|
+
> 日期:2026-09-10 · 状态:生效
|
|
4
|
+
> 详规见 [`docs/session-invariant.md`](../session-invariant.md)
|
|
5
|
+
|
|
6
|
+
## 背景
|
|
7
|
+
|
|
8
|
+
"恢复/切换会话后行为异常""输入丢失/错位"是历史高频抱怨,但一直说不清根因。
|
|
9
|
+
D8 审计用真实探针把它钉成了铁证:**构造含工具链的会话,`save → load` 后 5 条只剩 2 条**——
|
|
10
|
+
工具调用、工具结果、思考内容、注入的上下文**全部丢失**。
|
|
11
|
+
|
|
12
|
+
即:**模型看到的历史 ≠ 磁盘记录的历史**。
|
|
13
|
+
|
|
14
|
+
## 决策
|
|
15
|
+
|
|
16
|
+
1. 确立不变量:**凡是进入模型请求的内容,必须能由落盘数据重建**;
|
|
17
|
+
不能重建的,必须显式声明为"运行时派生"并给出补偿方式。**不允许无声地丢。**
|
|
18
|
+
2. 内容分三类:**P1 原始事实**(必须可逐项重建)、**P2 外部状态快照**(必须留痕)、
|
|
19
|
+
**P3 运行时派生**(不落盘,但须显式标记 + 恢复时补偿)。
|
|
20
|
+
判据核心:**事后能否重算**。
|
|
21
|
+
3. 落盘引入**结构化标记** `<!-- nf-msg <base64 JSON> -->` 作为**重建的唯一权威**;
|
|
22
|
+
人读 Markdown 保持不变(截断只影响展示,不影响重建)。
|
|
23
|
+
4. 注入的上下文(记忆/地图/知识库/工具清单)另存 `<id>.ctx.md` 快照留痕。
|
|
24
|
+
|
|
25
|
+
## 理由
|
|
26
|
+
|
|
27
|
+
- **否决"增强人读 Markdown 的解析"**:内容里出现 `### ❯ 用户`、`## ` 等会破坏解析
|
|
28
|
+
(实测已踩:注入内容里的 `## 标题` 被误判为轮次边界)→ 标记法无此歧义。
|
|
29
|
+
- **否决"抽独立 JSONL 存储"**:两套文件需同步,且旧会话迁移复杂;内嵌标记向后兼容(无标记即回退人读解析)。
|
|
30
|
+
- **否决"把注入内容混进会话消息"**:它们源自会变的项目文件,混入会让会话文件成倍膨胀且语义不清。
|
|
31
|
+
|
|
32
|
+
## 代价与边界
|
|
33
|
+
|
|
34
|
+
- 文件体积约 2 倍(人读部分 + 标记)。
|
|
35
|
+
- 标记是"机器真相",人读部分是"展示"——**二者不一致时以标记为准**(规则写死)。
|
|
36
|
+
- 派生项(如 `DEFAULT_SYSTEM`)**不进会话文件**,靠恢复时重放补偿;其定义处必须有显式标记说明。
|
|
37
|
+
|
|
38
|
+
## 关联
|
|
39
|
+
|
|
40
|
+
`store/session_store.py`、`core/session.py`、`ui/screens/chat.py`、`tests/test_session_invariant.py`
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# 决策:依赖一致性(只用已声明的依赖)
|
|
2
|
+
|
|
3
|
+
> 日期:2026-09-10 · 状态:生效
|
|
4
|
+
|
|
5
|
+
## 背景
|
|
6
|
+
|
|
7
|
+
健康体检时发现一个**真实可用性缺陷**:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
tools/image_tools.py: import requests ← 3 处
|
|
11
|
+
pyproject.toml 依赖: httpx, openai, pydantic, ...
|
|
12
|
+
↑ 没有 requests
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**本机恰好装了 `requests`**(所以测试全绿),但**全新用户 `pip install nexforge-cli` 后**,
|
|
16
|
+
识图/生图会因 `ImportError` 被 `except` 吞掉 → **静默失败**。
|
|
17
|
+
|
|
18
|
+
这既是一个可用性缺陷,也是"静默失败"病根的又一个实例。
|
|
19
|
+
|
|
20
|
+
## 决策
|
|
21
|
+
|
|
22
|
+
1. HTTP 客户端**统一为 httpx**(`pyproject` 已声明),全仓库不再使用 `requests`。
|
|
23
|
+
2. 新增 `tests/test_deps.py` 三条防线:
|
|
24
|
+
- **未声明的第三方 import**(AST 扫描全仓库,与 pyproject 声明比对)
|
|
25
|
+
- `image_tools` 具体回归(不得用 requests)
|
|
26
|
+
- HTTP 客户端一致性(全仓库不得 `import requests`)
|
|
27
|
+
3. 新增第三方依赖时,必须**同时**更新 `pyproject.toml`,否则测试会失败。
|
|
28
|
+
|
|
29
|
+
## 理由
|
|
30
|
+
|
|
31
|
+
- **本机环境 ≠ 用户环境**:依赖缺失类缺陷在本机不可见,只有"声明一致性检查"能提前发现。
|
|
32
|
+
- **否决"把 requests 加进依赖"**:项目已有 httpx,再加一个等价 HTTP 客户端徒增体积与维护面;
|
|
33
|
+
统一为 httpx 还能让超时/重试策略一致。
|
|
34
|
+
- **否决"只在代码里 try/except ImportError 静默降级"**:那会把缺陷藏得更深。
|
|
35
|
+
|
|
36
|
+
## 代价与边界
|
|
37
|
+
|
|
38
|
+
- httpx 与 requests 的 API 相近但不完全相同(本项目用到的 `post/get/.json()/.text/.status_code` 均一致)。
|
|
39
|
+
- 检查基于**顶层 import 的模块名**;通过 `importlib.import_module("字符串")` 的动态导入不在覆盖范围。
|
|
40
|
+
- 插件(`~/.nexforge/plugins/`)不受此检查约束——它们的额外依赖由插件的安装器负责(如
|
|
41
|
+
`plugin_gui_auto/requirements.txt`)。
|
|
42
|
+
|
|
43
|
+
## 关联
|
|
44
|
+
|
|
45
|
+
`tests/test_deps.py`、`src/nexforge/tools/image_tools.py`、`pyproject.toml`、
|
|
46
|
+
`docs/evidence/health_report.md`
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# 决策:D(回放测试)范围重定义
|
|
2
|
+
|
|
3
|
+
> 日期:2026-09-10 · 状态:**生效**
|
|
4
|
+
> 关联:D12 侦察(`docs/evidence/D12_audit.md`)、C 工程(`docs/session-invariant.md`)
|
|
5
|
+
> 说明:本文同时作为 **F(决策留痕)的首条记录**,确立 `docs/decisions/` 作为决策留痕位置。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 背景
|
|
10
|
+
|
|
11
|
+
D 工程原定目标:**"把目标模式四轮审查暴露的 12 个 bug 固化成回归网"**。
|
|
12
|
+
|
|
13
|
+
## 侦察结论(D12)
|
|
14
|
+
|
|
15
|
+
从 `.nexforge/kb/` 四份审查记录重建出 **11 条** bug(总监所述 12 条,差 1 条来源无法确认,未凑数):
|
|
16
|
+
|
|
17
|
+
| 覆盖状态 | 条数 | 说明 |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| 早已有既有测试 | 7 | 远早于 C 工程 |
|
|
20
|
+
| 由 C4 吸收 | 1 | 会话序列完整性(`test_session_invariant.py`)|
|
|
21
|
+
| 代码已删 | 1 | 无需回归 |
|
|
22
|
+
| **未覆盖** | 1 | #9 Esc 忙态判断 |
|
|
23
|
+
| **部分覆盖** | 1 | #10 停止后迟到回复 |
|
|
24
|
+
|
|
25
|
+
→ **原目标实际已完成**;再建回放网属于重复劳动(收敛原则点名的"反复磨同一模块、无新增价值")。
|
|
26
|
+
|
|
27
|
+
## 决策
|
|
28
|
+
|
|
29
|
+
1. **原 D 目标记为"已由既有测试 + C 工程吸收",不再单独建网。**
|
|
30
|
+
2. **D 重定义为"最小端到端回放"**:仅一条链路(提目标 → 出方案 → 确认 → 分解 → 执行 → 验收 → 停止),
|
|
31
|
+
在**每一步之后**校验会话不变量。独立价值在于覆盖 **D9/D10 才引入的重建链**,而非重测单点。
|
|
32
|
+
3. **刻意不建"框架"**:一条链路 + 复用既有夹具,避免为测试而测试。
|
|
33
|
+
4. **补齐仅存真缺口**:#9 / #10(D13 任务 1 已完成,含对照用例)。
|
|
34
|
+
|
|
35
|
+
## 理由
|
|
36
|
+
|
|
37
|
+
- **收敛原则**:反复磨同一模块、无新增价值即停。
|
|
38
|
+
- **侦察前置的收益**:避免约 2 天的重复劳动。这与 D8→D10 的教训同源——**先查证,再动工**。
|
|
39
|
+
|
|
40
|
+
## 影响
|
|
41
|
+
|
|
42
|
+
| 项 | 结果 |
|
|
43
|
+
|---|---|
|
|
44
|
+
| D 工程 | **完成(重定义后)** |
|
|
45
|
+
| F 工程 | 本文为首条决策记录,确立 `docs/decisions/` 位置 |
|
|
46
|
+
| 会话不变量 | 端到端回放成为其**跨组件验证入口**(`docs/session-invariant.md` §7)|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# 决策:审计以调用链为准(覆盖性结论须逐点附证)
|
|
2
|
+
|
|
3
|
+
> 日期:2026-09-10 · 状态:生效
|
|
4
|
+
|
|
5
|
+
## 背景
|
|
6
|
+
|
|
7
|
+
C1 审计(D8)产出了"模型可见输入点 14 处、类型 A 共 7 处未落盘"的结论。后续实践中发现**其中两处是错的**:
|
|
8
|
+
|
|
9
|
+
- 判"总监会话不落盘" → 实际 `chat.py:908` 早已每轮落盘(我只顺着内存对象查,没搜落盘调用链)
|
|
10
|
+
- 判"插话完全不记录" → 实际已随总监会话落盘(`chat.py:897` `add_user`)
|
|
11
|
+
|
|
12
|
+
同期还出现一次**方法错误**:用 `grep` 统计"裸 `except: pass`"得到 **0 处**(跨行匹配失效),
|
|
13
|
+
改用 AST 精确扫描后是 **101 处**。
|
|
14
|
+
|
|
15
|
+
## 决策
|
|
16
|
+
|
|
17
|
+
1. **结论以调用链为准**:判断"某内容是否落盘/是否执行"必须搜到实际调用点(`file:line`),
|
|
18
|
+
**不得只看对象形态或凭记忆**。
|
|
19
|
+
2. **凡下"共 N 处"这类覆盖性结论,每一点都须附证据**(调用链或工具输出)。
|
|
20
|
+
3. **工具给出的结论,必须先验证工具本身是否可靠**(grep 会说谎,AST 更可信)。
|
|
21
|
+
4. 清单**无法完整重建时如实声明缺项**,不得凑数(如"12 个 bug"实查为 11 条,差额来源无法确认)。
|
|
22
|
+
|
|
23
|
+
## 理由
|
|
24
|
+
|
|
25
|
+
- 覆盖性结论比单点结论**更容易出错**,却更常被当作事实引用——错一处会误导整条决策链
|
|
26
|
+
(D12 的"D 记已吸收"决定,正是建立在"7 条已覆盖"之上;若其中有假绿,决定就不成立)。
|
|
27
|
+
- **否决"凭记忆/凭印象下结论"**:本项目的记忆已多次被证伪。
|
|
28
|
+
|
|
29
|
+
## 代价与边界
|
|
30
|
+
|
|
31
|
+
- 审计更慢(要搜调用链、要写脚本实证)——但与"带着错误结论改错方向"相比,这个成本极低。
|
|
32
|
+
- 不要求每个细节都附证;**要求的是"覆盖性/否定性结论"必须有证据**。
|
|
33
|
+
- 实证脚本应落盘(`docs/evidence/`),便于复核。
|
|
34
|
+
|
|
35
|
+
## 关联
|
|
36
|
+
|
|
37
|
+
`docs/evidence/D8_audit.md`(含被后续修正的结论)、`D10`/`D14` 报告、
|
|
38
|
+
`scripts/gates/*`(gate 本身也遵守"失败必须可定位")
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# 决策:能力可用性上报(Capability 协议 + 注册制)
|
|
2
|
+
|
|
3
|
+
> 日期:2026-09-10 · 状态:生效
|
|
4
|
+
|
|
5
|
+
## 背景
|
|
6
|
+
|
|
7
|
+
E 工程审计发现:**多实现/可选能力**(识图、语音、搜索)在缺失时表现不一——
|
|
8
|
+
|
|
9
|
+
- 识图:**通道级静默**(单通道不可用不吭声,要等两路全废才报错)
|
|
10
|
+
- 语音:**全程静默**(引擎不可用/缺 SDK/非 Windows 一律无声)
|
|
11
|
+
- provider:**已达标**(注册制 + 缺什么报什么),可直接当模板
|
|
12
|
+
|
|
13
|
+
用户无法回答"这个功能现在能不能用、为什么不能用"。
|
|
14
|
+
|
|
15
|
+
## 决策
|
|
16
|
+
|
|
17
|
+
1. 定义统一契约 `Capability`:`name` / `title` / `available()` / `unavailable_reason()`。
|
|
18
|
+
2. **注册制**:`register_capability(impl)`,与 `provider.register_provider` 同构。
|
|
19
|
+
3. 提供 `get_capability(name)`(未登记返回 `None`,调用方决定报错还是降级)、
|
|
20
|
+
`describe_capabilities()` / `format_capabilities()`。
|
|
21
|
+
4. 新增 `/capabilities` 命令展示各能力状态与原因。
|
|
22
|
+
5. **只登记真正多实现/可替换的能力**(search / vision / tts);单实现无替换需求者
|
|
23
|
+
(kb / map / memory)**不登记**。
|
|
24
|
+
|
|
25
|
+
## 理由
|
|
26
|
+
|
|
27
|
+
- **三性**:可插拔(新增实现不改调用方分支)、可降级(先问 `available()` 再决定)、
|
|
28
|
+
可诊断(一条命令看清"哪个能力为何不可用")。
|
|
29
|
+
- **否决"给所有工具都套一层能力"**:单实现者套上去纯属过度抽象,徒增维护面。
|
|
30
|
+
- **否决"能力探测发真实请求"**:探测必须**只读、无副作用**(不发网络、不写文件),否则启动变慢且会打扰服务。
|
|
31
|
+
- **搜索引擎改为注册制**(原 if/elif 硬编码):新增引擎只需 `register_engine()`;
|
|
32
|
+
各引擎自带"配置就绪检查",被能力上报**复用**(单一真相,不重复实现判据)。
|
|
33
|
+
|
|
34
|
+
## 代价与边界
|
|
35
|
+
|
|
36
|
+
- 能力探测是**配置级**判断("有没有路"),不等于"请求一定成功"——文档已注明。
|
|
37
|
+
- 插件(如语音)登记能力时,需容忍旧版主程序无该模块(`except ImportError`)。
|
|
38
|
+
- 单个能力探测抛异常**不得**中断整体列举(记为该能力不可用 + 异常说明)。
|
|
39
|
+
|
|
40
|
+
## 关联
|
|
41
|
+
|
|
42
|
+
`core/capability.py`、`tools/search.py`、`tools/image_tools.py`、
|
|
43
|
+
`plugin_speech_summary/speech_summary.py`、`ui/slash_handler.py`、`tests/test_capability.py`
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# 决策:质量 Gate 体系(机器强制取代人肉提醒)
|
|
2
|
+
|
|
3
|
+
> 日期:2026-09-10 · 状态:生效
|
|
4
|
+
|
|
5
|
+
## 背景
|
|
6
|
+
|
|
7
|
+
此前所有质量约定都靠人记:改完记得跑 pytest、记得同步手册版本号、记得别提交凭据。
|
|
8
|
+
**人一忘,问题就漏**——曾出现版本号漂移、手册与代码脱节、敏感文件躺在工作区无人察觉。
|
|
9
|
+
对比 dsh(DeepSeek Harness)的做法:每条约定都配一个可执行 gate 并在 push 前强制运行。
|
|
10
|
+
|
|
11
|
+
## 决策
|
|
12
|
+
|
|
13
|
+
1. 建立聚合入口 `scripts/check.py`(`--fast` 秒级 / `--full` 含全量测试 / `--only` / `--list`)。
|
|
14
|
+
2. 每个校验项一个模块(`scripts/gates/`),**自动发现,新增无需注册**。
|
|
15
|
+
3. 提供 `scripts/install_hooks.py` 安装 **git 原生 pre-push 钩子**,失败即拦截;保留 `--no-verify` 逃生舱。
|
|
16
|
+
|
|
17
|
+
## 理由
|
|
18
|
+
|
|
19
|
+
- **把"我记得"变成"机器强制"**:纪律只有被执行才叫纪律。
|
|
20
|
+
- **否决了"为 gate 化而重构既有测试"**:`tests/test_manual_consistency.py` 是 212 行已验证的 pytest 用例,
|
|
21
|
+
重构成独立函数风险大于收益 → 改为**子进程包装 + 解析结果**(单一真相,不复制断言逻辑)。
|
|
22
|
+
- **否决引入 lefthook/ruff 等第三方**:项目约定"优先标准库";git 原生 hook + sh 脚本已足够。
|
|
23
|
+
- **否决"改错就静默通过"**:未发现任何 gate 本身也判失败(静默通过是最危险的失败模式)。
|
|
24
|
+
|
|
25
|
+
## 代价与边界
|
|
26
|
+
|
|
27
|
+
- pre-push 会拖慢推送 → fast gate 严格控制在秒级,全量测试只在 `--full` 或 CI。
|
|
28
|
+
- hook 装在本机(`.git/hooks/` 不入库)→ 换机器需重跑安装脚本;README/手册已说明。
|
|
29
|
+
- gate 只覆盖**已知**约定;新增约定需同步新增 gate。
|
|
30
|
+
|
|
31
|
+
## 关联
|
|
32
|
+
|
|
33
|
+
`scripts/check.py`、`scripts/gates/`、`scripts/install_hooks.py`、`manual/11-开发校验.md`
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# 决策记录(ADR)
|
|
2
|
+
|
|
3
|
+
> 本目录记录 NexForgeCLI 的**关键决策**:为什么这样设计、否决了哪些备选、代价是什么。
|
|
4
|
+
> 目的不是归档,而是**让后来者能分辨"有意为之"与"历史遗留"**——避免推翻一个深思熟虑的决定,
|
|
5
|
+
> 或在不知情的情况下重蹈已否决的方案。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 何时该写一条
|
|
10
|
+
|
|
11
|
+
**该写**(满足任一):
|
|
12
|
+
|
|
13
|
+
- 改变了**跨模块的约定或架构**(如统一能力接口、会话落盘格式)
|
|
14
|
+
- 在两个及以上合理方案中做了**取舍**,且否决理由值得记住
|
|
15
|
+
- 引入/拒绝了一项**依赖或工具链**
|
|
16
|
+
- 确立了一条**纪律**(如"审计以调用链为准"),且它是踩坑换来的
|
|
17
|
+
|
|
18
|
+
**不必写**:单点 bugfix、命名调整、纯样式改动、局部重构。
|
|
19
|
+
|
|
20
|
+
> **轻提示**:改 `src/nexforge/core/` 或 `src/nexforge/features/` 时,先自问一句
|
|
21
|
+
> "这算不算一条约定级决策?"——是就补一条。**不强制**(避免为写而写),
|
|
22
|
+
> 但若将来有人因缺少背景而误改,损失远大于写一条的成本。
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 格式
|
|
27
|
+
|
|
28
|
+
```markdown
|
|
29
|
+
# 决策:<一句话标题>
|
|
30
|
+
|
|
31
|
+
> 日期:YYYY-MM-DD · 状态:生效 / 已取代(指向新条目)
|
|
32
|
+
|
|
33
|
+
## 背景
|
|
34
|
+
(遇到了什么问题/约束)
|
|
35
|
+
|
|
36
|
+
## 决策
|
|
37
|
+
(定了什么)
|
|
38
|
+
|
|
39
|
+
## 理由
|
|
40
|
+
(为什么这样;**否决了哪些备选、为什么否决**)
|
|
41
|
+
|
|
42
|
+
## 代价与边界
|
|
43
|
+
(这个决定的成本、适用范围、什么时候该重新评估)
|
|
44
|
+
|
|
45
|
+
## 关联
|
|
46
|
+
(相关模块 / 文档 / 提交)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
文件名:`YYYY-MM-DD-<短标题>.md`。
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 索引
|
|
54
|
+
|
|
55
|
+
| 日期 | 决策 | 状态 |
|
|
56
|
+
|---|---|---|
|
|
57
|
+
| 2026-09-10 | [回放范围重定义](2026-09-10-回放范围重定义.md) | 生效 |
|
|
58
|
+
| 2026-09-10 | [质量 Gate 体系](2026-09-10-质量gate体系.md) | 生效 |
|
|
59
|
+
| 2026-09-10 | [Fails Loud 分级](2026-09-10-fails-loud分级.md) | 生效 |
|
|
60
|
+
| 2026-09-10 | [会话不变量](2026-09-10-会话不变量.md) | 生效 |
|
|
61
|
+
| 2026-09-10 | [能力可用性上报](2026-09-10-能力可用性上报.md) | 生效 |
|
|
62
|
+
| 2026-09-10 | [审计以调用链为准](2026-09-10-审计以调用链为准.md) | 生效 |
|
|
63
|
+
| 2026-09-10 | [依赖一致性](2026-09-10-依赖一致性.md) | 生效 |
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
=== D10 验收: A3/A4/A7 ===
|
|
2
|
+
=== A3: 上下文注入快照(记忆/地图/KB/外部工具) ===
|
|
3
|
+
快照轮数: 2
|
|
4
|
+
轮1: memory, project-map, kb, tool-manifest
|
|
5
|
+
轮2: memory
|
|
6
|
+
第1轮内容逐项一致: True
|
|
7
|
+
内容含 '## '/'### ' 未被误判为边界: True
|
|
8
|
+
第二轮独立可读: 第二轮记忆(已更新)
|
|
9
|
+
|
|
10
|
+
=== A4: 目标模式插话落盘 ===
|
|
11
|
+
总监会话条数: 2
|
|
12
|
+
插话内容在历史中可读: True
|
|
13
|
+
|
|
14
|
+
=== A7: 总监会话可重建 ===
|
|
15
|
+
原始 3 条 → 重建 3 条
|
|
16
|
+
严格可重建: True
|
|
17
|
+
exit=0
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
=== D10 全量回归 ===
|
|
2
|
+
......................................................................ss [ 18%]
|
|
3
|
+
s....................................................................... [ 37%]
|
|
4
|
+
........................................................................ [ 56%]
|
|
5
|
+
........................................................................ [ 75%]
|
|
6
|
+
........................................................................ [ 93%]
|
|
7
|
+
....................... [100%]
|
|
8
|
+
============================== warnings summary ===============================
|
|
9
|
+
tests/test_director_loop.py::test_dispatch_dev_keeps_long_goal
|
|
10
|
+
tests/test_director_loop.py::test_director_loop_full_flow
|
|
11
|
+
tests/test_director_loop.py::test_user_interrupt_soft
|
|
12
|
+
tests/test_director_loop.py::test_on_turn_done_dev_empty_content
|
|
13
|
+
D:\DevelopProject\NexForge\NexForgeCLI\tests\test_director_loop.py:44: RuntimeWarning: coroutine 'LoopScreen._mount' was never awaited
|
|
14
|
+
fn(*a, **k)
|
|
15
|
+
Enable tracemalloc to get traceback where the object was allocated.
|
|
16
|
+
See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.
|
|
17
|
+
|
|
18
|
+
tests/test_dual_panel.py::test_dev_log_hidden_initially
|
|
19
|
+
<string>:6: RuntimeWarning: coroutine 'GoalModeFeature._director_loop' was never awaited
|
|
20
|
+
Enable tracemalloc to get traceback where the object was allocated.
|
|
21
|
+
See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.
|
|
22
|
+
|
|
23
|
+
tests/test_federation.py::test_on_turn_done_full_chain
|
|
24
|
+
D:\DevelopProject\NexForge\NexForgeCLI\src\nexforge\features\federation_feature.py:100: RuntimeWarning: coroutine 'FederationFeature._sync_member_maps_async' was never awaited
|
|
25
|
+
self.screen._spawn(self._sync_member_maps_async(list(touched.keys())))
|
|
26
|
+
Enable tracemalloc to get traceback where the object was allocated.
|
|
27
|
+
See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.
|
|
28
|
+
|
|
29
|
+
tests/test_lang_cmd.py::test_lang_cmd_updates_sidebar_titles
|
|
30
|
+
C:\Users\48690\AppData\Roaming\Python\Python314\site-packages\textual\css\stylesheet.py:557: RuntimeWarning: coroutine 'GoalModeFeature._director_loop' was never awaited
|
|
31
|
+
rule_attributes[key].append((rule_specificity, value))
|
|
32
|
+
Enable tracemalloc to get traceback where the object was allocated.
|
|
33
|
+
See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.
|
|
34
|
+
|
|
35
|
+
tests/test_screenshot_tools.py::TestBlankDetection::test_pure_black_is_blank
|
|
36
|
+
tests/test_screenshot_tools.py::TestBlankDetection::test_white_not_blank
|
|
37
|
+
tests/test_screenshot_tools.py::TestBlankDetection::test_color_not_blank
|
|
38
|
+
tests/test_screenshot_tools.py::TestBlankDetection::test_mostly_black_but_content
|
|
39
|
+
D:\DevelopProject\NexForge\NexForgeCLI\src\nexforge\tools\screenshot_tools.py:183: DeprecationWarning: Image.Image.getdata is deprecated and will be removed in Pillow 14 (2027-10-15). Use get_flattened_data instead.
|
|
40
|
+
px = list(small.getdata())
|
|
41
|
+
|
|
42
|
+
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
|
|
43
|
+
380 passed, 3 skipped, 11 warnings in 122.72s (0:02:02)
|
|
44
|
+
exit=0
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
=== D11 任务1: A4 插话归属裁决 ===
|
|
2
|
+
=== 1) 插话入口的实际代码(chat.py) ===
|
|
3
|
+
365| )
|
|
4
|
+
366| return
|
|
5
|
+
367| # 已有目标 → 用户插话 → 入队(软打断: 总监响应用户, 不打断开发者)
|
|
6
|
+
368| gm_feat.enqueue_user_message(text)
|
|
7
|
+
369| await self._mount(UserMessage(text), dev=False) # 用户消息永远在下栏(修复: 开发者执行期间 _render_target=dev 会误挂上栏)
|
|
8
|
+
370| return
|
|
9
|
+
→ 该分支是否调用 self.session.add_user: False
|
|
10
|
+
|
|
11
|
+
=== 2) enqueue_user_message 的实现(只碰内存队列) ===
|
|
12
|
+
def enqueue_user_message(self, text: str) -> None:
|
|
13
|
+
"""用户在工作进行中插话 → 入队, 唤醒总监循环(软打断)。"""
|
|
14
|
+
self._user_inbox.append(text)
|
|
15
|
+
# 总监循环未运行(如重启后) → 先恢复, 避免"总监不理人"
|
|
16
|
+
if not self._director_loop_alive():
|
|
17
|
+
self._resume_director_loop()
|
|
18
|
+
self._wake_event.set()
|
|
19
|
+
|
|
20
|
+
=== 3) 实际执行: 插话后主会话是否被触及 ===
|
|
21
|
+
队列长度: 1
|
|
22
|
+
队列内容: ['优先修 bug']
|
|
23
|
+
本方法内是否出现 Session 引用: False
|
|
24
|
+
|
|
25
|
+
=== 4) 总监回合才写会话, 且写的是 _director_session ===
|
|
26
|
+
908| self._director_session.add_user(text)
|
|
27
|
+
918| self._director_session.add_assistant(msg)
|
|
28
|
+
919| self._save_director_session() # 每轮总监回合后落盘(隔离存储)
|
|
29
|
+
|
|
30
|
+
=== 结论 ===
|
|
31
|
+
插话 → _user_inbox(内存队列) → 总监循环 → _director_session.add_user
|
|
32
|
+
主会话 self.session 全程未被插话路径触及。
|
|
33
|
+
开发者(主 agent)收到的是总监加工后的指令(_dispatch_dev 的 instruction),
|
|
34
|
+
而非插话原文 → 插话不进入主会话的模型可见上下文。
|
|
35
|
+
⇒ 保持单写正确; 需在文档中写明'插话归属总监会话上下文'。
|
|
36
|
+
exit=0
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
=== D11 全量回归 ===
|
|
2
|
+
......................................................................ss [ 18%]
|
|
3
|
+
s....................................................................... [ 36%]
|
|
4
|
+
........................................................................ [ 55%]
|
|
5
|
+
........................................................................ [ 73%]
|
|
6
|
+
........................................................................ [ 92%]
|
|
7
|
+
.............................. [100%]
|
|
8
|
+
============================== warnings summary ===============================
|
|
9
|
+
tests/test_director_loop.py::test_dispatch_dev_keeps_long_goal
|
|
10
|
+
tests/test_director_loop.py::test_director_loop_full_flow
|
|
11
|
+
tests/test_director_loop.py::test_user_interrupt_soft
|
|
12
|
+
tests/test_director_loop.py::test_on_turn_done_dev_empty_content
|
|
13
|
+
D:\DevelopProject\NexForge\NexForgeCLI\tests\test_director_loop.py:44: RuntimeWarning: coroutine 'LoopScreen._mount' was never awaited
|
|
14
|
+
fn(*a, **k)
|
|
15
|
+
Enable tracemalloc to get traceback where the object was allocated.
|
|
16
|
+
See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.
|
|
17
|
+
|
|
18
|
+
tests/test_dual_panel.py::test_dev_log_hidden_initially
|
|
19
|
+
C:\Users\48690\AppData\Roaming\Python\Python314\site-packages\textual\content.py:1529: RuntimeWarning: coroutine 'GoalModeFeature._director_loop' was never awaited
|
|
20
|
+
new_lines = [Content(line, None) for line in line_text]
|
|
21
|
+
Enable tracemalloc to get traceback where the object was allocated.
|
|
22
|
+
See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.
|
|
23
|
+
|
|
24
|
+
tests/test_federation.py::test_on_turn_done_full_chain
|
|
25
|
+
D:\DevelopProject\NexForge\NexForgeCLI\src\nexforge\features\federation_feature.py:100: RuntimeWarning: coroutine 'FederationFeature._sync_member_maps_async' was never awaited
|
|
26
|
+
self.screen._spawn(self._sync_member_maps_async(list(touched.keys())))
|
|
27
|
+
Enable tracemalloc to get traceback where the object was allocated.
|
|
28
|
+
See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.
|
|
29
|
+
|
|
30
|
+
tests/test_lang_cmd.py::test_lang_cmd_updates_sidebar_titles
|
|
31
|
+
C:\Users\48690\AppData\Roaming\Python\Python314\site-packages\textual\message_pump.py:504: RuntimeWarning: coroutine 'GoalModeFeature._director_loop' was never awaited
|
|
32
|
+
message = events.Callback(callback=partial(callback, *args, **kwargs))
|
|
33
|
+
Enable tracemalloc to get traceback where the object was allocated.
|
|
34
|
+
See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.
|
|
35
|
+
|
|
36
|
+
tests/test_screenshot_tools.py::TestBlankDetection::test_pure_black_is_blank
|
|
37
|
+
tests/test_screenshot_tools.py::TestBlankDetection::test_white_not_blank
|
|
38
|
+
tests/test_screenshot_tools.py::TestBlankDetection::test_color_not_blank
|
|
39
|
+
tests/test_screenshot_tools.py::TestBlankDetection::test_mostly_black_but_content
|
|
40
|
+
D:\DevelopProject\NexForge\NexForgeCLI\src\nexforge\tools\screenshot_tools.py:183: DeprecationWarning: Image.Image.getdata is deprecated and will be removed in Pillow 14 (2027-10-15). Use get_flattened_data instead.
|
|
41
|
+
px = list(small.getdata())
|
|
42
|
+
|
|
43
|
+
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
|
|
44
|
+
387 passed, 3 skipped, 11 warnings in 124.45s (0:02:04)
|
|
45
|
+
exit=0
|