77 lines
2.3 KiB
Python
77 lines
2.3 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""SessionStart hook: compose prompts/session-start/*.md into one
|
||
|
|
additionalContext block.
|
||
|
|
|
||
|
|
Fires on startup/resume/clear, and on 'compact' (matcher includes it) so the
|
||
|
|
composed context survives a context-compaction pass, not just the first turn.
|
||
|
|
|
||
|
|
Prompt files live under prompts/<event>/*.md; only the session-start event is
|
||
|
|
implemented today (SessionEnd cannot inject context — ADR-028). Files are
|
||
|
|
concatenated in filename sort order (e.g. 10-orchestration.md) with no added
|
||
|
|
separator between them, so a single prompt file present alone reproduces the
|
||
|
|
exact bytes it contributes.
|
||
|
|
"""
|
||
|
|
import glob
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
import sys
|
||
|
|
|
||
|
|
PLUGIN_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||
|
|
SESSION_START_DIR = os.path.join(PLUGIN_ROOT, "prompts", "session-start")
|
||
|
|
|
||
|
|
# Deterministic injected-context budget, in lines. Below WARN_LINE_BUDGET,
|
||
|
|
# inject normally. Between the two, still inject but warn on stderr. Above
|
||
|
|
# REFUSE_LINE_BUDGET, refuse to inject anything and warn on stderr instead.
|
||
|
|
WARN_LINE_BUDGET = 120
|
||
|
|
REFUSE_LINE_BUDGET = 240
|
||
|
|
|
||
|
|
|
||
|
|
def prompt_files(session_start_dir=None):
|
||
|
|
if session_start_dir is None:
|
||
|
|
session_start_dir = SESSION_START_DIR
|
||
|
|
return sorted(glob.glob(os.path.join(session_start_dir, "*.md")))
|
||
|
|
|
||
|
|
|
||
|
|
def compose(paths):
|
||
|
|
"""Concatenate prompt file contents in order with no added separators."""
|
||
|
|
parts = []
|
||
|
|
for path in paths:
|
||
|
|
with open(path) as f:
|
||
|
|
parts.append(f.read())
|
||
|
|
return "".join(parts)
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
paths = prompt_files()
|
||
|
|
if not paths:
|
||
|
|
return
|
||
|
|
|
||
|
|
context = compose(paths)
|
||
|
|
line_count = len(context.splitlines())
|
||
|
|
|
||
|
|
if line_count > REFUSE_LINE_BUDGET:
|
||
|
|
print(
|
||
|
|
f"os-context: session-start prompt budget exceeded "
|
||
|
|
f"({line_count} lines > {REFUSE_LINE_BUDGET}) — refusing to inject.",
|
||
|
|
file=sys.stderr,
|
||
|
|
)
|
||
|
|
return
|
||
|
|
|
||
|
|
if line_count > WARN_LINE_BUDGET:
|
||
|
|
print(
|
||
|
|
f"os-context: session-start prompt budget exceeded "
|
||
|
|
f"({line_count} lines > {WARN_LINE_BUDGET}) — injecting anyway.",
|
||
|
|
file=sys.stderr,
|
||
|
|
)
|
||
|
|
|
||
|
|
print(json.dumps({
|
||
|
|
"hookSpecificOutput": {
|
||
|
|
"hookEventName": "SessionStart",
|
||
|
|
"additionalContext": context,
|
||
|
|
}
|
||
|
|
}))
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
sys.exit(main())
|