sessiontools 0.0.1__tar.gz → 0.0.3__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.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sessiontools
3
- Version: 0.0.1
3
+ Version: 0.0.3
4
4
  Summary: The harness layer: sessions, status and idle, one driver per harness - a library first
5
5
  Author: Cora 7
6
6
  Author-email: Cora 7 <ai-cora@failmode.com>
7
- Requires-Python: >=3.13
7
+ Requires-Python: >=3.11
@@ -1,11 +1,16 @@
1
1
  [project]
2
2
  name = "sessiontools"
3
- version = "0.0.1"
3
+ version = "0.0.3"
4
4
  description = "The harness layer: sessions, status and idle, one driver per harness - a library first"
5
5
  authors = [
6
6
  { name = "Cora 7", email = "ai-cora@failmode.com" }
7
7
  ]
8
- requires-python = ">=3.13"
8
+ # >=3.11, not the recipe's >=3.13: sessionmail (the first consumer) declares
9
+ # >=3.11, and uv resolves for EVERY version a project allows, so a stricter
10
+ # floor here made sessionmail's `uv sync` unsatisfiable (Pip, 13:02 Thu
11
+ # 2026-09-17). Measured: the suite passes on 3.11, 3.12 and 3.13; nothing in
12
+ # the tree needs 3.13.
13
+ requires-python = ">=3.11"
9
14
  # ZERO runtime dependencies, on purpose: sessionmail (click + mcp) will
10
15
  # depend on this, and a stranger installing sessionmail must be happy to
11
16
  # pull it. A library first.
@@ -6,6 +6,7 @@ cutover (Mike, voice 12:18 Thu 2026-09-17), and the one that arrives then
6
6
  is `session`, whose verbs the fleet's callers are already written to.
7
7
 
8
8
  from sessiontools import sessions, find, idle_seconds
9
+ from sessiontools import session_id, current, SESSION_ID_VARS
9
10
 
10
11
  Every function speaks OUR words - busy, not busy, unknown - never a
11
12
  harness's. The first driver is `claude_code`; the day a harness changes a
@@ -17,10 +18,13 @@ from __future__ import annotations
17
18
  from importlib.metadata import PackageNotFoundError, version
18
19
 
19
20
  from sessiontools.claude_code import (
21
+ SESSION_ID_VARS,
20
22
  SIDECAR_DIR_ENV,
21
23
  Session,
24
+ current,
22
25
  find,
23
26
  idle_seconds,
27
+ session_id,
24
28
  sessions,
25
29
  sidecar_dir,
26
30
  )
@@ -31,11 +35,14 @@ except PackageNotFoundError: # a checkout that is not installed
31
35
  __version__ = "0+unknown"
32
36
 
33
37
  __all__ = [
38
+ "SESSION_ID_VARS",
34
39
  "SIDECAR_DIR_ENV",
35
40
  "Session",
36
41
  "__version__",
42
+ "current",
37
43
  "find",
38
44
  "idle_seconds",
45
+ "session_id",
39
46
  "sessions",
40
47
  "sidecar_dir",
41
48
  ]
@@ -109,6 +109,42 @@ def find(session_id: str, env: dict[str, str] | None = None) -> Session | None:
109
109
  return None
110
110
 
111
111
 
112
+ #: Where Claude Code puts THIS session's id, first non-blank wins, in this
113
+ #: order (Mike, voice 20:36-20:41 Wed 2026-09-23). The chain was written
114
+ #: three times and never shared; this is the one copy. Public, so a caller
115
+ #: that needs the names (to scrub a child's environment, say) reads them
116
+ #: here instead of spelling them again.
117
+ SESSION_ID_VARS = ("CLAUDE_CODE_SESSION_ID", "CLAUDE_SESSION_ID")
118
+
119
+
120
+ def session_id(env: dict[str, str] | None = None) -> str | None:
121
+ """This session's id, from the environment ONLY; None when there is none.
122
+
123
+ Never the disk: the pager needs the id before Claude Code has written
124
+ its sidecar. The first NON-BLANK variable in SESSION_ID_VARS wins, and
125
+ its value is stripped - the rule sessionmail's `_seat.session_id`
126
+ already keeps (sessionmail 0c010ed, src/sessionmail/_seat.py:59
127
+ SESSION_VARS, :930 session_id), except that no id is None here, not
128
+ that module's `-` marks-line placeholder.
129
+ """
130
+ env = os.environ if env is None else env
131
+ for var in SESSION_ID_VARS:
132
+ value = (env.get(var) or "").strip()
133
+ if value:
134
+ return value
135
+ return None
136
+
137
+
138
+ def current(env: dict[str, str] | None = None) -> Session | None:
139
+ """This session, read from its sidecar: `find(session_id(env))`.
140
+
141
+ None when the environment names no session, or when no sidecar names
142
+ the one it does. Read-only, like everything in this driver.
143
+ """
144
+ sid = session_id(env)
145
+ return None if sid is None else find(sid, env)
146
+
147
+
112
148
  def idle_seconds(session_id: str, now: float | None = None,
113
149
  env: dict[str, str] | None = None) -> float | None:
114
150
  """The one number the pager wants: 0 while busy, else seconds since