@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,144 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# limit.sh — Smart output limiter with compact fallbacks
|
|
4
|
+
# Shared version — used as fallback for any ecosystem without its own limit.sh
|
|
5
|
+
# Usage: source this, then call limit_output, limit_tree, etc.
|
|
6
|
+
|
|
7
|
+
# Token profile multiplier (override via PMD_TOKEN_PROFILE env var)
|
|
8
|
+
PMD_TOKEN_PROFILE="${PMD_TOKEN_PROFILE:-medium}"
|
|
9
|
+
case "$PMD_TOKEN_PROFILE" in
|
|
10
|
+
low) MULT_NUM=1; MULT_DEN=2 ;;
|
|
11
|
+
medium) MULT_NUM=1; MULT_DEN=1 ;;
|
|
12
|
+
high) MULT_NUM=3; MULT_DEN=2 ;;
|
|
13
|
+
xhigh) MULT_NUM=2; MULT_DEN=1 ;;
|
|
14
|
+
unlimited) PMD_UNLIMITED=1 ;;
|
|
15
|
+
*) MULT_NUM=1; MULT_DEN=1 ;;
|
|
16
|
+
esac
|
|
17
|
+
|
|
18
|
+
# Token budget constants (override via PMD_MAX_* env vars, scaled by profile multiplier)
|
|
19
|
+
if [ "${PMD_UNLIMITED:-0}" = "1" ]; then
|
|
20
|
+
MAX_TREE=${PMD_MAX_TREE:-99999}
|
|
21
|
+
MAX_DEPS=${PMD_MAX_DEPS:-99999}
|
|
22
|
+
MAX_TODOS=${PMD_MAX_TODOS:-99999}
|
|
23
|
+
MAX_LOG=${PMD_MAX_LOG:-99999}
|
|
24
|
+
MAX_BRANCH=${PMD_MAX_BRANCH:-99999}
|
|
25
|
+
MAX_STATUS=${PMD_MAX_STATUS:-99999}
|
|
26
|
+
MAX_DIFF=${PMD_MAX_DIFF:-99999}
|
|
27
|
+
MAX_TYPECHECK=${PMD_MAX_TYPECHECK:-99999}
|
|
28
|
+
MAX_LINT=${PMD_MAX_LINT:-99999}
|
|
29
|
+
MAX_TEST=${PMD_MAX_TEST:-99999}
|
|
30
|
+
MAX_PRISMA=${PMD_MAX_PRISMA:-99999}
|
|
31
|
+
MAX_EXPRESS=${PMD_MAX_EXPRESS:-99999}
|
|
32
|
+
MAX_FASTAPI=${PMD_MAX_FASTAPI:-99999}
|
|
33
|
+
MAX_DJANGO=${PMD_MAX_DJANGO:-99999}
|
|
34
|
+
MAX_SQLALCHEMY=${PMD_MAX_SQLALCHEMY:-99999}
|
|
35
|
+
MAX_NEST=${PMD_MAX_NEST:-99999}
|
|
36
|
+
MAX_NEXTJS=${PMD_MAX_NEXTJS:-99999}
|
|
37
|
+
MAX_REACT=${PMD_MAX_REACT:-99999}
|
|
38
|
+
MAX_ANGULAR=${PMD_MAX_ANGULAR:-99999}
|
|
39
|
+
MAX_CMAKE=${PMD_MAX_CMAKE:-99999}
|
|
40
|
+
MAX_CLASS=${PMD_MAX_CLASS:-99999}
|
|
41
|
+
MAX_INTERFACE=${PMD_MAX_INTERFACE:-99999}
|
|
42
|
+
MAX_INCLUDE=${PMD_MAX_INCLUDE:-99999}
|
|
43
|
+
MAX_CARGO=${PMD_MAX_CARGO:-99999}
|
|
44
|
+
MAX_CARGO_FEATURES=${PMD_MAX_CARGO_FEATURES:-99999}
|
|
45
|
+
MAX_GO_PKGS=${PMD_MAX_GO_PKGS:-99999}
|
|
46
|
+
MAX_GO_INTERFACES=${PMD_MAX_GO_INTERFACES:-99999}
|
|
47
|
+
MAX_DOCKER=${PMD_MAX_DOCKER:-99999}
|
|
48
|
+
MAX_K8S=${PMD_MAX_K8S:-99999}
|
|
49
|
+
MAX_TF=${PMD_MAX_TF:-99999}
|
|
50
|
+
MAX_AWS=${PMD_MAX_AWS:-99999}
|
|
51
|
+
MAX_ARCH=${PMD_MAX_ARCH:-99999}
|
|
52
|
+
MAX_COMPOSE=${PMD_MAX_COMPOSE:-99999}
|
|
53
|
+
MAX_CREW=${PMD_MAX_CREW:-99999}
|
|
54
|
+
else
|
|
55
|
+
MAX_TREE=$(( (${PMD_MAX_TREE:-50} * MULT_NUM) / MULT_DEN ))
|
|
56
|
+
MAX_DEPS=$(( (${PMD_MAX_DEPS:-40} * MULT_NUM) / MULT_DEN ))
|
|
57
|
+
MAX_TODOS=$(( (${PMD_MAX_TODOS:-20} * MULT_NUM) / MULT_DEN ))
|
|
58
|
+
MAX_LOG=$(( (${PMD_MAX_LOG:-20} * MULT_NUM) / MULT_DEN ))
|
|
59
|
+
MAX_BRANCH=$(( (${PMD_MAX_BRANCH:-20} * MULT_NUM) / MULT_DEN ))
|
|
60
|
+
MAX_STATUS=$(( (${PMD_MAX_STATUS:-30} * MULT_NUM) / MULT_DEN ))
|
|
61
|
+
MAX_DIFF=$(( (${PMD_MAX_DIFF:-30} * MULT_NUM) / MULT_DEN ))
|
|
62
|
+
MAX_TYPECHECK=$(( (${PMD_MAX_TYPECHECK:-30} * MULT_NUM) / MULT_DEN ))
|
|
63
|
+
MAX_LINT=$(( (${PMD_MAX_LINT:-20} * MULT_NUM) / MULT_DEN ))
|
|
64
|
+
MAX_TEST=$(( (${PMD_MAX_TEST:-10} * MULT_NUM) / MULT_DEN ))
|
|
65
|
+
MAX_PRISMA=$(( (${PMD_MAX_PRISMA:-40} * MULT_NUM) / MULT_DEN ))
|
|
66
|
+
MAX_EXPRESS=$(( (${PMD_MAX_EXPRESS:-30} * MULT_NUM) / MULT_DEN ))
|
|
67
|
+
MAX_FASTAPI=$(( (${PMD_MAX_FASTAPI:-30} * MULT_NUM) / MULT_DEN ))
|
|
68
|
+
MAX_DJANGO=$(( (${PMD_MAX_DJANGO:-40} * MULT_NUM) / MULT_DEN ))
|
|
69
|
+
MAX_SQLALCHEMY=$(( (${PMD_MAX_SQLALCHEMY:-40} * MULT_NUM) / MULT_DEN ))
|
|
70
|
+
MAX_NEST=$(( (${PMD_MAX_NEST:-30} * MULT_NUM) / MULT_DEN ))
|
|
71
|
+
MAX_NEXTJS=$(( (${PMD_MAX_NEXTJS:-30} * MULT_NUM) / MULT_DEN ))
|
|
72
|
+
MAX_REACT=$(( (${PMD_MAX_REACT:-30} * MULT_NUM) / MULT_DEN ))
|
|
73
|
+
MAX_ANGULAR=$(( (${PMD_MAX_ANGULAR:-30} * MULT_NUM) / MULT_DEN ))
|
|
74
|
+
MAX_CMAKE=$(( (${PMD_MAX_CMAKE:-40} * MULT_NUM) / MULT_DEN ))
|
|
75
|
+
MAX_CLASS=$(( (${PMD_MAX_CLASS:-40} * MULT_NUM) / MULT_DEN ))
|
|
76
|
+
MAX_INTERFACE=$(( (${PMD_MAX_INTERFACE:-30} * MULT_NUM) / MULT_DEN ))
|
|
77
|
+
MAX_INCLUDE=$(( (${PMD_MAX_INCLUDE:-40} * MULT_NUM) / MULT_DEN ))
|
|
78
|
+
MAX_CARGO=$(( (${PMD_MAX_CARGO:-40} * MULT_NUM) / MULT_DEN ))
|
|
79
|
+
MAX_CARGO_FEATURES=$(( (${PMD_MAX_CARGO_FEATURES:-20} * MULT_NUM) / MULT_DEN ))
|
|
80
|
+
MAX_GO_PKGS=$(( (${PMD_MAX_GO_PKGS:-40} * MULT_NUM) / MULT_DEN ))
|
|
81
|
+
MAX_GO_INTERFACES=$(( (${PMD_MAX_GO_INTERFACES:-30} * MULT_NUM) / MULT_DEN ))
|
|
82
|
+
MAX_DOCKER=$(( (${PMD_MAX_DOCKER:-30} * MULT_NUM) / MULT_DEN ))
|
|
83
|
+
MAX_K8S=$(( (${PMD_MAX_K8S:-20} * MULT_NUM) / MULT_DEN ))
|
|
84
|
+
MAX_TF=$(( (${PMD_MAX_TF:-40} * MULT_NUM) / MULT_DEN ))
|
|
85
|
+
MAX_AWS=$(( (${PMD_MAX_AWS:-10} * MULT_NUM) / MULT_DEN ))
|
|
86
|
+
MAX_ARCH=$(( (${PMD_MAX_ARCH:-100} * MULT_NUM) / MULT_DEN ))
|
|
87
|
+
MAX_COMPOSE=$(( (${PMD_MAX_COMPOSE:-150} * MULT_NUM) / MULT_DEN ))
|
|
88
|
+
MAX_CREW=$(( (${PMD_MAX_CREW:-40} * MULT_NUM) / MULT_DEN ))
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# Ecosystem-specific tree exclusions (override via TREE_EXCLUDES env var)
|
|
92
|
+
TREE_EXCLUDES="${PMD_TREE_EXCLUDES:-.git|.pipemd}"
|
|
93
|
+
|
|
94
|
+
limit_output() {
|
|
95
|
+
local text="$1"
|
|
96
|
+
local max="${2:-25}"
|
|
97
|
+
local fallback="$3"
|
|
98
|
+
local lines
|
|
99
|
+
lines=$(echo "$text" | wc -l)
|
|
100
|
+
if [ "$lines" -le "$max" ]; then
|
|
101
|
+
echo "$text"
|
|
102
|
+
else
|
|
103
|
+
echo "$fallback"
|
|
104
|
+
fi
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
limit_tree() {
|
|
108
|
+
local max="${1:-$MAX_TREE}"
|
|
109
|
+
local excl="${TREE_EXCLUDES}"
|
|
110
|
+
|
|
111
|
+
if command -v tree &>/dev/null; then
|
|
112
|
+
local out3
|
|
113
|
+
out3=$(tree -L 3 -I "$excl" --dirsfirst 2>/dev/null)
|
|
114
|
+
local lines3=$(echo "$out3" | wc -l)
|
|
115
|
+
|
|
116
|
+
if [ "$lines3" -le "$max" ]; then
|
|
117
|
+
echo "$out3"
|
|
118
|
+
return
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
local out2
|
|
122
|
+
out2=$(tree -L 2 -I "$excl" --dirsfirst 2>/dev/null)
|
|
123
|
+
local lines2=$(echo "$out2" | wc -l)
|
|
124
|
+
|
|
125
|
+
if [ "$lines2" -le "$max" ]; then
|
|
126
|
+
echo "$out2"
|
|
127
|
+
echo "(${lines3} lines at depth 3, showing depth 2)"
|
|
128
|
+
return
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
local out1
|
|
132
|
+
out1=$(tree -L 1 -I "$excl" --dirsfirst 2>/dev/null)
|
|
133
|
+
echo "$out1"
|
|
134
|
+
echo "(${lines3} lines at depth 3, showing depth 1)"
|
|
135
|
+
else
|
|
136
|
+
echo "Project structure:"
|
|
137
|
+
find . -maxdepth 3 \
|
|
138
|
+
-not -path '*/.git/*' \
|
|
139
|
+
-not -path '*/.pipemd/*' \
|
|
140
|
+
-not -name '.git' \
|
|
141
|
+
-not -name '.pipemd' \
|
|
142
|
+
2>/dev/null | head -"$max" | sort
|
|
143
|
+
fi
|
|
144
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# compose-md — Deep prompt builder: assembles README.md and docs from sub-projects
|
|
4
|
+
# Discovers tracked .md files via git, classifies by importance, truncates smartly,
|
|
5
|
+
# and outputs a structured concatenation suitable for AI context.
|
|
6
|
+
#
|
|
7
|
+
# Environment variables (set by limit.sh or override):
|
|
8
|
+
# PMD_COMPOSE_DEPTH Max directory depth to search (default: 4)
|
|
9
|
+
# PMD_COMPOSE_MAX_FILES Max files to include (default: 15)
|
|
10
|
+
# PMD_COMPOSE_ROOT_LINES Line limit for root README.md (default: 200)
|
|
11
|
+
# PMD_COMPOSE_OTHER_ROOT_LINES Line limit for other root .md files (default: 80)
|
|
12
|
+
# PMD_COMPOSE_SUB_LINES Line limit for sub-directory READMEs (default: 50)
|
|
13
|
+
# PMD_COMPOSE_DEEP_LINES Line limit for deeper .md files (default: 30)
|
|
14
|
+
# MAX_COMPOSE Total line budget (set by limit.sh per token profile)
|
|
15
|
+
# PMD_TOKEN_PROFILE Token profile: low|medium|high|xhigh|unlimited
|
|
16
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
17
|
+
|
|
18
|
+
: "${PMD_COMPOSE_DEPTH:=4}"
|
|
19
|
+
: "${PMD_COMPOSE_MAX_FILES:=15}"
|
|
20
|
+
: "${PMD_COMPOSE_ROOT_LINES:=200}"
|
|
21
|
+
: "${PMD_COMPOSE_OTHER_ROOT_LINES:=80}"
|
|
22
|
+
: "${PMD_COMPOSE_SUB_LINES:=50}"
|
|
23
|
+
: "${PMD_COMPOSE_DEEP_LINES:=30}"
|
|
24
|
+
: "${MAX_COMPOSE:=${MAX_COMPOSE:-150}}"
|
|
25
|
+
|
|
26
|
+
EXCLUDE_NAMES="AGENTS.md AI_CONTEXT.md pmd.md CLAUDE.md WORKSPACE_CONTEXT.md"
|
|
27
|
+
EXCLUDE_DIRS=".pipemd node_modules .git vendor __pycache__ .next .nuxt dist build out coverage .cache .venv .tox"
|
|
28
|
+
|
|
29
|
+
excluded_name() {
|
|
30
|
+
local name="$1"
|
|
31
|
+
for exc in $EXCLUDE_NAMES; do
|
|
32
|
+
[ "$name" = "$exc" ] && return 0
|
|
33
|
+
done
|
|
34
|
+
return 1
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
excluded_path() {
|
|
38
|
+
local rel="$1"
|
|
39
|
+
for exc in $EXCLUDE_DIRS; do
|
|
40
|
+
case "$rel" in
|
|
41
|
+
"$exc"/*|"$exc") return 0 ;;
|
|
42
|
+
esac
|
|
43
|
+
done
|
|
44
|
+
return 1
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
|
|
48
|
+
echo "Not a git repository — cannot discover markdown files"
|
|
49
|
+
exit 0
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
files=()
|
|
53
|
+
while IFS= read -r f; do
|
|
54
|
+
[ -z "$f" ] && continue
|
|
55
|
+
name="$(basename "$f")"
|
|
56
|
+
excluded_name "$name" && continue
|
|
57
|
+
excluded_path "$f" && continue
|
|
58
|
+
files+=("$f")
|
|
59
|
+
done < <(git ls-files '*.md' '*.MD' '*.Markdown' '*.markdown' 2>/dev/null | sort)
|
|
60
|
+
|
|
61
|
+
if [ ${#files[@]} -eq 0 ]; then
|
|
62
|
+
echo "No tracked markdown files found"
|
|
63
|
+
exit 0
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
classify() {
|
|
67
|
+
local rel="$1"
|
|
68
|
+
local depth
|
|
69
|
+
depth="$(echo "$rel" | tr -cd '/' | wc -c)"
|
|
70
|
+
local name
|
|
71
|
+
name="$(basename "$rel")"
|
|
72
|
+
|
|
73
|
+
if [ "$depth" -eq 0 ]; then
|
|
74
|
+
if [ "$name" = "README.md" ] || [ "$name" = "README.MD" ]; then
|
|
75
|
+
echo "root-README"
|
|
76
|
+
else
|
|
77
|
+
echo "root-other"
|
|
78
|
+
fi
|
|
79
|
+
elif [ "$depth" -le 1 ]; then
|
|
80
|
+
if [ "$name" = "README.md" ] || [ "$name" = "README.MD" ]; then
|
|
81
|
+
echo "sub-README"
|
|
82
|
+
else
|
|
83
|
+
echo "deep-md"
|
|
84
|
+
fi
|
|
85
|
+
else
|
|
86
|
+
if [ "$name" = "README.md" ] || [ "$name" = "README.MD" ]; then
|
|
87
|
+
echo "sub-README"
|
|
88
|
+
else
|
|
89
|
+
echo "deep-md"
|
|
90
|
+
fi
|
|
91
|
+
fi
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
sort_key() {
|
|
95
|
+
local rel="$1"
|
|
96
|
+
local cls
|
|
97
|
+
cls="$(classify "$rel")"
|
|
98
|
+
case "$cls" in
|
|
99
|
+
root-README) echo "0$rel" ;;
|
|
100
|
+
root-other) echo "1$rel" ;;
|
|
101
|
+
sub-README) echo "2$rel" ;;
|
|
102
|
+
deep-md) echo "3$rel" ;;
|
|
103
|
+
esac
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
declare -A file_order
|
|
107
|
+
for f in "${files[@]}"; do
|
|
108
|
+
key="$(sort_key "$f")"
|
|
109
|
+
file_order["$key"]="$f"
|
|
110
|
+
done
|
|
111
|
+
|
|
112
|
+
sorted_files=()
|
|
113
|
+
for key in $(printf '%s\n' "${!file_order[@]}" | sort); do
|
|
114
|
+
sorted_files+=("${file_order[$key]}")
|
|
115
|
+
done
|
|
116
|
+
|
|
117
|
+
max_line_limit() {
|
|
118
|
+
local cls="$1"
|
|
119
|
+
case "$cls" in
|
|
120
|
+
root-README) echo "$PMD_COMPOSE_ROOT_LINES" ;;
|
|
121
|
+
root-other) echo "$PMD_COMPOSE_OTHER_ROOT_LINES" ;;
|
|
122
|
+
sub-README) echo "$PMD_COMPOSE_SUB_LINES" ;;
|
|
123
|
+
deep-md) echo "$PMD_COMPOSE_DEEP_LINES" ;;
|
|
124
|
+
*) echo "$PMD_COMPOSE_DEEP_LINES" ;;
|
|
125
|
+
esac
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
total_lines=0
|
|
129
|
+
included=0
|
|
130
|
+
truncated=0
|
|
131
|
+
|
|
132
|
+
for f in "${sorted_files[@]}"; do
|
|
133
|
+
[ "$included" -ge "$PMD_COMPOSE_MAX_FILES" ] && break
|
|
134
|
+
|
|
135
|
+
cls="$(classify "$f")"
|
|
136
|
+
limit="$(max_line_limit "$cls")"
|
|
137
|
+
|
|
138
|
+
if [ "$total_lines" -ge "$MAX_COMPOSE" ]; then
|
|
139
|
+
break
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
content=""
|
|
143
|
+
if [ -f "$f" ]; then
|
|
144
|
+
content="$(head -n "$limit" "$f" 2>/dev/null)" || continue
|
|
145
|
+
else
|
|
146
|
+
continue
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
actual_lines="$(echo "$content" | wc -l)"
|
|
150
|
+
was_truncated=0
|
|
151
|
+
|
|
152
|
+
real_lines="$(wc -l < "$f" 2>/dev/null)" || real_lines="$actual_lines"
|
|
153
|
+
if [ "$real_lines" -gt "$limit" ]; then
|
|
154
|
+
was_truncated=1
|
|
155
|
+
truncated=$((truncated + 1))
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
budget_left=$((MAX_COMPOSE - total_lines))
|
|
159
|
+
if [ "$actual_lines" -gt "$budget_left" ]; then
|
|
160
|
+
content="$(echo "$content" | head -n "$budget_left")"
|
|
161
|
+
actual_lines="$(echo "$content" | wc -l)"
|
|
162
|
+
was_truncated=1
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
echo ""
|
|
166
|
+
echo "### $f"
|
|
167
|
+
echo ""
|
|
168
|
+
printf '%s\n' "$content"
|
|
169
|
+
|
|
170
|
+
if [ "$was_truncated" -eq 1 ]; then
|
|
171
|
+
echo ""
|
|
172
|
+
echo "... *(truncated, ${real_lines} lines total)*"
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
total_lines=$((total_lines + actual_lines + 3))
|
|
176
|
+
included=$((included + 1))
|
|
177
|
+
done
|
|
178
|
+
|
|
179
|
+
echo ""
|
|
180
|
+
echo "---"
|
|
181
|
+
echo ""
|
|
182
|
+
echo "*${included} files composed, ${total_lines} lines${truncated:+ (${truncated} truncated)}*"
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# Auto-detect dependency file and list dependencies, prioritizing detected ecosystem
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
|
|
6
|
+
eco="${PMD_ECOSYSTEM:-}"
|
|
7
|
+
|
|
8
|
+
check_node() {
|
|
9
|
+
if [ -f package.json ]; then
|
|
10
|
+
out=$(node -e "const p=require('./package.json');const d={...p.dependencies,...p.devDependencies,...p.peerDependencies};if(!Object.keys(d).length){console.log('No dependencies');process.exit()};Object.entries(d).forEach(([k,v])=>console.log(k+' '+v))" 2>/dev/null)
|
|
11
|
+
if [ -n "$out" ]; then
|
|
12
|
+
limit_output "$out" "$MAX_DEPS" "$(echo "$out" | head -5 && echo "... and $(echo "$out" | wc -l) total dependencies")"
|
|
13
|
+
exit 0
|
|
14
|
+
fi
|
|
15
|
+
fi
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
check_python() {
|
|
19
|
+
if [ -f requirements.txt ]; then
|
|
20
|
+
out=$(head -20 requirements.txt)
|
|
21
|
+
limit_output "$out" "$MAX_DEPS" "$(head -5 requirements.txt && echo "... and $(wc -l < requirements.txt) total lines")"
|
|
22
|
+
exit 0
|
|
23
|
+
elif [ -f pyproject.toml ]; then
|
|
24
|
+
out=$(awk '/^\[project\.dependencies\]/{in_deps=1;next}/^\[/{in_deps=0}in_deps&&/^[a-zA-Z_-]/{gsub(/=.*/,"");gsub(/[^a-zA-Z0-9._-]/,"");if(length>0)print}' pyproject.toml 2>/dev/null | head -"$MAX_DEPS")
|
|
25
|
+
if [ -n "$out" ]; then
|
|
26
|
+
echo "Dependencies:"
|
|
27
|
+
echo "$out"
|
|
28
|
+
exit 0
|
|
29
|
+
fi
|
|
30
|
+
fi
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
check_rust() {
|
|
34
|
+
if [ -f Cargo.toml ]; then
|
|
35
|
+
out=$(awk '/^\[dependencies\]/{in_deps=1;next}/^\[/{in_deps=0}in_deps&&/^[a-zA-Z_-]/{gsub(/=.*/,"");gsub(/[^a-zA-Z0-9_-]/,"");if(length>0)print}' Cargo.toml 2>/dev/null | head -"$MAX_DEPS")
|
|
36
|
+
if [ -n "$out" ]; then
|
|
37
|
+
echo "Dependencies:"
|
|
38
|
+
echo "$out"
|
|
39
|
+
exit 0
|
|
40
|
+
fi
|
|
41
|
+
fi
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
check_go() {
|
|
45
|
+
if [ -f go.mod ]; then
|
|
46
|
+
out=$(awk '/^require \(/{in_req=1;next}/^\)/&&in_req/{in_req=0;next}in_req&&/^[[:space:]]+/{print $1,$2}/^require[[:space:]]+/&&!/\(/{print $2,$3}' go.mod 2>/dev/null | head -"$MAX_DEPS")
|
|
47
|
+
if [ -n "$out" ]; then
|
|
48
|
+
echo "Dependencies:"
|
|
49
|
+
echo "$out"
|
|
50
|
+
exit 0
|
|
51
|
+
fi
|
|
52
|
+
fi
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
case "$eco" in
|
|
56
|
+
Node-TypeScript) check_node ;;
|
|
57
|
+
Python) check_python ;;
|
|
58
|
+
Rust) check_rust ;;
|
|
59
|
+
Go) check_go ;;
|
|
60
|
+
C-CPP) ;;
|
|
61
|
+
esac
|
|
62
|
+
|
|
63
|
+
# Generic: try all in order
|
|
64
|
+
check_node || true
|
|
65
|
+
check_python || true
|
|
66
|
+
check_rust || true
|
|
67
|
+
check_go || true
|
|
68
|
+
|
|
69
|
+
echo "No dependency file recognized"
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# Find TODO, FIXME, HACK — generic (no file-type filter)
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
out=$(grep -rn 'TODO\|FIXME\|HACK' . 2>/dev/null | grep -v '/.git/' | grep -v '/.pipemd/')
|
|
6
|
+
limit_output "$out" "$MAX_TODOS" "$(echo "$out" | head -3 && echo "... and $(($(echo "$out" | wc -l) - 3)) more items")"
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# Auto-detect linter and run, prioritizing detected ecosystem
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
|
|
6
|
+
eco="${PMD_ECOSYSTEM:-}"
|
|
7
|
+
|
|
8
|
+
case "$eco" in
|
|
9
|
+
Node-TypeScript)
|
|
10
|
+
if compgen -G ".eslintrc.*" &>/dev/null || compgen -G "eslint.config.*" &>/dev/null; then
|
|
11
|
+
out=$(npx eslint . --format=compact 2>&1 | head -30)
|
|
12
|
+
limit_output "$out" "$MAX_LINT" "$(echo "$out" | head -3 && echo '... more lint issues')"
|
|
13
|
+
exit 0
|
|
14
|
+
fi
|
|
15
|
+
echo "No ESLint configuration found"
|
|
16
|
+
exit 0
|
|
17
|
+
;;
|
|
18
|
+
Python)
|
|
19
|
+
if command -v ruff &>/dev/null; then
|
|
20
|
+
out=$(ruff check . 2>&1 | head -30)
|
|
21
|
+
limit_output "$out" "$MAX_LINT" "$(echo "$out" | head -3 && echo '... more lint issues')"
|
|
22
|
+
exit 0
|
|
23
|
+
elif command -v flake8 &>/dev/null; then
|
|
24
|
+
out=$(flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 2>&1 | head -30)
|
|
25
|
+
limit_output "$out" "$MAX_LINT" "$(echo "$out" | head -3 && echo '... more flake8 errors')"
|
|
26
|
+
exit 0
|
|
27
|
+
fi
|
|
28
|
+
echo "No Python linter found"
|
|
29
|
+
exit 0
|
|
30
|
+
;;
|
|
31
|
+
C-CPP)
|
|
32
|
+
if command -v clang-tidy &>/dev/null; then
|
|
33
|
+
out=$(clang-tidy --checks='-*,bugprone-*,modernize-*,readability-*' -p build . 2>&1 | head -30)
|
|
34
|
+
limit_output "$out" "$MAX_LINT" "$(echo "$out" | head -3 && echo '... more clang-tidy warnings')"
|
|
35
|
+
exit 0
|
|
36
|
+
fi
|
|
37
|
+
echo "No clang-tidy found"
|
|
38
|
+
exit 0
|
|
39
|
+
;;
|
|
40
|
+
Rust)
|
|
41
|
+
if command -v cargo &>/dev/null && [ -f Cargo.toml ]; then
|
|
42
|
+
out=$(cargo clippy --message-format=short 2>&1 | grep -E '^(error|warning)\[' | head -30)
|
|
43
|
+
limit_output "$out" "$MAX_LINT" "$(echo "$out" | head -3 && echo '... more clippy warnings')"
|
|
44
|
+
exit 0
|
|
45
|
+
fi
|
|
46
|
+
echo "No cargo found"
|
|
47
|
+
exit 0
|
|
48
|
+
;;
|
|
49
|
+
Go)
|
|
50
|
+
if command -v go &>/dev/null && [ -f go.mod ]; then
|
|
51
|
+
out=$(go vet ./... 2>&1 | head -30)
|
|
52
|
+
limit_output "$out" "$MAX_LINT" "$(echo "$out" | head -3 && echo '... more go vet warnings')"
|
|
53
|
+
exit 0
|
|
54
|
+
fi
|
|
55
|
+
echo "No go found"
|
|
56
|
+
exit 0
|
|
57
|
+
;;
|
|
58
|
+
esac
|
|
59
|
+
|
|
60
|
+
# Generic: auto-detect
|
|
61
|
+
if compgen -G ".eslintrc.*" &>/dev/null || compgen -G "eslint.config.*" &>/dev/null; then
|
|
62
|
+
out=$(npx eslint . --format=compact 2>&1 | head -30)
|
|
63
|
+
limit_output "$out" "$MAX_LINT" "$(echo "$out" | head -3 && echo '... more lint issues')"
|
|
64
|
+
elif command -v ruff &>/dev/null; then
|
|
65
|
+
out=$(ruff check . 2>&1 | head -30)
|
|
66
|
+
limit_output "$out" "$MAX_LINT" "$(echo "$out" | head -3 && echo '... more lint issues')"
|
|
67
|
+
elif command -v flake8 &>/dev/null; then
|
|
68
|
+
out=$(flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 2>&1 | head -30)
|
|
69
|
+
limit_output "$out" "$MAX_LINT" "$(echo "$out" | head -3 && echo '... more flake8 errors')"
|
|
70
|
+
elif command -v clang-tidy &>/dev/null; then
|
|
71
|
+
out=$(clang-tidy --checks='-*,bugprone-*,modernize-*,readability-*' -p build . 2>&1 | head -30)
|
|
72
|
+
limit_output "$out" "$MAX_LINT" "$(echo "$out" | head -3 && echo '... more clang-tidy warnings')"
|
|
73
|
+
elif command -v cargo &>/dev/null && [ -f Cargo.toml ]; then
|
|
74
|
+
out=$(cargo clippy --message-format=short 2>&1 | grep -E '^(error|warning)\[' | head -30)
|
|
75
|
+
limit_output "$out" "$MAX_LINT" "$(echo "$out" | head -3 && echo '... more clippy warnings')"
|
|
76
|
+
elif command -v go &>/dev/null && [ -f go.mod ]; then
|
|
77
|
+
out=$(go vet ./... 2>&1 | head -30)
|
|
78
|
+
limit_output "$out" "$MAX_LINT" "$(echo "$out" | head -3 && echo '... more go vet warnings')"
|
|
79
|
+
else
|
|
80
|
+
echo "No linter configured for this ecosystem"
|
|
81
|
+
fi
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# Auto-detect test runner and run, prioritizing detected ecosystem
|
|
4
|
+
source "$(dirname "$0")/../lib/limit.sh"
|
|
5
|
+
|
|
6
|
+
eco="${PMD_ECOSYSTEM:-}"
|
|
7
|
+
|
|
8
|
+
case "$eco" in
|
|
9
|
+
Node-TypeScript)
|
|
10
|
+
if compgen -G "jest.config.*" &>/dev/null || compgen -G "vitest.config.*" &>/dev/null; then
|
|
11
|
+
out=$(npx jest --no-coverage --silent 2>&1 | tail -5 || npx vitest run --reporter=verbose 2>&1 | tail -5)
|
|
12
|
+
echo "$out"
|
|
13
|
+
exit 0
|
|
14
|
+
fi
|
|
15
|
+
# Fallback: detect test script in package.json
|
|
16
|
+
if [ -f package.json ]; then
|
|
17
|
+
test_cmd=$(node -e "const p=require('./package.json');console.log(p.scripts&&p.scripts['test:unit']?'test:unit':p.scripts&&p.scripts['test']?'test':'')" 2>/dev/null)
|
|
18
|
+
if [ -n "$test_cmd" ]; then
|
|
19
|
+
pkg_mgr="npm"
|
|
20
|
+
[ -f pnpm-lock.yaml ] && pkg_mgr="pnpm"
|
|
21
|
+
[ -f yarn.lock ] && pkg_mgr="yarn"
|
|
22
|
+
out=$($pkg_mgr run $test_cmd 2>&1 | tail -"$MAX_TEST")
|
|
23
|
+
if [ -n "$out" ]; then
|
|
24
|
+
echo "$out"
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
fi
|
|
28
|
+
fi
|
|
29
|
+
echo "No test runner found"
|
|
30
|
+
exit 0
|
|
31
|
+
;;
|
|
32
|
+
Python)
|
|
33
|
+
if command -v pytest &>/dev/null || [ -f pytest.ini ] || [ -f conftest.py ]; then
|
|
34
|
+
out=$(python -m pytest --tb=no -q 2>&1 | tail -5)
|
|
35
|
+
echo "$out"
|
|
36
|
+
exit 0
|
|
37
|
+
fi
|
|
38
|
+
echo "No pytest found"
|
|
39
|
+
exit 0
|
|
40
|
+
;;
|
|
41
|
+
C-CPP)
|
|
42
|
+
if [ -f CMakeLists.txt ] && [ -d build ]; then
|
|
43
|
+
out=$(ctest --test-dir build --output-on-failure 2>&1 | tail -5)
|
|
44
|
+
echo "$out"
|
|
45
|
+
exit 0
|
|
46
|
+
fi
|
|
47
|
+
echo "No CMake test directory found"
|
|
48
|
+
exit 0
|
|
49
|
+
;;
|
|
50
|
+
Rust)
|
|
51
|
+
if command -v cargo &>/dev/null && [ -f Cargo.toml ]; then
|
|
52
|
+
out=$(cargo test 2>&1 | tail -5)
|
|
53
|
+
echo "$out"
|
|
54
|
+
exit 0
|
|
55
|
+
fi
|
|
56
|
+
echo "No cargo found"
|
|
57
|
+
exit 0
|
|
58
|
+
;;
|
|
59
|
+
Go)
|
|
60
|
+
if command -v go &>/dev/null && [ -f go.mod ]; then
|
|
61
|
+
out=$(go test ./... 2>&1 | tail -5)
|
|
62
|
+
echo "$out"
|
|
63
|
+
exit 0
|
|
64
|
+
fi
|
|
65
|
+
echo "No go found"
|
|
66
|
+
exit 0
|
|
67
|
+
;;
|
|
68
|
+
esac
|
|
69
|
+
|
|
70
|
+
# Generic: auto-detect
|
|
71
|
+
if compgen -G "jest.config.*" &>/dev/null || compgen -G "vitest.config.*" &>/dev/null; then
|
|
72
|
+
out=$(npx jest --no-coverage --silent 2>&1 | tail -5 || npx vitest run --reporter=verbose 2>&1 | tail -5)
|
|
73
|
+
echo "$out"
|
|
74
|
+
elif command -v pytest &>/dev/null || [ -f pytest.ini ] || [ -f conftest.py ]; then
|
|
75
|
+
out=$(python -m pytest --tb=no -q 2>&1 | tail -5)
|
|
76
|
+
echo "$out"
|
|
77
|
+
elif command -v cargo &>/dev/null && [ -f Cargo.toml ]; then
|
|
78
|
+
out=$(cargo test 2>&1 | tail -5)
|
|
79
|
+
echo "$out"
|
|
80
|
+
elif command -v go &>/dev/null && [ -f go.mod ]; then
|
|
81
|
+
out=$(go test ./... 2>&1 | tail -5)
|
|
82
|
+
echo "$out"
|
|
83
|
+
elif [ -f CMakeLists.txt ] && [ -d build ]; then
|
|
84
|
+
out=$(ctest --test-dir build --output-on-failure 2>&1 | tail -5)
|
|
85
|
+
echo "$out"
|
|
86
|
+
elif [ -f package.json ]; then
|
|
87
|
+
test_cmd=$(node -e "const p=require('./package.json');console.log(p.scripts&&p.scripts['test:unit']?'test:unit':p.scripts&&p.scripts['test']?'test':'')" 2>/dev/null)
|
|
88
|
+
if [ -n "$test_cmd" ]; then
|
|
89
|
+
pkg_mgr="npm"
|
|
90
|
+
[ -f pnpm-lock.yaml ] && pkg_mgr="pnpm"
|
|
91
|
+
[ -f yarn.lock ] && pkg_mgr="yarn"
|
|
92
|
+
out=$($pkg_mgr run $test_cmd 2>&1 | tail -"$MAX_TEST")
|
|
93
|
+
if [ -n "$out" ]; then
|
|
94
|
+
echo "$out"
|
|
95
|
+
else
|
|
96
|
+
echo "Test runner produced no output"
|
|
97
|
+
fi
|
|
98
|
+
else
|
|
99
|
+
echo "No test runner configured for this ecosystem"
|
|
100
|
+
fi
|
|
101
|
+
else
|
|
102
|
+
echo "No test runner configured for this ecosystem"
|
|
103
|
+
fi
|