Skip to content

Commit 902e6d5

Browse files
committed
Update to ./context
1 parent ffa29f7 commit 902e6d5

File tree

3 files changed

+143
-107
lines changed

3 files changed

+143
-107
lines changed

context

Lines changed: 115 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Generates contextual information from a codebase to send to an LLM
55

66
# Default values
7-
FILES=""
7+
FILES=()
88
EXCLUDE=""
99
MAX_SIZE="500KB"
1010
INCLUDE_DEPS=false
@@ -15,11 +15,13 @@ FORMAT="md"
1515
SUMMARY=false
1616
SHOW_FILE_SIZES=false
1717
TRUNCATE_LARGE=""
18+
PROMPT_FILE=""
19+
VERBOSE=false
1820

1921
# Parse arguments
2022
while [[ "$#" -gt 0 ]]; do
2123
case $1 in
22-
--files=*) FILES="${1#*=}"; shift ;;
24+
--files=*) FILES+=("${1#*=}"); shift ;;
2325
--exclude=*) EXCLUDE="${1#*=}"; shift ;;
2426
--max-size=*) MAX_SIZE="${1#*=}"; shift ;;
2527
--include-deps) INCLUDE_DEPS=true; shift ;;
@@ -30,8 +32,10 @@ while [[ "$#" -gt 0 ]]; do
3032
--summary) SUMMARY=true; shift ;;
3133
--show-file-sizes) SHOW_FILE_SIZES=true; shift ;;
3234
--truncate-large=*) TRUNCATE_LARGE="${1#*=}"; shift ;;
35+
--prompt=*) PROMPT_FILE="${1#*=}"; shift ;;
36+
--verbose) VERBOSE=true; shift ;;
3337
--help|-h)
34-
echo "Usage: ./context [options]"
38+
echo "Usage: ./context [options] [file1 file2 ...]"
3539
echo ""
3640
echo "Options:"
3741
echo " --files=<pattern> File pattern to include (e.g., \"src/*.js\")"
@@ -45,19 +49,16 @@ while [[ "$#" -gt 0 ]]; do
4549
echo " --summary Include short summary of each file"
4650
echo " --show-file-sizes Include file sizes in output"
4751
echo " --truncate-large=<size> Truncate files larger than specified size (e.g., \"50KB\")"
52+
echo " --prompt=<file> Include prompt template from specified file"
53+
echo " --verbose Show verbose output"
4854
echo " --help, -h Show this help message"
4955
exit 0
5056
;;
51-
*) echo "Unknown parameter: $1"; exit 1 ;;
57+
--*) echo "Unknown parameter: $1"; exit 1 ;;
58+
*) FILES+=("$1"); shift ;;
5259
esac
5360
done
5461

55-
# Validate required parameters
56-
if [ -z "$FILES" ]; then
57-
echo "Error: --files parameter is required"
58-
exit 1
59-
fi
60-
6162
# Convert human-readable size to bytes
6263
convert_to_bytes() {
6364
local size=$1
@@ -80,23 +81,56 @@ fi
8081

8182
# Get all matching files
8283
find_files() {
83-
local find_cmd="find . -type f -path \"$FILES\""
84-
if [ -n "$EXCLUDE" ]; then
85-
find_cmd="$find_cmd -not -path \"$EXCLUDE\""
86-
fi
87-
eval $find_cmd | sort
84+
local all_files=""
85+
86+
# Process each file or pattern
87+
for file_pattern in "${FILES[@]}"; do
88+
# Check if it's a direct file path
89+
if [ -f "$file_pattern" ]; then
90+
all_files="$all_files"$'\n'"$file_pattern"
91+
else
92+
# It's a pattern, use find
93+
local find_cmd="find . -type f -path \"$file_pattern\""
94+
if [ -n "$EXCLUDE" ]; then
95+
find_cmd="$find_cmd -not -path \"$EXCLUDE\""
96+
fi
97+
local found_files=$(eval $find_cmd)
98+
if [ -n "$found_files" ]; then
99+
all_files="$all_files"$'\n'"$found_files"
100+
fi
101+
fi
102+
done
103+
104+
# Remove empty lines and sort
105+
echo "$all_files" | grep -v "^$" | sort | uniq
88106
}
89107

108+
# Handle empty file list
109+
if [ ${#FILES[@]} -eq 0 ]; then
110+
echo "Error: No files specified. Use --files=<pattern> or provide filenames directly."
111+
exit 1
112+
fi
113+
90114
ALL_FILES=$(find_files)
91115
TOTAL_SIZE=0
92116

93-
# Calculate current size
94-
for file in $ALL_FILES; do
95-
if [ -f "$file" ]; then
96-
file_size=$(wc -c < "$file")
97-
TOTAL_SIZE=$((TOTAL_SIZE + file_size))
98-
fi
99-
done
117+
# Human-readable size function
118+
human_readable_size() {
119+
local size=$1
120+
local units=("B" "KB" "MB" "GB" "TB")
121+
local unit_index=0
122+
local size_float=$size
123+
124+
while [ $(echo "$size_float >= 1024" | bc -l) -eq 1 ] && [ $unit_index -lt 4 ]; do
125+
size_float=$(echo "scale=2; $size_float / 1024" | bc -l)
126+
unit_index=$((unit_index + 1))
127+
done
128+
129+
# Remove trailing zeros and decimal point if it's a whole number
130+
size_float=$(echo $size_float | sed 's/\.0*$//')
131+
132+
echo "$size_float ${units[$unit_index]}"
133+
}
100134

101135
# Start the output based on format
102136
case $FORMAT in
@@ -117,63 +151,18 @@ case $FORMAT in
117151
;;
118152
esac
119153

120-
# Function to find dependencies in a file (basic implementation)
121-
find_dependencies() {
122-
local file=$1
123-
local ext=${file##*.}
124-
125-
case $ext in
126-
js|jsx|ts|tsx)
127-
grep -E "^import .+ from ['\"]\..*['\"]|^const .+ = require[[:space:]]*\(['\"]\..*['\"]\)" "$file" |
128-
sed -E "s/^import .+ from ['\"](\..*)['\"];?/\1/g;s/^const .+ = require[[:space:]]*\(['\"](\..*)['\"].*\);?/\1/g" |
129-
sed "s/'//g;s/\"//g"
130-
;;
131-
py)
132-
grep -E "^import .+|^from .+ import" "$file" |
133-
sed -E "s/^import (.+)/\1/g;s/^from (.+) import.*/\1/g" |
134-
grep -v "^import" | grep -v "^from"
135-
;;
136-
rb)
137-
grep -E "^require ['\"]\." "$file" |
138-
sed -E "s/^require ['\"](.+)['\"].*/\1/g"
139-
;;
140-
php)
141-
grep -E "^require|^include|^require_once|^include_once" "$file" |
142-
sed -E "s/^(require|include|require_once|include_once) ['\"](.+)['\"].*/\2/g"
143-
;;
144-
esac
145-
}
146-
147-
# Function to resolve a dependency path relative to a file
148-
resolve_dependency() {
149-
local base_file=$1
150-
local dep=$2
151-
local base_dir=$(dirname "$base_file")
152-
153-
# Handle file extensions if not specified
154-
if [[ ! "$dep" =~ \.[a-zA-Z0-9]+$ ]]; then
155-
# Try to find the file with common extensions
156-
for ext in js jsx ts tsx py rb php; do
157-
if [ -f "$base_dir/$dep.$ext" ]; then
158-
dep="$dep.$ext"
159-
break
160-
fi
161-
done
162-
fi
163-
164-
# Normalize the path
165-
local full_path="$base_dir/$dep"
166-
realpath "$full_path" 2>/dev/null || echo "$full_path"
167-
}
168-
169154
# Process each file
170155
file_count=0
171156
for file in $ALL_FILES; do
172157
if [ ! -f "$file" ]; then
158+
if [ "$VERBOSE" = true ]; then
159+
echo "Warning: File not found: $file" >&2
160+
fi
173161
continue
174162
fi
175163

176164
file_size=$(wc -c < "$file")
165+
TOTAL_SIZE=$((TOTAL_SIZE + file_size))
177166
truncated=false
178167
file_content=""
179168

@@ -197,7 +186,7 @@ for file in $ALL_FILES; do
197186
echo "### $file"
198187
if [ "$SHOW_FILE_SIZES" = true ]; then
199188
echo ""
200-
echo "Size: $(numfmt --to=iec-i --suffix=B $file_size)"
189+
echo "Size: $(human_readable_size $file_size)"
201190
echo ""
202191
fi
203192

@@ -242,7 +231,7 @@ for file in $ALL_FILES; do
242231
text)
243232
echo "=== $file ==="
244233
if [ "$SHOW_FILE_SIZES" = true ]; then
245-
echo "Size: $(numfmt --to=iec-i --suffix=B $file_size)"
234+
echo "Size: $(human_readable_size $file_size)"
246235
fi
247236

248237
if [ "$SUMMARY" = true ] && [ -n "$file_summary" ]; then
@@ -262,15 +251,11 @@ for file in $ALL_FILES; do
262251

263252
file_count=$((file_count + 1))
264253

265-
# Process dependencies if requested
254+
# Note: Dependency resolution disabled for now
266255
if [ "$INCLUDE_DEPS" = true ] && [ $DEPTH -gt 0 ]; then
267-
deps=$(find_dependencies "$file")
268-
for dep in $deps; do
269-
resolved_dep=$(resolve_dependency "$file" "$dep")
270-
if [ -f "$resolved_dep" ] && ! echo "$ALL_FILES" | grep -q "$resolved_dep"; then
271-
ALL_FILES="$ALL_FILES"$'\n'"$resolved_dep"
272-
fi
273-
done
256+
if [ "$VERBOSE" = true ]; then
257+
echo "Note: Dependency resolution is currently disabled" >&2
258+
fi
274259
fi
275260
done
276261

@@ -295,8 +280,9 @@ if [ "$INCLUDE_GIT" = true ] && command -v git >/dev/null 2>&1 && git rev-parse
295280
echo " ,"
296281
echo " \"git\": {"
297282
echo " \"commits\": ["
283+
commit_count=0
298284
git log -n $GIT_DEPTH --pretty=format:"%h|%s|%an|%ar" | while IFS="|" read -r hash message author date; do
299-
if [ "$hash" != "$(git log -n $GIT_DEPTH --pretty=format:"%h" | head -n1)" ]; then
285+
if [ $commit_count -gt 0 ]; then
300286
echo " ,"
301287
fi
302288
echo " {"
@@ -305,6 +291,7 @@ if [ "$INCLUDE_GIT" = true ] && command -v git >/dev/null 2>&1 && git rev-parse
305291
echo " \"author\": \"$(echo "$author" | sed 's/"/\\"/g')\","
306292
echo " \"date\": \"$date\""
307293
echo -n " }"
294+
commit_count=$((commit_count + 1))
308295
done
309296
echo ""
310297
echo " ],"
@@ -331,31 +318,53 @@ fi
331318
if [ "$FORMAT" = "json" ]; then
332319
echo ""
333320
echo " ]"
321+
322+
# Include prompt if specified
323+
if [ -n "$PROMPT_FILE" ] && [ -f "$PROMPT_FILE" ]; then
324+
prompt_content=$(cat "$PROMPT_FILE" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')
325+
echo " ,"
326+
echo " \"prompt\": \"$prompt_content\""
327+
fi
328+
334329
echo "}"
330+
else
331+
# Add context generation footer
332+
case $FORMAT in
333+
md)
334+
echo "## Context Information"
335+
echo ""
336+
echo "Generated on: $(date)"
337+
echo "Total files: $file_count"
338+
echo "Total size: $(human_readable_size $TOTAL_SIZE)"
339+
echo ""
340+
341+
# Include prompt template if specified
342+
if [ -n "$PROMPT_FILE" ] && [ -f "$PROMPT_FILE" ]; then
343+
echo "## Instructions for LLM"
344+
echo ""
345+
cat "$PROMPT_FILE"
346+
echo ""
347+
fi
348+
;;
349+
text)
350+
echo "CONTEXT INFORMATION"
351+
echo "------------------"
352+
echo ""
353+
echo "Generated on: $(date)"
354+
echo "Total files: $file_count"
355+
echo "Total size: $(human_readable_size $TOTAL_SIZE)"
356+
echo ""
357+
358+
# Include prompt template if specified
359+
if [ -n "$PROMPT_FILE" ] && [ -f "$PROMPT_FILE" ]; then
360+
echo "INSTRUCTIONS FOR LLM"
361+
echo "-------------------"
362+
echo ""
363+
cat "$PROMPT_FILE"
364+
echo ""
365+
fi
366+
;;
367+
esac
335368
fi
336369

337-
# Add context generation footer
338-
case $FORMAT in
339-
md)
340-
echo "## Context Information"
341-
echo ""
342-
echo "Generated on: $(date)"
343-
echo "Total files: $file_count"
344-
echo "Total size: $(numfmt --to=iec-i --suffix=B $TOTAL_SIZE)"
345-
echo ""
346-
;;
347-
json)
348-
# Already closed
349-
;;
350-
text)
351-
echo "CONTEXT INFORMATION"
352-
echo "------------------"
353-
echo ""
354-
echo "Generated on: $(date)"
355-
echo "Total files: $file_count"
356-
echo "Total size: $(numfmt --to=iec-i --suffix=B $TOTAL_SIZE)"
357-
echo ""
358-
;;
359-
esac
360-
361370
exit 0

docs/context.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,22 @@ The `context` tool extracts relevant code and context from your codebase to send
77
## Usage
88

99
```bash
10+
# Using patterns
1011
./context --files="src/components/*.js" --exclude="*.test.js" --max-size=300KB --format=md > context.txt
12+
13+
# Using direct file paths
14+
./context src/app.js src/utils.js README.md > context.txt
15+
16+
# Including a prompt template
17+
./context --prompt=prompts/context_prompt.txt app.js > context.txt
1118
```
1219

1320
## Arguments
1421

1522
| Argument | Description | Default |
1623
|----------|-------------|---------|
17-
| `--files=<pattern>` | File pattern to include (e.g., "src/*.js") | Required |
24+
| `--files=<pattern>` | File pattern to include (e.g., "src/*.js") | None |
25+
| Direct file arguments | Files or directories to include (e.g., app.js README.md) | None |
1826
| `--exclude=<pattern>` | File pattern to exclude (e.g., "node_modules/**") | None |
1927
| `--max-size=<size>` | Maximum context size in KB/MB (e.g., "500KB") | "500KB" |
2028
| `--include-deps` | Include dependent files based on imports/requires | False |
@@ -25,6 +33,7 @@ The `context` tool extracts relevant code and context from your codebase to send
2533
| `--summary` | Include short summary of each file | False |
2634
| `--show-file-sizes` | Include file sizes in output | False |
2735
| `--truncate-large=<size>` | Truncate files larger than specified size (e.g., "50KB") | None |
36+
| `--prompt=<file>` | Include prompt template from specified file | None |
2837

2938
## Examples
3039

prompts/context_prompt.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Please analyze the code provided above and suggest improvements, optimizations, or fixes.
2+
3+
If you make changes to the code, please format your response as follows:
4+
5+
1. First provide a summary of your changes and the reasoning behind them.
6+
2. Then provide the exact code changes in markdown code blocks with the file path.
7+
8+
For example:
9+
10+
```javascript src/utils.js
11+
function improvedFunction() {
12+
// Your improved code here
13+
}
14+
```
15+
16+
If you're creating new files, clearly indicate this at the beginning of the code block.
17+
18+
If you have any questions about the code or need clarification, please ask.

0 commit comments

Comments
 (0)