conduct-cli 0.6.19__tar.gz → 0.6.20__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.
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/PKG-INFO +1 -1
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/pyproject.toml +1 -1
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/hooks/session_start.py +79 -1
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli.egg-info/PKG-INFO +1 -1
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/README.md +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/setup.cfg +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/setup.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/__init__.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/api.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/guard.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/guardmcp.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/hook_precompact_template.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/hook_session_start_template.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/hook_stop_template.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/hook_template.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/hooks/__init__.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/hooks/base.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/hooks/posttooluse.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/hooks/precompact.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/hooks/pretooluse.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/hooks/session_parser.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/hooks/stop.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/log_util.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/main.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/mcp_server.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/memory.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli/paxel.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli.egg-info/SOURCES.txt +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli.egg-info/dependency_links.txt +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli.egg-info/entry_points.txt +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli.egg-info/requires.txt +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/src/conduct_cli.egg-info/top_level.txt +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/tests/test_bash_operator_signature.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/tests/test_command_word_matcher.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/tests/test_guard_policy.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/tests/test_guard_savings.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/tests/test_hook_syntax.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/tests/test_journal_drain.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/tests/test_log_util.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/tests/test_proxy_env.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/tests/test_signed_policy.py +0 -0
- {conduct_cli-0.6.19 → conduct_cli-0.6.20}/tests/test_switch.py +0 -0
|
@@ -57,12 +57,90 @@ def _check_proxy_token() -> None:
|
|
|
57
57
|
pass
|
|
58
58
|
|
|
59
59
|
|
|
60
|
+
def _backfill_prev_session(current_session_id: str, cwd: str | None) -> None:
|
|
61
|
+
"""Parse + PATCH the most recent completed session (the one that just ended).
|
|
62
|
+
|
|
63
|
+
Runs silently — never raises, never blocks the new session.
|
|
64
|
+
"""
|
|
65
|
+
try:
|
|
66
|
+
import re, urllib.request
|
|
67
|
+
from pathlib import Path as _P
|
|
68
|
+
|
|
69
|
+
claude_projects = _P.home() / ".claude" / "projects"
|
|
70
|
+
if not claude_projects.exists():
|
|
71
|
+
return
|
|
72
|
+
|
|
73
|
+
# find the project slug dir for this cwd
|
|
74
|
+
if cwd:
|
|
75
|
+
slug = re.sub(r"[^a-zA-Z0-9]", "-", cwd).strip("-")
|
|
76
|
+
project_dir = claude_projects / slug
|
|
77
|
+
else:
|
|
78
|
+
# fall back: pick most recently modified project dir
|
|
79
|
+
dirs = sorted(claude_projects.iterdir(), key=lambda d: d.stat().st_mtime, reverse=True)
|
|
80
|
+
project_dir = dirs[0] if dirs else None
|
|
81
|
+
|
|
82
|
+
if not project_dir or not project_dir.exists():
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
# pick the latest JSONL that isn't the current session
|
|
86
|
+
candidates = sorted(
|
|
87
|
+
(f for f in project_dir.glob("*.jsonl") if f.stem != current_session_id),
|
|
88
|
+
key=lambda f: f.stat().st_mtime,
|
|
89
|
+
reverse=True,
|
|
90
|
+
)
|
|
91
|
+
if not candidates:
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
prev_session_id = candidates[0].stem
|
|
95
|
+
|
|
96
|
+
from conduct_cli.hooks.session_parser import parse_session
|
|
97
|
+
data = parse_session("claude_code", prev_session_id, cwd)
|
|
98
|
+
|
|
99
|
+
cfg_path = _P.home() / ".conduct" / "config.json"
|
|
100
|
+
if not cfg_path.exists():
|
|
101
|
+
return
|
|
102
|
+
cfg = json.loads(cfg_path.read_text())
|
|
103
|
+
server = cfg.get("server", "").rstrip("/")
|
|
104
|
+
api_key = cfg.get("api_key", "")
|
|
105
|
+
workspace_id = cfg.get("workspace_id") or cfg.get("workspace", "")
|
|
106
|
+
if not server:
|
|
107
|
+
return
|
|
108
|
+
|
|
109
|
+
payload = json.dumps({
|
|
110
|
+
"intent": data.intent,
|
|
111
|
+
"tool_sequence": data.tool_sequence,
|
|
112
|
+
"session_parse_status": data.status,
|
|
113
|
+
"session_parser": data.parser,
|
|
114
|
+
}).encode()
|
|
115
|
+
req = urllib.request.Request(
|
|
116
|
+
f"{server}/guard/sessions/{prev_session_id}/intent",
|
|
117
|
+
data=payload,
|
|
118
|
+
headers={
|
|
119
|
+
"Content-Type": "application/json",
|
|
120
|
+
"X-API-Key": api_key,
|
|
121
|
+
"X-Workspace-ID": workspace_id,
|
|
122
|
+
},
|
|
123
|
+
method="PATCH",
|
|
124
|
+
)
|
|
125
|
+
urllib.request.urlopen(req, timeout=8)
|
|
126
|
+
except Exception:
|
|
127
|
+
pass
|
|
128
|
+
|
|
129
|
+
|
|
60
130
|
def main() -> None:
|
|
131
|
+
current_session_id = ""
|
|
132
|
+
cwd = None
|
|
61
133
|
try:
|
|
62
|
-
sys.stdin.read()
|
|
134
|
+
raw = sys.stdin.read()
|
|
135
|
+
hook_data = json.loads(raw) if raw.strip() else {}
|
|
136
|
+
current_session_id = hook_data.get("session_id", "")
|
|
137
|
+
cwd = hook_data.get("cwd")
|
|
63
138
|
except Exception:
|
|
64
139
|
pass
|
|
65
140
|
|
|
141
|
+
if current_session_id:
|
|
142
|
+
_backfill_prev_session(current_session_id, cwd)
|
|
143
|
+
|
|
66
144
|
_check_proxy_token()
|
|
67
145
|
|
|
68
146
|
if not SNAPSHOT_PATH.exists():
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|