claude-flow-novice 2.14.13 → 2.14.15

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.
Files changed (74) hide show
  1. package/.claude/commands/CFN_LOOP_TASK_MODE.md +7 -51
  2. package/.claude/commands/cfn-loop-cli.md +50 -125
  3. package/.claude/skills/cfn-agent-selector/SKILL.md +2 -2
  4. package/.claude/skills/cfn-agent-selector/select-agents.sh +0 -45
  5. package/.claude/skills/cfn-loop-orchestration/helpers/context-injection.sh +6 -69
  6. package/.claude/skills/cfn-loop-orchestration/orchestrate.sh +0 -17
  7. package/README.md +2 -2
  8. package/claude-assets/agents/cfn-dev-team/CLAUDE.md +3 -3
  9. package/claude-assets/agents/cfn-dev-team/README.md +1 -1
  10. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md +2 -2
  11. package/claude-assets/agents/cfn-dev-team/developers/README.md +3 -3
  12. package/claude-assets/agents/cfn-dev-team/documentation/agent-type-guidelines.md +1 -1
  13. package/claude-assets/agents/cfn-dev-team/test-agent.md +2 -2
  14. package/claude-assets/commands/CFN_LOOP_TASK_MODE.md +7 -51
  15. package/claude-assets/commands/cfn-loop-cli.md +50 -125
  16. package/claude-assets/skills/cfn-agent-selector/SKILL.md +2 -2
  17. package/claude-assets/skills/cfn-agent-selector/select-agents.sh +0 -45
  18. package/claude-assets/skills/cfn-loop-orchestration/helpers/context-injection.sh +6 -69
  19. package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh +0 -17
  20. package/claude-assets/skills/cfn-multi-coordinator-planning/README.md +256 -0
  21. package/claude-assets/skills/cfn-multi-coordinator-planning/SKILL.md +62 -0
  22. package/claude-assets/skills/cfn-multi-coordinator-planning/map-dependencies-conflicts.sh +376 -0
  23. package/claude-assets/skills/cfn-multi-coordinator-planning/plan-coordinator-resources.sh +258 -0
  24. package/claude-assets/skills/cfn-multi-coordinator-planning/plan-multi-coordinator-work.sh +267 -0
  25. package/claude-assets/skills/cfn-multi-coordinator-planning/plan-risk-rollout.sh +350 -0
  26. package/claude-assets/skills/cfn-multi-coordinator-planning/test-multi-coordinator-planning.sh +338 -0
  27. package/claude-assets/skills/cfn-multi-coordinator-planning/validate-task-planning.sh +189 -0
  28. package/dist/agents/agent-loader.js +165 -146
  29. package/dist/agents/agent-loader.js.map +1 -1
  30. package/package.json +1 -1
  31. package/.claude/skills/cfn-agent-selector/SKILL.md.backup_before_replace +0 -91
  32. package/.claude/skills/cfn-loop-orchestration/helpers/validate-task-context.sh +0 -241
  33. package/.claude/skills/pre-edit-backup/backup.sh +0 -130
  34. package/.claude/skills/pre-edit-backup/cleanup.sh +0 -155
  35. package/.claude/skills/pre-edit-backup/restore.sh +0 -128
  36. package/.claude/skills/pre-edit-backup/revert-file.sh +0 -168
  37. package/claude-assets/agents/cfn-dev-team/CLAUDE.md.backup_before_replace +0 -1086
  38. package/claude-assets/agents/cfn-dev-team/README.md.backup_before_replace +0 -116
  39. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md.backup_before_replace +0 -451
  40. package/claude-assets/agents/cfn-dev-team/developers/README.md.backup_before_replace +0 -69
  41. package/claude-assets/agents/cfn-dev-team/documentation/agent-type-guidelines.md.backup_before_replace +0 -465
  42. package/claude-assets/agents/cfn-dev-team/test-agent.md.backup_before_replace +0 -141
  43. package/claude-assets/skills/CFN-LOOP-VALIDATION.md +0 -202
  44. package/claude-assets/skills/REDIS-COORDINATION.md +0 -187
  45. package/claude-assets/skills/SKILL.md +0 -229
  46. package/claude-assets/skills/agent-discovery/agents-registry.json +0 -484
  47. package/claude-assets/skills/agent-name-validation/README.md +0 -28
  48. package/claude-assets/skills/agent-name-validation/SKILL.md +0 -168
  49. package/claude-assets/skills/agent-name-validation/validate-agent-names.sh +0 -47
  50. package/claude-assets/skills/cfn-agent-selector/SKILL.md.backup_before_replace +0 -91
  51. package/claude-assets/skills/cfn-loop-orchestration/helpers/validate-task-context.sh +0 -241
  52. package/claude-assets/skills/consensus-calculator.js +0 -45
  53. package/claude-assets/skills/evidence-chain.sql +0 -66
  54. package/claude-assets/skills/hook-pipeline/bash-dependency-checker.sh +0 -89
  55. package/claude-assets/skills/hook-pipeline/bash-pipe-safety.sh +0 -69
  56. package/claude-assets/skills/hook-pipeline/enforce-lf.sh +0 -36
  57. package/claude-assets/skills/hook-pipeline/js-promise-safety.sh +0 -110
  58. package/claude-assets/skills/hook-pipeline/python-async-safety.py +0 -124
  59. package/claude-assets/skills/hook-pipeline/python-import-checker.py +0 -114
  60. package/claude-assets/skills/hook-pipeline/python-subprocess-safety.py +0 -77
  61. package/claude-assets/skills/hook-pipeline/rust-command-safety.sh +0 -38
  62. package/claude-assets/skills/hook-pipeline/rust-dependency-checker.sh +0 -50
  63. package/claude-assets/skills/hook-pipeline/rust-future-safety.sh +0 -50
  64. package/claude-assets/skills/pre-edit-backup/backup.sh +0 -130
  65. package/claude-assets/skills/pre-edit-backup/cleanup.sh +0 -155
  66. package/claude-assets/skills/pre-edit-backup/restore.sh +0 -128
  67. package/claude-assets/skills/pre-edit-backup/revert-file.sh +0 -168
  68. package/claude-assets/skills/run-all-skill-tests.sh +0 -124
  69. package/claude-assets/skills/seo-orchestration/SKILL.md +0 -292
  70. package/claude-assets/skills/seo-orchestration/orchestrate-seo.sh +0 -566
  71. package/claude-assets/skills/seo-orchestration/orchestrate-seo.sh.backup +0 -755
  72. package/claude-assets/skills/seo-orchestration/validate-consensus.sh +0 -270
  73. package/claude-assets/skills/team-provider-routing/execute-agent.sh +0 -76
  74. package/claude-assets/skills/test-execution-coordinator-pattern.md +0 -228
@@ -1,89 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- # Bash Dependency Checker
5
- # Validates script dependencies and checks for their existence
6
-
7
- # Check if a file path is provided
8
- if [[ $# -ne 1 ]]; then
9
- echo "Usage: $0 <file_path>" >&2
10
- exit 1
11
- fi
12
-
13
- FILE_PATH="$1"
14
-
15
- # Skip non-bash files
16
- if [[ ! "$FILE_PATH" =~ \.(sh|bash)$ ]]; then
17
- exit 0
18
- fi
19
-
20
- # Skip empty files
21
- if [[ ! -s "$FILE_PATH" ]]; then
22
- exit 0
23
- fi
24
-
25
- # Function to resolve relative paths
26
- resolve_path() {
27
- local base_dir script_path="$1"
28
-
29
- # If path is absolute, return as-is
30
- if [[ "$script_path" =~ ^/ ]]; then
31
- echo "$script_path"
32
- return 0
33
- fi
34
-
35
- # Get base directory of the current script
36
- base_dir="$(dirname "$(readlink -f "$FILE_PATH")")"
37
-
38
- # Resolve relative paths
39
- readlink -f "$base_dir/$script_path"
40
- }
41
-
42
- # Function to extract script dependencies
43
- extract_dependencies() {
44
- local missing_deps=0
45
-
46
- # Extract sourced scripts using source, ., or direct paths
47
- while IFS= read -r line; do
48
- local script_path=""
49
-
50
- # Skip comments
51
- [[ "$line" =~ ^[[:space:]]*# ]] && continue
52
-
53
- # Match source, ., or sourced script patterns
54
- if [[ "$line" =~ ^[[:space:]]*(source|\.)[[:space:]]+([^\;]+) ]]; then
55
- script_path="${BASH_REMATCH[2]}"
56
- elif [[ "$line" =~ ^[[:space:]]*bash[[:space:]]+([^\;]+) ]]; then
57
- script_path="${BASH_REMATCH[1]}"
58
- else
59
- continue
60
- fi
61
-
62
- # Remove surrounding quotes and whitespace
63
- script_path=$(echo "$script_path" | xargs)
64
-
65
- # Skip variables and arithmetic expansions (after quote removal)
66
- if [[ "$script_path" =~ ^\$ ]]; then
67
- continue
68
- fi
69
-
70
- # Resolve path
71
- local resolved_path
72
- resolved_path=$(resolve_path "$script_path")
73
-
74
- # Check if resolved script exists
75
- if [[ ! -f "$resolved_path" ]]; then
76
- echo "Missing dependency: $resolved_path" >&2
77
- missing_deps=$((missing_deps + 1))
78
- fi
79
- done < "$FILE_PATH"
80
-
81
- return $missing_deps
82
- }
83
-
84
- # Run dependency checks
85
- if ! extract_dependencies; then
86
- exit 1
87
- fi
88
-
89
- exit 0
@@ -1,69 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- # Bash Pipe Safety Validator
5
- # Checks for potential pipe safety issues in bash scripts
6
-
7
- # Risky commands list
8
- RISKY_COMMANDS=(
9
- "redis-cli"
10
- "curl"
11
- "wget"
12
- "npm"
13
- "docker"
14
- "git"
15
- "mysql"
16
- "psql"
17
- "python"
18
- "node"
19
- )
20
-
21
- # Check if a file path is provided
22
- if [[ $# -ne 1 ]]; then
23
- echo "Usage: $0 <file_path>" >&2
24
- exit 1
25
- fi
26
-
27
- FILE_PATH="$1"
28
-
29
- # Skip non-bash files
30
- if [[ ! "$FILE_PATH" =~ \.(sh|bash)$ ]]; then
31
- exit 0
32
- fi
33
-
34
- # Skip empty files
35
- if [[ ! -s "$FILE_PATH" ]]; then
36
- exit 0
37
- fi
38
-
39
- # Check for pipefail (either 'set -o pipefail' or 'set -euo pipefail' or similar)
40
- if ! grep -qE "set -(o pipefail|[a-z]*o[a-z]*)" "$FILE_PATH" || ! grep -q "pipefail" "$FILE_PATH"; then
41
- echo "Warning: Missing 'set -o pipefail' in script" >&2
42
- exit 2
43
- fi
44
-
45
- # Function to check for risky pipe usage
46
- check_pipe_safety() {
47
- local line issues=0
48
-
49
- while IFS= read -r line; do
50
- # Check for pipe usage without stderr redirection
51
- if [[ "$line" =~ \| ]]; then
52
- for cmd in "${RISKY_COMMANDS[@]}"; do
53
- if [[ "$line" =~ $cmd ]] && [[ ! "$line" =~ (2>/dev/null|2>&1) ]]; then
54
- echo "Potential pipe safety issue in line: $line" >&2
55
- ((issues++))
56
- fi
57
- done
58
- fi
59
- done < "$FILE_PATH"
60
-
61
- return $issues
62
- }
63
-
64
- # Run safety checks
65
- if ! check_pipe_safety; then
66
- exit 2
67
- fi
68
-
69
- exit 0
@@ -1,36 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- # Enforce Line Endings Validator
5
- # Converts CRLF to LF for text files
6
-
7
- # Check if a file path is provided
8
- if [[ $# -ne 1 ]]; then
9
- echo "Usage: $0 <file_path>" >&2
10
- exit 1
11
- fi
12
-
13
- FILE_PATH="$1"
14
-
15
- # Skip empty files
16
- if [[ ! -s "$FILE_PATH" ]]; then
17
- exit 0
18
- fi
19
-
20
- # Check if file is binary
21
- if file --mime-type "$FILE_PATH" | grep -qE '(binary|application/)'; then
22
- exit 0
23
- fi
24
-
25
- # Skip files that are already LF (check for carriage return)
26
- if ! grep -q $'\r' "$FILE_PATH"; then
27
- exit 0
28
- fi
29
-
30
- # Convert CRLF to LF
31
- sed -i 's/\r$//' "$FILE_PATH"
32
-
33
- # Optional: Log the conversion
34
- echo "Converted $FILE_PATH to LF line endings" >&2
35
-
36
- exit 0
@@ -1,110 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Manual check for unhandled promises (fallback if ESLint not available)
3
-
4
- set -euo pipefail
5
-
6
- FILE="${1:-}"
7
- if [[ ! "$FILE" =~ \.(js|ts|jsx|tsx|mjs|cjs)$ ]]; then
8
- exit 0
9
- fi
10
-
11
- # Read file into array for context-aware checking
12
- mapfile -t FILE_LINES < "$FILE"
13
-
14
- # Check for async function calls without await/catch/then/return
15
- UNHANDLED=""
16
-
17
- for ((i=0; i<${#FILE_LINES[@]}; i++)); do
18
- line_num=$((i + 1))
19
- content="${FILE_LINES[$i]}"
20
-
21
- # Skip empty lines and comments
22
- if [[ -z "$content" ]] || [[ "$content" =~ ^[[:space:]]*// ]] || [[ "$content" =~ ^[[:space:]]*\* ]]; then
23
- continue
24
- fi
25
-
26
- # Skip if line doesn't contain function calls
27
- if ! echo "$content" | grep -qE '\w+\(\)'; then
28
- continue
29
- fi
30
-
31
- # Skip function definitions (async function foo(), function foo(), const foo = async)
32
- if echo "$content" | grep -qE '(async[[:space:]]+function|function[[:space:]]+|const[[:space:]]+\w+[[:space:]]*=[[:space:]]*async|let[[:space:]]+\w+[[:space:]]*=[[:space:]]*async|var[[:space:]]+\w+[[:space:]]*=[[:space:]]*async)'; then
33
- continue
34
- fi
35
-
36
- # Skip if line contains await, catch, then, or return
37
- if echo "$content" | grep -qE '(await|\.catch|\.then|return)'; then
38
- continue
39
- fi
40
-
41
- # Check next line for .catch() or .then() chaining (within 2 lines)
42
- has_chaining=false
43
- for ((j=1; j<=2 && (i+j)<${#FILE_LINES[@]}; j++)); do
44
- next_line="${FILE_LINES[$((i+j))]}"
45
- if echo "$next_line" | grep -qE '^[[:space:]]*\.(catch|then)'; then
46
- has_chaining=true
47
- break
48
- fi
49
- done
50
-
51
- if [[ "$has_chaining" == "true" ]]; then
52
- continue
53
- fi
54
-
55
- # Check if inside try-catch block (look back up to 10 lines)
56
- in_try_catch=false
57
- try_depth=0
58
- for ((j=1; j<=10 && (i-j)>=0; j++)); do
59
- prev_line="${FILE_LINES[$((i-j))]}"
60
-
61
- # Count braces to track depth
62
- if echo "$prev_line" | grep -qE '\{'; then
63
- ((try_depth++)) || true
64
- fi
65
- if echo "$prev_line" | grep -qE '\}'; then
66
- ((try_depth--)) || true
67
- fi
68
-
69
- # Found a try block at same depth
70
- if [[ $try_depth -gt 0 ]] && echo "$prev_line" | grep -qE '^[[:space:]]*try[[:space:]]*\{'; then
71
- in_try_catch=true
72
- break
73
- fi
74
- done
75
-
76
- if [[ "$in_try_catch" == "true" ]]; then
77
- continue
78
- fi
79
-
80
- # Extract function name and check if it's async
81
- FUNC_NAME=$(echo "$content" | grep -oE '\w+\(\)' | head -1 | sed 's/()//')
82
-
83
- if [[ -z "$FUNC_NAME" ]]; then
84
- continue
85
- fi
86
-
87
- # Check if function is async (look for async function definition)
88
- if grep -qE "async[[:space:]]+(function[[:space:]]+${FUNC_NAME}|const[[:space:]]+${FUNC_NAME}|let[[:space:]]+${FUNC_NAME}|var[[:space:]]+${FUNC_NAME})" "$FILE"; then
89
- if [[ -n "$UNHANDLED" ]]; then
90
- UNHANDLED="${UNHANDLED}"$'\n'"$line_num:$content"
91
- else
92
- UNHANDLED="$line_num:$content"
93
- fi
94
- fi
95
- done
96
-
97
- if [ -n "$UNHANDLED" ]; then
98
- echo "⚠️ Promise Safety Warning: Potential unhandled async calls" >&2
99
- echo "" >&2
100
- echo "$UNHANDLED" | while IFS=: read -r line_num content; do
101
- echo " Line $line_num: ${content}" >&2
102
- done
103
- echo "" >&2
104
- echo " Recommendation: Add 'await' or '.catch()' to handle promise" >&2
105
- echo " Better: Run ESLint with @typescript-eslint/no-floating-promises" >&2
106
- echo "" >&2
107
- exit 2
108
- fi
109
-
110
- exit 0
@@ -1,124 +0,0 @@
1
- #!/usr/bin/env python3
2
- import ast
3
- import sys
4
-
5
- class AsyncSafetyVisitor(ast.NodeVisitor):
6
- def __init__(self, debug=False):
7
- self.async_functions = {}
8
- self.unsafe_calls = []
9
- self.node_parents = {}
10
- self.debug = debug
11
-
12
- def visit(self, node):
13
- # Recursive parent tracking
14
- for child in ast.iter_child_nodes(node):
15
- self.node_parents[child] = node
16
- super().visit(node)
17
-
18
- def get_parent(self, node, node_type=None):
19
- """Recursively find parent of specified type"""
20
- current = self.node_parents.get(node)
21
- while current:
22
- if node_type is None or isinstance(current, node_type):
23
- return current
24
- current = self.node_parents.get(current)
25
- return None
26
-
27
- def is_awaited(self, node):
28
- """Check if node is directly inside an Await context"""
29
- # Parent chain traversal to find await
30
- parent = self.get_parent(node)
31
- while parent:
32
- if isinstance(parent, ast.Await):
33
- return True
34
- parent = self.get_parent(parent)
35
- return False
36
-
37
- def is_safe_call(self, node):
38
- """Detect safe async calls"""
39
- safe_async_funcs = {'create_task', 'gather'}
40
- safe_modules = {'asyncio'}
41
-
42
- return (
43
- isinstance(node.func, ast.Attribute) and
44
- node.func.attr in safe_async_funcs and
45
- (node.func.value.id if isinstance(node.func.value, ast.Name) else None) in safe_modules
46
- )
47
-
48
- def visit_AsyncFunctionDef(self, node):
49
- """Track async function contexts"""
50
- self.async_functions[node] = {
51
- 'name': node.name,
52
- 'context': node
53
- }
54
- self.generic_visit(node)
55
-
56
- def visit_Call(self, node):
57
- """Detect unsafe async calls"""
58
- # Skip if not in async function
59
- async_context = next(
60
- (func for func, details in self.async_functions.items()
61
- if node in ast.walk(details['context'])),
62
- None
63
- )
64
- if not async_context:
65
- return
66
-
67
- # Skip if it's a known safe call
68
- if self.is_safe_call(node):
69
- return
70
-
71
- # Detect function name
72
- func_name = (
73
- node.func.attr if isinstance(node.func, ast.Attribute)
74
- else node.func.id if isinstance(node.func, ast.Name)
75
- else 'Unknown'
76
- )
77
-
78
- # Detect if call is awaited
79
- if not self.is_awaited(node):
80
- if self.debug:
81
- print(f"Debugging - Unsafe Call: {ast.dump(node)}")
82
- print(f"Function: {func_name}, Awaited: False")
83
-
84
- self.unsafe_calls.append(
85
- f"Line {node.lineno}: Async function '{async_context.name}' calls '{func_name}' without await"
86
- )
87
-
88
- self.generic_visit(node)
89
-
90
- def validate_async_safety(file_path, debug=False):
91
- try:
92
- with open(file_path, 'r') as f:
93
- content = f.read()
94
- tree = ast.parse(content, filename=file_path)
95
- except SyntaxError as e:
96
- print(f"Syntax error in {file_path}: {e}")
97
- return 1
98
- except FileNotFoundError:
99
- print(f"File not found: {file_path}")
100
- return 1
101
-
102
- visitor = AsyncSafetyVisitor(debug=debug)
103
- visitor.visit(tree)
104
-
105
- if visitor.unsafe_calls:
106
- print("Async safety warnings:")
107
- for call in visitor.unsafe_calls:
108
- print(call)
109
- return 2
110
-
111
- return 0
112
-
113
- def main():
114
- if len(sys.argv) < 2:
115
- print("Usage: python3 python-async-safety.py <python_file>")
116
- return 1
117
-
118
- file_path = sys.argv[1]
119
- debug = "--debug" in sys.argv
120
- result = validate_async_safety(file_path, debug=debug)
121
- sys.exit(result)
122
-
123
- if __name__ == '__main__':
124
- main()
@@ -1,114 +0,0 @@
1
- #!/usr/bin/env python3
2
- import ast
3
- import sys
4
- import importlib.util
5
- import importlib.machinery
6
-
7
- class ImportChecker(ast.NodeVisitor):
8
- def __init__(self, debug=False):
9
- self.imported_modules = set()
10
- self.used_modules = {}
11
- self.debug = debug
12
-
13
- def visit_Name(self, node):
14
- if isinstance(node.ctx, ast.Load):
15
- # Specific modules to check
16
- specific_modules = {'json', 'requests', 'numpy', 'np'}
17
-
18
- if node.id in specific_modules and node.id not in self.imported_modules:
19
- self.used_modules[node.id] = node.lineno
20
- self.generic_visit(node)
21
-
22
- def visit_Import(self, node):
23
- for alias in node.names:
24
- module_name = alias.name.split('.')[0]
25
- self.imported_modules.add(module_name)
26
- if alias.asname:
27
- self.imported_modules.add(alias.asname)
28
- if self.debug:
29
- print(f"Imported module: {module_name}")
30
- self.generic_visit(node)
31
-
32
- def visit_ImportFrom(self, node):
33
- if node.module:
34
- base_module = node.module.split('.')[0]
35
- self.imported_modules.add(base_module)
36
-
37
- # Capture aliases for modules like 'numpy as np'
38
- for alias in node.names:
39
- if alias.asname:
40
- self.imported_modules.add(alias.asname)
41
-
42
- if self.debug:
43
- print(f"Imported from module: {base_module}")
44
- self.generic_visit(node)
45
-
46
- def is_module_resolvable(module_name, debug=False):
47
- """Specific import detection for known modules"""
48
-
49
- # Always check specific known modules
50
- specific_modules = {
51
- 'json', 'requests', 'numpy', 'np',
52
- 'pandas', 'scipy', 'sklearn', 'matplotlib'
53
- }
54
-
55
- if module_name in specific_modules:
56
- return False
57
-
58
- # Standard library
59
- standard_modules = {
60
- 'sys', 'os', 're', 'typing', 'collections', 'dataclasses',
61
- 'datetime', 'math', 'asyncio', 'argparse', 'random',
62
- 'functools', 'itertools', 'enum', 'pathlib', 'subprocess'
63
- }
64
-
65
- if module_name in standard_modules:
66
- return True
67
-
68
- # Fallback resolution strategies
69
- try:
70
- return importlib.util.find_spec(module_name) is not None
71
- except (ImportError, AttributeError):
72
- return False
73
-
74
- def validate_imports(file_path, debug=False):
75
- try:
76
- with open(file_path, 'r') as f:
77
- tree = ast.parse(f.read(), filename=file_path)
78
- except SyntaxError as e:
79
- print(f"Syntax error in {file_path}: {e}")
80
- return 1
81
- except FileNotFoundError:
82
- print(f"File not found: {file_path}")
83
- return 1
84
-
85
- visitor = ImportChecker(debug=debug)
86
- visitor.visit(tree)
87
-
88
- # Check for unresolved modules
89
- unresolved_modules = [
90
- (module, lineno) for module, lineno in visitor.used_modules.items()
91
- if not is_module_resolvable(module, debug=debug)
92
- ]
93
-
94
- # Validation
95
- if unresolved_modules:
96
- print("Import resolution warnings:")
97
- for module, lineno in unresolved_modules:
98
- print(f"Line {lineno}: Unable to resolve import: {module}")
99
- return 2
100
-
101
- return 0
102
-
103
- def main():
104
- if len(sys.argv) < 2:
105
- print("Usage: python3 python-import-checker.py <python_file>")
106
- return 1
107
-
108
- file_path = sys.argv[1]
109
- debug = "--debug" in sys.argv
110
- result = validate_imports(file_path, debug=debug)
111
- sys.exit(result)
112
-
113
- if __name__ == '__main__':
114
- main()
@@ -1,77 +0,0 @@
1
- #!/usr/bin/env python3
2
- import ast
3
- import sys
4
-
5
- class SubprocessSafetyVisitor(ast.NodeVisitor):
6
- def __init__(self):
7
- self.unsafe_calls = []
8
- self.allowed_stderr_values = {'Attribute': ['PIPE', 'DEVNULL', 'STDOUT'],
9
- 'Name': ['subprocess.PIPE', 'subprocess.DEVNULL', 'subprocess.STDOUT']}
10
-
11
- def is_safe_stderr(self, node):
12
- if isinstance(node, ast.Attribute):
13
- return node.attr in self.allowed_stderr_values['Attribute']
14
- if isinstance(node, ast.Name):
15
- return node.id in self.allowed_stderr_values['Name']
16
- return False
17
-
18
- def visit_Call(self, node):
19
- if isinstance(node.func, ast.Attribute):
20
- func_name = node.func.attr
21
- if func_name in ['run', 'Popen', 'check_output']:
22
- # Check if from subprocess module
23
- module_name = None
24
- if isinstance(node.func.value, ast.Name):
25
- module_name = node.func.value.id
26
-
27
- if module_name == 'subprocess':
28
- # Strategies for safe subprocess calls
29
- stderr_found = False
30
- capture_output_found = False
31
-
32
- for kw in node.keywords:
33
- if kw.arg == 'stderr' and self.is_safe_stderr(kw.value):
34
- stderr_found = True
35
- if kw.arg == 'capture_output' and isinstance(kw.value, ast.NameConstant) and kw.value.value is True:
36
- capture_output_found = True
37
-
38
- if not (stderr_found or capture_output_found):
39
- self.unsafe_calls.append(
40
- f"Line {node.lineno}: Subprocess call '{func_name}' without stderr parameter or capture_output"
41
- )
42
-
43
- self.generic_visit(node)
44
-
45
- def validate_subprocess_safety(file_path):
46
- try:
47
- with open(file_path, 'r') as f:
48
- tree = ast.parse(f.read(), filename=file_path)
49
- except SyntaxError as e:
50
- print(f"Syntax error in {file_path}: {e}")
51
- return 1
52
- except FileNotFoundError:
53
- print(f"File not found: {file_path}")
54
- return 1
55
-
56
- visitor = SubprocessSafetyVisitor()
57
- visitor.visit(tree)
58
-
59
- if visitor.unsafe_calls:
60
- print("Subprocess safety warnings:")
61
- for call in visitor.unsafe_calls:
62
- print(call)
63
- return 2
64
-
65
- return 0
66
-
67
- def main():
68
- if len(sys.argv) < 2:
69
- print("Usage: python3 python-subprocess-safety.py <python_file>")
70
- return 1
71
-
72
- file_path = sys.argv[1]
73
- result = validate_subprocess_safety(file_path)
74
- sys.exit(result)
75
-
76
- if __name__ == '__main__':
77
- main()
@@ -1,38 +0,0 @@
1
- #!/bin/bash
2
- # Rust Command Safety Validator
3
- set -o pipefail
4
-
5
- # Exit codes:
6
- # 0 - No issues found
7
- # 1 - File not found or cannot be read
8
- # 2 - Command safety warnings found
9
-
10
- if [ $# -eq 0 ]; then
11
- echo "Usage: $0 <rust_file>"
12
- exit 1
13
- fi
14
-
15
- file_path="$1"
16
-
17
- if [ ! -f "$file_path" ]; then
18
- echo "File not found: $file_path"
19
- exit 1
20
- fi
21
-
22
- # Use grep to find Command::new() calls and check for stderr in next 5 lines
23
- unsafe_commands=$(grep -n "Command::new(" "$file_path" | while read -r line; do
24
- line_num=$(echo "$line" | cut -d':' -f1)
25
- next_lines=$(tail -n +"$line_num" "$file_path" | head -n 5)
26
-
27
- if ! echo "$next_lines" | grep -q "\.stderr("; then
28
- echo "Line $line_num: Command::new() without stderr() configuration in next 5 lines"
29
- fi
30
- done)
31
-
32
- if [ -n "$unsafe_commands" ]; then
33
- echo "Command safety warnings:"
34
- echo "$unsafe_commands"
35
- exit 2
36
- fi
37
-
38
- exit 0