claude-mpm 4.15.2__py3-none-any.whl → 4.20.3__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_ENGINEER.md +286 -0
- claude_mpm/agents/BASE_PM.md +255 -23
- claude_mpm/agents/PM_INSTRUCTIONS.md +40 -0
- claude_mpm/agents/agent_loader.py +4 -4
- claude_mpm/agents/templates/agentic-coder-optimizer.json +9 -2
- claude_mpm/agents/templates/api_qa.json +7 -1
- claude_mpm/agents/templates/clerk-ops.json +8 -1
- claude_mpm/agents/templates/code_analyzer.json +4 -1
- claude_mpm/agents/templates/dart_engineer.json +11 -1
- claude_mpm/agents/templates/data_engineer.json +11 -1
- claude_mpm/agents/templates/documentation.json +6 -1
- claude_mpm/agents/templates/engineer.json +18 -1
- claude_mpm/agents/templates/gcp_ops_agent.json +8 -1
- claude_mpm/agents/templates/golang_engineer.json +11 -1
- claude_mpm/agents/templates/java_engineer.json +12 -2
- claude_mpm/agents/templates/local_ops_agent.json +216 -37
- claude_mpm/agents/templates/nextjs_engineer.json +11 -1
- claude_mpm/agents/templates/ops.json +8 -1
- claude_mpm/agents/templates/php-engineer.json +11 -1
- claude_mpm/agents/templates/project_organizer.json +9 -2
- claude_mpm/agents/templates/prompt-engineer.json +5 -1
- claude_mpm/agents/templates/python_engineer.json +19 -4
- claude_mpm/agents/templates/qa.json +7 -1
- claude_mpm/agents/templates/react_engineer.json +11 -1
- claude_mpm/agents/templates/refactoring_engineer.json +8 -1
- claude_mpm/agents/templates/research.json +4 -1
- claude_mpm/agents/templates/ruby-engineer.json +11 -1
- claude_mpm/agents/templates/rust_engineer.json +23 -8
- claude_mpm/agents/templates/security.json +6 -1
- claude_mpm/agents/templates/svelte-engineer.json +225 -0
- claude_mpm/agents/templates/ticketing.json +6 -1
- claude_mpm/agents/templates/typescript_engineer.json +11 -1
- claude_mpm/agents/templates/vercel_ops_agent.json +8 -1
- claude_mpm/agents/templates/version_control.json +8 -1
- claude_mpm/agents/templates/web_qa.json +7 -1
- claude_mpm/agents/templates/web_ui.json +11 -1
- claude_mpm/cli/commands/__init__.py +2 -0
- claude_mpm/cli/commands/configure.py +164 -16
- claude_mpm/cli/commands/configure_agent_display.py +6 -6
- claude_mpm/cli/commands/configure_behavior_manager.py +8 -8
- claude_mpm/cli/commands/configure_navigation.py +20 -18
- claude_mpm/cli/commands/configure_startup_manager.py +14 -14
- claude_mpm/cli/commands/configure_template_editor.py +8 -8
- claude_mpm/cli/commands/mpm_init.py +109 -24
- claude_mpm/cli/commands/skills.py +434 -0
- claude_mpm/cli/executor.py +2 -0
- claude_mpm/cli/interactive/__init__.py +3 -0
- claude_mpm/cli/interactive/skills_wizard.py +491 -0
- claude_mpm/cli/parsers/base_parser.py +7 -0
- claude_mpm/cli/parsers/skills_parser.py +137 -0
- claude_mpm/cli/startup.py +83 -0
- claude_mpm/commands/mpm-auto-configure.md +52 -0
- claude_mpm/commands/mpm-help.md +3 -0
- claude_mpm/commands/mpm-init.md +112 -6
- 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/constants.py +12 -0
- claude_mpm/core/config.py +42 -0
- claude_mpm/core/enums.py +18 -0
- claude_mpm/core/factories.py +1 -1
- claude_mpm/core/optimized_agent_loader.py +3 -3
- claude_mpm/core/types.py +2 -9
- claude_mpm/dashboard/static/js/dashboard.js +0 -14
- claude_mpm/dashboard/templates/index.html +3 -41
- claude_mpm/hooks/__init__.py +8 -0
- claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
- claude_mpm/hooks/session_resume_hook.py +121 -0
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/services/agents/auto_config_manager.py +1 -1
- 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/local_template_deployment.py +1 -1
- 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/recommender.py +47 -0
- claude_mpm/services/cli/resume_service.py +617 -0
- claude_mpm/services/cli/session_manager.py +87 -0
- claude_mpm/services/cli/session_resume_helper.py +352 -0
- claude_mpm/services/core/models/health.py +1 -28
- claude_mpm/services/core/path_resolver.py +1 -1
- 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 +1 -1
- claude_mpm/services/local_ops/crash_detector.py +1 -1
- claude_mpm/services/local_ops/health_checks/http_check.py +2 -1
- claude_mpm/services/local_ops/health_checks/process_check.py +2 -1
- claude_mpm/services/local_ops/health_checks/resource_check.py +2 -1
- claude_mpm/services/local_ops/health_manager.py +1 -1
- claude_mpm/services/local_ops/restart_manager.py +1 -1
- claude_mpm/services/mcp_config_manager.py +7 -131
- 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 +10 -0
- claude_mpm/services/socketio/handlers/registry.py +4 -2
- claude_mpm/services/socketio/server/main.py +7 -7
- claude_mpm/services/unified/deployment_strategies/local.py +1 -1
- claude_mpm/services/version_service.py +104 -1
- claude_mpm/skills/__init__.py +42 -0
- claude_mpm/skills/agent_skills_injector.py +331 -0
- claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -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/collaboration/brainstorming/SKILL.md +75 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +184 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +107 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/code-reviewer.md +146 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +118 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +177 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +175 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/common-failures.md +213 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +314 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +227 -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/main/artifacts-builder/SKILL.md +74 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +32 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +328 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +150 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +372 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +209 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +302 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +111 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +65 -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/testing/condition-based-waiting/SKILL.md +123 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +304 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +96 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +40 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
- claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +107 -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/skills/skills_registry.py +351 -0
- claude_mpm/skills/skills_service.py +730 -0
- claude_mpm/utils/agent_dependency_loader.py +2 -2
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/METADATA +211 -33
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/RECORD +195 -115
- claude_mpm/agents/INSTRUCTIONS_OLD_DEPRECATED.md +0 -602
- claude_mpm/dashboard/static/css/code-tree.css +0 -1639
- 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-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/top_level.txt +0 -0
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
<link rel="stylesheet" href="/static/css/dashboard.css">
|
|
34
34
|
<link rel="stylesheet" href="/static/css/connection-status.css">
|
|
35
35
|
<link rel="stylesheet" href="/static/css/activity.css">
|
|
36
|
-
<link rel="stylesheet" href="/static/css/code-tree.css">
|
|
37
36
|
|
|
38
37
|
<!-- Additional styles for file operations -->
|
|
39
38
|
<style>
|
|
@@ -258,7 +257,6 @@
|
|
|
258
257
|
<a href="#tools" class="tab-button" data-tab="tools">🔧 Tools</a>
|
|
259
258
|
<a href="#files" class="tab-button" data-tab="files">📁 Files</a>
|
|
260
259
|
<a href="#activity" class="tab-button" data-tab="activity">🌳 Activity</a>
|
|
261
|
-
<a href="#file_tree" class="tab-button" data-tab="claude-tree">📝 File Tree</a>
|
|
262
260
|
</div>
|
|
263
261
|
|
|
264
262
|
<!-- Events Tab -->
|
|
@@ -397,15 +395,6 @@
|
|
|
397
395
|
</div>
|
|
398
396
|
</div>
|
|
399
397
|
|
|
400
|
-
<!-- File Tree Tab -->
|
|
401
|
-
<div class="tab-content" id="claude-tree-tab">
|
|
402
|
-
<div id="claude-tree-container" style="width: 100%; height: 100%; position: relative;">
|
|
403
|
-
<!-- File activity tree will be rendered here by code-viewer.js -->
|
|
404
|
-
<!-- This container is ISOLATED from other tabs -->
|
|
405
|
-
</div>
|
|
406
|
-
</div>
|
|
407
|
-
|
|
408
|
-
|
|
409
398
|
</div>
|
|
410
399
|
</div>
|
|
411
400
|
</div>
|
|
@@ -489,16 +478,12 @@
|
|
|
489
478
|
});
|
|
490
479
|
};
|
|
491
480
|
|
|
492
|
-
// Load shared services first, then
|
|
481
|
+
// Load shared services first, then components
|
|
493
482
|
// Load services sequentially to ensure dependencies are available
|
|
494
483
|
loadModule('/static/js/shared/tooltip-service.js')
|
|
495
484
|
.then(() => loadModule('/static/js/shared/dom-helpers.js'))
|
|
496
485
|
.then(() => loadModule('/static/js/shared/event-bus.js'))
|
|
497
486
|
.then(() => loadModule('/static/js/shared/logger.js'))
|
|
498
|
-
.then(() => loadModule('/static/js/components/code-tree/tree-utils.js'))
|
|
499
|
-
.then(() => loadModule('/static/js/components/code-tree/tree-constants.js'))
|
|
500
|
-
.then(() => loadModule('/static/js/components/code-tree/tree-search.js'))
|
|
501
|
-
.then(() => loadModule('/static/js/components/code-tree/tree-breadcrumb.js'))
|
|
502
487
|
.then(() => {
|
|
503
488
|
// CRITICAL: Load socket-client.js FIRST (dependency of socket-manager)
|
|
504
489
|
return loadModule('/static/js/socket-client.js');
|
|
@@ -530,29 +515,15 @@
|
|
|
530
515
|
return Promise.all([
|
|
531
516
|
loadModule('/static/dist/dashboard.js'), // Use dist version that requires above components
|
|
532
517
|
loadModule('/static/dist/components/activity-tree.js'),
|
|
533
|
-
loadModule('/static/js/components/code-tree.js'), // TEMPORARY: Direct source for debugging
|
|
534
|
-
loadModule('/static/js/components/code-viewer.js').catch(err => {
|
|
535
|
-
console.error('[CRITICAL] Failed to load code-viewer.js:', err);
|
|
536
|
-
throw err;
|
|
537
|
-
}), // Code viewer now includes file change tracking
|
|
538
518
|
loadModule('/static/dist/components/file-viewer.js') // File viewer for viewing file contents
|
|
539
519
|
]);
|
|
540
520
|
})
|
|
541
521
|
.then(() => {
|
|
542
522
|
console.log('All dashboard modules loaded successfully');
|
|
543
|
-
|
|
544
|
-
// Debug: Check if CodeViewer loaded
|
|
545
|
-
if (window.CodeViewer) {
|
|
546
|
-
console.log('[DEBUG] CodeViewer is available on window object');
|
|
547
|
-
} else {
|
|
548
|
-
console.error('[ERROR] CodeViewer NOT FOUND on window object!');
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
// CodeViewer will auto-initialize and handle tab switching internally
|
|
552
|
-
|
|
523
|
+
|
|
553
524
|
// Browser Log Viewer initialization is now handled by UIStateManager
|
|
554
525
|
// This prevents duplicate event handlers and tab selection conflicts
|
|
555
|
-
|
|
526
|
+
|
|
556
527
|
// Load bulletproof tab isolation fix
|
|
557
528
|
loadModule('/static/js/tab-isolation-fix.js')
|
|
558
529
|
.then(() => {
|
|
@@ -564,15 +535,6 @@
|
|
|
564
535
|
|
|
565
536
|
// Hash navigation will handle default tab based on URL
|
|
566
537
|
// If no hash, default will be 'events' as per hashToTab mapping
|
|
567
|
-
// To start with File Tree, we can set hash if not present
|
|
568
|
-
setTimeout(() => {
|
|
569
|
-
if (!window.location.hash) {
|
|
570
|
-
console.log('No hash present, setting default to File Tree tab...');
|
|
571
|
-
window.location.hash = '#file_tree';
|
|
572
|
-
} else {
|
|
573
|
-
console.log('Hash present:', window.location.hash);
|
|
574
|
-
}
|
|
575
|
-
}, 500);
|
|
576
538
|
})
|
|
577
539
|
.catch(error => {
|
|
578
540
|
console.error('[CRITICAL] Error loading dashboard modules:', error);
|
claude_mpm/hooks/__init__.py
CHANGED
|
@@ -12,6 +12,11 @@ from .failure_learning import (
|
|
|
12
12
|
from .kuzu_enrichment_hook import KuzuEnrichmentHook, get_kuzu_enrichment_hook
|
|
13
13
|
from .kuzu_memory_hook import KuzuMemoryHook, get_kuzu_memory_hook
|
|
14
14
|
from .kuzu_response_hook import KuzuResponseHook, get_kuzu_response_hook
|
|
15
|
+
from .session_resume_hook import (
|
|
16
|
+
SessionResumeStartupHook,
|
|
17
|
+
get_session_resume_hook,
|
|
18
|
+
trigger_session_resume_check,
|
|
19
|
+
)
|
|
15
20
|
|
|
16
21
|
__all__ = [
|
|
17
22
|
"BaseHook",
|
|
@@ -24,10 +29,13 @@ __all__ = [
|
|
|
24
29
|
"KuzuMemoryHook",
|
|
25
30
|
"KuzuResponseHook",
|
|
26
31
|
"LearningExtractionHook",
|
|
32
|
+
"SessionResumeStartupHook",
|
|
27
33
|
"get_failure_detection_hook",
|
|
28
34
|
"get_fix_detection_hook",
|
|
29
35
|
"get_kuzu_enrichment_hook",
|
|
30
36
|
"get_kuzu_memory_hook",
|
|
31
37
|
"get_kuzu_response_hook",
|
|
32
38
|
"get_learning_extraction_hook",
|
|
39
|
+
"get_session_resume_hook",
|
|
40
|
+
"trigger_session_resume_check",
|
|
33
41
|
]
|
|
@@ -268,7 +268,10 @@ class ResponseTrackingManager:
|
|
|
268
268
|
def track_stop_response(
|
|
269
269
|
self, event: dict, session_id: str, metadata: dict, pending_prompts: dict
|
|
270
270
|
):
|
|
271
|
-
"""Track response for stop events.
|
|
271
|
+
"""Track response for stop events.
|
|
272
|
+
|
|
273
|
+
Captures Claude API stop_reason and usage data for context management.
|
|
274
|
+
"""
|
|
272
275
|
if not (self.response_tracking_enabled and self.response_tracker):
|
|
273
276
|
return
|
|
274
277
|
|
|
@@ -294,6 +297,37 @@ class ResponseTrackingManager:
|
|
|
294
297
|
# Add prompt timestamp to metadata
|
|
295
298
|
metadata["prompt_timestamp"] = prompt_data.get("timestamp")
|
|
296
299
|
|
|
300
|
+
# Capture Claude API stop_reason if available
|
|
301
|
+
if "stop_reason" in event:
|
|
302
|
+
metadata["stop_reason"] = event["stop_reason"]
|
|
303
|
+
if DEBUG:
|
|
304
|
+
print(
|
|
305
|
+
f" - Captured stop_reason: {event['stop_reason']}",
|
|
306
|
+
file=sys.stderr,
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
# Capture Claude API usage data if available
|
|
310
|
+
if "usage" in event:
|
|
311
|
+
usage_data = event["usage"]
|
|
312
|
+
metadata["usage"] = {
|
|
313
|
+
"input_tokens": usage_data.get("input_tokens", 0),
|
|
314
|
+
"output_tokens": usage_data.get("output_tokens", 0),
|
|
315
|
+
"cache_creation_input_tokens": usage_data.get(
|
|
316
|
+
"cache_creation_input_tokens", 0
|
|
317
|
+
),
|
|
318
|
+
"cache_read_input_tokens": usage_data.get(
|
|
319
|
+
"cache_read_input_tokens", 0
|
|
320
|
+
),
|
|
321
|
+
}
|
|
322
|
+
if DEBUG:
|
|
323
|
+
total_tokens = usage_data.get(
|
|
324
|
+
"input_tokens", 0
|
|
325
|
+
) + usage_data.get("output_tokens", 0)
|
|
326
|
+
print(
|
|
327
|
+
f" - Captured usage: {total_tokens} total tokens",
|
|
328
|
+
file=sys.stderr,
|
|
329
|
+
)
|
|
330
|
+
|
|
297
331
|
# Track the main Claude response
|
|
298
332
|
file_path = self.response_tracker.track_response(
|
|
299
333
|
agent_name="claude_main",
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""Session Resume Startup Hook.
|
|
2
|
+
|
|
3
|
+
WHY: This hook automatically checks for paused sessions on PM startup and displays
|
|
4
|
+
resume context to help users continue their work seamlessly.
|
|
5
|
+
|
|
6
|
+
DESIGN DECISIONS:
|
|
7
|
+
- Runs automatically on PM startup
|
|
8
|
+
- Non-blocking: doesn't prevent PM from starting if check fails
|
|
9
|
+
- Displays context to stdout for user visibility
|
|
10
|
+
- Integrates with existing session pause/resume infrastructure
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, Dict, Optional
|
|
15
|
+
|
|
16
|
+
from claude_mpm.core.logger import get_logger
|
|
17
|
+
from claude_mpm.services.cli.session_resume_helper import SessionResumeHelper
|
|
18
|
+
|
|
19
|
+
logger = get_logger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SessionResumeStartupHook:
|
|
23
|
+
"""Hook for automatic session resume detection on PM startup."""
|
|
24
|
+
|
|
25
|
+
def __init__(self, project_path: Optional[Path] = None):
|
|
26
|
+
"""Initialize the session resume hook.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
project_path: Project root path (default: current directory)
|
|
30
|
+
"""
|
|
31
|
+
self.project_path = project_path or Path.cwd()
|
|
32
|
+
self.resume_helper = SessionResumeHelper(self.project_path)
|
|
33
|
+
self._session_displayed = False
|
|
34
|
+
|
|
35
|
+
def on_pm_startup(self) -> Optional[Dict[str, Any]]:
|
|
36
|
+
"""Execute on PM startup to check for paused sessions.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Session data if paused session found, None otherwise
|
|
40
|
+
"""
|
|
41
|
+
try:
|
|
42
|
+
# Check if we already displayed a session in this process
|
|
43
|
+
if self._session_displayed:
|
|
44
|
+
logger.debug("Session already displayed, skipping")
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
# Check for paused sessions
|
|
48
|
+
session_data = self.resume_helper.check_and_display_resume_prompt()
|
|
49
|
+
|
|
50
|
+
if session_data:
|
|
51
|
+
self._session_displayed = True
|
|
52
|
+
logger.info("Paused session context displayed to user")
|
|
53
|
+
|
|
54
|
+
return session_data
|
|
55
|
+
|
|
56
|
+
except Exception as e:
|
|
57
|
+
logger.error(f"Failed to check for paused sessions: {e}", exc_info=True)
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
def get_session_count(self) -> int:
|
|
61
|
+
"""Get count of paused sessions.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Number of paused sessions
|
|
65
|
+
"""
|
|
66
|
+
try:
|
|
67
|
+
return self.resume_helper.get_session_count()
|
|
68
|
+
except Exception as e:
|
|
69
|
+
logger.error(f"Failed to get session count: {e}")
|
|
70
|
+
return 0
|
|
71
|
+
|
|
72
|
+
def clear_displayed_session(self, session_data: Dict[str, Any]) -> bool:
|
|
73
|
+
"""Clear a session after it has been displayed and user has acknowledged.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
session_data: Session data to clear
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
True if successfully cleared, False otherwise
|
|
80
|
+
"""
|
|
81
|
+
try:
|
|
82
|
+
return self.resume_helper.clear_session(session_data)
|
|
83
|
+
except Exception as e:
|
|
84
|
+
logger.error(f"Failed to clear session: {e}")
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
# Global hook instance
|
|
89
|
+
_session_resume_hook: Optional[SessionResumeStartupHook] = None
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def get_session_resume_hook(
|
|
93
|
+
project_path: Optional[Path] = None,
|
|
94
|
+
) -> SessionResumeStartupHook:
|
|
95
|
+
"""Get or create the global session resume hook instance.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
project_path: Project root path (default: current directory)
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
SessionResumeStartupHook instance
|
|
102
|
+
"""
|
|
103
|
+
global _session_resume_hook
|
|
104
|
+
|
|
105
|
+
if _session_resume_hook is None:
|
|
106
|
+
_session_resume_hook = SessionResumeStartupHook(project_path)
|
|
107
|
+
logger.debug("Created session resume hook instance")
|
|
108
|
+
|
|
109
|
+
return _session_resume_hook
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def trigger_session_resume_check() -> Optional[Dict[str, Any]]:
|
|
113
|
+
"""Trigger a session resume check (convenience function).
|
|
114
|
+
|
|
115
|
+
This is the main entry point for PM startup integration.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Session data if found, None otherwise
|
|
119
|
+
"""
|
|
120
|
+
hook = get_session_resume_hook()
|
|
121
|
+
return hook.on_pm_startup()
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
"""Resume Log Data Model.
|
|
2
|
+
|
|
3
|
+
This module defines the data structure for session resume logs that enable
|
|
4
|
+
seamless context restoration when Claude hits token limits.
|
|
5
|
+
|
|
6
|
+
Design Philosophy:
|
|
7
|
+
- Target 10k tokens maximum per resume log
|
|
8
|
+
- Human-readable markdown format
|
|
9
|
+
- Structured sections with token budgets
|
|
10
|
+
- Optimized for Claude consumption on session resume
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from datetime import datetime, timezone
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Any, Dict, List, Optional
|
|
17
|
+
|
|
18
|
+
from claude_mpm.core.logging_utils import get_logger
|
|
19
|
+
|
|
20
|
+
logger = get_logger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class ContextMetrics:
|
|
25
|
+
"""Context window usage metrics."""
|
|
26
|
+
|
|
27
|
+
total_budget: int = 200000
|
|
28
|
+
used_tokens: int = 0
|
|
29
|
+
remaining_tokens: int = 0
|
|
30
|
+
percentage_used: float = 0.0
|
|
31
|
+
stop_reason: Optional[str] = None
|
|
32
|
+
model: str = "claude-sonnet-4.5"
|
|
33
|
+
session_id: str = ""
|
|
34
|
+
timestamp: str = field(
|
|
35
|
+
default_factory=lambda: datetime.now(timezone.utc).isoformat()
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
39
|
+
"""Convert to dictionary."""
|
|
40
|
+
return {
|
|
41
|
+
"total_budget": self.total_budget,
|
|
42
|
+
"used_tokens": self.used_tokens,
|
|
43
|
+
"remaining_tokens": self.remaining_tokens,
|
|
44
|
+
"percentage_used": self.percentage_used,
|
|
45
|
+
"stop_reason": self.stop_reason,
|
|
46
|
+
"model": self.model,
|
|
47
|
+
"session_id": self.session_id,
|
|
48
|
+
"timestamp": self.timestamp,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def from_dict(cls, data: Dict[str, Any]) -> "ContextMetrics":
|
|
53
|
+
"""Create from dictionary."""
|
|
54
|
+
return cls(
|
|
55
|
+
total_budget=data.get("total_budget", 200000),
|
|
56
|
+
used_tokens=data.get("used_tokens", 0),
|
|
57
|
+
remaining_tokens=data.get("remaining_tokens", 0),
|
|
58
|
+
percentage_used=data.get("percentage_used", 0.0),
|
|
59
|
+
stop_reason=data.get("stop_reason"),
|
|
60
|
+
model=data.get("model", "claude-sonnet-4.5"),
|
|
61
|
+
session_id=data.get("session_id", ""),
|
|
62
|
+
timestamp=data.get("timestamp", datetime.now(timezone.utc).isoformat()),
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass
|
|
67
|
+
class ResumeLog:
|
|
68
|
+
"""Resume log containing all information needed to restore session context.
|
|
69
|
+
|
|
70
|
+
Token Budget Distribution (10k tokens total):
|
|
71
|
+
- Context Metrics: 500 tokens
|
|
72
|
+
- Mission Summary: 1,000 tokens
|
|
73
|
+
- Accomplishments: 2,000 tokens
|
|
74
|
+
- Key Findings: 2,500 tokens
|
|
75
|
+
- Decisions & Rationale: 1,500 tokens
|
|
76
|
+
- Next Steps: 1,500 tokens
|
|
77
|
+
- Critical Context: 1,000 tokens
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
# Session identification
|
|
81
|
+
session_id: str
|
|
82
|
+
previous_session_id: Optional[str] = None
|
|
83
|
+
created_at: str = field(
|
|
84
|
+
default_factory=lambda: datetime.now(timezone.utc).isoformat()
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Context metrics
|
|
88
|
+
context_metrics: ContextMetrics = field(default_factory=ContextMetrics)
|
|
89
|
+
|
|
90
|
+
# Core content sections (with token budgets)
|
|
91
|
+
mission_summary: str = "" # 1,000 tokens - What was the overall goal?
|
|
92
|
+
accomplishments: List[str] = field(
|
|
93
|
+
default_factory=list
|
|
94
|
+
) # 2,000 tokens - What was completed?
|
|
95
|
+
key_findings: List[str] = field(
|
|
96
|
+
default_factory=list
|
|
97
|
+
) # 2,500 tokens - What was discovered?
|
|
98
|
+
decisions_made: List[Dict[str, str]] = field(
|
|
99
|
+
default_factory=list
|
|
100
|
+
) # 1,500 tokens - What choices were made and why?
|
|
101
|
+
next_steps: List[str] = field(
|
|
102
|
+
default_factory=list
|
|
103
|
+
) # 1,500 tokens - What needs to happen next?
|
|
104
|
+
critical_context: Dict[str, Any] = field(
|
|
105
|
+
default_factory=dict
|
|
106
|
+
) # 1,000 tokens - Essential state/data
|
|
107
|
+
|
|
108
|
+
# Metadata
|
|
109
|
+
files_modified: List[str] = field(default_factory=list)
|
|
110
|
+
agents_used: Dict[str, int] = field(default_factory=dict)
|
|
111
|
+
errors_encountered: List[str] = field(default_factory=list)
|
|
112
|
+
warnings: List[str] = field(default_factory=list)
|
|
113
|
+
|
|
114
|
+
def to_markdown(self) -> str:
|
|
115
|
+
"""Generate markdown format for Claude consumption.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Markdown-formatted resume log
|
|
119
|
+
"""
|
|
120
|
+
sections = []
|
|
121
|
+
|
|
122
|
+
# Header
|
|
123
|
+
sections.append(f"# Session Resume Log: {self.session_id}\n")
|
|
124
|
+
sections.append(f"**Created**: {self.created_at}")
|
|
125
|
+
if self.previous_session_id:
|
|
126
|
+
sections.append(f"**Previous Session**: {self.previous_session_id}")
|
|
127
|
+
sections.append("")
|
|
128
|
+
|
|
129
|
+
# Context Metrics (500 tokens)
|
|
130
|
+
sections.append("## Context Metrics\n")
|
|
131
|
+
sections.append(f"- **Model**: {self.context_metrics.model}")
|
|
132
|
+
sections.append(
|
|
133
|
+
f"- **Tokens Used**: {self.context_metrics.used_tokens:,} / {self.context_metrics.total_budget:,}"
|
|
134
|
+
)
|
|
135
|
+
sections.append(
|
|
136
|
+
f"- **Percentage**: {self.context_metrics.percentage_used:.1f}%"
|
|
137
|
+
)
|
|
138
|
+
sections.append(
|
|
139
|
+
f"- **Remaining**: {self.context_metrics.remaining_tokens:,} tokens"
|
|
140
|
+
)
|
|
141
|
+
if self.context_metrics.stop_reason:
|
|
142
|
+
sections.append(f"- **Stop Reason**: {self.context_metrics.stop_reason}")
|
|
143
|
+
sections.append("")
|
|
144
|
+
|
|
145
|
+
# Mission Summary (1,000 tokens)
|
|
146
|
+
sections.append("## Mission Summary\n")
|
|
147
|
+
sections.append(
|
|
148
|
+
self.mission_summary
|
|
149
|
+
if self.mission_summary
|
|
150
|
+
else "_No mission summary provided_"
|
|
151
|
+
)
|
|
152
|
+
sections.append("")
|
|
153
|
+
|
|
154
|
+
# Accomplishments (2,000 tokens)
|
|
155
|
+
sections.append("## Accomplishments\n")
|
|
156
|
+
if self.accomplishments:
|
|
157
|
+
for i, item in enumerate(self.accomplishments, 1):
|
|
158
|
+
sections.append(f"{i}. {item}")
|
|
159
|
+
else:
|
|
160
|
+
sections.append("_No accomplishments recorded_")
|
|
161
|
+
sections.append("")
|
|
162
|
+
|
|
163
|
+
# Key Findings (2,500 tokens)
|
|
164
|
+
sections.append("## Key Findings\n")
|
|
165
|
+
if self.key_findings:
|
|
166
|
+
for i, finding in enumerate(self.key_findings, 1):
|
|
167
|
+
sections.append(f"{i}. {finding}")
|
|
168
|
+
else:
|
|
169
|
+
sections.append("_No key findings recorded_")
|
|
170
|
+
sections.append("")
|
|
171
|
+
|
|
172
|
+
# Decisions & Rationale (1,500 tokens)
|
|
173
|
+
sections.append("## Decisions & Rationale\n")
|
|
174
|
+
if self.decisions_made:
|
|
175
|
+
for i, decision in enumerate(self.decisions_made, 1):
|
|
176
|
+
decision_text = decision.get("decision", "")
|
|
177
|
+
rationale = decision.get("rationale", "")
|
|
178
|
+
sections.append(f"{i}. **Decision**: {decision_text}")
|
|
179
|
+
if rationale:
|
|
180
|
+
sections.append(f" **Rationale**: {rationale}")
|
|
181
|
+
else:
|
|
182
|
+
sections.append("_No decisions recorded_")
|
|
183
|
+
sections.append("")
|
|
184
|
+
|
|
185
|
+
# Next Steps (1,500 tokens)
|
|
186
|
+
sections.append("## Next Steps\n")
|
|
187
|
+
if self.next_steps:
|
|
188
|
+
for i, step in enumerate(self.next_steps, 1):
|
|
189
|
+
sections.append(f"{i}. {step}")
|
|
190
|
+
else:
|
|
191
|
+
sections.append("_No next steps defined_")
|
|
192
|
+
sections.append("")
|
|
193
|
+
|
|
194
|
+
# Critical Context (1,000 tokens)
|
|
195
|
+
sections.append("## Critical Context\n")
|
|
196
|
+
if self.critical_context:
|
|
197
|
+
for key, value in self.critical_context.items():
|
|
198
|
+
sections.append(f"- **{key}**: {value}")
|
|
199
|
+
else:
|
|
200
|
+
sections.append("_No critical context preserved_")
|
|
201
|
+
sections.append("")
|
|
202
|
+
|
|
203
|
+
# Metadata
|
|
204
|
+
sections.append("## Session Metadata\n")
|
|
205
|
+
if self.files_modified:
|
|
206
|
+
sections.append(f"**Files Modified** ({len(self.files_modified)}):")
|
|
207
|
+
for file in self.files_modified[:20]: # Limit to first 20
|
|
208
|
+
sections.append(f"- {file}")
|
|
209
|
+
if len(self.files_modified) > 20:
|
|
210
|
+
sections.append(f"- ... and {len(self.files_modified) - 20} more")
|
|
211
|
+
sections.append("")
|
|
212
|
+
|
|
213
|
+
if self.agents_used:
|
|
214
|
+
sections.append("**Agents Used**:")
|
|
215
|
+
for agent, count in self.agents_used.items():
|
|
216
|
+
sections.append(f"- {agent}: {count} delegations")
|
|
217
|
+
sections.append("")
|
|
218
|
+
|
|
219
|
+
if self.errors_encountered:
|
|
220
|
+
sections.append(f"**Errors** ({len(self.errors_encountered)}):")
|
|
221
|
+
for error in self.errors_encountered[:5]: # Limit to first 5
|
|
222
|
+
sections.append(f"- {error}")
|
|
223
|
+
sections.append("")
|
|
224
|
+
|
|
225
|
+
if self.warnings:
|
|
226
|
+
sections.append(f"**Warnings** ({len(self.warnings)}):")
|
|
227
|
+
for warning in self.warnings[:5]: # Limit to first 5
|
|
228
|
+
sections.append(f"- {warning}")
|
|
229
|
+
sections.append("")
|
|
230
|
+
|
|
231
|
+
return "\n".join(sections)
|
|
232
|
+
|
|
233
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
234
|
+
"""Convert to dictionary for JSON serialization."""
|
|
235
|
+
return {
|
|
236
|
+
"session_id": self.session_id,
|
|
237
|
+
"previous_session_id": self.previous_session_id,
|
|
238
|
+
"created_at": self.created_at,
|
|
239
|
+
"context_metrics": self.context_metrics.to_dict(),
|
|
240
|
+
"mission_summary": self.mission_summary,
|
|
241
|
+
"accomplishments": self.accomplishments,
|
|
242
|
+
"key_findings": self.key_findings,
|
|
243
|
+
"decisions_made": self.decisions_made,
|
|
244
|
+
"next_steps": self.next_steps,
|
|
245
|
+
"critical_context": self.critical_context,
|
|
246
|
+
"files_modified": self.files_modified,
|
|
247
|
+
"agents_used": self.agents_used,
|
|
248
|
+
"errors_encountered": self.errors_encountered,
|
|
249
|
+
"warnings": self.warnings,
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
@classmethod
|
|
253
|
+
def from_dict(cls, data: Dict[str, Any]) -> "ResumeLog":
|
|
254
|
+
"""Create from dictionary."""
|
|
255
|
+
context_metrics_data = data.get("context_metrics", {})
|
|
256
|
+
context_metrics = ContextMetrics.from_dict(context_metrics_data)
|
|
257
|
+
|
|
258
|
+
return cls(
|
|
259
|
+
session_id=data.get("session_id", ""),
|
|
260
|
+
previous_session_id=data.get("previous_session_id"),
|
|
261
|
+
created_at=data.get("created_at", datetime.now(timezone.utc).isoformat()),
|
|
262
|
+
context_metrics=context_metrics,
|
|
263
|
+
mission_summary=data.get("mission_summary", ""),
|
|
264
|
+
accomplishments=data.get("accomplishments", []),
|
|
265
|
+
key_findings=data.get("key_findings", []),
|
|
266
|
+
decisions_made=data.get("decisions_made", []),
|
|
267
|
+
next_steps=data.get("next_steps", []),
|
|
268
|
+
critical_context=data.get("critical_context", {}),
|
|
269
|
+
files_modified=data.get("files_modified", []),
|
|
270
|
+
agents_used=data.get("agents_used", {}),
|
|
271
|
+
errors_encountered=data.get("errors_encountered", []),
|
|
272
|
+
warnings=data.get("warnings", []),
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
def save(self, storage_dir: Optional[Path] = None) -> Path:
|
|
276
|
+
"""Save resume log to markdown file.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
storage_dir: Directory to save the log (default: .claude-mpm/resume-logs)
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
Path to saved file
|
|
283
|
+
"""
|
|
284
|
+
if storage_dir is None:
|
|
285
|
+
storage_dir = Path.home() / ".claude-mpm" / "resume-logs"
|
|
286
|
+
|
|
287
|
+
storage_dir.mkdir(parents=True, exist_ok=True)
|
|
288
|
+
|
|
289
|
+
# Generate filename
|
|
290
|
+
file_path = storage_dir / f"session-{self.session_id}.md"
|
|
291
|
+
|
|
292
|
+
try:
|
|
293
|
+
# Write markdown file
|
|
294
|
+
markdown_content = self.to_markdown()
|
|
295
|
+
file_path.write_text(markdown_content, encoding="utf-8")
|
|
296
|
+
|
|
297
|
+
logger.info(f"Resume log saved: {file_path}")
|
|
298
|
+
return file_path
|
|
299
|
+
|
|
300
|
+
except Exception as e:
|
|
301
|
+
logger.error(f"Failed to save resume log: {e}")
|
|
302
|
+
raise
|
|
303
|
+
|
|
304
|
+
@classmethod
|
|
305
|
+
def load(
|
|
306
|
+
cls, session_id: str, storage_dir: Optional[Path] = None
|
|
307
|
+
) -> Optional["ResumeLog"]:
|
|
308
|
+
"""Load resume log from file.
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
session_id: Session ID to load
|
|
312
|
+
storage_dir: Directory to load from (default: .claude-mpm/resume-logs)
|
|
313
|
+
|
|
314
|
+
Returns:
|
|
315
|
+
ResumeLog instance or None if not found
|
|
316
|
+
"""
|
|
317
|
+
if storage_dir is None:
|
|
318
|
+
storage_dir = Path.home() / ".claude-mpm" / "resume-logs"
|
|
319
|
+
|
|
320
|
+
file_path = storage_dir / f"session-{session_id}.md"
|
|
321
|
+
|
|
322
|
+
if not file_path.exists():
|
|
323
|
+
logger.debug(f"Resume log not found: {file_path}")
|
|
324
|
+
return None
|
|
325
|
+
|
|
326
|
+
try:
|
|
327
|
+
# For now, we just return the markdown content
|
|
328
|
+
# In the future, could parse markdown back to structured data
|
|
329
|
+
_ = file_path.read_text(encoding="utf-8")
|
|
330
|
+
logger.info(f"Resume log loaded: {file_path}")
|
|
331
|
+
|
|
332
|
+
# Return a basic ResumeLog with the markdown content embedded
|
|
333
|
+
return cls(
|
|
334
|
+
session_id=session_id,
|
|
335
|
+
mission_summary=f"Loaded from previous session. See full context in {file_path}",
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
except Exception as e:
|
|
339
|
+
logger.error(f"Failed to load resume log: {e}")
|
|
340
|
+
return None
|
|
@@ -678,7 +678,7 @@ class AutoConfigManagerService(BaseService, IAutoConfigManager):
|
|
|
678
678
|
agent_id, agent_name, success=True
|
|
679
679
|
)
|
|
680
680
|
deployed.append(agent_id)
|
|
681
|
-
self.logger.
|
|
681
|
+
self.logger.debug(f"Successfully deployed agent: {agent_id}")
|
|
682
682
|
|
|
683
683
|
except Exception as e:
|
|
684
684
|
self.logger.error(
|
|
@@ -71,7 +71,7 @@ class AgentConfigurationManager:
|
|
|
71
71
|
# Cache the result
|
|
72
72
|
self._base_agent_cache = (base_agent_data, base_agent_version)
|
|
73
73
|
|
|
74
|
-
self.logger.
|
|
74
|
+
self.logger.debug(f"Loaded base agent from {self.base_agent_path}")
|
|
75
75
|
return self._base_agent_cache
|
|
76
76
|
|
|
77
77
|
except Exception as e:
|
|
@@ -107,7 +107,7 @@ class AgentRecordService(BaseService):
|
|
|
107
107
|
record = self._deserialize_record(record_data)
|
|
108
108
|
records[agent_name] = record
|
|
109
109
|
|
|
110
|
-
self.logger.
|
|
110
|
+
self.logger.debug(f"Loaded {len(records)} agent records")
|
|
111
111
|
else:
|
|
112
112
|
self.logger.debug("No existing records file found")
|
|
113
113
|
|