@pipemd-core/pipemd 1.0.0
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/AI_SETUP_PIPEMD.md +184 -0
- package/CHANGELOG.md +47 -0
- package/LICENSE +15 -0
- package/README.md +535 -0
- package/dist/index.js +6647 -0
- package/dist/plugins/opencode-server.js +235 -0
- package/dist/plugins/opencode-tui.js +914 -0
- package/dist/templates/agent-decision-tree.md +113 -0
- package/dist/templates/static-rules.md +7 -0
- package/package.json +68 -0
- package/scripts/C-CPP/architecture/arch.sh +229 -0
- package/scripts/C-CPP/lib/limit.sh +146 -0
- package/scripts/C-CPP/project/class-diagram.sh +96 -0
- package/scripts/C-CPP/project/cmake-targets.sh +68 -0
- package/scripts/C-CPP/project/deps.sh +44 -0
- package/scripts/C-CPP/project/find-todos.sh +6 -0
- package/scripts/C-CPP/project/include-graph.sh +110 -0
- package/scripts/C-CPP/project/interfaces.sh +108 -0
- package/scripts/C-CPP/project/tree.sh +5 -0
- package/scripts/C-CPP/quality/lint.sh +14 -0
- package/scripts/C-CPP/quality/test-summary.sh +22 -0
- package/scripts/C-CPP/quality/type-check.sh +26 -0
- package/scripts/DevOps/architecture/arch.sh +186 -0
- package/scripts/DevOps/devops/aws-context.sh +34 -0
- package/scripts/DevOps/devops/docker-stats.sh +42 -0
- package/scripts/DevOps/devops/k8s-unhealthy.sh +41 -0
- package/scripts/DevOps/devops/tf-state.sh +65 -0
- package/scripts/DevOps/lib/limit.sh +143 -0
- package/scripts/Generic/architecture/arch.sh +570 -0
- package/scripts/Generic/lib/limit.sh +140 -0
- package/scripts/Go/architecture/arch.sh +79 -0
- package/scripts/Go/lib/limit.sh +142 -0
- package/scripts/Go/project/deps.sh +35 -0
- package/scripts/Go/project/find-todos.sh +6 -0
- package/scripts/Go/project/go-interfaces.sh +18 -0
- package/scripts/Go/project/go-packages.sh +28 -0
- package/scripts/Go/project/tree.sh +5 -0
- package/scripts/Go/quality/lint.sh +16 -0
- package/scripts/Go/quality/test-summary.sh +16 -0
- package/scripts/Go/quality/type-check.sh +16 -0
- package/scripts/Node-TypeScript/api/express-routes.sh +14 -0
- package/scripts/Node-TypeScript/api/nest-controllers.sh +18 -0
- package/scripts/Node-TypeScript/architecture/arch.sh +174 -0
- package/scripts/Node-TypeScript/frontend/angular-routes.sh +15 -0
- package/scripts/Node-TypeScript/frontend/nextjs-app-router.sh +13 -0
- package/scripts/Node-TypeScript/frontend/react-components.sh +20 -0
- package/scripts/Node-TypeScript/lib/limit.sh +146 -0
- package/scripts/Node-TypeScript/project/deps.sh +15 -0
- package/scripts/Node-TypeScript/project/find-todos.sh +6 -0
- package/scripts/Node-TypeScript/quality/lint.sh +10 -0
- package/scripts/Node-TypeScript/quality/test-summary.sh +39 -0
- package/scripts/Node-TypeScript/quality/type-check.sh +10 -0
- package/scripts/Python/api/fastapi-routes.sh +12 -0
- package/scripts/Python/architecture/arch.sh +220 -0
- package/scripts/Python/db/django-models.sh +12 -0
- package/scripts/Python/db/sqlalchemy.sh +17 -0
- package/scripts/Python/lib/limit.sh +144 -0
- package/scripts/Python/project/deps.sh +28 -0
- package/scripts/Python/project/find-todos.sh +6 -0
- package/scripts/Python/quality/lint.sh +13 -0
- package/scripts/Python/quality/test-summary.sh +11 -0
- package/scripts/Python/quality/type-check.sh +10 -0
- package/scripts/Rust/architecture/arch.sh +176 -0
- package/scripts/Rust/lib/limit.sh +142 -0
- package/scripts/Rust/project/cargo-deps.sh +42 -0
- package/scripts/Rust/project/cargo-features.sh +26 -0
- package/scripts/Rust/project/find-todos.sh +6 -0
- package/scripts/Rust/project/tree.sh +5 -0
- package/scripts/Rust/quality/lint.sh +16 -0
- package/scripts/Rust/quality/test-summary.sh +16 -0
- package/scripts/Rust/quality/type-check.sh +16 -0
- package/scripts/Shared/api/express-routes.sh +11 -0
- package/scripts/Shared/api/fastapi-routes.sh +10 -0
- package/scripts/Shared/api/nest-controllers.sh +22 -0
- package/scripts/Shared/architecture/normalize.sh +178 -0
- package/scripts/Shared/crew/crew.sh +15 -0
- package/scripts/Shared/db/django-models.sh +11 -0
- package/scripts/Shared/db/prisma.sh +33 -0
- package/scripts/Shared/db/sqlalchemy.sh +12 -0
- package/scripts/Shared/frontend/angular-routes.sh +11 -0
- package/scripts/Shared/frontend/nextjs-app-router.sh +13 -0
- package/scripts/Shared/frontend/react-components.sh +11 -0
- package/scripts/Shared/git/diff-stat.sh +6 -0
- package/scripts/Shared/git/git-branch.sh +16 -0
- package/scripts/Shared/git/git-log.sh +6 -0
- package/scripts/Shared/git/git-status.sh +6 -0
- package/scripts/Shared/lib/limit.sh +144 -0
- package/scripts/Shared/project/compose-md.sh +182 -0
- package/scripts/Shared/project/deps.sh +69 -0
- package/scripts/Shared/project/find-todos.sh +6 -0
- package/scripts/Shared/project/tree.sh +5 -0
- package/scripts/Shared/quality/lint.sh +81 -0
- package/scripts/Shared/quality/test-summary.sh +103 -0
- package/scripts/Shared/quality/type-check.sh +114 -0
- package/scripts/copy-plugins.mjs +4 -0
- package/scripts/copy-templates.mjs +5 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# CMake target metadata — executables, libraries, and link dependencies
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
|
|
6
|
+
if ! command -v python3 &>/dev/null; then
|
|
7
|
+
echo "python3 is required for CMake parsing"
|
|
8
|
+
exit 0
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
out=""
|
|
12
|
+
tmpfile=$(mktemp)
|
|
13
|
+
|
|
14
|
+
find . -name "CMakeLists.txt" \
|
|
15
|
+
-not -path "*/build/*" -not -path "*/.git/*" \
|
|
16
|
+
-not -path "*/cmake-build-*/*" -not -path "*/_deps/*" \
|
|
17
|
+
2>/dev/null | head -20 | while IFS= read -r cmake_file; do
|
|
18
|
+
rel="${cmake_file#./}"
|
|
19
|
+
dir="$(dirname "$rel")"
|
|
20
|
+
[ "$dir" = "." ] && dir="(root)"
|
|
21
|
+
|
|
22
|
+
PMDFILE="$cmake_file" PMDDIR="$dir" python3 -c '
|
|
23
|
+
import sys, re, os
|
|
24
|
+
|
|
25
|
+
cmake_file = os.environ.get("PMDFILE", "")
|
|
26
|
+
dir_label = os.environ.get("PMDDIR", "")
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
with open(cmake_file, "r", errors="replace") as f:
|
|
30
|
+
content = f.read()
|
|
31
|
+
except Exception:
|
|
32
|
+
sys.exit(0)
|
|
33
|
+
|
|
34
|
+
content = re.sub(r"#.*", "", content)
|
|
35
|
+
content = content.replace("\\\n", " ")
|
|
36
|
+
content = re.sub(r"\s+", " ", content)
|
|
37
|
+
|
|
38
|
+
targets = []
|
|
39
|
+
links = []
|
|
40
|
+
|
|
41
|
+
for m in re.finditer(r"add_executable\s*\(\s*([A-Za-z_]\w*)", content):
|
|
42
|
+
targets.append(f"exe:{m.group(1)}")
|
|
43
|
+
|
|
44
|
+
for m in re.finditer(r"add_library\s*\(\s*([A-Za-z_]\w*)\s+(STATIC|SHARED|MODULE|OBJECT|INTERFACE)", content):
|
|
45
|
+
targets.append(f"lib:{m.group(1)}({m.group(2)})")
|
|
46
|
+
|
|
47
|
+
for m in re.finditer(r"target_link_libraries\s*\(\s*([A-Za-z_]\w*)\s+(PUBLIC|PRIVATE|INTERFACE)\s+(.*?)\)", content):
|
|
48
|
+
links.append(f"{m.group(1)} <- {m.group(2)}: {m.group(3).strip()}")
|
|
49
|
+
|
|
50
|
+
if not targets and not links:
|
|
51
|
+
sys.exit(0)
|
|
52
|
+
|
|
53
|
+
print(f"[dir] {dir_label}")
|
|
54
|
+
for t in targets:
|
|
55
|
+
print(f" + {t}")
|
|
56
|
+
for l in links:
|
|
57
|
+
print(f" - {l}")
|
|
58
|
+
' >> "$tmpfile" 2>/dev/null
|
|
59
|
+
done
|
|
60
|
+
|
|
61
|
+
out=$(cat "$tmpfile")
|
|
62
|
+
rm -f "$tmpfile"
|
|
63
|
+
|
|
64
|
+
if [ -z "$out" ]; then
|
|
65
|
+
echo "No CMake targets found"
|
|
66
|
+
exit 0
|
|
67
|
+
fi
|
|
68
|
+
limit_output "$out" "$MAX_CMAKE" "$(echo "$out" | head -10 && echo "... and more CMake targets")"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# C/C++ dependency detection — Makefile, CMake, Conan, vcpkg
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
|
|
6
|
+
if [ -f CMakeLists.txt ]; then
|
|
7
|
+
out=$(grep -E '^\s*find_package|^\s*FetchContent_Declare|^\s*target_link_libraries' CMakeLists.txt 2>/dev/null | head -"$MAX_DEPS")
|
|
8
|
+
if [ -n "$out" ]; then
|
|
9
|
+
echo "CMake dependencies:"
|
|
10
|
+
echo "$out"
|
|
11
|
+
exit 0
|
|
12
|
+
fi
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
if [ -f Makefile ] || [ -f makefile ]; then
|
|
16
|
+
makefile="${makefile:-Makefile}"
|
|
17
|
+
[ -f makefile ] && makefile="makefile"
|
|
18
|
+
out=$(grep -E '^\s*(include|require|load|use)' "$makefile" 2>/dev/null | head -"$MAX_DEPS")
|
|
19
|
+
if [ -n "$out" ]; then
|
|
20
|
+
echo "Makefile dependencies:"
|
|
21
|
+
echo "$out"
|
|
22
|
+
exit 0
|
|
23
|
+
fi
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
if [ -f conanfile.txt ]; then
|
|
27
|
+
out=$(grep -E '^\s*[a-zA-Z]' conanfile.txt 2>/dev/null | head -"$MAX_DEPS")
|
|
28
|
+
if [ -n "$out" ]; then
|
|
29
|
+
echo "Conan dependencies:"
|
|
30
|
+
echo "$out"
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
if [ -f vcpkg.json ]; then
|
|
36
|
+
out=$(node -e "try{const p=require('./vcpkg.json');console.log((p.dependencies||[]).join('\n'))}catch{}" 2>/dev/null)
|
|
37
|
+
if [ -n "$out" ]; then
|
|
38
|
+
echo "vcpkg dependencies:"
|
|
39
|
+
echo "$out"
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
echo "No recognized C/C++ dependency file found"
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# Find TODO, FIXME, HACK in C/C++ source files
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
out=$(grep -rn --include="*.c" --include="*.cpp" --include="*.cc" --include="*.cxx" --include="*.h" --include="*.hpp" --include="*.hxx" 'TODO\|FIXME\|HACK' . 2>/dev/null | grep -v '/.git/' | grep -v '/.pipemd/' | grep -v '/build/' | grep -v '/cmake-build-' | grep -v '/_deps/')
|
|
6
|
+
limit_output "$out" "$MAX_TODOS" "$(echo "$out" | head -3 && echo "... and $(($(echo "$out" | wc -l) - 3)) more items")"
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# Include graph — external and standard library header dependencies
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
|
|
6
|
+
if ! command -v python3 &>/dev/null; then
|
|
7
|
+
echo "python3 is required for C++ include graph extraction"
|
|
8
|
+
exit 0
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
SOURCES=$(find . -type f \( -name "*.cpp" -o -name "*.cc" -o -name "*.cxx" -o -name "*.h" -o -name "*.hpp" -o -name "*.hxx" \) \
|
|
12
|
+
-not -path "*/build/*" -not -path "*/.git/*" -not -path "*/cmake-build-*/*" \
|
|
13
|
+
-not -path "*/_deps/*" -not -path "*/third_party/*" -not -path "*/external/*" \
|
|
14
|
+
2>/dev/null | head -50)
|
|
15
|
+
|
|
16
|
+
if [ -z "$SOURCES" ]; then
|
|
17
|
+
echo "No C/C++ source files found"
|
|
18
|
+
exit 0
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
echo "$SOURCES" | PMDMAX="${MAX_INCLUDE:-20}" python3 -c "
|
|
22
|
+
import sys, os, re
|
|
23
|
+
from collections import defaultdict
|
|
24
|
+
|
|
25
|
+
MAX = int(os.environ.get('PMDMAX', '20'))
|
|
26
|
+
|
|
27
|
+
STANDARD_HEADERS = {
|
|
28
|
+
'algorithm', 'array', 'atomic', 'bitset', 'cassert', 'ccomplex',
|
|
29
|
+
'cctype', 'cerrno', 'cfenv', 'cfloat', 'chrono', 'cinttypes',
|
|
30
|
+
'ciso646', 'climits', 'clocale', 'cmath', 'codecvt', 'compare',
|
|
31
|
+
'complex', 'concepts', 'condition_variable', 'coroutine', 'csetjmp',
|
|
32
|
+
'csignal', 'cstdalign', 'cstdarg', 'cstdbool', 'cstddef', 'cstdint',
|
|
33
|
+
'cstdio', 'cstdlib', 'cstring', 'ctgmath', 'ctime', 'cuchar',
|
|
34
|
+
'cwchar', 'cwctype', 'deque', 'exception', 'execution', 'filesystem',
|
|
35
|
+
'format', 'forward_list', 'fstream', 'functional', 'future',
|
|
36
|
+
'initializer_list', 'iomanip', 'ios', 'iosfwd', 'iostream',
|
|
37
|
+
'istream', 'iterator', 'limits', 'list', 'locale', 'map', 'memory',
|
|
38
|
+
'memory_resource', 'mutex', 'new', 'numbers', 'numeric', 'optional',
|
|
39
|
+
'ostream', 'queue', 'random', 'ranges', 'ratio', 'regex', 'scoped_allocator',
|
|
40
|
+
'set', 'shared_mutex', 'span', 'sstream', 'stack', 'stdexcept',
|
|
41
|
+
'streambuf', 'string', 'string_view', 'syncstream', 'system_error',
|
|
42
|
+
'thread', 'tuple', 'type_traits', 'typeindex', 'typeinfo', 'unordered_map',
|
|
43
|
+
'unordered_set', 'utility', 'valarray', 'variant', 'vector', 'version',
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
KNOWN_LIBS = {'boost', 'gtest', 'gmock', 'fmt', 'spdlog', 'nlohmann', 'openssl', 'curl', 'zlib', 'pthread', 'dlfcn'}
|
|
47
|
+
|
|
48
|
+
ext_re = re.compile(r'^\s*#\s*include\s*<([^>]+)>', re.MULTILINE)
|
|
49
|
+
local_re = re.compile(r'^\s*#\s*include\s*\x22([^\x22]+)\x22', re.MULTILINE)
|
|
50
|
+
|
|
51
|
+
ext_count = defaultdict(int)
|
|
52
|
+
ext_includes = defaultdict(set)
|
|
53
|
+
std_count = defaultdict(int)
|
|
54
|
+
local_includes = defaultdict(set)
|
|
55
|
+
|
|
56
|
+
for line in sys.stdin:
|
|
57
|
+
hdr = line.strip()
|
|
58
|
+
if not hdr or not os.path.isfile(hdr):
|
|
59
|
+
continue
|
|
60
|
+
try:
|
|
61
|
+
with open(hdr, 'r', errors='replace') as f:
|
|
62
|
+
content = f.read()
|
|
63
|
+
except Exception:
|
|
64
|
+
continue
|
|
65
|
+
|
|
66
|
+
basename = os.path.basename(hdr)
|
|
67
|
+
|
|
68
|
+
for m in ext_re.finditer(content):
|
|
69
|
+
header = m.group(1)
|
|
70
|
+
first_part = header.split('/')[0] if '/' in header else header
|
|
71
|
+
if header in STANDARD_HEADERS:
|
|
72
|
+
std_count[header] += 1
|
|
73
|
+
elif first_part in KNOWN_LIBS:
|
|
74
|
+
ext_count[first_part] += 1
|
|
75
|
+
ext_includes[first_part].add(header)
|
|
76
|
+
else:
|
|
77
|
+
ext_count[header] += 1
|
|
78
|
+
ext_includes[header].add(header)
|
|
79
|
+
|
|
80
|
+
for m in local_re.finditer(content):
|
|
81
|
+
inc = m.group(1)
|
|
82
|
+
local_includes[basename].add(inc)
|
|
83
|
+
|
|
84
|
+
lines = []
|
|
85
|
+
if std_count:
|
|
86
|
+
lines.append('Standard Library:')
|
|
87
|
+
for h in sorted(std_count, key=lambda x: -std_count[x])[:MAX]:
|
|
88
|
+
lines.append(f' <{h}> ({std_count[h]} files)')
|
|
89
|
+
|
|
90
|
+
if ext_count:
|
|
91
|
+
lines.append('')
|
|
92
|
+
lines.append('External Dependencies:')
|
|
93
|
+
for h in sorted(ext_count, key=lambda x: -ext_count[x])[:MAX]:
|
|
94
|
+
headers = ', '.join(sorted(ext_includes[h])[:3])
|
|
95
|
+
if len(ext_includes[h]) > 3:
|
|
96
|
+
headers += f' (+{len(ext_includes[h])-3} more)'
|
|
97
|
+
lines.append(f' {h} ({ext_count[h]} refs): {headers}')
|
|
98
|
+
|
|
99
|
+
if local_includes:
|
|
100
|
+
lines.append('')
|
|
101
|
+
lines.append('Internal Includes:')
|
|
102
|
+
sorted_local = sorted(local_includes.items(), key=lambda x: -len(x[1]))[:MAX]
|
|
103
|
+
for f, incs in sorted_local:
|
|
104
|
+
lines.append(f' {f} -> {len(incs)} headers')
|
|
105
|
+
|
|
106
|
+
if not std_count and not ext_count and not local_includes:
|
|
107
|
+
print('No includes found')
|
|
108
|
+
else:
|
|
109
|
+
print('\n'.join(lines))
|
|
110
|
+
"
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# C++ interface extraction — pure virtual function signatures
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
|
|
6
|
+
if ! command -v python3 &>/dev/null; then
|
|
7
|
+
echo "python3 is required for C++ interface extraction"
|
|
8
|
+
exit 0
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
HEADERS=$(find . -type f \( -name "*.h" -o -name "*.hpp" -o -name "*.hxx" \) \
|
|
12
|
+
-not -path "*/build/*" -not -path "*/.git/*" -not -path "*/cmake-build-*/*" \
|
|
13
|
+
-not -path "*/_deps/*" -not -path "*/third_party/*" -not -path "*/external/*" \
|
|
14
|
+
2>/dev/null | head -30)
|
|
15
|
+
|
|
16
|
+
if [ -z "$HEADERS" ]; then
|
|
17
|
+
echo "No C++ headers found"
|
|
18
|
+
exit 0
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
echo "$HEADERS" | PMDMAX="${MAX_INTERFACE:-15}" python3 -c "
|
|
22
|
+
import sys, os, re
|
|
23
|
+
|
|
24
|
+
MAX = int(os.environ.get('PMDMAX', '15'))
|
|
25
|
+
|
|
26
|
+
headers = []
|
|
27
|
+
for line in sys.stdin:
|
|
28
|
+
line = line.strip()
|
|
29
|
+
if line and os.path.isfile(line):
|
|
30
|
+
headers.append(line)
|
|
31
|
+
|
|
32
|
+
if not headers:
|
|
33
|
+
print('No C++ headers found')
|
|
34
|
+
sys.exit(0)
|
|
35
|
+
|
|
36
|
+
iface_blocks = []
|
|
37
|
+
class_re = re.compile(r'^\s*(?:class|struct)\s+([A-Za-z_]\w*)\s*(?::\s*(?:public|protected|private)\s+([A-Za-z_]\w*))?\s*\{', re.MULTILINE)
|
|
38
|
+
virt_re = re.compile(r'virtual\s+([\w:]+(?:\s*<[^>]+>)?(?:\s*[*&])?)\s+(\w+)\s*\(([^)]*)\)\s*(const)?\s*=\s*0\s*;')
|
|
39
|
+
|
|
40
|
+
for hdr in headers:
|
|
41
|
+
try:
|
|
42
|
+
with open(hdr, 'r', errors='replace') as f:
|
|
43
|
+
content = f.read()
|
|
44
|
+
except Exception:
|
|
45
|
+
continue
|
|
46
|
+
|
|
47
|
+
content = re.sub(r'//.*', '', content)
|
|
48
|
+
content = re.sub(r'/\*.*?\*/', '', content, flags=re.DOTALL)
|
|
49
|
+
|
|
50
|
+
pos = 0
|
|
51
|
+
while pos < len(content):
|
|
52
|
+
m = class_re.search(content, pos)
|
|
53
|
+
if not m:
|
|
54
|
+
break
|
|
55
|
+
cls_name = m.group(1)
|
|
56
|
+
start = m.end()
|
|
57
|
+
depth = 1
|
|
58
|
+
end = start
|
|
59
|
+
while end < len(content) and depth > 0:
|
|
60
|
+
if content[end] == '{':
|
|
61
|
+
depth += 1
|
|
62
|
+
elif content[end] == '}':
|
|
63
|
+
depth -= 1
|
|
64
|
+
end += 1
|
|
65
|
+
|
|
66
|
+
body = content[start:end]
|
|
67
|
+
found_methods = []
|
|
68
|
+
for vm in virt_re.finditer(body):
|
|
69
|
+
ret_type = vm.group(1).strip()
|
|
70
|
+
method_name = vm.group(2).strip()
|
|
71
|
+
params = vm.group(3).strip()
|
|
72
|
+
is_const = vm.group(4) is not None
|
|
73
|
+
if params:
|
|
74
|
+
params = re.sub(r'\s+', ' ', params)
|
|
75
|
+
param_types = []
|
|
76
|
+
for p in params.split(','):
|
|
77
|
+
p = p.strip()
|
|
78
|
+
if p:
|
|
79
|
+
parts = p.rsplit(None, 1)
|
|
80
|
+
if len(parts) == 2:
|
|
81
|
+
param_types.append(parts[0])
|
|
82
|
+
else:
|
|
83
|
+
param_types.append(p)
|
|
84
|
+
param_str = ', '.join(param_types)
|
|
85
|
+
suffix = ' const' if is_const else ''
|
|
86
|
+
sig = f'{method_name}({param_str}){suffix} -> {ret_type}'
|
|
87
|
+
else:
|
|
88
|
+
suffix = ' const' if is_const else ''
|
|
89
|
+
sig = f'{method_name}(){suffix} -> {ret_type}'
|
|
90
|
+
found_methods.append(sig)
|
|
91
|
+
|
|
92
|
+
if found_methods:
|
|
93
|
+
iface_blocks.append((os.path.basename(hdr), cls_name, found_methods))
|
|
94
|
+
pos = end
|
|
95
|
+
|
|
96
|
+
if not iface_blocks:
|
|
97
|
+
print('No pure virtual interfaces found')
|
|
98
|
+
sys.exit(0)
|
|
99
|
+
|
|
100
|
+
count = 0
|
|
101
|
+
for hdr, cls, methods in iface_blocks:
|
|
102
|
+
if count >= MAX:
|
|
103
|
+
break
|
|
104
|
+
print(f'[iface] {cls} ({hdr})')
|
|
105
|
+
for m in methods:
|
|
106
|
+
print(f' {m}')
|
|
107
|
+
count += 1
|
|
108
|
+
"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# C/C++ lint — clang-tidy or cppcheck
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
|
|
6
|
+
if command -v clang-tidy &>/dev/null; then
|
|
7
|
+
out=$(clang-tidy --checks='-*,bugprone-*,modernize-*,readability-*' -p build . 2>&1 | head -50)
|
|
8
|
+
limit_output "$out" "$MAX_LINT" "$(echo "$out" | head -3 && echo '... more clang-tidy warnings')"
|
|
9
|
+
elif command -v cppcheck &>/dev/null; then
|
|
10
|
+
out=$(cppcheck --enable=all --suppress=missingInclude . 2>&1 | head -50)
|
|
11
|
+
limit_output "$out" "$MAX_LINT" "$(echo "$out" | head -3 && echo '... more cppcheck warnings')"
|
|
12
|
+
else
|
|
13
|
+
echo "No C/C++ linter found (install clang-tidy or cppcheck)"
|
|
14
|
+
fi
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# C/C++ test summary — ctest or make test
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
|
|
6
|
+
if [ -f CMakeLists.txt ] && [ -d build ]; then
|
|
7
|
+
out=$(ctest --test-dir build --output-on-failure 2>&1 | tail -10)
|
|
8
|
+
if [ -n "$out" ]; then
|
|
9
|
+
limit_output "$out" "$MAX_TEST" "$(echo "$out" | head -3 && echo '... more test results')"
|
|
10
|
+
exit 0
|
|
11
|
+
fi
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
if [ -f Makefile ] || [ -f makefile ]; then
|
|
15
|
+
out=$(make test 2>&1 | tail -10)
|
|
16
|
+
if [ -n "$out" ]; then
|
|
17
|
+
limit_output "$out" "$MAX_TEST" "$(echo "$out" | head -3 && echo '... more test results')"
|
|
18
|
+
exit 0
|
|
19
|
+
fi
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
echo "No C/C++ test runner configured"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# C/C++ type check — compiler warnings
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
|
|
6
|
+
if [ -f CMakeLists.txt ] && [ -d build ]; then
|
|
7
|
+
out=$(cmake --build build 2>&1 | grep -E 'warning:|error:' | head -30)
|
|
8
|
+
if [ -z "$out" ]; then
|
|
9
|
+
echo "No compiler warnings"
|
|
10
|
+
exit 0
|
|
11
|
+
fi
|
|
12
|
+
limit_output "$out" "$MAX_TYPECHECK" "$(echo "$out" | head -3 && echo '... more compiler warnings')"
|
|
13
|
+
exit 0
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
if [ -f Makefile ] || [ -f makefile ]; then
|
|
17
|
+
out=$(make 2>&1 | grep -E 'warning:|error:' | head -30)
|
|
18
|
+
if [ -z "$out" ]; then
|
|
19
|
+
echo "No compiler warnings"
|
|
20
|
+
exit 0
|
|
21
|
+
fi
|
|
22
|
+
limit_output "$out" "$MAX_TYPECHECK" "$(echo "$out" | head -3 && echo '... more compiler warnings')"
|
|
23
|
+
exit 0
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
echo "No C/C++ type checker configured (build the project first)"
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# Architecture map — DevOps service dependencies (Docker Compose, Dockerfiles, Terraform)
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
|
|
6
|
+
: "${MAX_ARCH:=100}"
|
|
7
|
+
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
9
|
+
NORMALIZE="$SCRIPT_DIR/normalize.sh"
|
|
10
|
+
[ -f "$NORMALIZE" ] || NORMALIZE="$SCRIPT_DIR/../../Shared/architecture/normalize.sh"
|
|
11
|
+
|
|
12
|
+
(
|
|
13
|
+
if [ -f docker-compose.yml ] || [ -f docker-compose.yaml ]; then
|
|
14
|
+
COMPOSE_FILE="docker-compose.yml"
|
|
15
|
+
[ -f docker-compose.yaml ] && COMPOSE_FILE="docker-compose.yaml"
|
|
16
|
+
|
|
17
|
+
if command -v python3 &>/dev/null && python3 -c "import yaml" 2>/dev/null; then
|
|
18
|
+
python3 -c "
|
|
19
|
+
import sys, yaml, os
|
|
20
|
+
|
|
21
|
+
compose_file = os.environ.get('COMPOSE_FILE', 'docker-compose.yml')
|
|
22
|
+
try:
|
|
23
|
+
with open(compose_file, 'r') as f:
|
|
24
|
+
data = yaml.safe_load(f) or {}
|
|
25
|
+
except Exception:
|
|
26
|
+
sys.exit(0)
|
|
27
|
+
|
|
28
|
+
services = data.get('services', {})
|
|
29
|
+
if not services:
|
|
30
|
+
sys.exit(0)
|
|
31
|
+
|
|
32
|
+
for svc, cfg in services.items():
|
|
33
|
+
if not isinstance(cfg, dict):
|
|
34
|
+
continue
|
|
35
|
+
image = cfg.get('image', '')
|
|
36
|
+
if image:
|
|
37
|
+
img_name = image.split(':')[0].split('/')[-1]
|
|
38
|
+
print(f'{svc}\text:{img_name}')
|
|
39
|
+
depends = cfg.get('depends_on', [])
|
|
40
|
+
if isinstance(depends, list):
|
|
41
|
+
for dep in depends:
|
|
42
|
+
print(f'{svc}\t{dep}')
|
|
43
|
+
elif isinstance(depends, dict):
|
|
44
|
+
for dep in depends:
|
|
45
|
+
print(f'{svc}\t{dep}')
|
|
46
|
+
links = cfg.get('links', [])
|
|
47
|
+
for link in links:
|
|
48
|
+
dep = link.split(':')[0] if ':' in link else link
|
|
49
|
+
print(f'{svc}\t{dep}')
|
|
50
|
+
" COMPOSE_FILE="$COMPOSE_FILE" 2>/dev/null
|
|
51
|
+
else
|
|
52
|
+
awk '
|
|
53
|
+
/^[a-zA-Z0-9_-]+:/ && !/^[[:space:]]/ {
|
|
54
|
+
if (in_service && current_svc != "") {
|
|
55
|
+
services[current_svc] = 1
|
|
56
|
+
}
|
|
57
|
+
gsub(/:.*$/, "")
|
|
58
|
+
current_svc = $0
|
|
59
|
+
in_service = 1
|
|
60
|
+
next
|
|
61
|
+
}
|
|
62
|
+
in_service && /^[[:space:]]+depends_on:/ {
|
|
63
|
+
in_depends = 1
|
|
64
|
+
next
|
|
65
|
+
}
|
|
66
|
+
in_service && in_depends && /^[[:space:]]+-[[:space:]]*/ {
|
|
67
|
+
gsub(/^[[:space:]]+-[[:space:]]*/, "")
|
|
68
|
+
gsub(/:.*$/, "")
|
|
69
|
+
if (current_svc != "" && $0 != "") print current_svc "\t" $0
|
|
70
|
+
next
|
|
71
|
+
}
|
|
72
|
+
in_service && /^[[:space:]]+image:/ {
|
|
73
|
+
gsub(/^[[:space:]]+image:[[:space:]]*/, "")
|
|
74
|
+
gsub(/:.*$/, "")
|
|
75
|
+
img = $0
|
|
76
|
+
n = split(img, parts, "/")
|
|
77
|
+
short = parts[n]
|
|
78
|
+
if (current_svc != "" && short != "") print current_svc "\text:" short
|
|
79
|
+
next
|
|
80
|
+
}
|
|
81
|
+
/^[[:space:]]*$/ { in_depends = 0 }
|
|
82
|
+
/^[^[:space:]]/ && !/[a-zA-Z0-9_-]+:/ { in_service = 0 }
|
|
83
|
+
END { if (in_service && current_svc != "") services[current_svc] = 1 }
|
|
84
|
+
' "$COMPOSE_FILE" 2>/dev/null
|
|
85
|
+
fi
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
find . -name "Dockerfile" -not -path "*/.git/*" -not -path "*/.pipemd/*" 2>/dev/null | while IFS= read -r df; do
|
|
89
|
+
rel="${df#./}"
|
|
90
|
+
context_dir="$(dirname "$rel")"
|
|
91
|
+
[ "$context_dir" = "." ] && stage="main" || stage="$(basename "$context_dir")"
|
|
92
|
+
|
|
93
|
+
awk -v stage="$stage" '
|
|
94
|
+
/^FROM[[:space:]]/ {
|
|
95
|
+
img = $2
|
|
96
|
+
asname = ""
|
|
97
|
+
for (i = 3; i <= NF; i++) {
|
|
98
|
+
if ($i == "AS" || $i == "as" || $i == "As") {
|
|
99
|
+
asname = $(i+1)
|
|
100
|
+
break
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
gsub(/:.*$/, "", img)
|
|
104
|
+
base = img
|
|
105
|
+
n = split(base, parts, "/")
|
|
106
|
+
short = parts[n]
|
|
107
|
+
printf "%s\text:%s\n", stage, short
|
|
108
|
+
if (asname != "") printf "%s\t%s\n", stage, asname
|
|
109
|
+
}
|
|
110
|
+
/COPY[[:space:]]+--from=/ {
|
|
111
|
+
for (i = 1; i <= NF; i++) {
|
|
112
|
+
if ($i == "--from") {
|
|
113
|
+
src = $(i+1)
|
|
114
|
+
if (src !~ /^[0-9]+$/) {
|
|
115
|
+
printf "%s\t%s\n", stage, src
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
' "$df" 2>/dev/null
|
|
121
|
+
done
|
|
122
|
+
|
|
123
|
+
find . -name "*.tf" -not -path "*/.git/*" -not -path "*/.pipemd/*" -not -path "*/.terraform/*" 2>/dev/null | head -30 | while IFS= read -r tf; do
|
|
124
|
+
rel="${tf#./}"
|
|
125
|
+
tf_dir="$(dirname "$rel")"
|
|
126
|
+
[ "$tf_dir" = "." ] && tf_ctx="main" || tf_ctx="$(basename "$tf_dir")"
|
|
127
|
+
|
|
128
|
+
awk -v ctx="$tf_ctx" '
|
|
129
|
+
/^module[[:space:]]+"?/ {
|
|
130
|
+
gsub(/^module[[:space:]]+"?/, "")
|
|
131
|
+
gsub(/".*/, "")
|
|
132
|
+
name = $0
|
|
133
|
+
gsub(/[[:space:]]+/, "", name)
|
|
134
|
+
if (name != "") print ctx "\ttf:" name
|
|
135
|
+
}
|
|
136
|
+
/^data[[:space:]]+"?[a-zA-Z]/ {
|
|
137
|
+
gsub(/^data[[:space:]]+"?/, "")
|
|
138
|
+
gsub(/".*/, "")
|
|
139
|
+
dtype = $1
|
|
140
|
+
gsub(/[[:space:]]+/, "", dtype)
|
|
141
|
+
if (dtype != "") print ctx "\ttf:data_" dtype
|
|
142
|
+
}
|
|
143
|
+
/^resource[[:space:]]+"?[a-zA-Z]/ {
|
|
144
|
+
gsub(/^resource[[:space:]]+"?/, "")
|
|
145
|
+
gsub(/".*/, "")
|
|
146
|
+
rtype = $1
|
|
147
|
+
gsub(/[[:space:]]+/, "", rtype)
|
|
148
|
+
if (rtype != "") print ctx "\ttf:" rtype
|
|
149
|
+
}
|
|
150
|
+
/^provider[[:space:]]+"?[a-zA-Z]/ {
|
|
151
|
+
gsub(/^provider[[:space:]]+"?/, "")
|
|
152
|
+
gsub(/".*/, "")
|
|
153
|
+
pname = $0
|
|
154
|
+
gsub(/[[:space:]]+/, "", pname)
|
|
155
|
+
if (pname != "") print ctx "\text:" pname
|
|
156
|
+
}
|
|
157
|
+
' "$tf" 2>/dev/null
|
|
158
|
+
done
|
|
159
|
+
|
|
160
|
+
find . \( -name "*.yaml" -o -name "*.yml" \) -not -name "docker-compose.*" -not -path "*/.git/*" -not -path "*/.pipemd/*" 2>/dev/null | head -10 | while IFS= read -r kf; do
|
|
161
|
+
rel="${kf#./}"
|
|
162
|
+
kf_dir="$(dirname "$rel")"
|
|
163
|
+
[ "$kf_dir" = "." ] && kf_ctx="main" || kf_ctx="$(basename "$kf_dir")"
|
|
164
|
+
kf_base="$(basename "$rel" .yaml)"
|
|
165
|
+
[ "$kf_base" = "$(basename "$rel" .yml)" ] || kf_base="$(basename "$rel" .yml)"
|
|
166
|
+
|
|
167
|
+
if echo "$kf_base" | grep -qE '^(deploy|service|ingress|configmap|secret|daemonset|statefulset|deployment|cronjob|job|pod|hpa|pdb|namespace|pv|pvc)$'; then
|
|
168
|
+
awk -v ctx="$kf_ctx" '
|
|
169
|
+
/^[[:space:]]*name:/ {
|
|
170
|
+
gsub(/^[[:space:]]*name:[[:space:]]*/, "")
|
|
171
|
+
gsub(/"/, "")
|
|
172
|
+
gsub(/'"'"'/, "")
|
|
173
|
+
if ($0 != "") print ctx "\tk8s:" $0
|
|
174
|
+
}
|
|
175
|
+
/^[[:space:]]*image:/ {
|
|
176
|
+
gsub(/^[[:space:]]*image:[[:space:]]*/, "")
|
|
177
|
+
gsub(/:.*$/, "")
|
|
178
|
+
n = split($0, parts, "/")
|
|
179
|
+
short = parts[n]
|
|
180
|
+
if (short != "") print ctx "\text:" short
|
|
181
|
+
}
|
|
182
|
+
' "$kf" 2>/dev/null
|
|
183
|
+
fi
|
|
184
|
+
done
|
|
185
|
+
|
|
186
|
+
) | sort -u | MAX_ARCH="$MAX_ARCH" bash "$NORMALIZE"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# AWS caller identity — prevents account hallucination
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
|
|
6
|
+
if ! command -v aws &>/dev/null; then
|
|
7
|
+
echo "> ℹ️ aws CLI is not installed or not in PATH"
|
|
8
|
+
exit 0
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
identity=$(timeout 3s aws sts get-caller-identity --output json 2>/dev/null || true)
|
|
12
|
+
|
|
13
|
+
if [ -z "$identity" ]; then
|
|
14
|
+
echo "> ℹ️ Could not retrieve AWS caller identity (no credentials or timeout)"
|
|
15
|
+
exit 0
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
echo "## AWS Caller Identity"
|
|
19
|
+
echo ""
|
|
20
|
+
|
|
21
|
+
account=$(echo "$identity" | timeout 2s python3 -c "
|
|
22
|
+
import sys, json
|
|
23
|
+
d = json.load(sys.stdin)
|
|
24
|
+
account = d.get('Account', 'unknown')
|
|
25
|
+
userid = d.get('UserId', 'unknown')
|
|
26
|
+
arn = d.get('Arn', 'unknown')
|
|
27
|
+
print('| Field | Value |')
|
|
28
|
+
print('|-------|-------|')
|
|
29
|
+
print('| Account | {} |'.format(account))
|
|
30
|
+
print('| UserID | {} |'.format(userid))
|
|
31
|
+
print('| ARN | {} |'.format(arn))
|
|
32
|
+
" 2>/dev/null || echo "> Could not parse STS response")
|
|
33
|
+
|
|
34
|
+
echo "$account"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# Docker container health summary
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
|
|
6
|
+
if ! command -v docker &>/dev/null; then
|
|
7
|
+
echo "> ℹ️ docker is not installed or not in PATH"
|
|
8
|
+
exit 0
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
if ! timeout 3s docker info &>/dev/null; then
|
|
12
|
+
echo "> ℹ️ Docker daemon is not running"
|
|
13
|
+
exit 0
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
echo "## Docker Containers"
|
|
17
|
+
echo ""
|
|
18
|
+
|
|
19
|
+
containers=$(timeout 5s docker ps -a \
|
|
20
|
+
--filter "status=running" \
|
|
21
|
+
--filter "status=exited" \
|
|
22
|
+
--format "{{.Names}}|{{.Status}}|{{.Ports}}" 2>/dev/null)
|
|
23
|
+
|
|
24
|
+
if [ -z "$containers" ]; then
|
|
25
|
+
echo "> No running or recently exited containers found."
|
|
26
|
+
exit 0
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
echo "| Name | Status | Ports |"
|
|
30
|
+
echo "|------|--------|-------|"
|
|
31
|
+
|
|
32
|
+
echo "$containers" | head -15 | while IFS='|' read -r name status ports; do
|
|
33
|
+
clean_ports="${ports//-/}"
|
|
34
|
+
if [ -z "$clean_ports" ]; then clean_ports="—"; fi
|
|
35
|
+
echo "| ${name} | ${status} | ${clean_ports} |"
|
|
36
|
+
done
|
|
37
|
+
|
|
38
|
+
total=$(echo "$containers" | wc -l)
|
|
39
|
+
if [ "$total" -gt 15 ]; then
|
|
40
|
+
echo ""
|
|
41
|
+
echo "> Showing 15 of ${total} containers (truncated for token budget)"
|
|
42
|
+
fi
|