htmlgraph 0.23.1__py3-none-any.whl → 0.23.2__py3-none-any.whl
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.
- htmlgraph/__init__.py +1 -1
- htmlgraph/event_log.py +28 -0
- htmlgraph/hooks/orchestrator.py +68 -4
- {htmlgraph-0.23.1.dist-info → htmlgraph-0.23.2.dist-info}/METADATA +1 -1
- {htmlgraph-0.23.1.dist-info → htmlgraph-0.23.2.dist-info}/RECORD +12 -12
- {htmlgraph-0.23.1.data → htmlgraph-0.23.2.data}/data/htmlgraph/dashboard.html +0 -0
- {htmlgraph-0.23.1.data → htmlgraph-0.23.2.data}/data/htmlgraph/styles.css +0 -0
- {htmlgraph-0.23.1.data → htmlgraph-0.23.2.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
- {htmlgraph-0.23.1.data → htmlgraph-0.23.2.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
- {htmlgraph-0.23.1.data → htmlgraph-0.23.2.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
- {htmlgraph-0.23.1.dist-info → htmlgraph-0.23.2.dist-info}/WHEEL +0 -0
- {htmlgraph-0.23.1.dist-info → htmlgraph-0.23.2.dist-info}/entry_points.txt +0 -0
htmlgraph/__init__.py
CHANGED
htmlgraph/event_log.py
CHANGED
|
@@ -38,6 +38,22 @@ class EventRecord:
|
|
|
38
38
|
session_status: str | None = None
|
|
39
39
|
file_paths: list[str] | None = None
|
|
40
40
|
payload: dict[str, Any] | None = None
|
|
41
|
+
# Phase 1: Enhanced Event Data Schema for multi-AI delegation tracking
|
|
42
|
+
delegated_to_ai: str | None = (
|
|
43
|
+
None # "gemini", "codex", "copilot", "claude", or None
|
|
44
|
+
)
|
|
45
|
+
task_id: str | None = None # Unique task ID for parallel tracking
|
|
46
|
+
task_status: str | None = (
|
|
47
|
+
None # "pending", "running", "completed", "failed", "timeout"
|
|
48
|
+
)
|
|
49
|
+
model_selected: str | None = None # Specific model (e.g., "gemini-2.0-flash")
|
|
50
|
+
complexity_level: str | None = None # "low", "medium", "high", "very-high"
|
|
51
|
+
budget_mode: str | None = None # "free", "balanced", "performance"
|
|
52
|
+
execution_duration_seconds: float | None = None # How long delegation took
|
|
53
|
+
tokens_estimated: int | None = None # Estimated token usage
|
|
54
|
+
tokens_actual: int | None = None # Actual token usage
|
|
55
|
+
cost_usd: float | None = None # Calculated cost
|
|
56
|
+
task_findings: str | None = None # Results from delegated task
|
|
41
57
|
|
|
42
58
|
def to_json(self) -> dict[str, Any]:
|
|
43
59
|
return {
|
|
@@ -56,6 +72,18 @@ class EventRecord:
|
|
|
56
72
|
"session_status": self.session_status,
|
|
57
73
|
"file_paths": self.file_paths or [],
|
|
58
74
|
"payload": self.payload,
|
|
75
|
+
# Delegation fields
|
|
76
|
+
"delegated_to_ai": self.delegated_to_ai,
|
|
77
|
+
"task_id": self.task_id,
|
|
78
|
+
"task_status": self.task_status,
|
|
79
|
+
"model_selected": self.model_selected,
|
|
80
|
+
"complexity_level": self.complexity_level,
|
|
81
|
+
"budget_mode": self.budget_mode,
|
|
82
|
+
"execution_duration_seconds": self.execution_duration_seconds,
|
|
83
|
+
"tokens_estimated": self.tokens_estimated,
|
|
84
|
+
"tokens_actual": self.tokens_actual,
|
|
85
|
+
"cost_usd": self.cost_usd,
|
|
86
|
+
"task_findings": self.task_findings,
|
|
59
87
|
}
|
|
60
88
|
|
|
61
89
|
|
htmlgraph/hooks/orchestrator.py
CHANGED
|
@@ -107,6 +107,23 @@ def is_allowed_orchestrator_operation(tool: str, params: dict) -> tuple[bool, st
|
|
|
107
107
|
- reason_if_not: Explanation if blocked (empty if allowed)
|
|
108
108
|
- category: Operation category for logging
|
|
109
109
|
"""
|
|
110
|
+
# Get enforcement level from manager
|
|
111
|
+
try:
|
|
112
|
+
cwd = Path.cwd()
|
|
113
|
+
graph_dir = cwd / ".htmlgraph"
|
|
114
|
+
if not graph_dir.exists():
|
|
115
|
+
for parent in [cwd.parent, cwd.parent.parent, cwd.parent.parent.parent]:
|
|
116
|
+
candidate = parent / ".htmlgraph"
|
|
117
|
+
if candidate.exists():
|
|
118
|
+
graph_dir = candidate
|
|
119
|
+
break
|
|
120
|
+
manager = OrchestratorModeManager(graph_dir)
|
|
121
|
+
enforcement_level = (
|
|
122
|
+
manager.get_enforcement_level() if manager.is_enabled() else "guidance"
|
|
123
|
+
)
|
|
124
|
+
except Exception:
|
|
125
|
+
enforcement_level = "guidance"
|
|
126
|
+
|
|
110
127
|
# Use OrchestratorValidator for comprehensive validation
|
|
111
128
|
validator = OrchestratorValidator()
|
|
112
129
|
result, reason = validator.validate_tool_use(tool, params)
|
|
@@ -121,6 +138,10 @@ def is_allowed_orchestrator_operation(tool: str, params: dict) -> tuple[bool, st
|
|
|
121
138
|
if tool in ["Task", "AskUserQuestion", "TodoWrite"]:
|
|
122
139
|
return True, "", "orchestrator-core"
|
|
123
140
|
|
|
141
|
+
# FIX #2: Block Skills in strict mode (must be invoked via Task delegation)
|
|
142
|
+
if tool == "Skill" and enforcement_level == "strict":
|
|
143
|
+
return False, "Skills must be invoked via Task delegation", "skill-blocked"
|
|
144
|
+
|
|
124
145
|
# Category 2: SDK Operations - Always allowed
|
|
125
146
|
if tool == "Bash":
|
|
126
147
|
command = params.get("command", "")
|
|
@@ -141,11 +162,51 @@ def is_allowed_orchestrator_operation(tool: str, params: dict) -> tuple[bool, st
|
|
|
141
162
|
if "from htmlgraph import" in command or "import htmlgraph" in command:
|
|
142
163
|
return True, "", "sdk-inline"
|
|
143
164
|
|
|
165
|
+
# FIX #3: Check if bash command is in allowed whitelist (strict mode only)
|
|
166
|
+
# If we've gotten here, it's not a whitelisted command above
|
|
167
|
+
# Block non-whitelisted bash commands in strict mode
|
|
168
|
+
if enforcement_level == "strict":
|
|
169
|
+
# Check if it's a blocked test/build pattern (handled below)
|
|
170
|
+
blocked_patterns = [
|
|
171
|
+
r"^npm (run|test|build)",
|
|
172
|
+
r"^pytest",
|
|
173
|
+
r"^uv run pytest",
|
|
174
|
+
r"^python -m pytest",
|
|
175
|
+
r"^cargo (build|test)",
|
|
176
|
+
r"^mvn (compile|test|package)",
|
|
177
|
+
r"^make (test|build)",
|
|
178
|
+
]
|
|
179
|
+
is_blocked_pattern = any(
|
|
180
|
+
re.match(pattern, command) for pattern in blocked_patterns
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
if not is_blocked_pattern:
|
|
184
|
+
# Not a specifically blocked pattern, but also not whitelisted
|
|
185
|
+
# In strict mode, we should delegate
|
|
186
|
+
return (
|
|
187
|
+
False,
|
|
188
|
+
f"Bash command not in allowed list. Delegate to subagent.\n\n"
|
|
189
|
+
f"Command: {command[:100]}",
|
|
190
|
+
"bash-blocked",
|
|
191
|
+
)
|
|
192
|
+
|
|
144
193
|
# Category 3: Quick Lookups - Single operations only
|
|
145
194
|
if tool in ["Read", "Grep", "Glob"]:
|
|
146
195
|
# Check tool history to see if this is a single lookup or part of a sequence
|
|
147
196
|
history = load_tool_history()
|
|
148
197
|
|
|
198
|
+
# FIX #4: Check for mixed exploration pattern
|
|
199
|
+
exploration_count = sum(
|
|
200
|
+
1 for h in history[-5:] if h["tool"] in ["Read", "Grep", "Glob"]
|
|
201
|
+
)
|
|
202
|
+
if exploration_count >= 3 and enforcement_level == "strict":
|
|
203
|
+
return (
|
|
204
|
+
False,
|
|
205
|
+
"Multiple exploration calls detected. Delegate to Explorer agent.\n\n"
|
|
206
|
+
"Use Task tool with explorer subagent.",
|
|
207
|
+
"exploration-blocked",
|
|
208
|
+
)
|
|
209
|
+
|
|
149
210
|
# Look at last 3 tool calls
|
|
150
211
|
recent_same_tool = sum(1 for h in history[-3:] if h["tool"] == tool)
|
|
151
212
|
|
|
@@ -181,7 +242,7 @@ def is_allowed_orchestrator_operation(tool: str, params: dict) -> tuple[bool, st
|
|
|
181
242
|
command = params.get("command", "")
|
|
182
243
|
|
|
183
244
|
# Block compilation, testing, building (should be in subagent)
|
|
184
|
-
|
|
245
|
+
test_build_patterns: list[tuple[str, str]] = [
|
|
185
246
|
(r"^npm (run|test|build)", "npm test/build"),
|
|
186
247
|
(r"^pytest", "pytest"),
|
|
187
248
|
(r"^uv run pytest", "pytest"),
|
|
@@ -191,7 +252,7 @@ def is_allowed_orchestrator_operation(tool: str, params: dict) -> tuple[bool, st
|
|
|
191
252
|
(r"^make (test|build)", "make test/build"),
|
|
192
253
|
]
|
|
193
254
|
|
|
194
|
-
for pattern, name in
|
|
255
|
+
for pattern, name in test_build_patterns:
|
|
195
256
|
if re.match(pattern, command):
|
|
196
257
|
return (
|
|
197
258
|
False,
|
|
@@ -200,8 +261,11 @@ def is_allowed_orchestrator_operation(tool: str, params: dict) -> tuple[bool, st
|
|
|
200
261
|
"test-build-blocked",
|
|
201
262
|
)
|
|
202
263
|
|
|
203
|
-
#
|
|
204
|
-
|
|
264
|
+
# FIX #1: Remove "allowed-default" escape hatch in strict mode
|
|
265
|
+
if enforcement_level == "strict":
|
|
266
|
+
return False, "Not in allowed whitelist", "strict-blocked"
|
|
267
|
+
else:
|
|
268
|
+
return True, "Allowed in guidance mode", "guidance-allowed"
|
|
205
269
|
|
|
206
270
|
|
|
207
271
|
def create_task_suggestion(tool: str, params: dict) -> str:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: htmlgraph
|
|
3
|
-
Version: 0.23.
|
|
3
|
+
Version: 0.23.2
|
|
4
4
|
Summary: HTML is All You Need - Graph database on web standards
|
|
5
5
|
Project-URL: Homepage, https://github.com/Shakes-tzd/htmlgraph
|
|
6
6
|
Project-URL: Documentation, https://github.com/Shakes-tzd/htmlgraph#readme
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
htmlgraph/__init__.py,sha256=
|
|
1
|
+
htmlgraph/__init__.py,sha256=CpjmLuef0RQAd4Op9FbEPyFMeLmaavFZMejnMU9FbWM,4979
|
|
2
2
|
htmlgraph/agent_detection.py,sha256=MG1kx9S-ey_Wi84hJTwwgw6VDvYEbUpygmDjGPhHcUA,3805
|
|
3
3
|
htmlgraph/agent_registry.py,sha256=Usa_35by7p5gtpvHO7K3AcGimnorw-FzgPVa3cWTQ58,9448
|
|
4
4
|
htmlgraph/agents.py,sha256=Yvu6x1nOfrW2WhRTAHiCuSpvqoVJXx1Mkzd59kwEczw,33466
|
|
@@ -12,7 +12,7 @@ htmlgraph/dependency_models.py,sha256=eKpBz9y_pTE5E8baESqHyGUDj5-uXokVd2Bx3ZogAy
|
|
|
12
12
|
htmlgraph/deploy.py,sha256=kM_IMa3PmKpQf4YVH57aL9uV5IfpVJgaj-IFsgAKIbY,17771
|
|
13
13
|
htmlgraph/deployment_models.py,sha256=8pjvfe0YmExuYg65D4jO4kET52HaG8WhcArWXOJpfCQ,16064
|
|
14
14
|
htmlgraph/edge_index.py,sha256=epeUiTj1Hm-NQj8WCWjSUypG1e8Z2hJulNT9drHstcM,14937
|
|
15
|
-
htmlgraph/event_log.py,sha256=
|
|
15
|
+
htmlgraph/event_log.py,sha256=zJUefAaz97LvoVA-pi8uVMcCqA_pyS_saVczbioQf-Q,9372
|
|
16
16
|
htmlgraph/event_migration.py,sha256=7vocfwy-E6_D8_Aeql630FrlBXppIYp1iLmZ_cw_ras,2512
|
|
17
17
|
htmlgraph/exceptions.py,sha256=o_BPNQXtv9zaejbiItDVBK7kcGvYbh4Icj5NXmDSLeU,1592
|
|
18
18
|
htmlgraph/file_watcher.py,sha256=qwwmDkWnKLPp8a_48VrtJZo6HcoYPRz1KMAD39yCV7U,6296
|
|
@@ -104,7 +104,7 @@ htmlgraph/hooks/__init__.py,sha256=jL2HyCoFWQQ8l-4-EAlypDxPalNE3JBfDyELYWAg-g0,8
|
|
|
104
104
|
htmlgraph/hooks/event_tracker.py,sha256=KQcIWbhNJser6Tip87oUAPQJgUAAKESKE5ARQasLtCM,23301
|
|
105
105
|
htmlgraph/hooks/hooks-config.example.json,sha256=tXpk-U-FZzGOoNJK2uiDMbIHCYEHA794J-El0fBwkqg,197
|
|
106
106
|
htmlgraph/hooks/installer.py,sha256=nOctCFDEV7BEh7ZzxNY-apu1KZG0SHPMq74UPIOChqY,11756
|
|
107
|
-
htmlgraph/hooks/orchestrator.py,sha256=
|
|
107
|
+
htmlgraph/hooks/orchestrator.py,sha256=rKRx5EYED-BFQrnAJ_roIjpP8GOs3RKDpulDouA29K0,19781
|
|
108
108
|
htmlgraph/hooks/orchestrator_reflector.py,sha256=j3kZge33m42CEUVYiufiz7mf7Qm4DimnsRZKjbpZStA,5154
|
|
109
109
|
htmlgraph/hooks/post-checkout.sh,sha256=Hsr5hqD54jisGbtqf7-Z-G_b6XNGcee_CZRYaKYzWzU,615
|
|
110
110
|
htmlgraph/hooks/post-commit.sh,sha256=if65jNGZnEWsZPq_iYDNYunrZ1cmjPUEUbh6_4vfpOE,511
|
|
@@ -134,12 +134,12 @@ htmlgraph/services/claiming.py,sha256=HcrltEJKN72mxuD7fGuXWeh1U0vwhjMvhZcFc02Eiy
|
|
|
134
134
|
htmlgraph/templates/AGENTS.md.template,sha256=f96h7V6ygwj-v-fanVI48eYMxR6t_se4bet1H4ZsDpI,7642
|
|
135
135
|
htmlgraph/templates/CLAUDE.md.template,sha256=h1kG2hTX2XYig2KszsHBfzrwa_4Cfcq2Pj4SwqzeDlM,1984
|
|
136
136
|
htmlgraph/templates/GEMINI.md.template,sha256=gAGzE53Avki87BM_otqy5HdcYCoLsHgqaKjVzNzPMX8,1622
|
|
137
|
-
htmlgraph-0.23.
|
|
138
|
-
htmlgraph-0.23.
|
|
139
|
-
htmlgraph-0.23.
|
|
140
|
-
htmlgraph-0.23.
|
|
141
|
-
htmlgraph-0.23.
|
|
142
|
-
htmlgraph-0.23.
|
|
143
|
-
htmlgraph-0.23.
|
|
144
|
-
htmlgraph-0.23.
|
|
145
|
-
htmlgraph-0.23.
|
|
137
|
+
htmlgraph-0.23.2.data/data/htmlgraph/dashboard.html,sha256=rkZYjSnPbUuAm35QMpCNWemenYqQTdkkumCX2hhe8Dc,173537
|
|
138
|
+
htmlgraph-0.23.2.data/data/htmlgraph/styles.css,sha256=oDUSC8jG-V-hKojOBO9J88hxAeY2wJrBYTq0uCwX_Y4,7135
|
|
139
|
+
htmlgraph-0.23.2.data/data/htmlgraph/templates/AGENTS.md.template,sha256=f96h7V6ygwj-v-fanVI48eYMxR6t_se4bet1H4ZsDpI,7642
|
|
140
|
+
htmlgraph-0.23.2.data/data/htmlgraph/templates/CLAUDE.md.template,sha256=h1kG2hTX2XYig2KszsHBfzrwa_4Cfcq2Pj4SwqzeDlM,1984
|
|
141
|
+
htmlgraph-0.23.2.data/data/htmlgraph/templates/GEMINI.md.template,sha256=gAGzE53Avki87BM_otqy5HdcYCoLsHgqaKjVzNzPMX8,1622
|
|
142
|
+
htmlgraph-0.23.2.dist-info/METADATA,sha256=sXhGvvPyc0ZtSB0FvkXu4A_gaKqs9x0uu0pS8Yb2kh8,7753
|
|
143
|
+
htmlgraph-0.23.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
144
|
+
htmlgraph-0.23.2.dist-info/entry_points.txt,sha256=EaUbjA_bbDwEO_XDLEGMeK8aQP-ZnHiUTkLshyKDyB8,98
|
|
145
|
+
htmlgraph-0.23.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|