@mmerterden/multi-agent-pipeline 13.1.0 → 13.2.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/CHANGELOG.md +52 -0
- package/package.json +1 -1
- package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +257 -0
- package/pipeline/commands/multi-agent/sync/SKILL.md +4 -4
- package/pipeline/multi-agent-refs/cross-cli-contract.md +3 -3
- package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +258 -0
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +4 -4
- package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +78 -0
- package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +445 -0
- package/pipeline/skills/shared/external/ios-coding-standard/references/lint-local.sh +160 -0
- package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +1163 -0
- package/pipeline/skills/shared/external/ios-coding-standard/references/swiftlint.draft.yml +371 -0
- package/pipeline/skills/shared/external/ios-simulator/SKILL.md +1 -1
- package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +1 -1
- package/pipeline/skills/shared/external/swiftlint/SKILL.md +1 -1
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Local-only lint runner for the iOS coding standard.
|
|
3
|
+
#
|
|
4
|
+
# Nothing is written inside the repository. The config, the resolved config, the baseline and
|
|
5
|
+
# every report live under $WORK_ROOT, outside any git working tree. Adding SwiftLint to the
|
|
6
|
+
# project (a committed .swiftlint.yml, a build phase, a CI job) is a separate decision and this
|
|
7
|
+
# script deliberately does not take it.
|
|
8
|
+
#
|
|
9
|
+
# ./lint-local.sh <module-path> [--write-baseline] [--strict] [--report json|xcode|emoji]
|
|
10
|
+
#
|
|
11
|
+
# First run for a module:
|
|
12
|
+
# ./lint-local.sh Domains/<Module> --write-baseline # grandfather what exists today
|
|
13
|
+
# Then:
|
|
14
|
+
# ./lint-local.sh Domains/<Module> --strict # only new violations surface
|
|
15
|
+
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
|
|
18
|
+
SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
19
|
+
WORK_ROOT="${IOS_STANDARD_WORK_ROOT:-$HOME/.claude/local/ios-coding-standard}"
|
|
20
|
+
DRAFT_CONFIG="$SKILL_DIR/swiftlint.draft.yml"
|
|
21
|
+
|
|
22
|
+
MODULE_PATH="${1:-}"
|
|
23
|
+
shift || true
|
|
24
|
+
|
|
25
|
+
STRICT=""
|
|
26
|
+
WRITE_BASELINE=""
|
|
27
|
+
REPORTER="xcode"
|
|
28
|
+
while [ $# -gt 0 ]; do
|
|
29
|
+
case "$1" in
|
|
30
|
+
--strict) STRICT="--strict" ;;
|
|
31
|
+
--write-baseline) WRITE_BASELINE="1" ;;
|
|
32
|
+
--report) shift; REPORTER="${1:-xcode}" ;;
|
|
33
|
+
*) echo "unknown option: $1" >&2; exit 2 ;;
|
|
34
|
+
esac
|
|
35
|
+
shift
|
|
36
|
+
done
|
|
37
|
+
|
|
38
|
+
if [ -z "$MODULE_PATH" ] || [ ! -d "$MODULE_PATH" ]; then
|
|
39
|
+
echo "usage: $(basename "$0") <module-path> [--write-baseline] [--strict] [--report <kind>]" >&2
|
|
40
|
+
exit 2
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
if ! command -v swiftlint >/dev/null 2>&1; then
|
|
44
|
+
cat >&2 <<'EOF'
|
|
45
|
+
swiftlint is not installed.
|
|
46
|
+
|
|
47
|
+
Install it for your user only — this does not touch the project:
|
|
48
|
+
|
|
49
|
+
brew install swiftlint
|
|
50
|
+
|
|
51
|
+
If Homebrew is unavailable, a pinned local copy also works:
|
|
52
|
+
|
|
53
|
+
mkdir -p ~/.local/bin && cd ~/.local/bin
|
|
54
|
+
curl -sL https://github.com/realm/SwiftLint/releases/latest/download/portable_swiftlint.zip -o sl.zip
|
|
55
|
+
unzip -o sl.zip && rm sl.zip && chmod +x swiftlint
|
|
56
|
+
# then add ~/.local/bin to PATH
|
|
57
|
+
|
|
58
|
+
EOF
|
|
59
|
+
exit 127
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
REPO_ROOT="$(cd "$MODULE_PATH" && git rev-parse --show-toplevel)"
|
|
63
|
+
MODULE_ABS="$(cd "$MODULE_PATH" && pwd)"
|
|
64
|
+
MODULE_NAME="$(basename "$MODULE_ABS")"
|
|
65
|
+
MODULE_WORK="$WORK_ROOT/$MODULE_NAME"
|
|
66
|
+
mkdir -p "$MODULE_WORK"
|
|
67
|
+
|
|
68
|
+
case "$MODULE_WORK" in
|
|
69
|
+
"$REPO_ROOT"/*) echo "refusing to write inside the repository: $MODULE_WORK" >&2; exit 1 ;;
|
|
70
|
+
esac
|
|
71
|
+
|
|
72
|
+
# ── Placeholder resolution ────────────────────────────────────────────────
|
|
73
|
+
# Per-module inventory, produced by the audit's Phase 2d. Optional: without it the
|
|
74
|
+
# sensitive-data rules fall back to a conservative generic pattern.
|
|
75
|
+
INVENTORY="$MODULE_WORK/inventory.env"
|
|
76
|
+
if [ -f "$INVENTORY" ]; then
|
|
77
|
+
# shellcheck disable=SC1090
|
|
78
|
+
. "$INVENTORY"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# SENSITIVE / TRANSIENT: alternations of the module's own symbol names.
|
|
82
|
+
: "${SENSITIVE:=token|password|passcode|secret|credential|passport|nationalId|identityNumber|pnr|reservationCode|ticketNumber|membershipNumber|cardNumber|cvv|dateOfBirth}"
|
|
83
|
+
: "${TRANSIENT:=oneTimeCode|otp|verificationCode|draft}"
|
|
84
|
+
|
|
85
|
+
# SIBLINGS: every other module that lives beside this one — the MOD-01 import guard.
|
|
86
|
+
if [ -z "${SIBLINGS:-}" ]; then
|
|
87
|
+
PARENT="$(dirname "$MODULE_ABS")"
|
|
88
|
+
SIBLINGS="$(find "$PARENT" -mindepth 1 -maxdepth 1 -type d ! -name "$MODULE_NAME" -exec basename {} \; \
|
|
89
|
+
| sort | paste -sd'|' -)"
|
|
90
|
+
fi
|
|
91
|
+
[ -n "$SIBLINGS" ] || SIBLINGS="__none__"
|
|
92
|
+
|
|
93
|
+
# LOGIC: the paths where TEST-01/03/05 and CONC-04 apply.
|
|
94
|
+
# Logic paths only. A Scene is NOT logic: `Task { await viewModel.action() }` in a button
|
|
95
|
+
# closure is the idiomatic sync->async bridge, and flagging it buries the real finding.
|
|
96
|
+
: "${LOGIC:=.*(ViewModel|UseCase|Repository|Mapper)[^/]*\\.swift}"
|
|
97
|
+
|
|
98
|
+
RESOLVED="$MODULE_WORK/swiftlint.resolved.yml"
|
|
99
|
+
# Substituted with python rather than sed: every replacement is a regex alternation full of
|
|
100
|
+
# delimiter characters, and sed has no delimiter that is safe against all of them.
|
|
101
|
+
SENSITIVE="$SENSITIVE" TRANSIENT="$TRANSIENT" SIBLINGS="$SIBLINGS" LOGIC="$LOGIC" \
|
|
102
|
+
python3 -c '
|
|
103
|
+
import os, sys
|
|
104
|
+
src, dst = sys.argv[1], sys.argv[2]
|
|
105
|
+
text = open(src).read()
|
|
106
|
+
for key in ("SENSITIVE", "TRANSIENT", "SIBLINGS"):
|
|
107
|
+
# Wrapped in a non-capturing group: these values are alternations, and "|" binds looser than
|
|
108
|
+
# concatenation. Substituting them bare turns "prefix\bA|B|C" into "(prefix\bA) or (B) or (C)",
|
|
109
|
+
# which matches every line containing any bare term — the whole pattern silently collapses.
|
|
110
|
+
text = text.replace("((%s))" % key, "(?:%s)" % os.environ[key])
|
|
111
|
+
text = text.replace("((LOGIC))", os.environ["LOGIC"])
|
|
112
|
+
open(dst, "w").write(text)
|
|
113
|
+
' "$DRAFT_CONFIG" "$RESOLVED"
|
|
114
|
+
|
|
115
|
+
BASELINE="$MODULE_WORK/baseline.json"
|
|
116
|
+
|
|
117
|
+
echo "module : $MODULE_ABS"
|
|
118
|
+
echo "config : $RESOLVED"
|
|
119
|
+
echo "workdir : $MODULE_WORK (outside the repo)"
|
|
120
|
+
echo "siblings : $SIBLINGS"
|
|
121
|
+
[ -f "$INVENTORY" ] && echo "inventory : $INVENTORY" || echo "inventory : (none — using the generic fallback pattern)"
|
|
122
|
+
echo
|
|
123
|
+
|
|
124
|
+
cd "$MODULE_ABS"
|
|
125
|
+
|
|
126
|
+
if [ -n "$WRITE_BASELINE" ]; then
|
|
127
|
+
echo "writing baseline -> $BASELINE"
|
|
128
|
+
BL_PATHS=()
|
|
129
|
+
for d in Sources Tests; do [ -d "$d" ] && BL_PATHS+=("$d"); done
|
|
130
|
+
[ ${#BL_PATHS[@]} -gt 0 ] || BL_PATHS=(.)
|
|
131
|
+
swiftlint lint --config "$RESOLVED" --write-baseline "$BASELINE" --quiet "${BL_PATHS[@]}" || true
|
|
132
|
+
echo
|
|
133
|
+
echo "baseline written. from now on run without --write-baseline; only new violations surface."
|
|
134
|
+
exit 0
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
LINT_PATHS=()
|
|
138
|
+
for d in Sources Tests; do [ -d "$d" ] && LINT_PATHS+=("$d"); done
|
|
139
|
+
[ ${#LINT_PATHS[@]} -gt 0 ] || LINT_PATHS=(.)
|
|
140
|
+
|
|
141
|
+
ARGS=(lint --config "$RESOLVED" --reporter "$REPORTER" --quiet)
|
|
142
|
+
[ -f "$BASELINE" ] && ARGS+=(--baseline "$BASELINE")
|
|
143
|
+
[ -n "$STRICT" ] && ARGS+=("$STRICT")
|
|
144
|
+
|
|
145
|
+
set +e
|
|
146
|
+
# stdout is the report, stderr is progress + config diagnostics — never merge them, or a
|
|
147
|
+
# machine-readable reporter comes back with progress lines spliced into it.
|
|
148
|
+
swiftlint "${ARGS[@]}" "${LINT_PATHS[@]}" 2>"$MODULE_WORK/last-run.err" | tee "$MODULE_WORK/last-run.txt"
|
|
149
|
+
STATUS=${PIPESTATUS[0]}
|
|
150
|
+
if [ -s "$MODULE_WORK/last-run.err" ]; then
|
|
151
|
+
echo
|
|
152
|
+
echo "swiftlint diagnostics -> $MODULE_WORK/last-run.err"
|
|
153
|
+
grep -E '^(warning|error):' "$MODULE_WORK/last-run.err" | sort -u | head
|
|
154
|
+
fi
|
|
155
|
+
set -e
|
|
156
|
+
|
|
157
|
+
echo
|
|
158
|
+
echo "report: $MODULE_WORK/last-run.txt"
|
|
159
|
+
[ -f "$BASELINE" ] && echo "baseline in effect: $BASELINE (delete it to see every existing violation)"
|
|
160
|
+
exit $STATUS
|