@agentikos/omega-os 0.2.0 → 0.19.6

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 (376) hide show
  1. package/README.md +33 -3
  2. package/bootstrap/lib/__pycache__/claude-code-settings.cpython-313.pyc +0 -0
  3. package/bootstrap/lib/__pycache__/llm-clis.cpython-313.pyc +0 -0
  4. package/bootstrap/lib/__pycache__/manifest-helpers.cpython-313.pyc +0 -0
  5. package/bootstrap/lib/claude-code-settings.py +176 -0
  6. package/bootstrap/lib/common.sh +457 -1
  7. package/bootstrap/lib/llm-clis.py +341 -0
  8. package/bootstrap/lib/manifest-helpers.py +384 -0
  9. package/bootstrap/lib/steps.sh +790 -21
  10. package/bootstrap/manifest.example.yaml +87 -1
  11. package/bootstrap/templates/aisb/CLAUDE.md +305 -0
  12. package/bootstrap/templates/aisb/architect.md +204 -0
  13. package/bootstrap/templates/aisb/checkers/CLAUDE.md +9 -0
  14. package/bootstrap/templates/aisb/checkers/checker-architect.md +151 -0
  15. package/bootstrap/templates/aisb/checkers/checker-common.md +171 -0
  16. package/bootstrap/templates/aisb/checkers/checker-construct.md +129 -0
  17. package/bootstrap/templates/aisb/checkers/checker-keymaker.md +204 -0
  18. package/bootstrap/templates/aisb/checkers/checker-link.md +205 -0
  19. package/bootstrap/templates/aisb/checkers/checker-merovingian.md +219 -0
  20. package/bootstrap/templates/aisb/checkers/checker-morpheus.md +211 -0
  21. package/bootstrap/templates/aisb/checkers/checker-neo.md +177 -0
  22. package/bootstrap/templates/aisb/checkers/checker-niobe.md +156 -0
  23. package/bootstrap/templates/aisb/checkers/checker-oracle.md +164 -0
  24. package/bootstrap/templates/aisb/checkers/checker-seraph.md +187 -0
  25. package/bootstrap/templates/aisb/checkers/checker-smith.md +195 -0
  26. package/bootstrap/templates/aisb/checkers/checker-zion.md +113 -0
  27. package/bootstrap/templates/aisb/construct.md +135 -0
  28. package/bootstrap/templates/aisb/keymaker.md +227 -0
  29. package/bootstrap/templates/aisb/link.md +170 -0
  30. package/bootstrap/templates/aisb/lmc-protocol.md +57 -0
  31. package/bootstrap/templates/aisb/merovingian.md +159 -0
  32. package/bootstrap/templates/aisb/morpheus.md +243 -0
  33. package/bootstrap/templates/aisb/neo.md +147 -0
  34. package/bootstrap/templates/aisb/niobe.md +197 -0
  35. package/bootstrap/templates/aisb/oracle.md +244 -0
  36. package/bootstrap/templates/aisb/protocols/handoff-templates.md +204 -0
  37. package/bootstrap/templates/aisb/protocols/shared-protocol.md +248 -0
  38. package/bootstrap/templates/aisb/pythia.md +153 -0
  39. package/bootstrap/templates/aisb/seraph.md +315 -0
  40. package/bootstrap/templates/aisb/smith.md +202 -0
  41. package/bootstrap/templates/aisb/zion.md +172 -0
  42. package/bootstrap/templates/autonomous/audit-patrol.yaml +41 -0
  43. package/bootstrap/templates/autonomous/smith-reflect.yaml +43 -0
  44. package/bootstrap/templates/autonomous/ssh-key-rotate.yaml +46 -0
  45. package/bootstrap/templates/autonomous/support-agent.yaml +38 -0
  46. package/docs/AUDITS.md +85 -0
  47. package/docs/GAP-ANALYSIS.md +214 -0
  48. package/docs/INSTALL.md +47 -9
  49. package/docs/MCP-AND-PLUGINS.md +31 -4
  50. package/docs/SIMULATION.md +171 -0
  51. package/docs/simulate.sh +211 -0
  52. package/install.sh +164 -17
  53. package/omega/Agentik_Engine/README.md +4 -2
  54. package/omega/Agentik_Engine/omega_engine/__init__.py +147 -1
  55. package/omega/Agentik_Engine/omega_engine/__pycache__/__init__.cpython-313.pyc +0 -0
  56. package/omega/Agentik_Engine/omega_engine/__pycache__/account.cpython-313.pyc +0 -0
  57. package/omega/Agentik_Engine/omega_engine/__pycache__/agent_messages.cpython-313.pyc +0 -0
  58. package/omega/Agentik_Engine/omega_engine/__pycache__/aisb_chat.cpython-313.pyc +0 -0
  59. package/omega/Agentik_Engine/omega_engine/__pycache__/audit.cpython-313.pyc +0 -0
  60. package/omega/Agentik_Engine/omega_engine/__pycache__/audit_arsenal.cpython-313.pyc +0 -0
  61. package/omega/Agentik_Engine/omega_engine/__pycache__/audit_diff.cpython-313.pyc +0 -0
  62. package/omega/Agentik_Engine/omega_engine/__pycache__/audit_gate.cpython-313.pyc +0 -0
  63. package/omega/Agentik_Engine/omega_engine/__pycache__/auto_update.cpython-313.pyc +0 -0
  64. package/omega/Agentik_Engine/omega_engine/__pycache__/autonomous.cpython-313.pyc +0 -0
  65. package/omega/Agentik_Engine/omega_engine/__pycache__/backup.cpython-313.pyc +0 -0
  66. package/omega/Agentik_Engine/omega_engine/__pycache__/barrier.cpython-313.pyc +0 -0
  67. package/omega/Agentik_Engine/omega_engine/__pycache__/bus.cpython-313.pyc +0 -0
  68. package/omega/Agentik_Engine/omega_engine/__pycache__/cadence.cpython-313.pyc +0 -0
  69. package/omega/Agentik_Engine/omega_engine/__pycache__/classifier.cpython-313.pyc +0 -0
  70. package/omega/Agentik_Engine/omega_engine/__pycache__/cleanup.cpython-313.pyc +0 -0
  71. package/omega/Agentik_Engine/omega_engine/__pycache__/cli.cpython-313.pyc +0 -0
  72. package/omega/Agentik_Engine/omega_engine/__pycache__/completions.cpython-313.pyc +0 -0
  73. package/omega/Agentik_Engine/omega_engine/__pycache__/costs.cpython-313.pyc +0 -0
  74. package/omega/Agentik_Engine/omega_engine/__pycache__/done_signal.cpython-313.pyc +0 -0
  75. package/omega/Agentik_Engine/omega_engine/__pycache__/envelope.cpython-313.pyc +0 -0
  76. package/omega/Agentik_Engine/omega_engine/__pycache__/events.cpython-313.pyc +0 -0
  77. package/omega/Agentik_Engine/omega_engine/__pycache__/executor.cpython-313.pyc +0 -0
  78. package/omega/Agentik_Engine/omega_engine/__pycache__/handoff.cpython-313.pyc +0 -0
  79. package/omega/Agentik_Engine/omega_engine/__pycache__/hermes.cpython-313.pyc +0 -0
  80. package/omega/Agentik_Engine/omega_engine/__pycache__/hermes_bootstrap.cpython-313.pyc +0 -0
  81. package/omega/Agentik_Engine/omega_engine/__pycache__/hermes_desktop.cpython-313.pyc +0 -0
  82. package/omega/Agentik_Engine/omega_engine/__pycache__/learning.cpython-313.pyc +0 -0
  83. package/omega/Agentik_Engine/omega_engine/__pycache__/managed_agent.cpython-313.pyc +0 -0
  84. package/omega/Agentik_Engine/omega_engine/__pycache__/memory.cpython-313.pyc +0 -0
  85. package/omega/Agentik_Engine/omega_engine/__pycache__/menu.cpython-313.pyc +0 -0
  86. package/omega/Agentik_Engine/omega_engine/__pycache__/mission.cpython-313.pyc +0 -0
  87. package/omega/Agentik_Engine/omega_engine/__pycache__/plan.cpython-313.pyc +0 -0
  88. package/omega/Agentik_Engine/omega_engine/__pycache__/progress.cpython-313.pyc +0 -0
  89. package/omega/Agentik_Engine/omega_engine/__pycache__/project.cpython-313.pyc +0 -0
  90. package/omega/Agentik_Engine/omega_engine/__pycache__/prompts.cpython-313.pyc +0 -0
  91. package/omega/Agentik_Engine/omega_engine/__pycache__/provider.cpython-313.pyc +0 -0
  92. package/omega/Agentik_Engine/omega_engine/__pycache__/prune.cpython-313.pyc +0 -0
  93. package/omega/Agentik_Engine/omega_engine/__pycache__/pursue.cpython-313.pyc +0 -0
  94. package/omega/Agentik_Engine/omega_engine/__pycache__/reducer.cpython-313.pyc +0 -0
  95. package/omega/Agentik_Engine/omega_engine/__pycache__/report.cpython-313.pyc +0 -0
  96. package/omega/Agentik_Engine/omega_engine/__pycache__/router.cpython-313.pyc +0 -0
  97. package/omega/Agentik_Engine/omega_engine/__pycache__/skill_routing.cpython-313.pyc +0 -0
  98. package/omega/Agentik_Engine/omega_engine/__pycache__/smoke.cpython-313.pyc +0 -0
  99. package/omega/Agentik_Engine/omega_engine/__pycache__/store.cpython-313.pyc +0 -0
  100. package/omega/Agentik_Engine/omega_engine/__pycache__/supervisor.cpython-313.pyc +0 -0
  101. package/omega/Agentik_Engine/omega_engine/__pycache__/sync.cpython-313.pyc +0 -0
  102. package/omega/Agentik_Engine/omega_engine/__pycache__/task.cpython-313.pyc +0 -0
  103. package/omega/Agentik_Engine/omega_engine/__pycache__/telegram.cpython-313.pyc +0 -0
  104. package/omega/Agentik_Engine/omega_engine/__pycache__/telegram_history.cpython-313.pyc +0 -0
  105. package/omega/Agentik_Engine/omega_engine/__pycache__/tmux.cpython-313.pyc +0 -0
  106. package/omega/Agentik_Engine/omega_engine/__pycache__/tools.cpython-313.pyc +0 -0
  107. package/omega/Agentik_Engine/omega_engine/__pycache__/understand_anything.cpython-313.pyc +0 -0
  108. package/omega/Agentik_Engine/omega_engine/__pycache__/updater.cpython-313.pyc +0 -0
  109. package/omega/Agentik_Engine/omega_engine/__pycache__/validate.cpython-313.pyc +0 -0
  110. package/omega/Agentik_Engine/omega_engine/__pycache__/vault.cpython-313.pyc +0 -0
  111. package/omega/Agentik_Engine/omega_engine/__pycache__/webhooks.cpython-313.pyc +0 -0
  112. package/omega/Agentik_Engine/omega_engine/__pycache__/worker.cpython-313.pyc +0 -0
  113. package/omega/Agentik_Engine/omega_engine/account.py +28 -31
  114. package/omega/Agentik_Engine/omega_engine/agent_messages.py +167 -0
  115. package/omega/Agentik_Engine/omega_engine/aisb_chat.py +128 -0
  116. package/omega/Agentik_Engine/omega_engine/audit_diff.py +99 -0
  117. package/omega/Agentik_Engine/omega_engine/audit_gate.py +149 -0
  118. package/omega/Agentik_Engine/omega_engine/audits/__init__.py +60 -0
  119. package/omega/Agentik_Engine/omega_engine/audits/__pycache__/__init__.cpython-313.pyc +0 -0
  120. package/omega/Agentik_Engine/omega_engine/audits/__pycache__/batcher.cpython-313.pyc +0 -0
  121. package/omega/Agentik_Engine/omega_engine/audits/__pycache__/dispatcher.cpython-313.pyc +0 -0
  122. package/omega/Agentik_Engine/omega_engine/audits/__pycache__/generator.cpython-313.pyc +0 -0
  123. package/omega/Agentik_Engine/omega_engine/audits/__pycache__/history.cpython-313.pyc +0 -0
  124. package/omega/Agentik_Engine/omega_engine/audits/__pycache__/pipeline.cpython-313.pyc +0 -0
  125. package/omega/Agentik_Engine/omega_engine/audits/batcher.py +218 -0
  126. package/omega/Agentik_Engine/omega_engine/audits/dispatcher.py +92 -0
  127. package/omega/Agentik_Engine/omega_engine/audits/generator.py +234 -0
  128. package/omega/Agentik_Engine/omega_engine/audits/history.py +168 -0
  129. package/omega/Agentik_Engine/omega_engine/audits/pipeline.py +198 -0
  130. package/omega/Agentik_Engine/omega_engine/auto_update.py +339 -0
  131. package/omega/Agentik_Engine/omega_engine/backup.py +215 -0
  132. package/omega/Agentik_Engine/omega_engine/cadence.py +158 -0
  133. package/omega/Agentik_Engine/omega_engine/classifier.py +215 -0
  134. package/omega/Agentik_Engine/omega_engine/cleanup.py +673 -0
  135. package/omega/Agentik_Engine/omega_engine/cli.py +4156 -86
  136. package/omega/Agentik_Engine/omega_engine/completions.py +260 -0
  137. package/omega/Agentik_Engine/omega_engine/costs.py +100 -0
  138. package/omega/Agentik_Engine/omega_engine/daemons/__pycache__/__init__.cpython-313.pyc +0 -0
  139. package/omega/Agentik_Engine/omega_engine/daemons/__pycache__/autonomous.cpython-313.pyc +0 -0
  140. package/omega/Agentik_Engine/omega_engine/daemons/__pycache__/engine.cpython-313.pyc +0 -0
  141. package/omega/Agentik_Engine/omega_engine/daemons/__pycache__/telegram.cpython-313.pyc +0 -0
  142. package/omega/Agentik_Engine/omega_engine/daemons/engine.py +53 -4
  143. package/omega/Agentik_Engine/omega_engine/daemons/telegram.py +101 -17
  144. package/omega/Agentik_Engine/omega_engine/done_signal.py +154 -0
  145. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/__init__.cpython-313.pyc +0 -0
  146. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/artifact.cpython-313.pyc +0 -0
  147. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/automation.cpython-313.pyc +0 -0
  148. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/base.cpython-313.pyc +0 -0
  149. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/claudecode.cpython-313.pyc +0 -0
  150. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/connection.cpython-313.pyc +0 -0
  151. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/coworker.cpython-313.pyc +0 -0
  152. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/loop.cpython-313.pyc +0 -0
  153. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/prompt.cpython-313.pyc +0 -0
  154. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/skill.cpython-313.pyc +0 -0
  155. package/omega/Agentik_Engine/omega_engine/envelope.py +219 -0
  156. package/omega/Agentik_Engine/omega_engine/executor.py +149 -10
  157. package/omega/Agentik_Engine/omega_engine/genesis/__init__.py +134 -0
  158. package/omega/Agentik_Engine/omega_engine/genesis/__pycache__/__init__.cpython-313.pyc +0 -0
  159. package/omega/Agentik_Engine/omega_engine/genesis/__pycache__/orchestrator.cpython-313.pyc +0 -0
  160. package/omega/Agentik_Engine/omega_engine/genesis/__pycache__/phases.cpython-313.pyc +0 -0
  161. package/omega/Agentik_Engine/omega_engine/genesis/__pycache__/stack.cpython-313.pyc +0 -0
  162. package/omega/Agentik_Engine/omega_engine/genesis/__pycache__/state.cpython-313.pyc +0 -0
  163. package/omega/Agentik_Engine/omega_engine/genesis/orchestrator.py +262 -0
  164. package/omega/Agentik_Engine/omega_engine/genesis/phases.py +950 -0
  165. package/omega/Agentik_Engine/omega_engine/genesis/stack.py +324 -0
  166. package/omega/Agentik_Engine/omega_engine/genesis/state.py +353 -0
  167. package/omega/Agentik_Engine/omega_engine/handoff.py +459 -0
  168. package/omega/Agentik_Engine/omega_engine/hermes.py +426 -0
  169. package/omega/Agentik_Engine/omega_engine/hermes_bootstrap.py +382 -0
  170. package/omega/Agentik_Engine/omega_engine/hermes_desktop.py +469 -0
  171. package/omega/Agentik_Engine/omega_engine/integrations/__init__.py +30 -0
  172. package/omega/Agentik_Engine/omega_engine/integrations/__pycache__/__init__.cpython-313.pyc +0 -0
  173. package/omega/Agentik_Engine/omega_engine/integrations/__pycache__/graphify.cpython-313.pyc +0 -0
  174. package/omega/Agentik_Engine/omega_engine/integrations/graphify.py +234 -0
  175. package/omega/Agentik_Engine/omega_engine/learning.py +268 -0
  176. package/omega/Agentik_Engine/omega_engine/managed_agent.py +467 -0
  177. package/omega/Agentik_Engine/omega_engine/memory.py +271 -0
  178. package/omega/Agentik_Engine/omega_engine/menu.py +1065 -0
  179. package/omega/Agentik_Engine/omega_engine/migrations/__init__.py +144 -0
  180. package/omega/Agentik_Engine/omega_engine/migrations/__pycache__/__init__.cpython-313.pyc +0 -0
  181. package/omega/Agentik_Engine/omega_engine/migrations/__pycache__/v0_14_0.cpython-313.pyc +0 -0
  182. package/omega/Agentik_Engine/omega_engine/migrations/v0_14_0.py +29 -0
  183. package/omega/Agentik_Engine/omega_engine/mission.py +16 -13
  184. package/omega/Agentik_Engine/omega_engine/plan.py +846 -0
  185. package/omega/Agentik_Engine/omega_engine/prompts.py +158 -0
  186. package/omega/Agentik_Engine/omega_engine/provider.py +161 -12
  187. package/omega/Agentik_Engine/omega_engine/prune.py +151 -0
  188. package/omega/Agentik_Engine/omega_engine/pursue.py +205 -0
  189. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/__init__.cpython-313.pyc +0 -0
  190. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/agentic.cpython-313.pyc +0 -0
  191. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/base.cpython-313.pyc +0 -0
  192. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/corrective.cpython-313.pyc +0 -0
  193. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/graph.cpython-313.pyc +0 -0
  194. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/hybrid.cpython-313.pyc +0 -0
  195. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/multimodal.cpython-313.pyc +0 -0
  196. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/router.cpython-313.pyc +0 -0
  197. package/omega/Agentik_Engine/omega_engine/router.py +28 -0
  198. package/omega/Agentik_Engine/omega_engine/skill_discovery/__init__.py +48 -0
  199. package/omega/Agentik_Engine/omega_engine/skill_discovery/__pycache__/__init__.cpython-313.pyc +0 -0
  200. package/omega/Agentik_Engine/omega_engine/skill_discovery/__pycache__/auditor.cpython-313.pyc +0 -0
  201. package/omega/Agentik_Engine/omega_engine/skill_discovery/__pycache__/finder.cpython-313.pyc +0 -0
  202. package/omega/Agentik_Engine/omega_engine/skill_discovery/__pycache__/installer.cpython-313.pyc +0 -0
  203. package/omega/Agentik_Engine/omega_engine/skill_discovery/__pycache__/marketplaces.cpython-313.pyc +0 -0
  204. package/omega/Agentik_Engine/omega_engine/skill_discovery/auditor.py +232 -0
  205. package/omega/Agentik_Engine/omega_engine/skill_discovery/finder.py +94 -0
  206. package/omega/Agentik_Engine/omega_engine/skill_discovery/installer.py +129 -0
  207. package/omega/Agentik_Engine/omega_engine/skill_discovery/marketplaces.py +80 -0
  208. package/omega/Agentik_Engine/omega_engine/skill_routing.py +388 -0
  209. package/omega/Agentik_Engine/omega_engine/smoke.py +81 -0
  210. package/omega/Agentik_Engine/omega_engine/store.py +88 -41
  211. package/omega/Agentik_Engine/omega_engine/sync.py +142 -1
  212. package/omega/Agentik_Engine/omega_engine/telegram_history.py +260 -0
  213. package/omega/Agentik_Engine/omega_engine/tmux.py +526 -0
  214. package/omega/Agentik_Engine/omega_engine/understand_anything.py +275 -0
  215. package/omega/Agentik_Engine/omega_engine/updater.py +70 -0
  216. package/omega/Agentik_Engine/omega_engine/validate.py +186 -0
  217. package/omega/Agentik_Engine/omega_engine/vault.py +342 -0
  218. package/omega/Agentik_Engine/omega_engine/webhooks.py +262 -0
  219. package/omega/Agentik_Engine/omega_engine/worker.py +526 -0
  220. package/omega/Agentik_Engine/pyproject.toml +1 -1
  221. package/omega/Agentik_Engine/tests/__pycache__/test_account.cpython-313-pytest-8.4.2.pyc +0 -0
  222. package/omega/Agentik_Engine/tests/__pycache__/test_account.cpython-313.pyc +0 -0
  223. package/omega/Agentik_Engine/tests/__pycache__/test_adversarial.cpython-313-pytest-8.4.2.pyc +0 -0
  224. package/omega/Agentik_Engine/tests/__pycache__/test_adversarial.cpython-313.pyc +0 -0
  225. package/omega/Agentik_Engine/tests/__pycache__/test_agents_envelope.cpython-313-pytest-8.4.2.pyc +0 -0
  226. package/omega/Agentik_Engine/tests/__pycache__/test_agents_envelope.cpython-313.pyc +0 -0
  227. package/omega/Agentik_Engine/tests/__pycache__/test_audit_arsenal.cpython-313-pytest-8.4.2.pyc +0 -0
  228. package/omega/Agentik_Engine/tests/__pycache__/test_audit_arsenal.cpython-313.pyc +0 -0
  229. package/omega/Agentik_Engine/tests/__pycache__/test_audits_pipeline.cpython-313-pytest-8.4.2.pyc +0 -0
  230. package/omega/Agentik_Engine/tests/__pycache__/test_audits_pipeline.cpython-313.pyc +0 -0
  231. package/omega/Agentik_Engine/tests/__pycache__/test_auto_update_and_migrations.cpython-313-pytest-8.4.2.pyc +0 -0
  232. package/omega/Agentik_Engine/tests/__pycache__/test_auto_update_and_migrations.cpython-313.pyc +0 -0
  233. package/omega/Agentik_Engine/tests/__pycache__/test_autonomous.cpython-313-pytest-8.4.2.pyc +0 -0
  234. package/omega/Agentik_Engine/tests/__pycache__/test_autonomous.cpython-313.pyc +0 -0
  235. package/omega/Agentik_Engine/tests/__pycache__/test_educators.cpython-313-pytest-8.4.2.pyc +0 -0
  236. package/omega/Agentik_Engine/tests/__pycache__/test_educators.cpython-313.pyc +0 -0
  237. package/omega/Agentik_Engine/tests/__pycache__/test_executor.cpython-313-pytest-8.4.2.pyc +0 -0
  238. package/omega/Agentik_Engine/tests/__pycache__/test_executor.cpython-313.pyc +0 -0
  239. package/omega/Agentik_Engine/tests/__pycache__/test_genesis_and_plan.cpython-313-pytest-8.4.2.pyc +0 -0
  240. package/omega/Agentik_Engine/tests/__pycache__/test_genesis_and_plan.cpython-313.pyc +0 -0
  241. package/omega/Agentik_Engine/tests/__pycache__/test_graphify.cpython-313-pytest-8.4.2.pyc +0 -0
  242. package/omega/Agentik_Engine/tests/__pycache__/test_graphify.cpython-313.pyc +0 -0
  243. package/omega/Agentik_Engine/tests/__pycache__/test_handoff.cpython-313-pytest-8.4.2.pyc +0 -0
  244. package/omega/Agentik_Engine/tests/__pycache__/test_handoff.cpython-313.pyc +0 -0
  245. package/omega/Agentik_Engine/tests/__pycache__/test_hermes_and_ua.cpython-313-pytest-8.4.2.pyc +0 -0
  246. package/omega/Agentik_Engine/tests/__pycache__/test_hermes_and_ua.cpython-313.pyc +0 -0
  247. package/omega/Agentik_Engine/tests/__pycache__/test_hermes_bootstrap_and_desktop.cpython-313-pytest-8.4.2.pyc +0 -0
  248. package/omega/Agentik_Engine/tests/__pycache__/test_hermes_bootstrap_and_desktop.cpython-313.pyc +0 -0
  249. package/omega/Agentik_Engine/tests/__pycache__/test_install_steps.cpython-313-pytest-8.4.2.pyc +0 -0
  250. package/omega/Agentik_Engine/tests/__pycache__/test_install_steps.cpython-313.pyc +0 -0
  251. package/omega/Agentik_Engine/tests/__pycache__/test_install_ux.cpython-313-pytest-8.4.2.pyc +0 -0
  252. package/omega/Agentik_Engine/tests/__pycache__/test_install_ux.cpython-313.pyc +0 -0
  253. package/omega/Agentik_Engine/tests/__pycache__/test_installer_wiring.cpython-313-pytest-8.4.2.pyc +0 -0
  254. package/omega/Agentik_Engine/tests/__pycache__/test_installer_wiring.cpython-313.pyc +0 -0
  255. package/omega/Agentik_Engine/tests/__pycache__/test_intelligence.cpython-313-pytest-8.4.2.pyc +0 -0
  256. package/omega/Agentik_Engine/tests/__pycache__/test_intelligence.cpython-313.pyc +0 -0
  257. package/omega/Agentik_Engine/tests/__pycache__/test_llm_clis_and_uninstall.cpython-313-pytest-8.4.2.pyc +0 -0
  258. package/omega/Agentik_Engine/tests/__pycache__/test_llm_clis_and_uninstall.cpython-313.pyc +0 -0
  259. package/omega/Agentik_Engine/tests/__pycache__/test_managed_agent.cpython-313-pytest-8.4.2.pyc +0 -0
  260. package/omega/Agentik_Engine/tests/__pycache__/test_managed_agent.cpython-313.pyc +0 -0
  261. package/omega/Agentik_Engine/tests/__pycache__/test_max_provider_and_menu.cpython-313-pytest-8.4.2.pyc +0 -0
  262. package/omega/Agentik_Engine/tests/__pycache__/test_max_provider_and_menu.cpython-313.pyc +0 -0
  263. package/omega/Agentik_Engine/tests/__pycache__/test_menu_coverage.cpython-313-pytest-8.4.2.pyc +0 -0
  264. package/omega/Agentik_Engine/tests/__pycache__/test_menu_coverage.cpython-313.pyc +0 -0
  265. package/omega/Agentik_Engine/tests/__pycache__/test_mission.cpython-313-pytest-8.4.2.pyc +0 -0
  266. package/omega/Agentik_Engine/tests/__pycache__/test_mission.cpython-313.pyc +0 -0
  267. package/omega/Agentik_Engine/tests/__pycache__/test_progress.cpython-313-pytest-8.4.2.pyc +0 -0
  268. package/omega/Agentik_Engine/tests/__pycache__/test_progress.cpython-313.pyc +0 -0
  269. package/omega/Agentik_Engine/tests/__pycache__/test_project.cpython-313-pytest-8.4.2.pyc +0 -0
  270. package/omega/Agentik_Engine/tests/__pycache__/test_project.cpython-313.pyc +0 -0
  271. package/omega/Agentik_Engine/tests/__pycache__/test_pursue_cadence.cpython-313-pytest-8.4.2.pyc +0 -0
  272. package/omega/Agentik_Engine/tests/__pycache__/test_pursue_cadence.cpython-313.pyc +0 -0
  273. package/omega/Agentik_Engine/tests/__pycache__/test_rag.cpython-313-pytest-8.4.2.pyc +0 -0
  274. package/omega/Agentik_Engine/tests/__pycache__/test_rag.cpython-313.pyc +0 -0
  275. package/omega/Agentik_Engine/tests/__pycache__/test_reducer.cpython-313-pytest-8.4.2.pyc +0 -0
  276. package/omega/Agentik_Engine/tests/__pycache__/test_reducer.cpython-313.pyc +0 -0
  277. package/omega/Agentik_Engine/tests/__pycache__/test_report.cpython-313-pytest-8.4.2.pyc +0 -0
  278. package/omega/Agentik_Engine/tests/__pycache__/test_report.cpython-313.pyc +0 -0
  279. package/omega/Agentik_Engine/tests/__pycache__/test_role_aliases_and_ssot.cpython-313-pytest-8.4.2.pyc +0 -0
  280. package/omega/Agentik_Engine/tests/__pycache__/test_role_aliases_and_ssot.cpython-313.pyc +0 -0
  281. package/omega/Agentik_Engine/tests/__pycache__/test_skill_discovery_and_gate.cpython-313-pytest-8.4.2.pyc +0 -0
  282. package/omega/Agentik_Engine/tests/__pycache__/test_skill_discovery_and_gate.cpython-313.pyc +0 -0
  283. package/omega/Agentik_Engine/tests/__pycache__/test_skill_power.cpython-313-pytest-8.4.2.pyc +0 -0
  284. package/omega/Agentik_Engine/tests/__pycache__/test_skill_power.cpython-313.pyc +0 -0
  285. package/omega/Agentik_Engine/tests/__pycache__/test_skill_routing.cpython-313-pytest-8.4.2.pyc +0 -0
  286. package/omega/Agentik_Engine/tests/__pycache__/test_skill_routing.cpython-313.pyc +0 -0
  287. package/omega/Agentik_Engine/tests/__pycache__/test_snapshot_partial.cpython-313-pytest-8.4.2.pyc +0 -0
  288. package/omega/Agentik_Engine/tests/__pycache__/test_snapshot_partial.cpython-313.pyc +0 -0
  289. package/omega/Agentik_Engine/tests/__pycache__/test_telegram_history.cpython-313-pytest-8.4.2.pyc +0 -0
  290. package/omega/Agentik_Engine/tests/__pycache__/test_telegram_history.cpython-313.pyc +0 -0
  291. package/omega/Agentik_Engine/tests/__pycache__/test_tmux_and_aisb_chat.cpython-313-pytest-8.4.2.pyc +0 -0
  292. package/omega/Agentik_Engine/tests/__pycache__/test_tmux_and_aisb_chat.cpython-313.pyc +0 -0
  293. package/omega/Agentik_Engine/tests/__pycache__/test_tools_and_sync.cpython-313-pytest-8.4.2.pyc +0 -0
  294. package/omega/Agentik_Engine/tests/__pycache__/test_tools_and_sync.cpython-313.pyc +0 -0
  295. package/omega/Agentik_Engine/tests/__pycache__/test_v06_features.cpython-313-pytest-8.4.2.pyc +0 -0
  296. package/omega/Agentik_Engine/tests/__pycache__/test_v06_features.cpython-313.pyc +0 -0
  297. package/omega/Agentik_Engine/tests/__pycache__/test_vault.cpython-313-pytest-8.4.2.pyc +0 -0
  298. package/omega/Agentik_Engine/tests/__pycache__/test_vault.cpython-313.pyc +0 -0
  299. package/omega/Agentik_Engine/tests/__pycache__/test_webhooks_and_readiness.cpython-313-pytest-8.4.2.pyc +0 -0
  300. package/omega/Agentik_Engine/tests/__pycache__/test_webhooks_and_readiness.cpython-313.pyc +0 -0
  301. package/omega/Agentik_Engine/tests/__pycache__/test_worker_and_cleanup.cpython-313-pytest-8.4.2.pyc +0 -0
  302. package/omega/Agentik_Engine/tests/__pycache__/test_worker_and_cleanup.cpython-313.pyc +0 -0
  303. package/omega/Agentik_Engine/tests/test_account.py +8 -3
  304. package/omega/Agentik_Engine/tests/test_adversarial.py +351 -0
  305. package/omega/Agentik_Engine/tests/test_agents_envelope.py +274 -0
  306. package/omega/Agentik_Engine/tests/test_audits_pipeline.py +348 -0
  307. package/omega/Agentik_Engine/tests/test_auto_update_and_migrations.py +394 -0
  308. package/omega/Agentik_Engine/tests/test_genesis_and_plan.py +573 -0
  309. package/omega/Agentik_Engine/tests/test_graphify.py +190 -0
  310. package/omega/Agentik_Engine/tests/test_handoff.py +311 -0
  311. package/omega/Agentik_Engine/tests/test_hermes_and_ua.py +387 -0
  312. package/omega/Agentik_Engine/tests/test_hermes_bootstrap_and_desktop.py +358 -0
  313. package/omega/Agentik_Engine/tests/test_install_steps.py +359 -0
  314. package/omega/Agentik_Engine/tests/test_install_ux.py +151 -0
  315. package/omega/Agentik_Engine/tests/test_installer_wiring.py +496 -0
  316. package/omega/Agentik_Engine/tests/test_intelligence.py +285 -0
  317. package/omega/Agentik_Engine/tests/test_llm_clis_and_uninstall.py +228 -0
  318. package/omega/Agentik_Engine/tests/test_managed_agent.py +363 -0
  319. package/omega/Agentik_Engine/tests/test_max_provider_and_menu.py +231 -0
  320. package/omega/Agentik_Engine/tests/test_menu_coverage.py +72 -0
  321. package/omega/Agentik_Engine/tests/test_pursue_cadence.py +217 -0
  322. package/omega/Agentik_Engine/tests/test_role_aliases_and_ssot.py +207 -0
  323. package/omega/Agentik_Engine/tests/test_skill_discovery_and_gate.py +337 -0
  324. package/omega/Agentik_Engine/tests/test_skill_power.py +259 -0
  325. package/omega/Agentik_Engine/tests/test_skill_routing.py +189 -0
  326. package/omega/Agentik_Engine/tests/test_telegram_history.py +209 -0
  327. package/omega/Agentik_Engine/tests/test_tmux_and_aisb_chat.py +223 -0
  328. package/omega/Agentik_Engine/tests/test_v06_features.py +370 -0
  329. package/omega/Agentik_Engine/tests/test_vault.py +173 -0
  330. package/omega/Agentik_Engine/tests/test_webhooks_and_readiness.py +277 -0
  331. package/omega/Agentik_Engine/tests/test_worker_and_cleanup.py +541 -0
  332. package/omega/Agentik_Extra/etc/secrets/.vault-key +3 -0
  333. package/omega/Agentik_Extra/etc/secrets/.vault-pub +1 -0
  334. package/omega/Agentik_Runtime/audits.db +0 -0
  335. package/omega/Agentik_SSOT/VERSION +1 -1
  336. package/omega/Agentik_SSOT/claude-plugins/claude-plugins.yaml +100 -0
  337. package/omega/Agentik_SSOT/docs/LAYERS.md +90 -0
  338. package/omega/Agentik_SSOT/docs/USER-JOURNEY.md +283 -0
  339. package/omega/Agentik_SSOT/docs/quality-arsenal/ARSENAL-INTERCONNECTIONS.md +283 -0
  340. package/omega/Agentik_SSOT/docs/quality-arsenal/ARSENAL-ORCHESTRATION-PLAYBOOK.md +364 -0
  341. package/omega/Agentik_SSOT/docs/quality-arsenal/AUDIT-VERIFICATION-CONTRACT.md +272 -0
  342. package/omega/Agentik_SSOT/docs/quality-arsenal/QUALITY-ARSENAL-PREAMBLE.md +462 -0
  343. package/omega/Agentik_SSOT/marketplaces/design-discipline.yaml +86 -0
  344. package/omega/Agentik_SSOT/skills/a11yaudit/SKILL.md +161 -0
  345. package/omega/Agentik_SSOT/skills/apiaudit/SKILL.md +157 -0
  346. package/omega/Agentik_SSOT/skills/audit-orchestrator.md +212 -0
  347. package/omega/Agentik_SSOT/skills/audit-pilot.md +466 -0
  348. package/omega/Agentik_SSOT/skills/audit-tracker.md +147 -0
  349. package/omega/Agentik_SSOT/skills/automationaudit/SKILL.md +161 -0
  350. package/omega/Agentik_SSOT/skills/cadence/SKILL.md +76 -0
  351. package/omega/Agentik_SSOT/skills/codeaudit/SKILL.md +153 -0
  352. package/omega/Agentik_SSOT/skills/copyaudit/SKILL.md +161 -0
  353. package/omega/Agentik_SSOT/skills/dataaudit/SKILL.md +157 -0
  354. package/omega/Agentik_SSOT/skills/debugaudit/SKILL.md +161 -0
  355. package/omega/Agentik_SSOT/skills/dispatch/SKILL.md +79 -0
  356. package/omega/Agentik_SSOT/skills/dxaudit/SKILL.md +161 -0
  357. package/omega/Agentik_SSOT/skills/featureaudit/SKILL.md +161 -0
  358. package/omega/Agentik_SSOT/skills/flowaudit/SKILL.md +165 -0
  359. package/omega/Agentik_SSOT/skills/genesis/SKILL.md +116 -0
  360. package/omega/Agentik_SSOT/skills/handoff/SKILL.md +117 -0
  361. package/omega/Agentik_SSOT/skills/logicaudit/SKILL.md +165 -0
  362. package/omega/Agentik_SSOT/skills/motionaudit/SKILL.md +165 -0
  363. package/omega/Agentik_SSOT/skills/newcmd.md +300 -0
  364. package/omega/Agentik_SSOT/skills/perfaudit/SKILL.md +161 -0
  365. package/omega/Agentik_SSOT/skills/plan/SKILL.md +127 -0
  366. package/omega/Agentik_SSOT/skills/pursue/SKILL.md +68 -0
  367. package/omega/Agentik_SSOT/skills/quality-arsenal.md +180 -0
  368. package/omega/Agentik_SSOT/skills/rag-route.md +9 -0
  369. package/omega/Agentik_SSOT/skills/refontaudit/SKILL.md +165 -0
  370. package/omega/Agentik_SSOT/skills/retentionaudit/SKILL.md +165 -0
  371. package/omega/Agentik_SSOT/skills/secaudit/SKILL.md +157 -0
  372. package/omega/Agentik_SSOT/skills/seoaudit/SKILL.md +161 -0
  373. package/omega/Agentik_SSOT/skills/skill-auditor/SKILL.md +83 -0
  374. package/omega/Agentik_SSOT/skills/skill-finder/SKILL.md +116 -0
  375. package/omega/Agentik_SSOT/skills/uiuxaudit/SKILL.md +165 -0
  376. package/package.json +2 -2
@@ -0,0 +1,846 @@
1
+ """Plan v7 — FSM-enforced sequential plan executor.
2
+
3
+ What pre-v0.19 got wrong
4
+ ------------------------
5
+
6
+ The legacy ``/planner`` skill stored everything in a flat ``tracker.json``
7
+ that the agent read end-to-end at every turn. Three failure modes:
8
+
9
+ 1. **Visibility leak.** With 1500 tasks visible, an agent picks by bias
10
+ (short, easy, exciting) and skips ahead — "I'll do T-090 first,
11
+ it's the fun one". The user observed it jumping from T-050 to T-090
12
+ without finishing T-051..T-089.
13
+ 2. **Soft constraint.** The order was a PROMPT instruction
14
+ ("NEVER skip a step"). No runtime checks. The agent could violate
15
+ and nothing rejected the violation.
16
+ 3. **No explicit DAG.** Dependencies were implicit in numbering. Even
17
+ an honest agent couldn't tell that T-007 depended on T-005.
18
+
19
+ What this module does instead
20
+ -----------------------------
21
+
22
+ * **Persistent store.** Every task is a row in SQLite (per-project DB).
23
+ The agent sees one task at a time via ``next_eligible``, never the
24
+ whole list.
25
+ * **Explicit ``depends_on``.** Every task carries its predecessors as
26
+ a list of task ids. The plan refuses to advance a task whose deps
27
+ aren't all VERIFIED.
28
+ * **FSM enforced at engine level.** Transitions are validated by the
29
+ reducer. An attempt to mark T-090 DONE while T-089 is still PENDING
30
+ raises ``IllegalTransition`` — the agent CANNOT bypass it.
31
+ * **Verified completion.** Each task has a ``verify_cmd``. ``mark_done``
32
+ runs it inside the project root and refuses to flip to VERIFIED if
33
+ the command fails.
34
+
35
+ Public API (consumed by ``omega plan`` CLI)
36
+ -------------------------------------------
37
+
38
+ build_plan(slug) — read plan/DAG.json + Genesis features → load store
39
+ next_eligible(slug) — return the next PENDING task with all deps VERIFIED
40
+ mark_in_progress(slug, task_id)
41
+ mark_done(slug, task_id, *, verify=True) — runs verify_cmd, refuses if FAIL
42
+ mark_failed(slug, task_id, reason)
43
+ status(slug) — counts per state + active task
44
+ list_tasks(slug, *, state=None)
45
+ replan(slug) — reload DAG.json (idempotent)
46
+
47
+ The store
48
+ ---------
49
+
50
+ One SQLite DB per project at::
51
+
52
+ $OMEGA_HOME/Agentik_Coding/projects/<slug>/plan/plan.db
53
+
54
+ Schema::
55
+
56
+ CREATE TABLE tasks (
57
+ id TEXT PRIMARY KEY, -- F-001, F-002, ...
58
+ slug TEXT NOT NULL,
59
+ title TEXT NOT NULL,
60
+ depends_on TEXT NOT NULL, -- JSON array of task ids
61
+ wave INTEGER NOT NULL,
62
+ estimated_minutes INTEGER NOT NULL,
63
+ files_owned TEXT NOT NULL, -- JSON array
64
+ verify_cmd TEXT NOT NULL,
65
+ skill TEXT NOT NULL,
66
+ state TEXT NOT NULL, -- pending | in_progress | claimed_done | verified | failed
67
+ started_at REAL,
68
+ finished_at REAL,
69
+ last_attempt_at REAL,
70
+ attempts INTEGER NOT NULL DEFAULT 0,
71
+ last_error TEXT
72
+ );
73
+ CREATE INDEX idx_state ON tasks(state);
74
+ CREATE INDEX idx_wave ON tasks(wave);
75
+
76
+ The FSM
77
+ -------
78
+
79
+ pending → in_progress (next_eligible picked it)
80
+ in_progress → claimed_done (worker wrote .done.json; not yet trusted)
81
+ claimed_done → verified (verify_cmd exited 0 — TERMINAL ok)
82
+ in_progress → failed (worker exhausted retries — TERMINAL bad)
83
+ claimed_done → failed (verify_cmd exited != 0 → also TERMINAL bad)
84
+
85
+ The reducer (below) is the ONLY place that touches the ``state`` column.
86
+ Every transition validates the predecessors are all VERIFIED. There is
87
+ no other code path that can change task state.
88
+ """
89
+ from __future__ import annotations
90
+
91
+ import json
92
+ import os
93
+ import sqlite3
94
+ import subprocess
95
+ import threading
96
+ import time
97
+ from dataclasses import asdict, dataclass, field
98
+ from pathlib import Path
99
+ from typing import Any
100
+
101
+
102
+ # Valid states + transitions
103
+ PENDING = "pending"
104
+ IN_PROGRESS = "in_progress"
105
+ CLAIMED_DONE = "claimed_done"
106
+ VERIFIED = "verified"
107
+ FAILED = "failed"
108
+
109
+ _TERMINAL = (VERIFIED, FAILED)
110
+
111
+ # Allowed (current, next) transitions. Anything outside this set raises.
112
+ _ALLOWED: set[tuple[str, str]] = {
113
+ (PENDING, IN_PROGRESS),
114
+ (IN_PROGRESS, CLAIMED_DONE),
115
+ (CLAIMED_DONE, VERIFIED),
116
+ (CLAIMED_DONE, FAILED),
117
+ (IN_PROGRESS, FAILED),
118
+ # retry: a FAILED task can be reset to PENDING (operator explicit)
119
+ (FAILED, PENDING),
120
+ }
121
+
122
+
123
+ class PlanError(RuntimeError):
124
+ """Raised when an operation violates the plan FSM contract."""
125
+
126
+
127
+ # ---------------------------------------------------------------------------
128
+ # Dataclass mirror of the row
129
+ # ---------------------------------------------------------------------------
130
+
131
+
132
+ @dataclass
133
+ class PlanTask:
134
+ id: str
135
+ slug: str
136
+ title: str
137
+ depends_on: list[str]
138
+ wave: int
139
+ estimated_minutes: int
140
+ files_owned: list[str]
141
+ verify_cmd: str
142
+ skill: str
143
+ state: str = PENDING
144
+ started_at: float | None = None
145
+ finished_at: float | None = None
146
+ last_attempt_at: float | None = None
147
+ attempts: int = 0
148
+ last_error: str = ""
149
+
150
+ def to_dict(self) -> dict[str, Any]:
151
+ return asdict(self)
152
+
153
+ @staticmethod
154
+ def from_row(row: sqlite3.Row) -> "PlanTask":
155
+ return PlanTask(
156
+ id=row["id"], slug=row["slug"], title=row["title"],
157
+ depends_on=json.loads(row["depends_on"]),
158
+ wave=row["wave"], estimated_minutes=row["estimated_minutes"],
159
+ files_owned=json.loads(row["files_owned"]),
160
+ verify_cmd=row["verify_cmd"], skill=row["skill"],
161
+ state=row["state"],
162
+ started_at=row["started_at"], finished_at=row["finished_at"],
163
+ last_attempt_at=row["last_attempt_at"],
164
+ attempts=row["attempts"], last_error=row["last_error"] or "",
165
+ )
166
+
167
+
168
+ # ---------------------------------------------------------------------------
169
+ # Path resolver — strict per-project isolation
170
+ # ---------------------------------------------------------------------------
171
+
172
+
173
+ def _omega_home(explicit: str | Path | None = None) -> Path:
174
+ if explicit is not None:
175
+ return Path(explicit)
176
+ return Path(os.environ.get("OMEGA_HOME", str(Path.home() / "Omega")))
177
+
178
+
179
+ def project_root(slug: str, omega_home: str | Path | None = None) -> Path:
180
+ return _omega_home(omega_home) / "Agentik_Coding" / "projects" / slug
181
+
182
+
183
+ def db_path(slug: str, omega_home: str | Path | None = None) -> Path:
184
+ return project_root(slug, omega_home) / "plan" / "plan.db"
185
+
186
+
187
+ def dag_path(slug: str, omega_home: str | Path | None = None) -> Path:
188
+ return project_root(slug, omega_home) / "plan" / "DAG.json"
189
+
190
+
191
+ # ---------------------------------------------------------------------------
192
+ # DB bootstrap
193
+ # ---------------------------------------------------------------------------
194
+
195
+
196
+ _SCHEMA = """
197
+ CREATE TABLE IF NOT EXISTS tasks (
198
+ id TEXT PRIMARY KEY,
199
+ slug TEXT NOT NULL,
200
+ title TEXT NOT NULL,
201
+ depends_on TEXT NOT NULL,
202
+ wave INTEGER NOT NULL,
203
+ estimated_minutes INTEGER NOT NULL,
204
+ files_owned TEXT NOT NULL,
205
+ verify_cmd TEXT NOT NULL,
206
+ skill TEXT NOT NULL,
207
+ state TEXT NOT NULL,
208
+ started_at REAL,
209
+ finished_at REAL,
210
+ last_attempt_at REAL,
211
+ attempts INTEGER NOT NULL DEFAULT 0,
212
+ last_error TEXT
213
+ );
214
+ CREATE INDEX IF NOT EXISTS idx_state ON tasks(state);
215
+ CREATE INDEX IF NOT EXISTS idx_wave ON tasks(wave);
216
+ """
217
+
218
+
219
+ def _connect(slug: str, omega_home: str | Path | None = None) -> sqlite3.Connection:
220
+ p = db_path(slug, omega_home)
221
+ p.parent.mkdir(parents=True, exist_ok=True)
222
+ conn = sqlite3.connect(str(p), isolation_level=None, check_same_thread=False)
223
+ conn.row_factory = sqlite3.Row
224
+ conn.execute("PRAGMA journal_mode=WAL;")
225
+ conn.execute("PRAGMA synchronous=NORMAL;")
226
+ conn.executescript(_SCHEMA)
227
+ return conn
228
+
229
+
230
+ # Per-connection lock to serialise writes across threads.
231
+ _locks: dict[str, threading.Lock] = {}
232
+ _locks_lock = threading.Lock()
233
+
234
+
235
+ def _lock_for(slug: str) -> threading.Lock:
236
+ with _locks_lock:
237
+ if slug not in _locks:
238
+ _locks[slug] = threading.Lock()
239
+ return _locks[slug]
240
+
241
+
242
+ # ---------------------------------------------------------------------------
243
+ # build_plan — load DAG.json into the store
244
+ # ---------------------------------------------------------------------------
245
+
246
+
247
+ def _validate_dag(features: list[dict[str, Any]]) -> None:
248
+ """Topological soundness + uniqueness check."""
249
+ ids = [f["id"] for f in features]
250
+ if len(ids) != len(set(ids)):
251
+ dupes = [x for x in ids if ids.count(x) > 1]
252
+ raise PlanError(f"duplicate feature ids in DAG: {sorted(set(dupes))}")
253
+ id_set = set(ids)
254
+ for f in features:
255
+ for dep in f.get("depends_on", []):
256
+ if dep not in id_set:
257
+ raise PlanError(
258
+ f"feature {f['id']} depends on unknown {dep!r}"
259
+ )
260
+ # Cycle detection via Kahn's algorithm
261
+ indeg = {fid: 0 for fid in ids}
262
+ for f in features:
263
+ for dep in f.get("depends_on", []):
264
+ indeg[f["id"]] += 1
265
+ queue = [fid for fid, d in indeg.items() if d == 0]
266
+ seen = 0
267
+ edges = {f["id"]: list(f.get("depends_on", [])) for f in features}
268
+ rev = {fid: [] for fid in ids}
269
+ for fid, deps in edges.items():
270
+ for d in deps:
271
+ rev[d].append(fid)
272
+ while queue:
273
+ cur = queue.pop()
274
+ seen += 1
275
+ for nxt in rev[cur]:
276
+ indeg[nxt] -= 1
277
+ if indeg[nxt] == 0:
278
+ queue.append(nxt)
279
+ if seen != len(ids):
280
+ raise PlanError("DAG has a cycle — features must be acyclic")
281
+
282
+
283
+ def build_plan(
284
+ slug: str,
285
+ *,
286
+ omega_home: str | Path | None = None,
287
+ reset_failed: bool = False,
288
+ ) -> dict[str, Any]:
289
+ """Read ``plan/DAG.json``, validate the DAG, upsert every task.
290
+
291
+ Idempotent: re-running picks up new features and updates titles +
292
+ depends_on for known ones. State is PRESERVED (a task already
293
+ VERIFIED stays VERIFIED). If ``reset_failed=True``, every FAILED task
294
+ is re-set to PENDING.
295
+ """
296
+ dp = dag_path(slug, omega_home)
297
+ if not dp.exists():
298
+ raise PlanError(
299
+ f"no DAG at {dp} — run `omega genesis run {slug}` to produce it"
300
+ )
301
+ data = json.loads(dp.read_text())
302
+ features = data.get("features") or []
303
+ _validate_dag(features)
304
+
305
+ inserted = 0
306
+ updated = 0
307
+ with _lock_for(slug):
308
+ conn = _connect(slug, omega_home)
309
+ try:
310
+ existing = {
311
+ r["id"]: r for r in conn.execute(
312
+ "SELECT * FROM tasks WHERE slug = ?", (slug,)
313
+ ).fetchall()
314
+ }
315
+ for f in features:
316
+ fid = f["id"]
317
+ if fid in existing:
318
+ # Update mutable metadata only; preserve state +
319
+ # timing fields.
320
+ conn.execute(
321
+ "UPDATE tasks SET title=?, depends_on=?, wave=?, "
322
+ "estimated_minutes=?, files_owned=?, verify_cmd=?, "
323
+ "skill=? WHERE id=?",
324
+ (
325
+ f["title"], json.dumps(f.get("depends_on", [])),
326
+ int(f.get("wave", 1)),
327
+ int(f.get("estimated_minutes", 30)),
328
+ json.dumps(f.get("files_owned", [])),
329
+ f.get("verify_cmd", "true"),
330
+ f.get("skill", ""),
331
+ fid,
332
+ ),
333
+ )
334
+ updated += 1
335
+ else:
336
+ conn.execute(
337
+ "INSERT INTO tasks(id, slug, title, depends_on, wave, "
338
+ "estimated_minutes, files_owned, verify_cmd, skill, "
339
+ "state, attempts) VALUES (?,?,?,?,?,?,?,?,?,?,0)",
340
+ (
341
+ fid, slug, f["title"],
342
+ json.dumps(f.get("depends_on", [])),
343
+ int(f.get("wave", 1)),
344
+ int(f.get("estimated_minutes", 30)),
345
+ json.dumps(f.get("files_owned", [])),
346
+ f.get("verify_cmd", "true"),
347
+ f.get("skill", ""),
348
+ PENDING,
349
+ ),
350
+ )
351
+ inserted += 1
352
+ if reset_failed:
353
+ conn.execute(
354
+ "UPDATE tasks SET state=?, last_error='' "
355
+ "WHERE slug=? AND state=?",
356
+ (PENDING, slug, FAILED),
357
+ )
358
+ finally:
359
+ conn.close()
360
+
361
+ return {"slug": slug, "inserted": inserted, "updated": updated,
362
+ "total": len(features)}
363
+
364
+
365
+ # ---------------------------------------------------------------------------
366
+ # State helpers
367
+ # ---------------------------------------------------------------------------
368
+
369
+
370
+ def _get_task(
371
+ slug: str, task_id: str, *, omega_home: str | Path | None = None,
372
+ ) -> PlanTask | None:
373
+ conn = _connect(slug, omega_home)
374
+ try:
375
+ row = conn.execute(
376
+ "SELECT * FROM tasks WHERE id = ? AND slug = ?", (task_id, slug),
377
+ ).fetchone()
378
+ finally:
379
+ conn.close()
380
+ if not row:
381
+ return None
382
+ return PlanTask.from_row(row)
383
+
384
+
385
+ def list_tasks(
386
+ slug: str,
387
+ *,
388
+ state: str | None = None,
389
+ omega_home: str | Path | None = None,
390
+ ) -> list[PlanTask]:
391
+ """List every task for a project. Filter by state when provided."""
392
+ conn = _connect(slug, omega_home)
393
+ try:
394
+ if state is None:
395
+ rows = conn.execute(
396
+ "SELECT * FROM tasks WHERE slug = ? "
397
+ "ORDER BY wave, id", (slug,),
398
+ ).fetchall()
399
+ else:
400
+ rows = conn.execute(
401
+ "SELECT * FROM tasks WHERE slug = ? AND state = ? "
402
+ "ORDER BY wave, id", (slug, state),
403
+ ).fetchall()
404
+ finally:
405
+ conn.close()
406
+ return [PlanTask.from_row(r) for r in rows]
407
+
408
+
409
+ def status(slug: str, *, omega_home: str | Path | None = None) -> dict[str, Any]:
410
+ """Per-state counts + the currently-active task (if any) + completion %."""
411
+ conn = _connect(slug, omega_home)
412
+ try:
413
+ counts = {
414
+ r["state"]: r["c"] for r in conn.execute(
415
+ "SELECT state, COUNT(*) AS c FROM tasks WHERE slug = ? "
416
+ "GROUP BY state", (slug,),
417
+ ).fetchall()
418
+ }
419
+ active = conn.execute(
420
+ "SELECT id, title FROM tasks WHERE slug = ? AND state = ? "
421
+ "LIMIT 1", (slug, IN_PROGRESS),
422
+ ).fetchone()
423
+ total = conn.execute(
424
+ "SELECT COUNT(*) AS c FROM tasks WHERE slug = ?", (slug,),
425
+ ).fetchone()["c"]
426
+ finally:
427
+ conn.close()
428
+ verified = counts.get(VERIFIED, 0)
429
+ pct = round(100.0 * verified / total, 1) if total else 0.0
430
+ return {
431
+ "slug": slug,
432
+ "total": total,
433
+ "counts": {
434
+ "pending": counts.get(PENDING, 0),
435
+ "in_progress": counts.get(IN_PROGRESS, 0),
436
+ "claimed_done": counts.get(CLAIMED_DONE, 0),
437
+ "verified": counts.get(VERIFIED, 0),
438
+ "failed": counts.get(FAILED, 0),
439
+ },
440
+ "active": dict(active) if active else None,
441
+ "completion_pct": pct,
442
+ }
443
+
444
+
445
+ # ---------------------------------------------------------------------------
446
+ # The reducer — the ONLY place state transitions happen
447
+ # ---------------------------------------------------------------------------
448
+
449
+
450
+ def _are_deps_verified(
451
+ conn: sqlite3.Connection, slug: str, deps: list[str],
452
+ ) -> tuple[bool, list[str]]:
453
+ """Return (ok, missing). ``missing`` is the list of deps that aren't
454
+ VERIFIED yet — used to compose a clear error message."""
455
+ if not deps:
456
+ return True, []
457
+ placeholders = ",".join("?" * len(deps))
458
+ rows = conn.execute(
459
+ f"SELECT id, state FROM tasks WHERE slug=? AND id IN ({placeholders})",
460
+ (slug, *deps),
461
+ ).fetchall()
462
+ have = {r["id"]: r["state"] for r in rows}
463
+ missing = [d for d in deps if have.get(d) != VERIFIED]
464
+ return (len(missing) == 0), missing
465
+
466
+
467
+ def _transition(
468
+ slug: str, task_id: str, new_state: str,
469
+ *,
470
+ omega_home: str | Path | None = None,
471
+ skip_dep_check: bool = False,
472
+ error: str = "",
473
+ attempts_delta: int = 0,
474
+ ) -> PlanTask:
475
+ """Atomically transition one task. The single funnel for every state change.
476
+
477
+ Validates:
478
+ 1. Task exists.
479
+ 2. (current → new) is in the ALLOWED set.
480
+ 3. When new == IN_PROGRESS, every dependency must be VERIFIED.
481
+ 4. When new == VERIFIED, the previous state must be CLAIMED_DONE
482
+ AND every dependency must be VERIFIED (defence in depth).
483
+
484
+ Raises :class:`PlanError` on any violation.
485
+ """
486
+ with _lock_for(slug):
487
+ conn = _connect(slug, omega_home)
488
+ try:
489
+ row = conn.execute(
490
+ "SELECT * FROM tasks WHERE slug=? AND id=?",
491
+ (slug, task_id),
492
+ ).fetchone()
493
+ if not row:
494
+ raise PlanError(f"unknown task {task_id!r} for slug {slug!r}")
495
+ cur_state = row["state"]
496
+ if (cur_state, new_state) not in _ALLOWED:
497
+ raise PlanError(
498
+ f"illegal transition {task_id}: "
499
+ f"{cur_state} → {new_state}"
500
+ )
501
+ # Dep enforcement
502
+ deps = json.loads(row["depends_on"])
503
+ if new_state in (IN_PROGRESS, VERIFIED) and not skip_dep_check:
504
+ ok, missing = _are_deps_verified(conn, slug, deps)
505
+ if not ok:
506
+ raise PlanError(
507
+ f"{task_id} cannot move to {new_state} — "
508
+ f"unverified deps: {missing}"
509
+ )
510
+ now = time.time()
511
+ updates: dict[str, Any] = {"state": new_state}
512
+ if new_state == IN_PROGRESS:
513
+ updates["started_at"] = now
514
+ updates["last_attempt_at"] = now
515
+ elif new_state == VERIFIED:
516
+ updates["finished_at"] = now
517
+ elif new_state == FAILED:
518
+ updates["finished_at"] = now
519
+ if error:
520
+ updates["last_error"] = error
521
+ elif new_state == PENDING:
522
+ # operator-issued retry — clear timing
523
+ updates["started_at"] = None
524
+ updates["finished_at"] = None
525
+ updates["last_error"] = ""
526
+ sets = ", ".join(f"{k}=?" for k in updates.keys())
527
+ args = list(updates.values())
528
+ if attempts_delta:
529
+ sets += ", attempts = attempts + ?"
530
+ args.append(attempts_delta)
531
+ args.append(slug)
532
+ args.append(task_id)
533
+ conn.execute(
534
+ f"UPDATE tasks SET {sets} WHERE slug=? AND id=?",
535
+ args,
536
+ )
537
+ # Re-read the row.
538
+ row = conn.execute(
539
+ "SELECT * FROM tasks WHERE slug=? AND id=?",
540
+ (slug, task_id),
541
+ ).fetchone()
542
+ finally:
543
+ conn.close()
544
+ return PlanTask.from_row(row)
545
+
546
+
547
+ # ---------------------------------------------------------------------------
548
+ # Public state-change API
549
+ # ---------------------------------------------------------------------------
550
+
551
+
552
+ def mark_in_progress(
553
+ slug: str, task_id: str, *,
554
+ omega_home: str | Path | None = None,
555
+ ) -> PlanTask:
556
+ """Move PENDING → IN_PROGRESS. Refuses if any dep isn't VERIFIED."""
557
+ return _transition(
558
+ slug, task_id, IN_PROGRESS, omega_home=omega_home,
559
+ attempts_delta=1,
560
+ )
561
+
562
+
563
+ def mark_claimed_done(
564
+ slug: str, task_id: str, *,
565
+ omega_home: str | Path | None = None,
566
+ ) -> PlanTask:
567
+ """Worker wrote .done.json → IN_PROGRESS → CLAIMED_DONE.
568
+
569
+ Not verified yet — the next call (``mark_done`` with verify) decides.
570
+ """
571
+ return _transition(
572
+ slug, task_id, CLAIMED_DONE, omega_home=omega_home,
573
+ skip_dep_check=True, # deps were already checked at IN_PROGRESS
574
+ )
575
+
576
+
577
+ def mark_done(
578
+ slug: str, task_id: str, *,
579
+ omega_home: str | Path | None = None,
580
+ verify: bool = True,
581
+ verify_cwd: str | Path | None = None,
582
+ verify_timeout_s: int = 600,
583
+ ) -> PlanTask:
584
+ """Run the verify_cmd; CLAIMED_DONE → VERIFIED on exit 0,
585
+ CLAIMED_DONE → FAILED otherwise.
586
+
587
+ If ``verify=False``, the verification step is skipped (operator
588
+ override — useful when the verify_cmd doesn't yet exist).
589
+ """
590
+ task = _get_task(slug, task_id, omega_home=omega_home)
591
+ if task is None:
592
+ raise PlanError(f"unknown task {task_id!r}")
593
+ if task.state != CLAIMED_DONE:
594
+ # Allow IN_PROGRESS → VERIFIED only when we explicitly skip verify
595
+ # (the operator knows what they're doing); otherwise demand the
596
+ # claimed_done pit-stop.
597
+ if task.state == IN_PROGRESS and not verify:
598
+ _transition(slug, task_id, CLAIMED_DONE,
599
+ omega_home=omega_home, skip_dep_check=True)
600
+ else:
601
+ raise PlanError(
602
+ f"{task_id} is in state {task.state}; "
603
+ f"expected {CLAIMED_DONE} before mark_done"
604
+ )
605
+
606
+ if verify:
607
+ cwd = Path(verify_cwd) if verify_cwd else project_root(slug, omega_home)
608
+ try:
609
+ proc = subprocess.run(
610
+ ["bash", "-c", task.verify_cmd],
611
+ check=False, capture_output=True, text=True,
612
+ timeout=verify_timeout_s, cwd=str(cwd),
613
+ )
614
+ rc = proc.returncode
615
+ tail = (proc.stdout + "\n" + proc.stderr).strip()[-400:]
616
+ except subprocess.TimeoutExpired:
617
+ rc = 124
618
+ tail = f"verify_cmd timed out after {verify_timeout_s}s"
619
+ except OSError as exc:
620
+ rc = 127
621
+ tail = f"verify_cmd exec error: {exc}"
622
+ if rc != 0:
623
+ return _transition(
624
+ slug, task_id, FAILED, omega_home=omega_home,
625
+ error=f"verify_cmd rc={rc}: {tail}",
626
+ skip_dep_check=True,
627
+ )
628
+
629
+ return _transition(
630
+ slug, task_id, VERIFIED, omega_home=omega_home,
631
+ )
632
+
633
+
634
+ def mark_failed(
635
+ slug: str, task_id: str, reason: str = "",
636
+ *,
637
+ omega_home: str | Path | None = None,
638
+ ) -> PlanTask:
639
+ """Force-fail a task (operator action — e.g. mission abort)."""
640
+ return _transition(
641
+ slug, task_id, FAILED, omega_home=omega_home,
642
+ error=reason, skip_dep_check=True,
643
+ )
644
+
645
+
646
+ def retry(
647
+ slug: str, task_id: str, *,
648
+ omega_home: str | Path | None = None,
649
+ ) -> PlanTask:
650
+ """Reset a FAILED task to PENDING (operator decided to retry)."""
651
+ return _transition(
652
+ slug, task_id, PENDING, omega_home=omega_home,
653
+ skip_dep_check=True,
654
+ )
655
+
656
+
657
+ # ---------------------------------------------------------------------------
658
+ # next_eligible — the function workers call to know what to do next
659
+ # ---------------------------------------------------------------------------
660
+
661
+
662
+ @dataclass
663
+ class RunResult:
664
+ """Result of an autonomous ``run`` loop iteration set."""
665
+
666
+ slug: str
667
+ iterations: int = 0
668
+ verified: list[str] = field(default_factory=list)
669
+ failed: list[str] = field(default_factory=list)
670
+ skipped_no_eligible: bool = False
671
+ elapsed_s: float = 0.0
672
+ final_status: dict[str, Any] = field(default_factory=dict)
673
+
674
+ def to_dict(self) -> dict[str, Any]:
675
+ return asdict(self)
676
+
677
+
678
+ def run(
679
+ slug: str,
680
+ *,
681
+ omega_home: str | Path | None = None,
682
+ worker_role: str = "worker_ui",
683
+ max_iterations: int | None = None,
684
+ dispatch: Any | None = None,
685
+ spawn_cmd: list[str] | None = None,
686
+ on_iteration: Any | None = None,
687
+ sleep_between_s: float = 0.0,
688
+ ) -> RunResult:
689
+ """Autonomous multi-day plan loop with FSM enforcement.
690
+
691
+ Walks ``pending → in_progress → claimed_done → verified`` for every
692
+ eligible task in turn, using ``next_eligible`` to pick the single
693
+ next task. Built so it can run UNATTENDED for hours / days inside a
694
+ detached tmux session.
695
+
696
+ Dispatch path
697
+ -------------
698
+
699
+ For each task:
700
+
701
+ 1. ``mark_in_progress`` (FAILS via reducer if any dep isn't VERIFIED —
702
+ that's the cardinal invariant that fixes the v6 skip bug).
703
+ 2. Call the ``dispatch`` callable (or run ``spawn_cmd`` via subprocess
704
+ if no callable was passed) with the task object. The callable
705
+ is responsible for invoking the worker (omega worker spawn / a
706
+ Hermes call / a /team mission / whatever) AND waiting for the
707
+ worker's ``.done.json``.
708
+ 3. ``mark_claimed_done`` once the worker reported done.
709
+ 4. ``mark_done`` which runs ``verify_cmd`` inside the project root.
710
+ If verify_cmd exits 0 → VERIFIED. Otherwise → FAILED.
711
+
712
+ The loop continues until ``next_eligible`` returns None OR
713
+ ``max_iterations`` is hit. Failed tasks do NOT unlock their
714
+ dependants (correct behaviour — the loop falls naturally to
715
+ no-eligible after one failure cascade).
716
+
717
+ Parameters
718
+ ----------
719
+ dispatch : callable(task: PlanTask) -> None
720
+ How to spawn the worker. None ⇒ use ``spawn_cmd``. If both are
721
+ None, the loop ONLY runs the engine's verify_cmd (useful for
722
+ dry-running a plan whose tasks are already implemented).
723
+ spawn_cmd : list[str]
724
+ Shell tokens to run for each task. ``{task_id}``, ``{slug}``,
725
+ ``{title}``, ``{verify}``, ``{files}``, ``{skill}`` are substituted.
726
+ on_iteration : callable(task: PlanTask, result: str) -> None
727
+ Optional hook for telemetry / Telegram updates after each task.
728
+ """
729
+ import time as _t
730
+ started = _t.time()
731
+ out = RunResult(slug=slug)
732
+ iters = 0
733
+ while True:
734
+ if max_iterations is not None and iters >= max_iterations:
735
+ break
736
+ task = next_eligible(slug, omega_home=omega_home)
737
+ if task is None:
738
+ out.skipped_no_eligible = True
739
+ break
740
+ iters += 1
741
+ # Step 1: PENDING → IN_PROGRESS (reducer-enforced dep check)
742
+ try:
743
+ mark_in_progress(slug, task.id, omega_home=omega_home)
744
+ except PlanError as exc:
745
+ # next_eligible promised this would work; if it didn't, the
746
+ # store is in a bad state. Skip + record + continue.
747
+ out.failed.append(task.id)
748
+ if on_iteration:
749
+ on_iteration(task, f"in_progress failed: {exc}")
750
+ continue
751
+
752
+ # Step 2: dispatch the worker
753
+ dispatch_err: str | None = None
754
+ try:
755
+ if dispatch is not None:
756
+ dispatch(task)
757
+ elif spawn_cmd:
758
+ substituted = [
759
+ seg.format(
760
+ task_id=task.id, slug=task.slug, title=task.title,
761
+ verify=task.verify_cmd, skill=task.skill,
762
+ files=",".join(task.files_owned),
763
+ ) for seg in spawn_cmd
764
+ ]
765
+ subprocess.run(substituted, check=False, timeout=3600)
766
+ # No dispatch + no spawn_cmd = test/dry mode → straight to claimed.
767
+ except Exception as exc: # noqa: BLE001
768
+ dispatch_err = f"dispatch raised: {exc!r}"
769
+
770
+ # Step 3: mark_claimed_done (engine-side bookkeeping)
771
+ try:
772
+ mark_claimed_done(slug, task.id, omega_home=omega_home)
773
+ except PlanError as exc:
774
+ mark_failed(slug, task.id,
775
+ reason=f"could not move to claimed_done: {exc}",
776
+ omega_home=omega_home)
777
+ out.failed.append(task.id)
778
+ if on_iteration:
779
+ on_iteration(task, f"claimed failed: {exc}")
780
+ continue
781
+
782
+ # Step 4: verify_cmd runs (engine, not worker) → VERIFIED or FAILED
783
+ try:
784
+ t = mark_done(slug, task.id, omega_home=omega_home, verify=True)
785
+ if t.state == VERIFIED:
786
+ out.verified.append(task.id)
787
+ if on_iteration:
788
+ on_iteration(task, "verified")
789
+ else:
790
+ out.failed.append(task.id)
791
+ if on_iteration:
792
+ on_iteration(task, f"failed: {t.last_error}")
793
+ except PlanError as exc:
794
+ mark_failed(slug, task.id, reason=str(exc),
795
+ omega_home=omega_home)
796
+ out.failed.append(task.id)
797
+ if on_iteration:
798
+ on_iteration(task, f"verify raised: {exc}")
799
+
800
+ if dispatch_err and task.id not in out.failed:
801
+ # Worker side blew up after engine already verified — record
802
+ # the warning in last_error but don't override state.
803
+ out.failed.append(task.id)
804
+
805
+ if sleep_between_s > 0:
806
+ _t.sleep(sleep_between_s)
807
+
808
+ out.iterations = iters
809
+ out.elapsed_s = round(_t.time() - started, 2)
810
+ out.final_status = status(slug, omega_home=omega_home)
811
+ return out
812
+
813
+
814
+ def next_eligible(
815
+ slug: str,
816
+ *,
817
+ omega_home: str | Path | None = None,
818
+ ) -> PlanTask | None:
819
+ """Return the single next task the agent should work on.
820
+
821
+ Eligibility rule: state=PENDING AND every dep is VERIFIED.
822
+ Ordering: lowest wave first, then lowest id (lexicographic).
823
+
824
+ The worker MUST be handed ONLY this object — never the full task
825
+ list. That's how we close the visibility leak from the v6 planner.
826
+ """
827
+ with _lock_for(slug):
828
+ conn = _connect(slug, omega_home)
829
+ try:
830
+ rows = conn.execute(
831
+ "SELECT * FROM tasks WHERE slug = ? AND state = ? "
832
+ "ORDER BY wave, id", (slug, PENDING),
833
+ ).fetchall()
834
+ finally:
835
+ conn.close()
836
+ for row in rows:
837
+ task = PlanTask.from_row(row)
838
+ with _lock_for(slug):
839
+ conn = _connect(slug, omega_home)
840
+ try:
841
+ ok, _ = _are_deps_verified(conn, slug, task.depends_on)
842
+ finally:
843
+ conn.close()
844
+ if ok:
845
+ return task
846
+ return None