euron-code 0.5.0__tar.gz → 0.5.1__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 (94) hide show
  1. {euron_code-0.5.0 → euron_code-0.5.1}/CHANGELOG.md +5 -0
  2. {euron_code-0.5.0 → euron_code-0.5.1}/PKG-INFO +1 -1
  3. {euron_code-0.5.0 → euron_code-0.5.1}/pyproject.toml +1 -1
  4. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/__init__.py +1 -1
  5. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/api.py +13 -0
  6. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_v5.py +27 -0
  7. {euron_code-0.5.0 → euron_code-0.5.1}/.gitignore +0 -0
  8. {euron_code-0.5.0 → euron_code-0.5.1}/LICENSE +0 -0
  9. {euron_code-0.5.0 → euron_code-0.5.1}/README.md +0 -0
  10. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/__main__.py +0 -0
  11. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/activity.py +0 -0
  12. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/agent.py +0 -0
  13. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/attachments.py +0 -0
  14. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/auth.py +0 -0
  15. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/builtin_skills/build-from-reference/SKILL.md +0 -0
  16. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/builtin_skills/explain-codebase/SKILL.md +0 -0
  17. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/builtin_skills/review/SKILL.md +0 -0
  18. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/builtin_skills/test-writer/SKILL.md +0 -0
  19. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/cache.py +0 -0
  20. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/checkpoints.py +0 -0
  21. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/cli.py +0 -0
  22. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/config.py +0 -0
  23. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/context.py +0 -0
  24. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/contextforge/LICENSE +0 -0
  25. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/contextforge/__init__.py +0 -0
  26. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/contextforge/text.py +0 -0
  27. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/contextforge/toolout.py +0 -0
  28. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/credentials.py +0 -0
  29. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/doctor.py +0 -0
  30. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/documents.py +0 -0
  31. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/error_hints.py +0 -0
  32. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/errorlog.py +0 -0
  33. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/frontmatter.py +0 -0
  34. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/hooks.py +0 -0
  35. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/keys.py +0 -0
  36. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/licensing.py +0 -0
  37. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/memory.py +0 -0
  38. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/permissions.py +0 -0
  39. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/project_setup.py +0 -0
  40. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/prompts.py +0 -0
  41. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/repl.py +0 -0
  42. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/repomap.py +0 -0
  43. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/rules.py +0 -0
  44. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/sessions.py +0 -0
  45. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/skills.py +0 -0
  46. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/textsafe.py +0 -0
  47. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/__init__.py +0 -0
  48. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/background.py +0 -0
  49. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/base.py +0 -0
  50. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/db.py +0 -0
  51. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/document.py +0 -0
  52. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/erie.py +0 -0
  53. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/fs.py +0 -0
  54. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/ignore.py +0 -0
  55. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/oss.py +0 -0
  56. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/reuse.py +0 -0
  57. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/search.py +0 -0
  58. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/shell.py +0 -0
  59. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/skill.py +0 -0
  60. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/symbols.py +0 -0
  61. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/task.py +0 -0
  62. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/todo.py +0 -0
  63. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/tools/web.py +0 -0
  64. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/trust.py +0 -0
  65. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/ui.py +0 -0
  66. {euron_code-0.5.0 → euron_code-0.5.1}/src/euron_code/usage_view.py +0 -0
  67. {euron_code-0.5.0 → euron_code-0.5.1}/tests/conftest.py +0 -0
  68. {euron_code-0.5.0 → euron_code-0.5.1}/tests/helpers.py +0 -0
  69. {euron_code-0.5.0 → euron_code-0.5.1}/tests/mock_gateway.py +0 -0
  70. {euron_code-0.5.0 → euron_code-0.5.1}/tests/serve_helper.py +0 -0
  71. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_agent_mock.py +0 -0
  72. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_api_shell.py +0 -0
  73. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_bench.py +0 -0
  74. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_cli_e2e.py +0 -0
  75. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_context_memory_sessions.py +0 -0
  76. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_db.py +0 -0
  77. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_erie.py +0 -0
  78. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_permissions.py +0 -0
  79. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_powershell_exit_codes.py +0 -0
  80. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_repl.py +0 -0
  81. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_search.py +0 -0
  82. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_textsafe.py +0 -0
  83. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_tools_fs.py +0 -0
  84. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_v2_rules_skills_hooks.py +0 -0
  85. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_v2_tokens_shortcuts.py +0 -0
  86. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_v2_usage_headers.py +0 -0
  87. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_v31_security.py +0 -0
  88. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_v3_accounts_value_setup.py +0 -0
  89. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_v3_activity.py +0 -0
  90. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_v3_attachments.py +0 -0
  91. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_v3_context.py +0 -0
  92. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_v3_live_repl.py +0 -0
  93. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_v3_single_login.py +0 -0
  94. {euron_code-0.5.0 → euron_code-0.5.1}/tests/test_v4.py +0 -0
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.1 (2026-11-05)
4
+
5
+ - Running `euron` again right after a run finished no longer says Euron Code is already running for
6
+ your account: the login is freed when Euron Code exits.
7
+
3
8
  ## 0.5.0 (2026-11-05)
4
9
 
5
10
  ### Build from references (V5 contract section 1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: euron-code
3
- Version: 0.5.0
3
+ Version: 0.5.1
4
4
  Summary: Euron Code: an agentic coding assistant in your terminal for Euron Plus and Super 30 students.
5
5
  Project-URL: Homepage, https://euron.one/code-agent
6
6
  Author-email: Euron <contact@euron.one>
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "euron-code"
7
- version = "0.5.0"
7
+ version = "0.5.1"
8
8
  description = "Euron Code: an agentic coding assistant in your terminal for Euron Plus and Super 30 students."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1,3 +1,3 @@
1
1
  """Euron Code: an agentic coding assistant for the terminal."""
2
2
 
3
- __version__ = "0.5.0"
3
+ __version__ = "0.5.1"
@@ -259,7 +259,20 @@ class Client:
259
259
  follow_redirects=False,
260
260
  )
261
261
 
262
+ def release_session(self) -> None:
263
+ """Free the one-login lock on exit, so the next run on this computer is not told
264
+ "already running" for two minutes. Best effort: a few seconds at most, never raises."""
265
+ sid = self.session_id
266
+ if not (self.api_key and valid_id(sid)):
267
+ return
268
+ try:
269
+ self._http.post(f"{self.base_url}/v1/session/release", timeout=3.0,
270
+ headers={**self._headers(), "X-Euron-Session": str(sid)})
271
+ except Exception:
272
+ pass
273
+
262
274
  def close(self) -> None:
275
+ self.release_session()
263
276
  self._http.close()
264
277
 
265
278
  def _headers(self) -> Dict[str, str]:
@@ -396,3 +396,30 @@ def test_form_placeholders_are_not_leftover_template_text():
396
396
  assert not PLACEHOLDER_RE.search(_FORM_HINT_RE.sub("", form))
397
397
  assert PLACEHOLDER_RE.search(_FORM_HINT_RE.sub("", "<h1>Your Name</h1>"))
398
398
  assert _PAST["ADAPT"] == "adapted" and _PAST["REUSE"] == "reused"
399
+
400
+
401
+ def test_close_releases_the_one_login_lock():
402
+ import httpx
403
+ from euron_code import api
404
+ seen = []
405
+
406
+ def handler(request):
407
+ seen.append((request.url.path, request.headers.get("x-euron-session"), request.headers.get("authorization")))
408
+ return httpx.Response(200, json={"released": True})
409
+
410
+ c = api.Client(api_key="euron-test-key", base_url="https://x.test/api/v1/code-agent",
411
+ transport=httpx.MockTransport(handler))
412
+ c.session_id = "20261105-181647-b6522b"
413
+ c.close()
414
+ assert seen == [("/api/v1/code-agent/v1/session/release", "20261105-181647-b6522b", "Bearer euron-test-key")]
415
+
416
+ def boom(request):
417
+ raise httpx.ConnectError("offline")
418
+
419
+ c2 = api.Client(api_key="k", base_url="https://x.test", transport=httpx.MockTransport(boom))
420
+ c2.session_id = "20261105-181647-b6522b"
421
+ c2.close() # never raises
422
+ c3 = api.Client(api_key=None, base_url="https://x.test", transport=httpx.MockTransport(handler))
423
+ c3.session_id = "20261105-181647-b6522b"
424
+ c3.close()
425
+ assert len(seen) == 1 # not logged in: nothing sent
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes