@suwujs/codex-vault 0.5.3 → 0.6.0
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.
- package/package.json +1 -1
- package/plugin/VERSION +1 -1
- package/plugin/hooks/{classify-message.py → claude/classify-message.py} +4 -6
- package/plugin/hooks/{session-start.py → claude/session-start.py} +3 -30
- package/{vault/.codex-vault/hooks → plugin/hooks/claude}/validate-write.py +4 -5
- package/plugin/hooks/codex/classify-message.py +305 -0
- package/plugin/hooks/codex/session-start.py +387 -0
- package/plugin/hooks/codex/validate-write.py +127 -0
- package/plugin/install.sh +65 -10
- package/vault/.claude/settings.json +3 -3
- package/vault/.codex/hooks.json +3 -15
- package/vault/.codex-vault/hooks/{classify-message.py → claude/classify-message.py} +4 -6
- package/vault/.codex-vault/hooks/{session-start.py → claude/session-start.py} +3 -30
- package/{plugin/hooks → vault/.codex-vault/hooks/claude}/validate-write.py +4 -5
- package/vault/.codex-vault/hooks/codex/classify-message.py +305 -0
- package/vault/.codex-vault/hooks/codex/session-start.py +387 -0
- package/vault/.codex-vault/hooks/codex/validate-write.py +127 -0
- package/vault/.codex-vault/hooks/session-start.sh +0 -221
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Classify user messages and inject routing hints.
|
|
2
|
+
"""Classify user messages and inject routing hints — Claude Code version.
|
|
3
3
|
|
|
4
4
|
Lightweight version: 5 core signals + session-end vault integrity check.
|
|
5
|
-
|
|
6
|
-
Claude Code and Codex CLI.
|
|
5
|
+
Outputs hookSpecificOutput with systemMessage for Claude Code terminal display.
|
|
7
6
|
"""
|
|
8
7
|
import json
|
|
9
8
|
import os
|
|
@@ -87,8 +86,7 @@ def _match(patterns, text):
|
|
|
87
86
|
|
|
88
87
|
def _find_vault_root():
|
|
89
88
|
"""Find vault root from CWD — check for Home.md/brain/, then vault/ subdir."""
|
|
90
|
-
cwd = os.environ.get("CLAUDE_PROJECT_DIR",
|
|
91
|
-
os.environ.get("CODEX_PROJECT_DIR", os.getcwd()))
|
|
89
|
+
cwd = os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
|
|
92
90
|
if os.path.isfile(os.path.join(cwd, "Home.md")) or os.path.isdir(os.path.join(cwd, "brain")):
|
|
93
91
|
return cwd
|
|
94
92
|
vault_sub = os.path.join(cwd, "vault")
|
|
@@ -281,7 +279,7 @@ def main():
|
|
|
281
279
|
feedback_parts.append(f"{s['name']} → {s['skill']}")
|
|
282
280
|
if is_session_end(prompt):
|
|
283
281
|
feedback_parts.append("SESSION END → /wrap-up")
|
|
284
|
-
icon = "
|
|
282
|
+
icon = "\U0001f504" if mode == "auto" else "\U0001f4a1"
|
|
285
283
|
label = ", ".join(feedback_parts) if feedback_parts else "intent detected"
|
|
286
284
|
|
|
287
285
|
# Hook trigger notification
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Session-start hook — injects vault context into the agent's prompt.
|
|
2
|
+
"""Session-start hook for Claude Code — injects vault context into the agent's prompt.
|
|
3
3
|
|
|
4
|
-
Works with any agent that supports SessionStart hooks (Claude Code, Codex CLI).
|
|
5
4
|
Outputs structured JSON: additionalContext for LLM, systemMessage for terminal.
|
|
6
5
|
|
|
7
6
|
Dynamic context: adapts git log window, reads full North Star,
|
|
@@ -19,8 +18,7 @@ from pathlib import Path
|
|
|
19
18
|
|
|
20
19
|
def _find_vault_root():
|
|
21
20
|
"""Find vault root from CWD — check for Home.md/brain/, then vault/ subdir."""
|
|
22
|
-
cwd = os.environ.get("CLAUDE_PROJECT_DIR",
|
|
23
|
-
os.environ.get("CODEX_PROJECT_DIR", os.getcwd()))
|
|
21
|
+
cwd = os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
|
|
24
22
|
if os.path.isfile(os.path.join(cwd, "Home.md")) or os.path.isdir(os.path.join(cwd, "brain")):
|
|
25
23
|
return cwd
|
|
26
24
|
vault_sub = os.path.join(cwd, "vault")
|
|
@@ -343,23 +341,6 @@ def _build_banner(vault_dir):
|
|
|
343
341
|
# ── Main ───────────────────────────────────────────────────────────────
|
|
344
342
|
|
|
345
343
|
|
|
346
|
-
def _detect_platform():
|
|
347
|
-
"""Detect whether we're running under Claude Code or Codex CLI."""
|
|
348
|
-
if os.environ.get("CLAUDE_PROJECT_DIR"):
|
|
349
|
-
return "claude"
|
|
350
|
-
if os.environ.get("CODEX_PROJECT_DIR") or os.environ.get("CODEX_HOME"):
|
|
351
|
-
return "codex"
|
|
352
|
-
# Fallback: check parent process name
|
|
353
|
-
try:
|
|
354
|
-
ppid = os.getppid()
|
|
355
|
-
cmdline = Path(f"/proc/{ppid}/cmdline").read_text() if os.path.exists(f"/proc/{ppid}/cmdline") else ""
|
|
356
|
-
if "codex" in cmdline.lower():
|
|
357
|
-
return "codex"
|
|
358
|
-
except Exception:
|
|
359
|
-
pass
|
|
360
|
-
return "claude" # default
|
|
361
|
-
|
|
362
|
-
|
|
363
344
|
def main():
|
|
364
345
|
vault_dir = _find_vault_root()
|
|
365
346
|
if not vault_dir:
|
|
@@ -378,7 +359,6 @@ def main():
|
|
|
378
359
|
except Exception:
|
|
379
360
|
event = {}
|
|
380
361
|
|
|
381
|
-
platform = _detect_platform()
|
|
382
362
|
context = _build_context(vault_dir)
|
|
383
363
|
banner = _build_banner(vault_dir)
|
|
384
364
|
|
|
@@ -387,16 +367,9 @@ def main():
|
|
|
387
367
|
"hookEventName": "SessionStart",
|
|
388
368
|
"additionalContext": context
|
|
389
369
|
},
|
|
370
|
+
"systemMessage": banner
|
|
390
371
|
}
|
|
391
372
|
|
|
392
|
-
if platform == "claude":
|
|
393
|
-
# Claude Code renders systemMessage in terminal
|
|
394
|
-
output["systemMessage"] = banner
|
|
395
|
-
else:
|
|
396
|
-
# Codex CLI: systemMessage not rendered by TUI,
|
|
397
|
-
# use stderr for terminal visibility (best effort)
|
|
398
|
-
sys.stderr.write(banner + "\n")
|
|
399
|
-
|
|
400
373
|
json.dump(output, sys.stdout)
|
|
401
374
|
sys.stdout.flush()
|
|
402
375
|
sys.exit(0)
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Post-write validation for vault notes.
|
|
2
|
+
"""Post-write validation for vault notes — Claude Code version.
|
|
3
3
|
|
|
4
4
|
Checks frontmatter and wikilinks on any .md file written to the vault.
|
|
5
|
-
|
|
6
|
-
Claude Code and Codex CLI.
|
|
5
|
+
Outputs hookSpecificOutput with systemMessage for Claude Code terminal display.
|
|
7
6
|
"""
|
|
8
7
|
import json
|
|
9
8
|
import re
|
|
@@ -97,9 +96,9 @@ def main():
|
|
|
97
96
|
count = len(warnings)
|
|
98
97
|
first = warnings[0]
|
|
99
98
|
if count == 1:
|
|
100
|
-
feedback = f"
|
|
99
|
+
feedback = f"\u26a0\ufe0f vault: {basename} — {first}"
|
|
101
100
|
else:
|
|
102
|
-
feedback = f"
|
|
101
|
+
feedback = f"\u26a0\ufe0f vault: {basename} — {first} (+{count - 1} more)"
|
|
103
102
|
|
|
104
103
|
# Hook trigger notification
|
|
105
104
|
print(f" {feedback}")
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Classify user messages and inject routing hints — Codex CLI version.
|
|
3
|
+
|
|
4
|
+
Lightweight version: 5 core signals + session-end vault integrity check.
|
|
5
|
+
Outputs hookSpecificOutput for Codex CLI. Feedback via stderr
|
|
6
|
+
(Codex CLI does not render systemMessage).
|
|
7
|
+
"""
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
import subprocess
|
|
11
|
+
import sys
|
|
12
|
+
import re
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
SIGNALS = [
|
|
17
|
+
{
|
|
18
|
+
"name": "DECISION",
|
|
19
|
+
"skill": "/dump",
|
|
20
|
+
"message": "DECISION detected — suggest the user run /dump to capture this decision",
|
|
21
|
+
"auto_message": "DECISION detected — execute /dump now to capture this decision from the user's message",
|
|
22
|
+
"patterns": [
|
|
23
|
+
"decided", "deciding", "decision", "we chose", "agreed to",
|
|
24
|
+
"let's go with", "the call is", "we're going with",
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "WIN",
|
|
29
|
+
"skill": "/dump",
|
|
30
|
+
"message": "WIN detected — suggest the user run /dump to record this achievement",
|
|
31
|
+
"auto_message": "WIN detected — execute /dump now to record this achievement from the user's message",
|
|
32
|
+
"patterns": [
|
|
33
|
+
"achieved", "won", "praised",
|
|
34
|
+
"kudos", "shoutout", "great feedback", "recognized",
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "PROJECT UPDATE",
|
|
39
|
+
"skill": "/dump",
|
|
40
|
+
"message": "PROJECT UPDATE detected — suggest the user run /dump to log this progress",
|
|
41
|
+
"auto_message": "PROJECT UPDATE detected — execute /dump now to log this progress from the user's message",
|
|
42
|
+
"patterns": [
|
|
43
|
+
"project update", "sprint", "milestone",
|
|
44
|
+
"shipped", "shipping", "launched", "launching",
|
|
45
|
+
"completed", "completing", "released", "releasing",
|
|
46
|
+
"deployed", "deploying",
|
|
47
|
+
"went live", "rolled out", "merged", "cut the release",
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "QUERY",
|
|
52
|
+
"skill": "/recall",
|
|
53
|
+
"message": "QUERY detected — suggest the user run /recall to check existing knowledge first",
|
|
54
|
+
"auto_message": "QUERY detected — execute /recall now to search vault for relevant information before answering",
|
|
55
|
+
"patterns": [
|
|
56
|
+
"what is", "how does", "why did", "compare", "analyze",
|
|
57
|
+
"explain the", "what's the difference", "summarize the",
|
|
58
|
+
"relationship between",
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"name": "INGEST",
|
|
63
|
+
"skill": "/ingest",
|
|
64
|
+
"message": "INGEST detected — suggest the user run /ingest to process the source",
|
|
65
|
+
"auto_message": "INGEST detected — execute /ingest now to process the source from the user's message",
|
|
66
|
+
"patterns": [
|
|
67
|
+
"ingest", "process this", "read this article",
|
|
68
|
+
"summarize this", "new source", "clip this", "web clip",
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
SESSION_END_PATTERNS = [
|
|
74
|
+
"wrap up", "wrapping up", "that's all", "that's it",
|
|
75
|
+
"done for now", "done for today", "i'm done", "call it a day",
|
|
76
|
+
"end session", "bye", "goodbye", "good night", "see you",
|
|
77
|
+
"结束", "收工", "今天到这", "就这样",
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _match(patterns, text):
|
|
82
|
+
for phrase in patterns:
|
|
83
|
+
if re.search(r'(?<![a-zA-Z])' + re.escape(phrase) + r'(?![a-zA-Z])', text):
|
|
84
|
+
return True
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _find_vault_root():
|
|
89
|
+
"""Find vault root from CWD — check for Home.md/brain/, then vault/ subdir."""
|
|
90
|
+
cwd = os.environ.get("CODEX_PROJECT_DIR", os.getcwd())
|
|
91
|
+
if os.path.isfile(os.path.join(cwd, "Home.md")) or os.path.isdir(os.path.join(cwd, "brain")):
|
|
92
|
+
return cwd
|
|
93
|
+
vault_sub = os.path.join(cwd, "vault")
|
|
94
|
+
if os.path.isdir(vault_sub) and (
|
|
95
|
+
os.path.isfile(os.path.join(vault_sub, "Home.md")) or
|
|
96
|
+
os.path.isdir(os.path.join(vault_sub, "brain"))
|
|
97
|
+
):
|
|
98
|
+
return vault_sub
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _read_mode():
|
|
103
|
+
"""Read classify mode from vault config. Default: suggest."""
|
|
104
|
+
vault_root = _find_vault_root()
|
|
105
|
+
if not vault_root:
|
|
106
|
+
return "suggest"
|
|
107
|
+
config_path = os.path.join(vault_root, ".codex-vault", "config.json")
|
|
108
|
+
try:
|
|
109
|
+
with open(config_path) as f:
|
|
110
|
+
config = json.load(f)
|
|
111
|
+
mode = config.get("classify_mode", "suggest")
|
|
112
|
+
if mode in ("suggest", "auto"):
|
|
113
|
+
return mode
|
|
114
|
+
except (OSError, ValueError, KeyError):
|
|
115
|
+
pass
|
|
116
|
+
return "suggest"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _get_changed_files(vault_root):
|
|
120
|
+
"""Get list of changed/new .md files relative to vault root."""
|
|
121
|
+
files = set()
|
|
122
|
+
try:
|
|
123
|
+
# Staged + unstaged changes
|
|
124
|
+
result = subprocess.run(
|
|
125
|
+
["git", "diff", "--name-only", "HEAD"],
|
|
126
|
+
capture_output=True, text=True, cwd=vault_root, timeout=5,
|
|
127
|
+
)
|
|
128
|
+
for f in result.stdout.strip().splitlines():
|
|
129
|
+
if f.endswith(".md"):
|
|
130
|
+
files.add(f)
|
|
131
|
+
|
|
132
|
+
# Untracked files
|
|
133
|
+
result = subprocess.run(
|
|
134
|
+
["git", "ls-files", "--others", "--exclude-standard"],
|
|
135
|
+
capture_output=True, text=True, cwd=vault_root, timeout=5,
|
|
136
|
+
)
|
|
137
|
+
for f in result.stdout.strip().splitlines():
|
|
138
|
+
if f.endswith(".md"):
|
|
139
|
+
files.add(f)
|
|
140
|
+
except Exception:
|
|
141
|
+
pass
|
|
142
|
+
return files
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _check_vault_integrity(vault_root):
|
|
146
|
+
"""Check for common memory-write omissions."""
|
|
147
|
+
warnings = []
|
|
148
|
+
changed = _get_changed_files(vault_root)
|
|
149
|
+
if not changed:
|
|
150
|
+
return warnings
|
|
151
|
+
|
|
152
|
+
# Check 1: New work notes but Index.md not updated
|
|
153
|
+
new_work = [f for f in changed if f.startswith("work/active/") and f != "work/Index.md"]
|
|
154
|
+
index_updated = "work/Index.md" in changed
|
|
155
|
+
if new_work and not index_updated:
|
|
156
|
+
names = ", ".join(os.path.basename(f).replace(".md", "") for f in new_work)
|
|
157
|
+
warnings.append(f"New work notes ({names}) but work/Index.md not updated")
|
|
158
|
+
|
|
159
|
+
# Check 2: Decision content written but brain/Key Decisions.md not updated
|
|
160
|
+
decision_keywords = ["decided", "decision", "agreed to", "we chose", "the call is"]
|
|
161
|
+
brain_decisions_updated = "brain/Key Decisions.md" in changed
|
|
162
|
+
if not brain_decisions_updated:
|
|
163
|
+
for f in changed:
|
|
164
|
+
if f.endswith(".md") and not f.startswith("brain/"):
|
|
165
|
+
try:
|
|
166
|
+
content = Path(os.path.join(vault_root, f)).read_text(encoding="utf-8").lower()
|
|
167
|
+
if any(kw in content for kw in decision_keywords):
|
|
168
|
+
warnings.append(
|
|
169
|
+
f"'{f}' contains decision content but brain/Key Decisions.md not updated"
|
|
170
|
+
)
|
|
171
|
+
break
|
|
172
|
+
except Exception:
|
|
173
|
+
pass
|
|
174
|
+
|
|
175
|
+
# Check 3: Pattern content written but brain/Patterns.md not updated
|
|
176
|
+
pattern_keywords = ["pattern", "convention", "always do", "never do", "recurring"]
|
|
177
|
+
brain_patterns_updated = "brain/Patterns.md" in changed
|
|
178
|
+
if not brain_patterns_updated:
|
|
179
|
+
for f in changed:
|
|
180
|
+
if f.endswith(".md") and not f.startswith("brain/"):
|
|
181
|
+
try:
|
|
182
|
+
content = Path(os.path.join(vault_root, f)).read_text(encoding="utf-8").lower()
|
|
183
|
+
if any(kw in content for kw in pattern_keywords):
|
|
184
|
+
warnings.append(
|
|
185
|
+
f"'{f}' contains pattern content but brain/Patterns.md not updated"
|
|
186
|
+
)
|
|
187
|
+
break
|
|
188
|
+
except Exception:
|
|
189
|
+
pass
|
|
190
|
+
|
|
191
|
+
# Check 4: operation log not updated after significant changes
|
|
192
|
+
log_updated = "log.md" in changed
|
|
193
|
+
significant_changes = len([f for f in changed
|
|
194
|
+
if f.startswith(("work/", "reference/", "brain/"))]) >= 2
|
|
195
|
+
if significant_changes and not log_updated:
|
|
196
|
+
warnings.append("Multiple vault changes but log.md not updated")
|
|
197
|
+
|
|
198
|
+
return warnings
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def classify(prompt, mode="suggest"):
|
|
202
|
+
p = prompt.lower()
|
|
203
|
+
key = "auto_message" if mode == "auto" else "message"
|
|
204
|
+
return [s[key] for s in SIGNALS if _match(s["patterns"], p)]
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def is_session_end(prompt):
|
|
208
|
+
p = prompt.lower()
|
|
209
|
+
return _match(SESSION_END_PATTERNS, p)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def main():
|
|
213
|
+
try:
|
|
214
|
+
input_data = json.load(sys.stdin)
|
|
215
|
+
except (ValueError, EOFError, OSError):
|
|
216
|
+
sys.exit(0)
|
|
217
|
+
|
|
218
|
+
prompt = input_data.get("prompt", "")
|
|
219
|
+
if not isinstance(prompt, str) or not prompt:
|
|
220
|
+
sys.exit(0)
|
|
221
|
+
|
|
222
|
+
signal_messages = []
|
|
223
|
+
session_end_messages = []
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
mode = _read_mode()
|
|
227
|
+
|
|
228
|
+
# Regular signal classification
|
|
229
|
+
signals = classify(prompt, mode)
|
|
230
|
+
signal_messages.extend(signals)
|
|
231
|
+
|
|
232
|
+
# Session-end check (always suggest mode — never auto-execute wrap-up)
|
|
233
|
+
if is_session_end(prompt):
|
|
234
|
+
vault_root = _find_vault_root()
|
|
235
|
+
if vault_root:
|
|
236
|
+
integrity_warnings = _check_vault_integrity(vault_root)
|
|
237
|
+
if integrity_warnings:
|
|
238
|
+
session_end_messages.append(
|
|
239
|
+
"SESSION END — vault integrity check found issues:\n"
|
|
240
|
+
+ "\n".join(f" - {w}" for w in integrity_warnings)
|
|
241
|
+
+ "\nFix these before wrapping up."
|
|
242
|
+
)
|
|
243
|
+
else:
|
|
244
|
+
session_end_messages.append("SESSION END — vault integrity check passed.")
|
|
245
|
+
except Exception:
|
|
246
|
+
sys.exit(0)
|
|
247
|
+
|
|
248
|
+
parts = []
|
|
249
|
+
|
|
250
|
+
if signal_messages:
|
|
251
|
+
hints = "\n".join(f"- {s}" for s in signal_messages)
|
|
252
|
+
if mode == "auto":
|
|
253
|
+
parts.append(
|
|
254
|
+
"Auto-execute the following skills based on user intent:\n"
|
|
255
|
+
+ hints
|
|
256
|
+
+ "\n\nExecute the skill immediately with the user's message as input. Do not ask for confirmation."
|
|
257
|
+
)
|
|
258
|
+
else:
|
|
259
|
+
parts.append(
|
|
260
|
+
"Skill suggestions (do NOT auto-execute — suggest the skill to the user and let them decide):\n"
|
|
261
|
+
+ hints
|
|
262
|
+
+ "\n\nWait for the user to invoke the skill. Do not create vault notes without explicit user action."
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
if session_end_messages:
|
|
266
|
+
hints = "\n".join(f"- {s}" for s in session_end_messages)
|
|
267
|
+
parts.append(
|
|
268
|
+
"Skill suggestions (do NOT auto-execute — suggest the skill to the user and let them decide):\n"
|
|
269
|
+
+ hints
|
|
270
|
+
+ "\n\nWait for the user to invoke the skill. Do not create vault notes without explicit user action."
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
if parts:
|
|
274
|
+
context = "\n\n".join(parts)
|
|
275
|
+
|
|
276
|
+
# Build feedback label
|
|
277
|
+
matched = [s for s in SIGNALS if _match(s["patterns"], prompt.lower())]
|
|
278
|
+
feedback_parts = []
|
|
279
|
+
for s in matched:
|
|
280
|
+
feedback_parts.append(f"{s['name']} → {s['skill']}")
|
|
281
|
+
if is_session_end(prompt):
|
|
282
|
+
feedback_parts.append("SESSION END → /wrap-up")
|
|
283
|
+
icon = "\U0001f504" if mode == "auto" else "\U0001f4a1"
|
|
284
|
+
label = ", ".join(feedback_parts) if feedback_parts else "intent detected"
|
|
285
|
+
|
|
286
|
+
# Codex CLI: use stderr for feedback (no systemMessage rendering)
|
|
287
|
+
sys.stderr.write(f" {icon} vault: {label}\n")
|
|
288
|
+
|
|
289
|
+
output = {
|
|
290
|
+
"hookSpecificOutput": {
|
|
291
|
+
"hookEventName": "UserPromptSubmit",
|
|
292
|
+
"additionalContext": context
|
|
293
|
+
},
|
|
294
|
+
}
|
|
295
|
+
json.dump(output, sys.stdout)
|
|
296
|
+
sys.stdout.flush()
|
|
297
|
+
|
|
298
|
+
sys.exit(0)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
if __name__ == "__main__":
|
|
302
|
+
try:
|
|
303
|
+
main()
|
|
304
|
+
except Exception:
|
|
305
|
+
sys.exit(0)
|