hcom 0.1.5__py3-none-any.whl → 0.1.7__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.
Potentially problematic release.
This version of hcom might be problematic. Click here for more details.
- hcom/__init__.py +1 -1
- hcom/__main__.py +70 -38
- {hcom-0.1.5.dist-info → hcom-0.1.7.dist-info}/METADATA +14 -13
- hcom-0.1.7.dist-info/RECORD +7 -0
- hcom-0.1.5.dist-info/RECORD +0 -7
- {hcom-0.1.5.dist-info → hcom-0.1.7.dist-info}/WHEEL +0 -0
- {hcom-0.1.5.dist-info → hcom-0.1.7.dist-info}/entry_points.txt +0 -0
- {hcom-0.1.5.dist-info → hcom-0.1.7.dist-info}/top_level.txt +0 -0
hcom/__init__.py
CHANGED
hcom/__main__.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""
|
|
3
3
|
hcom - Claude Hook Comms
|
|
4
|
-
|
|
4
|
+
Lightweight CLI tool for real-time communication between Claude Code subagents using hooks
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import os
|
|
@@ -170,27 +170,22 @@ def get_config_value(key, default=None):
|
|
|
170
170
|
return config.get(key, default)
|
|
171
171
|
|
|
172
172
|
def get_hook_command():
|
|
173
|
-
"""
|
|
173
|
+
"""Get hook command with silent fallback
|
|
174
|
+
|
|
175
|
+
Uses ${HCOM:-true} for clean paths, conditional for paths with spaces.
|
|
176
|
+
Both approaches exit silently (code 0) when not launched via 'hcom open'.
|
|
177
|
+
"""
|
|
174
178
|
python_path = sys.executable
|
|
175
179
|
script_path = os.path.abspath(__file__)
|
|
176
180
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
for char in problematic_chars)
|
|
183
|
-
|
|
184
|
-
if has_problematic_chars:
|
|
185
|
-
# Use direct paths with proper escaping
|
|
186
|
-
# Escape backslashes first, then quotes
|
|
187
|
-
escaped_python = python_path.replace('\\', '\\\\').replace('"', '\\"')
|
|
188
|
-
escaped_script = script_path.replace('\\', '\\\\').replace('"', '\\"')
|
|
189
|
-
return f'"{escaped_python}" "{escaped_script}"', {}
|
|
181
|
+
if ' ' in python_path or ' ' in script_path:
|
|
182
|
+
# Paths with spaces: use conditional check
|
|
183
|
+
escaped_python = shlex.quote(python_path)
|
|
184
|
+
escaped_script = shlex.quote(script_path)
|
|
185
|
+
return f'[ "${{HCOM_ACTIVE}}" = "1" ] && {escaped_python} {escaped_script} || true', {}
|
|
190
186
|
else:
|
|
191
|
-
#
|
|
192
|
-
|
|
193
|
-
return '$HCOM', env_vars
|
|
187
|
+
# Clean paths: use environment variable
|
|
188
|
+
return '${HCOM:-true}', {}
|
|
194
189
|
|
|
195
190
|
def build_claude_env():
|
|
196
191
|
"""Build environment variables for Claude instances"""
|
|
@@ -206,9 +201,11 @@ def build_claude_env():
|
|
|
206
201
|
|
|
207
202
|
env.update(config.get('env_overrides', {}))
|
|
208
203
|
|
|
209
|
-
#
|
|
210
|
-
|
|
211
|
-
|
|
204
|
+
# Set HCOM only for clean paths (spaces handled differently)
|
|
205
|
+
python_path = sys.executable
|
|
206
|
+
script_path = os.path.abspath(__file__)
|
|
207
|
+
if ' ' not in python_path and ' ' not in script_path:
|
|
208
|
+
env['HCOM'] = f'{python_path} {script_path}'
|
|
212
209
|
|
|
213
210
|
return env
|
|
214
211
|
|
|
@@ -265,7 +262,7 @@ def send_message(from_instance, message):
|
|
|
265
262
|
except Exception:
|
|
266
263
|
return False
|
|
267
264
|
|
|
268
|
-
def should_deliver_message(msg, instance_name):
|
|
265
|
+
def should_deliver_message(msg, instance_name, all_instance_names=None):
|
|
269
266
|
"""Check if message should be delivered based on @-mentions"""
|
|
270
267
|
text = msg['message']
|
|
271
268
|
|
|
@@ -277,11 +274,22 @@ def should_deliver_message(msg, instance_name):
|
|
|
277
274
|
if not mentions:
|
|
278
275
|
return True
|
|
279
276
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
277
|
+
# Check if this instance matches any mention
|
|
278
|
+
this_instance_matches = any(instance_name.lower().startswith(mention.lower()) for mention in mentions)
|
|
279
|
+
|
|
280
|
+
if this_instance_matches:
|
|
281
|
+
return True
|
|
282
|
+
|
|
283
|
+
# If we have all_instance_names, check if ANY mention matches ANY instance
|
|
284
|
+
if all_instance_names:
|
|
285
|
+
any_mention_matches = any(
|
|
286
|
+
any(name.lower().startswith(mention.lower()) for name in all_instance_names)
|
|
287
|
+
for mention in mentions
|
|
288
|
+
)
|
|
289
|
+
if not any_mention_matches:
|
|
290
|
+
return True # No matches anywhere = broadcast to all
|
|
283
291
|
|
|
284
|
-
return False
|
|
292
|
+
return False # This instance doesn't match, but others might
|
|
285
293
|
|
|
286
294
|
# ==================== Parsing and Helper Functions ====================
|
|
287
295
|
|
|
@@ -423,15 +431,22 @@ def _remove_hcom_hooks_from_settings(settings):
|
|
|
423
431
|
|
|
424
432
|
# Patterns to match any hcom hook command
|
|
425
433
|
# - $HCOM post/stop/notify
|
|
434
|
+
# - ${HCOM:-...} post/stop/notify
|
|
435
|
+
# - [ "${HCOM_ACTIVE}" = "1" ] && ... hcom.py ... || true
|
|
426
436
|
# - hcom post/stop/notify
|
|
437
|
+
# - uvx hcom post/stop/notify
|
|
427
438
|
# - /path/to/hcom.py post/stop/notify
|
|
439
|
+
# - sh -c "[ ... ] && ... hcom ..."
|
|
428
440
|
# - "/path with spaces/python" "/path with spaces/hcom.py" post/stop/notify
|
|
429
441
|
# - '/path/to/python' '/path/to/hcom.py' post/stop/notify
|
|
430
442
|
hcom_patterns = [
|
|
431
|
-
r'
|
|
443
|
+
r'\$\{?HCOM', # Environment variable (with or without braces)
|
|
444
|
+
r'\bHCOM_ACTIVE.*hcom\.py', # Conditional with HCOM_ACTIVE check
|
|
432
445
|
r'\bhcom\s+(post|stop|notify)\b', # Direct hcom command
|
|
446
|
+
r'\buvx\s+hcom\s+(post|stop|notify)\b', # uvx hcom command
|
|
433
447
|
r'hcom\.py["\']?\s+(post|stop|notify)\b', # hcom.py with optional quote
|
|
434
448
|
r'["\'][^"\']*hcom\.py["\']?\s+(post|stop|notify)\b', # Quoted path with hcom.py
|
|
449
|
+
r'sh\s+-c.*hcom', # Shell wrapper with hcom
|
|
435
450
|
]
|
|
436
451
|
compiled_patterns = [re.compile(pattern) for pattern in hcom_patterns]
|
|
437
452
|
|
|
@@ -713,7 +728,7 @@ def setup_hooks():
|
|
|
713
728
|
if hcom_send_permission not in settings['permissions']['allow']:
|
|
714
729
|
settings['permissions']['allow'].append(hcom_send_permission)
|
|
715
730
|
|
|
716
|
-
# Get the hook command
|
|
731
|
+
# Get the hook command template
|
|
717
732
|
hook_cmd_base, _ = get_hook_command()
|
|
718
733
|
|
|
719
734
|
# Add PostToolUse hook
|
|
@@ -881,10 +896,11 @@ def get_new_messages(instance_name):
|
|
|
881
896
|
# Filter messages:
|
|
882
897
|
# 1. Exclude own messages
|
|
883
898
|
# 2. Apply @-mention filtering
|
|
899
|
+
all_instance_names = list(positions.keys())
|
|
884
900
|
messages = []
|
|
885
901
|
for msg in all_messages:
|
|
886
902
|
if msg['from'] != instance_name:
|
|
887
|
-
if should_deliver_message(msg, instance_name):
|
|
903
|
+
if should_deliver_message(msg, instance_name, all_instance_names):
|
|
888
904
|
messages.append(msg)
|
|
889
905
|
|
|
890
906
|
# Update position to end of file
|
|
@@ -1280,18 +1296,21 @@ def cmd_help():
|
|
|
1280
1296
|
|
|
1281
1297
|
Usage:
|
|
1282
1298
|
hcom open [n] Launch n Claude instances
|
|
1283
|
-
hcom open
|
|
1299
|
+
hcom open <agent> Launch named agent from .claude/agents/
|
|
1300
|
+
hcom open --prefix <team> n Launch n instances with team prefix
|
|
1284
1301
|
hcom watch View conversation dashboard
|
|
1285
|
-
hcom clear
|
|
1286
|
-
hcom cleanup
|
|
1287
|
-
hcom cleanup --all
|
|
1288
|
-
hcom help
|
|
1302
|
+
hcom clear Clear and archive conversation
|
|
1303
|
+
hcom cleanup Remove hooks from current directory
|
|
1304
|
+
hcom cleanup --all Remove hooks from all tracked directories
|
|
1305
|
+
hcom help Show this help
|
|
1289
1306
|
|
|
1290
1307
|
Automation:
|
|
1291
|
-
hcom send 'msg'
|
|
1292
|
-
hcom send '@prefix msg'
|
|
1293
|
-
hcom watch --logs
|
|
1294
|
-
hcom watch --status
|
|
1308
|
+
hcom send 'msg' Send message
|
|
1309
|
+
hcom send '@prefix msg' Send to specific instances
|
|
1310
|
+
hcom watch --logs Show logs
|
|
1311
|
+
hcom watch --status Show status
|
|
1312
|
+
|
|
1313
|
+
Docs: https://raw.githubusercontent.com/aannoo/claude-hook-comms/main/README.md""")
|
|
1295
1314
|
return 0
|
|
1296
1315
|
|
|
1297
1316
|
def cmd_open(*args):
|
|
@@ -1779,6 +1798,19 @@ def cmd_send(message):
|
|
|
1779
1798
|
print(f"Error: {error}", file=sys.stderr)
|
|
1780
1799
|
return 1
|
|
1781
1800
|
|
|
1801
|
+
# Check for unmatched mentions (minimal warning)
|
|
1802
|
+
mentions = MENTION_PATTERN.findall(message)
|
|
1803
|
+
if mentions and pos_file.exists():
|
|
1804
|
+
try:
|
|
1805
|
+
positions = load_positions(pos_file)
|
|
1806
|
+
all_instances = list(positions.keys())
|
|
1807
|
+
unmatched = [m for m in mentions
|
|
1808
|
+
if not any(name.lower().startswith(m.lower()) for name in all_instances)]
|
|
1809
|
+
if unmatched:
|
|
1810
|
+
print(f"Note: @{', @'.join(unmatched)} don't match any instances - broadcasting to all")
|
|
1811
|
+
except Exception:
|
|
1812
|
+
pass # Don't fail on warning
|
|
1813
|
+
|
|
1782
1814
|
# Send message
|
|
1783
1815
|
sender_name = get_config_value('sender_name', 'bigboss')
|
|
1784
1816
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hcom
|
|
3
|
-
Version: 0.1.
|
|
4
|
-
Summary: Lightweight CLI tool for real-time
|
|
3
|
+
Version: 0.1.7
|
|
4
|
+
Summary: Lightweight CLI tool for real-time communication between Claude Code subagents using hooks
|
|
5
5
|
Author-email: aannoo <your@email.com>
|
|
6
6
|
License: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/aannoo/claude-hook-comms
|
|
@@ -26,9 +26,9 @@ Classifier: Topic :: Communications
|
|
|
26
26
|
Requires-Python: >=3.6
|
|
27
27
|
Description-Content-Type: text/markdown
|
|
28
28
|
|
|
29
|
-
# Claude
|
|
29
|
+
# hcom - Claude Hook Comms
|
|
30
30
|
|
|
31
|
-
Lightweight CLI tool for real-time communication between
|
|
31
|
+
Lightweight CLI tool for real-time communication between Claude Code [subagents](https://docs.anthropic.com/en/docs/claude-code/sub-agents) using [hooks](https://docs.anthropic.com/en/docs/claude-code/hooks).
|
|
32
32
|
|
|
33
33
|
## 🦆 What It Does
|
|
34
34
|
|
|
@@ -38,7 +38,7 @@ Creates a group chat where you and multiple interactive Claude Code subagents ca
|
|
|
38
38
|
|
|
39
39
|
## 🦷 Features
|
|
40
40
|
|
|
41
|
-
- **Multi-Terminal Launch** - Launch
|
|
41
|
+
- **Multi-Terminal Launch** - Launch Claude Code subagents in new terminals
|
|
42
42
|
- **Live Dashboard** - Real-time monitoring of all instances
|
|
43
43
|
- **Multi-Agent Communication** - Claude instances talk to each other across projects
|
|
44
44
|
- **@Mention Targeting** - Send messages to specific subagents or teams
|
|
@@ -100,11 +100,12 @@ cd backend && hcom open api-specialist
|
|
|
100
100
|
cd ../frontend && hcom open ui-specialist
|
|
101
101
|
|
|
102
102
|
# Create named teams that can be @mentioned
|
|
103
|
-
cd ~/api && hcom open --prefix api debugger
|
|
104
|
-
cd ~/auth && hcom open --prefix auth debugger
|
|
103
|
+
cd ~/api && hcom open --prefix api debugger # Creates api-hovoa7
|
|
104
|
+
cd ~/auth && hcom open --prefix auth debugger # Creates auth-hovob8
|
|
105
105
|
|
|
106
|
-
# Message specific teams
|
|
107
|
-
hcom send "@api login works but API fails"
|
|
106
|
+
# Message specific teams or instances
|
|
107
|
+
hcom send "@api login works but API fails" # Messages all api-* instances
|
|
108
|
+
hcom send "@hovoa7 can you check this?" # Message specific instance by name
|
|
108
109
|
```
|
|
109
110
|
|
|
110
111
|
|
|
@@ -120,7 +121,7 @@ hcom send "@api login works but API fails" # or in dashboard: hcom watch
|
|
|
120
121
|
### Automation Commands
|
|
121
122
|
| Command | Description |
|
|
122
123
|
|---------|-------------|
|
|
123
|
-
| `hcom send 'message'` | Send message |
|
|
124
|
+
| `hcom send 'message'` | Send message to chat |
|
|
124
125
|
| `hcom watch --logs` | View message history (non-interactive) |
|
|
125
126
|
| `hcom watch --status` | Show instance status (non-interactive) |
|
|
126
127
|
| `hcom watch --wait [timeout]` | Wait and notify for new messages |
|
|
@@ -195,18 +196,18 @@ HCOM_MAX_MESSAGE_SIZE=8192 hcom send "$(cat long_report.txt)"
|
|
|
195
196
|
|
|
196
197
|
hcom adds hooks to your project directory's `.claude/settings.local.json`:
|
|
197
198
|
|
|
198
|
-
1. **Sending**: Claude
|
|
199
|
+
1. **Sending**: Claude agents use `echo "HCOM_SEND:message"` internally (you use `hcom send` from terminal)
|
|
199
200
|
2. **Receiving**: Other Claudes get notified via Stop hook
|
|
200
201
|
3. **Waiting**: Stop hook keeps Claude in a waiting state for new messages
|
|
201
202
|
|
|
202
203
|
- **Identity**: Each instance gets a unique name based on conversation UUID (e.g., "hovoa7")
|
|
203
204
|
- **Persistence**: Names persist across `--resume` maintaining conversation context
|
|
204
205
|
- **Status Detection**: Notification hook tracks permission requests and activity
|
|
205
|
-
- **Agents**: When you run `hcom open researcher`, it loads an interactive
|
|
206
|
+
- **Agents**: When you run `hcom open researcher`, it loads an interactive Claude session with a system prompt from `.claude/agents/researcher.md` (local) or `~/.claude/agents/researcher.md` (global). Agents can specify `model:` and `tools:` in YAML frontmatter
|
|
206
207
|
|
|
207
208
|
### Architecture
|
|
208
209
|
- **Single conversation** - All instances share one global conversation
|
|
209
|
-
- **Opt-in participation** - Only
|
|
210
|
+
- **Opt-in participation** - Only Claude Code instances launched with `hcom open` join the chat
|
|
210
211
|
- **@-mention filtering** - Target messages to specific instances or teams
|
|
211
212
|
|
|
212
213
|
### File Structure
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
hcom/__init__.py,sha256=yxqzLIr5XxsUrfSe-inggLeqMM300Z4PrewklOE1FCk,96
|
|
2
|
+
hcom/__main__.py,sha256=VsTjMMUpknJ_D638HT9KrLX7Aid0c9dPq8p020c5gZA,75178
|
|
3
|
+
hcom-0.1.7.dist-info/METADATA,sha256=rYV5yFW1j2FFvxKSvKrSKzGSq3FzFrM3pD04x2xRpwY,10370
|
|
4
|
+
hcom-0.1.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
5
|
+
hcom-0.1.7.dist-info/entry_points.txt,sha256=cz9K9PsgYmORUxNKxVRrpxLS3cxRJcDZkE-PpfvOhI8,44
|
|
6
|
+
hcom-0.1.7.dist-info/top_level.txt,sha256=8AS1nVUWA26vxjDQ5viRxgJnwSvUWk1W6GP4g6ldZ-0,5
|
|
7
|
+
hcom-0.1.7.dist-info/RECORD,,
|
hcom-0.1.5.dist-info/RECORD
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
hcom/__init__.py,sha256=21Stc_3iuK1pjO6Nhkq7JmBYyatpk5yhMR0iSZ9U7eA,96
|
|
2
|
-
hcom/__main__.py,sha256=BAgC4SZoZznLG4Xd6Hjs3guCRV3iHg1vlgVxQ5wv9nw,73545
|
|
3
|
-
hcom-0.1.5.dist-info/METADATA,sha256=dzIT8zFctb5xaApTRtmEbh6e1Wj8pdg0hOl2X7LsuPc,10210
|
|
4
|
-
hcom-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
5
|
-
hcom-0.1.5.dist-info/entry_points.txt,sha256=cz9K9PsgYmORUxNKxVRrpxLS3cxRJcDZkE-PpfvOhI8,44
|
|
6
|
-
hcom-0.1.5.dist-info/top_level.txt,sha256=8AS1nVUWA26vxjDQ5viRxgJnwSvUWk1W6GP4g6ldZ-0,5
|
|
7
|
-
hcom-0.1.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|