@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,142 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # limit.sh — Smart output limiter with compact fallbacks
4
+ # TOKEN profile multiplier (override via PMD_TOKEN_PROFILE env var)
5
+ PMD_TOKEN_PROFILE="${PMD_TOKEN_PROFILE:-medium}"
6
+ case "$PMD_TOKEN_PROFILE" in
7
+ low) MULT_NUM=1; MULT_DEN=2 ;;
8
+ medium) MULT_NUM=1; MULT_DEN=1 ;;
9
+ high) MULT_NUM=3; MULT_DEN=2 ;;
10
+ xhigh) MULT_NUM=2; MULT_DEN=1 ;;
11
+ unlimited) PMD_UNLIMITED=1 ;;
12
+ *) MULT_NUM=1; MULT_DEN=1 ;;
13
+ esac
14
+
15
+ # Token budget constants (override via PMD_MAX_* env vars, scaled by profile)
16
+ if [ "${PMD_UNLIMITED:-0}" = "1" ]; then
17
+ MAX_TREE=${PMD_MAX_TREE:-99999}
18
+ MAX_DEPS=${PMD_MAX_DEPS:-99999}
19
+ MAX_TODOS=${PMD_MAX_TODOS:-99999}
20
+ MAX_LOG=${PMD_MAX_LOG:-99999}
21
+ MAX_BRANCH=${PMD_MAX_BRANCH:-99999}
22
+ MAX_STATUS=${PMD_MAX_STATUS:-99999}
23
+ MAX_DIFF=${PMD_MAX_DIFF:-99999}
24
+ MAX_TYPECHECK=${PMD_MAX_TYPECHECK:-99999}
25
+ MAX_LINT=${PMD_MAX_LINT:-99999}
26
+ MAX_TEST=${PMD_MAX_TEST:-99999}
27
+ MAX_PRISMA=${PMD_MAX_PRISMA:-99999}
28
+ MAX_EXPRESS=${PMD_MAX_EXPRESS:-99999}
29
+ MAX_FASTAPI=${PMD_MAX_FASTAPI:-99999}
30
+ MAX_DJANGO=${PMD_MAX_DJANGO:-99999}
31
+ MAX_SQLALCHEMY=${PMD_MAX_SQLALCHEMY:-99999}
32
+ MAX_NEST=${PMD_MAX_NEST:-99999}
33
+ MAX_NEXTJS=${PMD_MAX_NEXTJS:-99999}
34
+ MAX_REACT=${PMD_MAX_REACT:-99999}
35
+ MAX_ANGULAR=${PMD_MAX_ANGULAR:-99999}
36
+ MAX_CMAKE=${PMD_MAX_CMAKE:-99999}
37
+ MAX_CLASS=${PMD_MAX_CLASS:-99999}
38
+ MAX_INTERFACE=${PMD_MAX_INTERFACE:-99999}
39
+ MAX_INCLUDE=${PMD_MAX_INCLUDE:-99999}
40
+ MAX_CARGO=${PMD_MAX_CARGO:-99999}
41
+ MAX_GO_PKGS=${PMD_MAX_GO_PKGS:-99999}
42
+ MAX_CARGO_FEATURES=${PMD_MAX_CARGO_FEATURES:-99999}
43
+ MAX_GO_INTERFACES=${PMD_MAX_GO_INTERFACES:-99999}
44
+ MAX_DOCKER=${PMD_MAX_DOCKER:-99999}
45
+ MAX_K8S=${PMD_MAX_K8S:-99999}
46
+ MAX_TF=${PMD_MAX_TF:-99999}
47
+ MAX_AWS=${PMD_MAX_AWS:-99999}
48
+ MAX_ARCH=${PMD_MAX_ARCH:-99999}
49
+ MAX_COMPOSE=${PMD_MAX_COMPOSE:-99999}
50
+ MAX_CREW=${PMD_MAX_CREW:-99999}
51
+ else
52
+ MAX_TREE=$(( (${PMD_MAX_TREE:-50} * MULT_NUM) / MULT_DEN ))
53
+ MAX_DEPS=$(( (${PMD_MAX_DEPS:-40} * MULT_NUM) / MULT_DEN ))
54
+ MAX_TODOS=$(( (${PMD_MAX_TODOS:-20} * MULT_NUM) / MULT_DEN ))
55
+ MAX_LOG=$(( (${PMD_MAX_LOG:-20} * MULT_NUM) / MULT_DEN ))
56
+ MAX_BRANCH=$(( (${PMD_MAX_BRANCH:-20} * MULT_NUM) / MULT_DEN ))
57
+ MAX_STATUS=$(( (${PMD_MAX_STATUS:-30} * MULT_NUM) / MULT_DEN ))
58
+ MAX_DIFF=$(( (${PMD_MAX_DIFF:-30} * MULT_NUM) / MULT_DEN ))
59
+ MAX_TYPECHECK=$(( (${PMD_MAX_TYPECHECK:-30} * MULT_NUM) / MULT_DEN ))
60
+ MAX_LINT=$(( (${PMD_MAX_LINT:-20} * MULT_NUM) / MULT_DEN ))
61
+ MAX_TEST=$(( (${PMD_MAX_TEST:-10} * MULT_NUM) / MULT_DEN ))
62
+ MAX_PRISMA=$(( (${PMD_MAX_PRISMA:-40} * MULT_NUM) / MULT_DEN ))
63
+ MAX_EXPRESS=$(( (${PMD_MAX_EXPRESS:-30} * MULT_NUM) / MULT_DEN ))
64
+ MAX_FASTAPI=$(( (${PMD_MAX_FASTAPI:-30} * MULT_NUM) / MULT_DEN ))
65
+ MAX_DJANGO=$(( (${PMD_MAX_DJANGO:-40} * MULT_NUM) / MULT_DEN ))
66
+ MAX_SQLALCHEMY=$(( (${PMD_MAX_SQLALCHEMY:-40} * MULT_NUM) / MULT_DEN ))
67
+ MAX_NEST=$(( (${PMD_MAX_NEST:-30} * MULT_NUM) / MULT_DEN ))
68
+ MAX_NEXTJS=$(( (${PMD_MAX_NEXTJS:-30} * MULT_NUM) / MULT_DEN ))
69
+ MAX_REACT=$(( (${PMD_MAX_REACT:-30} * MULT_NUM) / MULT_DEN ))
70
+ MAX_ANGULAR=$(( (${PMD_MAX_ANGULAR:-30} * MULT_NUM) / MULT_DEN ))
71
+ MAX_CMAKE=$(( (${PMD_MAX_CMAKE:-40} * MULT_NUM) / MULT_DEN ))
72
+ MAX_CLASS=$(( (${PMD_MAX_CLASS:-40} * MULT_NUM) / MULT_DEN ))
73
+ MAX_INTERFACE=$(( (${PMD_MAX_INTERFACE:-30} * MULT_NUM) / MULT_DEN ))
74
+ MAX_INCLUDE=$(( (${PMD_MAX_INCLUDE:-40} * MULT_NUM) / MULT_DEN ))
75
+ MAX_CARGO=$(( (${PMD_MAX_CARGO:-40} * MULT_NUM) / MULT_DEN ))
76
+ MAX_GO_PKGS=$(( (${PMD_MAX_GO_PKGS:-40} * MULT_NUM) / MULT_DEN ))
77
+ MAX_CARGO_FEATURES=$(( (${PMD_MAX_CARGO_FEATURES:-20} * MULT_NUM) / MULT_DEN ))
78
+ MAX_GO_INTERFACES=$(( (${PMD_MAX_GO_INTERFACES:-30} * MULT_NUM) / MULT_DEN ))
79
+ MAX_DOCKER=$(( (${PMD_MAX_DOCKER:-30} * MULT_NUM) / MULT_DEN ))
80
+ MAX_K8S=$(( (${PMD_MAX_K8S:-20} * MULT_NUM) / MULT_DEN ))
81
+ MAX_TF=$(( (${PMD_MAX_TF:-40} * MULT_NUM) / MULT_DEN ))
82
+ MAX_AWS=$(( (${PMD_MAX_AWS:-10} * MULT_NUM) / MULT_DEN ))
83
+ MAX_ARCH=$(( (${PMD_MAX_ARCH:-100} * MULT_NUM) / MULT_DEN ))
84
+ MAX_COMPOSE=$(( (${PMD_MAX_COMPOSE:-150} * MULT_NUM) / MULT_DEN ))
85
+ MAX_CREW=$(( (${PMD_MAX_CREW:-40} * MULT_NUM) / MULT_DEN ))
86
+ fi
87
+
88
+ TREE_EXCLUDES="${PMD_TREE_EXCLUDES:-target|.git|.pipemd|node_modules|cargo-registry}"
89
+
90
+ limit_output() {
91
+ local text="$1"
92
+ local max="${2:-25}"
93
+ local fallback="$3"
94
+ local lines
95
+ lines=$(echo "$text" | wc -l)
96
+ if [ "$lines" -le "$max" ]; then
97
+ echo "$text"
98
+ else
99
+ echo "$fallback"
100
+ fi
101
+ }
102
+
103
+ limit_tree() {
104
+ local max="${1:-$MAX_TREE}"
105
+ local excl="${TREE_EXCLUDES}"
106
+
107
+ if command -v tree &>/dev/null; then
108
+ local out3
109
+ out3=$(tree -L 3 -I "$excl" --dirsfirst 2>/dev/null)
110
+ local lines3=$(echo "$out3" | wc -l)
111
+
112
+ if [ "$lines3" -le "$max" ]; then
113
+ echo "$out3"
114
+ return
115
+ fi
116
+
117
+ local out2
118
+ out2=$(tree -L 2 -I "$excl" --dirsfirst 2>/dev/null)
119
+ local lines2=$(echo "$out2" | wc -l)
120
+
121
+ if [ "$lines2" -le "$max" ]; then
122
+ echo "$out2"
123
+ echo "(${lines3} lines at depth 3, showing depth 2)"
124
+ return
125
+ fi
126
+
127
+ local out1
128
+ out1=$(tree -L 1 -I "$excl" --dirsfirst 2>/dev/null)
129
+ echo "$out1"
130
+ echo "(${lines3} lines at depth 3, showing depth 1)"
131
+ else
132
+ echo "Project structure:"
133
+ find . -maxdepth 3 \
134
+ -not -path '*/target/*' \
135
+ -not -path '*/.git/*' \
136
+ -not -path '*/.pipemd/*' \
137
+ -not -name 'target' \
138
+ -not -name '.git' \
139
+ -not -name '.pipemd' \
140
+ 2>/dev/null | head -"$max" | sort
141
+ fi
142
+ }
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Cargo dependencies — parse Cargo.toml [dependencies]
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+
6
+ if [ ! -f Cargo.toml ]; then
7
+ echo "No Cargo.toml found"
8
+ exit 0
9
+ fi
10
+
11
+ out=$(awk '
12
+ /^\[dependencies\]/ { in_deps=1; next }
13
+ /^\[/ { in_deps=0 }
14
+ in_deps && /^[a-zA-Z_-]/ {
15
+ gsub(/=.*/, "")
16
+ gsub(/[^a-zA-Z0-9_-]/, "")
17
+ if (length($0) > 0) print $0
18
+ }
19
+ ' Cargo.toml 2>/dev/null | head -"$MAX_DEPS")
20
+
21
+ if [ -z "$out" ]; then
22
+ echo "No dependencies found in Cargo.toml"
23
+ exit 0
24
+ fi
25
+
26
+ echo "$out"
27
+
28
+ dev_out=$(awk '
29
+ /^\[dev-dependencies\]/ { in_dev=1; next }
30
+ /^\[/ { in_dev=0 }
31
+ in_dev && /^[a-zA-Z_-]/ {
32
+ gsub(/=.*/, "")
33
+ gsub(/[^a-zA-Z0-9_-]/, "")
34
+ if (length($0) > 0) print $0
35
+ }
36
+ ' Cargo.toml 2>/dev/null | head -10)
37
+
38
+ if [ -n "$dev_out" ]; then
39
+ echo ""
40
+ echo "Dev dependencies:"
41
+ echo "$dev_out"
42
+ fi
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Cargo feature flags — parse [features] from Cargo.toml
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+
6
+ if [ ! -f Cargo.toml ]; then
7
+ echo "No Cargo.toml found"
8
+ exit 0
9
+ fi
10
+
11
+ out=$(awk '
12
+ /^\[features\]/ { in_features=1; next }
13
+ /^\[/ { in_features=0 }
14
+ in_features && /=/ {
15
+ gsub(/ = .*/, "")
16
+ gsub(/[^a-zA-Z0-9_-]/, "")
17
+ if (length($0) > 0) print $0
18
+ }
19
+ ' Cargo.toml 2>/dev/null)
20
+
21
+ if [ -z "$out" ]; then
22
+ echo "No features defined in Cargo.toml"
23
+ exit 0
24
+ fi
25
+
26
+ limit_output "$out" "$MAX_CARGO_FEATURES" "$(echo "$out" | head -5 && echo '... more features')"
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Find TODO, FIXME, HACK in Rust source files
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ out=$(grep -rn --include="*.rs" 'TODO\|FIXME\|HACK\|XXX\|UNSAFE' . 2>/dev/null | grep -v '/.git/' | grep -v '/.pipemd/' | grep -v '/target/')
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
+ # Rust project tree — progressive depth fallback
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ limit_tree "$MAX_TREE"
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Rust lint — cargo clippy
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+
6
+ if ! command -v cargo &>/dev/null; then
7
+ echo "cargo not found"
8
+ exit 0
9
+ fi
10
+
11
+ out=$(cargo clippy --message-format=short 2>&1 | grep -E '^(error|warning)\[' | head -30)
12
+ if [ -z "$out" ]; then
13
+ echo "No clippy warnings"
14
+ exit 0
15
+ fi
16
+ limit_output "$out" "$MAX_LINT" "$(echo "$out" | head -3 && echo '... more clippy warnings')"
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Rust test summary — cargo test
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+
6
+ if ! command -v cargo &>/dev/null; then
7
+ echo "cargo not found"
8
+ exit 0
9
+ fi
10
+
11
+ out=$(cargo test 2>&1 | tail -5)
12
+ if [ -z "$out" ]; then
13
+ echo "No test results"
14
+ exit 0
15
+ fi
16
+ echo "$out"
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Rust type check — cargo check
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+
6
+ if ! command -v cargo &>/dev/null; then
7
+ echo "cargo not found"
8
+ exit 0
9
+ fi
10
+
11
+ out=$(cargo check 2>&1 | grep -E '^error' | head -20)
12
+ if [ -z "$out" ]; then
13
+ echo "No type errors"
14
+ exit 0
15
+ fi
16
+ limit_output "$out" "$MAX_TYPECHECK" "$(echo "$out" | head -5 && echo '... more type errors')"
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Express route metadata — method + path signatures
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ out=$(grep -rn --include='*.js' --include='*.ts' --include='*.mjs' \
6
+ -E '(app|router)\.(get|post|put|delete|patch|all)\(' \
7
+ . 2>/dev/null | grep -v 'node_modules' \
8
+ | sed -E 's/.*\.(get|post|put|delete|patch|all)\([[:space:]]*['\''"](\/[^'\''"]*)['\''"].*/\U\1 \2/' \
9
+ | head -"$MAX_EXPRESS")
10
+ [ -z "$out" ] && echo "No Express routes found" && exit 0
11
+ echo "$out"
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # FastAPI route metadata — endpoint signatures
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ out=$(grep -rn --include='*.py' '@\(app\|router\)\.\(get\|post\|put\|delete\|patch\)' . 2>/dev/null \
6
+ | grep -v '/__pycache__/' | grep -v '/.venv/' | grep -v '/venv/' \
7
+ | sed -E 's/.*@\w+\.(get|post|put|delete|patch)\([[:space:]]*['\''"](\/[^'\''"]*)['\''"].*/\U\1 \2/' \
8
+ | head -"$MAX_FASTAPI")
9
+ [ -z "$out" ] && echo "No FastAPI routes detected" && exit 0
10
+ echo "$out"
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # NestJS controller metadata — auto-detect if NestJS is present
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ if [ ! -d src ]; then
6
+ echo "No NestJS controllers detected"
7
+ exit 0
8
+ fi
9
+ files=$(grep -rl --include='*.ts' '@Controller\|@Get\|@Post\|@Put\|@Delete\|@Patch' src/ 2>/dev/null | grep -v '/node_modules/' | head -10)
10
+ [ -z "$files" ] && echo "No NestJS controllers found" && exit 0
11
+
12
+ echo "$files" | while IFS= read -r f; do
13
+ [ -z "$f" ] && continue
14
+ controller=$(grep -E '@Controller\s*\(\s*['\''"](\/[^'\''"]*)' "$f" 2>/dev/null | sed -E "s/@Controller\s*\(\s*['\"]//;s/['\"].*//")
15
+ methods=$(grep -E '@(Get|Post|Put|Delete|Patch)\s*\(\s*['\''"](\/[^'\''"]*)' "$f" 2>/dev/null | sed -E "s/@(Get|Post|Put|Delete|Patch)\s*\(\s*['\"]//;s/['\"].*//")
16
+ if [ -n "$controller" ]; then
17
+ echo "Controller: $controller"
18
+ echo "$methods" | while IFS= read -r m; do
19
+ [ -n "$m" ] && echo " $m"
20
+ done
21
+ fi
22
+ done | head -"$MAX_NEST"
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Architecture normalizer — TSV edge-list → Mermaid graph TD
4
+ # Input: TSV on stdin (source<TAB>target, ext: prefix marks external deps)
5
+ # Output: Mermaid graph TD with subgraphs, ranked external deps, line budget
6
+ # Env: MAX_ARCH (default 100), MAX_EXT (default 8)
7
+
8
+ : "${MAX_ARCH:=100}"
9
+ : "${MAX_EXT:=8}"
10
+
11
+ awk -v max_arch="$MAX_ARCH" -v max_ext="$MAX_EXT" '
12
+ function safe_id(s) {
13
+ gsub(/[^a-zA-Z0-9]/, "_", s)
14
+ return s
15
+ }
16
+
17
+ function clean_label(s) {
18
+ gsub(/^src\//, "", s)
19
+ gsub(/^lib\//, "", s)
20
+ gsub(/^app\//, "", s)
21
+ gsub(/^cmd\//, "", s)
22
+ gsub(/^internal\//, "", s)
23
+ gsub(/^pkg\//, "", s)
24
+ gsub(/^\(root\)$/, "main", s)
25
+ return s
26
+ }
27
+
28
+ function group_of(s, n, parts) {
29
+ n = split(s, parts, "/")
30
+ return (n > 1) ? parts[1] : ""
31
+ }
32
+
33
+ BEGIN {
34
+ FS = "\t"
35
+ ne = 0; ni = 0; nx = 0; ng = 0
36
+ }
37
+
38
+ {
39
+ s = $1; d = $2
40
+ gsub(/^[[:space:]]+|[[:space:]]+$/, s)
41
+ gsub(/^[[:space:]]+|[[:space:]]+$/, d)
42
+ if (s == "" || d == "" || s == d) next
43
+
44
+ key = s SUBSEP d
45
+ if (key in seen) next
46
+ seen[key] = 1
47
+ ne++
48
+ esrc[ne] = s; edst[ne] = d
49
+
50
+ if (s ~ /^ext:/) {
51
+ n = substr(s, 5)
52
+ if (!(n in exti)) { nx++; exti[n] = nx; extn[nx] = n }
53
+ extdeg[n]++
54
+ } else {
55
+ if (!(s in inti)) { ni++; inti[s] = ni; intn[ni] = s }
56
+ g = group_of(s)
57
+ if (g != "" && !(g in grpi)) { ng++; grp_order[ng] = g; grpi[g] = 1 }
58
+ igrp[s] = g
59
+ }
60
+
61
+ if (d ~ /^ext:/) {
62
+ n = substr(d, 5)
63
+ if (!(n in exti)) { nx++; exti[n] = nx; extn[nx] = n }
64
+ extdeg[n]++
65
+ } else {
66
+ if (!(d in inti)) { ni++; inti[d] = ni; intn[ni] = d }
67
+ g = group_of(d)
68
+ if (g != "" && !(g in grpi)) { ng++; grp_order[ng] = g; grpi[g] = 1 }
69
+ igrp[d] = g
70
+ }
71
+ }
72
+
73
+ END {
74
+ if (ni == 0) {
75
+ print "No modules found"
76
+ exit 0
77
+ }
78
+
79
+ # Sort external deps by in-degree (descending)
80
+ for (i = 1; i <= nx; i++) {
81
+ for (j = i + 1; j <= nx; j++) {
82
+ if (extdeg[extn[j]] > extdeg[extn[i]]) {
83
+ tmp = extn[i]; extn[i] = extn[j]; extn[j] = tmp
84
+ }
85
+ }
86
+ }
87
+
88
+ # Determine how many external deps to show
89
+ n_show_ext = (nx > max_ext) ? max_ext : nx
90
+ for (i = 1; i <= n_show_ext; i++) show_ext[extn[i]] = 1
91
+
92
+ # Count edges that will be shown
93
+ shown_edges = 0
94
+ for (i = 1; i <= ne; i++) {
95
+ s = esrc[i]; d = edst[i]
96
+ if (s ~ /^ext:/) { n = substr(s, 5); if (!(n in show_ext)) continue }
97
+ if (d ~ /^ext:/) { n = substr(d, 5); if (!(n in show_ext)) continue }
98
+ shown_edges++
99
+ }
100
+
101
+ # Estimate total lines for budget check
102
+ est = 2 + ng * 2 + ni + (n_show_ext > 0 ? 2 + n_show_ext : 0) + shown_edges + 1
103
+
104
+ # Progressive simplification when over budget
105
+ skip_intra = 0
106
+ if (est > max_arch * 1.3) skip_intra = 1
107
+ reduce_ext = 0
108
+ if (est > max_arch * 1.6) { reduce_ext = 1; n_show_ext = (n_show_ext > 5) ? 5 : n_show_ext; for (i = 1; i <= n_show_ext; i++) show_ext[extn[i]] = 1 }
109
+
110
+ # Count group sizes
111
+ for (i = 1; i <= ni; i++) {
112
+ g = igrp[intn[i]]
113
+ if (g != "") grp_size[g]++
114
+ }
115
+
116
+ print "graph TD"
117
+
118
+ # Root-level nodes (no group or group with single member)
119
+ for (i = 1; i <= ni; i++) {
120
+ n = intn[i]
121
+ g = igrp[n]
122
+ if (g == "" || grp_size[g] <= 1) {
123
+ printf " %s[\"%s\"]\n", safe_id(n), clean_label(n)
124
+ }
125
+ }
126
+
127
+ # Grouped subgraphs
128
+ for (gi = 1; gi <= ng; gi++) {
129
+ g = grp_order[gi]
130
+ if (grp_size[g] <= 1) continue
131
+ printf " subgraph g_%s[\"%s\"]\n", safe_id(g), g
132
+ for (i = 1; i <= ni; i++) {
133
+ n = intn[i]
134
+ if (igrp[n] == g) {
135
+ printf " %s[\"%s\"]\n", safe_id(n), clean_label(n)
136
+ }
137
+ }
138
+ print " end"
139
+ }
140
+
141
+ # External subgraph
142
+ if (n_show_ext > 0) {
143
+ print " subgraph g_ext[\"external\"]"
144
+ for (i = 1; i <= n_show_ext; i++) {
145
+ n = extn[i]
146
+ printf " ext_%s[\"%s\"]\n", safe_id(n), n
147
+ }
148
+ print " end"
149
+ }
150
+
151
+ # Edges
152
+ edge_count = 0
153
+ for (i = 1; i <= ne; i++) {
154
+ s = esrc[i]; d = edst[i]
155
+
156
+ if (s ~ /^ext:/) { n = substr(s, 5); if (!(n in show_ext)) continue }
157
+ if (d ~ /^ext:/) { n = substr(d, 5); if (!(n in show_ext)) continue }
158
+
159
+ # Skip same-group internal edges if over budget
160
+ if (skip_intra && !(s ~ /^ext:/) && !(d ~ /^ext:/) && igrp[s] != "" && igrp[s] == igrp[d]) continue
161
+
162
+ sid = (s ~ /^ext:/) ? "ext_" safe_id(substr(s, 5)) : safe_id(s)
163
+ did = (d ~ /^ext:/) ? "ext_" safe_id(substr(d, 5)) : safe_id(d)
164
+
165
+ printf " %s --> %s\n", sid, did
166
+ edge_count++
167
+
168
+ if (edge_count >= max_arch) break
169
+ }
170
+
171
+ # Summary comment
172
+ hidden = (nx > n_show_ext) ? nx - n_show_ext : 0
173
+ printf " %% %d modules", ni
174
+ if (n_show_ext > 0) printf ", %d deps", n_show_ext
175
+ if (hidden > 0) printf " (%d hidden)", hidden
176
+ printf ", %d edges\n", edge_count
177
+ }
178
+ '
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # crew.sh — PipeMD Crew coordination block.
4
+ #
5
+ # Thin delegator: the heavy logic (session ledger, process scan, conflict
6
+ # detection) lives in the `pmd` binary so it stays unit-testable. This script
7
+ # only applies the token budget and calls `pmd crew render`.
8
+
9
+ source "$(dirname "$0")/../lib/limit.sh" 2>/dev/null || MAX_CREW="${PMD_MAX_CREW:-40}"
10
+
11
+ if command -v pmd >/dev/null 2>&1; then
12
+ PMD_MAX_CREW="${MAX_CREW:-40}" pmd crew render 2>/dev/null || echo "_(crew block unavailable)_"
13
+ else
14
+ echo "_(pmd not on PATH — crew coordination block unavailable)_"
15
+ fi
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Django model metadata — model names and field summaries
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ files=$(find . -name 'models.py' -not -path '*/venv/*' -not -path '*/.venv/*' -not -path '*/node_modules/*' 2>/dev/null | head -5)
6
+ [ -z "$files" ] && echo "No Django models found" && exit 0
7
+ echo "$files" | while IFS= read -r f; do
8
+ [ -z "$f" ] && continue
9
+ echo "=== $f ==="
10
+ awk '/^class [A-Z]/{gsub(/\(.*/,"",$0); print "Model: "$2; next} /^[[:space:]]+[a-z_]+ = models\./{gsub(/ = .*/,"",$1); print " "$1; next}' "$f" | head -"$MAX_DJANGO"
11
+ done | head -30
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Prisma model metadata — model names, field counts, enums
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ SCHEMA=""
6
+ for f in prisma/schema.prisma src/prisma/schema.prisma; do
7
+ [ -f "$f" ] && SCHEMA="$f" && break
8
+ done
9
+ [ -z "$SCHEMA" ] && echo "No prisma schema found" && exit 0
10
+
11
+ out=""
12
+ in_model=0; model=""; fields=0
13
+ while IFS= read -r line; do
14
+ if [[ "$line" =~ ^model[[:space:]]+([A-Za-z_][A-Za-z0-9_]*) ]]; then
15
+ in_model=1; model="${BASH_REMATCH[1]}"; fields=0
16
+ elif [[ "$line" =~ ^enum[[:space:]]+([A-Za-z_][A-Za-z0-9_]*) ]]; then
17
+ in_model=0; enum_name="${BASH_REMATCH[1]}"; enum_vals=""
18
+ elif (( in_model )); then
19
+ if [[ "$line" =~ ^[[:space:]]+@@ ]]; then
20
+ continue
21
+ elif [[ "$line" =~ ^[[:space:]]+[a-zA-Z] ]]; then
22
+ (( fields++ ))
23
+ elif [[ "$line" =~ ^\} ]]; then
24
+ out+="${model} (${fields} fields)\n"
25
+ in_model=0
26
+ fi
27
+ fi
28
+ done < "$SCHEMA"
29
+
30
+ # Extract enums separately
31
+ awk '/^enum[[:space:]]/{e=$2;v="";next} /^[[:space:]]+[A-Z]/{v=v?v","$1:$1} /^\}/{if(e)print "enum "e" = ["v"]";e=""}' "$SCHEMA"
32
+
33
+ printf '%b' "$out" | head -"$MAX_PRISMA"
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # SQLAlchemy model metadata — model signatures and tables
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ files=$(find . -name '*.py' -not -path '*/venv/*' -not -path '*/.venv/*' -not -path '*/node_modules/*' -not -path '*/__pycache__/*' 2>/dev/null | head -20)
6
+ [ -z "$files" ] && echo "No SQLAlchemy models detected" && exit 0
7
+ out=$(echo "$files" | while IFS= read -r f; do
8
+ [ -z "$f" ] && continue
9
+ grep -n 'class.*Model\|__tablename__\|Column(' "$f" 2>/dev/null | head -5
10
+ done)
11
+ [ -z "$out" ] && echo "No SQLAlchemy models detected" && exit 0
12
+ echo "$out" | head -"$MAX_SQLALCHEMY"
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Angular route metadata — route definitions from routing modules
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ files=$(find src -name '*-routing.module.ts' -o -name '*-routing.module.js' 2>/dev/null | grep -v '/node_modules/')
6
+ [ -z "$files" ] && echo "No Angular routing modules found" && exit 0
7
+ echo "$files" | while IFS= read -r f; do
8
+ [ -z "$f" ] && continue
9
+ echo "=== $f ==="
10
+ grep -E 'path:\s*['\''"]' "$f" 2>/dev/null | sed -E "s/.*path:\s*['\"]([^'\"]+)['\"].*/\1/" | head -10
11
+ done | head -"$MAX_ANGULAR"
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Next.js App Router route tree — page.tsx files
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ if [ ! -d app ]; then
6
+ echo "No Next.js app/ directory found"
7
+ exit 0
8
+ fi
9
+ out=$(find app -name 'page.tsx' -o -name 'page.ts' -o -name 'page.jsx' -o -name 'page.js' 2>/dev/null \
10
+ | sed 's|^app||;s|/page\.\(tsx\|ts\|jsx\|js\)$||;s|^$|/|' \
11
+ | sort)
12
+ [ -z "$out" ] && echo "No Next.js pages found" && exit 0
13
+ echo "$out" | head -"$MAX_NEXTJS"
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # React component metadata — exported function components and Props types
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ out=$(grep -rn --include='*.tsx' --include='*.jsx' \
6
+ -E '^export (default )?function [A-Z][A-Za-z]*|^export const [A-Z][A-Za-z]* =|^const [A-Z][A-Za-z]*: React\.FC' \
7
+ . 2>/dev/null | grep -v 'node_modules' \
8
+ | sed -E 's/:[0-9]+:.*export (default )?(function |const )([A-Z][A-Za-z]*).*/\3/' \
9
+ | sort -u | head -"$MAX_REACT")
10
+ [ -z "$out" ] && echo "No React components detected" && exit 0
11
+ echo "$out"
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Git diff stat — truncated with count if large
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ out=$(git diff --stat 2>/dev/null)
6
+ limit_output "$out" "$MAX_DIFF" "$(echo "$out" | head -10 && echo "... $(($(echo "$out" | wc -l) - 10)) more files")"
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Current branch and tracking info
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ branch=$(git branch --show-current 2>/dev/null)
6
+ tracking=$(git rev-list --left-right --count HEAD...@'{u}' 2>/dev/null | awk '{print "ahead " $1 ", behind " $2}')
7
+ if [ -n "$branch" ]; then
8
+ echo "$branch"
9
+ if [ -n "$tracking" ]; then
10
+ echo "$tracking"
11
+ else
12
+ echo "no upstream"
13
+ fi
14
+ else
15
+ echo "not a git repository"
16
+ fi
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Git log — last 10 commits
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ out=$(git log --oneline --date=short --format="%h %ad %s" -10 2>/dev/null | cut -c1-256)
6
+ limit_output "$out" "$MAX_LOG" "$(echo "$out" | head -3 && echo '... more commits')"
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ # Git status — summary counts if too many files
4
+ source "$(dirname "$0")/../lib/limit.sh"
5
+ out=$(git status --short --branch 2>/dev/null)
6
+ limit_output "$out" "$MAX_STATUS" "$(echo "$out" | head -5; echo "... and $(($(echo "$out" | wc -l) - 5)) more changes")"