openfish 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. openfish-1.0.0/PKG-INFO +115 -0
  2. openfish-1.0.0/README_PYPI.md +88 -0
  3. openfish-1.0.0/openfish.egg-info/PKG-INFO +115 -0
  4. openfish-1.0.0/openfish.egg-info/SOURCES.txt +88 -0
  5. openfish-1.0.0/openfish.egg-info/dependency_links.txt +1 -0
  6. openfish-1.0.0/openfish.egg-info/entry_points.txt +2 -0
  7. openfish-1.0.0/openfish.egg-info/requires.txt +5 -0
  8. openfish-1.0.0/openfish.egg-info/top_level.txt +1 -0
  9. openfish-1.0.0/pyproject.toml +58 -0
  10. openfish-1.0.0/setup.cfg +4 -0
  11. openfish-1.0.0/src/__init__.py +1 -0
  12. openfish-1.0.0/src/app.py +136 -0
  13. openfish-1.0.0/src/approval.py +57 -0
  14. openfish-1.0.0/src/approval_store.py +122 -0
  15. openfish-1.0.0/src/audit.py +81 -0
  16. openfish-1.0.0/src/audit_events.py +130 -0
  17. openfish-1.0.0/src/auth.py +7 -0
  18. openfish-1.0.0/src/chat_state_store.py +375 -0
  19. openfish-1.0.0/src/cli.py +1480 -0
  20. openfish-1.0.0/src/codex_runner.py +735 -0
  21. openfish-1.0.0/src/codex_session_service.py +290 -0
  22. openfish-1.0.0/src/config.py +197 -0
  23. openfish-1.0.0/src/db.py +108 -0
  24. openfish-1.0.0/src/event_consistency.py +90 -0
  25. openfish-1.0.0/src/formatters.py +674 -0
  26. openfish-1.0.0/src/github_repo_service.py +105 -0
  27. openfish-1.0.0/src/main.py +12 -0
  28. openfish-1.0.0/src/mcp_service.py +500 -0
  29. openfish-1.0.0/src/models.py +51 -0
  30. openfish-1.0.0/src/process_lock.py +73 -0
  31. openfish-1.0.0/src/progress_reporter.py +69 -0
  32. openfish-1.0.0/src/project_registry.py +188 -0
  33. openfish-1.0.0/src/project_state_store.py +384 -0
  34. openfish-1.0.0/src/redaction.py +47 -0
  35. openfish-1.0.0/src/repo_inspector.py +65 -0
  36. openfish-1.0.0/src/resources/env.example +53 -0
  37. openfish-1.0.0/src/resources/migrations/0002_chat_context.sql +12 -0
  38. openfish-1.0.0/src/resources/migrations/0003_scheduled_tasks.sql +22 -0
  39. openfish-1.0.0/src/resources/migrations/0004_chat_flows_and_recent_projects.sql +17 -0
  40. openfish-1.0.0/src/resources/migrations/0005_chat_ui_mode.sql +2 -0
  41. openfish-1.0.0/src/resources/migrations/0006_chat_delivery_state.sql +11 -0
  42. openfish-1.0.0/src/resources/migrations/0007_chat_codex_model.sql +2 -0
  43. openfish-1.0.0/src/resources/migrations/0008_system_notifications.sql +10 -0
  44. openfish-1.0.0/src/resources/schema.sql +191 -0
  45. openfish-1.0.0/src/router.py +2447 -0
  46. openfish-1.0.0/src/schedule_store.py +222 -0
  47. openfish-1.0.0/src/scheduler.py +92 -0
  48. openfish-1.0.0/src/security_guard.py +39 -0
  49. openfish-1.0.0/src/skills_service.py +206 -0
  50. openfish-1.0.0/src/system_notification_store.py +103 -0
  51. openfish-1.0.0/src/task_runtime_store.py +322 -0
  52. openfish-1.0.0/src/task_store.py +810 -0
  53. openfish-1.0.0/src/telegram_adapter.py +1829 -0
  54. openfish-1.0.0/src/telegram_messages.py +124 -0
  55. openfish-1.0.0/src/telegram_sink.py +383 -0
  56. openfish-1.0.0/src/telegram_views.py +452 -0
  57. openfish-1.0.0/src/update_service.py +174 -0
  58. openfish-1.0.0/tests/test_approval.py +33 -0
  59. openfish-1.0.0/tests/test_approval_store.py +114 -0
  60. openfish-1.0.0/tests/test_audit.py +80 -0
  61. openfish-1.0.0/tests/test_cards_snapshot.py +59 -0
  62. openfish-1.0.0/tests/test_chat_state_store.py +134 -0
  63. openfish-1.0.0/tests/test_cli.py +661 -0
  64. openfish-1.0.0/tests/test_codex_runner.py +382 -0
  65. openfish-1.0.0/tests/test_config.py +92 -0
  66. openfish-1.0.0/tests/test_db.py +61 -0
  67. openfish-1.0.0/tests/test_event_consistency.py +34 -0
  68. openfish-1.0.0/tests/test_formatters.py +307 -0
  69. openfish-1.0.0/tests/test_github_repo_service.py +43 -0
  70. openfish-1.0.0/tests/test_mcp_service.py +130 -0
  71. openfish-1.0.0/tests/test_process_lock.py +38 -0
  72. openfish-1.0.0/tests/test_progress_reporter.py +63 -0
  73. openfish-1.0.0/tests/test_project_registry.py +91 -0
  74. openfish-1.0.0/tests/test_project_state_store.py +90 -0
  75. openfish-1.0.0/tests/test_redaction.py +22 -0
  76. openfish-1.0.0/tests/test_router.py +2028 -0
  77. openfish-1.0.0/tests/test_schedule_store.py +70 -0
  78. openfish-1.0.0/tests/test_scheduler.py +90 -0
  79. openfish-1.0.0/tests/test_security_guard.py +17 -0
  80. openfish-1.0.0/tests/test_skills_service.py +53 -0
  81. openfish-1.0.0/tests/test_system_notification_store.py +45 -0
  82. openfish-1.0.0/tests/test_task_events.py +128 -0
  83. openfish-1.0.0/tests/test_task_runtime_store.py +93 -0
  84. openfish-1.0.0/tests/test_task_store_context.py +463 -0
  85. openfish-1.0.0/tests/test_task_store_schedule.py +151 -0
  86. openfish-1.0.0/tests/test_telegram_adapter.py +1742 -0
  87. openfish-1.0.0/tests/test_telegram_messages.py +13 -0
  88. openfish-1.0.0/tests/test_telegram_sink.py +261 -0
  89. openfish-1.0.0/tests/test_telegram_views.py +219 -0
  90. openfish-1.0.0/tests/test_update_service.py +156 -0
@@ -0,0 +1,115 @@
1
+ Metadata-Version: 2.4
2
+ Name: openfish
3
+ Version: 1.0.0
4
+ Summary: OpenFish: single-user Telegram-driven personal Codex assistant
5
+ Author: Re13orn
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Re13orn/openfish
8
+ Project-URL: Repository, https://github.com/Re13orn/openfish
9
+ Project-URL: Issues, https://github.com/Re13orn/openfish/issues
10
+ Project-URL: Changelog, https://github.com/Re13orn/openfish/blob/main/CHANGELOG.md
11
+ Keywords: telegram,codex,assistant,cli,self-hosted
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Communications :: Chat
19
+ Classifier: Topic :: Software Development :: Build Tools
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.12
22
+ Description-Content-Type: text/markdown
23
+ Requires-Dist: PyYAML>=6.0
24
+ Requires-Dist: python-telegram-bot>=22.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=8.0; extra == "dev"
27
+
28
+ OpenFish
29
+ ========
30
+
31
+ OpenFish is a single-user, Telegram-driven local Codex assistant.
32
+
33
+ It lets one trusted owner control local repositories from Telegram while execution, approvals, state, and audit data remain on the local machine.
34
+
35
+ Core capabilities
36
+ -----------------
37
+
38
+ - Project lifecycle: list, select, add, disable, archive
39
+ - Task lifecycle: ask, do, resume, retry, cancel
40
+ - Scheduling: periodic task add/list/run/pause/enable/delete
41
+ - Approval flow: approve/reject continuation
42
+ - Project memory: notes, recent summaries, paginated memory view
43
+ - Codex session browser: OpenFish sessions and local native sessions
44
+ - MCP management: list, inspect, enable, disable
45
+ - Service controls: restart, logs, update-check, self-update
46
+ - CLI runtime: `openfish install`, `configure`, `check`, `start`
47
+
48
+ Quick start
49
+ -----------
50
+
51
+ Install:
52
+
53
+ ```bash
54
+ pip install openfish
55
+ ```
56
+
57
+ Repository mode:
58
+
59
+ ```bash
60
+ openfish install
61
+ openfish configure
62
+ openfish check
63
+ openfish start
64
+ ```
65
+
66
+ Home runtime mode:
67
+
68
+ ```bash
69
+ openfish init-home
70
+ export OPENFISH_HOME=~/.config/openfish
71
+ openfish install
72
+ openfish configure
73
+ openfish check
74
+ openfish start
75
+ ```
76
+
77
+ Common commands
78
+ ---------------
79
+
80
+ - `openfish install`
81
+ - `openfish uninstall`
82
+ - `openfish configure`
83
+ - `openfish init-home`
84
+ - `openfish check`
85
+ - `openfish start`
86
+ - `openfish stop`
87
+ - `openfish restart`
88
+ - `openfish status`
89
+ - `openfish logs`
90
+ - `openfish update-check`
91
+
92
+ Scope
93
+ -----
94
+
95
+ OpenFish is built for:
96
+
97
+ - one trusted owner
98
+ - local-first execution
99
+ - project-scoped continuity
100
+ - Telegram as the primary control surface
101
+
102
+ OpenFish is not:
103
+
104
+ - a multi-user bot platform
105
+ - a public remote shell
106
+ - a cloud orchestration system
107
+
108
+ Links
109
+ -----
110
+
111
+ - Homepage: https://github.com/Re13orn/openfish
112
+ - README: https://github.com/Re13orn/openfish/blob/main/README.md
113
+ - 中文说明: https://github.com/Re13orn/openfish/blob/main/README_CN.md
114
+ - Security: https://github.com/Re13orn/openfish/blob/main/SECURITY.md
115
+ - Changelog: https://github.com/Re13orn/openfish/blob/main/CHANGELOG.md
@@ -0,0 +1,88 @@
1
+ OpenFish
2
+ ========
3
+
4
+ OpenFish is a single-user, Telegram-driven local Codex assistant.
5
+
6
+ It lets one trusted owner control local repositories from Telegram while execution, approvals, state, and audit data remain on the local machine.
7
+
8
+ Core capabilities
9
+ -----------------
10
+
11
+ - Project lifecycle: list, select, add, disable, archive
12
+ - Task lifecycle: ask, do, resume, retry, cancel
13
+ - Scheduling: periodic task add/list/run/pause/enable/delete
14
+ - Approval flow: approve/reject continuation
15
+ - Project memory: notes, recent summaries, paginated memory view
16
+ - Codex session browser: OpenFish sessions and local native sessions
17
+ - MCP management: list, inspect, enable, disable
18
+ - Service controls: restart, logs, update-check, self-update
19
+ - CLI runtime: `openfish install`, `configure`, `check`, `start`
20
+
21
+ Quick start
22
+ -----------
23
+
24
+ Install:
25
+
26
+ ```bash
27
+ pip install openfish
28
+ ```
29
+
30
+ Repository mode:
31
+
32
+ ```bash
33
+ openfish install
34
+ openfish configure
35
+ openfish check
36
+ openfish start
37
+ ```
38
+
39
+ Home runtime mode:
40
+
41
+ ```bash
42
+ openfish init-home
43
+ export OPENFISH_HOME=~/.config/openfish
44
+ openfish install
45
+ openfish configure
46
+ openfish check
47
+ openfish start
48
+ ```
49
+
50
+ Common commands
51
+ ---------------
52
+
53
+ - `openfish install`
54
+ - `openfish uninstall`
55
+ - `openfish configure`
56
+ - `openfish init-home`
57
+ - `openfish check`
58
+ - `openfish start`
59
+ - `openfish stop`
60
+ - `openfish restart`
61
+ - `openfish status`
62
+ - `openfish logs`
63
+ - `openfish update-check`
64
+
65
+ Scope
66
+ -----
67
+
68
+ OpenFish is built for:
69
+
70
+ - one trusted owner
71
+ - local-first execution
72
+ - project-scoped continuity
73
+ - Telegram as the primary control surface
74
+
75
+ OpenFish is not:
76
+
77
+ - a multi-user bot platform
78
+ - a public remote shell
79
+ - a cloud orchestration system
80
+
81
+ Links
82
+ -----
83
+
84
+ - Homepage: https://github.com/Re13orn/openfish
85
+ - README: https://github.com/Re13orn/openfish/blob/main/README.md
86
+ - 中文说明: https://github.com/Re13orn/openfish/blob/main/README_CN.md
87
+ - Security: https://github.com/Re13orn/openfish/blob/main/SECURITY.md
88
+ - Changelog: https://github.com/Re13orn/openfish/blob/main/CHANGELOG.md
@@ -0,0 +1,115 @@
1
+ Metadata-Version: 2.4
2
+ Name: openfish
3
+ Version: 1.0.0
4
+ Summary: OpenFish: single-user Telegram-driven personal Codex assistant
5
+ Author: Re13orn
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Re13orn/openfish
8
+ Project-URL: Repository, https://github.com/Re13orn/openfish
9
+ Project-URL: Issues, https://github.com/Re13orn/openfish/issues
10
+ Project-URL: Changelog, https://github.com/Re13orn/openfish/blob/main/CHANGELOG.md
11
+ Keywords: telegram,codex,assistant,cli,self-hosted
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Communications :: Chat
19
+ Classifier: Topic :: Software Development :: Build Tools
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.12
22
+ Description-Content-Type: text/markdown
23
+ Requires-Dist: PyYAML>=6.0
24
+ Requires-Dist: python-telegram-bot>=22.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=8.0; extra == "dev"
27
+
28
+ OpenFish
29
+ ========
30
+
31
+ OpenFish is a single-user, Telegram-driven local Codex assistant.
32
+
33
+ It lets one trusted owner control local repositories from Telegram while execution, approvals, state, and audit data remain on the local machine.
34
+
35
+ Core capabilities
36
+ -----------------
37
+
38
+ - Project lifecycle: list, select, add, disable, archive
39
+ - Task lifecycle: ask, do, resume, retry, cancel
40
+ - Scheduling: periodic task add/list/run/pause/enable/delete
41
+ - Approval flow: approve/reject continuation
42
+ - Project memory: notes, recent summaries, paginated memory view
43
+ - Codex session browser: OpenFish sessions and local native sessions
44
+ - MCP management: list, inspect, enable, disable
45
+ - Service controls: restart, logs, update-check, self-update
46
+ - CLI runtime: `openfish install`, `configure`, `check`, `start`
47
+
48
+ Quick start
49
+ -----------
50
+
51
+ Install:
52
+
53
+ ```bash
54
+ pip install openfish
55
+ ```
56
+
57
+ Repository mode:
58
+
59
+ ```bash
60
+ openfish install
61
+ openfish configure
62
+ openfish check
63
+ openfish start
64
+ ```
65
+
66
+ Home runtime mode:
67
+
68
+ ```bash
69
+ openfish init-home
70
+ export OPENFISH_HOME=~/.config/openfish
71
+ openfish install
72
+ openfish configure
73
+ openfish check
74
+ openfish start
75
+ ```
76
+
77
+ Common commands
78
+ ---------------
79
+
80
+ - `openfish install`
81
+ - `openfish uninstall`
82
+ - `openfish configure`
83
+ - `openfish init-home`
84
+ - `openfish check`
85
+ - `openfish start`
86
+ - `openfish stop`
87
+ - `openfish restart`
88
+ - `openfish status`
89
+ - `openfish logs`
90
+ - `openfish update-check`
91
+
92
+ Scope
93
+ -----
94
+
95
+ OpenFish is built for:
96
+
97
+ - one trusted owner
98
+ - local-first execution
99
+ - project-scoped continuity
100
+ - Telegram as the primary control surface
101
+
102
+ OpenFish is not:
103
+
104
+ - a multi-user bot platform
105
+ - a public remote shell
106
+ - a cloud orchestration system
107
+
108
+ Links
109
+ -----
110
+
111
+ - Homepage: https://github.com/Re13orn/openfish
112
+ - README: https://github.com/Re13orn/openfish/blob/main/README.md
113
+ - 中文说明: https://github.com/Re13orn/openfish/blob/main/README_CN.md
114
+ - Security: https://github.com/Re13orn/openfish/blob/main/SECURITY.md
115
+ - Changelog: https://github.com/Re13orn/openfish/blob/main/CHANGELOG.md
@@ -0,0 +1,88 @@
1
+ README_PYPI.md
2
+ pyproject.toml
3
+ openfish.egg-info/PKG-INFO
4
+ openfish.egg-info/SOURCES.txt
5
+ openfish.egg-info/dependency_links.txt
6
+ openfish.egg-info/entry_points.txt
7
+ openfish.egg-info/requires.txt
8
+ openfish.egg-info/top_level.txt
9
+ src/__init__.py
10
+ src/app.py
11
+ src/approval.py
12
+ src/approval_store.py
13
+ src/audit.py
14
+ src/audit_events.py
15
+ src/auth.py
16
+ src/chat_state_store.py
17
+ src/cli.py
18
+ src/codex_runner.py
19
+ src/codex_session_service.py
20
+ src/config.py
21
+ src/db.py
22
+ src/event_consistency.py
23
+ src/formatters.py
24
+ src/github_repo_service.py
25
+ src/main.py
26
+ src/mcp_service.py
27
+ src/models.py
28
+ src/process_lock.py
29
+ src/progress_reporter.py
30
+ src/project_registry.py
31
+ src/project_state_store.py
32
+ src/redaction.py
33
+ src/repo_inspector.py
34
+ src/router.py
35
+ src/schedule_store.py
36
+ src/scheduler.py
37
+ src/security_guard.py
38
+ src/skills_service.py
39
+ src/system_notification_store.py
40
+ src/task_runtime_store.py
41
+ src/task_store.py
42
+ src/telegram_adapter.py
43
+ src/telegram_messages.py
44
+ src/telegram_sink.py
45
+ src/telegram_views.py
46
+ src/update_service.py
47
+ src/resources/env.example
48
+ src/resources/schema.sql
49
+ src/resources/migrations/0002_chat_context.sql
50
+ src/resources/migrations/0003_scheduled_tasks.sql
51
+ src/resources/migrations/0004_chat_flows_and_recent_projects.sql
52
+ src/resources/migrations/0005_chat_ui_mode.sql
53
+ src/resources/migrations/0006_chat_delivery_state.sql
54
+ src/resources/migrations/0007_chat_codex_model.sql
55
+ src/resources/migrations/0008_system_notifications.sql
56
+ tests/test_approval.py
57
+ tests/test_approval_store.py
58
+ tests/test_audit.py
59
+ tests/test_cards_snapshot.py
60
+ tests/test_chat_state_store.py
61
+ tests/test_cli.py
62
+ tests/test_codex_runner.py
63
+ tests/test_config.py
64
+ tests/test_db.py
65
+ tests/test_event_consistency.py
66
+ tests/test_formatters.py
67
+ tests/test_github_repo_service.py
68
+ tests/test_mcp_service.py
69
+ tests/test_process_lock.py
70
+ tests/test_progress_reporter.py
71
+ tests/test_project_registry.py
72
+ tests/test_project_state_store.py
73
+ tests/test_redaction.py
74
+ tests/test_router.py
75
+ tests/test_schedule_store.py
76
+ tests/test_scheduler.py
77
+ tests/test_security_guard.py
78
+ tests/test_skills_service.py
79
+ tests/test_system_notification_store.py
80
+ tests/test_task_events.py
81
+ tests/test_task_runtime_store.py
82
+ tests/test_task_store_context.py
83
+ tests/test_task_store_schedule.py
84
+ tests/test_telegram_adapter.py
85
+ tests/test_telegram_messages.py
86
+ tests/test_telegram_sink.py
87
+ tests/test_telegram_views.py
88
+ tests/test_update_service.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ openfish = src.cli:main
@@ -0,0 +1,5 @@
1
+ PyYAML>=6.0
2
+ python-telegram-bot>=22.0
3
+
4
+ [dev]
5
+ pytest>=8.0
@@ -0,0 +1 @@
1
+ src
@@ -0,0 +1,58 @@
1
+ [build-system]
2
+ requires = ["setuptools>=69", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "openfish"
7
+ version = "1.0.0"
8
+ description = "OpenFish: single-user Telegram-driven personal Codex assistant"
9
+ readme = "README_PYPI.md"
10
+ requires-python = ">=3.12"
11
+ license = "MIT"
12
+ authors = [
13
+ { name = "Re13orn" },
14
+ ]
15
+ keywords = ["telegram", "codex", "assistant", "cli", "self-hosted"]
16
+ classifiers = [
17
+ "Development Status :: 5 - Production/Stable",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Topic :: Communications :: Chat",
24
+ "Topic :: Software Development :: Build Tools",
25
+ "Topic :: Software Development :: Libraries :: Python Modules",
26
+ ]
27
+ dependencies = [
28
+ "PyYAML>=6.0",
29
+ "python-telegram-bot>=22.0",
30
+ ]
31
+
32
+ [project.urls]
33
+ Homepage = "https://github.com/Re13orn/openfish"
34
+ Repository = "https://github.com/Re13orn/openfish"
35
+ Issues = "https://github.com/Re13orn/openfish/issues"
36
+ Changelog = "https://github.com/Re13orn/openfish/blob/main/CHANGELOG.md"
37
+
38
+ [project.scripts]
39
+ openfish = "src.cli:main"
40
+
41
+ [project.optional-dependencies]
42
+ dev = [
43
+ "pytest>=8.0",
44
+ ]
45
+
46
+ [tool.setuptools]
47
+ packages = ["src"]
48
+ include-package-data = true
49
+
50
+ [tool.setuptools.package-data]
51
+ src = [
52
+ "resources/schema.sql",
53
+ "resources/env.example",
54
+ "resources/migrations/*.sql",
55
+ ]
56
+
57
+ [tool.pytest.ini_options]
58
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ """OpenFish assistant package."""
@@ -0,0 +1,136 @@
1
+ """Application composition root."""
2
+
3
+ import logging
4
+ from pathlib import Path
5
+
6
+ from src.audit import AuditLogger
7
+ from src.approval import ApprovalService
8
+ from src.codex_runner import CodexRunner
9
+ from src.codex_session_service import CodexSessionService
10
+ from src.config import AppConfig, load_config
11
+ from src.db import Database
12
+ from src.github_repo_service import GitHubRepoService
13
+ from src.project_registry import ProjectRegistry
14
+ from src.process_lock import ProcessLock, acquire_process_lock
15
+ from src.repo_inspector import RepoInspector
16
+ from src.router import CommandRouter
17
+ from src.scheduler import ScheduledTaskService
18
+ from src.skills_service import SkillsService
19
+ from src.mcp_service import McpService
20
+ from src.task_store import TaskStore
21
+ from src.telegram_adapter import TelegramBotService
22
+ from src.update_service import UpdateService
23
+
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ class Application:
29
+ """Build and run the single-process assistant service."""
30
+
31
+ def __init__(self, config: AppConfig) -> None:
32
+ self.config = config
33
+ self.process_lock: ProcessLock | None = None
34
+ self.db = Database(config.sqlite_path, config.schema_path, config.migrations_dir)
35
+ self.projects = ProjectRegistry(config.projects_config_path)
36
+ self.tasks = TaskStore(self.db)
37
+ self.audit = AuditLogger(self.db)
38
+ self.approvals = ApprovalService()
39
+ self.codex = CodexRunner(config)
40
+ self.codex_sessions = CodexSessionService(db=self.db, codex_home=config.codex_home)
41
+ self.skills = SkillsService(
42
+ codex_bin=config.codex_bin,
43
+ skills_root=config.codex_home / "skills",
44
+ enable_install=config.enable_skill_install,
45
+ timeout_seconds=config.skill_install_timeout_seconds,
46
+ )
47
+ self.mcp = McpService(
48
+ codex_bin=config.codex_bin,
49
+ timeout_seconds=config.codex_command_timeout_seconds,
50
+ config_path=config.codex_home / "config.toml",
51
+ )
52
+ self.updates = UpdateService(
53
+ repo_root=Path(__file__).resolve().parents[2],
54
+ script_path=Path(__file__).resolve().parents[1] / "scripts" / "install_start.sh",
55
+ )
56
+ self.github_repos = GitHubRepoService()
57
+ self.repo = RepoInspector()
58
+ self.router = CommandRouter(
59
+ config=config,
60
+ projects=self.projects,
61
+ tasks=self.tasks,
62
+ audit=self.audit,
63
+ codex=self.codex,
64
+ repo=self.repo,
65
+ approvals=self.approvals,
66
+ skills_service=self.skills,
67
+ mcp_service=self.mcp,
68
+ update_service=self.updates,
69
+ codex_sessions=self.codex_sessions,
70
+ github_repos=self.github_repos,
71
+ )
72
+ self.scheduler = ScheduledTaskService(
73
+ tasks=self.tasks,
74
+ router=self.router,
75
+ poll_interval_seconds=self.config.schedule_poll_interval_seconds,
76
+ enabled=self.config.enable_scheduler,
77
+ missed_run_policy=self.config.schedule_missed_run_policy,
78
+ )
79
+ self.bot = TelegramBotService(config=config, router=self.router)
80
+
81
+ def run(self) -> None:
82
+ self._configure_logging()
83
+ self.process_lock = acquire_process_lock(self.config.process_lock_path)
84
+ logger.info("Acquired process lock: %s", self.config.process_lock_path)
85
+ self.projects.load()
86
+ self._run_startup_health_checks()
87
+ self.db.connect()
88
+ self.db.initialize_schema()
89
+ self.tasks.sync_projects_from_registry(self.projects)
90
+ recovered_task_ids = self.tasks.recover_interrupted_tasks()
91
+ if recovered_task_ids:
92
+ logger.warning(
93
+ "Recovered %d interrupted task(s) on startup: %s",
94
+ len(recovered_task_ids),
95
+ ", ".join(str(task_id) for task_id in recovered_task_ids),
96
+ )
97
+ self.scheduler.start()
98
+ try:
99
+ self.bot.run_polling()
100
+ finally:
101
+ self.scheduler.stop()
102
+ self.db.close_all()
103
+ if self.process_lock is not None:
104
+ self.process_lock.release()
105
+ self.process_lock = None
106
+
107
+ def _configure_logging(self) -> None:
108
+ logging.basicConfig(
109
+ level=getattr(logging, self.config.log_level.upper(), logging.INFO),
110
+ format="%(asctime)s %(levelname)s %(name)s: %(message)s",
111
+ )
112
+
113
+ def _run_startup_health_checks(self) -> None:
114
+ if not self.projects.projects:
115
+ logger.warning(
116
+ "Project registry is empty. Service will start, but you should add a project via /project-add."
117
+ )
118
+ return
119
+
120
+ for key, project in self.projects.projects.items():
121
+ if not project.is_active:
122
+ continue
123
+ if not self.projects.is_path_allowed(project, project.path):
124
+ raise ValueError(
125
+ f"Project '{key}' path is not in allowed_directories: {project.path}"
126
+ )
127
+ project_path = Path(project.path)
128
+ if not project_path.exists():
129
+ logger.warning("Project path does not exist for key=%s path=%s", key, project_path)
130
+
131
+
132
+ def create_app() -> Application:
133
+ """Factory used by CLI entry points and tests."""
134
+
135
+ config = load_config()
136
+ return Application(config)
@@ -0,0 +1,57 @@
1
+ """Approval policy helpers for Phase 3 workflow."""
2
+
3
+ from dataclasses import dataclass
4
+ import re
5
+
6
+ from src.codex_runner import CodexRunResult
7
+
8
+
9
+ APPROVAL_PATTERNS = [
10
+ re.compile(r"\bneeds?\s+approval\b", re.IGNORECASE),
11
+ re.compile(r"\bwaiting\s+for\s+approval\b", re.IGNORECASE),
12
+ re.compile(r"\brequires?\s+approval\b", re.IGNORECASE),
13
+ re.compile(r"\bapprove\b", re.IGNORECASE),
14
+ re.compile(r"等待审批"),
15
+ re.compile(r"需要审批"),
16
+ re.compile(r"请批准"),
17
+ ]
18
+
19
+
20
+ @dataclass(slots=True)
21
+ class ApprovalAssessment:
22
+ requires_approval: bool
23
+ reason: str | None
24
+
25
+
26
+ class ApprovalService:
27
+ """Detects approval pauses from Codex output and builds follow-up instructions."""
28
+
29
+ def assess(self, result: CodexRunResult) -> ApprovalAssessment:
30
+ text_parts = [result.summary or "", result.stderr or "", result.stdout or ""]
31
+ combined = "\n".join(part for part in text_parts if part).strip()
32
+ if not combined:
33
+ return ApprovalAssessment(requires_approval=False, reason=None)
34
+
35
+ for pattern in APPROVAL_PATTERNS:
36
+ if pattern.search(combined):
37
+ reason = self._extract_reason(combined)
38
+ return ApprovalAssessment(requires_approval=True, reason=reason)
39
+ return ApprovalAssessment(requires_approval=False, reason=None)
40
+
41
+ def build_resume_instruction(self, requested_action: str, user_note: str | None = None) -> str:
42
+ base = (
43
+ "Approval granted. Continue the previously blocked task with conservative changes and concise summary. "
44
+ f"Approved action context: {requested_action}"
45
+ )
46
+ if user_note:
47
+ return f"{base}\nUser note: {user_note}"
48
+ return base
49
+
50
+ def _extract_reason(self, text: str, max_len: int = 240) -> str:
51
+ for line in text.splitlines():
52
+ candidate = line.strip()
53
+ if not candidate:
54
+ continue
55
+ if any(p.search(candidate) for p in APPROVAL_PATTERNS):
56
+ return candidate[:max_len]
57
+ return text[:max_len]