modmgr 0.0.2__tar.gz → 0.0.3__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.
- {modmgr-0.0.2/src/modmgr.egg-info → modmgr-0.0.3}/PKG-INFO +21 -7
- {modmgr-0.0.2 → modmgr-0.0.3}/README.md +20 -6
- {modmgr-0.0.2 → modmgr-0.0.3}/pyproject.toml +1 -1
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/__init__.py +1 -1
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/acf_parser.py +0 -30
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/apply_ops.py +19 -1
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/backup_dir_builder.py +6 -16
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/backup_ops.py +157 -70
- modmgr-0.0.3/src/modmgr/bootstrap.py +136 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/cli.py +28 -24
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/core/workspacemanager.py +19 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/database_ops.py +230 -1
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/engine.py +57 -4
- modmgr-0.0.3/src/modmgr/orchestrator/__init__.py +136 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/orchestrator/_common.py +14 -17
- modmgr-0.0.3/src/modmgr/orchestrator/compute_pipeline.py +140 -0
- modmgr-0.0.3/src/modmgr/orchestrator/data_port.py +229 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/orchestrator/entry.py +2 -0
- modmgr-0.0.3/src/modmgr/orchestrator/fileops/__init__.py +292 -0
- modmgr-0.0.3/src/modmgr/orchestrator/fileops/_common.py +11 -0
- modmgr-0.0.3/src/modmgr/orchestrator/fileops/planner/__init__.py +1 -0
- {modmgr-0.0.2/src/modmgr/orchestrator → modmgr-0.0.3/src/modmgr/orchestrator/fileops/planner}/ignore_rules.py +10 -22
- modmgr-0.0.3/src/modmgr/orchestrator/fileops/planner/planner.py +263 -0
- {modmgr-0.0.2/src/modmgr/orchestrator → modmgr-0.0.3/src/modmgr/orchestrator/fileops/planner}/preflight.py +3 -9
- modmgr-0.0.3/src/modmgr/orchestrator/resolver.py +65 -0
- modmgr-0.0.3/src/modmgr/orchestrator/verifier.py +34 -0
- modmgr-0.0.3/src/modmgr/osplatform.py +83 -0
- modmgr-0.0.3/src/modmgr/path_normalizer.py +153 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/paths.py +46 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/prep.py +22 -6
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/restore_ops.py +19 -7
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/rule_aggregator.py +28 -27
- modmgr-0.0.3/src/modmgr/rule_validator.py +262 -0
- modmgr-0.0.3/src/modmgr/userconfig_ops.py +157 -0
- {modmgr-0.0.2 → modmgr-0.0.3/src/modmgr.egg-info}/PKG-INFO +21 -7
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr.egg-info/SOURCES.txt +72 -49
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/__init__.py +2 -2
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/adapters.py +8 -3
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/app.py +5 -4
- modmgr-0.0.3/src/modmgr_web/dependencies.py +23 -0
- modmgr-0.0.3/src/modmgr_web/routes/config.py +75 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/routes/database.py +11 -7
- modmgr-0.0.3/src/modmgr_web/routes/os_defaults.py +22 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/routes/rules.py +94 -65
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/routes/workspace.py +104 -52
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/schemas.py +14 -34
- modmgr-0.0.2/src/modmgr_web/static/assets/AdvancedPage-BlynjfkZ.css → modmgr-0.0.3/src/modmgr_web/static/assets/AdvancedPage-BOy2nqQ8.css +1 -1
- modmgr-0.0.3/src/modmgr_web/static/assets/AdvancedPage-CwT_3NzI.js +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/ComputePrepPage-BxOuQEE4.js +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/ConflictsPage-st8yBvaW.js +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/DataSourcePage-B0Fb4feM.css +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/DataSourcePage-BtCbwJ-T.js +9 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/DatabaseSelector.vue_vue_type_script_setup_true_lang-BIJrR2HG.js +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/ForestPage-6KpG9V6V.js +1 -0
- modmgr-0.0.2/src/modmgr_web/static/assets/ForestPage-Byt42R5I.css → modmgr-0.0.3/src/modmgr_web/static/assets/ForestPage-DGF6rvaN.css +1 -1
- modmgr-0.0.3/src/modmgr_web/static/assets/OperationsPage-D-Nv6brQ.js +1 -0
- modmgr-0.0.2/src/modmgr_web/static/assets/RuleEditorPage-BRdl1DQE.js → modmgr-0.0.3/src/modmgr_web/static/assets/RuleEditorPage-BSBCt3wv.js +1 -1
- modmgr-0.0.3/src/modmgr_web/static/assets/RulesOverviewPage-X6AwekNq.js +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/RulesOverviewPage-n5UOmk0q.css +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/SettingsPage-BqGIPRGT.css +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/SettingsPage-D__Ltuai.js +3 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/WorkspaceListPage-BhaxJXyF.js +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/WorkspaceListPage-CpPPvOBL.css +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/el-alert-D2Saa0Hc.js +1 -0
- modmgr-0.0.2/src/modmgr_web/static/assets/el-button-AT5h7hGh.js → modmgr-0.0.3/src/modmgr_web/static/assets/el-button-BYe4S2ex.js +2 -2
- modmgr-0.0.2/src/modmgr_web/static/assets/el-card-D-_HzL2Z.js → modmgr-0.0.3/src/modmgr_web/static/assets/el-card-s1CSqXfS.js +1 -1
- modmgr-0.0.3/src/modmgr_web/static/assets/el-checkbox-DeteIHNl.js +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/el-descriptions-vSz7N21L.js +1 -0
- modmgr-0.0.2/src/modmgr_web/static/assets/el-dialog-Cza5NAqp.js → modmgr-0.0.3/src/modmgr_web/static/assets/el-dialog-DwhSavoe.js +1 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/el-empty-CCIPJNFU.js → modmgr-0.0.3/src/modmgr_web/static/assets/el-empty-VMYF2sSP.js +1 -1
- modmgr-0.0.3/src/modmgr_web/static/assets/el-form-item-B4gKaEz8.js +12 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/el-overlay-wnSnOlkc.js +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/el-popconfirm-BGy5JHgt.js +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/el-radio-group-DoHaUrP6.js +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/el-select-OUVOOvVS.js +1 -0
- modmgr-0.0.2/src/modmgr_web/static/assets/el-switch-DIwbzpAs.js → modmgr-0.0.3/src/modmgr_web/static/assets/el-switch-BaqOoRAo.js +1 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/el-table-column-CHXB8sqU.js → modmgr-0.0.3/src/modmgr_web/static/assets/el-table-column-ZcwEwZCy.js +2 -2
- modmgr-0.0.3/src/modmgr_web/static/assets/el-tag-BkjtId4Z.js +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/el-tag-ChKtugzh.css +1 -0
- modmgr-0.0.2/src/modmgr_web/static/assets/errorCodes-R2Ns5uWN.js → modmgr-0.0.3/src/modmgr_web/static/assets/errorCodes-D-5ZmgKx.js +1 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/index-CS8EMmUO.js → modmgr-0.0.3/src/modmgr_web/static/assets/index-CD5SgAY3.js +1 -1
- modmgr-0.0.3/src/modmgr_web/static/assets/index-D1sN9TXS.js +20 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/index-DoSbT-ZE.js +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/index-wmYzOOc3.js +1 -0
- modmgr-0.0.3/src/modmgr_web/static/assets/omit-0VPi5Pw4.js +1 -0
- modmgr-0.0.2/src/modmgr_web/static/assets/scroll-B0BQcoln.js → modmgr-0.0.3/src/modmgr_web/static/assets/scroll-bIjgS0la.js +1 -1
- modmgr-0.0.3/src/modmgr_web/static/assets/validator-bvQTp9xD.js +1 -0
- modmgr-0.0.2/src/modmgr_web/static/assets/vue-vendor-D2-6FgTr.js → modmgr-0.0.3/src/modmgr_web/static/assets/vue-vendor-BAcbAOSy.js +1 -1
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/index.html +2 -2
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_backup_dir_builder.py +5 -18
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_backup_dir_multi_mod.py +2 -2
- modmgr-0.0.3/tests/test_backup_ops.py +95 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_backup_tree.py +129 -5
- modmgr-0.0.3/tests/test_bootstrap.py +187 -0
- modmgr-0.0.3/tests/test_case_mismatch_warning.py +121 -0
- modmgr-0.0.3/tests/test_database_ops_promotion.py +231 -0
- modmgr-0.0.3/tests/test_dataport_spec.py +724 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_dispatch_cross_contam.py +1 -1
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_dump_backup_assignment.py +1 -1
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_full_pipeline_integration.py +3 -3
- modmgr-0.0.3/tests/test_gate_boundary.py +177 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_ignore_rules.py +9 -21
- modmgr-0.0.3/tests/test_inherent_fixes.py +222 -0
- modmgr-0.0.3/tests/test_kmmignore_lifecycle.py +441 -0
- modmgr-0.0.3/tests/test_orchestrator.py +486 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_orchestrator_engine.py +93 -47
- modmgr-0.0.3/tests/test_osplatform.py +142 -0
- modmgr-0.0.3/tests/test_path_normalizer.py +350 -0
- modmgr-0.0.3/tests/test_paths.py +119 -0
- modmgr-0.0.3/tests/test_planner_fileops.py +278 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_preflight.py +20 -21
- modmgr-0.0.3/tests/test_restore_backupdir_contract.py +349 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_restore_ops.py +1 -1
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_rule_aggregator.py +4 -33
- modmgr-0.0.3/tests/test_rule_validator.py +345 -0
- modmgr-0.0.3/tests/test_userconfig_ops.py +179 -0
- modmgr-0.0.3/tests/test_validator_normalizer_placement.py +423 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_web_api.py +219 -398
- modmgr-0.0.3/tests/test_web_api_rule_sources.py +356 -0
- modmgr-0.0.3/tests/test_web_purification.py +512 -0
- modmgr-0.0.2/src/modmgr/bootstrap.py +0 -284
- modmgr-0.0.2/src/modmgr/orchestrator/__init__.py +0 -308
- modmgr-0.0.2/src/modmgr/orchestrator/compute_pipeline.py +0 -232
- modmgr-0.0.2/src/modmgr/orchestrator/planner_fileops.py +0 -151
- modmgr-0.0.2/src/modmgr/orchestrator/resolver.py +0 -116
- modmgr-0.0.2/src/modmgr_web/routes/config.py +0 -73
- modmgr-0.0.2/src/modmgr_web/routes/pipeline.py +0 -158
- modmgr-0.0.2/src/modmgr_web/static/assets/AdvancedPage-BVtD3b30.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/ComputePrepPage-Bbijng11.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/ConflictsPage-CtRN5peD.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/DataSourcePage-CYYM2t-S.css +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/DataSourcePage-la0myoei.js +0 -9
- modmgr-0.0.2/src/modmgr_web/static/assets/DatabaseSelector.vue_vue_type_script_setup_true_lang-BOtgwjhY.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/ForestPage-CdwZkKqj.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/OperationsPage-Df4OFUiU.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/RulesOverviewPage-CgxjIB-t.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/RulesOverviewPage-u3pKIDBY.css +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/SettingsPage-Bm_gPec4.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/SettingsPage-D2YOErl8.css +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/WorkspaceListPage-Bt5Ef8qB.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/WorkspaceListPage-gpzf4m3z.css +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/el-alert-IVqfzkxo.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/el-checkbox-DamL9NFG.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/el-descriptions-DCWEzttD.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/el-form-item-BTg7KMpb.js +0 -12
- modmgr-0.0.2/src/modmgr_web/static/assets/el-overlay-BozBPV_3.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/el-popconfirm-Dh0aYkpl.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/el-radio-group-DS4donKo.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/el-scrollbar-GF-yQkxY.css +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/el-scrollbar-bnCh1REM.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/el-select-CjDrv2OP.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/el-tag-1VV9QMa7.css +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/el-tag-CzJcUa9U.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/index-BvWwu1pq.js +0 -19
- modmgr-0.0.2/src/modmgr_web/static/assets/index-KQG8QDNo.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/index-xu_G5r7L.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/omit-DgViQIMi.js +0 -1
- modmgr-0.0.2/src/modmgr_web/static/assets/validator-DDEwb28U.js +0 -1
- modmgr-0.0.2/tests/test_backup_ops.py +0 -716
- modmgr-0.0.2/tests/test_bootstrap.py +0 -198
- modmgr-0.0.2/tests/test_orchestrator.py +0 -628
- modmgr-0.0.2/tests/test_paths.py +0 -56
- {modmgr-0.0.2 → modmgr-0.0.3}/LICENSE +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/MANIFEST.in +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/setup.cfg +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/core/__init__.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/forest_visual.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/iojson.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/path_resolver.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/pathstyle.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/schema.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/steam_scanner.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/validation.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr/vdf_parser.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr.egg-info/dependency_links.txt +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr.egg-info/entry_points.txt +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr.egg-info/requires.txt +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr.egg-info/top_level.txt +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/__main__.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/routes/__init__.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/routes/backups.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/sse.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/ComputePrepPage-Cuwyx6dM.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/ConflictsPage-Dfe3kTdp.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/OperationsPage-DUJyGPlV.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/RuleEditorPage-BN6I5Wjs.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/el-alert-B6UgayC7.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/el-button-DITZ5HsB.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/el-card-BAyktVMS.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/el-checkbox-CzNtyWdF.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/el-descriptions-BpDzfuC8.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/el-dialog-DdHdkgt4.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/el-empty-S7fQQ3B8.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/el-form-item-BUYvSc9V.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/el-input-xaztPnzw.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/el-overlay-BKLuON5C.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/el-popconfirm-BmypG9Rq.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/el-radio-group-iy_biC8N.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/el-select-CK58rX4v.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/el-switch-DpR9-s4E.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/el-table-column-Dp73S2HR.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/assets/index-BK5KbVso.css +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/favicon.jpg +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/src/modmgr_web/static/mockServiceWorker.js +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_apply_ops.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_cli_database_ops.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_contract.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_database_ops.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_engine.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_forest_visual.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_integration_fixtures.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_iojson.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_path_resolver.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_pathstyle.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_restore_per_design.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_steam_scanner.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_validation.py +0 -0
- {modmgr-0.0.2 → modmgr-0.0.3}/tests/test_web_entrypoint.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: modmgr
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3
|
|
4
4
|
Summary: File mapping and backup rule engine for workshop mods
|
|
5
5
|
Project-URL: Homepage, https://github.com/Knighthana/modmanager
|
|
6
6
|
Project-URL: Repository, https://github.com/Knighthana/modmanager
|
|
@@ -18,15 +18,20 @@ Requires-Dist: uvicorn[standard]>=0.23; extra == "web"
|
|
|
18
18
|
Dynamic: license-file
|
|
19
19
|
|
|
20
20
|
---
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
Status: active
|
|
22
|
+
Authority: reference-only
|
|
23
|
+
Purpose: readme for beginner
|
|
24
|
+
Read-Tier: never
|
|
25
|
+
Applicable-to: human-only
|
|
26
|
+
Unapplicable-to: agents
|
|
27
|
+
Updated: 2026-06-01
|
|
25
28
|
---
|
|
26
29
|
|
|
27
30
|
The Knighthana's Mod Manager
|
|
28
31
|
============================
|
|
29
32
|
|
|
33
|
+
作为向最终用户的说明文档省略了内部细节的详细描述,故此**禁止**任何Agent以此作为实现依据;
|
|
34
|
+
|
|
30
35
|
**项目仍然处于开发阶段,部分核心功能正在深度重构和优化,欢迎开发者加入讨论和贡献,但目前不建议一般用户直接用于生产环境**
|
|
31
36
|
|
|
32
37
|
探索性开发已告一段落,因个人工作变动,项目短期内将进入低活跃维护状态,欢迎有兴趣的开发者参与。
|
|
@@ -57,7 +62,7 @@ The Knighthana's Mod Manager(简称KMM)通过对"文件迁移过程"进行脱离
|
|
|
57
62
|
pip install modmgr
|
|
58
63
|
|
|
59
64
|
# 安装 Web 界面(可选)
|
|
60
|
-
pip install modmgr[web]
|
|
65
|
+
pip install "modmgr[web]"
|
|
61
66
|
|
|
62
67
|
# 启动 Web 服务(需先安装 web 依赖)
|
|
63
68
|
modmgr-web # → http://127.0.0.1:8000
|
|
@@ -73,16 +78,23 @@ modmgr-cli --help
|
|
|
73
78
|
待程序运行之后,请打开浏览器在[KMM面板](127.0.0.1:8000)进行操作:
|
|
74
79
|
|
|
75
80
|
1. 在“数据来源”点击“扫描Steam库”等待其完成,这一步是为了创建游戏-MOD数据库;
|
|
81
|
+

|
|
76
82
|
2. 在“设置面板”的“规则来源”下方,点击“➕ 添加来源”创建一个新的空行,将Modder交给你的kmmrule文件的路径填写在空行中,点击“保存”;
|
|
83
|
+

|
|
77
84
|
3. **务必**点击下方的“保存设置”按钮,对设定进行保存;
|
|
78
85
|
4. 进入“工作区”页面,点击右上方的“新建工作区”,输入必要的信息来创建一个工作区,每个工作区各自保存了一种替换模式,尽可能为每类不同的任务创建不同的工作区;
|
|
86
|
+
 
|
|
79
87
|
5. 在面板中点击工作区条目的“进入”来进入一个工作区;
|
|
80
88
|
6. 在“发现的规则文件”勾选Modder提供给你的kmmrule文件前方的复选框,如果感兴趣可以点击右侧的“展开”以查看这个规则的详细信息;
|
|
89
|
+

|
|
81
90
|
7. 点击“进入计算准备”,系统会自动将你导航到“计算准备”页面;
|
|
82
91
|
8. 仅保留想要替换的库/游戏/MOD前方的复选框,之后点击“开始计算”或者“计算查看”;复选框用于确定实际影响的游戏/MOD,可见按钮仅仅用于调整视觉效果,不影响最终结果;
|
|
92
|
+

|
|
83
93
|
9. 自行点击或等待系统导航进入“森林可视”界面,可以放大映射图,检查这些映射是不是你所想要的;
|
|
94
|
+

|
|
84
95
|
10. 如果有必要,在“冲突裁决”页面进行手动裁决;
|
|
85
96
|
11. 进入“文件操作”页面,如果这是首次操作,必须先点击“备份”,如果心存疑虑,务必打开"dry run"开关进行模拟;"dry run"不会进行任何实际的文件操作;
|
|
97
|
+

|
|
86
98
|
12. “备份”完成后,可以点击“应用”进行文件替换,等待操作完成;
|
|
87
99
|
13. 如果您的游戏/MOD需要分时间使用多个不同的规则,那么下次请在“备份”前先点击“恢复”,然后再“备份”和“应用”;
|
|
88
100
|
|
|
@@ -101,7 +113,7 @@ modmgr-cli --help
|
|
|
101
113
|
|---|------|-------|-----|
|
|
102
114
|
|用户配置|`~/.config/kmm/`|`%APPDATA%/kmm/`|`~/Library/Preferences/kmm/`|
|
|
103
115
|
|默认数据库|`~/.local/share/kmm/`|`%LOCALAPPDATA%/kmm/database/`|`~/Library/Application Support/kmm/`|
|
|
104
|
-
|默认工作区|`~/.cache/kmm/workspace/`|`%LOCALAPPDATA%/kmm/workspace
|
|
116
|
+
|默认工作区|`~/.cache/kmm/workspace/`|`%LOCALAPPDATA%/kmm/workspace/`|`~/Library/Caches/`|
|
|
105
117
|
|
|
106
118
|
这些值是硬编码的“默认值”,但目前也支持通过“设置面板”进行自定义;
|
|
107
119
|
|
|
@@ -130,6 +142,8 @@ modmgr-cli --help
|
|
|
130
142
|
|
|
131
143
|
项目还在成长,接受各种想法;
|
|
132
144
|
|
|
145
|
+
---------------------------
|
|
146
|
+
|
|
133
147
|
Knighthana
|
|
134
148
|
|
|
135
149
|
2026/05/22
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
Status: active
|
|
3
|
+
Authority: reference-only
|
|
4
|
+
Purpose: readme for beginner
|
|
5
|
+
Read-Tier: never
|
|
6
|
+
Applicable-to: human-only
|
|
7
|
+
Unapplicable-to: agents
|
|
8
|
+
Updated: 2026-06-01
|
|
6
9
|
---
|
|
7
10
|
|
|
8
11
|
The Knighthana's Mod Manager
|
|
9
12
|
============================
|
|
10
13
|
|
|
14
|
+
作为向最终用户的说明文档省略了内部细节的详细描述,故此**禁止**任何Agent以此作为实现依据;
|
|
15
|
+
|
|
11
16
|
**项目仍然处于开发阶段,部分核心功能正在深度重构和优化,欢迎开发者加入讨论和贡献,但目前不建议一般用户直接用于生产环境**
|
|
12
17
|
|
|
13
18
|
探索性开发已告一段落,因个人工作变动,项目短期内将进入低活跃维护状态,欢迎有兴趣的开发者参与。
|
|
@@ -38,7 +43,7 @@ The Knighthana's Mod Manager(简称KMM)通过对"文件迁移过程"进行脱离
|
|
|
38
43
|
pip install modmgr
|
|
39
44
|
|
|
40
45
|
# 安装 Web 界面(可选)
|
|
41
|
-
pip install modmgr[web]
|
|
46
|
+
pip install "modmgr[web]"
|
|
42
47
|
|
|
43
48
|
# 启动 Web 服务(需先安装 web 依赖)
|
|
44
49
|
modmgr-web # → http://127.0.0.1:8000
|
|
@@ -54,16 +59,23 @@ modmgr-cli --help
|
|
|
54
59
|
待程序运行之后,请打开浏览器在[KMM面板](127.0.0.1:8000)进行操作:
|
|
55
60
|
|
|
56
61
|
1. 在“数据来源”点击“扫描Steam库”等待其完成,这一步是为了创建游戏-MOD数据库;
|
|
62
|
+

|
|
57
63
|
2. 在“设置面板”的“规则来源”下方,点击“➕ 添加来源”创建一个新的空行,将Modder交给你的kmmrule文件的路径填写在空行中,点击“保存”;
|
|
64
|
+

|
|
58
65
|
3. **务必**点击下方的“保存设置”按钮,对设定进行保存;
|
|
59
66
|
4. 进入“工作区”页面,点击右上方的“新建工作区”,输入必要的信息来创建一个工作区,每个工作区各自保存了一种替换模式,尽可能为每类不同的任务创建不同的工作区;
|
|
67
|
+
 
|
|
60
68
|
5. 在面板中点击工作区条目的“进入”来进入一个工作区;
|
|
61
69
|
6. 在“发现的规则文件”勾选Modder提供给你的kmmrule文件前方的复选框,如果感兴趣可以点击右侧的“展开”以查看这个规则的详细信息;
|
|
70
|
+

|
|
62
71
|
7. 点击“进入计算准备”,系统会自动将你导航到“计算准备”页面;
|
|
63
72
|
8. 仅保留想要替换的库/游戏/MOD前方的复选框,之后点击“开始计算”或者“计算查看”;复选框用于确定实际影响的游戏/MOD,可见按钮仅仅用于调整视觉效果,不影响最终结果;
|
|
73
|
+

|
|
64
74
|
9. 自行点击或等待系统导航进入“森林可视”界面,可以放大映射图,检查这些映射是不是你所想要的;
|
|
75
|
+

|
|
65
76
|
10. 如果有必要,在“冲突裁决”页面进行手动裁决;
|
|
66
77
|
11. 进入“文件操作”页面,如果这是首次操作,必须先点击“备份”,如果心存疑虑,务必打开"dry run"开关进行模拟;"dry run"不会进行任何实际的文件操作;
|
|
78
|
+

|
|
67
79
|
12. “备份”完成后,可以点击“应用”进行文件替换,等待操作完成;
|
|
68
80
|
13. 如果您的游戏/MOD需要分时间使用多个不同的规则,那么下次请在“备份”前先点击“恢复”,然后再“备份”和“应用”;
|
|
69
81
|
|
|
@@ -82,7 +94,7 @@ modmgr-cli --help
|
|
|
82
94
|
|---|------|-------|-----|
|
|
83
95
|
|用户配置|`~/.config/kmm/`|`%APPDATA%/kmm/`|`~/Library/Preferences/kmm/`|
|
|
84
96
|
|默认数据库|`~/.local/share/kmm/`|`%LOCALAPPDATA%/kmm/database/`|`~/Library/Application Support/kmm/`|
|
|
85
|
-
|默认工作区|`~/.cache/kmm/workspace/`|`%LOCALAPPDATA%/kmm/workspace
|
|
97
|
+
|默认工作区|`~/.cache/kmm/workspace/`|`%LOCALAPPDATA%/kmm/workspace/`|`~/Library/Caches/`|
|
|
86
98
|
|
|
87
99
|
这些值是硬编码的“默认值”,但目前也支持通过“设置面板”进行自定义;
|
|
88
100
|
|
|
@@ -111,6 +123,8 @@ modmgr-cli --help
|
|
|
111
123
|
|
|
112
124
|
项目还在成长,接受各种想法;
|
|
113
125
|
|
|
126
|
+
---------------------------
|
|
127
|
+
|
|
114
128
|
Knighthana
|
|
115
129
|
|
|
116
130
|
2026/05/22
|
|
@@ -116,34 +116,6 @@ def parse_appworkshop_acf(acf_path: str) -> list[dict[str, Any]]:
|
|
|
116
116
|
return items
|
|
117
117
|
|
|
118
118
|
|
|
119
|
-
def find_appmanifest_acf_files(steamapps_path: str) -> dict[str, str]:
|
|
120
|
-
"""
|
|
121
|
-
Find all appmanifest_*.acf files in steamapps directory.
|
|
122
|
-
|
|
123
|
-
Args:
|
|
124
|
-
steamapps_path: Path to steamapps/ directory
|
|
125
|
-
|
|
126
|
-
Returns:
|
|
127
|
-
Dict: {appid: path_to_appmanifest_acf}
|
|
128
|
-
Example: {"270150": "/path/to/appmanifest_270150.acf", ...}
|
|
129
|
-
"""
|
|
130
|
-
raise NotImplementedError("To be implemented in M1.1")
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
def find_appworkshop_acf_files(steamapps_path: str) -> dict[str, str]:
|
|
134
|
-
"""
|
|
135
|
-
Find all appworkshop_*.acf files in steamapps directory.
|
|
136
|
-
|
|
137
|
-
Args:
|
|
138
|
-
steamapps_path: Path to steamapps/ directory
|
|
139
|
-
|
|
140
|
-
Returns:
|
|
141
|
-
Dict: {appid: path_to_appworkshop_acf}
|
|
142
|
-
Example: {"270150": "/path/to/appworkshop_270150.acf", ...}
|
|
143
|
-
"""
|
|
144
|
-
raise NotImplementedError("To be implemented in M1.1")
|
|
145
|
-
|
|
146
|
-
|
|
147
119
|
def get_workshop_timeupdated(steamapps_path: str, appid: str, contentid: str | None = None) -> str:
|
|
148
120
|
"""从 appworkshop_{appid}.acf 读取 timeupdated 字段并返回字符串。
|
|
149
121
|
|
|
@@ -295,8 +267,6 @@ def get_workshop_latest_timeupdated(steamapps_path: str, appid: str, contentid:
|
|
|
295
267
|
__all__ = [
|
|
296
268
|
"parse_appmanifest_acf",
|
|
297
269
|
"parse_appworkshop_acf",
|
|
298
|
-
"find_appmanifest_acf_files",
|
|
299
|
-
"find_appworkshop_acf_files",
|
|
300
270
|
"get_workshop_timeupdated",
|
|
301
271
|
"get_workshop_latest_timeupdated",
|
|
302
272
|
]
|
|
@@ -45,6 +45,11 @@ def apply_entries(
|
|
|
45
45
|
target_path = entry["path"]
|
|
46
46
|
request = entry.get("request")
|
|
47
47
|
|
|
48
|
+
if not target_path:
|
|
49
|
+
errors.append(f"E_APPLY_MISSING_TARGET: apply entry has empty target path")
|
|
50
|
+
finished += 1
|
|
51
|
+
continue
|
|
52
|
+
|
|
48
53
|
if request is None:
|
|
49
54
|
skipped.append({"path": target_path, "reason": "no source (vacuous node)"})
|
|
50
55
|
finished += 1
|
|
@@ -61,8 +66,10 @@ def apply_entries(
|
|
|
61
66
|
|
|
62
67
|
try:
|
|
63
68
|
if action == "delete":
|
|
69
|
+
# File-to-file guard in BOTH modes so dry_run reports
|
|
70
|
+
# the same errors the real run would
|
|
71
|
+
_assert_is_file(target_path, action)
|
|
64
72
|
if not dry_run:
|
|
65
|
-
_assert_is_file(target_path, action)
|
|
66
73
|
os.remove(target_path)
|
|
67
74
|
applied.append({
|
|
68
75
|
"action": "delete",
|
|
@@ -78,6 +85,17 @@ def apply_entries(
|
|
|
78
85
|
finished += 1
|
|
79
86
|
continue
|
|
80
87
|
|
|
88
|
+
# Existence + file-type checks in BOTH modes so dry_run
|
|
89
|
+
# reports the same errors the real run would (§6.2)
|
|
90
|
+
if os.path.isdir(source_path):
|
|
91
|
+
errors.append(f"E_APPLY_DIRECTORY_NOT_ALLOWED: {action} source is a directory: {source_path}")
|
|
92
|
+
finished += 1
|
|
93
|
+
continue
|
|
94
|
+
if not os.path.isfile(source_path):
|
|
95
|
+
errors.append(f"E_APPLY_MISSING_SOURCE: {source_path}")
|
|
96
|
+
finished += 1
|
|
97
|
+
continue
|
|
98
|
+
|
|
81
99
|
if not dry_run:
|
|
82
100
|
_assert_is_file(source_path, action)
|
|
83
101
|
os.makedirs(os.path.dirname(target_path), exist_ok=True)
|
|
@@ -63,7 +63,7 @@ def build_backup_dirs(
|
|
|
63
63
|
- backup_dir → 属于该目录的文件绝对路径列表
|
|
64
64
|
- warnings: 稳定性检查中被跳过的 contentid 警告信息
|
|
65
65
|
"""
|
|
66
|
-
baksuffix = str(user_config.get("baksuffix"
|
|
66
|
+
baksuffix = str(user_config.get("baksuffix"))
|
|
67
67
|
|
|
68
68
|
# ── 1. 收集所有目标路径 ──────────────────────────────────────────
|
|
69
69
|
targets: list[str] = []
|
|
@@ -190,23 +190,13 @@ def build_backup_dir(
|
|
|
190
190
|
return next(iter(dirs.keys()))
|
|
191
191
|
|
|
192
192
|
|
|
193
|
-
def load_dir_suffixes(
|
|
194
|
-
"""
|
|
193
|
+
def load_dir_suffixes() -> list[str]:
|
|
194
|
+
"""返回硬编码的目录名后缀列表。
|
|
195
195
|
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
始终包含 ``".kmmbackup"``。
|
|
197
|
+
kmmignore 规则仅来自 ``.kmmignore`` 文件,不再通过此函数读取。
|
|
198
198
|
"""
|
|
199
|
-
|
|
200
|
-
config_ignore = user_config.get("ignore")
|
|
201
|
-
if isinstance(config_ignore, list):
|
|
202
|
-
for item in config_ignore:
|
|
203
|
-
if isinstance(item, str) and item.strip():
|
|
204
|
-
s = item.strip()
|
|
205
|
-
if not s.startswith("."):
|
|
206
|
-
s = "." + s
|
|
207
|
-
if s not in suffixes:
|
|
208
|
-
suffixes.append(s)
|
|
209
|
-
return suffixes
|
|
199
|
+
return [".kmmbackup"]
|
|
210
200
|
|
|
211
201
|
|
|
212
202
|
__all__ = [
|