@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.
Files changed (96) hide show
  1. package/AI_SETUP_PIPEMD.md +184 -0
  2. package/CHANGELOG.md +47 -0
  3. package/LICENSE +15 -0
  4. package/README.md +535 -0
  5. package/dist/index.js +6647 -0
  6. package/dist/plugins/opencode-server.js +235 -0
  7. package/dist/plugins/opencode-tui.js +914 -0
  8. package/dist/templates/agent-decision-tree.md +113 -0
  9. package/dist/templates/static-rules.md +7 -0
  10. package/package.json +68 -0
  11. package/scripts/C-CPP/architecture/arch.sh +229 -0
  12. package/scripts/C-CPP/lib/limit.sh +146 -0
  13. package/scripts/C-CPP/project/class-diagram.sh +96 -0
  14. package/scripts/C-CPP/project/cmake-targets.sh +68 -0
  15. package/scripts/C-CPP/project/deps.sh +44 -0
  16. package/scripts/C-CPP/project/find-todos.sh +6 -0
  17. package/scripts/C-CPP/project/include-graph.sh +110 -0
  18. package/scripts/C-CPP/project/interfaces.sh +108 -0
  19. package/scripts/C-CPP/project/tree.sh +5 -0
  20. package/scripts/C-CPP/quality/lint.sh +14 -0
  21. package/scripts/C-CPP/quality/test-summary.sh +22 -0
  22. package/scripts/C-CPP/quality/type-check.sh +26 -0
  23. package/scripts/DevOps/architecture/arch.sh +186 -0
  24. package/scripts/DevOps/devops/aws-context.sh +34 -0
  25. package/scripts/DevOps/devops/docker-stats.sh +42 -0
  26. package/scripts/DevOps/devops/k8s-unhealthy.sh +41 -0
  27. package/scripts/DevOps/devops/tf-state.sh +65 -0
  28. package/scripts/DevOps/lib/limit.sh +143 -0
  29. package/scripts/Generic/architecture/arch.sh +570 -0
  30. package/scripts/Generic/lib/limit.sh +140 -0
  31. package/scripts/Go/architecture/arch.sh +79 -0
  32. package/scripts/Go/lib/limit.sh +142 -0
  33. package/scripts/Go/project/deps.sh +35 -0
  34. package/scripts/Go/project/find-todos.sh +6 -0
  35. package/scripts/Go/project/go-interfaces.sh +18 -0
  36. package/scripts/Go/project/go-packages.sh +28 -0
  37. package/scripts/Go/project/tree.sh +5 -0
  38. package/scripts/Go/quality/lint.sh +16 -0
  39. package/scripts/Go/quality/test-summary.sh +16 -0
  40. package/scripts/Go/quality/type-check.sh +16 -0
  41. package/scripts/Node-TypeScript/api/express-routes.sh +14 -0
  42. package/scripts/Node-TypeScript/api/nest-controllers.sh +18 -0
  43. package/scripts/Node-TypeScript/architecture/arch.sh +174 -0
  44. package/scripts/Node-TypeScript/frontend/angular-routes.sh +15 -0
  45. package/scripts/Node-TypeScript/frontend/nextjs-app-router.sh +13 -0
  46. package/scripts/Node-TypeScript/frontend/react-components.sh +20 -0
  47. package/scripts/Node-TypeScript/lib/limit.sh +146 -0
  48. package/scripts/Node-TypeScript/project/deps.sh +15 -0
  49. package/scripts/Node-TypeScript/project/find-todos.sh +6 -0
  50. package/scripts/Node-TypeScript/quality/lint.sh +10 -0
  51. package/scripts/Node-TypeScript/quality/test-summary.sh +39 -0
  52. package/scripts/Node-TypeScript/quality/type-check.sh +10 -0
  53. package/scripts/Python/api/fastapi-routes.sh +12 -0
  54. package/scripts/Python/architecture/arch.sh +220 -0
  55. package/scripts/Python/db/django-models.sh +12 -0
  56. package/scripts/Python/db/sqlalchemy.sh +17 -0
  57. package/scripts/Python/lib/limit.sh +144 -0
  58. package/scripts/Python/project/deps.sh +28 -0
  59. package/scripts/Python/project/find-todos.sh +6 -0
  60. package/scripts/Python/quality/lint.sh +13 -0
  61. package/scripts/Python/quality/test-summary.sh +11 -0
  62. package/scripts/Python/quality/type-check.sh +10 -0
  63. package/scripts/Rust/architecture/arch.sh +176 -0
  64. package/scripts/Rust/lib/limit.sh +142 -0
  65. package/scripts/Rust/project/cargo-deps.sh +42 -0
  66. package/scripts/Rust/project/cargo-features.sh +26 -0
  67. package/scripts/Rust/project/find-todos.sh +6 -0
  68. package/scripts/Rust/project/tree.sh +5 -0
  69. package/scripts/Rust/quality/lint.sh +16 -0
  70. package/scripts/Rust/quality/test-summary.sh +16 -0
  71. package/scripts/Rust/quality/type-check.sh +16 -0
  72. package/scripts/Shared/api/express-routes.sh +11 -0
  73. package/scripts/Shared/api/fastapi-routes.sh +10 -0
  74. package/scripts/Shared/api/nest-controllers.sh +22 -0
  75. package/scripts/Shared/architecture/normalize.sh +178 -0
  76. package/scripts/Shared/crew/crew.sh +15 -0
  77. package/scripts/Shared/db/django-models.sh +11 -0
  78. package/scripts/Shared/db/prisma.sh +33 -0
  79. package/scripts/Shared/db/sqlalchemy.sh +12 -0
  80. package/scripts/Shared/frontend/angular-routes.sh +11 -0
  81. package/scripts/Shared/frontend/nextjs-app-router.sh +13 -0
  82. package/scripts/Shared/frontend/react-components.sh +11 -0
  83. package/scripts/Shared/git/diff-stat.sh +6 -0
  84. package/scripts/Shared/git/git-branch.sh +16 -0
  85. package/scripts/Shared/git/git-log.sh +6 -0
  86. package/scripts/Shared/git/git-status.sh +6 -0
  87. package/scripts/Shared/lib/limit.sh +144 -0
  88. package/scripts/Shared/project/compose-md.sh +182 -0
  89. package/scripts/Shared/project/deps.sh +69 -0
  90. package/scripts/Shared/project/find-todos.sh +6 -0
  91. package/scripts/Shared/project/tree.sh +5 -0
  92. package/scripts/Shared/quality/lint.sh +81 -0
  93. package/scripts/Shared/quality/test-summary.sh +103 -0
  94. package/scripts/Shared/quality/type-check.sh +114 -0
  95. package/scripts/copy-plugins.mjs +4 -0
  96. 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,5 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Project tree — progressive depth fallback
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ limit_tree "$MAX_TREE"
@@ -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