aiwcli 0.10.3 → 0.11.1
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/bin/run.js +1 -1
- package/dist/commands/clear.js +28 -131
- package/dist/commands/init/index.js +3 -3
- package/dist/lib/gitignore-manager.d.ts +32 -0
- package/dist/lib/gitignore-manager.js +141 -2
- package/dist/templates/CLAUDE.md +8 -8
- package/dist/templates/_shared/.claude/commands/handoff-resume.md +64 -0
- package/dist/templates/_shared/.claude/commands/handoff.md +16 -10
- package/dist/templates/_shared/.claude/settings.json +7 -7
- package/dist/templates/_shared/hooks-ts/_utils/git-state.ts +2 -0
- package/dist/templates/_shared/hooks-ts/archive_plan.ts +159 -0
- package/dist/templates/_shared/hooks-ts/context_monitor.ts +147 -0
- package/dist/templates/_shared/hooks-ts/file-suggestion.ts +130 -0
- package/dist/templates/_shared/hooks-ts/pre_compact.ts +49 -0
- package/dist/templates/_shared/hooks-ts/session_end.ts +107 -0
- package/dist/templates/_shared/hooks-ts/session_start.ts +144 -0
- package/dist/templates/_shared/hooks-ts/task_create_capture.ts +48 -0
- package/dist/templates/_shared/hooks-ts/task_update_capture.ts +74 -0
- package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +83 -0
- package/dist/templates/_shared/lib-ts/CLAUDE.md +318 -0
- package/dist/templates/_shared/lib-ts/base/atomic-write.ts +12 -12
- package/dist/templates/_shared/lib-ts/base/constants.ts +22 -15
- package/dist/templates/_shared/lib-ts/base/git-state.ts +1 -1
- package/dist/templates/_shared/lib-ts/base/hook-utils.ts +129 -50
- package/dist/templates/_shared/lib-ts/base/inference.ts +28 -21
- package/dist/templates/_shared/lib-ts/base/logger.ts +15 -2
- package/dist/templates/_shared/lib-ts/base/state-io.ts +9 -7
- package/dist/templates/_shared/lib-ts/base/stop-words.ts +131 -131
- package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +142 -0
- package/dist/templates/_shared/lib-ts/base/utils.ts +69 -69
- package/dist/templates/_shared/lib-ts/context/context-formatter.ts +30 -24
- package/dist/templates/_shared/lib-ts/context/context-selector.ts +50 -32
- package/dist/templates/_shared/lib-ts/context/context-store.ts +76 -48
- package/dist/templates/_shared/lib-ts/context/plan-manager.ts +43 -23
- package/dist/templates/_shared/lib-ts/context/task-tracker.ts +10 -6
- package/dist/templates/_shared/lib-ts/handoff/document-generator.ts +11 -10
- package/dist/templates/_shared/lib-ts/handoff/handoff-reader.ts +158 -0
- package/dist/templates/_shared/lib-ts/templates/formatters.ts +6 -4
- package/dist/templates/_shared/lib-ts/types.ts +68 -55
- package/dist/templates/_shared/scripts/resolve_context.ts +24 -0
- package/dist/templates/_shared/scripts/resume_handoff.ts +345 -0
- package/dist/templates/_shared/scripts/save_handoff.ts +3 -3
- package/dist/templates/_shared/scripts/status_line.ts +687 -0
- package/dist/templates/cc-native/.claude/settings.json +175 -185
- package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +15 -17
- package/dist/templates/cc-native/_cc-native/agents/CLAUDE.md +0 -2
- package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +109 -135
- package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.ts +119 -0
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +1027 -0
- package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +61 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +156 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +792 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +199 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +144 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/config.ts +57 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/constants.ts +83 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/corroboration.ts +115 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/debug.ts +80 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +120 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/json-parser.ts +168 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/nul +3 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/orchestrator.ts +250 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/agent.ts +275 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/codex.ts +130 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/gemini.ts +107 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/index.ts +10 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/types.ts +23 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +240 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/tsconfig.json +18 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +385 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/verdict.ts +72 -0
- package/dist/templates/cc-native/_cc-native/plan-review.config.json +14 -1
- package/oclif.manifest.json +1 -1
- package/package.json +2 -2
- package/dist/templates/_shared/hooks/__init__.py +0 -16
- package/dist/templates/_shared/hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/context_enforcer.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/context_monitor.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/file-suggestion.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/pre_compact.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/session_end.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/session_start.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/task_create_atomicity.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/task_create_capture.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/task_update_capture.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/user_prompt_submit.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/archive_plan.py +0 -177
- package/dist/templates/_shared/hooks/context_monitor.py +0 -270
- package/dist/templates/_shared/hooks/file-suggestion.py +0 -215
- package/dist/templates/_shared/hooks/pre_compact.py +0 -104
- package/dist/templates/_shared/hooks/session_end.py +0 -173
- package/dist/templates/_shared/hooks/session_start.py +0 -206
- package/dist/templates/_shared/hooks/task_create_capture.py +0 -108
- package/dist/templates/_shared/hooks/task_update_capture.py +0 -145
- package/dist/templates/_shared/hooks/user_prompt_submit.py +0 -139
- package/dist/templates/_shared/lib/__init__.py +0 -1
- package/dist/templates/_shared/lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__init__.py +0 -65
- package/dist/templates/_shared/lib/base/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/atomic_write.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/constants.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/hook_utils.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/inference.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/logger.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/stop_words.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/subprocess_utils.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/utils.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/atomic_write.py +0 -180
- package/dist/templates/_shared/lib/base/constants.py +0 -358
- package/dist/templates/_shared/lib/base/hook_utils.py +0 -339
- package/dist/templates/_shared/lib/base/inference.py +0 -307
- package/dist/templates/_shared/lib/base/logger.py +0 -305
- package/dist/templates/_shared/lib/base/stop_words.py +0 -221
- package/dist/templates/_shared/lib/base/subprocess_utils.py +0 -46
- package/dist/templates/_shared/lib/base/utils.py +0 -263
- package/dist/templates/_shared/lib/context/__init__.py +0 -102
- package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/cache.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/context_extractor.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/context_formatter.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/context_selector.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/context_store.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/discovery.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/event_log.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/plan_archive.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/plan_manager.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/task_sync.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/task_tracker.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/context_formatter.py +0 -317
- package/dist/templates/_shared/lib/context/context_selector.py +0 -508
- package/dist/templates/_shared/lib/context/context_store.py +0 -653
- package/dist/templates/_shared/lib/context/plan_manager.py +0 -303
- package/dist/templates/_shared/lib/context/task_tracker.py +0 -188
- package/dist/templates/_shared/lib/handoff/__init__.py +0 -22
- package/dist/templates/_shared/lib/handoff/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/handoff/__pycache__/document_generator.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/handoff/document_generator.py +0 -278
- package/dist/templates/_shared/lib/templates/README.md +0 -206
- package/dist/templates/_shared/lib/templates/__init__.py +0 -36
- package/dist/templates/_shared/lib/templates/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/templates/__pycache__/formatters.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/templates/__pycache__/persona_questions.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/templates/__pycache__/plan_context.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/templates/formatters.py +0 -146
- package/dist/templates/_shared/lib/templates/plan_context.py +0 -73
- package/dist/templates/_shared/scripts/__pycache__/save_handoff.cpython-313.pyc +0 -0
- package/dist/templates/_shared/scripts/__pycache__/status_line.cpython-313.pyc +0 -0
- package/dist/templates/_shared/scripts/save_handoff.py +0 -357
- package/dist/templates/_shared/scripts/status_line.py +0 -716
- package/dist/templates/cc-native/.claude/commands/cc-native/fresh-perspective.md +0 -8
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/fresh-perspective.md +0 -8
- package/dist/templates/cc-native/MIGRATION.md +0 -86
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/add_plan_context.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/mark_questions_asked.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_accepted.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_questions_early.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/suggest-fresh-perspective.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.py +0 -130
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +0 -954
- package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.py +0 -81
- package/dist/templates/cc-native/_cc-native/hooks/suggest-fresh-perspective.py +0 -340
- package/dist/templates/cc-native/_cc-native/lib/CLAUDE.md +0 -265
- package/dist/templates/cc-native/_cc-native/lib/__init__.py +0 -53
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/atomic_write.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/constants.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/debug.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/orchestrator.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/state.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/utils.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/constants.py +0 -45
- package/dist/templates/cc-native/_cc-native/lib/debug.py +0 -139
- package/dist/templates/cc-native/_cc-native/lib/orchestrator.py +0 -362
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__init__.py +0 -28
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/base.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/codex.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/gemini.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +0 -215
- package/dist/templates/cc-native/_cc-native/lib/reviewers/base.py +0 -88
- package/dist/templates/cc-native/_cc-native/lib/reviewers/codex.py +0 -124
- package/dist/templates/cc-native/_cc-native/lib/reviewers/gemini.py +0 -108
- package/dist/templates/cc-native/_cc-native/lib/state.py +0 -268
- package/dist/templates/cc-native/_cc-native/lib/utils.py +0 -1071
- package/dist/templates/cc-native/_cc-native/scripts/__pycache__/aggregate_agents.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/scripts/aggregate_agents.py +0 -168
- package/dist/templates/cc-native/_cc-native/workflows/fresh-perspective.md +0 -134
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
"""Unified logging for all hooks and libraries.
|
|
2
|
-
|
|
3
|
-
Provides a single logging interface that replaces:
|
|
4
|
-
- log_hook_error() from hook_utils.py (error-only, plain text)
|
|
5
|
-
- debug.py from cc-native (per-context, plain text)
|
|
6
|
-
- eprint() for diagnostic output (stderr-only, no persistence)
|
|
7
|
-
|
|
8
|
-
Log format: JSONL (one JSON object per line)
|
|
9
|
-
Log location: _output/hook-log.jsonl (global, all sessions)
|
|
10
|
-
Filter by session using the "sid" field.
|
|
11
|
-
|
|
12
|
-
Environment variables:
|
|
13
|
-
- HOOK_LOG_DISABLE=1: Disable all file logging
|
|
14
|
-
- HOOK_LOG_LEVEL=warn: Minimum level to log (default: debug)
|
|
15
|
-
- HOOK_ERROR_LOG_DISABLE=1: Legacy alias for HOOK_LOG_DISABLE
|
|
16
|
-
|
|
17
|
-
Never raises — all errors silently swallowed.
|
|
18
|
-
No buffering — each call is one open+write+close.
|
|
19
|
-
Stdlib only — json, os, sys, datetime, pathlib.
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
import json
|
|
23
|
-
import os
|
|
24
|
-
import sys
|
|
25
|
-
from datetime import datetime, timezone
|
|
26
|
-
from pathlib import Path
|
|
27
|
-
from typing import Any, Dict, Optional
|
|
28
|
-
|
|
29
|
-
_LEVELS = {"debug": 0, "info": 1, "warn": 2, "error": 3}
|
|
30
|
-
|
|
31
|
-
_MAX_LOG_LINES = 10_000 # Max lines in global log before pruning
|
|
32
|
-
|
|
33
|
-
# Module-level context path cache.
|
|
34
|
-
# Set once per hook process via set_context_path() or auto-resolved on first use.
|
|
35
|
-
_cached_context_path: Optional[Path] = None
|
|
36
|
-
_context_resolved: bool = False
|
|
37
|
-
|
|
38
|
-
# Module-level session ID cache.
|
|
39
|
-
# Set once per hook process via set_session_id().
|
|
40
|
-
_cached_session_id: Optional[str] = None
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def set_session_id(session_id: Optional[str]) -> None:
|
|
44
|
-
"""Set the session ID for this process. All subsequent log calls include it.
|
|
45
|
-
|
|
46
|
-
Args:
|
|
47
|
-
session_id: Claude Code session ID (e.g., "a1b2c3d4")
|
|
48
|
-
or None to clear.
|
|
49
|
-
"""
|
|
50
|
-
global _cached_session_id
|
|
51
|
-
_cached_session_id = session_id
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def set_context_path(path: Optional[Path]) -> None:
|
|
55
|
-
"""Set the context path for this process. All subsequent log calls use it.
|
|
56
|
-
|
|
57
|
-
Call this once in your hook after resolving the context:
|
|
58
|
-
from lib.base.logger import set_context_path
|
|
59
|
-
set_context_path(get_context_dir(context_id, project_root))
|
|
60
|
-
|
|
61
|
-
Args:
|
|
62
|
-
path: Path to context folder (e.g., _output/contexts/<context-id>/)
|
|
63
|
-
or None to force global-only logging.
|
|
64
|
-
"""
|
|
65
|
-
global _cached_context_path, _context_resolved
|
|
66
|
-
_cached_context_path = path
|
|
67
|
-
_context_resolved = True
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def _auto_resolve_context_path() -> Optional[Path]:
|
|
71
|
-
"""Try to auto-resolve context path from session_id. Called once per process.
|
|
72
|
-
|
|
73
|
-
Uses the context store to look up which context owns this session,
|
|
74
|
-
then returns its directory path. Falls back to None (global log).
|
|
75
|
-
"""
|
|
76
|
-
global _cached_context_path, _context_resolved
|
|
77
|
-
_context_resolved = True # Don't retry on failure
|
|
78
|
-
|
|
79
|
-
try:
|
|
80
|
-
from ..context.context_store import get_context_by_session_id
|
|
81
|
-
from .constants import get_context_dir
|
|
82
|
-
|
|
83
|
-
# Hook input isn't available here, but we can check if a recent
|
|
84
|
-
# context dir exists by scanning _output/contexts/ for one that
|
|
85
|
-
# has a state.json with a matching session
|
|
86
|
-
# This is too expensive for a logger. Instead, rely on set_context_path().
|
|
87
|
-
except Exception:
|
|
88
|
-
pass
|
|
89
|
-
|
|
90
|
-
return None
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def _get_context_path() -> Optional[Path]:
|
|
94
|
-
"""Get the cached context path, auto-resolving on first call."""
|
|
95
|
-
global _context_resolved
|
|
96
|
-
if not _context_resolved:
|
|
97
|
-
_auto_resolve_context_path()
|
|
98
|
-
return _cached_context_path
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def _get_min_level() -> int:
|
|
102
|
-
"""Get minimum log level from environment."""
|
|
103
|
-
env = os.environ.get("HOOK_LOG_LEVEL", "debug").lower()
|
|
104
|
-
return _LEVELS.get(env, 0)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def _is_disabled() -> bool:
|
|
108
|
-
"""Check if file logging is disabled."""
|
|
109
|
-
if os.environ.get("HOOK_LOG_DISABLE") == "1":
|
|
110
|
-
return True
|
|
111
|
-
if os.environ.get("HOOK_ERROR_LOG_DISABLE") == "1":
|
|
112
|
-
return True
|
|
113
|
-
return False
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
def _get_project_root() -> Path:
|
|
117
|
-
"""Get project root from environment or cwd."""
|
|
118
|
-
env_dir = os.environ.get("CLAUDE_PROJECT_DIR", "")
|
|
119
|
-
return Path(env_dir) if env_dir else Path.cwd()
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def hook_log(
|
|
123
|
-
level: str,
|
|
124
|
-
hook_name: str,
|
|
125
|
-
message: str,
|
|
126
|
-
*,
|
|
127
|
-
component: str = "",
|
|
128
|
-
data: Any = None,
|
|
129
|
-
traceback_str: str = "",
|
|
130
|
-
stderr: bool = True,
|
|
131
|
-
) -> None:
|
|
132
|
-
"""Write a structured log entry to the global hook log.
|
|
133
|
-
|
|
134
|
-
All entries go to _output/hook-log.jsonl. Use the "sid" field
|
|
135
|
-
(set via set_session_id) to filter by session.
|
|
136
|
-
|
|
137
|
-
Args:
|
|
138
|
-
level: "debug" | "info" | "warn" | "error"
|
|
139
|
-
hook_name: Hook or module name (e.g., "session_end")
|
|
140
|
-
message: Log message
|
|
141
|
-
component: Sub-component (e.g., "git", "parse")
|
|
142
|
-
data: Optional structured data (must be JSON-serializable)
|
|
143
|
-
traceback_str: Optional traceback string
|
|
144
|
-
stderr: Also write to stderr (default: True)
|
|
145
|
-
"""
|
|
146
|
-
try:
|
|
147
|
-
level_lower = level.lower()
|
|
148
|
-
level_num = _LEVELS.get(level_lower, 0)
|
|
149
|
-
|
|
150
|
-
# Write to stderr if requested
|
|
151
|
-
if stderr:
|
|
152
|
-
prefix = f"[{hook_name}]"
|
|
153
|
-
if component:
|
|
154
|
-
prefix = f"[{hook_name}:{component}]"
|
|
155
|
-
print(f"{prefix} {message}", file=sys.stderr)
|
|
156
|
-
if traceback_str:
|
|
157
|
-
print(traceback_str, file=sys.stderr)
|
|
158
|
-
|
|
159
|
-
# Check if file logging is enabled
|
|
160
|
-
if _is_disabled():
|
|
161
|
-
return
|
|
162
|
-
|
|
163
|
-
# Check minimum level
|
|
164
|
-
if level_num < _get_min_level():
|
|
165
|
-
return
|
|
166
|
-
|
|
167
|
-
# Build JSONL entry
|
|
168
|
-
ts = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]
|
|
169
|
-
entry: Dict[str, Any] = {
|
|
170
|
-
"ts": ts,
|
|
171
|
-
"level": level_lower,
|
|
172
|
-
"hook": hook_name,
|
|
173
|
-
"msg": message,
|
|
174
|
-
}
|
|
175
|
-
if _cached_session_id:
|
|
176
|
-
entry["sid"] = _cached_session_id
|
|
177
|
-
if component:
|
|
178
|
-
entry["component"] = component
|
|
179
|
-
if data is not None:
|
|
180
|
-
try:
|
|
181
|
-
json.dumps(data, default=str) # Validate serializable
|
|
182
|
-
entry["data"] = data
|
|
183
|
-
except (TypeError, ValueError):
|
|
184
|
-
entry["data"] = str(data)
|
|
185
|
-
if traceback_str:
|
|
186
|
-
entry["tb"] = traceback_str.rstrip()
|
|
187
|
-
|
|
188
|
-
line = json.dumps(entry, ensure_ascii=True, default=str) + "\n"
|
|
189
|
-
|
|
190
|
-
# Always write to global log
|
|
191
|
-
project_root = _get_project_root()
|
|
192
|
-
log_path = project_root / "_output" / "hook-log.jsonl"
|
|
193
|
-
|
|
194
|
-
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
195
|
-
|
|
196
|
-
# Line-count guard: prune to last _MAX_LOG_LINES
|
|
197
|
-
if log_path.exists():
|
|
198
|
-
try:
|
|
199
|
-
with open(log_path, "r", encoding="utf-8", errors="replace") as f:
|
|
200
|
-
existing = f.readlines()
|
|
201
|
-
if len(existing) > _MAX_LOG_LINES:
|
|
202
|
-
with open(log_path, "w", encoding="utf-8") as f:
|
|
203
|
-
f.writelines(existing[-_MAX_LOG_LINES:])
|
|
204
|
-
except OSError:
|
|
205
|
-
pass
|
|
206
|
-
|
|
207
|
-
with open(log_path, "a", encoding="utf-8") as f:
|
|
208
|
-
f.write(line)
|
|
209
|
-
|
|
210
|
-
except Exception:
|
|
211
|
-
pass # Never crash
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
def log_debug(hook_name: str, message: str, **kwargs: Any) -> None:
|
|
215
|
-
"""Log a debug-level message."""
|
|
216
|
-
hook_log("debug", hook_name, message, **kwargs)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
def log_info(hook_name: str, message: str, **kwargs: Any) -> None:
|
|
220
|
-
"""Log an info-level message."""
|
|
221
|
-
hook_log("info", hook_name, message, **kwargs)
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
def log_warn(hook_name: str, message: str, **kwargs: Any) -> None:
|
|
225
|
-
"""Log a warn-level message."""
|
|
226
|
-
hook_log("warn", hook_name, message, **kwargs)
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
def log_error(hook_name: str, message: str, **kwargs: Any) -> None:
|
|
230
|
-
"""Log an error-level message."""
|
|
231
|
-
hook_log("error", hook_name, message, **kwargs)
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
def log_diagnostic(
|
|
235
|
-
hook_name: str,
|
|
236
|
-
phase: str,
|
|
237
|
-
summary: str,
|
|
238
|
-
*,
|
|
239
|
-
inputs: Any = None,
|
|
240
|
-
decision: Any = None,
|
|
241
|
-
reasoning: Any = None,
|
|
242
|
-
component: str = "diag",
|
|
243
|
-
data: Any = None,
|
|
244
|
-
) -> None:
|
|
245
|
-
"""Log a structured diagnostic entry at a hook decision point.
|
|
246
|
-
|
|
247
|
-
Emits a debug-level JSONL entry with tagged, filterable data.
|
|
248
|
-
Use at key decision points: receive (what came in), decide (what was chosen),
|
|
249
|
-
result (what happened).
|
|
250
|
-
|
|
251
|
-
Args:
|
|
252
|
-
hook_name: Hook or module name (e.g., "session_start")
|
|
253
|
-
phase: Decision phase — "receive", "decide", or "result"
|
|
254
|
-
summary: One-line description (e.g., "source=clear, session=a1b2c3d4")
|
|
255
|
-
inputs: Input data relevant to this phase
|
|
256
|
-
decision: The decision made (for "decide" phase)
|
|
257
|
-
reasoning: Why this decision was made
|
|
258
|
-
component: Log component tag (default: "diag")
|
|
259
|
-
data: Extra data to merge into the structured entry
|
|
260
|
-
"""
|
|
261
|
-
diag_data: Dict[str, Any] = {"phase": phase}
|
|
262
|
-
if inputs is not None:
|
|
263
|
-
diag_data["inputs"] = inputs
|
|
264
|
-
if decision is not None:
|
|
265
|
-
diag_data["decision"] = decision
|
|
266
|
-
if reasoning is not None:
|
|
267
|
-
diag_data["reasoning"] = reasoning
|
|
268
|
-
if data is not None and isinstance(data, dict):
|
|
269
|
-
diag_data.update(data)
|
|
270
|
-
hook_log(
|
|
271
|
-
"debug",
|
|
272
|
-
hook_name,
|
|
273
|
-
f"[DIAG:{phase}] {summary}",
|
|
274
|
-
component=component,
|
|
275
|
-
data=diag_data,
|
|
276
|
-
)
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
def log_hook_error(
|
|
280
|
-
hook_name: str,
|
|
281
|
-
error: Exception,
|
|
282
|
-
hook_event: str = "unknown",
|
|
283
|
-
traceback_str: str = "",
|
|
284
|
-
) -> None:
|
|
285
|
-
"""Backward-compatible wrapper matching the old hook_utils.log_hook_error signature.
|
|
286
|
-
|
|
287
|
-
Delegates to hook_log("error", ...) with the same behavior:
|
|
288
|
-
- Message capped at 200 chars, newlines stripped
|
|
289
|
-
- Never raises
|
|
290
|
-
|
|
291
|
-
Args:
|
|
292
|
-
hook_name: Name of the hook
|
|
293
|
-
error: The exception that occurred
|
|
294
|
-
hook_event: Hook event type (e.g., "PreToolUse")
|
|
295
|
-
traceback_str: Optional formatted traceback
|
|
296
|
-
"""
|
|
297
|
-
msg = str(error).replace("\n", " ").replace("\r", "")[:200]
|
|
298
|
-
err_type = type(error).__name__
|
|
299
|
-
hook_log(
|
|
300
|
-
"error",
|
|
301
|
-
hook_name,
|
|
302
|
-
f"[{hook_event}] {err_type}: {msg}",
|
|
303
|
-
traceback_str=traceback_str,
|
|
304
|
-
stderr=True,
|
|
305
|
-
)
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
"""Stop words for context ID generation.
|
|
2
|
-
|
|
3
|
-
Generated from analysis of 1,424 prompts, context summaries, and plan files.
|
|
4
|
-
Words that appear frequently but don't help identify the specific task.
|
|
5
|
-
|
|
6
|
-
Categories organized for maintainability. Add new corpus-derived words to
|
|
7
|
-
the appropriate category or to "Corpus-derived additions" at the end.
|
|
8
|
-
|
|
9
|
-
ACTION VERBS ARE INTENTIONALLY EXCLUDED from this list:
|
|
10
|
-
add, fix, update, create, implement, refactor, migrate, debug, remove, change,
|
|
11
|
-
move, rename, delete, build, test, deploy, verify, analyze, modify, write, run,
|
|
12
|
-
check, replace, save, sync, load, extract, install, refactor, clean, merge, etc.
|
|
13
|
-
|
|
14
|
-
These action verbs should REMAIN in context IDs as they identify the task type.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
STOP_WORDS = {
|
|
18
|
-
# ========================================================================
|
|
19
|
-
# ARTICLES
|
|
20
|
-
# ========================================================================
|
|
21
|
-
'a', 'an', 'the',
|
|
22
|
-
|
|
23
|
-
# ========================================================================
|
|
24
|
-
# PREPOSITIONS
|
|
25
|
-
# ========================================================================
|
|
26
|
-
'to', 'for', 'in', 'on', 'at', 'by', 'with', 'from', 'of', 'about',
|
|
27
|
-
'into', 'over', 'under', 'between', 'through', 'during', 'before', 'after',
|
|
28
|
-
'above', 'below', 'against', 'among', 'around', 'behind', 'beside', 'besides',
|
|
29
|
-
'beyond', 'down', 'inside', 'outside', 'near', 'off', 'onto', 'out',
|
|
30
|
-
'since', 'toward', 'towards', 'until', 'upon', 'within', 'without',
|
|
31
|
-
'across', 'along', 'via', 'per',
|
|
32
|
-
|
|
33
|
-
# ========================================================================
|
|
34
|
-
# PRONOUNS
|
|
35
|
-
# ========================================================================
|
|
36
|
-
# Personal pronouns
|
|
37
|
-
'i', 'you', 'he', 'she', 'it', 'we', 'they',
|
|
38
|
-
'me', 'him', 'her', 'us', 'them',
|
|
39
|
-
'myself', 'yourself', 'himself', 'herself', 'itself', 'ourselves', 'themselves',
|
|
40
|
-
|
|
41
|
-
# Possessive pronouns
|
|
42
|
-
'my', 'your', 'his', 'her', 'its', 'our', 'their',
|
|
43
|
-
'mine', 'yours', 'hers', 'ours', 'theirs',
|
|
44
|
-
|
|
45
|
-
# Demonstrative pronouns
|
|
46
|
-
'this', 'that', 'these', 'those',
|
|
47
|
-
|
|
48
|
-
# Relative pronouns
|
|
49
|
-
'who', 'whom', 'whose', 'which', 'that',
|
|
50
|
-
|
|
51
|
-
# Indefinite pronouns
|
|
52
|
-
'someone', 'somebody', 'something', 'anyone', 'anybody', 'anything',
|
|
53
|
-
'everyone', 'everybody', 'everything', 'no one', 'nobody', 'nothing',
|
|
54
|
-
'one', 'ones',
|
|
55
|
-
|
|
56
|
-
# ========================================================================
|
|
57
|
-
# AUXILIARY/MODAL VERBS
|
|
58
|
-
# ========================================================================
|
|
59
|
-
'am', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
|
|
60
|
-
'have', 'has', 'had', 'having',
|
|
61
|
-
'do', 'does', 'did', 'doing', 'done',
|
|
62
|
-
'can', 'could', 'will', 'would', 'shall', 'should', 'may', 'might', 'must',
|
|
63
|
-
|
|
64
|
-
# ========================================================================
|
|
65
|
-
# CONJUNCTIONS
|
|
66
|
-
# ========================================================================
|
|
67
|
-
'and', 'or', 'but', 'nor', 'so', 'yet', 'for',
|
|
68
|
-
'if', 'then', 'else', 'whether', 'unless', 'although', 'though',
|
|
69
|
-
'because', 'since', 'while', 'whereas', 'whenever', 'wherever',
|
|
70
|
-
|
|
71
|
-
# ========================================================================
|
|
72
|
-
# QUESTION WORDS
|
|
73
|
-
# ========================================================================
|
|
74
|
-
'what', 'when', 'where', 'why', 'how',
|
|
75
|
-
|
|
76
|
-
# ========================================================================
|
|
77
|
-
# ADVERBS OF PLACE/TIME
|
|
78
|
-
# ========================================================================
|
|
79
|
-
'here', 'there', 'now', 'then', 'always', 'never', 'often', 'sometimes',
|
|
80
|
-
'already', 'still', 'yet', 'soon', 'later', 'ago', 'today', 'tomorrow',
|
|
81
|
-
'yesterday', 'currently', 'previously', 'recently', 'immediately',
|
|
82
|
-
'finally', 'eventually', 'meanwhile', 'afterwards',
|
|
83
|
-
|
|
84
|
-
# ========================================================================
|
|
85
|
-
# NEGATION
|
|
86
|
-
# ========================================================================
|
|
87
|
-
'no', 'not', 'none', 'never', 'neither', 'nor',
|
|
88
|
-
'don', 'doesn', 'didn', 'won', 'wouldn', 'couldn', 'shouldn',
|
|
89
|
-
'isn', 'aren', 'wasn', 'weren', 'hasn', 'haven', 'hadn',
|
|
90
|
-
|
|
91
|
-
# ========================================================================
|
|
92
|
-
# QUANTIFIERS
|
|
93
|
-
# ========================================================================
|
|
94
|
-
'some', 'any', 'all', 'each', 'every', 'both', 'few', 'more', 'most',
|
|
95
|
-
'many', 'much', 'several', 'other', 'another', 'enough', 'less', 'least',
|
|
96
|
-
'either', 'neither', 'such',
|
|
97
|
-
|
|
98
|
-
# ========================================================================
|
|
99
|
-
# FILLER/HEDGE WORDS
|
|
100
|
-
# ========================================================================
|
|
101
|
-
'just', 'also', 'only', 'really', 'actually', 'basically', 'simply',
|
|
102
|
-
'very', 'quite', 'rather', 'pretty', 'somewhat', 'almost', 'nearly',
|
|
103
|
-
'exactly', 'completely', 'entirely', 'totally', 'absolutely',
|
|
104
|
-
'probably', 'possibly', 'maybe', 'perhaps', 'definitely', 'certainly',
|
|
105
|
-
'apparently', 'obviously', 'clearly', 'literally', 'essentially',
|
|
106
|
-
|
|
107
|
-
# ========================================================================
|
|
108
|
-
# SPEECH-TO-TEXT FILLERS (STT artifacts from voice input)
|
|
109
|
-
# ========================================================================
|
|
110
|
-
'um', 'uh', 'ah', 'oh', 'hmm', 'hm', 'er', 'eh', 'huh',
|
|
111
|
-
'hey', 'hi', 'hello', 'yeah', 'yep', 'yup', 'nah', 'nope',
|
|
112
|
-
'gonna', 'gotta', 'wanna', 'kinda', 'sorta',
|
|
113
|
-
'stuff', 'anyway', 'anyways', 'alright', 'right', 'well',
|
|
114
|
-
|
|
115
|
-
# ========================================================================
|
|
116
|
-
# COMMON REQUEST PHRASES (from corpus: high frequency in prompts)
|
|
117
|
-
# ========================================================================
|
|
118
|
-
'want', 'need', 'help', 'please', 'like', 'let', 'get',
|
|
119
|
-
'think', 'know', 'see', 'try', 'make', 'give', 'take',
|
|
120
|
-
'look', 'looking', 'trying', 'going', 'getting', 'making',
|
|
121
|
-
|
|
122
|
-
# ========================================================================
|
|
123
|
-
# COMMON NON-ACTION VERBS
|
|
124
|
-
# ========================================================================
|
|
125
|
-
'go', 'come', 'put', 'say', 'tell', 'ask', 'find', 'keep',
|
|
126
|
-
'seem', 'appear', 'become', 'remain', 'stay', 'feel', 'show', 'mean',
|
|
127
|
-
'include', 'provide', 'require', 'allow', 'expect', 'cause',
|
|
128
|
-
'follow', 'consider', 'continue', 'start', 'begin', 'end',
|
|
129
|
-
'contain', 'contain', 'contains',
|
|
130
|
-
|
|
131
|
-
# ========================================================================
|
|
132
|
-
# LINKING/TRANSITION WORDS
|
|
133
|
-
# ========================================================================
|
|
134
|
-
'however', 'therefore', 'thus', 'hence', 'otherwise', 'instead',
|
|
135
|
-
'moreover', 'furthermore', 'nevertheless', 'nonetheless', 'accordingly',
|
|
136
|
-
'consequently', 'similarly', 'likewise', 'conversely', 'alternatively',
|
|
137
|
-
|
|
138
|
-
# ========================================================================
|
|
139
|
-
# CORPUS-DERIVED HIGH-FREQUENCY NOISE (from 1,424 docs analysis)
|
|
140
|
-
# ========================================================================
|
|
141
|
-
# Words appearing in >10% of documents that don't identify the task
|
|
142
|
-
|
|
143
|
-
# File extensions/technical noise (appear in paths, not task descriptors)
|
|
144
|
-
'py', 'md', 'ts', 'json', 'js', 'yaml', 'toml', 'exe', 'bat',
|
|
145
|
-
|
|
146
|
-
# Common Claude/coding terms that don't identify specific tasks
|
|
147
|
-
'using', 'used', 'uses',
|
|
148
|
-
'based', 'following',
|
|
149
|
-
'same', 'different', 'specific', 'existing', 'new', 'current', 'first',
|
|
150
|
-
'full', 'complete', 'single', 'multiple', 'simple',
|
|
151
|
-
'needed', 'required', 'provided', 'expected', 'correctly',
|
|
152
|
-
'works', 'working', 'work',
|
|
153
|
-
|
|
154
|
-
# Common structural words from plan files
|
|
155
|
-
'step', 'steps', 'phase', 'below', 'above',
|
|
156
|
-
|
|
157
|
-
# Query/clarification language (high frequency in prompts)
|
|
158
|
-
'questions', 'question', 'clarification',
|
|
159
|
-
|
|
160
|
-
# Overly generic terms
|
|
161
|
-
'thing', 'things', 'way', 'ways', 'kind', 'type', 'types',
|
|
162
|
-
'example', 'examples', 'case', 'cases',
|
|
163
|
-
'part', 'parts', 'point', 'points',
|
|
164
|
-
'time', 'times', 'next', 'last', 'end',
|
|
165
|
-
'set', 'list', 'group', 'item', 'items',
|
|
166
|
-
|
|
167
|
-
# ========================================================================
|
|
168
|
-
# PROGRAMMING KEYWORDS (code tokens that leak from pasted code)
|
|
169
|
-
# ========================================================================
|
|
170
|
-
'self', 'def', 'return', 'import', 'true', 'false', 'none', 'str',
|
|
171
|
-
'const', 'async', 'class', 'assert', 'except', 'dict', 'len', 'args',
|
|
172
|
-
'sys', 'eprint', 'elif', 'lambda', 'yield', 'pass',
|
|
173
|
-
|
|
174
|
-
# ========================================================================
|
|
175
|
-
# GENERIC ADJECTIVES (non-specific modifiers)
|
|
176
|
-
# ========================================================================
|
|
177
|
-
'high', 'low', 'important', 'critical', 'optional', 'manual',
|
|
178
|
-
'real', 'empty', 'stable', 'active', 'proper', 'correct',
|
|
179
|
-
'basic', 'main', 'primary', 'secondary', 'general', 'overall',
|
|
180
|
-
|
|
181
|
-
# ========================================================================
|
|
182
|
-
# GENERIC TECHNICAL NOUNS (common but non-specific)
|
|
183
|
-
# ========================================================================
|
|
184
|
-
'information', 'format', 'status', 'method', 'purpose', 'result',
|
|
185
|
-
'source', 'value', 'option', 'options', 'feature', 'features', 'issue',
|
|
186
|
-
'process', 'version', 'mode', 'state',
|
|
187
|
-
|
|
188
|
-
# ========================================================================
|
|
189
|
-
# DOCUMENT/CODE STRUCTURE (generic structural terms)
|
|
190
|
-
# ========================================================================
|
|
191
|
-
'section', 'lines', 'line', 'folder', 'directory', 'index',
|
|
192
|
-
'level', 'block', 'chunk', 'region', 'header', 'footer',
|
|
193
|
-
|
|
194
|
-
# ========================================================================
|
|
195
|
-
# FRAGMENT WORDS (artifacts from contractions/tokenization)
|
|
196
|
-
# ========================================================================
|
|
197
|
-
're', 'pl', 'aiw', 've', 'll', 'doesn', 't', 's',
|
|
198
|
-
|
|
199
|
-
# ========================================================================
|
|
200
|
-
# CORPUS-DERIVED SHORT NOISE (2026-02 analysis of 131 docs)
|
|
201
|
-
# ========================================================================
|
|
202
|
-
# Contractions with punctuation stripped (I'm -> im, etc.)
|
|
203
|
-
'im', 'ive', 'id', 'ill', 'youre', 'youve', 'youll',
|
|
204
|
-
'hes', 'shes', 'weve', 'theyre', 'theyve', 'dont', 'doesnt',
|
|
205
|
-
'didnt', 'wont', 'wouldnt', 'cant', 'couldnt', 'shouldnt', 'isnt',
|
|
206
|
-
'arent', 'wasnt', 'werent', 'hasnt', 'havent', 'hadnt', 'lets',
|
|
207
|
-
'thats', 'whats', 'heres', 'theres', 'whos',
|
|
208
|
-
|
|
209
|
-
# Filler/noise from corpus (>10% frequency, non-action)
|
|
210
|
-
'etc', 'up', 'as', 'cc',
|
|
211
|
-
|
|
212
|
-
# Number words (common in plans but don't identify task)
|
|
213
|
-
'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten',
|
|
214
|
-
|
|
215
|
-
# Single letters (artifacts from lists, paths, variables)
|
|
216
|
-
'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
|
|
217
|
-
'q', 'r', 'u', 'v', 'w', 'x', 'y', 'z',
|
|
218
|
-
|
|
219
|
-
# Short adverbs/fillers from review
|
|
220
|
-
'too', 'yes', 'ok', 'okay',
|
|
221
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
"""Utilities for subprocess calls that invoke Claude Code CLI.
|
|
2
|
-
|
|
3
|
-
Provides centralized management of environment flags for internal subprocess calls
|
|
4
|
-
(orchestrator, agents, inference) to prevent recursion and unnecessary hook overhead.
|
|
5
|
-
"""
|
|
6
|
-
import os
|
|
7
|
-
from typing import Dict
|
|
8
|
-
|
|
9
|
-
# Environment variable names - single source of truth
|
|
10
|
-
ENV_INTERNAL_CALL = "AIWCLI_INTERNAL_CALL"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def get_internal_subprocess_env() -> Dict[str, str]:
|
|
14
|
-
"""Get environment dict for internal Claude Code subprocess calls.
|
|
15
|
-
|
|
16
|
-
This prevents internal subprocess calls (orchestrator, agents, inference)
|
|
17
|
-
from triggering hooks that would cause recursion or unnecessary overhead.
|
|
18
|
-
|
|
19
|
-
All hooks should check is_internal_call() and return early if True.
|
|
20
|
-
|
|
21
|
-
Returns:
|
|
22
|
-
Environment dict with AIWCLI_INTERNAL_CALL flag set
|
|
23
|
-
|
|
24
|
-
Example:
|
|
25
|
-
>>> env = get_internal_subprocess_env()
|
|
26
|
-
>>> subprocess.run(['claude', '--agent', 'my-agent'], env=env)
|
|
27
|
-
"""
|
|
28
|
-
env = os.environ.copy()
|
|
29
|
-
env[ENV_INTERNAL_CALL] = 'true'
|
|
30
|
-
return env
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def is_internal_call() -> bool:
|
|
34
|
-
"""Check if current process is an internal subprocess call.
|
|
35
|
-
|
|
36
|
-
Hooks should check this at the beginning and return early to avoid
|
|
37
|
-
recursion and unnecessary processing for internal subprocess calls.
|
|
38
|
-
|
|
39
|
-
Returns:
|
|
40
|
-
True if this is an internal call that should skip hooks
|
|
41
|
-
|
|
42
|
-
Example:
|
|
43
|
-
>>> if is_internal_call():
|
|
44
|
-
... return # Skip hook processing
|
|
45
|
-
"""
|
|
46
|
-
return os.environ.get(ENV_INTERNAL_CALL) == 'true'
|