This commit is contained in:
AIOSAI
2026-03-06 20:40:16 +00:00
parent 3555e88ed5
commit a59f9c006b
327 changed files with 3106 additions and 1169 deletions
+49
View File
@@ -0,0 +1,49 @@
{
"generated_at": "2026-03-06T20:20:39.989231+00:00",
"branches": {
"flow": {
"branch_name": "FLOW",
"branch_path": "/home/coder/workspace/src/aipass/flow",
"last_updated": "2026-03-06T20:20:39.988098+00:00",
"active_plans": [
{
"plan_id": "FPLAN-0002",
"subject": "",
"status": "open",
"created": "2026-03-06T20:20:39.986512+00:00",
"file_path": "/home/coder/workspace/src/aipass/flow/FPLAN-0002_2026-03-06.md",
"relative_path": "flow",
"branch": "flow"
}
],
"recently_closed": [],
"statistics": {
"active_count": 1,
"total_closed": 0,
"recently_closed_included": 0
}
}
},
"global_statistics": {
"total_active": 1,
"total_closed": 0,
"branches_reporting": 1
},
"active_plans": [
{
"plan_id": "FPLAN-0002",
"subject": "",
"status": "open",
"created": "2026-03-06T20:20:39.986512+00:00",
"file_path": "/home/coder/workspace/src/aipass/flow/FPLAN-0002_2026-03-06.md",
"relative_path": "flow",
"branch": "flow"
}
],
"recently_closed": [],
"statistics": {
"active_count": 1,
"total_closed": 0,
"recently_closed_included": 0
}
}
+35
View File
@@ -0,0 +1,35 @@
2026-03-06 19:26:01 - captured_ai_mail - INFO - [ai_mail] Discovering modules...
2026-03-06 19:26:01 - captured_ai_mail - ERROR - [-] aipass.ai_mail.apps.modules.email - import error: No module named 'aipass.dev_central'
2026-03-06 19:26:01 - captured_ai_mail - INFO - [+] aipass.ai_mail.apps.modules.dispatch
2026-03-06 19:26:01 - captured_ai_mail - INFO - [+] aipass.ai_mail.apps.modules.branch_ping
2026-03-06 19:26:01 - captured_ai_mail - INFO - [ai_mail] Discovered 2 modules
2026-03-06 19:26:27 - captured_ai_mail - INFO - [ai_mail] Discovering modules...
2026-03-06 19:26:27 - captured_ai_mail - ERROR - [-] aipass.ai_mail.apps.modules.email - import error: No module named 'aipass.dev_central'
2026-03-06 19:26:27 - captured_ai_mail - INFO - [+] aipass.ai_mail.apps.modules.dispatch
2026-03-06 19:26:27 - captured_ai_mail - INFO - [+] aipass.ai_mail.apps.modules.branch_ping
2026-03-06 19:26:27 - captured_ai_mail - INFO - [ai_mail] Discovered 2 modules
2026-03-06 20:32:14 - captured_ai_mail - INFO - [ai_mail] Discovering modules...
2026-03-06 20:32:14 - captured_ai_mail - ERROR - [-] aipass.ai_mail.apps.modules.email - import error: No module named 'aipass.dev_central'
2026-03-06 20:32:14 - captured_ai_mail - INFO - [+] aipass.ai_mail.apps.modules.dispatch
2026-03-06 20:32:14 - captured_ai_mail - INFO - [+] aipass.ai_mail.apps.modules.branch_ping
2026-03-06 20:32:14 - captured_ai_mail - INFO - [ai_mail] Discovered 2 modules
2026-03-06 20:32:37 - captured_ai_mail - INFO - [ai_mail] Discovering modules...
2026-03-06 20:32:37 - captured_ai_mail - ERROR - [-] aipass.ai_mail.apps.modules.email - import error: No module named 'aipass.dev_central'
2026-03-06 20:32:37 - captured_ai_mail - INFO - [+] aipass.ai_mail.apps.modules.dispatch
2026-03-06 20:32:37 - captured_ai_mail - INFO - [+] aipass.ai_mail.apps.modules.branch_ping
2026-03-06 20:32:37 - captured_ai_mail - INFO - [ai_mail] Discovered 2 modules
2026-03-06 20:32:42 - captured_ai_mail - INFO - [ai_mail] Discovering modules...
2026-03-06 20:32:42 - captured_ai_mail - ERROR - [-] aipass.ai_mail.apps.modules.email - import error: No module named 'aipass.dev_central'
2026-03-06 20:32:42 - captured_ai_mail - INFO - [+] aipass.ai_mail.apps.modules.dispatch
2026-03-06 20:32:42 - captured_ai_mail - INFO - [+] aipass.ai_mail.apps.modules.branch_ping
2026-03-06 20:32:42 - captured_ai_mail - INFO - [ai_mail] Discovered 2 modules
2026-03-06 20:33:19 - captured_ai_mail - INFO - [ai_mail] Discovering modules...
2026-03-06 20:33:19 - captured_ai_mail - ERROR - [-] aipass.ai_mail.apps.modules.email - import error: No module named 'aipass.dev_central'
2026-03-06 20:33:19 - captured_ai_mail - INFO - [+] aipass.ai_mail.apps.modules.dispatch
2026-03-06 20:33:19 - captured_ai_mail - INFO - [+] aipass.ai_mail.apps.modules.branch_ping
2026-03-06 20:33:19 - captured_ai_mail - INFO - [ai_mail] Discovered 2 modules
2026-03-06 20:33:19 - captured_ai_mail - INFO - [ai_mail] Discovering modules...
2026-03-06 20:33:19 - captured_ai_mail - ERROR - [-] aipass.ai_mail.apps.modules.email - import error: No module named 'aipass.dev_central'
2026-03-06 20:33:19 - captured_ai_mail - INFO - [+] aipass.ai_mail.apps.modules.dispatch
2026-03-06 20:33:19 - captured_ai_mail - INFO - [+] aipass.ai_mail.apps.modules.branch_ping
2026-03-06 20:33:19 - captured_ai_mail - INFO - [ai_mail] Discovered 2 modules
+1
View File
@@ -0,0 +1 @@
2026-03-06 20:33:19 - captured_dispatch - INFO - [dispatch] Showing dispatch status
+29
View File
@@ -0,0 +1,29 @@
2026-03-06 19:25:57 - captured_api - INFO - [api] Discovering modules...
2026-03-06 19:25:57 - captured_api - INFO - [+] telegram_service
2026-03-06 19:25:57 - captured_api - INFO - [+] telegram_bot
2026-03-06 19:25:57 - captured_api - INFO - [+] api_key
2026-03-06 19:25:57 - captured_api - ERROR - [-] openrouter_client - import error: name 'OpenAI' is not defined
2026-03-06 19:25:57 - captured_api - INFO - [+] usage_tracker
2026-03-06 19:25:57 - captured_api - INFO - [api] Discovered 4 modules
2026-03-06 19:25:57 - captured_api - WARNING - Unknown command: test
2026-03-06 19:26:31 - captured_api - INFO - [api] Discovering modules...
2026-03-06 19:26:31 - captured_api - INFO - [+] telegram_service
2026-03-06 19:26:31 - captured_api - INFO - [+] telegram_bot
2026-03-06 19:26:31 - captured_api - INFO - [+] api_key
2026-03-06 19:26:31 - captured_api - ERROR - [-] openrouter_client - import error: name 'OpenAI' is not defined
2026-03-06 19:26:31 - captured_api - INFO - [+] usage_tracker
2026-03-06 19:26:31 - captured_api - INFO - [api] Discovered 4 modules
2026-03-06 19:26:38 - captured_api - INFO - [api] Discovering modules...
2026-03-06 19:26:38 - captured_api - INFO - [+] telegram_service
2026-03-06 19:26:38 - captured_api - INFO - [+] telegram_bot
2026-03-06 19:26:38 - captured_api - INFO - [+] api_key
2026-03-06 19:26:38 - captured_api - ERROR - [-] openrouter_client - import error: name 'OpenAI' is not defined
2026-03-06 19:26:38 - captured_api - INFO - [+] usage_tracker
2026-03-06 19:26:38 - captured_api - INFO - [api] Discovered 4 modules
2026-03-06 19:26:41 - captured_api - INFO - [api] Discovering modules...
2026-03-06 19:26:41 - captured_api - INFO - [+] telegram_service
2026-03-06 19:26:41 - captured_api - INFO - [+] telegram_bot
2026-03-06 19:26:41 - captured_api - INFO - [+] api_key
2026-03-06 19:26:41 - captured_api - ERROR - [-] openrouter_client - import error: name 'OpenAI' is not defined
2026-03-06 19:26:41 - captured_api - INFO - [+] usage_tracker
2026-03-06 19:26:41 - captured_api - INFO - [api] Discovered 4 modules
+6
View File
@@ -0,0 +1,6 @@
2026-03-06 19:26:45 - captured_aggregate_central - INFO - [aggregate_central] Starting central aggregation
2026-03-06 19:26:45 - captured_aggregate_central - INFO - [aggregate_central] Processing branch: flow
2026-03-06 19:26:45 - captured_aggregate_central - INFO - [aggregate_central] SUCCESS: Aggregation complete: 0 active, 0 recently closed
2026-03-06 20:20:39 - captured_aggregate_central - INFO - [aggregate_central] Starting central aggregation
2026-03-06 20:20:39 - captured_aggregate_central - INFO - [aggregate_central] Processing branch: flow
2026-03-06 20:20:39 - captured_aggregate_central - INFO - [aggregate_central] SUCCESS: Aggregation complete: 1 active, 0 recently closed
+4
View File
@@ -0,0 +1,4 @@
2026-03-06 19:26:52 - captured_close_plan - INFO - [close_plan] Deleted empty template file: /tmp/FPLAN-0001_test_plan_from_devpulse_2026-03-06.md
2026-03-06 19:26:52 - captured_close_plan - INFO - [close_plan] Removed FPLAN-0001 from registry
2026-03-06 20:21:02 - captured_close_plan - INFO - [close_plan] Deleted empty template file: /home/coder/workspace/src/aipass/flow/FPLAN-0002_2026-03-06.md
2026-03-06 20:21:02 - captured_close_plan - INFO - [close_plan] Removed FPLAN-0002 from registry
+2
View File
@@ -0,0 +1,2 @@
2026-03-06 19:26:45 - captured_create_plan - INFO - [create_plan] Created FPLAN-0001 in /tmp
2026-03-06 20:20:39 - captured_create_plan - INFO - [create_plan] Created FPLAN-0002 in flow
+77
View File
@@ -0,0 +1,77 @@
2026-03-06 19:25:13 - captured_flow - INFO - [FLOW] Skipped post_close_runner - no handle_command()
2026-03-06 19:25:13 - captured_flow - INFO - [FLOW] Loaded module: aggregate_central
2026-03-06 19:25:13 - captured_flow - INFO - [FLOW] Loaded module: registry_monitor
2026-03-06 19:25:13 - captured_flow - INFO - [FLOW] Loaded module: restore_plan
2026-03-06 19:25:13 - captured_flow - INFO - [FLOW] Loaded module: list_plans
2026-03-06 19:25:13 - captured_flow - INFO - [FLOW] Loaded module: close_plan
2026-03-06 19:25:13 - captured_flow - INFO - [FLOW] Loaded module: create_plan
2026-03-06 19:25:53 - captured_flow - INFO - [FLOW] Skipped post_close_runner - no handle_command()
2026-03-06 19:25:53 - captured_flow - INFO - [FLOW] Loaded module: aggregate_central
2026-03-06 19:25:53 - captured_flow - INFO - [FLOW] Loaded module: registry_monitor
2026-03-06 19:25:53 - captured_flow - INFO - [FLOW] Loaded module: restore_plan
2026-03-06 19:25:53 - captured_flow - INFO - [FLOW] Loaded module: list_plans
2026-03-06 19:25:53 - captured_flow - INFO - [FLOW] Loaded module: close_plan
2026-03-06 19:25:53 - captured_flow - INFO - [FLOW] Loaded module: create_plan
2026-03-06 19:26:45 - captured_flow - INFO - [FLOW] Skipped post_close_runner - no handle_command()
2026-03-06 19:26:45 - captured_flow - INFO - [FLOW] Loaded module: aggregate_central
2026-03-06 19:26:45 - captured_flow - INFO - [FLOW] Loaded module: registry_monitor
2026-03-06 19:26:45 - captured_flow - INFO - [FLOW] Loaded module: restore_plan
2026-03-06 19:26:45 - captured_flow - INFO - [FLOW] Loaded module: list_plans
2026-03-06 19:26:45 - captured_flow - INFO - [FLOW] Loaded module: close_plan
2026-03-06 19:26:45 - captured_flow - INFO - [FLOW] Loaded module: create_plan
2026-03-06 19:26:49 - captured_flow - INFO - [FLOW] Skipped post_close_runner - no handle_command()
2026-03-06 19:26:49 - captured_flow - INFO - [FLOW] Loaded module: aggregate_central
2026-03-06 19:26:49 - captured_flow - INFO - [FLOW] Loaded module: registry_monitor
2026-03-06 19:26:49 - captured_flow - INFO - [FLOW] Loaded module: restore_plan
2026-03-06 19:26:49 - captured_flow - INFO - [FLOW] Loaded module: list_plans
2026-03-06 19:26:49 - captured_flow - INFO - [FLOW] Loaded module: close_plan
2026-03-06 19:26:49 - captured_flow - INFO - [FLOW] Loaded module: create_plan
2026-03-06 19:26:52 - captured_flow - INFO - [FLOW] Skipped post_close_runner - no handle_command()
2026-03-06 19:26:52 - captured_flow - INFO - [FLOW] Loaded module: aggregate_central
2026-03-06 19:26:52 - captured_flow - INFO - [FLOW] Loaded module: registry_monitor
2026-03-06 19:26:52 - captured_flow - INFO - [FLOW] Loaded module: restore_plan
2026-03-06 19:26:52 - captured_flow - INFO - [FLOW] Loaded module: list_plans
2026-03-06 19:26:52 - captured_flow - INFO - [FLOW] Loaded module: close_plan
2026-03-06 19:26:52 - captured_flow - INFO - [FLOW] Loaded module: create_plan
2026-03-06 20:20:13 - captured_flow - INFO - [FLOW] Skipped post_close_runner - no handle_command()
2026-03-06 20:20:13 - captured_flow - INFO - [FLOW] Loaded module: aggregate_central
2026-03-06 20:20:13 - captured_flow - INFO - [FLOW] Loaded module: registry_monitor
2026-03-06 20:20:13 - captured_flow - INFO - [FLOW] Loaded module: restore_plan
2026-03-06 20:20:13 - captured_flow - INFO - [FLOW] Loaded module: list_plans
2026-03-06 20:20:13 - captured_flow - INFO - [FLOW] Loaded module: close_plan
2026-03-06 20:20:13 - captured_flow - INFO - [FLOW] Loaded module: create_plan
2026-03-06 20:20:22 - captured_flow - INFO - [FLOW] Skipped post_close_runner - no handle_command()
2026-03-06 20:20:22 - captured_flow - INFO - [FLOW] Loaded module: aggregate_central
2026-03-06 20:20:22 - captured_flow - INFO - [FLOW] Loaded module: registry_monitor
2026-03-06 20:20:22 - captured_flow - INFO - [FLOW] Loaded module: restore_plan
2026-03-06 20:20:22 - captured_flow - INFO - [FLOW] Loaded module: list_plans
2026-03-06 20:20:22 - captured_flow - INFO - [FLOW] Loaded module: close_plan
2026-03-06 20:20:22 - captured_flow - INFO - [FLOW] Loaded module: create_plan
2026-03-06 20:20:39 - captured_flow - INFO - [FLOW] Skipped post_close_runner - no handle_command()
2026-03-06 20:20:39 - captured_flow - INFO - [FLOW] Loaded module: aggregate_central
2026-03-06 20:20:39 - captured_flow - INFO - [FLOW] Loaded module: registry_monitor
2026-03-06 20:20:39 - captured_flow - INFO - [FLOW] Loaded module: restore_plan
2026-03-06 20:20:39 - captured_flow - INFO - [FLOW] Loaded module: list_plans
2026-03-06 20:20:39 - captured_flow - INFO - [FLOW] Loaded module: close_plan
2026-03-06 20:20:39 - captured_flow - INFO - [FLOW] Loaded module: create_plan
2026-03-06 20:21:02 - captured_flow - INFO - [FLOW] Skipped post_close_runner - no handle_command()
2026-03-06 20:21:02 - captured_flow - INFO - [FLOW] Loaded module: aggregate_central
2026-03-06 20:21:02 - captured_flow - INFO - [FLOW] Loaded module: registry_monitor
2026-03-06 20:21:02 - captured_flow - INFO - [FLOW] Loaded module: restore_plan
2026-03-06 20:21:02 - captured_flow - INFO - [FLOW] Loaded module: list_plans
2026-03-06 20:21:02 - captured_flow - INFO - [FLOW] Loaded module: close_plan
2026-03-06 20:21:02 - captured_flow - INFO - [FLOW] Loaded module: create_plan
2026-03-06 20:37:06 - captured_flow - INFO - [FLOW] Skipped post_close_runner - no handle_command()
2026-03-06 20:37:06 - captured_flow - INFO - [FLOW] Loaded module: aggregate_central
2026-03-06 20:37:06 - captured_flow - INFO - [FLOW] Loaded module: registry_monitor
2026-03-06 20:37:06 - captured_flow - INFO - [FLOW] Loaded module: restore_plan
2026-03-06 20:37:06 - captured_flow - INFO - [FLOW] Loaded module: list_plans
2026-03-06 20:37:06 - captured_flow - INFO - [FLOW] Loaded module: close_plan
2026-03-06 20:37:06 - captured_flow - INFO - [FLOW] Loaded module: create_plan
2026-03-06 20:38:04 - captured_flow - INFO - [FLOW] Skipped post_close_runner - no handle_command()
2026-03-06 20:38:04 - captured_flow - INFO - [FLOW] Loaded module: aggregate_central
2026-03-06 20:38:04 - captured_flow - INFO - [FLOW] Loaded module: registry_monitor
2026-03-06 20:38:04 - captured_flow - INFO - [FLOW] Loaded module: restore_plan
2026-03-06 20:38:04 - captured_flow - INFO - [FLOW] Loaded module: list_plans
2026-03-06 20:38:04 - captured_flow - INFO - [FLOW] Loaded module: close_plan
2026-03-06 20:38:04 - captured_flow - INFO - [FLOW] Loaded module: create_plan
+2
View File
@@ -0,0 +1,2 @@
2026-03-06 19:25:53 - captured_list_plans - INFO - [list_plans] No plans in registry
2026-03-06 19:26:49 - captured_list_plans - INFO - [list_plans] Listed plans (filter: open)
View File
+2
View File
@@ -0,0 +1,2 @@
2026-03-06 20:19:23 - captured_monitor_module - INFO - Starting unified monitoring (args: [])
2026-03-06 20:19:23 - captured_monitor_module - INFO - All monitoring threads started
+2 -2
View File
@@ -48,10 +48,10 @@ dev = [
[project.scripts]
drone = "aipass.drone.cli:main"
seedgo = "seedgo.cli:main"
seedgo = "aipass.seedgo.apps.seedgo:main"
[tool.hatch.build.targets.wheel]
packages = ["src/aipass", "src/seedgo"]
packages = ["src/aipass"]
[tool.pytest.ini_options]
testpaths = ["tests"]
+1
View File
@@ -0,0 +1 @@
2026-03-06 19:24:36 - captured_seedgo_verify - INFO - Seedgo verify: 5/5 (100%)
+78
View File
@@ -0,0 +1,78 @@
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Starting standards compliance check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - ERROR - [standards_checklist] Error reading branch registry: name 'BRANCH_REGISTRY_PATH' is not defined
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running IMPORTS standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] IMPORTS check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running ARCHITECTURE standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] ARCHITECTURE check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running NAMING standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] NAMING check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running CLI standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] CLI check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running HANDLERS standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] HANDLERS check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running MODULES standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] MODULES check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running DOCUMENTATION standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] DOCUMENTATION check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running JSON_STRUCTURE standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] JSON_STRUCTURE check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running TESTING standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] TESTING check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running ERROR_HANDLING standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] ERROR_HANDLING check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running ENCAPSULATION standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] ENCAPSULATION check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running TRIGGER standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] TRIGGER check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running LOG_LEVEL standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] LOG_LEVEL check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running CLI_FLAGS standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] CLI_FLAGS check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running LOG_HANDLER standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] LOG_HANDLER check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running LOG_VISIBILITY standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] LOG_VISIBILITY check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running PERMISSION_FLAGS standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] PERMISSION_FLAGS check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Running SHEBANG standard check on src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] SHEBANG check complete: 0/100
2026-03-06 19:25:42 - captured_standards_checklist - INFO - [standards_checklist] Standards check complete: 0% average compliance
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Starting standards compliance check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - ERROR - [standards_checklist] Error reading branch registry: name 'BRANCH_REGISTRY_PATH' is not defined
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running IMPORTS standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] IMPORTS check complete: 80/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running ARCHITECTURE standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] ARCHITECTURE check complete: 100/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running NAMING standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] NAMING check complete: 100/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running CLI standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] CLI check complete: 100/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running HANDLERS standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] HANDLERS check complete: 100/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running MODULES standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] MODULES check complete: 60/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running DOCUMENTATION standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] DOCUMENTATION check complete: 100/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running JSON_STRUCTURE standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] JSON_STRUCTURE check complete: 100/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running TESTING standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] TESTING check complete: 100/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running ERROR_HANDLING standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] ERROR_HANDLING check complete: 66/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running ENCAPSULATION standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] ENCAPSULATION check complete: 100/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running TRIGGER standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] TRIGGER check complete: 100/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running LOG_LEVEL standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] LOG_LEVEL check complete: 100/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running CLI_FLAGS standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] CLI_FLAGS check complete: 100/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running LOG_HANDLER standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] LOG_HANDLER check complete: 100/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running LOG_VISIBILITY standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] LOG_VISIBILITY check complete: 100/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running PERMISSION_FLAGS standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] PERMISSION_FLAGS check complete: 100/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Running SHEBANG standard check on /home/coder/workspace/src/aipass/drone/apps/modules/config.py
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] SHEBANG check complete: 100/100
2026-03-06 19:25:46 - captured_standards_checklist - INFO - [standards_checklist] Standards check complete: 94% average compliance
+288 -31
View File
@@ -1,51 +1,308 @@
# AI_MAIL
**Purpose:** Inter-agent messaging, inbox management, dispatch delivery
**Module:** `aipass.ai_mail`
**Created:** 2026-03-05
---
# AI_MAIL - Branch Documentation
## Overview
### What I Do
**Location**: `/home/aipass/aipass_core/ai_mail`
**Profile**: Communication Infrastructure
**Purpose**: Branch-to-branch email system providing file-based messaging for AI branches
**Created**: 2025-11-07
## What I Do
### How I Work
- **Entry Point:** `apps/ai_mail.py`
- **Pattern:** Auto-discovers and routes to modules
AI_MAIL provides internal email system for AI branches within AIPass. Core responsibilities include:
---
- Deliver email messages between AI branches
- Manage inbox, sent, and deleted mailboxes for each branch
- Track email lifecycle: new → opened → closed
- Support reply chains with auto-close behavior
- Auto-generate per-branch configs (user_config.json in [branch]_json/)
- Auto-detect calling branch via PWD/CWD for sender identity
- Update dashboard on delivery (DASHBOARD.local.json)
- Dispatch daemon: continuous polling engine spawns agents for `--dispatch` emails
- Single instance per branch locking (PID-based dispatch lock)
- Reply chain validation (sender must match dispatched_to)
- Maintain 100% CLI standards compliance
- Preserve branch email identities (no impersonation)
## What I Don't Do
- No SMTP/IMAP protocols
- No external email delivery
- No human email accounts
- No centralized identity (each branch has independent config)
- No manual setup required from branches
## How I Work
File-based architecture using JSON for message storage. PWD auto-detection finds calling branch, checks for local config in [branch]_json/, generates config if missing, sends from detected branch identity.
3-layer handler architecture:
- **Modules**: Orchestrate commands
- **Handlers**: Execute business logic
- **Prax**: Provides logging infrastructure
## Architecture
**Pattern**: Modular architecture
**Structure**: apps/ directory with modules/ and handlers/ subdirectories
**Orchestrator**: apps/ai_mail.py - auto-discovers and routes to modules
**Module Interface**: All modules implement handle_command(args) -> bool
### Directory Structure
```
AI_MAIL/
├── apps/
│ ├── ai_mail.py # Entry point
│ ├── modules/ # Business logic
│ ├── handlers/ # Implementation
│ └── plugins/ # Extensions
├── docs/
├── tests/
├── passport.json # Identity
├── local.json # Session history
├── observations.json # Collaboration patterns
└── README.md
apps/
├── ai_mail.py # Main orchestrator
├── __init__.py
├── modules/
│ ├── email.py # Core email functionality
│ ├── branch_ping.py # Branch health monitoring
│ ├── dispatch.py # Dispatch status tracking
│ └── extensions/ # Module extensions
├── handlers/
│ ├── central_writer.py # Central file updates
│ ├── dispatch/ # Dispatch operations
│ │ ├── daemon.py # Continuous dispatch daemon (polling + spawning)
│ │ ├── pending_work.py # Per-branch pending work tracking
│ │ └── status.py # Dispatch log and status
│ ├── email/ # Email operations
│ │ ├── create.py # Create email messages
│ │ ├── delivery.py # Deliver to branch inboxes (write-only, no spawning)
│ │ ├── format.py # Email formatting
│ │ ├── footer.py # Auto-footer for outgoing emails
│ │ ├── header.py # Email header formatting
│ │ ├── inbox_cleanup.py # Inbox cleanup operations
│ │ ├── inbox_lock.py # Inbox file locking
│ │ ├── inbox_ops.py # Inbox operations
│ │ ├── lock_utils.py # PID-based dispatch lock per branch
│ │ ├── purge.py # Auto-purge sent/deleted when >10 items
│ │ └── reply.py # Reply handling with chain validation
│ ├── json_utils/ # JSON operations
│ │ └── json_handler.py # JSON file operations
│ ├── monitoring/ # System monitoring
│ │ ├── data_ops.py # Data operations
│ │ ├── errors.py # Error handling
│ │ └── memory.py # Memory health checks
│ ├── persistence/ # Data persistence
│ │ └── json_ops.py # JSON persistence ops
│ ├── registry/ # Branch registry
│ │ ├── load.py # Load registry
│ │ ├── read.py # Read registry data
│ │ ├── update.py # Update registry
│ │ └── validate.py # Validate registry
│ ├── trigger/ # Event consumers
│ │ └── error_handler.py # Handle error_detected events
│ └── users/ # User/branch config
│ ├── branch_detection.py # Auto-detect calling branch
│ ├── config_generator.py # Generate branch configs
│ ├── load.py # Load configurations
│ └── user.py # User operations
├── extensions/ # App extensions (placeholder)
├── plugins/ # Plugins (placeholder)
└── json_templates/ # JSON templates
├── custom/ # Custom templates
├── default/ # Default templates
└── registry/ # Registry templates
```
---
### Modules
## Commands
- `email` - Core email functionality (send, inbox, view, reply, close, sent, contacts)
- `branch_ping` - Branch memory health monitoring
- `dispatch` - Dispatch status tracking, log, and daemon management
*Configure after initialization*
### Handlers (by domain)
---
**Dispatch**: daemon, pending_work, status
**Email**: create, delivery, footer, format, header, inbox_cleanup, inbox_lock, inbox_ops, lock_utils, purge, reply
**JSON Utils**: json_handler
**Monitoring**: data_ops, errors, memory
**Persistence**: json_ops
**Registry**: load, read, update, validate
**Trigger**: error_handler
**Users**: branch_detection, config_generator, load, user
## Usage
Primary commands: `inbox`, `view`, `reply`, `close`, `send`, `sent`, `contacts`, `ping`, `dispatch`.
### Email Lifecycle v2
AI_MAIL uses a 3-state email model:
**States:**
- `new` - Email just delivered, never viewed
- `opened` - Email content has been viewed, awaiting resolution
- `closed` - Email resolved (replied or dismissed), archived to deleted
**Flow:**
```
Email sent → inbox (status: "new")
↓
view <id> → status: "opened"
↓
┌──────────┴──────────┐
↓ ↓
reply <id> "msg" close <id>
↓ ↓
auto-closes closes
└──────────┬──────────┘
↓
archived to deleted/
```
### Basic Commands
```bash
# Send email
drone @ai_mail send @recipient "Subject" "Message"
# Send with dispatch (auto-execute at recipient)
drone @ai_mail send @recipient "Task" "Details" --dispatch
# Broadcast to all branches
drone @ai_mail send @all "Announcement" "Message"
# Check inbox (shows new + opened emails)
drone @ai_mail inbox
# View email content (marks as opened)
drone @ai_mail view <message_id>
# Reply to email (sends reply + auto-closes original)
drone @ai_mail reply <message_id> "Your reply message"
# Close email without replying (archives to deleted)
drone @ai_mail close <message_id>
# View sent messages
drone @ai_mail sent
# List contacts
drone @ai_mail contacts
```
### Backward Compatibility
```bash
# 'read' command now behaves like 'view'
# (marks as opened, does NOT archive)
drone @ai_mail read <message_id>
```
### Dispatch System (v3.0)
The `--dispatch` flag marks emails for autonomous execution. The **dispatch daemon** polls inboxes and spawns agents — delivery.py is write-only.
**Architecture:**
- `delivery.py` writes to inbox + sends desktop notification. No spawning.
- `daemon.py` polls all branch inboxes every 5 min for `--dispatch` emails
- Agents spawned via `claude -c -p` from the branch's CWD (auto-continues most recent session)
- Agents are ephemeral (wake, do work, exit). The daemon is the continuity.
- All safety limits configured in `safety_config.json`
**Running the daemon:**
```bash
python3 apps/handlers/dispatch/daemon.py # Standalone
ai_mail dispatch daemon # Via module
tmux new-session -d -s dispatch 'python3 apps/handlers/dispatch/daemon.py'
```
**Safety features:**
- **Kill switch**: `touch /home/aipass/.aipass/autonomous_pause` freezes all dispatches
- **Max turns**: 15 per wake (configurable)
- **Max dispatches/branch/day**: 10 (configurable, resets at midnight)
- **Single instance lock**: PID-based `.dispatch.lock` prevents concurrent agents per branch
- **DEV_CENTRAL protection**: @dev_central is never auto-dispatched
- **Notification throttling**: Max 3 desktop notifications per recipient in 30s window
- **Stale lock timeout**: 10 minutes (auto-cleanup of dead locks)
### Direct Module Access
```bash
# Email operations
python3 apps/ai_mail.py email [command]
# Branch health check
python3 apps/ai_mail.py ping
# Dispatch status
python3 apps/ai_mail.py dispatch status
# Start dispatch daemon
python3 apps/ai_mail.py dispatch daemon
```
## Integration Points
### Depends On
**Depends On**:
- PRAX - Logging infrastructure
- CLI - Display and formatting
- DRONE - Command routing
**Provides To**:
- All branches - Email communication
- AIPASS - System coordination
## Memory System
### Core Files
- `AI_MAIL.id.json` - Branch identity and architecture
- `AI_MAIL.local.json` - Session history (max 600 lines)
- `AI_MAIL.observations.json` - Collaboration patterns (max 600 lines)
- `AI_MAIL.ai_mail.json` - Email dashboard
### Mailbox Structure
- `ai_mail.local/inbox.json` - Incoming messages (new + opened status)
- `ai_mail.local/sent/` - Sent messages (individual files, auto-purged at >10)
- `ai_mail.local/deleted/` - Closed/archived messages (individual files, auto-purged at >10)
- `ai_mail.local/.dispatch.lock` - PID-based dispatch lock (when agent active)
- `ai_mail.local/daemon_state.json` - Daemon daily counts and session tracking
- `ai_mail.local/dispatch_daemon.log` - Daemon activity log
- `safety_config.json` - Kill switch, poll interval, max turns/dispatches, autonomous branch list
**Email Schema (v2):**
```json
{
"id": "abc123",
"from": "@sender",
"from_name": "SENDER Branch",
"to": "@recipient",
"subject": "Subject line",
"message": "Message body",
"status": "new", // new | opened | closed
"timestamp": "2025-11-30 12:00:00",
"thread_id": null, // For future threading
"reply_to": null // Original message ID if reply
}
```
### Health Monitoring
- 🟢 **Healthy**: Under 80% of limits
- 🟡 **Warning**: 80-100% of limits
- 🔴 **Critical**: Over limits (compression needed)
## Standards Compliance
Seed audit score: **89%** (passing)
Following AIPass code standards:
- 100% CLI integration
- Proper import patterns
- 3-layer architecture
- Handler independence
- Auto-discovery patterns
## Development Notes
- Code is truth - fail honestly
- Simple solutions over complex architecture
- Test incrementally, preserve what works
- Each instance isolated with own memory
- Never explain context again - memories persist
---
### Provides To
*Last Updated: 2026-02-28*
*Maintained by: AI_MAIL Branch*
@@ -0,0 +1,9 @@
{
"module_name": "branch_ping",
"version": "1.0.0",
"timestamp": "2025-11-13",
"config": {
"auto_save": true,
"enabled": true
}
}
@@ -0,0 +1,8 @@
{
"module_name": "branch_ping",
"created": "2025-11-13",
"last_updated": "2025-11-13",
"operations_total": 0,
"operations_successful": 0,
"operations_failed": 0
}
@@ -0,0 +1,11 @@
[
{
"timestamp": "2026-03-06T20:33:19.802974",
"operation": "ping_executed",
"data": {
"branch": "AI_MAIL",
"local_count": 0,
"obs_count": 0
}
}
]
@@ -0,0 +1,23 @@
{
"last_updated": "2026-03-06T20:33:19.797905",
"active_branches": {
"/home/coder/workspace/src/aipass/ai_mail": {
"branch_name": "AI_MAIL",
"last_ping": "2026-03-06T20:33:19.797892",
"local_md": {
"line_count": 0,
"status": "\ud83d\udfe2 Healthy"
},
"observations_md": {
"line_count": 0,
"status": "\ud83d\udfe2 Healthy"
}
}
},
"statistics": {
"total_branches": 1,
"green_status": 0,
"yellow_status": 0,
"red_status": 0
}
}
-1
View File
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
+1 -1
View File
@@ -45,7 +45,7 @@ def _extract_branch_name(filepath: str) -> str:
"""Extract branch name from a file path."""
parts = filepath.split("/")
for i, part in enumerate(parts):
if part in ("aipass_core", "MEMORY_BANK", "Nexus"):
if part in ("aipass", "MEMORY_BANK", "Nexus"):
if i + 1 < len(parts):
return parts[i + 1]
return "unknown"
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -25,7 +24,7 @@ This file serves as AI_MAIL's API output for AIPASS dashboard integration.
Architecture:
- Scans all ai_mail.local/inbox.json files across the system
- Calculates per-branch unread/total message counts
- Writes aggregated stats to /home/aipass/aipass_os/AI_CENTRAL/AI_MAIL.central.json
- Writes aggregated stats to AI_CENTRAL/AI_MAIL.central.json (under repo root)
"""
# CRITICAL: Use importlib to bypass local json/ directory and get stdlib json
@@ -51,10 +50,19 @@ from typing import Dict, Any, List, Tuple
# CONSTANTS
# =============================================================================
AIPASS_HOME = Path.home() # /home/aipass - scan from user home
AI_CENTRAL_DIR = Path.home() / "aipass_os" / "AI_CENTRAL"
def _find_repo_root() -> Path:
"""Walk up from this file to find AIPASS_REGISTRY.json (repo root)."""
current = Path(__file__).resolve().parent
for parent in [current] + list(current.parents):
if (parent / "AIPASS_REGISTRY.json").exists():
return parent
return Path.cwd()
_REPO_ROOT = _find_repo_root()
AI_CENTRAL_DIR = _REPO_ROOT / "aipass_os" / "AI_CENTRAL"
CENTRAL_FILE = AI_CENTRAL_DIR / "AI_MAIL.central.json"
BRANCH_REGISTRY = Path.home() / "BRANCH_REGISTRY.json"
BRANCH_REGISTRY = _REPO_ROOT / "AIPASS_REGISTRY.json"
# =============================================================================
@@ -65,7 +73,7 @@ def find_all_inbox_files() -> List[Path]:
"""
Find all inbox.json files in ai_mail.local directories.
Scans the entire /home/aipass directory for ai_mail.local/inbox.json files.
Scans the repo root directory for ai_mail.local/inbox.json files.
Excludes backup directories to avoid counting archived data.
Returns:
@@ -77,7 +85,7 @@ def find_all_inbox_files() -> List[Path]:
inbox_files = []
# Search pattern: any directory ending in ai_mail.local containing inbox.json
for ai_mail_dir in AIPASS_HOME.rglob("ai_mail.local"):
for ai_mail_dir in _REPO_ROOT.rglob("ai_mail.local"):
# Skip backup/archive directories (but NOT backup_system branch itself)
path_str = str(ai_mail_dir)
if ".backup" in path_str or ".archive" in path_str or "/backups/" in path_str:
@@ -94,10 +102,10 @@ def extract_branch_name(inbox_path: Path) -> str:
"""
Extract branch name from inbox.json path.
Given: /home/aipass/seed/ai_mail.local/inbox.json
Given: .../seed/ai_mail.local/inbox.json
Returns: SEED
Given: /home/aipass/aipass_core/prax/ai_mail.local/inbox.json
Given: .../prax/ai_mail.local/inbox.json
Returns: PRAX
Args:
@@ -275,7 +283,7 @@ def update_central() -> Dict[str, Any]:
1. Scans all branch ai_mail.local/inbox.json files
2. Aggregates unread and total message counts per branch
3. Calculates system-wide totals
4. Writes results to /home/aipass/aipass_os/AI_CENTRAL/AI_MAIL.central.json
4. Writes results to AI_CENTRAL/AI_MAIL.central.json (under repo root)
Returns:
The data written to central file (for logging/verification)
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -49,19 +48,29 @@ from urllib.error import URLError
from aipass.prax.apps.modules.logger import system_logger as logger
def _find_repo_root() -> Path:
"""Walk up from this file to find AIPASS_REGISTRY.json (repo root)."""
current = Path(__file__).resolve().parent
for parent in [current] + list(current.parents):
if (parent / "AIPASS_REGISTRY.json").exists():
return parent
return Path.cwd()
# Infrastructure paths
AIPASS_ROOT = Path.home() / "aipass_core"
AIPASS_HOME = Path.home()
_REPO_ROOT = _find_repo_root()
_AI_MAIL_DIR = Path(__file__).resolve().parents[3] # ai_mail/
# Paths
CONFIG_FILE = AIPASS_ROOT / "ai_mail" / "safety_config.json"
DAEMON_STATE_FILE = AIPASS_ROOT / "ai_mail" / "ai_mail.local" / "daemon_state.json"
DAEMON_LOG_FILE = AIPASS_ROOT / "ai_mail" / "ai_mail.local" / "dispatch_daemon.log"
DAEMON_PID_FILE = AIPASS_ROOT / "ai_mail" / "ai_mail.local" / "daemon.pid"
BRANCH_REGISTRY = AIPASS_HOME / "BRANCH_REGISTRY.json"
CONFIG_FILE = _AI_MAIL_DIR / "safety_config.json"
DAEMON_STATE_FILE = _AI_MAIL_DIR / "ai_mail.local" / "daemon_state.json"
DAEMON_LOG_FILE = _AI_MAIL_DIR / "ai_mail.local" / "dispatch_daemon.log"
DAEMON_PID_FILE = _AI_MAIL_DIR / "ai_mail.local" / "daemon.pid"
BRANCH_REGISTRY = _REPO_ROOT / "AIPASS_REGISTRY.json"
# Telegram notifications (scheduler bot)
SCHEDULER_CONFIG = AIPASS_HOME / ".aipass" / "scheduler_config.json"
SCHEDULER_CONFIG = _REPO_ROOT / ".aipass" / "scheduler_config.json"
# Graceful shutdown
SHUTDOWN = False
@@ -132,7 +141,7 @@ def _set_session_name(branch_path: Path, name: str) -> bool:
Writing a custom-title entry makes the session identifiable in /resume picker.
"""
encoded_cwd = str(branch_path).replace("/", "-")
projects_dir = Path.home() / ".claude" / "projects" / encoded_cwd
projects_dir = Path("~/.claude/projects").expanduser() / encoded_cwd
if not projects_dir.exists():
return False
jsonl_files = sorted(
@@ -226,7 +235,7 @@ def _acquire_lock(branch_path: Path, pid: int) -> tuple[bool, str]:
def load_config() -> Dict[str, Any]:
"""Load safety config from JSON file."""
DEFAULTS = {
"kill_switch_path": str(AIPASS_HOME / ".aipass" / "autonomous_pause"),
"kill_switch_path": str(_REPO_ROOT / ".aipass" / "autonomous_pause"),
"poll_interval_seconds": 300,
"max_depth": 3,
"max_turns_per_wake": 50,
@@ -271,7 +280,7 @@ def save_daemon_state(state: Dict[str, Any]) -> None:
def is_kill_switch_active(config: Dict[str, Any]) -> bool:
"""Check if the system-wide kill switch is engaged."""
kill_path = Path(config.get("kill_switch_path", str(AIPASS_HOME / ".aipass" / "autonomous_pause")))
kill_path = Path(config.get("kill_switch_path", str(_REPO_ROOT / ".aipass" / "autonomous_pause")))
return kill_path.exists()
@@ -416,7 +425,7 @@ def spawn_agent(
]
# Build monitor command (dispatch_monitor wraps claude, handles bounce + lock cleanup)
MONITOR_SCRIPT = AIPASS_ROOT / "ai_mail" / "apps" / "handlers" / "dispatch" / "dispatch_monitor.py"
MONITOR_SCRIPT = Path(__file__).resolve().parent / "dispatch_monitor.py"
LOG_DIR = branch_path / "ai_mail.local"
LOG_DIR.mkdir(parents=True, exist_ok=True)
STDERR_LOG = str(LOG_DIR / "agent_stderr.log")
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -32,8 +31,8 @@ PENDING_WORK_FILENAME = ".pending_work.json"
def _get_pending_path(branch_path: Path) -> Path:
"""Get the pending work file path for a branch."""
if branch_path == Path("/") or branch_path == Path.home():
return Path.home() / "ai_mail.local" / PENDING_WORK_FILENAME
if branch_path == Path("/"):
return Path.cwd() / "ai_mail.local" / PENDING_WORK_FILENAME
return branch_path / "ai_mail.local" / PENDING_WORK_FILENAME
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -28,9 +27,9 @@ from pathlib import Path
from datetime import datetime
from typing import Dict, Any, List, Optional
# Dispatch log location
AIPASS_ROOT = Path.home() / "aipass_core"
DISPATCH_LOG_FILE = AIPASS_ROOT / "ai_mail" / "ai_mail.local" / "dispatch_log.json"
# Dispatch log location (package-relative)
_AI_MAIL_DIR = Path(__file__).resolve().parents[3] # ai_mail/
DISPATCH_LOG_FILE = _AI_MAIL_DIR / "ai_mail.local" / "dispatch_log.json"
def load_dispatch_log() -> List[Dict[str, Any]]:
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -41,12 +40,22 @@ from typing import Optional, Tuple, List
from aipass.prax.apps.modules.logger import system_logger as logger
def _find_repo_root() -> Path:
"""Walk up from this file to find AIPASS_REGISTRY.json (repo root)."""
current = Path(__file__).resolve().parent
for parent in [current] + list(current.parents):
if (parent / "AIPASS_REGISTRY.json").exists():
return parent
return Path.cwd()
# Infrastructure paths
AIPASS_ROOT = Path.home() / "aipass_core"
AIPASS_HOME = Path.home()
CONFIG_FILE = AIPASS_ROOT / "ai_mail" / "safety_config.json"
BRANCH_REGISTRY = AIPASS_HOME / "BRANCH_REGISTRY.json"
PAUSE_FILE = AIPASS_HOME / ".aipass" / "autonomous_pause"
_REPO_ROOT = _find_repo_root()
_AI_MAIL_DIR = Path(__file__).resolve().parents[3] # ai_mail/
CONFIG_FILE = _AI_MAIL_DIR / "safety_config.json"
BRANCH_REGISTRY = _REPO_ROOT / "AIPASS_REGISTRY.json"
PAUSE_FILE = _REPO_ROOT / ".aipass" / "autonomous_pause"
MONITOR_SCRIPT = Path(__file__).parent / "dispatch_monitor.py"
# Default prompt when no custom message provided
@@ -182,7 +191,7 @@ def _load_config() -> dict:
def _set_session_name(branch_path: Path, name: str) -> bool:
"""Write custom-title to the most recent Claude session JSONL for a branch."""
encoded_cwd = str(branch_path).replace("/", "-")
projects_dir = Path.home() / ".claude" / "projects" / encoded_cwd
projects_dir = Path("~/.claude/projects").expanduser() / encoded_cwd
if not projects_dir.exists():
return False
jsonl_files = sorted(
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -171,8 +170,8 @@ def push_dashboard_update(branch_path: Path) -> bool:
branch_path = Path(branch_path)
# Determine inbox path
if branch_path == Path("/") or branch_path == Path.home():
inbox_file = Path.home() / "ai_mail.local" / "inbox.json"
if branch_path == Path("/"):
inbox_file = Path.cwd() / "ai_mail.local" / "inbox.json"
else:
inbox_file = branch_path / "ai_mail.local" / "inbox.json"
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -36,6 +35,18 @@ from typing import Dict, Tuple, List, Optional, Callable
from aipass.ai_mail.apps.handlers.json_utils.json_handler import load_json, save_json
def _find_repo_root() -> Path:
"""Walk up from this file to find AIPASS_REGISTRY.json (repo root)."""
current = Path(__file__).resolve().parent
for parent in [current] + list(current.parents):
if (parent / "AIPASS_REGISTRY.json").exists():
return parent
return Path.cwd()
_REPO_ROOT = _find_repo_root()
# Lazy imports to avoid circular dependencies
_CONSOLE = None
_INBOX_LOCK = None
@@ -62,13 +73,13 @@ def _get_console():
def get_all_branches() -> List[Dict]:
"""
Get list of all branches for email routing.
Reads from AIPass branch registry at /home/aipass/BRANCH_REGISTRY.json
Reads from AIPass branch registry (AIPASS_REGISTRY.json at repo root).
Returns:
List of dicts with branch info:
[{"name": "AIPASS.admin", "path": "/", "email": "@admin"}, ...]
"""
registry_file = Path("/home/aipass/BRANCH_REGISTRY.json")
registry_file = _REPO_ROOT / "AIPASS_REGISTRY.json"
branches = []
if not registry_file.exists():
@@ -198,7 +209,7 @@ def _is_private_branch_email(email: str) -> bool:
Returns:
True if email belongs to a private branch, False otherwise
"""
registry_path = Path.home() / "PRIVATE_BRANCH_REGISTRY.json"
registry_path = _REPO_ROOT / "PRIVATE_BRANCH_REGISTRY.json"
if not registry_path.exists():
return False
try:
@@ -273,8 +284,8 @@ def deliver_email_to_branch(
branch_path = Path(branches[to_branch])
# Find the branch's ai_mail.local/inbox.json file
if branch_path == Path("/") or branch_path == Path.home():
inbox_file = Path.home() / "ai_mail.local" / "inbox.json"
if branch_path == Path("/") or branch_path == _REPO_ROOT:
inbox_file = _REPO_ROOT / "ai_mail.local" / "inbox.json"
else:
inbox_file = branch_path / "ai_mail.local" / "inbox.json"
@@ -364,7 +375,7 @@ def _get_summary_file_path(branch_path: Path) -> Path:
Get the summary file path for a branch.
Pattern: [BRANCH_NAME].ai_mail.json
Example: /home/aipass/aipass_core/drone/DRONE.ai_mail.json
Example: src/aipass/drone/DRONE.ai_mail.json
Args:
branch_path: Path to branch directory
@@ -374,7 +385,7 @@ def _get_summary_file_path(branch_path: Path) -> Path:
"""
branch_name = branch_path.name.upper()
if branch_path == Path("/") or branch_path == Path.home():
if branch_path == Path("/") or branch_path == _REPO_ROOT:
branch_name = "AIPASS"
summary_file = branch_path / f"{branch_name}.ai_mail.json"
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -31,7 +30,16 @@ from typing import Dict, Optional
from aipass.prax.apps.modules.logger import system_logger as logger
from aipass.cli.apps.modules import console
REGISTRY_PATH = Path.home() / "BRANCH_REGISTRY.json"
def _find_repo_root() -> Path:
"""Walk up from this file to find AIPASS_REGISTRY.json (repo root)."""
current = Path(__file__).resolve().parent
for parent in [current] + list(current.parents):
if (parent / "AIPASS_REGISTRY.json").exists():
return parent
return Path.cwd()
REGISTRY_PATH = _find_repo_root() / "AIPASS_REGISTRY.json"
def lookup_branch_alias(branch_name: str) -> Optional[str]:
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
from pathlib import Path
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -57,8 +56,11 @@ def _get_console() -> Any:
def _get_update_section() -> Any:
"""Lazy import update_section."""
from aipass.dev_central.devpulse.apps.modules.dashboard import update_section
return update_section
try:
from aipass.devpulse.apps.modules.dashboard import update_section
return update_section
except ImportError:
return None
def _get_push_dashboard_update() -> Any:
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -41,8 +40,8 @@ STALE_LOCK_TIMEOUT = 600
def _get_lock_path(branch_path: Path) -> Path:
"""Get the lock file path for a branch."""
if branch_path == Path("/") or branch_path == Path.home():
return Path.home() / "ai_mail.local" / LOCK_FILENAME
if branch_path == Path("/"):
return Path.cwd() / "ai_mail.local" / LOCK_FILENAME
return branch_path / "ai_mail.local" / LOCK_FILENAME
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -42,9 +41,19 @@ from aipass.prax.apps.modules.logger import system_logger as logger
# Purge configuration
MAX_EMAILS = 10
# Memory Bank paths for subprocess vectorization
MEMORY_BANK_PYTHON = Path.home() / "MEMORY_BANK" / ".venv" / "bin" / "python3"
CHROMA_SUBPROCESS_SCRIPT = Path.home() / "MEMORY_BANK" / "apps" / "handlers" / "storage" / "chroma_subprocess.py"
# Memory Bank paths for subprocess vectorization (optional external service)
# These are resolved relative to repo root if available; vectorization is best-effort
def _find_repo_root() -> Path:
"""Walk up from this file to find AIPASS_REGISTRY.json (repo root)."""
current = Path(__file__).resolve().parent
for parent in [current] + list(current.parents):
if (parent / "AIPASS_REGISTRY.json").exists():
return parent
return Path.cwd()
_REPO_ROOT = _find_repo_root()
MEMORY_BANK_PYTHON = _REPO_ROOT / "MEMORY_BANK" / ".venv" / "bin" / "python3"
CHROMA_SUBPROCESS_SCRIPT = _REPO_ROOT / "MEMORY_BANK" / "apps" / "handlers" / "storage" / "chroma_subprocess.py"
def purge_sent_folder(mailbox_path: Path) -> Dict[str, Any]:
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -97,7 +96,7 @@ def send_reply(
# Normalize dispatched_to to email format if it's a path
# DRONE's preprocess_args converts @branch to paths, so we may receive
# "/home/aipass/aipass_core/trigger" instead of "@trigger"
# a filesystem path instead of "@trigger"
if dispatched_to and not dispatched_to.startswith('@'):
# It's a path - look up email in registry
dispatch_info = get_branch_info_from_registry(Path(dispatched_to))
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -24,10 +23,9 @@ the Seed architecture standard requiring apps/handlers/json/json_handler.py.
from pathlib import Path
# Infrastructure paths
AIPASS_ROOT = Path.home() / "aipass_core"
AI_MAIL_ROOT = Path.home() / "aipass_core" / "ai_mail"
AI_MAIL_JSON_DIR = AI_MAIL_ROOT / "ai_mail_json"
# Infrastructure paths (package-relative)
_AI_MAIL_ROOT = Path(__file__).resolve().parents[3] # ai_mail/
AI_MAIL_JSON_DIR = _AI_MAIL_ROOT / "ai_mail_json"
from aipass.ai_mail.apps.handlers.json_utils.json_handler import ( # noqa: F401
load_json,
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -29,13 +28,12 @@ from datetime import datetime
from typing import Dict, List, Any, Optional
import inspect
# Infrastructure paths
AIPASS_ROOT = Path.home() / "aipass_core"
# Infrastructure paths (package-relative)
_AI_MAIL_ROOT = Path(__file__).resolve().parents[3] # ai_mail/
# Constants - Updated for AI_MAIL
AI_MAIL_ROOT = AIPASS_ROOT / "ai_mail"
AI_MAIL_JSON_DIR = AI_MAIL_ROOT / "ai_mail_json"
JSON_TEMPLATES_DIR = AI_MAIL_ROOT / "apps" / "json_templates"
AI_MAIL_JSON_DIR = _AI_MAIL_ROOT / "ai_mail_json"
JSON_TEMPLATES_DIR = _AI_MAIL_ROOT / "apps" / "json_templates"
def _get_caller_module_name() -> str:
@@ -271,7 +269,7 @@ if __name__ == "__main__":
increment_counter("ai_mail", "test_counter", 1)
update_data_metrics("ai_mail", test_metric="working")
print("\nCheck /home/aipass/aipass_core/ai_mail/ai_mail_json/ for created files:")
print(f"\nCheck {AI_MAIL_JSON_DIR}/ for created files:")
print(" - ai_mail_config.json")
print(" - ai_mail_data.json")
print(" - ai_mail_log.json")
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -37,6 +36,18 @@ from typing import Optional, Dict, Tuple
from aipass.cli.apps.modules import console
def _find_repo_root() -> Path:
"""Walk up from this file to find AIPASS_REGISTRY.json (repo root)."""
current = Path(__file__).resolve().parent
for parent in [current] + list(current.parents):
if (parent / "AIPASS_REGISTRY.json").exists():
return parent
return Path.cwd()
_REPO_ROOT = _find_repo_root()
# =============================================
# CONSTANTS
# =============================================
@@ -108,18 +119,18 @@ def get_branch_from_log_path(log_file_path: str) -> Tuple[str, Path]:
Extract branch name and root path from log file path
Args:
log_file_path: Full path to log file (e.g., /home/aipass/api/logs/openrouter.log)
log_file_path: Full path to log file (e.g., .../api/logs/openrouter.log)
Returns:
Tuple of (branch_name, branch_root_path)
Example: ("API", Path("/home/aipass/api"))
Example: ("API", Path(".../api"))
Special case: root directory returns ("AIPASS.admin", Path("/"))
"""
log_path = Path(log_file_path)
# Navigate up from log file to branch root
# /home/aipass/api/logs/openrouter.log -> /home/aipass/api
# .../api/logs/openrouter.log -> .../api
branch_root = log_path.parent.parent
# Special case: root directory
@@ -127,8 +138,8 @@ def get_branch_from_log_path(log_file_path: str) -> Tuple[str, Path]:
return "AIPASS.admin", branch_root
# Extract branch name from directory name
# /home/aipass/api -> "API"
# /home/aipass/backup-system -> "BACKUP_SYSTEM"
# .../api -> "API"
# .../backup-system -> "BACKUP_SYSTEM"
branch_folder = branch_root.name.replace("-", "_")
branch_name = branch_folder.upper()
@@ -186,7 +197,7 @@ def format_error_email(error_hash: str, error_info: Dict, branch_name: str) -> s
Returns:
Formatted email message
"""
branch_root = Path.home() / "aipass_core" / branch_name.lower()
branch_root = _REPO_ROOT / "src" / "aipass" / branch_name.lower()
logs_dir = branch_root / "logs"
message = f"""Error detected in {branch_name} logs
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# =============================================
# META DATA HEADER
@@ -31,13 +30,12 @@ from datetime import datetime
from typing import Dict, List, Any, Optional
import inspect
# Infrastructure paths
AIPASS_ROOT = Path.home() / "aipass_core"
# Infrastructure paths (package-relative)
_AI_MAIL_ROOT = Path(__file__).resolve().parents[3] # ai_mail/
# Constants
AI_MAIL_ROOT = AIPASS_ROOT / "ai_mail"
AI_MAIL_JSON_DIR = AI_MAIL_ROOT / "ai_mail_json"
JSON_TEMPLATES_DIR = AI_MAIL_ROOT / "apps" / "json_templates"
AI_MAIL_JSON_DIR = _AI_MAIL_ROOT / "ai_mail_json"
JSON_TEMPLATES_DIR = _AI_MAIL_ROOT / "apps" / "json_templates"
def _get_caller_module_name() -> str:
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -38,13 +37,24 @@ from aipass.cli.apps.modules import console
# Constants
MODULE_NAME = "registry.read"
BRANCH_REGISTRY_PATH = Path("/home/aipass/BRANCH_REGISTRY.json")
def _find_repo_root() -> Path:
"""Walk up from this file to find AIPASS_REGISTRY.json (repo root)."""
current = Path(__file__).resolve().parent
for parent in [current] + list(current.parents):
if (parent / "AIPASS_REGISTRY.json").exists():
return parent
return Path.cwd()
BRANCH_REGISTRY_PATH = _find_repo_root() / "AIPASS_REGISTRY.json"
def get_all_branches() -> List[Dict]:
"""
Get list of all branches for email selection.
Reads from AIPass branch registry at /home/aipass/BRANCH_REGISTRY.json
Reads from AIPass branch registry (AIPASS_REGISTRY.json at repo root)
Returns:
List of dicts with branch info:
@@ -155,7 +165,7 @@ def get_branch_path_map() -> Dict[str, str]:
Returns:
Dict mapping email -> path
Example: {"@admin": "/", "@flow": "/home/aipass/flow"}
Example: {"@admin": "/", "@flow": "src/aipass/flow"}
"""
branches = get_all_branches()
return {branch["email"]: branch["path"] for branch in branches}
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -39,9 +38,8 @@ from aipass.cli.apps.modules import console
# Constants
MODULE_NAME = "registry.update"
AIPASS_ROOT = Path.home() / "aipass_core"
AI_MAIL_ROOT = AIPASS_ROOT / "ai_mail"
AI_MAIL_JSON = AI_MAIL_ROOT / "ai_mail_json"
_AI_MAIL_ROOT = Path(__file__).resolve().parents[3] # ai_mail/
AI_MAIL_JSON = _AI_MAIL_ROOT / "ai_mail_json"
REGISTRY_PATH = AI_MAIL_JSON / "local_memory_monitor_registry.json"
THRESHOLDS = {
"green": (0, 400),
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -235,8 +234,8 @@ if __name__ == "__main__":
# Sample test data
test_branches = [
{"name": "AIPASS.admin", "path": "/", "email": "@admin"},
{"name": "FLOW", "path": "/home/aipass/flow", "email": "@flow"},
{"name": "DRONE", "path": "/home/aipass/drone", "email": "@drone"},
{"name": "FLOW", "path": "src/aipass/flow", "email": "@flow"},
{"name": "DRONE", "path": "src/aipass/drone", "email": "@drone"},
]
has_collisions, collisions = check_email_collisions(test_branches)
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
# =============================================
# META DATA HEADER
@@ -34,7 +33,16 @@ from typing import Dict
# =============================================
# CONSTANTS
# =============================================
BRANCH_REGISTRY_PATH = Path.home() / "BRANCH_REGISTRY.json"
def _find_repo_root() -> Path:
"""Walk up from this file to find AIPASS_REGISTRY.json (repo root)."""
current = Path(__file__).resolve().parent
for parent in [current] + list(current.parents):
if (parent / "AIPASS_REGISTRY.json").exists():
return parent
return Path.cwd()
BRANCH_REGISTRY_PATH = _find_repo_root() / "AIPASS_REGISTRY.json"
# =============================================
# BRANCH DETECTION FUNCTIONS
@@ -51,7 +59,7 @@ def detect_branch_from_pwd() -> Dict | None:
Dict with branch info if detected:
{
"name": "SEED",
"path": "/home/aipass/seed",
"path": "src/aipass/seedgo",
"email": "@seed",
"display_name": "Seed (Standards Branch)",
...
@@ -83,7 +91,7 @@ def find_branch_root(start_path: Path) -> Path | None:
Walk up directory tree to find branch root.
Branch root = directory containing a [BRANCH_NAME].id.json file.
Example: /home/aipass/seed/ contains SEED.id.json
Example: src/aipass/seedgo/ contains SEED.id.json
Args:
start_path: Directory to start searching from (usually PWD)
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
# =============================================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
# =============================================
# META DATA HEADER
@@ -35,9 +34,8 @@ from typing import Dict
# =============================================
# CONSTANTS
# =============================================
AIPASS_ROOT = Path.home() / "aipass_core"
AI_MAIL_ROOT = AIPASS_ROOT / "ai_mail"
AI_MAIL_JSON = AI_MAIL_ROOT / "ai_mail_json"
_AI_MAIL_ROOT = Path(__file__).resolve().parents[3] # ai_mail/
AI_MAIL_JSON = _AI_MAIL_ROOT / "ai_mail_json"
USER_CONFIG_FILE = AI_MAIL_JSON / "user_config.json"
# Import branch detection (after constants defined)
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
# =============================================
# META DATA HEADER
@@ -106,7 +105,8 @@ def get_user_by_email(email: str) -> Dict | None:
from .branch_detection import get_branch_info_from_registry
# Use registry lookup
registry_path = Path.home() / "BRANCH_REGISTRY.json"
from .branch_detection import BRANCH_REGISTRY_PATH
registry_path = BRANCH_REGISTRY_PATH
if not registry_path.exists():
return None
@@ -136,7 +136,8 @@ def get_all_users() -> Dict[str, Dict]:
Returns:
Dict mapping branch emails to user info dicts
"""
registry_path = Path.home() / "BRANCH_REGISTRY.json"
from .branch_detection import BRANCH_REGISTRY_PATH
registry_path = BRANCH_REGISTRY_PATH
if not registry_path.exists():
return {}
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
+1 -2
View File
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -57,7 +56,7 @@ DAEMON:
Run as: ai_mail dispatch daemon
Or standalone: python3 apps/handlers/dispatch/daemon.py
Kill switch: touch /home/aipass/.aipass/autonomous_pause
Kill switch: touch <repo_root>/.aipass/autonomous_pause
Config: safety_config.json
EXAMPLE:
+14 -7
View File
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -39,15 +38,23 @@ import argparse
from pathlib import Path
from typing import List
# Infrastructure
AIPASS_ROOT = Path.home() / "aipass_core"
# Infrastructure (package-relative)
_AI_MAIL_DIR = Path(__file__).resolve().parents[2] # ai_mail/
from aipass.prax.apps.modules.logger import system_logger as logger
from aipass.cli.apps.modules import console
from aipass.ai_mail.apps.handlers.central_writer import update_central
from aipass.dev_central.devpulse.apps.modules.dashboard import update_section as _update_dashboard_section
from aipass.ai_mail.apps.handlers.email.dashboard_sync import push_dashboard_update
try:
from aipass.ai_mail.apps.handlers.central_writer import update_central
except ImportError:
update_central = None
try:
from aipass.devpulse.apps.modules.dashboard import update_section as _update_dashboard_section
except ImportError:
_update_dashboard_section = None
# Import handlers (business logic providers)
from aipass.ai_mail.apps.handlers.email.delivery import deliver_email_to_branch
from aipass.ai_mail.apps.handlers.email.create import create_email_file, load_email_file
@@ -300,7 +307,7 @@ def handle_send(args: List[str]) -> bool:
if a.startswith('@') and not rest:
recipients.append(a)
elif a.startswith('/') and not rest:
# Path-based recipient (e.g., /home/aipass/...)
# Path-based recipient (e.g., /path/to/branch)
recipients.append(a)
else:
rest.append(a)
@@ -459,7 +466,7 @@ def send_email_direct(to_branch: str, subject: str, message: str, auto_execute:
user_info = {
"email_address": email_addr,
"display_name": branch_name,
"mailbox_path": str(AIPASS_ROOT / from_branch.lstrip('@').lower() / "ai_mail.local"),
"mailbox_path": str(_AI_MAIL_DIR.parent / from_branch.lstrip('@').lower() / "ai_mail.local"),
"timestamp_format": "%Y-%m-%d %H:%M:%S"
}
else:
-1
View File
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
+9
View File
@@ -0,0 +1,9 @@
{
"module_name": "api",
"version": "1.0.0",
"timestamp": "2025-11-13",
"config": {
"auto_save": true,
"enabled": true
}
}
+8
View File
@@ -0,0 +1,8 @@
{
"module_name": "api",
"created": "2025-11-13",
"last_updated": "2025-11-13",
"operations_total": 0,
"operations_successful": 0,
"operations_failed": 0
}
@@ -0,0 +1,9 @@
{
"module_name": "api_key",
"version": "1.0.0",
"timestamp": "2025-11-13",
"config": {
"auto_save": true,
"enabled": true
}
}
@@ -0,0 +1,8 @@
{
"module_name": "api_key",
"created": "2025-11-13",
"last_updated": "2025-11-13",
"operations_total": 0,
"operations_successful": 0,
"operations_failed": 0
}
+16
View File
@@ -0,0 +1,16 @@
[
{
"timestamp": "2026-03-06T19:26:31.512349",
"operation": "api_key_get-key",
"data": {
"command": "get-key"
}
},
{
"timestamp": "2026-03-06T19:26:38.756413",
"operation": "api_key_validate",
"data": {
"command": "validate"
}
}
]
+55
View File
@@ -0,0 +1,55 @@
[
{
"timestamp": "2026-03-06T19:25:27.817286",
"operation": "api_help_displayed",
"data": {
"trigger": "--help"
}
},
{
"timestamp": "2026-03-06T19:25:57.579810",
"operation": "api_command_attempted",
"data": {
"command": "test",
"modules_discovered": 4
}
},
{
"timestamp": "2026-03-06T19:26:31.498902",
"operation": "api_command_attempted",
"data": {
"command": "get-key",
"modules_discovered": 4
}
},
{
"timestamp": "2026-03-06T19:26:38.745089",
"operation": "api_command_attempted",
"data": {
"command": "validate",
"modules_discovered": 4
}
},
{
"timestamp": "2026-03-06T19:26:41.953458",
"operation": "api_command_attempted",
"data": {
"command": "stats",
"modules_discovered": 4
}
},
{
"timestamp": "2026-03-06T20:37:07.497952",
"operation": "api_help_displayed",
"data": {
"trigger": "--help"
}
},
{
"timestamp": "2026-03-06T20:38:04.859299",
"operation": "api_help_displayed",
"data": {
"trigger": "--help"
}
}
]
@@ -0,0 +1,9 @@
{
"module_name": "usage_tracker",
"version": "1.0.0",
"timestamp": "2025-11-13",
"config": {
"auto_save": true,
"enabled": true
}
}
@@ -0,0 +1,8 @@
{
"module_name": "usage_tracker",
"created": "2025-11-13",
"last_updated": "2025-11-13",
"operations_total": 0,
"operations_successful": 0,
"operations_failed": 0
}
@@ -0,0 +1,9 @@
[
{
"timestamp": "2026-03-06T19:26:41.965942",
"operation": "usage_stats",
"data": {
"command": "stats"
}
}
]
-1
View File
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
+1 -1
View File
@@ -28,7 +28,7 @@ def _extract_branch_name(filepath: str) -> str:
"""Extract branch name from a file path."""
parts = filepath.split("/")
for i, part in enumerate(parts):
if part in ("aipass_core", "MEMORY_BANK", "seed", ".vscode"):
if part in ("MEMORY_BANK", "seed", ".vscode"):
if i + 1 < len(parts):
return parts[i + 1]
if part in ("aipass",) and i + 1 < len(parts) and parts[i + 1] == "apps":
+5 -8
View File
@@ -1,5 +1,3 @@
#!/home/aipass/.venv/bin/python3
# -*- coding: utf-8 -*-
# ===================AIPASS====================
# META DATA HEADER
@@ -51,7 +49,7 @@ from aipass.cli.apps.modules import console
API_ROOT = Path(__file__).resolve().parent.parent.parent.parent
DEFAULT_ENV_PATHS = [
API_ROOT / ".env", # <api_root>/.env
Path.home() / ".env", # ~/.env
Path.cwd() / ".env", # <cwd>/.env
]
@@ -64,9 +62,8 @@ def read_env_file(env_var: str, search_paths: Optional[List[Path]] = None) -> Op
Read environment variable from .env files with multi-path search.
Searches multiple .env file locations in order:
1. /home/aipass/aipass_core/api/.env
2. /home/aipass/aipass_core/.env
3. /home/aipass/.env
1. <api_root>/.env (package-relative)
2. <cwd>/.env (current working directory)
Args:
env_var: Environment variable name to read (e.g., 'OPENROUTER_API_KEY')
@@ -118,7 +115,7 @@ def read_env_file_dict(env_path: Path) -> Dict[str, str]:
dict: Dictionary of key-value pairs from .env file
Example:
>>> env_vars = read_env_file_dict(Path('/home/aipass/aipass_core/api/.env'))
>>> env_vars = read_env_file_dict(Path('api/.env'))
>>> print(env_vars.get('OPENROUTER_API_KEY'))
"""
env_dict = {}
@@ -167,7 +164,7 @@ def create_env_template(provider: str = "openrouter", target_path: Optional[Path
Example:
>>> if create_env_template('openrouter'):
... print("Template created at /home/aipass/aipass_core/api/.env")
... print("Template created at <api_root>/.env")
"""
# Default to api/.env
env_path = target_path or (API_ROOT / ".env")
+1 -3
View File
@@ -1,5 +1,3 @@
#!/home/aipass/.venv/bin/python3
# -*- coding: utf-8 -*-
# ===================AIPASS====================
# META DATA HEADER
@@ -130,7 +128,7 @@ def get_key_from_config(provider: str) -> Optional[str]:
"""
Retrieve API key from config JSON file.
Reads from: /home/aipass/aipass_core/api/api_json/api_connect_config.json
Reads from: <api_root>/api_json/api_connect_config.json
Args:
provider: Provider name (e.g., 'openrouter')
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -25,8 +24,9 @@ import inspect
# Infrastructure
# Constants
API_ROOT = Path.home() / "aipass_core" / "api"
# Constants — package-relative paths
# Navigate: json_handler.py -> json/ -> handlers/ -> apps/ -> api/
API_ROOT = Path(__file__).resolve().parent.parent.parent.parent
API_JSON_DIR = API_ROOT / "api_json"
JSON_TEMPLATES_DIR = API_ROOT / "apps" / "json_templates"
@@ -275,7 +275,7 @@ if __name__ == "__main__":
update_data_metrics("api", test_metric="working")
console.print()
console.print("[green]Check /home/aipass/aipass_core/api/api_json/ for created files:[/green]")
console.print(f"[green]Check {API_JSON_DIR}/ for created files:[/green]")
console.print(" [dim]•[/dim] api_config.json")
console.print(" [dim]•[/dim] api_data.json")
console.print(" [dim]•[/dim] api_log.json")
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
# =============================================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -20,9 +19,7 @@ Business logic for querying and filtering OpenRouter models:
- Parse model data and capabilities
- Extract model metadata (context, pricing, capabilities)
Extracted from:
- /home/aipass/aipass_core/api/apps/archive.temp/openrouter.py
- /home/aipass/aipass_core/api/.archive/find_free_models.py
Extracted from legacy archive files (openrouter.py, find_free_models.py).
"""
# AIPASS_ROOT import pattern
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -46,7 +45,7 @@ Usage:
bot = BaseBot(
bot_id="dev_central",
bot_token="123:ABC",
work_dir=Path("/home/aipass/aipass_os/dev_central"),
work_dir=Path.cwd(),
bot_name="AIPass Dev Central Bot",
allowed_user_ids=[7235222625],
)
@@ -65,6 +64,7 @@ import argparse
import atexit
import json
import os
import shutil
import signal
import subprocess
import threading
@@ -115,7 +115,16 @@ from aipass.api.apps.handlers.telegram.log_streamer import LogStreamer
# MODULE-LEVEL CONSTANTS
# =============================================
PENDING_DIR = Path.home() / ".aipass" / "telegram_pending"
def _aipass_data_dir() -> Path:
"""User data directory for AIPass runtime files (config, state, pending)."""
env = os.environ.get("AIPASS_DATA_DIR")
if env:
return Path(env)
return Path(os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share")) / "aipass"
_DATA_DIR = _aipass_data_dir()
PENDING_DIR = _DATA_DIR / "telegram_pending"
PENDING_TTL = 3600 # 1 hour
TELEGRAM_CHAR_LIMIT = 4096
RATE_LIMIT_MESSAGES = 5
@@ -123,7 +132,7 @@ RATE_LIMIT_WINDOW = 60
POLL_TIMEOUT = 30
SEND_KEYS_DELAY = 0.5
HEARTBEAT_INTERVAL = 30 # seconds
CLAUDE_BIN = str(Path.home() / ".local" / "bin" / "claude")
CLAUDE_BIN = shutil.which("claude") or "claude"
TEMP_DIR = Path("/tmp/telegram_uploads")
MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
@@ -216,10 +225,10 @@ class BaseBot:
self.logger = get_direct_logger()
# Lock file
self._lock_file = Path.home() / ".aipass" / "telegram_bots" / f".{bot_id}.lock"
self._lock_file = _DATA_DIR / "telegram_bots" / f".{bot_id}.lock"
# Offset file
self._offset_file = Path.home() / ".aipass" / "telegram_bots" / f"{bot_id}_offset.json"
self._offset_file = _DATA_DIR / "telegram_bots" / f"{bot_id}_offset.json"
# =============================================
# MAIN ENTRY POINT
@@ -1475,7 +1484,9 @@ class BaseBot:
"""
slug = str(self.work_dir).replace("/", "-")
# Look for transcript files matching the session pattern
projects_dir = Path.home() / ".claude" / "projects" / slug
# Claude Code stores transcripts under ~/.claude/projects/
claude_home = Path(os.environ.get("CLAUDE_HOME", Path.home() / ".claude"))
projects_dir = claude_home / "projects" / slug
if not projects_dir.exists():
return 0
@@ -1758,11 +1769,11 @@ if __name__ == "__main__":
parser.add_argument("--config", help="Path to bot config JSON")
args = parser.parse_args()
# Load config from ~/.aipass/telegram_bots/{bot_id}.json or --config path
# Load config from data dir telegram_bots/{bot_id}.json or --config path
config_path = (
Path(args.config)
if args.config
else Path.home() / ".aipass" / "telegram_bots" / f"{args.bot_id}.json"
else _DATA_DIR / "telegram_bots" / f"{args.bot_id}.json"
)
with open(config_path, "r", encoding="utf-8") as f:
@@ -1771,7 +1782,7 @@ if __name__ == "__main__":
bot = BaseBot(
bot_id=args.bot_id,
bot_token=config["bot_token"],
work_dir=Path(config.get("work_dir", str(Path.home()))),
work_dir=Path(config.get("work_dir", str(Path.cwd()))),
bot_name=config.get("bot_name", "AIPass Bot"),
allowed_user_ids=config.get("allowed_user_ids", []),
branch_name=config.get("branch_name"),
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -38,6 +37,8 @@ from pathlib import Path
# Standard library
import json
import os
import shutil
import subprocess
from datetime import datetime, timezone
from typing import Optional
@@ -57,9 +58,26 @@ from aipass.api.apps.handlers.telegram.bot_registry import (
# =============================================
TELEGRAM_API = "https://api.telegram.org/bot{token}"
BOT_CONFIG_DIR = Path.home() / ".aipass" / "telegram_bots"
BRANCH_REGISTRY = Path.home() / "BRANCH_REGISTRY.json"
SYSTEMD_DIR = Path.home() / ".config" / "systemd" / "user"
def _aipass_data_dir() -> Path:
"""User data directory for AIPass runtime files."""
env = os.environ.get("AIPASS_DATA_DIR")
if env:
return Path(env)
return Path(os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share")) / "aipass"
def _find_repo_root() -> Path:
"""Walk up from this file to find AIPASS_REGISTRY.json (repo root)."""
current = Path(__file__).resolve().parent
for parent in [current] + list(current.parents):
if (parent / "AIPASS_REGISTRY.json").exists():
return parent
return Path.cwd()
_DATA_DIR = _aipass_data_dir()
BOT_CONFIG_DIR = _DATA_DIR / "telegram_bots"
BRANCH_REGISTRY = _find_repo_root() / "AIPASS_REGISTRY.json"
SYSTEMD_DIR = Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config")) / "systemd" / "user"
# Default commands set on every new bot via BotFather
DEFAULT_BOT_COMMANDS = [
@@ -269,7 +287,7 @@ def start_bot_process(bot_id: str) -> bool:
True if the process was launched successfully, False otherwise.
"""
BASE_BOT_PATH = Path(__file__).resolve().parent / "base_bot.py"
PYTHON = str(Path.home() / ".venv" / "bin" / "python3")
PYTHON = shutil.which("python3") or sys.executable
try:
proc = subprocess.Popen(
@@ -366,7 +384,7 @@ def create_bot(
BOT_USERNAME = bot_info.get("username", "unknown")
# Step 2: Validate branch if provided
RESOLVED_WORK_DIR = str(Path.home()) if work_dir is None else str(work_dir)
RESOLVED_WORK_DIR = str(Path.cwd()) if work_dir is None else str(work_dir)
if branch_name:
branch_info = validate_branch(branch_name)
if not branch_info:
@@ -516,7 +534,7 @@ def delete_bot(bot_id: str, kill_tmux: bool = True) -> bool:
logger.warning("Failed to remove config file: %s", e)
# Step 4: Clean up pending files (both v1 and v2 naming)
PENDING_DIR = Path.home() / ".aipass" / "telegram_pending"
PENDING_DIR = _DATA_DIR / "telegram_pending"
BRANCH_NAME = bot.get("branch_name", bot_id)
# v2 naming: bot-{bot_id}.json
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -71,7 +70,7 @@ def start_bot(bot_id: str) -> int | None:
if not bot_token:
return None
work_dir = Path(config.get("work_dir", str(Path.home())))
work_dir = Path(config.get("work_dir", str(Path.cwd())))
bot_name = config.get("bot_name", f"AIPass {bot_id} Bot")
allowed_user_ids = config.get("allowed_user_ids", [])
branch_name = config.get("branch_name")
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -36,6 +35,7 @@ from pathlib import Path
# Standard library
import fcntl
import json
import os
from datetime import datetime, timezone
from typing import Optional
@@ -46,7 +46,14 @@ from aipass.prax.apps.modules.logger import system_logger as logger
# CONSTANTS
# =============================================
REGISTRY_DIR = Path.home() / ".aipass" / "telegram_bots"
def _aipass_data_dir() -> Path:
"""User data directory for AIPass runtime files."""
env = os.environ.get("AIPASS_DATA_DIR")
if env:
return Path(env)
return Path(os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share")) / "aipass"
REGISTRY_DIR = _aipass_data_dir() / "telegram_bots"
REGISTRY_FILE = REGISTRY_DIR / "_registry.json"
# =============================================
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -44,6 +43,7 @@ from pathlib import Path
# Standard library
import asyncio
import json
import os
import re
import time
from typing import Any, Optional
@@ -64,7 +64,14 @@ except ImportError:
# CONSTANTS
# =============================================
BOT_CONFIG_DIR = Path.home() / ".aipass" / "telegram_bots"
def _aipass_data_dir() -> Path:
"""User data directory for AIPass runtime files."""
env = os.environ.get("AIPASS_DATA_DIR")
if env:
return Path(env)
return Path(os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share")) / "aipass"
BOT_CONFIG_DIR = _aipass_data_dir() / "telegram_bots"
TELETHON_CONFIG_PATH = BOT_CONFIG_DIR / ".telethon_config.json"
SESSION_PATH = BOT_CONFIG_DIR / ".telethon" # Telethon appends .session automatically
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -30,7 +29,7 @@ Usage:
branch_name="dev_central",
bot_id="dev_central",
bot_token="123:ABC",
work_dir=Path("/home/aipass/aipass_os/dev_central"),
work_dir=Path.cwd(),
bot_name="AIPass Dev Central Bot",
allowed_user_ids=[7235222625],
)
@@ -38,6 +37,7 @@ Usage:
"""
# Infrastructure
import os
import sys
from pathlib import Path
@@ -130,11 +130,15 @@ if __name__ == "__main__":
parser.add_argument("--config", help="Path to bot config JSON")
args = parser.parse_args()
# Load config from ~/.aipass/telegram_bots/{bot_id}.json or --config path
# Load config from data dir telegram_bots/{bot_id}.json or --config path
_env_data = os.environ.get("AIPASS_DATA_DIR")
_data_dir = Path(_env_data) if _env_data else (
Path(os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share")) / "aipass"
)
config_path = (
Path(args.config)
if args.config
else Path.home() / ".aipass" / "telegram_bots" / f"{args.bot_id}.json"
else _data_dir / "telegram_bots" / f"{args.bot_id}.json"
)
with open(config_path, "r", encoding="utf-8") as f:
@@ -157,7 +161,7 @@ if __name__ == "__main__":
bot = BaseBot(
bot_id=args.bot_id,
bot_token=config["bot_token"],
work_dir=Path(config.get("work_dir", str(Path.home()))),
work_dir=Path(config.get("work_dir", str(Path.cwd()))),
bot_name=config.get("bot_name", "AIPass Bot"),
allowed_user_ids=config.get("allowed_user_ids", []),
shared_session=shared_session,
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -29,6 +28,7 @@ Manages Telegram bot configuration:
"""
# Infrastructure
import os
import sys
from pathlib import Path
@@ -40,8 +40,16 @@ from typing import Optional, List
# CONSTANTS
# =============================================
CONFIG_PATH = Path.home() / ".aipass" / "telegram_config.json"
BOT_CONFIG_DIR = Path.home() / ".aipass" / "telegram_bots"
def _aipass_data_dir() -> Path:
"""User data directory for AIPass runtime files."""
env = os.environ.get("AIPASS_DATA_DIR")
if env:
return Path(env)
return Path(os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share")) / "aipass"
_DATA_DIR = _aipass_data_dir()
CONFIG_PATH = _DATA_DIR / "telegram_config.json"
BOT_CONFIG_DIR = _DATA_DIR / "telegram_bots"
REQUIRED_BOT_FIELDS = ("bot_id", "bot_token")
@@ -165,7 +173,7 @@ def load_bot_config(bot_id: str) -> dict | None:
"bot_token": "123:ABC...",
"bot_name": "AIPass Dev Central Bot",
"branch_name": "dev_central", // null for base bot
"work_dir": "/home/aipass/aipass_os/dev_central",
"work_dir": "/path/to/branch/work_dir",
"allowed_user_ids": [7235222625]
}
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -51,7 +50,15 @@ from aipass.prax.apps.modules.logger import get_direct_logger
# CONSTANTS
# =============================================
SYSTEM_LOGS_DIR = Path("/home/aipass/system_logs")
def _find_repo_root() -> Path:
"""Walk up from this file to find AIPASS_REGISTRY.json (repo root)."""
current = Path(__file__).resolve().parent
for parent in [current] + list(current.parents):
if (parent / "AIPASS_REGISTRY.json").exists():
return parent
return Path.cwd()
SYSTEM_LOGS_DIR = _find_repo_root() / "logs"
BATCH_INTERVAL = 5.0
TELEGRAM_MAX_LENGTH = 4000
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -28,6 +27,7 @@ Reads bot token and chat_id from ~/.aipass/scheduler_config.json.
"""
# Infrastructure
import os
import sys
from pathlib import Path
@@ -40,7 +40,14 @@ from urllib.error import URLError
# CONSTANTS
# =============================================
CONFIG_PATH = Path.home() / ".aipass" / "scheduler_config.json"
def _aipass_data_dir() -> Path:
"""User data directory for AIPass runtime files."""
env = os.environ.get("AIPASS_DATA_DIR")
if env:
return Path(env)
return Path(os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share")) / "aipass"
CONFIG_PATH = _aipass_data_dir() / "scheduler_config.json"
# =============================================
# PUBLIC API
@@ -1,4 +1,4 @@
#!/home/aipass/.venv/bin/python3
#!/usr/bin/env python3
# ===================AIPASS====================
# META DATA HEADER
@@ -34,9 +34,7 @@ from dataclasses import dataclass
from pathlib import Path
from typing import List, Optional
# Infrastructure
AIPASS_ROOT = Path.home() / "aipass_core"
sys.path.insert(0, str(AIPASS_ROOT))
# Infrastructure — disabled file, no sys.path manipulation needed
logger = logging.getLogger("telegram_output_parser")
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -21,9 +20,8 @@ CWD-Safe Response Routing for Multi-Bot Architecture
Fixes the CWD mismatch bug in the Stop hook. When Claude fires the Stop hook,
the working directory may be a subdirectory of the branch root (e.g.,
/home/aipass/aipass_os/dev_central/git_repo/ instead of
/home/aipass/aipass_os/dev_central/). The old logic used Path.cwd().name
which fails in subdirectories.
<branch_root>/git_repo/ instead of <branch_root>/). The old logic used
Path.cwd().name which fails in subdirectories.
New logic uses cwd.relative_to(work_dir) which succeeds if CWD is ANYWHERE
in the bot's directory tree.
@@ -52,7 +50,15 @@ from aipass.prax.apps.modules.logger import system_logger as logger
# CONSTANTS
# =============================================
PENDING_DIR = Path.home() / ".aipass" / "telegram_pending"
def _aipass_data_dir() -> Path:
"""User data directory for AIPass runtime files."""
env = os.environ.get("AIPASS_DATA_DIR")
if env:
return Path(env)
return Path(os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share")) / "aipass"
_DATA_DIR = _aipass_data_dir()
PENDING_DIR = _DATA_DIR / "telegram_pending"
PENDING_TTL = 3600 # 1 hour
@@ -225,7 +231,7 @@ def find_pending_bot(
try:
cwd = Path.cwd()
except OSError:
cwd = Path.home()
cwd = Path.cwd()
if env_bot_id is None:
env_bot_id = os.environ.get("AIPASS_BOT_ID")
@@ -1,4 +1,4 @@
#!/home/aipass/.venv/bin/python3
#!/usr/bin/env python3
# ===================AIPASS====================
# META DATA HEADER
@@ -28,7 +28,7 @@ Two modes of operation:
2. Capture mode: Run Claude directly and capture stdout for response
Supports branch targeting: messages starting with @branch_name spawn Claude
in that branch's directory. Default: /home/aipass/aipass_os/dev_central.
in that branch's directory.
"""
import sys
@@ -42,20 +42,19 @@ import uuid
from pathlib import Path
from typing import Tuple, Optional, List
# Infrastructure
AIPASS_ROOT = Path.home() / "aipass_core"
sys.path.insert(0, str(AIPASS_ROOT))
# Infrastructure — disabled file, kept for reference only
import logging
logger = logging.getLogger("telegram_spawner")
from api.apps.handlers.telegram.output_parser import OutputParser, ParsedResult
from api.apps.handlers.telegram.session_store import get_session, save_session
# NOTE: These imports reference old non-aipass namespace and won't work.
# from api.apps.handlers.telegram.output_parser import OutputParser, ParsedResult
# from api.apps.handlers.telegram.session_store import get_session, save_session
# Constants
DEFAULT_SESSION_PATH = Path.home() / "aipass_os" / "dev_central"
BRANCH_REGISTRY_PATH = Path.home() / "BRANCH_REGISTRY.json"
CLAUDE_BIN = str(Path.home() / ".local" / "bin" / "claude")
# Constants — package-relative
DEFAULT_SESSION_PATH = Path.cwd()
BRANCH_REGISTRY_PATH = Path.cwd() / "AIPASS_REGISTRY.json"
CLAUDE_BIN = shutil.which("claude") or "claude"
TMUX_SESSION_NAME = "telegram-claude"
TELEGRAM_CHAR_LIMIT = 4096
DEFAULT_TIMEOUT = 120 # seconds
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -44,7 +43,7 @@ from typing import List, Optional
# Constants
SESSION_PREFIX = "telegram-"
DEFAULT_BRANCH = "dev_central"
CLAUDE_BIN = str(Path.home() / ".local" / "bin" / "claude")
CLAUDE_BIN = shutil.which("claude") or "claude"
SEND_KEYS_DELAY = 0.5 # seconds between text injection and Enter
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -18,12 +17,21 @@ Telegram Service Handler
Low-level systemd operations for telegram-bridge service.
"""
import os
import subprocess
from pathlib import Path
from typing import Tuple
def _find_repo_root() -> Path:
"""Walk up from this file to find AIPASS_REGISTRY.json (repo root)."""
current = Path(__file__).resolve().parent
for parent in [current] + list(current.parents):
if (parent / "AIPASS_REGISTRY.json").exists():
return parent
return Path.cwd()
SERVICE_NAME = "telegram-bridge"
LOG_FILE = Path.home() / "system_logs" / "telegram_bridge.log"
LOG_FILE = _find_repo_root() / "logs" / "telegram_bridge.log"
def start_service() -> Tuple[bool, str]:
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -21,7 +20,7 @@ Business logic for aggregating usage statistics:
- Cost, token, and latency aggregation
- Model usage tracking and breakdown
Extracted from: /home/aipass/aipass_core/api/apps/archive.temp/api_usage.py
Extracted from legacy archive (api_usage.py).
Functions: get_caller_usage(), get_session_summary(), get_daily_usage()
"""
@@ -1,5 +1,3 @@
#!/home/aipass/.venv/bin/python3
# -*- coding: utf-8 -*-
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -20,7 +19,7 @@ Business logic for tracking API usage from OpenRouter:
- Store generation tracking data with newest-first ordering
- Handle HTTP requests with proper error handling
Extracted from: /home/aipass/aipass_core/api/apps/archive.temp/api_usage.py
Extracted from legacy archive (api_usage.py).
Functions: track_usage(), _get_generation_metrics(), _store_usage_data()
"""
-1
View File
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER
@@ -1,4 +1,3 @@
#!/home/aipass/.venv/bin/python3
# ===================AIPASS====================
# META DATA HEADER

Some files were not shown because too many files have changed in this diff Show More