claude-mpm 4.7.4__py3-none-any.whl → 4.18.2__py3-none-any.whl
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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +118 -0
- claude_mpm/agents/BASE_ENGINEER.md +286 -0
- claude_mpm/agents/BASE_PM.md +106 -1
- claude_mpm/agents/OUTPUT_STYLE.md +329 -11
- claude_mpm/agents/PM_INSTRUCTIONS.md +397 -459
- claude_mpm/agents/agent_loader.py +17 -5
- claude_mpm/agents/frontmatter_validator.py +284 -253
- claude_mpm/agents/templates/README.md +465 -0
- claude_mpm/agents/templates/agent-manager.json +4 -1
- claude_mpm/agents/templates/agentic-coder-optimizer.json +13 -3
- claude_mpm/agents/templates/api_qa.json +11 -2
- claude_mpm/agents/templates/circuit_breakers.md +638 -0
- claude_mpm/agents/templates/clerk-ops.json +12 -2
- claude_mpm/agents/templates/code_analyzer.json +8 -2
- claude_mpm/agents/templates/content-agent.json +358 -0
- claude_mpm/agents/templates/dart_engineer.json +15 -2
- claude_mpm/agents/templates/data_engineer.json +15 -2
- claude_mpm/agents/templates/documentation.json +10 -2
- claude_mpm/agents/templates/engineer.json +21 -1
- claude_mpm/agents/templates/gcp_ops_agent.json +12 -2
- claude_mpm/agents/templates/git_file_tracking.md +584 -0
- claude_mpm/agents/templates/golang_engineer.json +270 -0
- claude_mpm/agents/templates/imagemagick.json +4 -1
- claude_mpm/agents/templates/java_engineer.json +346 -0
- claude_mpm/agents/templates/local_ops_agent.json +1227 -6
- claude_mpm/agents/templates/memory_manager.json +4 -1
- claude_mpm/agents/templates/nextjs_engineer.json +141 -133
- claude_mpm/agents/templates/ops.json +12 -2
- claude_mpm/agents/templates/php-engineer.json +270 -174
- claude_mpm/agents/templates/pm_examples.md +474 -0
- claude_mpm/agents/templates/pm_red_flags.md +240 -0
- claude_mpm/agents/templates/product_owner.json +338 -0
- claude_mpm/agents/templates/project_organizer.json +14 -4
- claude_mpm/agents/templates/prompt-engineer.json +13 -2
- claude_mpm/agents/templates/python_engineer.json +174 -81
- claude_mpm/agents/templates/qa.json +11 -2
- claude_mpm/agents/templates/react_engineer.json +16 -3
- claude_mpm/agents/templates/refactoring_engineer.json +12 -2
- claude_mpm/agents/templates/research.json +34 -21
- claude_mpm/agents/templates/response_format.md +583 -0
- claude_mpm/agents/templates/ruby-engineer.json +129 -192
- claude_mpm/agents/templates/rust_engineer.json +270 -0
- claude_mpm/agents/templates/security.json +10 -2
- claude_mpm/agents/templates/svelte-engineer.json +225 -0
- claude_mpm/agents/templates/ticketing.json +10 -2
- claude_mpm/agents/templates/typescript_engineer.json +116 -125
- claude_mpm/agents/templates/validation_templates.md +312 -0
- claude_mpm/agents/templates/vercel_ops_agent.json +12 -2
- claude_mpm/agents/templates/version_control.json +12 -2
- claude_mpm/agents/templates/web_qa.json +11 -2
- claude_mpm/agents/templates/web_ui.json +15 -2
- claude_mpm/cli/__init__.py +34 -614
- claude_mpm/cli/commands/agent_manager.py +25 -12
- claude_mpm/cli/commands/agent_state_manager.py +186 -0
- claude_mpm/cli/commands/agents.py +235 -148
- claude_mpm/cli/commands/agents_detect.py +380 -0
- claude_mpm/cli/commands/agents_recommend.py +309 -0
- claude_mpm/cli/commands/aggregate.py +7 -3
- claude_mpm/cli/commands/analyze.py +9 -4
- claude_mpm/cli/commands/analyze_code.py +7 -2
- claude_mpm/cli/commands/auto_configure.py +570 -0
- claude_mpm/cli/commands/config.py +47 -13
- claude_mpm/cli/commands/configure.py +419 -1571
- claude_mpm/cli/commands/configure_agent_display.py +261 -0
- claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
- claude_mpm/cli/commands/configure_hook_manager.py +225 -0
- claude_mpm/cli/commands/configure_models.py +18 -0
- claude_mpm/cli/commands/configure_navigation.py +167 -0
- claude_mpm/cli/commands/configure_paths.py +104 -0
- claude_mpm/cli/commands/configure_persistence.py +254 -0
- claude_mpm/cli/commands/configure_startup_manager.py +646 -0
- claude_mpm/cli/commands/configure_template_editor.py +497 -0
- claude_mpm/cli/commands/configure_validators.py +73 -0
- claude_mpm/cli/commands/local_deploy.py +537 -0
- claude_mpm/cli/commands/memory.py +54 -20
- claude_mpm/cli/commands/mpm_init.py +585 -196
- claude_mpm/cli/commands/mpm_init_handler.py +37 -3
- claude_mpm/cli/commands/search.py +170 -4
- claude_mpm/cli/commands/upgrade.py +152 -0
- claude_mpm/cli/executor.py +202 -0
- claude_mpm/cli/helpers.py +105 -0
- claude_mpm/cli/interactive/__init__.py +3 -0
- claude_mpm/cli/interactive/skills_wizard.py +491 -0
- claude_mpm/cli/parsers/__init__.py +7 -1
- claude_mpm/cli/parsers/agents_parser.py +9 -0
- claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
- claude_mpm/cli/parsers/base_parser.py +110 -3
- claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +65 -5
- claude_mpm/cli/shared/output_formatters.py +28 -19
- claude_mpm/cli/startup.py +481 -0
- claude_mpm/cli/utils.py +52 -1
- claude_mpm/commands/mpm-agents-detect.md +168 -0
- claude_mpm/commands/mpm-agents-recommend.md +214 -0
- claude_mpm/commands/mpm-agents.md +75 -1
- claude_mpm/commands/mpm-auto-configure.md +217 -0
- claude_mpm/commands/mpm-help.md +163 -0
- claude_mpm/commands/mpm-init.md +148 -3
- claude_mpm/commands/mpm-version.md +113 -0
- claude_mpm/commands/mpm.md +1 -0
- claude_mpm/config/agent_config.py +2 -2
- claude_mpm/config/model_config.py +428 -0
- claude_mpm/constants.py +1 -0
- claude_mpm/core/base_service.py +13 -12
- claude_mpm/core/enums.py +452 -0
- claude_mpm/core/factories.py +1 -1
- claude_mpm/core/instruction_reinforcement_hook.py +2 -1
- claude_mpm/core/interactive_session.py +9 -3
- claude_mpm/core/log_manager.py +2 -0
- claude_mpm/core/logging_config.py +6 -2
- claude_mpm/core/oneshot_session.py +8 -4
- claude_mpm/core/optimized_agent_loader.py +3 -3
- claude_mpm/core/output_style_manager.py +12 -192
- claude_mpm/core/service_registry.py +5 -1
- claude_mpm/core/types.py +2 -9
- claude_mpm/core/typing_utils.py +7 -6
- claude_mpm/dashboard/static/js/dashboard.js +0 -14
- claude_mpm/dashboard/templates/index.html +3 -41
- claude_mpm/hooks/__init__.py +20 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +4 -2
- claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +23 -2
- claude_mpm/hooks/failure_learning/__init__.py +60 -0
- claude_mpm/hooks/failure_learning/failure_detection_hook.py +235 -0
- claude_mpm/hooks/failure_learning/fix_detection_hook.py +217 -0
- claude_mpm/hooks/failure_learning/learning_extraction_hook.py +286 -0
- claude_mpm/hooks/instruction_reinforcement.py +7 -2
- claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
- claude_mpm/hooks/kuzu_memory_hook.py +37 -12
- claude_mpm/hooks/kuzu_response_hook.py +183 -0
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/services/agents/__init__.py +18 -5
- claude_mpm/services/agents/auto_config_manager.py +796 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
- claude_mpm/services/agents/deployment/agent_validator.py +17 -1
- claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
- claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
- claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
- claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
- claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
- claude_mpm/services/agents/local_template_manager.py +1 -1
- claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
- claude_mpm/services/agents/observers.py +547 -0
- claude_mpm/services/agents/recommender.py +568 -0
- claude_mpm/services/agents/registry/modification_tracker.py +5 -2
- claude_mpm/services/command_handler_service.py +11 -5
- claude_mpm/services/core/__init__.py +33 -1
- claude_mpm/services/core/interfaces/__init__.py +90 -3
- claude_mpm/services/core/interfaces/agent.py +184 -0
- claude_mpm/services/core/interfaces/health.py +172 -0
- claude_mpm/services/core/interfaces/model.py +281 -0
- claude_mpm/services/core/interfaces/process.py +372 -0
- claude_mpm/services/core/interfaces/project.py +121 -0
- claude_mpm/services/core/interfaces/restart.py +307 -0
- claude_mpm/services/core/interfaces/stability.py +260 -0
- claude_mpm/services/core/memory_manager.py +11 -24
- claude_mpm/services/core/models/__init__.py +79 -0
- claude_mpm/services/core/models/agent_config.py +381 -0
- claude_mpm/services/core/models/health.py +162 -0
- claude_mpm/services/core/models/process.py +235 -0
- claude_mpm/services/core/models/restart.py +302 -0
- claude_mpm/services/core/models/stability.py +264 -0
- claude_mpm/services/core/models/toolchain.py +306 -0
- claude_mpm/services/core/path_resolver.py +23 -7
- claude_mpm/services/diagnostics/__init__.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
- claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
- claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
- claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
- claude_mpm/services/diagnostics/checks/installation_check.py +30 -29
- claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
- claude_mpm/services/diagnostics/checks/mcp_check.py +50 -36
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +38 -33
- claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
- claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
- claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
- claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
- claude_mpm/services/diagnostics/models.py +19 -24
- claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
- claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
- claude_mpm/services/infrastructure/monitoring/base.py +5 -13
- claude_mpm/services/infrastructure/monitoring/network.py +7 -6
- claude_mpm/services/infrastructure/monitoring/process.py +13 -12
- claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
- claude_mpm/services/infrastructure/monitoring/service.py +16 -15
- claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
- claude_mpm/services/local_ops/__init__.py +163 -0
- claude_mpm/services/local_ops/crash_detector.py +257 -0
- claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
- claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
- claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
- claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
- claude_mpm/services/local_ops/health_manager.py +430 -0
- claude_mpm/services/local_ops/log_monitor.py +396 -0
- claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
- claude_mpm/services/local_ops/process_manager.py +595 -0
- claude_mpm/services/local_ops/resource_monitor.py +331 -0
- claude_mpm/services/local_ops/restart_manager.py +401 -0
- claude_mpm/services/local_ops/restart_policy.py +387 -0
- claude_mpm/services/local_ops/state_manager.py +372 -0
- claude_mpm/services/local_ops/unified_manager.py +600 -0
- claude_mpm/services/mcp_config_manager.py +9 -4
- claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
- claude_mpm/services/mcp_gateway/core/base.py +18 -31
- claude_mpm/services/mcp_gateway/main.py +30 -0
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +206 -32
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +30 -28
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +25 -5
- claude_mpm/services/mcp_service_verifier.py +1 -1
- claude_mpm/services/memory/failure_tracker.py +563 -0
- claude_mpm/services/memory_hook_service.py +165 -4
- claude_mpm/services/model/__init__.py +147 -0
- claude_mpm/services/model/base_provider.py +365 -0
- claude_mpm/services/model/claude_provider.py +412 -0
- claude_mpm/services/model/model_router.py +453 -0
- claude_mpm/services/model/ollama_provider.py +415 -0
- claude_mpm/services/monitor/daemon_manager.py +3 -2
- claude_mpm/services/monitor/handlers/dashboard.py +2 -1
- claude_mpm/services/monitor/handlers/hooks.py +2 -1
- claude_mpm/services/monitor/management/lifecycle.py +3 -2
- claude_mpm/services/monitor/server.py +2 -1
- claude_mpm/services/project/__init__.py +23 -0
- claude_mpm/services/project/detection_strategies.py +719 -0
- claude_mpm/services/project/toolchain_analyzer.py +581 -0
- claude_mpm/services/self_upgrade_service.py +342 -0
- claude_mpm/services/session_management_service.py +3 -2
- claude_mpm/services/session_manager.py +205 -1
- claude_mpm/services/shared/async_service_base.py +16 -27
- claude_mpm/services/shared/lifecycle_service_base.py +1 -14
- claude_mpm/services/socketio/handlers/__init__.py +5 -2
- claude_mpm/services/socketio/handlers/hook.py +13 -2
- claude_mpm/services/socketio/handlers/registry.py +4 -2
- claude_mpm/services/socketio/server/main.py +10 -8
- claude_mpm/services/subprocess_launcher_service.py +14 -5
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +7 -6
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
- claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
- claude_mpm/services/unified/deployment_strategies/local.py +6 -5
- claude_mpm/services/unified/deployment_strategies/utils.py +6 -5
- claude_mpm/services/unified/deployment_strategies/vercel.py +7 -6
- claude_mpm/services/unified/interfaces.py +3 -1
- claude_mpm/services/unified/unified_analyzer.py +14 -10
- claude_mpm/services/unified/unified_config.py +2 -1
- claude_mpm/services/unified/unified_deployment.py +9 -4
- claude_mpm/services/version_service.py +104 -1
- claude_mpm/skills/__init__.py +21 -0
- claude_mpm/skills/bundled/__init__.py +6 -0
- claude_mpm/skills/bundled/api-documentation.md +393 -0
- claude_mpm/skills/bundled/async-testing.md +571 -0
- claude_mpm/skills/bundled/code-review.md +143 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/docker-containerization.md +194 -0
- claude_mpm/skills/bundled/express-local-dev.md +1429 -0
- claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
- claude_mpm/skills/bundled/git-workflow.md +414 -0
- claude_mpm/skills/bundled/imagemagick.md +204 -0
- claude_mpm/skills/bundled/json-data-handling.md +223 -0
- claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
- claude_mpm/skills/bundled/pdf.md +141 -0
- claude_mpm/skills/bundled/performance-profiling.md +567 -0
- claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
- claude_mpm/skills/bundled/security-scanning.md +327 -0
- claude_mpm/skills/bundled/systematic-debugging.md +473 -0
- claude_mpm/skills/bundled/test-driven-development.md +378 -0
- claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
- claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
- claude_mpm/skills/bundled/xlsx.md +157 -0
- claude_mpm/skills/registry.py +286 -0
- claude_mpm/skills/skill_manager.py +310 -0
- claude_mpm/storage/state_storage.py +15 -15
- claude_mpm/tools/code_tree_analyzer.py +177 -141
- claude_mpm/tools/code_tree_events.py +4 -2
- claude_mpm/utils/agent_dependency_loader.py +40 -20
- claude_mpm/utils/display_helper.py +260 -0
- claude_mpm/utils/git_analyzer.py +407 -0
- claude_mpm/utils/robust_installer.py +73 -19
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/METADATA +129 -12
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/RECORD +295 -193
- claude_mpm/dashboard/static/css/code-tree.css +0 -1639
- claude_mpm/dashboard/static/index-hub-backup.html +0 -713
- claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
- claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
- claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
- claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
- claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
- claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
- claude_mpm/services/project/analyzer_refactored.py +0 -450
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/WHEEL +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Self-Upgrade Service
|
|
3
|
+
====================
|
|
4
|
+
|
|
5
|
+
Handles version checking and self-upgrade functionality for claude-mpm.
|
|
6
|
+
Supports pip, pipx, and npm installations with automatic detection.
|
|
7
|
+
|
|
8
|
+
WHY: Users should be notified of updates and have an easy way to upgrade
|
|
9
|
+
without manually running installation commands.
|
|
10
|
+
|
|
11
|
+
DESIGN DECISIONS:
|
|
12
|
+
- Detects installation method (pip/pipx/npm/editable)
|
|
13
|
+
- Non-blocking version checks with caching
|
|
14
|
+
- Interactive upgrade prompts with confirmation
|
|
15
|
+
- Automatic restart after upgrade
|
|
16
|
+
- Graceful failure handling (never breaks existing installation)
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import os
|
|
20
|
+
import subprocess
|
|
21
|
+
import sys
|
|
22
|
+
from datetime import datetime, timezone
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from typing import Dict, Optional, Tuple
|
|
25
|
+
|
|
26
|
+
from packaging import version
|
|
27
|
+
|
|
28
|
+
from ..core.logger import get_logger
|
|
29
|
+
from ..core.unified_paths import PathContext
|
|
30
|
+
from .mcp_gateway.utils.package_version_checker import PackageVersionChecker
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class InstallationMethod:
|
|
34
|
+
"""Installation method enumeration."""
|
|
35
|
+
|
|
36
|
+
PIP = "pip"
|
|
37
|
+
PIPX = "pipx"
|
|
38
|
+
NPM = "npm"
|
|
39
|
+
EDITABLE = "editable"
|
|
40
|
+
UNKNOWN = "unknown"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class SelfUpgradeService:
|
|
44
|
+
"""
|
|
45
|
+
Service for checking and performing self-upgrades.
|
|
46
|
+
|
|
47
|
+
Capabilities:
|
|
48
|
+
- Detect current installation method
|
|
49
|
+
- Check PyPI/npm for latest version
|
|
50
|
+
- Prompt user for upgrade confirmation
|
|
51
|
+
- Execute upgrade command
|
|
52
|
+
- Restart after upgrade
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(self):
|
|
56
|
+
"""Initialize the self-upgrade service."""
|
|
57
|
+
self.logger = get_logger("SelfUpgradeService")
|
|
58
|
+
self.version_checker = PackageVersionChecker()
|
|
59
|
+
self.current_version = self._get_current_version()
|
|
60
|
+
self.installation_method = self._detect_installation_method()
|
|
61
|
+
|
|
62
|
+
def _get_current_version(self) -> str:
|
|
63
|
+
"""
|
|
64
|
+
Get the current installed version.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Version string (e.g., "4.7.10")
|
|
68
|
+
"""
|
|
69
|
+
try:
|
|
70
|
+
from .. import __version__
|
|
71
|
+
|
|
72
|
+
return __version__
|
|
73
|
+
except ImportError:
|
|
74
|
+
# Fallback to VERSION file
|
|
75
|
+
try:
|
|
76
|
+
version_file = Path(__file__).parent.parent / "VERSION"
|
|
77
|
+
if version_file.exists():
|
|
78
|
+
return version_file.read_text().strip()
|
|
79
|
+
except Exception:
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
return "unknown"
|
|
83
|
+
|
|
84
|
+
def _detect_installation_method(self) -> str:
|
|
85
|
+
"""
|
|
86
|
+
Detect how claude-mpm was installed.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Installation method constant
|
|
90
|
+
"""
|
|
91
|
+
# Check for editable install
|
|
92
|
+
if PathContext.detect_deployment_context().name in [
|
|
93
|
+
"DEVELOPMENT",
|
|
94
|
+
"EDITABLE_INSTALL",
|
|
95
|
+
]:
|
|
96
|
+
return InstallationMethod.EDITABLE
|
|
97
|
+
|
|
98
|
+
# Check for pipx by looking at executable path
|
|
99
|
+
executable = sys.executable
|
|
100
|
+
if "pipx" in executable:
|
|
101
|
+
return InstallationMethod.PIPX
|
|
102
|
+
|
|
103
|
+
# Check if npm wrapper is present
|
|
104
|
+
try:
|
|
105
|
+
result = subprocess.run(
|
|
106
|
+
["npm", "list", "-g", "claude-mpm"],
|
|
107
|
+
check=False,
|
|
108
|
+
capture_output=True,
|
|
109
|
+
text=True,
|
|
110
|
+
timeout=5,
|
|
111
|
+
)
|
|
112
|
+
if result.returncode == 0 and "claude-mpm" in result.stdout:
|
|
113
|
+
return InstallationMethod.NPM
|
|
114
|
+
except Exception:
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
# Default to pip
|
|
118
|
+
return InstallationMethod.PIP
|
|
119
|
+
|
|
120
|
+
async def check_for_update(
|
|
121
|
+
self, cache_ttl: Optional[int] = None
|
|
122
|
+
) -> Optional[Dict[str, any]]:
|
|
123
|
+
"""
|
|
124
|
+
Check if an update is available.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
cache_ttl: Cache time-to-live in seconds (default: 24 hours)
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Dict with update info or None:
|
|
131
|
+
{
|
|
132
|
+
"current": "4.7.10",
|
|
133
|
+
"latest": "4.7.11",
|
|
134
|
+
"update_available": True,
|
|
135
|
+
"installation_method": "pipx",
|
|
136
|
+
"upgrade_command": "pipx upgrade claude-mpm"
|
|
137
|
+
}
|
|
138
|
+
"""
|
|
139
|
+
if self.current_version == "unknown":
|
|
140
|
+
self.logger.warning("Cannot check for updates: version unknown")
|
|
141
|
+
return None
|
|
142
|
+
|
|
143
|
+
# Check PyPI for Python installations
|
|
144
|
+
if self.installation_method in [
|
|
145
|
+
InstallationMethod.PIP,
|
|
146
|
+
InstallationMethod.PIPX,
|
|
147
|
+
]:
|
|
148
|
+
result = await self.version_checker.check_for_update(
|
|
149
|
+
"claude-mpm", self.current_version, cache_ttl
|
|
150
|
+
)
|
|
151
|
+
if result and result.get("update_available"):
|
|
152
|
+
result["installation_method"] = self.installation_method
|
|
153
|
+
result["upgrade_command"] = self._get_upgrade_command()
|
|
154
|
+
return result
|
|
155
|
+
|
|
156
|
+
# Check npm for npm installations
|
|
157
|
+
elif self.installation_method == InstallationMethod.NPM:
|
|
158
|
+
npm_version = await self._check_npm_version()
|
|
159
|
+
if npm_version:
|
|
160
|
+
current_ver = version.parse(self.current_version)
|
|
161
|
+
latest_ver = version.parse(npm_version)
|
|
162
|
+
if latest_ver > current_ver:
|
|
163
|
+
return {
|
|
164
|
+
"current": self.current_version,
|
|
165
|
+
"latest": npm_version,
|
|
166
|
+
"update_available": True,
|
|
167
|
+
"installation_method": InstallationMethod.NPM,
|
|
168
|
+
"upgrade_command": self._get_upgrade_command(),
|
|
169
|
+
"checked_at": datetime.now(timezone.utc).isoformat(),
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return None
|
|
173
|
+
|
|
174
|
+
async def _check_npm_version(self) -> Optional[str]:
|
|
175
|
+
"""
|
|
176
|
+
Check npm registry for latest version.
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
Latest version string or None
|
|
180
|
+
"""
|
|
181
|
+
try:
|
|
182
|
+
result = subprocess.run(
|
|
183
|
+
["npm", "view", "claude-mpm", "version"],
|
|
184
|
+
check=False,
|
|
185
|
+
capture_output=True,
|
|
186
|
+
text=True,
|
|
187
|
+
timeout=10,
|
|
188
|
+
)
|
|
189
|
+
if result.returncode == 0:
|
|
190
|
+
return result.stdout.strip()
|
|
191
|
+
except Exception as e:
|
|
192
|
+
self.logger.debug(f"npm version check failed: {e}")
|
|
193
|
+
|
|
194
|
+
return None
|
|
195
|
+
|
|
196
|
+
def _get_upgrade_command(self) -> str:
|
|
197
|
+
"""
|
|
198
|
+
Get the appropriate upgrade command for current installation method.
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
Shell command string to upgrade claude-mpm
|
|
202
|
+
"""
|
|
203
|
+
if self.installation_method == InstallationMethod.PIPX:
|
|
204
|
+
return "pipx upgrade claude-mpm"
|
|
205
|
+
if self.installation_method == InstallationMethod.NPM:
|
|
206
|
+
return "npm update -g claude-mpm"
|
|
207
|
+
if self.installation_method == InstallationMethod.PIP:
|
|
208
|
+
return f"{sys.executable} -m pip install --upgrade claude-mpm"
|
|
209
|
+
if self.installation_method == InstallationMethod.EDITABLE:
|
|
210
|
+
return "git pull && pip install -e ."
|
|
211
|
+
return "pip install --upgrade claude-mpm"
|
|
212
|
+
|
|
213
|
+
def prompt_for_upgrade(self, update_info: Dict[str, any]) -> bool:
|
|
214
|
+
"""
|
|
215
|
+
Prompt user to upgrade.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
update_info: Update information dict
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
True if user confirms upgrade, False otherwise
|
|
222
|
+
"""
|
|
223
|
+
current = update_info["current"]
|
|
224
|
+
latest = update_info["latest"]
|
|
225
|
+
method = update_info.get("installation_method", "unknown")
|
|
226
|
+
|
|
227
|
+
print("\n🎉 New version available!")
|
|
228
|
+
print(f" Current: v{current}")
|
|
229
|
+
print(f" Latest: v{latest}")
|
|
230
|
+
print(f" Installation method: {method}")
|
|
231
|
+
print(f"\nTo upgrade, run: {update_info['upgrade_command']}")
|
|
232
|
+
|
|
233
|
+
try:
|
|
234
|
+
response = input("\nWould you like to upgrade now? [y/N]: ").strip().lower()
|
|
235
|
+
return response in ["y", "yes"]
|
|
236
|
+
except (KeyboardInterrupt, EOFError):
|
|
237
|
+
print("\n")
|
|
238
|
+
return False
|
|
239
|
+
|
|
240
|
+
def perform_upgrade(self, update_info: Dict[str, any]) -> Tuple[bool, str]:
|
|
241
|
+
"""
|
|
242
|
+
Perform the upgrade.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
update_info: Update information dict
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
Tuple of (success: bool, message: str)
|
|
249
|
+
"""
|
|
250
|
+
command = update_info["upgrade_command"]
|
|
251
|
+
|
|
252
|
+
# Don't upgrade editable installs automatically
|
|
253
|
+
if self.installation_method == InstallationMethod.EDITABLE:
|
|
254
|
+
return (
|
|
255
|
+
False,
|
|
256
|
+
"Editable installation detected. Please update manually with: git pull && pip install -e .",
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
print("\n⏳ Upgrading claude-mpm...")
|
|
260
|
+
print(f" Running: {command}")
|
|
261
|
+
|
|
262
|
+
try:
|
|
263
|
+
# Execute upgrade command
|
|
264
|
+
result = subprocess.run(
|
|
265
|
+
command,
|
|
266
|
+
check=False,
|
|
267
|
+
shell=True,
|
|
268
|
+
capture_output=True,
|
|
269
|
+
text=True,
|
|
270
|
+
timeout=300, # 5 minutes
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
if result.returncode == 0:
|
|
274
|
+
return (True, f"✅ Successfully upgraded to v{update_info['latest']}")
|
|
275
|
+
error_msg = result.stderr or result.stdout or "Unknown error"
|
|
276
|
+
return (False, f"❌ Upgrade failed: {error_msg}")
|
|
277
|
+
|
|
278
|
+
except subprocess.TimeoutExpired:
|
|
279
|
+
return (False, "❌ Upgrade timed out")
|
|
280
|
+
except Exception as e:
|
|
281
|
+
return (False, f"❌ Upgrade failed: {e!s}")
|
|
282
|
+
|
|
283
|
+
def restart_after_upgrade(self) -> None:
|
|
284
|
+
"""
|
|
285
|
+
Restart claude-mpm after a successful upgrade.
|
|
286
|
+
|
|
287
|
+
Preserves original command line arguments.
|
|
288
|
+
"""
|
|
289
|
+
print("\n🔄 Restarting claude-mpm...")
|
|
290
|
+
|
|
291
|
+
try:
|
|
292
|
+
# Get current command line arguments
|
|
293
|
+
args = sys.argv[:]
|
|
294
|
+
|
|
295
|
+
# Replace current process with new one
|
|
296
|
+
if self.installation_method == InstallationMethod.PIPX:
|
|
297
|
+
# Use pipx run
|
|
298
|
+
os.execvp("pipx", ["pipx", "run", "claude-mpm", *args[1:]])
|
|
299
|
+
elif self.installation_method == InstallationMethod.NPM:
|
|
300
|
+
# Use npm executable
|
|
301
|
+
os.execvp("claude-mpm", args)
|
|
302
|
+
else:
|
|
303
|
+
# Use Python executable
|
|
304
|
+
os.execvp(sys.executable, [sys.executable, *args])
|
|
305
|
+
|
|
306
|
+
except Exception as e:
|
|
307
|
+
self.logger.error(f"Failed to restart: {e}")
|
|
308
|
+
print(f"\n⚠️ Restart failed: {e}")
|
|
309
|
+
print("Please restart claude-mpm manually.")
|
|
310
|
+
|
|
311
|
+
async def check_and_prompt_on_startup(
|
|
312
|
+
self, auto_upgrade: bool = False
|
|
313
|
+
) -> Optional[Dict[str, any]]:
|
|
314
|
+
"""
|
|
315
|
+
Check for updates on startup and optionally prompt user.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
auto_upgrade: If True, upgrade without prompting (use with caution)
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
Update info if available, None otherwise
|
|
322
|
+
"""
|
|
323
|
+
# Skip for editable installs
|
|
324
|
+
if self.installation_method == InstallationMethod.EDITABLE:
|
|
325
|
+
return None
|
|
326
|
+
|
|
327
|
+
try:
|
|
328
|
+
update_info = await self.check_for_update()
|
|
329
|
+
|
|
330
|
+
if update_info and update_info.get("update_available"):
|
|
331
|
+
if auto_upgrade or self.prompt_for_upgrade(update_info):
|
|
332
|
+
success, message = self.perform_upgrade(update_info)
|
|
333
|
+
print(message)
|
|
334
|
+
if success:
|
|
335
|
+
self.restart_after_upgrade()
|
|
336
|
+
|
|
337
|
+
return update_info
|
|
338
|
+
|
|
339
|
+
except Exception as e:
|
|
340
|
+
self.logger.debug(f"Startup version check failed: {e}")
|
|
341
|
+
|
|
342
|
+
return None
|
|
@@ -17,6 +17,7 @@ from datetime import timezone
|
|
|
17
17
|
from typing import Any, Dict, List, Optional
|
|
18
18
|
|
|
19
19
|
from claude_mpm.core.base_service import BaseService
|
|
20
|
+
from claude_mpm.core.enums import OperationResult, ServiceState
|
|
20
21
|
from claude_mpm.services.core.interfaces import SessionManagementInterface
|
|
21
22
|
|
|
22
23
|
|
|
@@ -223,7 +224,7 @@ class SessionManagementService(BaseService, SessionManagementInterface):
|
|
|
223
224
|
"id": session_id,
|
|
224
225
|
"config": session_config,
|
|
225
226
|
"start_time": time.time(),
|
|
226
|
-
"status":
|
|
227
|
+
"status": ServiceState.RUNNING,
|
|
227
228
|
"type": session_config.get("type", "interactive"),
|
|
228
229
|
}
|
|
229
230
|
|
|
@@ -267,7 +268,7 @@ class SessionManagementService(BaseService, SessionManagementInterface):
|
|
|
267
268
|
return self.active_sessions[session_id].copy()
|
|
268
269
|
return {
|
|
269
270
|
"id": session_id,
|
|
270
|
-
"status":
|
|
271
|
+
"status": OperationResult.ERROR,
|
|
271
272
|
"error": "Session not found",
|
|
272
273
|
}
|
|
273
274
|
|
|
@@ -6,12 +6,19 @@ Ensures a single session ID is generated and used across all components.
|
|
|
6
6
|
|
|
7
7
|
This service addresses race conditions and duplicate session ID generation
|
|
8
8
|
by providing a single source of truth for session identifiers.
|
|
9
|
+
|
|
10
|
+
Extended with:
|
|
11
|
+
- Token usage tracking and monitoring
|
|
12
|
+
- Resume log generation on session end
|
|
13
|
+
- Context metrics persistence
|
|
14
|
+
- Automatic resume log injection on session startup
|
|
9
15
|
"""
|
|
10
16
|
|
|
11
17
|
import os
|
|
12
18
|
from datetime import datetime, timezone
|
|
19
|
+
from pathlib import Path
|
|
13
20
|
from threading import Lock
|
|
14
|
-
from typing import Optional
|
|
21
|
+
from typing import Any, Dict, Optional
|
|
15
22
|
|
|
16
23
|
from claude_mpm.core.logging_utils import get_logger
|
|
17
24
|
|
|
@@ -64,6 +71,24 @@ class SessionManager:
|
|
|
64
71
|
self._session_id = self._generate_session_id()
|
|
65
72
|
self._session_start_time = datetime.now(timezone.utc)
|
|
66
73
|
|
|
74
|
+
# Token usage tracking
|
|
75
|
+
self._cumulative_tokens = 0
|
|
76
|
+
self._total_budget = 200000 # Default Claude Code budget
|
|
77
|
+
self._last_stop_reason: Optional[str] = None
|
|
78
|
+
|
|
79
|
+
# Context metrics storage
|
|
80
|
+
self._context_metrics: Dict[str, Any] = {
|
|
81
|
+
"total_budget": self._total_budget,
|
|
82
|
+
"used_tokens": 0,
|
|
83
|
+
"remaining_tokens": self._total_budget,
|
|
84
|
+
"percentage_used": 0.0,
|
|
85
|
+
"stop_reason": None,
|
|
86
|
+
"model": "claude-sonnet-4.5",
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Resume log reference (loaded on startup if exists)
|
|
90
|
+
self._resume_log_content: Optional[str] = None
|
|
91
|
+
|
|
67
92
|
# Mark as initialized
|
|
68
93
|
self.__class__._initialized = True
|
|
69
94
|
|
|
@@ -71,6 +96,9 @@ class SessionManager:
|
|
|
71
96
|
f"SessionManager initialized with session ID: {self._session_id}"
|
|
72
97
|
)
|
|
73
98
|
|
|
99
|
+
# Check for resume log from previous session
|
|
100
|
+
self._load_resume_log()
|
|
101
|
+
|
|
74
102
|
def _generate_session_id(self) -> str:
|
|
75
103
|
"""
|
|
76
104
|
Generate or retrieve a session ID.
|
|
@@ -134,6 +162,182 @@ class SessionManager:
|
|
|
134
162
|
f"Session ID already set to {session_id}, no change needed"
|
|
135
163
|
)
|
|
136
164
|
|
|
165
|
+
def update_token_usage(
|
|
166
|
+
self,
|
|
167
|
+
input_tokens: int = 0,
|
|
168
|
+
output_tokens: int = 0,
|
|
169
|
+
stop_reason: Optional[str] = None,
|
|
170
|
+
) -> Dict[str, Any]:
|
|
171
|
+
"""
|
|
172
|
+
Update cumulative token usage for the session.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
input_tokens: Input tokens from latest API call
|
|
176
|
+
output_tokens: Output tokens from latest API call
|
|
177
|
+
stop_reason: Stop reason from Claude API
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
Updated context metrics
|
|
181
|
+
"""
|
|
182
|
+
with self.__class__._lock:
|
|
183
|
+
# Update cumulative usage
|
|
184
|
+
tokens_used = input_tokens + output_tokens
|
|
185
|
+
self._cumulative_tokens += tokens_used
|
|
186
|
+
|
|
187
|
+
# Update stop reason if provided
|
|
188
|
+
if stop_reason:
|
|
189
|
+
self._last_stop_reason = stop_reason
|
|
190
|
+
|
|
191
|
+
# Calculate metrics
|
|
192
|
+
remaining = max(0, self._total_budget - self._cumulative_tokens)
|
|
193
|
+
percentage = (self._cumulative_tokens / self._total_budget) * 100
|
|
194
|
+
|
|
195
|
+
# Update context metrics
|
|
196
|
+
self._context_metrics = {
|
|
197
|
+
"total_budget": self._total_budget,
|
|
198
|
+
"used_tokens": self._cumulative_tokens,
|
|
199
|
+
"remaining_tokens": remaining,
|
|
200
|
+
"percentage_used": percentage,
|
|
201
|
+
"stop_reason": self._last_stop_reason,
|
|
202
|
+
"model": "claude-sonnet-4.5",
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
logger.debug(
|
|
206
|
+
f"Token usage updated: {self._cumulative_tokens}/{self._total_budget} "
|
|
207
|
+
f"({percentage:.1f}%) - Stop reason: {stop_reason}"
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
return self._context_metrics.copy()
|
|
211
|
+
|
|
212
|
+
def get_context_metrics(self) -> Dict[str, Any]:
|
|
213
|
+
"""
|
|
214
|
+
Get current context metrics.
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
Dictionary containing token usage and context metrics
|
|
218
|
+
"""
|
|
219
|
+
with self.__class__._lock:
|
|
220
|
+
return self._context_metrics.copy()
|
|
221
|
+
|
|
222
|
+
def get_token_usage_percentage(self) -> float:
|
|
223
|
+
"""
|
|
224
|
+
Get current token usage as a percentage (0.0 to 1.0).
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
Token usage percentage
|
|
228
|
+
"""
|
|
229
|
+
with self.__class__._lock:
|
|
230
|
+
return self._context_metrics["percentage_used"] / 100.0
|
|
231
|
+
|
|
232
|
+
def should_warn_context_limit(self, threshold: float = 0.70) -> bool:
|
|
233
|
+
"""
|
|
234
|
+
Check if context usage has reached warning threshold.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
threshold: Warning threshold (0.0 to 1.0)
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
True if threshold reached
|
|
241
|
+
"""
|
|
242
|
+
return self.get_token_usage_percentage() >= threshold
|
|
243
|
+
|
|
244
|
+
def _load_resume_log(self) -> None:
|
|
245
|
+
"""
|
|
246
|
+
Load resume log from previous session if it exists.
|
|
247
|
+
|
|
248
|
+
This is called during initialization to check for session continuity.
|
|
249
|
+
"""
|
|
250
|
+
try:
|
|
251
|
+
# Lazy import to avoid circular dependencies
|
|
252
|
+
from claude_mpm.services.infrastructure.resume_log_generator import (
|
|
253
|
+
ResumeLogGenerator,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
generator = ResumeLogGenerator()
|
|
257
|
+
|
|
258
|
+
# Check if there's a resume log for this session
|
|
259
|
+
# (Could be from a previous interrupted session with same ID)
|
|
260
|
+
resume_content = generator.load_resume_log(self._session_id)
|
|
261
|
+
|
|
262
|
+
if resume_content:
|
|
263
|
+
self._resume_log_content = resume_content
|
|
264
|
+
logger.info(f"Loaded resume log for session {self._session_id}")
|
|
265
|
+
else:
|
|
266
|
+
logger.debug("No resume log found for current session")
|
|
267
|
+
|
|
268
|
+
except Exception as e:
|
|
269
|
+
logger.warning(f"Failed to load resume log: {e}")
|
|
270
|
+
# Non-critical error, continue without resume log
|
|
271
|
+
|
|
272
|
+
def get_resume_log_content(self) -> Optional[str]:
|
|
273
|
+
"""
|
|
274
|
+
Get resume log content if loaded.
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
Resume log markdown content or None
|
|
278
|
+
"""
|
|
279
|
+
with self.__class__._lock:
|
|
280
|
+
return self._resume_log_content
|
|
281
|
+
|
|
282
|
+
def generate_resume_log(
|
|
283
|
+
self,
|
|
284
|
+
session_state: Optional[Dict[str, Any]] = None,
|
|
285
|
+
) -> Optional[Path]:
|
|
286
|
+
"""
|
|
287
|
+
Generate and save resume log for current session.
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
session_state: Optional session state data to include
|
|
291
|
+
|
|
292
|
+
Returns:
|
|
293
|
+
Path to saved resume log or None if generation failed
|
|
294
|
+
"""
|
|
295
|
+
try:
|
|
296
|
+
# Lazy import to avoid circular dependencies
|
|
297
|
+
from claude_mpm.models.resume_log import ContextMetrics, ResumeLog
|
|
298
|
+
from claude_mpm.services.infrastructure.resume_log_generator import (
|
|
299
|
+
ResumeLogGenerator,
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
generator = ResumeLogGenerator()
|
|
303
|
+
|
|
304
|
+
# Create context metrics from current state
|
|
305
|
+
context_metrics = ContextMetrics(
|
|
306
|
+
total_budget=self._total_budget,
|
|
307
|
+
used_tokens=self._cumulative_tokens,
|
|
308
|
+
remaining_tokens=self._context_metrics["remaining_tokens"],
|
|
309
|
+
percentage_used=self._context_metrics["percentage_used"],
|
|
310
|
+
stop_reason=self._last_stop_reason,
|
|
311
|
+
model=self._context_metrics["model"],
|
|
312
|
+
session_id=self._session_id,
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
if session_state:
|
|
316
|
+
# Generate from provided session state
|
|
317
|
+
resume_log = generator.generate_from_session_state(
|
|
318
|
+
session_id=self._session_id,
|
|
319
|
+
session_state=session_state,
|
|
320
|
+
stop_reason=self._last_stop_reason,
|
|
321
|
+
)
|
|
322
|
+
else:
|
|
323
|
+
# Create minimal resume log
|
|
324
|
+
resume_log = ResumeLog(
|
|
325
|
+
session_id=self._session_id,
|
|
326
|
+
context_metrics=context_metrics,
|
|
327
|
+
mission_summary="Session ended - resume log auto-generated.",
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
if resume_log:
|
|
331
|
+
file_path = generator.save_resume_log(resume_log)
|
|
332
|
+
logger.info(f"Resume log generated and saved: {file_path}")
|
|
333
|
+
return file_path
|
|
334
|
+
logger.warning("Resume log generation returned None")
|
|
335
|
+
return None
|
|
336
|
+
|
|
337
|
+
except Exception as e:
|
|
338
|
+
logger.error(f"Failed to generate resume log: {e}", exc_info=True)
|
|
339
|
+
return None
|
|
340
|
+
|
|
137
341
|
@classmethod
|
|
138
342
|
def reset(cls) -> None:
|
|
139
343
|
"""
|