@paulduvall/claude-dev-toolkit 0.0.1-alpha.2 → 0.0.1-alpha.21
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/LICENSE +21 -0
- package/README.md +88 -37
- package/bin/claude-commands +307 -65
- package/commands/active/xarchitecture.md +393 -0
- package/commands/active/xconfig.md +127 -0
- package/commands/active/xcontinue.md +92 -0
- package/commands/active/xdebug.md +130 -0
- package/commands/active/xdocs.md +178 -0
- package/commands/active/xexplore.md +94 -0
- package/commands/active/xgit.md +149 -0
- package/commands/active/xpipeline.md +152 -0
- package/commands/active/xquality.md +96 -0
- package/commands/active/xrefactor.md +198 -0
- package/commands/active/xrelease.md +142 -0
- package/commands/active/xsecurity.md +92 -0
- package/commands/active/xspec.md +174 -0
- package/commands/active/xtdd.md +151 -0
- package/commands/active/xtest.md +89 -0
- package/commands/active/xverify.md +80 -0
- package/commands/experiments/xact.md +742 -0
- package/commands/experiments/xanalytics.md +113 -0
- package/commands/experiments/xanalyze.md +70 -0
- package/commands/experiments/xapi.md +161 -0
- package/commands/experiments/xatomic.md +112 -0
- package/commands/experiments/xaws.md +85 -0
- package/commands/experiments/xcicd.md +337 -0
- package/commands/experiments/xcommit.md +122 -0
- package/commands/experiments/xcompliance.md +182 -0
- package/commands/experiments/xconstraints.md +89 -0
- package/commands/experiments/xcoverage.md +90 -0
- package/commands/experiments/xdb.md +102 -0
- package/commands/experiments/xdesign.md +121 -0
- package/commands/experiments/xdevcontainer.md +238 -0
- package/commands/experiments/xevaluate.md +111 -0
- package/commands/experiments/xfootnote.md +12 -0
- package/commands/experiments/xgenerate.md +117 -0
- package/commands/experiments/xgovernance.md +149 -0
- package/commands/experiments/xgreen.md +66 -0
- package/commands/experiments/xiac.md +118 -0
- package/commands/experiments/xincident.md +137 -0
- package/commands/experiments/xinfra.md +115 -0
- package/commands/experiments/xknowledge.md +115 -0
- package/commands/experiments/xmaturity.md +120 -0
- package/commands/experiments/xmetrics.md +118 -0
- package/commands/experiments/xmonitoring.md +128 -0
- package/commands/experiments/xnew.md +903 -0
- package/commands/experiments/xobservable.md +114 -0
- package/commands/experiments/xoidc.md +165 -0
- package/commands/experiments/xoptimize.md +115 -0
- package/commands/experiments/xperformance.md +112 -0
- package/commands/experiments/xplanning.md +131 -0
- package/commands/experiments/xpolicy.md +115 -0
- package/commands/experiments/xproduct.md +98 -0
- package/commands/experiments/xreadiness.md +75 -0
- package/commands/experiments/xred.md +55 -0
- package/commands/experiments/xrisk.md +128 -0
- package/commands/experiments/xrules.md +124 -0
- package/commands/experiments/xsandbox.md +120 -0
- package/commands/experiments/xscan.md +102 -0
- package/commands/experiments/xsetup.md +123 -0
- package/commands/experiments/xtemplate.md +116 -0
- package/commands/experiments/xtrace.md +212 -0
- package/commands/experiments/xux.md +171 -0
- package/commands/experiments/xvalidate.md +104 -0
- package/commands/experiments/xworkflow.md +113 -0
- package/hooks/.smellrc.example.json +19 -0
- package/hooks/README.md +263 -0
- package/hooks/check-commit-signing.py +127 -0
- package/hooks/check-complexity.py +38 -0
- package/hooks/check-security.py +37 -0
- package/hooks/claude-wrapper.sh +29 -0
- package/hooks/config.py +110 -0
- package/hooks/file-logger.sh +100 -0
- package/hooks/lib/argument-parser.sh +427 -0
- package/hooks/lib/config-constants.sh +230 -0
- package/hooks/lib/context-manager.sh +560 -0
- package/hooks/lib/error-handler.sh +423 -0
- package/hooks/lib/execution-engine.sh +444 -0
- package/hooks/lib/execution-results.sh +113 -0
- package/hooks/lib/execution-simulation.sh +114 -0
- package/hooks/lib/field-validators.sh +104 -0
- package/hooks/lib/file-utils.sh +398 -0
- package/hooks/lib/subagent-discovery.sh +468 -0
- package/hooks/lib/subagent-validator.sh +407 -0
- package/hooks/lib/validation-reporter.sh +134 -0
- package/hooks/on-error-debug.sh +226 -0
- package/hooks/pre-commit-quality.sh +204 -0
- package/hooks/pre-commit-test-runner.sh +132 -0
- package/hooks/pre-write-security.sh +115 -0
- package/hooks/prevent-credential-exposure.sh +279 -0
- package/hooks/security_bandit.py +177 -0
- package/hooks/security_checks.py +97 -0
- package/hooks/security_secrets.py +81 -0
- package/hooks/security_trojan.py +61 -0
- package/hooks/settings.example.json +52 -0
- package/hooks/smell_checks.py +238 -0
- package/hooks/smell_javascript.py +231 -0
- package/hooks/smell_python.py +110 -0
- package/hooks/smell_ruff.py +70 -0
- package/hooks/smell_types.py +72 -0
- package/hooks/subagent-trigger-simple.sh +202 -0
- package/hooks/subagent-trigger.sh +253 -0
- package/hooks/suppression.py +82 -0
- package/hooks/tab-color.sh +70 -0
- package/hooks/verify-before-edit.sh +135 -0
- package/lib/backup-restore-command.js +140 -0
- package/lib/base/base-command.js +252 -0
- package/lib/base/command-result.js +184 -0
- package/lib/config/constants.js +255 -0
- package/lib/config.js +48 -6
- package/lib/configure-command.js +428 -0
- package/lib/dependency-validator.js +64 -5
- package/lib/hook-installer-core.js +2 -2
- package/lib/installation-instruction-generator.js +213 -495
- package/lib/installer.js +134 -56
- package/lib/oidc-command.js +740 -0
- package/lib/services/backup-list-service.js +226 -0
- package/lib/services/backup-service.js +230 -0
- package/lib/services/command-installer-service.js +217 -0
- package/lib/services/logger-service.js +201 -0
- package/lib/services/package-manager-service.js +319 -0
- package/lib/services/platform-instruction-service.js +294 -0
- package/lib/services/recovery-instruction-service.js +348 -0
- package/lib/services/restore-service.js +221 -0
- package/lib/setup-command.js +359 -0
- package/lib/setup-wizard.js +155 -262
- package/lib/uninstall-command.js +100 -0
- package/lib/utils/claude-path-config.js +184 -0
- package/lib/utils/file-system-utils.js +152 -0
- package/lib/utils.js +8 -4
- package/lib/verify-command.js +430 -0
- package/package.json +7 -3
- package/scripts/postinstall.js +172 -157
- package/subagents/debug-specialist.md +7 -0
- package/templates/README.md +115 -0
- package/templates/basic-settings.json +30 -0
- package/templates/comprehensive-settings.json +57 -0
- package/templates/global-claude.md +344 -0
- package/templates/hybrid-hook-config.yaml +132 -0
- package/templates/security-focused-settings.json +62 -0
- package/templates/subagent-hooks.yaml +188 -0
- package/lib/package-manager-service.js +0 -270
- package/subagents/debug-context.md +0 -197
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
|
|
4
|
+
# Context Management Module for Subagent-Hook Integration
|
|
5
|
+
#
|
|
6
|
+
# This module provides functionality to gather, manage, and pass context
|
|
7
|
+
# information to subagents during hook execution.
|
|
8
|
+
|
|
9
|
+
# Include guard
|
|
10
|
+
[[ -n "${_CONTEXT_MANAGER_LOADED:-}" ]] && return 0
|
|
11
|
+
_CONTEXT_MANAGER_LOADED=1
|
|
12
|
+
|
|
13
|
+
# Source required modules
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
+
source "$SCRIPT_DIR/config-constants.sh"
|
|
16
|
+
source "$SCRIPT_DIR/file-utils.sh"
|
|
17
|
+
source "$SCRIPT_DIR/error-handler.sh"
|
|
18
|
+
|
|
19
|
+
##################################
|
|
20
|
+
# Context Structure
|
|
21
|
+
##################################
|
|
22
|
+
|
|
23
|
+
# Global variables for context management (compatible with older bash versions)
|
|
24
|
+
CONTEXT_FILE=""
|
|
25
|
+
# CONTEXT_TIMEOUT is defined in config-constants.sh as readonly
|
|
26
|
+
CONTEXT_DATA=""
|
|
27
|
+
|
|
28
|
+
##################################
|
|
29
|
+
# Context Gathering Functions
|
|
30
|
+
##################################
|
|
31
|
+
|
|
32
|
+
gather_basic_context() {
|
|
33
|
+
local event_type="${1:-unknown}"
|
|
34
|
+
local subagent_name="${2:-unknown}"
|
|
35
|
+
local additional_context="${3:-}"
|
|
36
|
+
|
|
37
|
+
log_debug "Gathering basic context for $subagent_name (event: $event_type)"
|
|
38
|
+
|
|
39
|
+
# Create base context structure
|
|
40
|
+
local safe_event safe_name safe_user safe_wd
|
|
41
|
+
safe_event=$(json_escape "$event_type")
|
|
42
|
+
safe_name=$(json_escape "$subagent_name")
|
|
43
|
+
safe_user=$(json_escape "$USER")
|
|
44
|
+
safe_wd=$(json_escape "$(pwd)")
|
|
45
|
+
|
|
46
|
+
local context_json
|
|
47
|
+
context_json=$(cat <<EOF
|
|
48
|
+
{
|
|
49
|
+
"metadata": {
|
|
50
|
+
"timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
|
|
51
|
+
"hook_version": "$SUBAGENT_HOOK_VERSION",
|
|
52
|
+
"api_version": "$API_VERSION"
|
|
53
|
+
},
|
|
54
|
+
"event": {
|
|
55
|
+
"type": "$safe_event",
|
|
56
|
+
"trigger": "${CLAUDE_HOOK_TRIGGER:-manual}",
|
|
57
|
+
"subagent": "$safe_name"
|
|
58
|
+
},
|
|
59
|
+
"environment": {
|
|
60
|
+
"user": "$safe_user",
|
|
61
|
+
"working_directory": "$safe_wd",
|
|
62
|
+
"process_id": $$,
|
|
63
|
+
"session_id": "${CLAUDE_SESSION_ID:-$$}"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
EOF
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
CONTEXT_DATA="$context_json"
|
|
70
|
+
log_debug "Basic context gathered successfully"
|
|
71
|
+
return $EXIT_SUCCESS
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
gather_claude_context() {
|
|
75
|
+
local current_context="$CONTEXT_DATA"
|
|
76
|
+
|
|
77
|
+
log_debug "Gathering Claude-specific context"
|
|
78
|
+
|
|
79
|
+
# Extract Claude environment variables
|
|
80
|
+
local claude_context
|
|
81
|
+
claude_context=$(cat <<EOF
|
|
82
|
+
{
|
|
83
|
+
"claude": {
|
|
84
|
+
"tool": "${CLAUDE_TOOL:-unknown}",
|
|
85
|
+
"file": "${CLAUDE_FILE:-none}",
|
|
86
|
+
"content": "${CLAUDE_CONTENT:-none}",
|
|
87
|
+
"version": "${CLAUDE_VERSION:-unknown}",
|
|
88
|
+
"project": "${CLAUDE_PROJECT:-unknown}",
|
|
89
|
+
"security_override": "disabled"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
EOF
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Merge with existing context
|
|
96
|
+
CONTEXT_DATA=$(echo "$current_context" | jq --argjson claude "$(echo "$claude_context" | jq '.claude')" '. + {claude: $claude}' 2>/dev/null) || {
|
|
97
|
+
log_warning "Failed to merge Claude context with jq, using concatenation"
|
|
98
|
+
CONTEXT_DATA="$current_context,$claude_context"
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
log_debug "Claude context gathered successfully"
|
|
102
|
+
return $EXIT_SUCCESS
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
gather_git_context() {
|
|
106
|
+
local current_context="$CONTEXT_DATA"
|
|
107
|
+
|
|
108
|
+
log_debug "Gathering Git context"
|
|
109
|
+
|
|
110
|
+
local git_branch git_commit git_status git_remote
|
|
111
|
+
git_branch=$(git branch --show-current 2>/dev/null || echo "not-in-git")
|
|
112
|
+
git_commit=$(git rev-parse HEAD 2>/dev/null || echo "unknown")
|
|
113
|
+
git_remote=$(git remote get-url origin 2>/dev/null || echo "none")
|
|
114
|
+
|
|
115
|
+
# Get git status in a safe way
|
|
116
|
+
local git_changes="clean"
|
|
117
|
+
if git status --porcelain 2>/dev/null | grep -q .; then
|
|
118
|
+
git_changes="modified"
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
local git_context
|
|
122
|
+
git_context=$(cat <<EOF
|
|
123
|
+
{
|
|
124
|
+
"git": {
|
|
125
|
+
"branch": "$git_branch",
|
|
126
|
+
"commit": "${git_commit:0:8}",
|
|
127
|
+
"status": "$git_changes",
|
|
128
|
+
"remote": "$git_remote",
|
|
129
|
+
"in_repo": $(if [[ "$git_branch" != "not-in-git" ]]; then echo "true"; else echo "false"; fi)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
EOF
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Merge with existing context
|
|
136
|
+
CONTEXT_DATA=$(echo "$current_context" | jq --argjson git "$(echo "$git_context" | jq '.git')" '. + {git: $git}' 2>/dev/null) || {
|
|
137
|
+
log_warning "Failed to merge Git context with jq, using concatenation"
|
|
138
|
+
CONTEXT_DATA="$current_context,$git_context"
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
log_debug "Git context gathered successfully"
|
|
142
|
+
return $EXIT_SUCCESS
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
gather_file_context() {
|
|
146
|
+
local file_path="${CLAUDE_FILE:-}"
|
|
147
|
+
local current_context="$CONTEXT_DATA"
|
|
148
|
+
|
|
149
|
+
if [[ -z "$file_path" ]] || [[ "$file_path" == "none" ]]; then
|
|
150
|
+
log_debug "No file context to gather"
|
|
151
|
+
return $EXIT_SUCCESS
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
log_debug "Gathering file context for: $file_path"
|
|
155
|
+
|
|
156
|
+
local file_info=""
|
|
157
|
+
local file_type="unknown"
|
|
158
|
+
local file_size="0"
|
|
159
|
+
local file_permissions="unknown"
|
|
160
|
+
|
|
161
|
+
if [[ -f "$file_path" ]]; then
|
|
162
|
+
file_type=$(file -b "$file_path" 2>/dev/null || echo "unknown")
|
|
163
|
+
file_size=$(stat -f%z "$file_path" 2>/dev/null || stat -c%s "$file_path" 2>/dev/null || echo "0")
|
|
164
|
+
file_permissions=$(stat -f%A "$file_path" 2>/dev/null || stat -c%a "$file_path" 2>/dev/null || echo "unknown")
|
|
165
|
+
|
|
166
|
+
# Get file extension
|
|
167
|
+
local file_ext="${file_path##*.}"
|
|
168
|
+
[[ "$file_ext" == "$file_path" ]] && file_ext="none"
|
|
169
|
+
|
|
170
|
+
file_info="exists"
|
|
171
|
+
elif [[ -d "$file_path" ]]; then
|
|
172
|
+
file_info="directory"
|
|
173
|
+
file_type="directory"
|
|
174
|
+
else
|
|
175
|
+
file_info="not_found"
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
local file_context
|
|
179
|
+
file_context=$(cat <<EOF
|
|
180
|
+
{
|
|
181
|
+
"file": {
|
|
182
|
+
"path": "$file_path",
|
|
183
|
+
"name": "$(basename "$file_path")",
|
|
184
|
+
"directory": "$(dirname "$file_path")",
|
|
185
|
+
"extension": "${file_ext:-none}",
|
|
186
|
+
"type": "$file_type",
|
|
187
|
+
"size": $file_size,
|
|
188
|
+
"permissions": "$file_permissions",
|
|
189
|
+
"status": "$file_info"
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
EOF
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# Merge with existing context
|
|
196
|
+
CONTEXT_DATA=$(echo "$current_context" | jq --argjson file "$(echo "$file_context" | jq '.file')" '. + {file: $file}' 2>/dev/null) || {
|
|
197
|
+
log_warning "Failed to merge file context with jq, using concatenation"
|
|
198
|
+
CONTEXT_DATA="$current_context,$file_context"
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
log_debug "File context gathered successfully"
|
|
202
|
+
return $EXIT_SUCCESS
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
gather_system_context() {
|
|
206
|
+
local current_context="$CONTEXT_DATA"
|
|
207
|
+
|
|
208
|
+
log_debug "Gathering system context"
|
|
209
|
+
|
|
210
|
+
local system_context
|
|
211
|
+
system_context=$(cat <<EOF
|
|
212
|
+
{
|
|
213
|
+
"system": {
|
|
214
|
+
"hostname": "redacted",
|
|
215
|
+
"os": "$(uname -s 2>/dev/null || echo 'unknown')",
|
|
216
|
+
"architecture": "$(uname -m 2>/dev/null || echo 'unknown')",
|
|
217
|
+
"shell": "${SHELL##*/}",
|
|
218
|
+
"term": "${TERM:-unknown}",
|
|
219
|
+
"lang": "${LANG:-unknown}",
|
|
220
|
+
"timezone": "$(date +%Z 2>/dev/null || echo 'unknown')",
|
|
221
|
+
"uptime": "$(uptime 2>/dev/null | cut -d',' -f1 | sed 's/.*up //' || echo 'unknown')"
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
EOF
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# Merge with existing context
|
|
228
|
+
CONTEXT_DATA=$(echo "$current_context" | jq --argjson system "$(echo "$system_context" | jq '.system')" '. + {system: $system}' 2>/dev/null) || {
|
|
229
|
+
log_warning "Failed to merge system context with jq, using concatenation"
|
|
230
|
+
CONTEXT_DATA="$current_context,$system_context"
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
log_debug "System context gathered successfully"
|
|
234
|
+
return $EXIT_SUCCESS
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
##################################
|
|
238
|
+
# Context File Management
|
|
239
|
+
##################################
|
|
240
|
+
|
|
241
|
+
create_context_file() {
|
|
242
|
+
local subagent_name="${1:-unknown}"
|
|
243
|
+
local event_type="${2:-unknown}"
|
|
244
|
+
|
|
245
|
+
log_debug "Creating context file for $subagent_name"
|
|
246
|
+
|
|
247
|
+
# Generate unique context file name
|
|
248
|
+
local temp_file
|
|
249
|
+
if ! temp_file=$(create_temp_file "$CONTEXT_FILE_PREFIX" "${subagent_name}-${event_type}-$$"); then
|
|
250
|
+
log_error "Failed to create context temp file"
|
|
251
|
+
return $EXIT_GENERAL_ERROR
|
|
252
|
+
fi
|
|
253
|
+
|
|
254
|
+
CONTEXT_FILE="$temp_file"
|
|
255
|
+
log_debug "Context file created: $CONTEXT_FILE"
|
|
256
|
+
return $EXIT_SUCCESS
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
write_context_to_file() {
|
|
260
|
+
local context_file="${1:-$CONTEXT_FILE}"
|
|
261
|
+
local context_data="${2:-$CONTEXT_DATA}"
|
|
262
|
+
|
|
263
|
+
if [[ -z "$context_file" ]]; then
|
|
264
|
+
log_error "Context file path not specified"
|
|
265
|
+
return $EXIT_GENERAL_ERROR
|
|
266
|
+
fi
|
|
267
|
+
|
|
268
|
+
if [[ -z "$context_data" ]]; then
|
|
269
|
+
log_error "No context data to write"
|
|
270
|
+
return $EXIT_GENERAL_ERROR
|
|
271
|
+
fi
|
|
272
|
+
|
|
273
|
+
log_debug "Writing context data to file: $context_file"
|
|
274
|
+
|
|
275
|
+
# Validate JSON format if possible
|
|
276
|
+
if command -v jq >/dev/null 2>&1; then
|
|
277
|
+
if ! echo "$context_data" | jq . >/dev/null 2>&1; then
|
|
278
|
+
log_warning "Context data is not valid JSON, writing as-is"
|
|
279
|
+
fi
|
|
280
|
+
fi
|
|
281
|
+
|
|
282
|
+
# Write context data to file
|
|
283
|
+
if ! echo "$context_data" > "$context_file" 2>/dev/null; then
|
|
284
|
+
log_error "Failed to write context data to file: $context_file"
|
|
285
|
+
return $EXIT_GENERAL_ERROR
|
|
286
|
+
fi
|
|
287
|
+
|
|
288
|
+
log_debug "Context data written successfully: $context_file"
|
|
289
|
+
return $EXIT_SUCCESS
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
##################################
|
|
293
|
+
# Complete Context Gathering
|
|
294
|
+
##################################
|
|
295
|
+
|
|
296
|
+
gather_complete_context() {
|
|
297
|
+
local event_type="${1:-unknown}"
|
|
298
|
+
local subagent_name="${2:-unknown}"
|
|
299
|
+
local additional_context="${3:-}"
|
|
300
|
+
local include_system="${4:-false}"
|
|
301
|
+
|
|
302
|
+
log_info "Gathering complete context for subagent: $subagent_name"
|
|
303
|
+
|
|
304
|
+
# Gather all context components
|
|
305
|
+
if ! gather_basic_context "$event_type" "$subagent_name" "$additional_context"; then
|
|
306
|
+
log_error "Failed to gather basic context"
|
|
307
|
+
return $EXIT_GENERAL_ERROR
|
|
308
|
+
fi
|
|
309
|
+
|
|
310
|
+
if ! gather_claude_context; then
|
|
311
|
+
log_error "Failed to gather Claude context"
|
|
312
|
+
return $EXIT_GENERAL_ERROR
|
|
313
|
+
fi
|
|
314
|
+
|
|
315
|
+
if ! gather_git_context; then
|
|
316
|
+
log_warning "Failed to gather Git context (continuing)"
|
|
317
|
+
fi
|
|
318
|
+
|
|
319
|
+
if ! gather_file_context; then
|
|
320
|
+
log_warning "Failed to gather file context (continuing)"
|
|
321
|
+
fi
|
|
322
|
+
|
|
323
|
+
if [[ "$include_system" == true ]]; then
|
|
324
|
+
if ! gather_system_context; then
|
|
325
|
+
log_warning "Failed to gather system context (continuing)"
|
|
326
|
+
fi
|
|
327
|
+
fi
|
|
328
|
+
|
|
329
|
+
# Add additional context if provided
|
|
330
|
+
if [[ -n "$additional_context" ]]; then
|
|
331
|
+
add_additional_context "$additional_context"
|
|
332
|
+
fi
|
|
333
|
+
|
|
334
|
+
log_info "Complete context gathering finished"
|
|
335
|
+
return $EXIT_SUCCESS
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
add_additional_context() {
|
|
339
|
+
local additional_context="$1"
|
|
340
|
+
local current_context="$CONTEXT_DATA"
|
|
341
|
+
|
|
342
|
+
if [[ -z "$additional_context" ]]; then
|
|
343
|
+
return $EXIT_SUCCESS
|
|
344
|
+
fi
|
|
345
|
+
|
|
346
|
+
log_debug "Adding additional context"
|
|
347
|
+
|
|
348
|
+
local additional_json
|
|
349
|
+
additional_json=$(cat <<EOF
|
|
350
|
+
{
|
|
351
|
+
"additional": {
|
|
352
|
+
"user_provided": "$additional_context",
|
|
353
|
+
"timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
EOF
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
# Merge with existing context
|
|
360
|
+
CONTEXT_DATA=$(echo "$current_context" | jq --argjson additional "$(echo "$additional_json" | jq '.additional')" '. + {additional: $additional}' 2>/dev/null) || {
|
|
361
|
+
log_warning "Failed to merge additional context with jq"
|
|
362
|
+
CONTEXT_DATA="$current_context,$additional_json"
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
log_debug "Additional context added successfully"
|
|
366
|
+
return $EXIT_SUCCESS
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
##################################
|
|
370
|
+
# Context Validation Functions
|
|
371
|
+
##################################
|
|
372
|
+
|
|
373
|
+
validate_context_data() {
|
|
374
|
+
local context_data="${1:-$CONTEXT_DATA}"
|
|
375
|
+
|
|
376
|
+
if [[ -z "$context_data" ]]; then
|
|
377
|
+
log_error "No context data to validate"
|
|
378
|
+
return $EXIT_VALIDATION_FAILED
|
|
379
|
+
fi
|
|
380
|
+
|
|
381
|
+
log_debug "Validating context data"
|
|
382
|
+
|
|
383
|
+
# Check if it's valid JSON
|
|
384
|
+
if command -v jq >/dev/null 2>&1; then
|
|
385
|
+
if ! echo "$context_data" | jq . >/dev/null 2>&1; then
|
|
386
|
+
log_error "Context data is not valid JSON"
|
|
387
|
+
return $EXIT_VALIDATION_FAILED
|
|
388
|
+
fi
|
|
389
|
+
fi
|
|
390
|
+
|
|
391
|
+
# Check for required fields
|
|
392
|
+
local required_fields=("metadata" "event" "environment")
|
|
393
|
+
local field
|
|
394
|
+
|
|
395
|
+
for field in "${required_fields[@]}"; do
|
|
396
|
+
if command -v jq >/dev/null 2>&1; then
|
|
397
|
+
if ! echo "$context_data" | jq -e ".$field" >/dev/null 2>&1; then
|
|
398
|
+
log_error "Required context field missing: $field"
|
|
399
|
+
return $EXIT_VALIDATION_FAILED
|
|
400
|
+
fi
|
|
401
|
+
else
|
|
402
|
+
# Fallback validation without jq
|
|
403
|
+
if ! echo "$context_data" | grep -q "\"$field\""; then
|
|
404
|
+
log_error "Required context field missing: $field"
|
|
405
|
+
return $EXIT_VALIDATION_FAILED
|
|
406
|
+
fi
|
|
407
|
+
fi
|
|
408
|
+
done
|
|
409
|
+
|
|
410
|
+
log_debug "Context data validation passed"
|
|
411
|
+
return $EXIT_SUCCESS
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
validate_context_file() {
|
|
415
|
+
local context_file="${1:-$CONTEXT_FILE}"
|
|
416
|
+
|
|
417
|
+
if [[ -z "$context_file" ]]; then
|
|
418
|
+
log_error "No context file specified"
|
|
419
|
+
return $EXIT_VALIDATION_FAILED
|
|
420
|
+
fi
|
|
421
|
+
|
|
422
|
+
if ! file_exists_and_readable "$context_file"; then
|
|
423
|
+
log_error "Context file not accessible: $context_file"
|
|
424
|
+
return $EXIT_VALIDATION_FAILED
|
|
425
|
+
fi
|
|
426
|
+
|
|
427
|
+
# Read and validate content
|
|
428
|
+
local content
|
|
429
|
+
if ! content=$(read_file_safely "$context_file"); then
|
|
430
|
+
log_error "Failed to read context file: $context_file"
|
|
431
|
+
return $EXIT_VALIDATION_FAILED
|
|
432
|
+
fi
|
|
433
|
+
|
|
434
|
+
if ! validate_context_data "$content"; then
|
|
435
|
+
log_error "Context file contains invalid data: $context_file"
|
|
436
|
+
return $EXIT_VALIDATION_FAILED
|
|
437
|
+
fi
|
|
438
|
+
|
|
439
|
+
log_debug "Context file validation passed: $context_file"
|
|
440
|
+
return $EXIT_SUCCESS
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
##################################
|
|
444
|
+
# Context Cleanup Functions
|
|
445
|
+
##################################
|
|
446
|
+
|
|
447
|
+
cleanup_context_file() {
|
|
448
|
+
local context_file="${1:-$CONTEXT_FILE}"
|
|
449
|
+
|
|
450
|
+
if [[ -n "$context_file" ]] && [[ -f "$context_file" ]]; then
|
|
451
|
+
log_debug "Cleaning up context file: $context_file"
|
|
452
|
+
cleanup_specific_temp_file "$context_file"
|
|
453
|
+
fi
|
|
454
|
+
|
|
455
|
+
# Reset global variables
|
|
456
|
+
CONTEXT_FILE=""
|
|
457
|
+
CONTEXT_DATA=""
|
|
458
|
+
|
|
459
|
+
return $EXIT_SUCCESS
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
cleanup_all_context_files() {
|
|
463
|
+
log_debug "Cleaning up all context files"
|
|
464
|
+
|
|
465
|
+
# Clean up temporary context files
|
|
466
|
+
cleanup_temp_files "$CONTEXT_FILE_PREFIX*"
|
|
467
|
+
|
|
468
|
+
return $EXIT_SUCCESS
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
##################################
|
|
472
|
+
# Context Access Functions
|
|
473
|
+
##################################
|
|
474
|
+
|
|
475
|
+
get_context_file() {
|
|
476
|
+
echo "$CONTEXT_FILE"
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
get_context_data() {
|
|
480
|
+
echo "$CONTEXT_DATA"
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
get_context_field() {
|
|
484
|
+
local field_path="$1"
|
|
485
|
+
local context_data="${2:-$CONTEXT_DATA}"
|
|
486
|
+
|
|
487
|
+
if [[ -z "$field_path" ]]; then
|
|
488
|
+
log_error "Field path is required"
|
|
489
|
+
return $EXIT_VALIDATION_FAILED
|
|
490
|
+
fi
|
|
491
|
+
|
|
492
|
+
if command -v jq >/dev/null 2>&1; then
|
|
493
|
+
echo "$context_data" | jq -r "$field_path" 2>/dev/null || echo ""
|
|
494
|
+
else
|
|
495
|
+
log_warning "jq not available, cannot extract field: $field_path"
|
|
496
|
+
return $EXIT_GENERAL_ERROR
|
|
497
|
+
fi
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
##################################
|
|
501
|
+
# Context Debugging Functions
|
|
502
|
+
##################################
|
|
503
|
+
|
|
504
|
+
dump_context() {
|
|
505
|
+
local format="${1:-json}"
|
|
506
|
+
local context_data="${2:-$CONTEXT_DATA}"
|
|
507
|
+
|
|
508
|
+
log_info "Dumping context (format: $format)"
|
|
509
|
+
|
|
510
|
+
case "$format" in
|
|
511
|
+
"json")
|
|
512
|
+
if command -v jq >/dev/null 2>&1; then
|
|
513
|
+
echo "$context_data" | jq .
|
|
514
|
+
else
|
|
515
|
+
echo "$context_data"
|
|
516
|
+
fi
|
|
517
|
+
;;
|
|
518
|
+
"yaml")
|
|
519
|
+
if command -v yq >/dev/null 2>&1; then
|
|
520
|
+
echo "$context_data" | yq .
|
|
521
|
+
else
|
|
522
|
+
log_warning "yq not available, falling back to JSON"
|
|
523
|
+
dump_context "json" "$context_data"
|
|
524
|
+
fi
|
|
525
|
+
;;
|
|
526
|
+
"text"|*)
|
|
527
|
+
echo "Context Summary:"
|
|
528
|
+
echo "==============="
|
|
529
|
+
|
|
530
|
+
if command -v jq >/dev/null 2>&1; then
|
|
531
|
+
echo "Event: $(echo "$context_data" | jq -r '.event.type // "unknown"')"
|
|
532
|
+
echo "Subagent: $(echo "$context_data" | jq -r '.event.subagent // "unknown"')"
|
|
533
|
+
echo "User: $(echo "$context_data" | jq -r '.environment.user // "unknown"')"
|
|
534
|
+
echo "Working Directory: $(echo "$context_data" | jq -r '.environment.working_directory // "unknown"')"
|
|
535
|
+
echo "Timestamp: $(echo "$context_data" | jq -r '.metadata.timestamp // "unknown"')"
|
|
536
|
+
else
|
|
537
|
+
echo "Raw context data:"
|
|
538
|
+
echo "$context_data"
|
|
539
|
+
fi
|
|
540
|
+
;;
|
|
541
|
+
esac
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
##################################
|
|
545
|
+
# Initialization
|
|
546
|
+
##################################
|
|
547
|
+
|
|
548
|
+
initialize_context_manager() {
|
|
549
|
+
log_debug "Context manager module initialized"
|
|
550
|
+
|
|
551
|
+
# CONTEXT_TIMEOUT is already set in config-constants.sh as readonly
|
|
552
|
+
|
|
553
|
+
# Ensure temp directory is available
|
|
554
|
+
if [[ ! -d "/tmp" ]]; then
|
|
555
|
+
log_error "Temporary directory not available"
|
|
556
|
+
return $EXIT_GENERAL_ERROR
|
|
557
|
+
fi
|
|
558
|
+
|
|
559
|
+
return $EXIT_SUCCESS
|
|
560
|
+
}
|