diff --git a/.agents/plugins/opencode-aidevops/tools.mjs b/.agents/plugins/opencode-aidevops/tools.mjs index a12422684..187aaf6ab 100644 --- a/.agents/plugins/opencode-aidevops/tools.mjs +++ b/.agents/plugins/opencode-aidevops/tools.mjs @@ -2,6 +2,16 @@ import { execSync } from "child_process"; import { existsSync } from "fs"; import { join } from "path"; +/** + * Escape a string for safe interpolation into a shell command. + * Wraps in single quotes and escapes any internal single quotes. + * @param {string} str + * @returns {string} + */ +function shellEscape(str) { + return "'" + String(str).replace(/'/g, "'\\''") + "'"; +} + /** * Create a memory tool (recall or store) using a shared factory pattern. * Deduplicates the near-identical memory_recall and memory_store definitions. @@ -266,7 +276,7 @@ export function createTools(scriptsDir, run, pipelines) { description: 'Recall memories from the aidevops cross-session memory system. Args: query (string), limit (string, default "5")', buildArgs: (args, helper) => ({ - cmd: `bash "${helper}" recall "${args.query}" --limit ${args.limit || "5"} 2>/dev/null`, + cmd: `bash "${helper}" recall ${shellEscape(args.query)} --limit ${shellEscape(args.limit || "5")}`, timeout: 10000, }), }), @@ -282,8 +292,9 @@ export function createTools(scriptsDir, run, pipelines) { if (!content) { return { cmd: `echo "Error: content is required to store a memory" >&2; exit 1`, timeout: 1000 }; } + const confidence = args.confidence || "medium"; return { - cmd: `bash "${helper}" store "${content}" --confidence ${args.confidence || "medium"} 2>/dev/null`, + cmd: `bash "${helper}" store ${shellEscape(content)} --confidence ${shellEscape(confidence)}`, timeout: 10000, }; }, diff --git a/.agents/scripts/commands/patterns.md b/.agents/scripts/commands/patterns.md index 8a6164ac9..23727add2 100644 --- a/.agents/scripts/commands/patterns.md +++ b/.agents/scripts/commands/patterns.md @@ -15,16 +15,16 @@ Arguments: $ARGUMENTS ```bash # Get success patterns -~/.aidevops/agents/scripts/memory-helper.sh recall --type SUCCESS_PATTERN --limit 20 +~/.aidevops/agents/scripts/memory-helper.sh recall "success pattern" --type SUCCESS_PATTERN --limit 20 # Get failure patterns -~/.aidevops/agents/scripts/memory-helper.sh recall --type FAILURE_PATTERN --limit 20 +~/.aidevops/agents/scripts/memory-helper.sh recall "failure pattern" --type FAILURE_PATTERN --limit 20 # Get working solutions -~/.aidevops/agents/scripts/memory-helper.sh recall --type WORKING_SOLUTION --limit 10 +~/.aidevops/agents/scripts/memory-helper.sh recall "working solution" --type WORKING_SOLUTION --limit 10 # Get failed approaches -~/.aidevops/agents/scripts/memory-helper.sh recall --type FAILED_APPROACH --limit 10 +~/.aidevops/agents/scripts/memory-helper.sh recall "failed approach" --type FAILED_APPROACH --limit 10 ``` 2. If arguments are provided, filter results relevant to the task description. diff --git a/.agents/scripts/pre-commit-hook.sh b/.agents/scripts/pre-commit-hook.sh index f12e15419..ac88e1284 100755 --- a/.agents/scripts/pre-commit-hook.sh +++ b/.agents/scripts/pre-commit-hook.sh @@ -79,10 +79,14 @@ validate_positional_parameters() { # Exclude currency/pricing patterns: $[1-9] followed by digit, decimal, comma, # slash (e.g. $28/mo, $1.99, $1,000), pipe (markdown table cell), or common # currency/pricing unit words (per, mo, month, flat, etc.). - if [[ -f "$file" ]] && grep -n '\$[1-9]' "$file" | grep -v 'local.*=.*\$[1-9]' | grep -vE '\$[1-9][0-9.,/]' | grep -vE '\$[1-9]\s*\|' | grep -vE '\$[1-9]\s+(per|mo(nth)?|year|yr|day|week|hr|hour|flat|each|off|fee|plan|tier|user|seat|unit|addon|setup|trial|credit|annual|quarterly|monthly)\b' >/dev/null; then - print_error "Direct positional parameter usage in $file" - grep -n '\$[1-9]' "$file" | grep -v 'local.*=.*\$[1-9]' | grep -vE '\$[1-9][0-9.,/]' | grep -vE '\$[1-9]\s*\|' | grep -vE '\$[1-9]\s+(per|mo(nth)?|year|yr|day|week|hr|hour|flat|each|off|fee|plan|tier|user|seat|unit|addon|setup|trial|credit|annual|quarterly|monthly)\b' | head -3 - ((violations++)) + if [[ -f "$file" ]]; then + local violations_output + violations_output=$(grep -n '\$[1-9]' "$file" | grep -v 'local.*=.*\$[1-9]' | grep -vE '\$[1-9][0-9.,/]' | grep -vE '\$[1-9]\s*\|' | grep -vE '\$[1-9]\s+(per|mo(nth)?|year|yr|day|week|hr|hour|flat|each|off|fee|plan|tier|user|seat|unit|addon|setup|trial|credit|annual|quarterly|monthly)\b') || true + if [[ -n "$violations_output" ]]; then + print_error "Direct positional parameter usage in $file" + echo "$violations_output" | head -3 + ((++violations)) + fi fi done diff --git a/.agents/scripts/settings-helper.sh b/.agents/scripts/settings-helper.sh index b32d7705d..030c3fe1a 100755 --- a/.agents/scripts/settings-helper.sh +++ b/.agents/scripts/settings-helper.sh @@ -310,11 +310,11 @@ cmd_list() { for section in $sections; do echo -e "${BLUE}[$section]${NC}" local keys - keys=$(jq -r ".$section | keys[]" "$SETTINGS_FILE" 2>/dev/null) + keys=$(jq -r --arg s "$section" '.[$s] | keys[]' "$SETTINGS_FILE" 2>/dev/null) for key in $keys; do local full_key="${section}.${key}" local value - value=$(jq -r ".$section.$key" "$SETTINGS_FILE" 2>/dev/null) + value=$(jq -r --arg s "$section" --arg k "$key" '.[$s][$k]' "$SETTINGS_FILE" 2>/dev/null) local env_var env_var=$(_env_var_for_key "$full_key") local env_override="" diff --git a/tests/test-smoke-help.sh b/tests/test-smoke-help.sh index 2d1331068..4cfe10610 100644 --- a/tests/test-smoke-help.sh +++ b/tests/test-smoke-help.sh @@ -180,7 +180,7 @@ while IFS= read -r script; do fi # Run help command with timeout (5s max) and capture output - help_output=$(timeout 5 bash "$abs_path" help 2>&1) || true + help_output=$(timeout 5 bash "$abs_path" help 2>&1) help_exit=$? # Some scripts exit 0 on help, some exit 1 (usage error) - both are acceptable