aetherius 0.2.0__tar.gz → 0.3.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 (228) hide show
  1. aetherius-0.3.0/.dockerignore +11 -0
  2. {aetherius-0.2.0 → aetherius-0.3.0}/.env.example +8 -0
  3. aetherius-0.3.0/.github/workflows/release.yml +92 -0
  4. aetherius-0.3.0/CHANGELOG.md +189 -0
  5. {aetherius-0.2.0 → aetherius-0.3.0}/PKG-INFO +98 -9
  6. {aetherius-0.2.0 → aetherius-0.3.0}/README.md +90 -8
  7. {aetherius-0.2.0/src/aetherius/_contracts → aetherius-0.3.0/contracts}/blueprint.schema.json +50 -2
  8. {aetherius-0.2.0 → aetherius-0.3.0}/contracts/events.schema.json +1 -1
  9. aetherius-0.3.0/contracts/openapi.yaml +308 -0
  10. aetherius-0.3.0/deploy/.env.example +17 -0
  11. aetherius-0.3.0/deploy/Dockerfile +63 -0
  12. aetherius-0.3.0/deploy/aetherius.service +29 -0
  13. aetherius-0.3.0/deploy/docker-compose.yml +28 -0
  14. {aetherius-0.2.0 → aetherius-0.3.0}/pyproject.toml +9 -1
  15. {aetherius-0.2.0/contracts → aetherius-0.3.0/src/aetherius/_contracts}/blueprint.schema.json +50 -2
  16. aetherius-0.3.0/src/aetherius/acts/_shared.py +116 -0
  17. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/continuum/browser.py +103 -13
  18. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/continuum/driver.py +18 -0
  19. aetherius-0.3.0/src/aetherius/acts/vector/client.py +216 -0
  20. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/vector/driver.py +54 -5
  21. aetherius-0.3.0/src/aetherius/acts/vector/impersonate.py +81 -0
  22. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/builder/catalog.py +4 -1
  23. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/builder/factory.py +4 -0
  24. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/builder/validation.py +16 -13
  25. aetherius-0.2.0/src/aetherius/cli.py → aetherius-0.3.0/src/aetherius/cli/__init__.py +27 -31
  26. aetherius-0.3.0/src/aetherius/cli/_shared.py +20 -0
  27. aetherius-0.3.0/src/aetherius/cli/schedule.py +245 -0
  28. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/config/settings.py +17 -0
  29. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/app.py +2 -2
  30. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/console.tcss +40 -0
  31. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/builder/options_editor.py +8 -0
  32. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/home.py +5 -0
  33. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/library.py +17 -0
  34. aetherius-0.3.0/src/aetherius/console/screens/schedules/__init__.py +12 -0
  35. aetherius-0.3.0/src/aetherius/console/screens/schedules/_common.py +44 -0
  36. aetherius-0.3.0/src/aetherius/console/screens/schedules/detail.py +269 -0
  37. aetherius-0.3.0/src/aetherius/console/screens/schedules/form.py +350 -0
  38. aetherius-0.3.0/src/aetherius/console/screens/schedules/screen.py +182 -0
  39. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screenshots.py +134 -4
  40. aetherius-0.3.0/src/aetherius/console/widgets/confirm.py +52 -0
  41. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/widgets/form.py +6 -2
  42. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/widgets/run_summary.py +2 -1
  43. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/actions/base.py +19 -7
  44. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/actions/flow.py +20 -13
  45. aetherius-0.3.0/src/aetherius/core/actions/notification.py +59 -0
  46. aetherius-0.3.0/src/aetherius/core/actions/registry.py +117 -0
  47. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/blueprint/models.py +6 -0
  48. aetherius-0.3.0/src/aetherius/core/blueprint/validator.py +83 -0
  49. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/errors.py +22 -0
  50. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/events/models.py +5 -1
  51. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/extraction/json_extractor.py +12 -0
  52. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/runtime/context.py +5 -0
  53. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/runtime/engine.py +7 -57
  54. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/runtime/result.py +2 -0
  55. aetherius-0.3.0/src/aetherius/core/runtime/steps.py +289 -0
  56. aetherius-0.3.0/src/aetherius/models/store/.gitkeep +0 -0
  57. aetherius-0.3.0/src/aetherius/network/__init__.py +35 -0
  58. aetherius-0.3.0/src/aetherius/network/geo.py +63 -0
  59. aetherius-0.3.0/src/aetherius/network/identity.py +104 -0
  60. aetherius-0.3.0/src/aetherius/network/pool.py +64 -0
  61. aetherius-0.3.0/src/aetherius/network/proxy.py +90 -0
  62. aetherius-0.3.0/src/aetherius/network/transport.py +33 -0
  63. aetherius-0.3.0/src/aetherius/notify/__init__.py +48 -0
  64. aetherius-0.3.0/src/aetherius/notify/base.py +18 -0
  65. aetherius-0.3.0/src/aetherius/notify/channels/__init__.py +19 -0
  66. aetherius-0.3.0/src/aetherius/notify/channels/_http.py +31 -0
  67. aetherius-0.3.0/src/aetherius/notify/channels/discord.py +52 -0
  68. aetherius-0.3.0/src/aetherius/notify/channels/ntfy.py +66 -0
  69. aetherius-0.3.0/src/aetherius/notify/channels/telegram.py +48 -0
  70. aetherius-0.3.0/src/aetherius/notify/channels/webhook.py +32 -0
  71. aetherius-0.3.0/src/aetherius/notify/message.py +26 -0
  72. aetherius-0.3.0/src/aetherius/notify/registry.py +98 -0
  73. aetherius-0.3.0/src/aetherius/notify/sink.py +51 -0
  74. aetherius-0.3.0/src/aetherius/plugins.py +88 -0
  75. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/_transform.py +21 -1
  76. aetherius-0.3.0/src/aetherius/server/app.py +68 -0
  77. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/server/config.py +18 -0
  78. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/server/deps.py +14 -0
  79. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/server/jobs.py +63 -4
  80. aetherius-0.3.0/src/aetherius/server/routes/schedules.py +142 -0
  81. aetherius-0.3.0/src/aetherius/server/scheduler/__init__.py +32 -0
  82. aetherius-0.3.0/src/aetherius/server/scheduler/alerts.py +140 -0
  83. aetherius-0.3.0/src/aetherius/server/scheduler/manual.py +82 -0
  84. aetherius-0.3.0/src/aetherius/server/scheduler/misfire.py +71 -0
  85. aetherius-0.3.0/src/aetherius/server/scheduler/service.py +198 -0
  86. aetherius-0.3.0/src/aetherius/server/scheduler/triggers.py +115 -0
  87. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/server/schemas.py +35 -0
  88. aetherius-0.3.0/src/aetherius/stealth/fingerprint/hardening.py +193 -0
  89. aetherius-0.3.0/src/aetherius/stealth/fingerprint/headers.py +46 -0
  90. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/fingerprint/profile.py +48 -7
  91. aetherius-0.3.0/src/aetherius/stealth/fingerprint/webrtc.py +64 -0
  92. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/humanizer/timing.py +15 -8
  93. aetherius-0.3.0/src/aetherius/store/__init__.py +28 -0
  94. aetherius-0.3.0/src/aetherius/store/engine.py +71 -0
  95. aetherius-0.3.0/src/aetherius/store/models.py +48 -0
  96. aetherius-0.3.0/src/aetherius/store/runs.py +91 -0
  97. aetherius-0.3.0/src/aetherius/store/schedules.py +118 -0
  98. aetherius-0.3.0/src/aetherius/store/schema.py +78 -0
  99. aetherius-0.3.0/src/aetherius/store/state.py +51 -0
  100. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/version.py +1 -1
  101. aetherius-0.2.0/CHANGELOG.md +0 -39
  102. aetherius-0.2.0/RELEASING.md +0 -49
  103. aetherius-0.2.0/contracts/openapi.yaml +0 -152
  104. aetherius-0.2.0/src/aetherius/acts/_shared.py +0 -61
  105. aetherius-0.2.0/src/aetherius/acts/vector/client.py +0 -129
  106. aetherius-0.2.0/src/aetherius/core/actions/registry.py +0 -70
  107. aetherius-0.2.0/src/aetherius/core/blueprint/validator.py +0 -45
  108. aetherius-0.2.0/src/aetherius/server/app.py +0 -37
  109. {aetherius-0.2.0 → aetherius-0.3.0}/.github/workflows/ci.yml +0 -0
  110. {aetherius-0.2.0 → aetherius-0.3.0}/.gitignore +0 -0
  111. {aetherius-0.2.0 → aetherius-0.3.0}/CONTRIBUTING.md +0 -0
  112. {aetherius-0.2.0 → aetherius-0.3.0}/LICENSE +0 -0
  113. {aetherius-0.2.0 → aetherius-0.3.0}/Makefile +0 -0
  114. {aetherius-0.2.0 → aetherius-0.3.0}/blueprints/UKIT.king.blueprint.json +0 -0
  115. {aetherius-0.2.0 → aetherius-0.3.0}/blueprints/direct.linkaetherius.blueprint.json +0 -0
  116. {aetherius-0.2.0 → aetherius-0.3.0}/blueprints/github.aetherius.blueprint.json +0 -0
  117. {aetherius-0.2.0 → aetherius-0.3.0}/blueprints/github.github.blueprint.json +0 -0
  118. {aetherius-0.2.0 → aetherius-0.3.0}/blueprints/github.zeb.blueprint.json +0 -0
  119. {aetherius-0.2.0 → aetherius-0.3.0}/blueprints/licence.aetherius.blueprint.json +0 -0
  120. {aetherius-0.2.0 → aetherius-0.3.0}/blueprints/record.aetherius.blueprint.json +0 -0
  121. {aetherius-0.2.0/src/aetherius/models/store → aetherius-0.3.0/deploy/blueprints}/.gitkeep +0 -0
  122. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/__init__.py +0 -0
  123. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/__main__.py +0 -0
  124. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/_contracts/__init__.py +0 -0
  125. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/__init__.py +0 -0
  126. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/continuum/__init__.py +0 -0
  127. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/continuum/actions.py +0 -0
  128. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/continuum/bridge.py +0 -0
  129. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/continuum/debug_overlay.py +0 -0
  130. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/continuum/human_actions.py +0 -0
  131. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/oracle/__init__.py +0 -0
  132. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/oracle/driver.py +0 -0
  133. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/oracle/locator.py +0 -0
  134. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/oracle/model.py +0 -0
  135. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/oracle/perception.py +0 -0
  136. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/phantom/__init__.py +0 -0
  137. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/phantom/driver.py +0 -0
  138. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/phantom/loop.py +0 -0
  139. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/phantom/memory.py +0 -0
  140. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/phantom/perception.py +0 -0
  141. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/phantom/planner.py +0 -0
  142. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/vector/__init__.py +0 -0
  143. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/acts/vector/auth.py +0 -0
  144. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/builder/__init__.py +0 -0
  145. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/builder/templates.py +0 -0
  146. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/config/__init__.py +0 -0
  147. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/config/secrets.py +0 -0
  148. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/__init__.py +0 -0
  149. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/daemon_control.py +0 -0
  150. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/run_bridge.py +0 -0
  151. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/__init__.py +0 -0
  152. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/_pending.py +0 -0
  153. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/builder/__init__.py +0 -0
  154. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/builder/act_picker.py +0 -0
  155. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/builder/io_editor.py +0 -0
  156. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/builder/preview.py +0 -0
  157. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/builder/screen.py +0 -0
  158. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/builder/step_editor.py +0 -0
  159. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/catalog.py +0 -0
  160. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/library_scan.py +0 -0
  161. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/recorder.py +0 -0
  162. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/runs.py +0 -0
  163. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/sessions.py +0 -0
  164. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/screens/settings.py +0 -0
  165. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/theme.py +0 -0
  166. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/widgets/__init__.py +0 -0
  167. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/widgets/event_log.py +0 -0
  168. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/console/widgets/json_preview.py +0 -0
  169. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/__init__.py +0 -0
  170. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/actions/__init__.py +0 -0
  171. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/actions/data.py +0 -0
  172. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/actions/interaction.py +0 -0
  173. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/actions/navigation.py +0 -0
  174. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/actions/spec.py +0 -0
  175. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/blueprint/__init__.py +0 -0
  176. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/blueprint/loader.py +0 -0
  177. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/blueprint/template.py +0 -0
  178. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/driver.py +0 -0
  179. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/events/__init__.py +0 -0
  180. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/events/bus.py +0 -0
  181. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/events/sinks.py +0 -0
  182. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/extraction/__init__.py +0 -0
  183. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/extraction/html_extractor.py +0 -0
  184. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/runtime/__init__.py +0 -0
  185. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/core/runtime/selector.py +0 -0
  186. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/models/__init__.py +0 -0
  187. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/models/registry.py +0 -0
  188. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/__init__.py +0 -0
  189. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/_capture_js.py +0 -0
  190. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/_gesture_js.py +0 -0
  191. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/_names.py +0 -0
  192. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/_overlay_js.py +0 -0
  193. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/_playwright.py +0 -0
  194. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/_selector_js.py +0 -0
  195. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/_vector_js.py +0 -0
  196. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/base.py +0 -0
  197. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/blueprint_recorder.py +0 -0
  198. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/capture.py +0 -0
  199. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/continuum_backend.py +0 -0
  200. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/gesture_recorder.py +0 -0
  201. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/selector_synth.py +0 -0
  202. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/session.py +0 -0
  203. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/recorder/vector_backend.py +0 -0
  204. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/server/__init__.py +0 -0
  205. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/server/routes/__init__.py +0 -0
  206. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/server/routes/blueprints.py +0 -0
  207. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/server/routes/recorder.py +0 -0
  208. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/server/routes/runs.py +0 -0
  209. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/server/routes/stream.py +0 -0
  210. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/__init__.py +0 -0
  211. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/fingerprint/__init__.py +0 -0
  212. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/fingerprint/patch.py +0 -0
  213. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/gestures/__init__.py +0 -0
  214. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/gestures/data/human_library.json +0 -0
  215. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/gestures/library.py +0 -0
  216. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/gestures/seed.py +0 -0
  217. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/humanizer/__init__.py +0 -0
  218. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/humanizer/input.py +0 -0
  219. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/humanizer/keyboard.py +0 -0
  220. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/humanizer/mouse.py +0 -0
  221. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/humanizer/scroll.py +0 -0
  222. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/ml/__init__.py +0 -0
  223. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/ml/fingerprint_model.py +0 -0
  224. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/ml/motion_model.py +0 -0
  225. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/policy.py +0 -0
  226. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/session/__init__.py +0 -0
  227. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/session/store.py +0 -0
  228. {aetherius-0.2.0 → aetherius-0.3.0}/src/aetherius/stealth/session/warmup.py +0 -0
@@ -0,0 +1,11 @@
1
+ # Contexte de build Docker (deploy/Dockerfile, contexte = racine du depot).
2
+ # Allowlist : seul ce que le Dockerfile copie entre dans le contexte — le reste (dont .env et
3
+ # tout secret local) est exclu par construction.
4
+ *
5
+ !pyproject.toml
6
+ !README.md
7
+ !LICENSE
8
+ !src
9
+ !examples
10
+ **/__pycache__
11
+ **/*.pyc
@@ -18,3 +18,11 @@ AETHERIUS_SECRET_QUOTES_PASS=demo
18
18
  # Universite de Bordeaux ENT/CAS.
19
19
  AETHERIUS_SECRET_BORDEAUX_USER=your-username
20
20
  AETHERIUS_SECRET_BORDEAUX_PASS='your-password'
21
+
22
+ # Notification targets (see docs/notifications.md) — uncomment the channels you use.
23
+ # A channel address grants write (and for ntfy, read) access: keep them out of Blueprints.
24
+ # AETHERIUS_SECRET_WEBHOOK_URL=https://webhook.site/<your-uuid>
25
+ # AETHERIUS_SECRET_DISCORD_WEBHOOK=https://discord.com/api/webhooks/<id>/<token>
26
+ # AETHERIUS_SECRET_TELEGRAM_BOT_TOKEN=123456:bot-token
27
+ # AETHERIUS_SECRET_TELEGRAM_CHAT_ID=123456789
28
+ # AETHERIUS_SECRET_NTFY_TOPIC=my-private-topic
@@ -0,0 +1,92 @@
1
+ # Automated release. Publishing lives here (as infra), not in a doc to remember.
2
+ #
3
+ # To cut a release:
4
+ # 1. Bump the version in BOTH src/aetherius/version.py and sdks/typescript/package.json (same X.Y.Z).
5
+ # 2. Add a "## [X.Y.Z] - <date>" section at the top of CHANGELOG.md (becomes the release notes).
6
+ # 3. Commit, then: git tag vX.Y.Z && git push && git push --tags
7
+ #
8
+ # Pushing the tag triggers this workflow, which — after checking the tag matches the versions —
9
+ # publishes to PyPI and npm and creates the GitHub Release. Nothing else to run by hand.
10
+ #
11
+ # One-time setup (see the pinned note): a PyPI "trusted publisher" for this repo (no token), and an
12
+ # NPM_TOKEN repository secret (npm automation token).
13
+
14
+ name: Release
15
+
16
+ on:
17
+ push:
18
+ tags: ["v*"]
19
+
20
+ permissions:
21
+ contents: read
22
+
23
+ jobs:
24
+ check-version:
25
+ name: Tag matches package versions
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ - name: Verify tag == version.py == package.json
30
+ run: |
31
+ tag="${GITHUB_REF_NAME#v}"
32
+ py=$(python3 -c "import re,pathlib; print(re.search(r'__version__\s*=\s*\"([^\"]+)\"', pathlib.Path('src/aetherius/version.py').read_text()).group(1))")
33
+ ts=$(node -p "require('./sdks/typescript/package.json').version")
34
+ echo "tag=$tag python=$py npm=$ts"
35
+ test "$tag" = "$py" || { echo "::error::Tag $tag != Python version $py (bump src/aetherius/version.py)"; exit 1; }
36
+ test "$tag" = "$ts" || { echo "::error::Tag $tag != npm version $ts (bump sdks/typescript/package.json)"; exit 1; }
37
+
38
+ pypi:
39
+ name: Publish to PyPI
40
+ needs: check-version
41
+ runs-on: ubuntu-latest
42
+ permissions:
43
+ id-token: write # OIDC for PyPI trusted publishing (no token stored)
44
+ steps:
45
+ - uses: actions/checkout@v4
46
+ - uses: actions/setup-python@v5
47
+ with:
48
+ python-version: "3.12"
49
+ - run: python3 -m pip install build
50
+ - run: python3 -m build
51
+ - uses: pypa/gh-action-pypi-publish@release/v1
52
+
53
+ npm:
54
+ name: Publish to npm
55
+ needs: check-version
56
+ runs-on: ubuntu-latest
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+ - uses: actions/setup-node@v4
60
+ with:
61
+ node-version: "20"
62
+ registry-url: "https://registry.npmjs.org"
63
+ - run: npm install --no-audit --no-fund
64
+ working-directory: sdks/typescript
65
+ - run: npm run build
66
+ working-directory: sdks/typescript
67
+ - run: npm publish --access public
68
+ working-directory: sdks/typescript
69
+ env:
70
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
71
+
72
+ github-release:
73
+ name: GitHub Release
74
+ needs: [pypi, npm]
75
+ runs-on: ubuntu-latest
76
+ permissions:
77
+ contents: write
78
+ steps:
79
+ - uses: actions/checkout@v4
80
+ - name: Extract the CHANGELOG section for this version
81
+ run: |
82
+ version="${GITHUB_REF_NAME#v}"
83
+ awk -v ver="$version" '
84
+ $0 ~ "^## \\[" ver "\\]" { f=1; next }
85
+ /^## \[/ { if (f) exit }
86
+ f { print }
87
+ ' CHANGELOG.md > release-notes.md
88
+ [ -s release-notes.md ] || echo "Release ${GITHUB_REF_NAME}." > release-notes.md
89
+ - name: Create the release
90
+ env:
91
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
92
+ run: gh release create "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" --notes-file release-notes.md
@@ -0,0 +1,189 @@
1
+ # Changelog
2
+
3
+ Toutes les évolutions notables du projet sont consignées ici. Le format s'inspire de
4
+ [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/) et le versionnage suit
5
+ [SemVer](https://semver.org/lang/fr/). Tant que la version reste en `0.x`, l'API publique peut encore
6
+ évoluer entre deux versions mineures (durcissement de la Phase 1 en conditions réelles).
7
+
8
+ ## [Non publié]
9
+
10
+ ## [0.3.0] - 2026-07-17
11
+
12
+ Phase 1.5 : le socle devient **opérationnel** (planification, alertes, réactivité, furtivité réseau
13
+ et empreinte), et durcissement du socle Phase 1 avant d'entamer la Phase 2 (audit croisé de la doc).
14
+
15
+ ### Ajouté
16
+ - **Durcissement de l'empreinte (Jalon 1.5-H)** — les signaux à forte valeur que le profil laissait à
17
+ découvert sont fermés **de façon cohérente avec le profil actif** (un signal masqué mais incohérent
18
+ est un tell pire que l'absence de masque). Côté navigateur,
19
+ [`stealth/fingerprint/hardening.py`](src/aetherius/stealth/fingerprint/hardening.py) injecte, après
20
+ le script de cohérence du profil, un init script masquant : **Canvas** (`toDataURL`/`toBlob`/
21
+ `getImageData`) et **AudioContext** avec un bruit **déterministe par profil** (seed calculé côté
22
+ Python, hachage JS — stable entre deux lectures d'un même run, différent d'un profil à l'autre, lu
23
+ depuis une copie offscreen pour ne pas s'accumuler), **polices** (`measureText`), **client hints**
24
+ (`navigator.userAgentData`), **écran** (`screen.*` + `devicePixelRatio`) et **WebGL2**
25
+ (`getParameter`). Côté **Vector** (Act I, sans discrétion jusqu'ici),
26
+ [`stealth/fingerprint/headers.py`](src/aetherius/stealth/fingerprint/headers.py) donne une identité
27
+ d'en-têtes par défaut (`User-Agent`, `Sec-CH-UA`/`-Mobile`/`-Platform`, `Accept`, `Accept-Language`
28
+ aligné sur la géo) supprimant la signature « client HTTP nu » — **opt-in** (injectée seulement quand
29
+ `options.stealth` nomme un profil, un run sans stealth reste inchangé), les en-têtes explicites du
30
+ Blueprint gardant la priorité (fusion insensible à la casse) ; l'impersonation TLS `curl_cffi` garde
31
+ ses propres en-têtes. Le `FingerprintProfile` gagne les champs `screen`/`device_pixel_ratio`/
32
+ `ua_platform`/`ua_full_version` et dérive `Sec-CH-UA` de sa propre version d'UA : la limite « UA-CH
33
+ drift » est **levée**. Exemples exécutables zéro config
34
+ `examples/continuum/fingerprint-hardening.blueprint.json` et
35
+ `examples/vector/http-headers-identity.blueprint.json`. Voir [docs/stealth.md](docs/stealth.md).
36
+ - **Identité réseau (Jalon 1.5-G)** — option `options.proxy` de premier niveau qui rend le bot
37
+ invisible **au niveau réseau**, pour les **deux** moteurs (la couche stealth ne touche que le
38
+ navigateur). Le module `aetherius.network` est activé : `parse_proxy`/`ProxySpec` (rendu httpx et
39
+ Playwright, credentials masqués dans les logs), `ProxyPool` (rotation `per_run`/`round_robin`/
40
+ `random`/`sticky` — l'IP change d'un run à l'autre, ou reste stable par clé), `geo_hint` (cohérence
41
+ timezone/locale/langues avec le pays de l'IP), `resolve_identity` (option du Blueprint > défaut
42
+ d'environnement `AETHERIUS_PROXY_*` > aucun). Vector route par `httpx.Client(proxy=...)`
43
+ (HTTP/HTTPS, plus SOCKS5 via l'extra `[network]` avec garde typée si absent) et peut imiter la
44
+ poignée de main TLS d'un vrai navigateur (JA3/JA4) via un transport `curl_cffi` isolé
45
+ (`acts/vector/impersonate.py`, extra `[network]`, `DependencyError` claire sinon). Continuum lie le
46
+ proxy au lancement du contexte, force l'anti-fuite WebRTC (flag Chromium `disable_non_proxied_udp`
47
+ + init-script filtrant les candidats ICE locaux — indispensable, sinon le proxy laisse fuir l'IP
48
+ réelle) et dérive le profil d'empreinte pour coller à la géo (timezone/locale/`navigator.languages`
49
+ alignés sur l'IP, vérifiés sur Chromium réel). Identifiants **jamais** stockés dans le Blueprint
50
+ (`{{ secrets.x }}`). Le Studio préserve `options.proxy` verbatim (aucune régression à l'édition).
51
+ Exemple exécutable `examples/vector/ip-echo-proxy.blueprint.json` (nécessite un proxy via `.env`).
52
+ Voir [docs/network.md](docs/network.md).
53
+ - **Déploiement always-on (Jalon 1.5-F)** — recette 24/7 vérifiée de bout en bout pour héberger le
54
+ daemon (et donc le scheduler) sur un hôte toujours allumé : VPS, Raspberry Pi, NAS. Les brouillons
55
+ `deploy/` sont finalisés : image Docker multi-stage (wheel construit à part, image finale sans
56
+ sources ni outils de build), utilisateur non-root, `HEALTHCHECK` sur `/health`, exemples embarqués
57
+ comme sondes zéro config, variante Act II exécutable (`--build-arg BROWSER=1` : extra `[browser]` +
58
+ Chromium sous `PLAYWRIGHT_BROWSERS_PATH` partagé) ; `docker-compose.yml` (volume persistant unique
59
+ `/data`, port publié sur la loopback de l'hôte, `env_file` + `.env.example`, montage lecture seule
60
+ `blueprints/` — les schedules résolvent des chemins côté conteneur) ; service systemd utilisateur
61
+ (`enable-linger`, `EnvironmentFile` optionnel, redémarrage automatique) ; `.dockerignore` racine en
62
+ allowlist (l'ancien `deploy/.dockerignore` était inopérant, le contexte de build étant la racine).
63
+ Durcissement afférent : un `AETHERIUS_DAEMON_TOKEN` vide vaut absence de token — l'interpolation
64
+ compose (`${VAR:-}`) n'active plus l'auth par accident (`server/config.py`, test miroir). Doc
65
+ complète (recettes, persistance, sauvegarde SQLite, sécurité : loopback par défaut, exposer =
66
+ token + reverse proxy TLS) : voir [docs/deployment.md](docs/deployment.md).
67
+ - **Actions custom / plugins (Jalon 1.5-E)** — points d'extension activés : un paquet tiers ajoute
68
+ des actions de Blueprint et des canaux de notification sans forker le cœur. Découverte par
69
+ entry-points (`aetherius.actions`, `aetherius.notify_channels`) dans le nouveau module
70
+ `aetherius.plugins` (`load_plugins()` idempotent, appelé au démarrage par la CLI, le lifespan du
71
+ daemon et `RunEngine.run` ; surface d'import unique pour les auteurs de plugins). Le registre
72
+ d'actions dormant est activé : une action plugin embarque son `ActionSpec` (visible du Studio et
73
+ des validators, invariant « registre = source, catalogue = projection » préservé), est
74
+ **act-agnostique** (hors capability-table, validée dynamiquement) et dispatchée par les drivers
75
+ en repli après leur `match` built-in. Gardes de collision sur les deux registres (les built-ins
76
+ restent prioritaires, un conflit est un échec de chargement explicite) et pannes isolées (un
77
+ plugin qui lève à l'import est loggé et sauté, jamais fatal). Plugin d'exemple exécutable
78
+ (`examples/plugins/` : action `demo.slugify` + canal `logfile` + Blueprint zéro réseau), chargé
79
+ par de vrais entry-points dans les tests. Voir [docs/plugins.md](docs/plugins.md).
80
+ - **Écran Console « Schedules »** — l'UI du scheduler (Jalon 1.5-D) dans la Console : liste des
81
+ schedules (trigger, politique d'alerte, statut, prochains/derniers tirs en heure locale, sonde
82
+ d'honnêteté « daemon actif ou non »), pause/reprise (`p`, la reprise recale la cadence),
83
+ suppression confirmée (`d`, nouveau `ConfirmModal` réutilisable), **détail** avec l'historique
84
+ des runs du schedule et un **tir manuel** aux événements streamés en direct (même brique
85
+ in-process que `aetherius schedule run`, extraite dans `server/scheduler/manual.py::fire_schedule`
86
+ et partagée CLI/Console), et **formulaire guidé** de création/édition (inputs du Blueprint en
87
+ champs, secrets jamais saisis — état `.env` affiché, trigger/misfire/notify validés à la
88
+ sauvegarde). Raccourci `s` dans Library pour planifier le Blueprint surligné. Captures SVG
89
+ déterministes (fuseau épinglé, store de démo figé) et neutralisation renforcée des chemins
90
+ (le home ne fuit plus, même tronqué dans une colonne). Voir [docs/console.md](docs/console.md).
91
+ - **Scheduler intégré au daemon (Jalon 1.5-D)** — rejeu persistant d'un Blueprint à heure fixe
92
+ (cron à 5 champs, évalué dans le fuseau local, DST gérés via `tzlocal`), par intervalle ou en tir
93
+ unique (`at`). Boucle de tick dans le lifespan du daemon (30 s, `AETHERIUS_DAEMON_SCHEDULER_TICK_SECONDS`) ;
94
+ un run planifié passe par `RunManager.submit` — mêmes événements, même historique, plus le lien
95
+ `schedule_id`. Rattrapage des tirs manqués par politique `misfire` (`skip`/`run_once`/`run_all`,
96
+ portée par le trigger, résolue par le tick au-delà d'une fenêtre de grâce) et politique d'alerte
97
+ par schedule (`failure`/`success`/`always`/`change` — la dédup au changement d'état s'appuie sur
98
+ `state.compare_and_set`, cibles `{{ secrets.x }}` rendues au tir, jamais persistées). CLI
99
+ `aetherius schedule add|list|rm|pause|resume|run` (écrit directement dans le store : marche daemon
100
+ éteint ; `cli.py` devient le package `cli/`) et API `/v1/schedules` (CRUD + tir immédiat,
101
+ contrat OpenAPI à jour). Exemple zéro config : `examples/vector/quotes-watch.blueprint.json`.
102
+ Dépendances : `croniter` (déjà déclarée) + `tzlocal`. Voir [docs/scheduler.md](docs/scheduler.md).
103
+ - **Notifications natives (Jalon 1.5-C)** — couche d'alerte sans dépendance nouvelle (`notify/`) :
104
+ quatre canaux built-in en un POST `httpx` chacun (webhook générique, Discord, Telegram, ntfy pour
105
+ la push téléphone, en mode JSON publishing), action `notify` Act-agnostique (handler partagé, se
106
+ combine à `when`), `NotifySink` de fin de run (`failure`/`success`/`always`) et registre de canaux
107
+ prêt pour les plugins (Jalon E). Échec d'envoi contenu : jamais fatal au run, `delivered` exposé
108
+ dans les outputs du step. Exemple zéro config :
109
+ `examples/vector/books-restock-notify.blueprint.json`. Voir
110
+ [docs/notifications.md](docs/notifications.md).
111
+ - **Réactivité et flux conditionnel (Jalon 1.5-B)** — garde d'étape `when` universelle (évaluée
112
+ avant dispatch, même règle de véracité que `assert` ; step sauté = statut `skipped` + événement
113
+ `step_skipped`, contrats et SDK TypeScript à jour) et actions `if`/`repeat`/`for_each` exécutées
114
+ par un **exécuteur récursif** dans le moteur (`core/runtime/steps.py`), en amont des drivers —
115
+ tous les Acts en héritent sans câblage, `repeat` rejoint les capacités Vector. Variable de boucle
116
+ `as` (défaut `item`) exposée au template le temps de l'itération, validation sémantique récursive
117
+ des branches, identifiants de steps imbriqués traçables (`loop[2].fetch`), schéma des steps
118
+ formalisé (`when`, `then`/`else`/`steps`). Deux exemples zéro config dans `examples/vector/`.
119
+ Voir [docs/blueprint-schema.md](docs/blueprint-schema.md).
120
+ - **Persistance durable (Jalon 1.5-A)** — socle de stockage SQLite (stdlib `sqlite3`, mode WAL, zéro
121
+ dépendance) sous `~/.aetherius/aetherius.db`, avec migrations versionnées (`PRAGMA user_version`) et
122
+ trois dépôts typés : schedules, historique des runs, état clé/valeur inter-run (`compare_and_set`
123
+ pour la déduplication d'alertes). Le daemon persiste désormais le résultat de ses runs dans le store
124
+ (migration douce, sans régression). Voir [docs/store.md](docs/store.md).
125
+ - **Cadrage Phase 1.5** — squelette (stubs, interfaces, contrats) et spécifications par jalon pour
126
+ rendre le socle **récurrent, réactif et furtif** : persistance SQLite (`store/`), notifications
127
+ natives (`notify/`), scheduler du daemon, flux conditionnel (`when`, `if`/`repeat`/`for_each`),
128
+ plugins, déploiement 24/7, **identité réseau** (`network/` : proxy, rotation d'IP, anti-fuite
129
+ WebRTC, cohérence géo, impersonation TLS) et **durcissement de l'empreinte**
130
+ (`stealth/fingerprint/` : canvas/audio/UA-CH/écran/WebGL2 + identité d'en-têtes pour Vector).
131
+ Aucune capacité n'est encore activée (jalons en attente : l'action `notify` est déclarée mais
132
+ marquée `PENDING`, les modules lèvent une erreur « jalon en attente ») ; `make check` reste vert.
133
+ Nouvel extra optionnel `[network]` (SOCKS5 + `curl_cffi`). Voir [docs/phase-1.5/](docs/phase-1.5/README.md).
134
+ - **Suivi des nouveaux onglets (Act II — Continuum)** : un clic ouvrant un onglet (`target="_blank"`,
135
+ `window.open`) rend la nouvelle page active pour les steps suivants, avec retombée sur une page
136
+ survivante si l'onglet actif se referme. Auparavant les steps restaient bloqués sur l'onglet initial.
137
+ - **Recorder « Make input »** : le `type`/`format` de l'input produit est inféré du type HTML du champ
138
+ (`number`, `date`+`format`, `email`/`url`, …) au lieu d'un `string` générique.
139
+
140
+ ### Sécurité
141
+ - **Évaluateur `where` (Act I — Vector)** : rejet explicite des attributs magiques (`__class__`,
142
+ `__globals__`, tout nom en `__`) dans l'AST-walk. L'allowlist de nœuds bloquait déjà l'exécution de
143
+ code, mais la traversée d'attributs dunder combinée à une comparaison restait un oracle booléen sur
144
+ le graphe d'objets Python — la garde ferme cette évasion de sandbox sans dépendre de l'absence
145
+ d'appels/indexation.
146
+
147
+ ### Corrigé
148
+ - **`precise_sleep` (stealth/humanizer)** : le busy-wait pur sous 20 ms saturait un cœur CPU à 100 %
149
+ (chaque point de geste souris), risque de privation de ressources sur le daemon en multi-run.
150
+ Désormais `time.sleep` cède le CPU pour le gros du délai et le busy-wait ne couvre que la queue
151
+ (~1,5 ms) — précision de timing inchangée, CPU au repos (~9 %).
152
+ - **Debug (Act II — Continuum)** : quand les entrées sont humanisées, `slow_mo` est à 0 et les actions
153
+ brutes (`select`, `upload`, `navigate`, …) défilaient instantanément, illisibles en debug. Elles
154
+ reçoivent maintenant un délai manuel équivalent.
155
+
156
+ ## [0.2.0] - 2026-07-10
157
+
158
+ Première release publique. Elle clôt la **Phase 1** : le socle d'Aetherius, utilisable comme
159
+ **bibliothèque** (in-process Python) et comme **service** (daemon local + SDK), avec sa Console.
160
+
161
+ ### Ajouté
162
+ - **Daemon local (FastAPI)** — passerelle HTTP + WebSocket exposant le moteur à tout langage
163
+ (`aetherius serve`, bind loopback, token bearer optionnel) : `POST /v1/runs`, `GET /v1/runs/{id}`,
164
+ `WS /v1/runs/{id}/events` (rejeu bufferisé + flux live jusqu'à `done`), `POST /v1/blueprints/validate`,
165
+ `GET /v1/schema`, `GET /health`. L'enregistrement reste host-local (`POST /v1/recorder/sessions` → 501).
166
+ Voir [docs/daemon.md](docs/daemon.md).
167
+ - **SDK TypeScript** `@aetherius/client` (Node 20+) — spawn du daemon (ou `baseUrl`),
168
+ `client.run(blueprint, { inputs, secrets, onEvent })`, streaming d'événements typé.
169
+ - **Console : écran Settings** — démarrer/arrêter le daemon et voir son statut, sans quitter le terminal.
170
+ - **Act I — Vector** : client HTTP/API (requêtes, retries/backoff, 5 stratégies d'auth, extraction
171
+ JSONPath et CSS/XPath, moteur de templates Jinja2).
172
+ - **Act II — Continuum** : automatisation d'un vrai navigateur (Playwright, extra `[browser]`) —
173
+ navigation, interactions, extraction DOM, `wait_for` avec échec nommé, sessions persistantes, debug.
174
+ - **Système de discrétion (stealth)** : couche transverse (`options.stealth`) — souris humaine par
175
+ rejeu géométrique de gestes, clavier/scroll/timing humains, fingerprint, warmup de profil.
176
+ - **Recorder** : création de Blueprint par démonstration (Continuum et Vector) + gesture recorder.
177
+ - **Builder headless + Blueprint Studio** : construction guidée de Blueprints sans JSON, avec aperçu
178
+ validé en direct, réutilisable par la Console, le daemon et les SDKs.
179
+ - **Console (Textual)** : Library, Runs, Catalog, Recorder, Blueprint Studio, Settings.
180
+ - **Contrats** langage-agnostiques (`contracts/`) : schéma Blueprint, OpenAPI du daemon, schéma
181
+ d'événements — source de vérité, gardés par des tests.
182
+
183
+ ### Notes
184
+ - SemVer `0.x` : l'API peut évoluer pendant le durcissement de la Phase 1.
185
+ - La **Phase 2** ajoutera Act III (Oracle, vision) et Act IV (Phantom, agent autonome).
186
+
187
+ [Non publié]: https://github.com/kln-mltre/Aetherius/compare/v0.3.0...HEAD
188
+ [0.3.0]: https://github.com/kln-mltre/Aetherius/releases/tag/v0.3.0
189
+ [0.2.0]: https://github.com/kln-mltre/Aetherius/releases/tag/v0.2.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aetherius
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: A fixed, robust web-bot engine driven by declarative instruction files (Blueprints).
5
5
  Project-URL: Repository, https://github.com/kln-mltre/Aetherius
6
6
  Author: Kylian Malartre
@@ -18,6 +18,7 @@ License: Aetherius
18
18
  License-File: LICENSE
19
19
  Keywords: agent,automation,bot,browser,playwright,scraping,stealth
20
20
  Requires-Python: >=3.11
21
+ Requires-Dist: croniter>=2.0
21
22
  Requires-Dist: fastapi>=0.110
22
23
  Requires-Dist: httpx>=0.27
23
24
  Requires-Dist: jinja2>=3.1
@@ -33,17 +34,20 @@ Requires-Dist: rich>=13.7
33
34
  Requires-Dist: tenacity>=8.2
34
35
  Requires-Dist: textual>=0.60
35
36
  Requires-Dist: typer>=0.12
37
+ Requires-Dist: tzlocal>=5.0
36
38
  Requires-Dist: uvicorn[standard]>=0.29
37
39
  Requires-Dist: websockets>=12.0
38
40
  Provides-Extra: agent
39
41
  Requires-Dist: anthropic>=0.25; extra == 'agent'
40
42
  Provides-Extra: all
41
43
  Requires-Dist: anthropic>=0.25; extra == 'all'
44
+ Requires-Dist: curl-cffi>=0.6; extra == 'all'
42
45
  Requires-Dist: numpy>=1.26; extra == 'all'
43
46
  Requires-Dist: onnxruntime>=1.17; extra == 'all'
44
47
  Requires-Dist: opencv-python-headless>=4.9; extra == 'all'
45
48
  Requires-Dist: pillow>=10.3; extra == 'all'
46
49
  Requires-Dist: playwright>=1.44; extra == 'all'
50
+ Requires-Dist: socksio>=1.0; extra == 'all'
47
51
  Provides-Extra: browser
48
52
  Requires-Dist: playwright>=1.44; extra == 'browser'
49
53
  Provides-Extra: dev
@@ -54,6 +58,9 @@ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
54
58
  Requires-Dist: pytest>=8.1; extra == 'dev'
55
59
  Requires-Dist: ruff>=0.4; extra == 'dev'
56
60
  Requires-Dist: twine>=5.0; extra == 'dev'
61
+ Provides-Extra: network
62
+ Requires-Dist: curl-cffi>=0.6; extra == 'network'
63
+ Requires-Dist: socksio>=1.0; extra == 'network'
57
64
  Provides-Extra: stealth
58
65
  Requires-Dist: numpy>=1.26; extra == 'stealth'
59
66
  Provides-Extra: vision
@@ -315,8 +322,9 @@ aetherius # ouvre la Console
315
322
 
316
323
  ![La Console Aetherius : écran d'accueil](docs/screenshots/home.svg)
317
324
 
318
- > **État actuel** : la Console est navigable de bout en bout. Library, Runs, Catalog, le **Recorder**,
319
- > le **Blueprint Studio** et **Settings** (démarrer/arrêter le daemon) sont pleinement fonctionnels
325
+ > **État actuel** : la Console est navigable de bout en bout. Library, Runs, **Schedules** (runs
326
+ > récurrents : liste, tir manuel, historique, création guidée), Catalog, le **Recorder**, le
327
+ > **Blueprint Studio** et **Settings** (démarrer/arrêter le daemon) sont pleinement fonctionnels
320
328
  > pour Act I (Vector) et Act II (Continuum, avec l'extra `[browser]`) ; seul **Sessions** affiche
321
329
  > honnêtement son jalon en attente (stealth/session). Détails : [docs/console.md](docs/console.md).
322
330
 
@@ -456,20 +464,25 @@ console.log(result.outputs.events);
456
464
  ```
457
465
  src/aetherius/
458
466
  core/ blueprint (models/loader/validator/template), actions (le dictionnaire),
459
- runtime (engine/context/selector/result), extraction, events, errors, driver
467
+ runtime (engine/context/steps/selector/result), extraction, events, errors, driver
460
468
  acts/ vector (I), continuum (II), oracle (III), phantom (IV)
461
469
  stealth/ policy, humanizer (mouse/keyboard/scroll/timing), gestures, fingerprint,
462
470
  session (store/warmup), ml (optionnel)
463
471
  recorder/ blueprint_recorder, gesture_recorder, capture, selector_synth
464
472
  builder/ construction headless de Blueprint (factory, catalog, templates)
465
- console/ interface terminale globale (Textual) : Blueprint Studio, runs, catalogue,
466
- sessions, settings — la porte d'entrée de l'outil
473
+ console/ interface terminale globale (Textual) : Blueprint Studio, runs, schedules,
474
+ catalogue, sessions, settings — la porte d'entrée de l'outil
475
+ notify/ canaux d'alerte natifs (webhook/discord/telegram/ntfy) + registre ouvert aux plugins
476
+ store/ état durable SQLite sous ~/.aetherius : schedules, historique des runs, état inter-run
477
+ plugins.py découverte des extensions tierces par entry-points (actions + canaux)
467
478
  models/ registry + cache des assets ML runtime
468
- server/ daemon FastAPI (routes/jobs/schemas)
479
+ server/ daemon FastAPI (routes/jobs/schemas) + scheduler (triggers/misfire/alerts)
480
+ cli/ commandes scriptables (run/validate/serve/record, groupe schedule)
469
481
  config/ settings
470
482
  contracts/ blueprint.schema.json, openapi.yaml, events.schema.json (source de vérité)
483
+ deploy/ recette always-on : Dockerfile, docker-compose.yml, service systemd
471
484
  sdks/ typescript (@aetherius/client), python
472
- examples/ Blueprints de démonstration
485
+ examples/ Blueprints de démonstration (par Act + plugins/)
473
486
  training/ entraînement des modèles Oracle (hors runtime)
474
487
  legacy_examples/ code de référence des projets d'origine (UKit, TikTok) + carte de provenance
475
488
  ```
@@ -521,7 +534,8 @@ Conventions de contribution (discipline de test, invariants, structure des tests
521
534
  Le projet avance en deux grandes phases. La **Phase 1** — le socle, utilisable comme **bibliothèque**
522
535
  (in-process Python) et comme **service** (daemon + SDK) — est **terminée avec ce jalon** : un premier
523
536
  point de contrôle, à éprouver en conditions réelles avant d'attaquer la **Phase 2** (les deux Acts les
524
- plus lourds).
537
+ plus lourds). Entre les deux, une **Phase 1.5** durcit ce socle pour les workflows **récurrents et
538
+ réactifs** (planification, alertes, réactivité) — voir ci-dessous.
525
539
 
526
540
  ### Phase 1 — le socle réutilisable (terminée)
527
541
 
@@ -589,6 +603,81 @@ plus lourds).
589
603
  **Phase 1 terminée.** Aetherius est utilisable comme bibliothèque et comme service ; c'est le point de
590
604
  contrôle prévu pour l'éprouver en conditions réelles et corriger avant la suite.
591
605
 
606
+ ### Phase 1.5 — socle opérationnel (en cours)
607
+
608
+ Un palier intermédiaire, dans l'esprit du durcissement du socle : rendre Aetherius capable de porter
609
+ des workflows **récurrents et réactifs** (planifier un Blueprint, réagir aux données extraites,
610
+ alerter au bon moment) avant les Acts autonomes. Le cas fil rouge : surveiller un produit en rupture,
611
+ vérifier plusieurs fois par jour, alerter au retour en stock. Et, dans la même veine furtive que la
612
+ couche stealth, le rendre invisible **au niveau réseau** (proxy, rotation d'IP). Cadrage complet et
613
+ **spécifications par jalon** : [docs/phase-1.5/](docs/phase-1.5/README.md).
614
+
615
+ - [x] **Persistance (`store/`)** : état durable SQLite (stdlib) sous `~/.aetherius` — schedules,
616
+ historique des runs, état inter-run. Fondation des autres jalons. Le daemon y persiste désormais
617
+ l'historique de ses runs. [docs/store.md](docs/store.md),
618
+ [docs/phase-1.5/a-store.md](docs/phase-1.5/a-store.md).
619
+ - [x] **Réactivité et flux conditionnel** : garde d'étape `when` universelle (step sauté = statut
620
+ `skipped` + événement `step_skipped`) et actions `if`/`repeat`/`for_each` exécutées récursivement
621
+ par le moteur sur tous les Acts (validation récursive des branches, variable de boucle `as`,
622
+ rend la réutilisation de session Continuum exprimable). Exemples zéro config dans
623
+ `examples/vector/`. [docs/blueprint-schema.md](docs/blueprint-schema.md),
624
+ [docs/phase-1.5/b-flow.md](docs/phase-1.5/b-flow.md).
625
+ - [x] **Notifications natives** : couche d'alerte sans dépendance nouvelle (webhook générique,
626
+ Discord, Telegram, **ntfy** pour la push téléphone — un POST `httpx` chacun), action `notify`
627
+ Act-agnostique (handler partagé, se combine à `when`) + `NotifySink` de fin de run
628
+ (`failure`/`success`/`always`), registre de canaux prêt pour les plugins (Jalon E), échec d'envoi
629
+ contenu (jamais fatal au run, `delivered` exposé). La dédup au changement d'état est désormais
630
+ portée par le scheduler (Jalon D, politique `change`). Exemple zéro config :
631
+ `examples/vector/books-restock-notify.blueprint.json`. [docs/notifications.md](docs/notifications.md),
632
+ [docs/phase-1.5/c-notifications.md](docs/phase-1.5/c-notifications.md).
633
+ - [x] **Scheduler (daemon)** : rejeu persistant d'un Blueprint à heure fixe (cron, fuseau local,
634
+ DST gérés) ou par intervalle, plus le tir unique (`at`). Intégré au daemon (lifespan FastAPI,
635
+ tick 30 s) ; un run planifié passe par `RunManager.submit` — indiscernable d'un run manuel, avec
636
+ le lien `schedule_id` dans l'historique. CLI `aetherius schedule add|list|rm|pause|resume|run`
637
+ (écrit directement dans le store : marche daemon éteint) et API `/v1/schedules` (CRUD + tir
638
+ immédiat). Rattrapage des tirs manqués par politique `misfire` (`skip`/`run_once`/`run_all`) et
639
+ politique d'alerte par schedule (`failure`/`success`/`always`/`change` — dédup au changement
640
+ d'état via le store). **Écran Console dédié** : liste, pause/reprise, suppression, détail avec
641
+ historique et tir manuel (événements en direct), formulaire de création/édition guidé, raccourci
642
+ `s` depuis Library. Exemple zéro config : `examples/vector/quotes-watch.blueprint.json`.
643
+ [docs/scheduler.md](docs/scheduler.md),
644
+ [docs/phase-1.5/d-scheduler.md](docs/phase-1.5/d-scheduler.md).
645
+ - [x] **Actions custom / plugins** : points d'extension activés — un paquet tiers ajoute des
646
+ **actions** et des **canaux de notification** sans forker le cœur. Découverte par entry-points
647
+ (`aetherius.actions`, `aetherius.notify_channels`) chargée au démarrage (CLI, daemon, moteur
648
+ in-process) ; une action plugin embarque sa spec (visible du Studio et du validator, act-agnostique,
649
+ dispatchée en repli après les built-ins) ; gardes de collision (les built-ins restent prioritaires)
650
+ et pannes isolées (un plugin cassé est loggé et sauté, jamais fatal au démarrage). Plugin d'exemple
651
+ exécutable : `examples/plugins/` (action `demo.slugify` + canal `logfile`).
652
+ [docs/plugins.md](docs/plugins.md), [docs/phase-1.5/e-plugins.md](docs/phase-1.5/e-plugins.md).
653
+ - [x] **Déploiement always-on** : recette 24/7 vérifiée de bout en bout pour héberger le daemon sur
654
+ une machine allumée (VPS, Raspberry Pi, NAS) — la réponse honnête au « hors machine ». Deux voies
655
+ dans [`deploy/`](deploy/) : image Docker durcie (multi-stage, non-root, healthcheck, variante Act
656
+ II via `--build-arg BROWSER=1`) + `docker-compose.yml` (volume persistant unique `/data`, port
657
+ publié sur la loopback de l'hôte, Blueprints utilisateur montés) et service systemd utilisateur
658
+ (`enable-linger`, redémarrage automatique). Tout l'état durable (schedules, historique, profils)
659
+ vit sous `AETHERIUS_DATA_DIR` et survit aux redémarrages ; sécurité par défaut : loopback, et
660
+ exposer exige token + reverse proxy TLS. [docs/deployment.md](docs/deployment.md),
661
+ [docs/phase-1.5/f-deployment.md](docs/phase-1.5/f-deployment.md).
662
+ - [x] **Identité réseau** : option `options.proxy` de premier niveau atteignant les **deux** moteurs
663
+ (Vector httpx/curl_cffi, Continuum Playwright ; HTTP/HTTPS/SOCKS5). Rotation de l'IP par run
664
+ (`per_run`/`round_robin`/`random`/`sticky`, pool inline ou défaut d'environnement `AETHERIUS_PROXY_*`),
665
+ prévention de la fuite WebRTC (flag de lancement + init-script, liée au proxy), cohérence géo
666
+ (timezone/locale/langues alignés sur le pays de l'IP, écrasant le profil d'empreinte) et
667
+ impersonation TLS (JA3/JA4) pour Vector via l'extra `[network]`. Identifiants jamais stockés
668
+ (`{{ secrets.x }}`). Exemple : `examples/vector/ip-echo-proxy.blueprint.json` (nécessite un proxy).
669
+ [docs/network.md](docs/network.md), [docs/phase-1.5/g-network.md](docs/phase-1.5/g-network.md).
670
+ - [x] **Durcissement de l'empreinte** : les signaux restants sont fermés **de façon cohérente avec le
671
+ profil** — Canvas et AudioContext (bruit déterministe par profil, stable entre deux lectures),
672
+ énumération des polices (`measureText`), client hints (`Sec-CH-UA` / `navigator.userAgentData`
673
+ dérivés de l'UA du profil, la limite « UA-CH drift » est levée), dimensions d'écran /
674
+ `devicePixelRatio` et WebGL2. Vector (Act I) gagne une **identité d'en-têtes par défaut** (UA +
675
+ client hints + `Accept-Language` alignés) quand `options.stealth` nomme un profil, sans écraser les
676
+ en-têtes explicites du Blueprint ni rien changer aux runs sans stealth. Exemples zéro config :
677
+ `examples/continuum/fingerprint-hardening.blueprint.json` et
678
+ `examples/vector/http-headers-identity.blueprint.json`. [docs/stealth.md](docs/stealth.md),
679
+ [docs/phase-1.5/h-fingerprint.md](docs/phase-1.5/h-fingerprint.md).
680
+
592
681
  ### Phase 2 — les Acts autonomes (à venir)
593
682
 
594
683
  - [ ] Act III — Oracle (vision + entraînement).
@@ -250,8 +250,9 @@ aetherius # ouvre la Console
250
250
 
251
251
  ![La Console Aetherius : écran d'accueil](docs/screenshots/home.svg)
252
252
 
253
- > **État actuel** : la Console est navigable de bout en bout. Library, Runs, Catalog, le **Recorder**,
254
- > le **Blueprint Studio** et **Settings** (démarrer/arrêter le daemon) sont pleinement fonctionnels
253
+ > **État actuel** : la Console est navigable de bout en bout. Library, Runs, **Schedules** (runs
254
+ > récurrents : liste, tir manuel, historique, création guidée), Catalog, le **Recorder**, le
255
+ > **Blueprint Studio** et **Settings** (démarrer/arrêter le daemon) sont pleinement fonctionnels
255
256
  > pour Act I (Vector) et Act II (Continuum, avec l'extra `[browser]`) ; seul **Sessions** affiche
256
257
  > honnêtement son jalon en attente (stealth/session). Détails : [docs/console.md](docs/console.md).
257
258
 
@@ -391,20 +392,25 @@ console.log(result.outputs.events);
391
392
  ```
392
393
  src/aetherius/
393
394
  core/ blueprint (models/loader/validator/template), actions (le dictionnaire),
394
- runtime (engine/context/selector/result), extraction, events, errors, driver
395
+ runtime (engine/context/steps/selector/result), extraction, events, errors, driver
395
396
  acts/ vector (I), continuum (II), oracle (III), phantom (IV)
396
397
  stealth/ policy, humanizer (mouse/keyboard/scroll/timing), gestures, fingerprint,
397
398
  session (store/warmup), ml (optionnel)
398
399
  recorder/ blueprint_recorder, gesture_recorder, capture, selector_synth
399
400
  builder/ construction headless de Blueprint (factory, catalog, templates)
400
- console/ interface terminale globale (Textual) : Blueprint Studio, runs, catalogue,
401
- sessions, settings — la porte d'entrée de l'outil
401
+ console/ interface terminale globale (Textual) : Blueprint Studio, runs, schedules,
402
+ catalogue, sessions, settings — la porte d'entrée de l'outil
403
+ notify/ canaux d'alerte natifs (webhook/discord/telegram/ntfy) + registre ouvert aux plugins
404
+ store/ état durable SQLite sous ~/.aetherius : schedules, historique des runs, état inter-run
405
+ plugins.py découverte des extensions tierces par entry-points (actions + canaux)
402
406
  models/ registry + cache des assets ML runtime
403
- server/ daemon FastAPI (routes/jobs/schemas)
407
+ server/ daemon FastAPI (routes/jobs/schemas) + scheduler (triggers/misfire/alerts)
408
+ cli/ commandes scriptables (run/validate/serve/record, groupe schedule)
404
409
  config/ settings
405
410
  contracts/ blueprint.schema.json, openapi.yaml, events.schema.json (source de vérité)
411
+ deploy/ recette always-on : Dockerfile, docker-compose.yml, service systemd
406
412
  sdks/ typescript (@aetherius/client), python
407
- examples/ Blueprints de démonstration
413
+ examples/ Blueprints de démonstration (par Act + plugins/)
408
414
  training/ entraînement des modèles Oracle (hors runtime)
409
415
  legacy_examples/ code de référence des projets d'origine (UKit, TikTok) + carte de provenance
410
416
  ```
@@ -456,7 +462,8 @@ Conventions de contribution (discipline de test, invariants, structure des tests
456
462
  Le projet avance en deux grandes phases. La **Phase 1** — le socle, utilisable comme **bibliothèque**
457
463
  (in-process Python) et comme **service** (daemon + SDK) — est **terminée avec ce jalon** : un premier
458
464
  point de contrôle, à éprouver en conditions réelles avant d'attaquer la **Phase 2** (les deux Acts les
459
- plus lourds).
465
+ plus lourds). Entre les deux, une **Phase 1.5** durcit ce socle pour les workflows **récurrents et
466
+ réactifs** (planification, alertes, réactivité) — voir ci-dessous.
460
467
 
461
468
  ### Phase 1 — le socle réutilisable (terminée)
462
469
 
@@ -524,6 +531,81 @@ plus lourds).
524
531
  **Phase 1 terminée.** Aetherius est utilisable comme bibliothèque et comme service ; c'est le point de
525
532
  contrôle prévu pour l'éprouver en conditions réelles et corriger avant la suite.
526
533
 
534
+ ### Phase 1.5 — socle opérationnel (en cours)
535
+
536
+ Un palier intermédiaire, dans l'esprit du durcissement du socle : rendre Aetherius capable de porter
537
+ des workflows **récurrents et réactifs** (planifier un Blueprint, réagir aux données extraites,
538
+ alerter au bon moment) avant les Acts autonomes. Le cas fil rouge : surveiller un produit en rupture,
539
+ vérifier plusieurs fois par jour, alerter au retour en stock. Et, dans la même veine furtive que la
540
+ couche stealth, le rendre invisible **au niveau réseau** (proxy, rotation d'IP). Cadrage complet et
541
+ **spécifications par jalon** : [docs/phase-1.5/](docs/phase-1.5/README.md).
542
+
543
+ - [x] **Persistance (`store/`)** : état durable SQLite (stdlib) sous `~/.aetherius` — schedules,
544
+ historique des runs, état inter-run. Fondation des autres jalons. Le daemon y persiste désormais
545
+ l'historique de ses runs. [docs/store.md](docs/store.md),
546
+ [docs/phase-1.5/a-store.md](docs/phase-1.5/a-store.md).
547
+ - [x] **Réactivité et flux conditionnel** : garde d'étape `when` universelle (step sauté = statut
548
+ `skipped` + événement `step_skipped`) et actions `if`/`repeat`/`for_each` exécutées récursivement
549
+ par le moteur sur tous les Acts (validation récursive des branches, variable de boucle `as`,
550
+ rend la réutilisation de session Continuum exprimable). Exemples zéro config dans
551
+ `examples/vector/`. [docs/blueprint-schema.md](docs/blueprint-schema.md),
552
+ [docs/phase-1.5/b-flow.md](docs/phase-1.5/b-flow.md).
553
+ - [x] **Notifications natives** : couche d'alerte sans dépendance nouvelle (webhook générique,
554
+ Discord, Telegram, **ntfy** pour la push téléphone — un POST `httpx` chacun), action `notify`
555
+ Act-agnostique (handler partagé, se combine à `when`) + `NotifySink` de fin de run
556
+ (`failure`/`success`/`always`), registre de canaux prêt pour les plugins (Jalon E), échec d'envoi
557
+ contenu (jamais fatal au run, `delivered` exposé). La dédup au changement d'état est désormais
558
+ portée par le scheduler (Jalon D, politique `change`). Exemple zéro config :
559
+ `examples/vector/books-restock-notify.blueprint.json`. [docs/notifications.md](docs/notifications.md),
560
+ [docs/phase-1.5/c-notifications.md](docs/phase-1.5/c-notifications.md).
561
+ - [x] **Scheduler (daemon)** : rejeu persistant d'un Blueprint à heure fixe (cron, fuseau local,
562
+ DST gérés) ou par intervalle, plus le tir unique (`at`). Intégré au daemon (lifespan FastAPI,
563
+ tick 30 s) ; un run planifié passe par `RunManager.submit` — indiscernable d'un run manuel, avec
564
+ le lien `schedule_id` dans l'historique. CLI `aetherius schedule add|list|rm|pause|resume|run`
565
+ (écrit directement dans le store : marche daemon éteint) et API `/v1/schedules` (CRUD + tir
566
+ immédiat). Rattrapage des tirs manqués par politique `misfire` (`skip`/`run_once`/`run_all`) et
567
+ politique d'alerte par schedule (`failure`/`success`/`always`/`change` — dédup au changement
568
+ d'état via le store). **Écran Console dédié** : liste, pause/reprise, suppression, détail avec
569
+ historique et tir manuel (événements en direct), formulaire de création/édition guidé, raccourci
570
+ `s` depuis Library. Exemple zéro config : `examples/vector/quotes-watch.blueprint.json`.
571
+ [docs/scheduler.md](docs/scheduler.md),
572
+ [docs/phase-1.5/d-scheduler.md](docs/phase-1.5/d-scheduler.md).
573
+ - [x] **Actions custom / plugins** : points d'extension activés — un paquet tiers ajoute des
574
+ **actions** et des **canaux de notification** sans forker le cœur. Découverte par entry-points
575
+ (`aetherius.actions`, `aetherius.notify_channels`) chargée au démarrage (CLI, daemon, moteur
576
+ in-process) ; une action plugin embarque sa spec (visible du Studio et du validator, act-agnostique,
577
+ dispatchée en repli après les built-ins) ; gardes de collision (les built-ins restent prioritaires)
578
+ et pannes isolées (un plugin cassé est loggé et sauté, jamais fatal au démarrage). Plugin d'exemple
579
+ exécutable : `examples/plugins/` (action `demo.slugify` + canal `logfile`).
580
+ [docs/plugins.md](docs/plugins.md), [docs/phase-1.5/e-plugins.md](docs/phase-1.5/e-plugins.md).
581
+ - [x] **Déploiement always-on** : recette 24/7 vérifiée de bout en bout pour héberger le daemon sur
582
+ une machine allumée (VPS, Raspberry Pi, NAS) — la réponse honnête au « hors machine ». Deux voies
583
+ dans [`deploy/`](deploy/) : image Docker durcie (multi-stage, non-root, healthcheck, variante Act
584
+ II via `--build-arg BROWSER=1`) + `docker-compose.yml` (volume persistant unique `/data`, port
585
+ publié sur la loopback de l'hôte, Blueprints utilisateur montés) et service systemd utilisateur
586
+ (`enable-linger`, redémarrage automatique). Tout l'état durable (schedules, historique, profils)
587
+ vit sous `AETHERIUS_DATA_DIR` et survit aux redémarrages ; sécurité par défaut : loopback, et
588
+ exposer exige token + reverse proxy TLS. [docs/deployment.md](docs/deployment.md),
589
+ [docs/phase-1.5/f-deployment.md](docs/phase-1.5/f-deployment.md).
590
+ - [x] **Identité réseau** : option `options.proxy` de premier niveau atteignant les **deux** moteurs
591
+ (Vector httpx/curl_cffi, Continuum Playwright ; HTTP/HTTPS/SOCKS5). Rotation de l'IP par run
592
+ (`per_run`/`round_robin`/`random`/`sticky`, pool inline ou défaut d'environnement `AETHERIUS_PROXY_*`),
593
+ prévention de la fuite WebRTC (flag de lancement + init-script, liée au proxy), cohérence géo
594
+ (timezone/locale/langues alignés sur le pays de l'IP, écrasant le profil d'empreinte) et
595
+ impersonation TLS (JA3/JA4) pour Vector via l'extra `[network]`. Identifiants jamais stockés
596
+ (`{{ secrets.x }}`). Exemple : `examples/vector/ip-echo-proxy.blueprint.json` (nécessite un proxy).
597
+ [docs/network.md](docs/network.md), [docs/phase-1.5/g-network.md](docs/phase-1.5/g-network.md).
598
+ - [x] **Durcissement de l'empreinte** : les signaux restants sont fermés **de façon cohérente avec le
599
+ profil** — Canvas et AudioContext (bruit déterministe par profil, stable entre deux lectures),
600
+ énumération des polices (`measureText`), client hints (`Sec-CH-UA` / `navigator.userAgentData`
601
+ dérivés de l'UA du profil, la limite « UA-CH drift » est levée), dimensions d'écran /
602
+ `devicePixelRatio` et WebGL2. Vector (Act I) gagne une **identité d'en-têtes par défaut** (UA +
603
+ client hints + `Accept-Language` alignés) quand `options.stealth` nomme un profil, sans écraser les
604
+ en-têtes explicites du Blueprint ni rien changer aux runs sans stealth. Exemples zéro config :
605
+ `examples/continuum/fingerprint-hardening.blueprint.json` et
606
+ `examples/vector/http-headers-identity.blueprint.json`. [docs/stealth.md](docs/stealth.md),
607
+ [docs/phase-1.5/h-fingerprint.md](docs/phase-1.5/h-fingerprint.md).
608
+
527
609
  ### Phase 2 — les Acts autonomes (à venir)
528
610
 
529
611
  - [ ] Act III — Oracle (vision + entraînement).