claude-dev-env 8.105.2 → 8.106.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.
@@ -0,0 +1,301 @@
1
+ """Constants for the gate that stops walks and content searches over a Claude transcript root.
2
+
3
+ Holds the transcript root pattern and the marker word every root path holds,
4
+ the path parts the gate joins and splits on, the shell assignment and variable
5
+ reference patterns, the directory-change programs, the option grammar of each
6
+ POSIX search program and the PowerShell switches, the Grep and Glob tool names
7
+ and input keys, the hook name the block log records, and the deny message that
8
+ names the list-then-read fix.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import re
14
+ from dataclasses import dataclass
15
+
16
+ __all__ = [
17
+ "TRANSCRIPT_ROOT_PATTERN",
18
+ "TRANSCRIPT_ROOT_MARKER",
19
+ "PATH_SEPARATOR",
20
+ "WINDOWS_PATH_SEPARATOR",
21
+ "CURRENT_DIRECTORY",
22
+ "POWERSHELL_PATH_LIST_SEPARATOR",
23
+ "WILDCARD_ONLY_SEGMENT_PATTERN",
24
+ "RECURSIVE_GLOB_SEGMENT",
25
+ "ABSOLUTE_PATH_PATTERN",
26
+ "SHELL_ASSIGNMENT_PATTERN",
27
+ "SPACED_ASSIGNMENT_NAME_PATTERN",
28
+ "SPACED_ASSIGNMENT_OPERATOR",
29
+ "SPACED_ASSIGNMENT_TOKEN_COUNT",
30
+ "ALL_ASSIGNMENT_PREFIX_WORDS",
31
+ "SHELL_VARIABLE_SIGIL",
32
+ "SHELL_VARIABLE_REFERENCE_TEMPLATE",
33
+ "ALL_CHANGE_DIRECTORY_PROGRAM_NAMES",
34
+ "ALL_HOME_DEFAULT_CHANGE_DIRECTORY_PROGRAM_NAMES",
35
+ "ALL_PUSH_DIRECTORY_PROGRAM_NAMES",
36
+ "ALL_POP_DIRECTORY_PROGRAM_NAMES",
37
+ "HOME_DIRECTORY",
38
+ "FIND_MAXIMUM_DEPTH_OPTION",
39
+ "ALL_SHALLOW_DEPTH_VALUES",
40
+ "OPTION_PREFIX",
41
+ "LONG_OPTION_PREFIX",
42
+ "END_OF_OPTIONS_TOKEN",
43
+ "GLUED_OPTION_VALUE_SEPARATOR",
44
+ "RECURSE_DIRECTORIES_ACTION",
45
+ "PosixSearchGrammar",
46
+ "ALL_GREP_PROGRAM_NAMES",
47
+ "GREP_GRAMMAR",
48
+ "ALL_INDEXED_SEARCH_PROGRAM_NAMES",
49
+ "INDEXED_SEARCH_GRAMMAR",
50
+ "UNIX_LS_GRAMMAR",
51
+ "TREE_PROGRAM_NAME",
52
+ "TREE_GRAMMAR",
53
+ "POWERSHELL_TOOL_NAME",
54
+ "POWERSHELL_DEPTH_OPTION",
55
+ "POWERSHELL_NON_RECURSIVE_DEPTH",
56
+ "ALL_POWERSHELL_SWITCH_OPTIONS",
57
+ "POWERSHELL_GLUED_VALUE_SEPARATOR",
58
+ "POWERSHELL_MINIMUM_ABBREVIATION_LENGTH",
59
+ "ALL_POWERSHELL_ABBREVIABLE_OPTIONS",
60
+ "ALL_SELECT_STRING_PROGRAM_NAMES",
61
+ "GLOB_TOOL_NAME",
62
+ "ALL_FILE_SEARCH_TOOL_NAMES",
63
+ "TOOL_INPUT_PATH_KEY",
64
+ "TOOL_INPUT_PATTERN_KEY",
65
+ "TOOL_INPUT_COMMAND_KEY",
66
+ "PAYLOAD_TOOL_NAME_KEY",
67
+ "PAYLOAD_TOOL_INPUT_KEY",
68
+ "PAYLOAD_CWD_KEY",
69
+ "GATE_HOOK_NAME",
70
+ "TRANSCRIPT_ROOT_DENY_REASON_TEMPLATE",
71
+ ]
72
+
73
+ TRANSCRIPT_ROOT_PATTERN = re.compile(
74
+ r"(?:^|/)(?:\.claude|\.claude-profiles/[^/]+|\.claude-[^/]+)/projects(?=/|$)",
75
+ re.IGNORECASE,
76
+ )
77
+ TRANSCRIPT_ROOT_MARKER = "projects"
78
+ PATH_SEPARATOR = "/"
79
+ WINDOWS_PATH_SEPARATOR = "\\"
80
+ CURRENT_DIRECTORY = "."
81
+ POWERSHELL_PATH_LIST_SEPARATOR = ","
82
+ WILDCARD_ONLY_SEGMENT_PATTERN = re.compile(r"[*?.]*\*[*?.]*")
83
+ RECURSIVE_GLOB_SEGMENT = "**"
84
+ ABSOLUTE_PATH_PATTERN = re.compile(r"^(?:[A-Za-z]:|/|\\|~|\$)")
85
+
86
+ SHELL_ASSIGNMENT_PATTERN = re.compile(
87
+ r"^\$?(?:env:)?(?P<name>[A-Za-z_][A-Za-z0-9_]*)=(?P<value>.+)$"
88
+ )
89
+ SPACED_ASSIGNMENT_NAME_PATTERN = re.compile(r"^\$(?:env:)?(?P<name>[A-Za-z_][A-Za-z0-9_]*)$")
90
+ SPACED_ASSIGNMENT_OPERATOR = "="
91
+ SPACED_ASSIGNMENT_TOKEN_COUNT = 3
92
+ ALL_ASSIGNMENT_PREFIX_WORDS: frozenset[str] = frozenset({"export", "local", "declare", "set"})
93
+ SHELL_VARIABLE_SIGIL = "$"
94
+ SHELL_VARIABLE_REFERENCE_TEMPLATE = r"\$(?:\{{{name}\}}|(?:env:)?{name}(?![A-Za-z0-9_]))"
95
+ ALL_CHANGE_DIRECTORY_PROGRAM_NAMES: frozenset[str] = frozenset(
96
+ {"cd", "chdir", "pushd", "set-location", "sl", "push-location"}
97
+ )
98
+ ALL_HOME_DEFAULT_CHANGE_DIRECTORY_PROGRAM_NAMES: frozenset[str] = frozenset(
99
+ {"cd", "chdir", "set-location", "sl"}
100
+ )
101
+ ALL_PUSH_DIRECTORY_PROGRAM_NAMES: frozenset[str] = frozenset({"pushd", "push-location"})
102
+ ALL_POP_DIRECTORY_PROGRAM_NAMES: frozenset[str] = frozenset({"popd", "pop-location"})
103
+ HOME_DIRECTORY = "~"
104
+
105
+ FIND_MAXIMUM_DEPTH_OPTION = "-maxdepth"
106
+ ALL_SHALLOW_DEPTH_VALUES: frozenset[str] = frozenset({"0", "1"})
107
+ OPTION_PREFIX = "-"
108
+ LONG_OPTION_PREFIX = "--"
109
+ END_OF_OPTIONS_TOKEN = "--"
110
+ GLUED_OPTION_VALUE_SEPARATOR = "="
111
+ RECURSE_DIRECTORIES_ACTION = "recurse"
112
+
113
+
114
+ @dataclass(frozen=True)
115
+ class PosixSearchGrammar:
116
+ """How one POSIX search program reads its options and paths.
117
+
118
+ Attributes:
119
+ is_recursive_by_default: True when the program walks below its paths with no option.
120
+ all_recurse_options: Options that turn on recursion, such as ``-r`` or ``--recursive``.
121
+ all_value_letters: Short option letters that take a value, glued or as the next token.
122
+ all_value_options: Long options that take the next token as their value.
123
+ all_depth_options: Options whose value limits the depth; a shallow value stops recursion.
124
+ all_recurse_value_options: Options whose value ``recurse`` turns on recursion.
125
+ all_pattern_options: Options that supply the pattern or list files with no pattern,
126
+ so no positional pattern comes first.
127
+ takes_pattern_positional: True when the first positional is the pattern.
128
+ """
129
+
130
+ is_recursive_by_default: bool
131
+ all_recurse_options: frozenset[str] = frozenset()
132
+ all_value_letters: frozenset[str] = frozenset()
133
+ all_value_options: frozenset[str] = frozenset()
134
+ all_depth_options: frozenset[str] = frozenset()
135
+ all_recurse_value_options: frozenset[str] = frozenset()
136
+ all_pattern_options: frozenset[str] = frozenset()
137
+ takes_pattern_positional: bool = False
138
+
139
+
140
+ ALL_GREP_PROGRAM_NAMES: frozenset[str] = frozenset({"grep", "egrep", "fgrep"})
141
+ GREP_GRAMMAR = PosixSearchGrammar(
142
+ is_recursive_by_default=False,
143
+ all_recurse_options=frozenset({"-r", "-R", "--recursive", "--dereference-recursive"}),
144
+ all_value_letters=frozenset({"e", "f", "m", "A", "B", "C", "d", "D"}),
145
+ all_value_options=frozenset(
146
+ {
147
+ "--regexp",
148
+ "--file",
149
+ "--max-count",
150
+ "--after-context",
151
+ "--before-context",
152
+ "--context",
153
+ "--directories",
154
+ "--devices",
155
+ "--include",
156
+ "--exclude",
157
+ "--exclude-dir",
158
+ "--exclude-from",
159
+ "--label",
160
+ "--group-separator",
161
+ }
162
+ ),
163
+ all_recurse_value_options=frozenset({"-d", "--directories"}),
164
+ all_pattern_options=frozenset({"-e", "-f", "--regexp", "--file"}),
165
+ takes_pattern_positional=True,
166
+ )
167
+ ALL_INDEXED_SEARCH_PROGRAM_NAMES: frozenset[str] = frozenset({"rg", "ag", "ack", "fd", "fdfind"})
168
+ INDEXED_SEARCH_GRAMMAR = PosixSearchGrammar(
169
+ is_recursive_by_default=True,
170
+ all_value_letters=frozenset(
171
+ {"e", "f", "g", "t", "T", "m", "A", "B", "C", "d", "j", "M", "r", "E", "x", "X", "S", "G"}
172
+ ),
173
+ all_value_options=frozenset(
174
+ {
175
+ "--regexp",
176
+ "--file",
177
+ "--glob",
178
+ "--iglob",
179
+ "--type",
180
+ "--type-not",
181
+ "--type-add",
182
+ "--max-count",
183
+ "--after-context",
184
+ "--before-context",
185
+ "--context",
186
+ "--max-depth",
187
+ "--maxdepth",
188
+ "--depth",
189
+ "--threads",
190
+ "--max-columns",
191
+ "--max-filesize",
192
+ "--sort",
193
+ "--sortr",
194
+ "--encoding",
195
+ "--pre",
196
+ "--pre-glob",
197
+ "--engine",
198
+ "--path-separator",
199
+ "--replace",
200
+ "--color",
201
+ "--colors",
202
+ "--ignore",
203
+ "--file-search-regex",
204
+ "--extension",
205
+ "--exclude",
206
+ "--exec",
207
+ "--exec-batch",
208
+ "--size",
209
+ "--changed-within",
210
+ "--changed-before",
211
+ }
212
+ ),
213
+ all_depth_options=frozenset({"-d", "--max-depth", "--maxdepth", "--depth"}),
214
+ all_pattern_options=frozenset({"-e", "-f", "--regexp", "--file", "--files"}),
215
+ takes_pattern_positional=True,
216
+ )
217
+ UNIX_LS_GRAMMAR = PosixSearchGrammar(
218
+ is_recursive_by_default=False,
219
+ all_recurse_options=frozenset({"-R", "--recursive"}),
220
+ all_value_letters=frozenset({"I", "w", "T"}),
221
+ all_value_options=frozenset(
222
+ {"--ignore", "--hide", "--width", "--tabsize", "--sort", "--format", "--time-style"}
223
+ ),
224
+ )
225
+ TREE_PROGRAM_NAME = "tree"
226
+ TREE_GRAMMAR = PosixSearchGrammar(
227
+ is_recursive_by_default=True,
228
+ all_value_letters=frozenset({"L", "P", "I", "o", "H", "T"}),
229
+ all_value_options=frozenset({"--filelimit", "--charset", "--sort", "--timefmt"}),
230
+ all_depth_options=frozenset({"-L"}),
231
+ )
232
+
233
+ POWERSHELL_TOOL_NAME = "PowerShell"
234
+ POWERSHELL_DEPTH_OPTION = "-depth"
235
+ POWERSHELL_NON_RECURSIVE_DEPTH = "0"
236
+ ALL_POWERSHELL_SWITCH_OPTIONS: frozenset[str] = frozenset(
237
+ {
238
+ "-recurse",
239
+ "-r",
240
+ "-rec",
241
+ "-file",
242
+ "-directory",
243
+ "-ad",
244
+ "-af",
245
+ "-ah",
246
+ "-ar",
247
+ "-as",
248
+ "-force",
249
+ "-name",
250
+ "-hidden",
251
+ "-system",
252
+ "-readonly",
253
+ "-followsymlink",
254
+ "-list",
255
+ "-simplematch",
256
+ "-casesensitive",
257
+ "-notmatch",
258
+ "-allmatches",
259
+ "-quiet",
260
+ "-raw",
261
+ "-noemphasis",
262
+ "-wait",
263
+ "-verbose",
264
+ "-vb",
265
+ "-debug",
266
+ "-db",
267
+ "-whatif",
268
+ "-wi",
269
+ "-confirm",
270
+ "-cf",
271
+ "-usetransaction",
272
+ "-usetx",
273
+ }
274
+ )
275
+ POWERSHELL_GLUED_VALUE_SEPARATOR = ":"
276
+ POWERSHELL_MINIMUM_ABBREVIATION_LENGTH = 3
277
+ ALL_POWERSHELL_ABBREVIABLE_OPTIONS: frozenset[str] = ALL_POWERSHELL_SWITCH_OPTIONS | frozenset(
278
+ {POWERSHELL_DEPTH_OPTION, "-path", "-literalpath", "-filter", "-include", "-exclude"}
279
+ )
280
+ ALL_SELECT_STRING_PROGRAM_NAMES: frozenset[str] = frozenset({"select-string", "sls"})
281
+
282
+ GLOB_TOOL_NAME = "Glob"
283
+ ALL_FILE_SEARCH_TOOL_NAMES: frozenset[str] = frozenset({"Grep", GLOB_TOOL_NAME})
284
+ TOOL_INPUT_PATH_KEY = "path"
285
+ TOOL_INPUT_PATTERN_KEY = "pattern"
286
+ TOOL_INPUT_COMMAND_KEY = "command"
287
+ PAYLOAD_TOOL_NAME_KEY = "tool_name"
288
+ PAYLOAD_TOOL_INPUT_KEY = "tool_input"
289
+ PAYLOAD_CWD_KEY = "cwd"
290
+
291
+ GATE_HOOK_NAME = "transcript_root_search_gate.py"
292
+
293
+ TRANSCRIPT_ROOT_DENY_REASON_TEMPLATE = (
294
+ "BLOCKED: this call walks or searches every transcript under `{root}`. "
295
+ "A Claude transcript root holds thousands of JSONL session files, so a "
296
+ "recursive walk or content search there runs for minutes and times out. "
297
+ "Scope the search: list the project folders by name first, for example "
298
+ '`Get-ChildItem "{root}" -Directory -Filter "*<session id fragment>*"` or '
299
+ '`Glob(pattern="*<session id fragment>*", path="{root}")`, then read the one '
300
+ "transcript in the matching folder, or search inside that one folder."
301
+ )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-dev-env",
3
- "version": "8.105.2",
3
+ "version": "8.106.1",
4
4
  "description": "Claude Code development standards — rules, hooks, agents, commands, and skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -86,6 +86,7 @@ ALL_ACTION_BOUNDARY_EXEMPT_REGISTRATION_PATHS = (
86
86
  "blocking/resolve_thread_reply_gate.py",
87
87
  "blocking/turn_review_gate.py",
88
88
  "blocking/wakeup_cap_gate.py",
89
+ "blocking/transcript_root_search_gate.py",
89
90
  )
90
91
  ALL_TEST_DIRECTORY_NAMES = frozenset({"tests"})
91
92
  ALL_TEST_FILE_PREFIXES = ("test_",)