@techierathore/techieflow 1.0.4 → 1.1.1
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/.claude/commands/TechieFlow/agents/flow-master.md +2 -0
- package/.claude/commands/TechieFlow/agents/verifier.md +2 -2
- package/.claude/commands/TechieFlow/tasks/_develop-mode.md +34 -0
- package/.claude/commands/TechieFlow/tasks/_owner-language.md +1 -0
- package/.claude/commands/TechieFlow/tasks/_status-update-gate.md +4 -3
- package/.claude/commands/TechieFlow/tasks/_yolo-mode.md +2 -2
- package/.claude/commands/TechieFlow/tasks/amend-docs.md +2 -2
- package/.claude/commands/TechieFlow/tasks/day1-brownfield.md +3 -3
- package/.claude/commands/TechieFlow/tasks/day1-greenfield.md +5 -5
- package/.claude/commands/TechieFlow/tasks/develop-end-to-end.md +30 -0
- package/.claude/commands/TechieFlow/tasks/fix-issues.md +3 -2
- package/.claude/commands/TechieFlow/tasks/generate-html.md +2 -2
- package/.claude/commands/TechieFlow/tasks/handoff-phase.md +2 -2
- package/.claude/commands/TechieFlow/tasks/mockups.md +2 -2
- package/.claude/commands/TechieFlow/tasks/productguide.md +2 -2
- package/.claude/commands/TechieFlow/tasks/render-workflow-docs.md +1 -1
- package/.claude/commands/TechieFlow/tasks/triage-and-fix.md +2 -2
- package/.claude/commands/TechieFlow/tasks/triage-issues.md +2 -2
- package/.claude/commands/TechieFlow/tasks/verify-phase.md +12 -11
- package/.opencode/plugin/techieflow.js +194 -14
- package/.tfcore/agents/flow-master.md +2 -0
- package/.tfcore/agents/verifier.md +2 -2
- package/.tfcore/core-config.yaml +2 -1
- package/.tfcore/hooks/block-git.sh +4 -2
- package/.tfcore/hooks/guard-build.sh +5 -1
- package/.tfcore/hooks/guard-db.sh +112 -13
- package/.tfcore/hooks/guard-status-html.sh +86 -2
- package/.tfcore/hooks/guard-verify-deps.sh +16 -1
- package/.tfcore/hooks/guard-verify.sh +8 -3
- package/.tfcore/hooks/sweep-artifacts.sh +46 -0
- package/.tfcore/hooks/yolo-allow.sh +27 -0
- package/.tfcore/standards/blazor-zoom.cs.txt +191 -0
- package/.tfcore/standards/coding-standards-dotnet.md +31 -3
- package/.tfcore/standards/owner-words.txt +23 -0
- package/.tfcore/tasks/_develop-mode.md +34 -0
- package/.tfcore/tasks/_owner-language.md +1 -0
- package/.tfcore/tasks/_status-update-gate.md +4 -3
- package/.tfcore/tasks/_yolo-mode.md +2 -2
- package/.tfcore/tasks/amend-docs.md +2 -2
- package/.tfcore/tasks/day1-brownfield.md +3 -3
- package/.tfcore/tasks/day1-greenfield.md +5 -5
- package/.tfcore/tasks/develop-end-to-end.md +30 -0
- package/.tfcore/tasks/fix-issues.md +3 -2
- package/.tfcore/tasks/generate-html.md +2 -2
- package/.tfcore/tasks/handoff-phase.md +2 -2
- package/.tfcore/tasks/mockups.md +2 -2
- package/.tfcore/tasks/productguide.md +2 -2
- package/.tfcore/tasks/render-workflow-docs.md +1 -1
- package/.tfcore/tasks/triage-and-fix.md +2 -2
- package/.tfcore/tasks/triage-issues.md +2 -2
- package/.tfcore/tasks/verify-phase.md +12 -11
- package/.tfcore/telemetry/SCHEMA.md +10 -2
- package/.tfcore/telemetry/install-metrics.sh +3 -2
- package/.tfcore/telemetry/tf-metrics.sh +38 -2
- package/.tfcore/templates/stack-defaults/dotnet.md +3 -1
- package/.tfcore/templates/v4custom/app-agents-md-tmpl.md +6 -0
- package/.tfcore/templates/v4custom/app-architecture-tmpl.md +5 -0
- package/.tfcore/templates/v4custom/app-brd-tmpl.md +7 -4
- package/.tfcore/templates/v4custom/app-checklist-tmpl.md +11 -0
- package/.tfcore/templates/v4custom/app-phase-brd-tmpl.md +94 -0
- package/.tfcore/templates/v4custom/app-phase-uidesign-tmpl.md +60 -0
- package/.tfcore/templates/v4custom/app-phases-tmpl.md +2 -1
- package/.tfcore/templates/v4custom/app-uidesign-tmpl.md +4 -2
- package/.tfcore/templates/v4custom/build-subagent-prompt.md +2 -2
- package/.tfcore/templates/v4custom/html-render-shell.md +6 -2
- package/.tfcore/utils/__pycache__/tf-devguide-list.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-doc-check.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-split-brd.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-status-facts.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-verify-list.cpython-312.pyc +0 -0
- package/.tfcore/utils/tf-appium.mjs +179 -0
- package/.tfcore/utils/tf-assets-browser.mjs +96 -0
- package/.tfcore/utils/tf-assets.sh +97 -12
- package/.tfcore/utils/tf-brd-status.py +14 -5
- package/.tfcore/utils/tf-build-list.py +95 -12
- package/.tfcore/utils/tf-build-list.sh +2 -1
- package/.tfcore/utils/tf-build.sh +163 -15
- package/.tfcore/utils/tf-checklist-edit.py +21 -3
- package/.tfcore/utils/tf-ci-repro.py +685 -0
- package/.tfcore/utils/tf-ci-repro.sh +24 -0
- package/.tfcore/utils/tf-day1-files.py +55 -28
- package/.tfcore/utils/tf-develop.sh +264 -0
- package/.tfcore/utils/tf-devguide-list.py +53 -24
- package/.tfcore/utils/tf-doc-check.py +218 -26
- package/.tfcore/utils/tf-doc-tests.sh +116 -0
- package/.tfcore/utils/tf-emit.sh +132 -45
- package/.tfcore/utils/tf-feedback.sh +13 -0
- package/.tfcore/utils/tf-fix-close.sh +87 -31
- package/.tfcore/utils/tf-goal.sh +12 -12
- package/.tfcore/utils/tf-harness.sh +9 -4
- package/.tfcore/utils/tf-lock.sh +29 -0
- package/.tfcore/utils/tf-log-miss.py +34 -8
- package/.tfcore/utils/tf-login.mjs +167 -0
- package/.tfcore/utils/tf-maccatalyst-check.sh +92 -0
- package/.tfcore/utils/tf-menus.mjs +401 -0
- package/.tfcore/utils/tf-misses-md.py +10 -4
- package/.tfcore/utils/tf-mockup-parity.mjs +763 -71
- package/.tfcore/utils/tf-mockup-parity.sh +25 -2
- package/.tfcore/utils/tf-owner-text.py +233 -0
- package/.tfcore/utils/tf-owner-text.sh +14 -0
- package/.tfcore/utils/tf-phase.sh +38 -4
- package/.tfcore/utils/tf-portable.sh +230 -0
- package/.tfcore/utils/tf-render-html.py +79 -5
- package/.tfcore/utils/tf-req-ids.py +36 -0
- package/.tfcore/utils/tf-selfcheck.sh +39 -6
- package/.tfcore/utils/tf-split-brd.py +11 -1
- package/.tfcore/utils/tf-stack-check.sh +3 -0
- package/.tfcore/utils/tf-status-evidence.sh +11 -9
- package/.tfcore/utils/tf-status-facts.py +160 -45
- package/.tfcore/utils/tf-theme.mjs +189 -0
- package/.tfcore/utils/tf-triage.py +74 -17
- package/.tfcore/utils/tf-triage.sh +2 -0
- package/.tfcore/utils/tf-verify-boot.sh +529 -54
- package/.tfcore/utils/tf-verify-emit.sh +57 -17
- package/.tfcore/utils/tf-verify-env.sh +33 -4
- package/.tfcore/utils/tf-verify-list.py +290 -24
- package/.tfcore/utils/tf-verify-list.sh +3 -1
- package/.tfcore/utils/tf-verify-native.mjs +307 -0
- package/.tfcore/utils/tf-verify-screens.mjs +341 -44
- package/.tfcore/utils/tf-verify-screens.sh +23 -5
- package/.tfcore/utils/tf-verify-tests.sh +310 -19
- package/.tfcore/utils/tf-verify-verdict.py +163 -21
- package/.tfcore/utils/tf-verify-zoom.mjs +193 -0
- package/.tfcore/utils/tf-verify-zoom.sh +29 -0
- package/.tfcore/utils/tf-yolo-alias.sh +84 -0
- package/.tfcore/utils/tf-yolo-perms.py +135 -0
- package/.tfcore/utils/tf-yolo-start.sh +44 -0
- package/.tfcore/utils/tf-yolo.sh +31 -3
- package/.tfcore/utils/tf_defect.py +27 -0
- package/.tfcore/utils/tf_feedback.py +272 -0
- package/.tfcore/utils/tf_roadmap.py +35 -0
- package/.tfcore/utils/tf_stack_check.py +93 -0
- package/README.md +6 -2
- package/docs/TechieFlow-Installation.md +5 -3
- package/opencode.jsonc +6 -2
- package/package.json +1 -1
- package/scripts/install.mjs +13 -2
- package/.tfcore/utils/__pycache__/tf-brd-status.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-codex-bind.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-codex-telemetry.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-day1-files.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-log-miss.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-misses-md.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-mockups-locate.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-opencode-audit.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-render-html.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-triage.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-verify-verdict.cpython-312.pyc +0 -0
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
# bash .tfcore/utils/tf-build.sh [build] [<target>] [-- <extra dotnet args>]
|
|
7
7
|
# bash .tfcore/utils/tf-build.sh test [<target>] [-- <extra dotnet args>]
|
|
8
8
|
# bash .tfcore/utils/tf-build.sh run <project> [-- <extra dotnet args>]
|
|
9
|
+
# bash .tfcore/utils/tf-build.sh publish <project> -- -o <dir> [-c <config>] # tf-verify-boot.sh's
|
|
9
10
|
# bash .tfcore/utils/tf-build.sh probe # print the platform and the rungs, run nothing
|
|
11
|
+
# bash .tfcore/utils/tf-build.sh --print [build|test] # print the command this repository uses, run nothing
|
|
10
12
|
#
|
|
11
13
|
# <target> is a .sln, .slnx or .csproj relative to the current folder (default: the one
|
|
12
14
|
# solution or project found here). Output goes to tests/.artifacts/build/<UTC time>.log.
|
|
@@ -27,14 +29,28 @@
|
|
|
27
29
|
# A workload / SDK-missing error (NETSDK1178, Microsoft.iOS/Android/MacCatalyst.Sdk, Workload ID,
|
|
28
30
|
# WindowsAppSDK, command not found) means the wrong rung: the next one is tried, nothing is logged
|
|
29
31
|
# as a blocker. A CS#### error means the code is wrong: the rung stays and the script exits 1.
|
|
32
|
+
# A locked output file (MSB3021, MSB3027, "being used by another process") is neither: the same
|
|
33
|
+
# rung waits and tries again, then says NOT-RUN naming the lock; it never falls to the next rung
|
|
34
|
+
# (TF-035). On WSL a build that changes side -- a WSL rung, then a Windows one, over the same obj/,
|
|
35
|
+
# in this run or since the last -- first clears obj/**/scopedcss: a Blazor build names each scoped
|
|
36
|
+
# stylesheet by a hash of the path, the two sides hash differently, and the incremental target
|
|
37
|
+
# kept the old names, so every page's own styles stopped applying (TfLens, 2026-09-11).
|
|
38
|
+
# One build, test or publish at a time per repository: a second one waits for the first
|
|
39
|
+
# (tests/.artifacts/build/.lock names who holds it). Builders side by side each rebuilt the same
|
|
40
|
+
# obj/ under the others: a running app lost its stylesheet or its process, and a publish carried a
|
|
41
|
+
# dll older than its own source (TF-043). A lock whose process has gone is taken over.
|
|
30
42
|
set -u
|
|
43
|
+
# mapfile and the other bash-4 / GNU-only spellings go through the shim (a stock Mac has bash 3.2).
|
|
44
|
+
source "$(dirname "${BASH_SOURCE[0]}")/tf-portable.sh"
|
|
31
45
|
|
|
32
|
-
MODE="build"; TARGET=""; EXTRA=()
|
|
46
|
+
MODE="build"; TARGET=""; EXTRA=(); PRINT=0
|
|
47
|
+
[[ "${1:-}" == "--print" ]] && { PRINT=1; shift; } # print the resolved command, run nothing (TfLens TF-049)
|
|
33
48
|
case "${1:-}" in
|
|
34
|
-
build|test|run|probe) MODE="$1"; shift ;;
|
|
49
|
+
build|test|run|publish|probe) MODE="$1"; shift ;;
|
|
35
50
|
esac
|
|
36
51
|
while [[ $# -gt 0 ]]; do
|
|
37
52
|
if [[ "$1" == "--" ]]; then shift; EXTRA=("$@"); break; fi
|
|
53
|
+
if [[ "$1" == "--print" ]]; then PRINT=1; shift; continue; fi
|
|
38
54
|
TARGET="$1"; shift
|
|
39
55
|
done
|
|
40
56
|
|
|
@@ -48,10 +64,11 @@ elif [[ "$U" == Linux* ]]; then
|
|
|
48
64
|
fi
|
|
49
65
|
elif [[ "$U" == windows || "$U" == MINGW* || "$U" == MSYS* || "$U" == CYGWIN* ]]; then PLATFORM="windows"
|
|
50
66
|
fi
|
|
67
|
+
PLATFORM="${TF_BUILD_PLATFORM:-$PLATFORM}" # the self-tests only
|
|
51
68
|
|
|
52
69
|
# ---- target ---------------------------------------------------------------------------
|
|
53
70
|
if [[ -z "$TARGET" && "$MODE" != "probe" ]]; then
|
|
54
|
-
|
|
71
|
+
tf_read_lines CANDS < <(ls -1 *.slnx *.sln 2>/dev/null; ls -1 *.csproj 2>/dev/null)
|
|
55
72
|
if [[ ${#CANDS[@]} -eq 1 ]]; then TARGET="${CANDS[0]}"
|
|
56
73
|
elif [[ ${#CANDS[@]} -gt 1 ]]; then echo "NOT-RUN more than one solution or project here; name one: ${CANDS[*]}"; exit 2
|
|
57
74
|
fi
|
|
@@ -63,14 +80,14 @@ projects=()
|
|
|
63
80
|
if [[ -n "$TARGET" ]]; then
|
|
64
81
|
case "$TARGET" in
|
|
65
82
|
*.csproj) projects=("$TARGET") ;;
|
|
66
|
-
*.sln)
|
|
67
|
-
*.slnx)
|
|
83
|
+
*.sln) tf_read_lines projects < <(grep -oE '"[^"]+\.csproj"' "$TARGET" 2>/dev/null | tr -d '"' | tr '\\' '/') ;;
|
|
84
|
+
*.slnx) tf_read_lines projects < <(grep -oE 'Path="[^"]+\.csproj"' "$TARGET" 2>/dev/null | sed 's/Path="//; s/"$//' | tr '\\' '/') ;;
|
|
68
85
|
esac
|
|
69
86
|
base="$(dirname "$TARGET")"
|
|
70
|
-
for p in "${projects[@]}"; do
|
|
87
|
+
for p in ${projects[@]+"${projects[@]}"}; do # the +form: an empty array under set -u (bash 3.2)
|
|
71
88
|
f="$p"; [[ -f "$f" ]] || f="$base/$p"
|
|
72
89
|
[[ -f "$f" ]] || continue
|
|
73
|
-
if grep -qiE '<UseMaui
|
|
90
|
+
if grep -qiE '<UseMaui>[[:space:]]*true|Microsoft\.NET\.Sdk\.Maui|net[0-9.]+-(android|ios|maccatalyst|windows10)' "$f"; then maui=1; fi
|
|
74
91
|
done
|
|
75
92
|
fi
|
|
76
93
|
|
|
@@ -91,17 +108,121 @@ if [[ "$MODE" == "probe" ]]; then
|
|
|
91
108
|
fi
|
|
92
109
|
[[ -z "$TARGET" && "$MODE" != "run" ]] && { echo "NOT-RUN no .sln, .slnx or .csproj here; name the target"; exit 2; }
|
|
93
110
|
|
|
111
|
+
# ---- test on a solution: one test project at a time (TechieRag TF-004) ----------------------------
|
|
112
|
+
# `dotnet test <solution>` runs every test project at once. On a 7.8 GB WSL machine TechieRag's local-
|
|
113
|
+
# model tests took the memory while TechieRag.Tests walked folders, and a test that passes alone failed
|
|
114
|
+
# with "Cannot allocate memory", twice in one day. Each test project now runs on its own, through this
|
|
115
|
+
# same script, and the verdicts are merged into one line naming one joined log: FAIL if any failed
|
|
116
|
+
# (naming which), else NOT-RUN if any could not run, else PASS. TF_TEST_TOGETHER=1 runs them together.
|
|
117
|
+
if [[ "$MODE" == "test" && "${TF_TEST_TOGETHER:-0}" != "1" && "$TARGET" == *.sln* ]]; then
|
|
118
|
+
tests=()
|
|
119
|
+
for p in ${projects[@]+"${projects[@]}"}; do
|
|
120
|
+
f="$p"; [[ -f "$f" ]] || f="$base/$p"
|
|
121
|
+
[[ -f "$f" ]] || continue
|
|
122
|
+
grep -qiE 'Microsoft\.NET\.Test\.Sdk|<IsTestProject>[[:space:]]*true|"(xunit|xunit\.v3|NUnit|MSTest(\.TestFramework)?|TUnit)"|Include="(xunit|xunit\.v3|NUnit|MSTest|TUnit)' "$f" && tests+=("$f")
|
|
123
|
+
done
|
|
124
|
+
if [[ ${#tests[@]} -gt 1 ]]; then
|
|
125
|
+
if [[ $PRINT -eq 1 ]]; then
|
|
126
|
+
for t in "${tests[@]}"; do echo "dotnet test $t ${EXTRA[*]:-}"; done; exit 0
|
|
127
|
+
fi
|
|
128
|
+
mkdir -p tests/.artifacts/build
|
|
129
|
+
JOINED="tests/.artifacts/build/$(date -u +%Y%m%dT%H%M%SZ)-test-split-$$.log"; : > "$JOINED"
|
|
130
|
+
fails=(); notrun=(); passed=0; lines=(); pass=()
|
|
131
|
+
[[ ${#EXTRA[@]} -gt 0 ]] && pass=(-- "${EXTRA[@]}")
|
|
132
|
+
for t in "${tests[@]}"; do
|
|
133
|
+
out="$(TF_TEST_TOGETHER=1 bash "${BASH_SOURCE[0]}" test "$t" ${pass[@]+"${pass[@]}"} 2>&1)"
|
|
134
|
+
v="$(grep -m1 -E '^(PASS|FAIL|NOT-RUN)' <<<"$out")"
|
|
135
|
+
lg="$(sed -n 's/.*log \(tests\/\.artifacts\/build\/[^ ;]*\).*/\1/p' <<<"$v" | head -1)"
|
|
136
|
+
{ echo "### test project: $t"; [[ -n "$lg" && -f "$lg" ]] && cat "$lg" || echo "$out"; } >> "$JOINED"
|
|
137
|
+
lines+=(" $(basename "$t" .csproj): $v")
|
|
138
|
+
case "$v" in PASS*) passed=$((passed+1)) ;; FAIL*) fails+=("$(basename "$t" .csproj)") ;; *) notrun+=("$(basename "$t" .csproj)") ;; esac
|
|
139
|
+
done
|
|
140
|
+
if [[ ${#fails[@]} -gt 0 ]]; then
|
|
141
|
+
echo "FAIL tests failed in ${fails[*]} (${#tests[@]} test projects, each run on its own; $passed passed); log $JOINED"; rc=1
|
|
142
|
+
elif [[ ${#notrun[@]} -gt 0 ]]; then
|
|
143
|
+
echo "NOT-RUN ${notrun[*]} could not run (${#tests[@]} test projects, each run on its own; $passed passed); log $JOINED"; rc=2
|
|
144
|
+
else
|
|
145
|
+
echo "PASS test on $PLATFORM — ${#tests[@]} test projects, each run on its own, all passed; log $JOINED"; rc=0
|
|
146
|
+
fi
|
|
147
|
+
printf '%s\n' "${lines[@]}"
|
|
148
|
+
exit $rc
|
|
149
|
+
fi
|
|
150
|
+
fi
|
|
151
|
+
|
|
94
152
|
# ---- the dotnet verb -------------------------------------------------------------------
|
|
95
153
|
verb="$MODE"
|
|
96
154
|
args=("$verb")
|
|
97
155
|
[[ -n "$TARGET" ]] && args+=("$TARGET")
|
|
98
156
|
[[ "$MODE" == "run" ]] && args=("run" "--project" "$TARGET")
|
|
99
|
-
args+=("${EXTRA[@]}")
|
|
157
|
+
args+=(${EXTRA[@]+"${EXTRA[@]}"})
|
|
158
|
+
[[ $PRINT -eq 1 ]] && { echo "dotnet ${args[*]}"; exit 0; }
|
|
100
159
|
|
|
101
160
|
mkdir -p tests/.artifacts/build
|
|
102
|
-
LOG="tests/.artifacts/build/$(date -u +%Y%m%dT%H%M%SZ)-$MODE
|
|
161
|
+
LOG="tests/.artifacts/build/$(date -u +%Y%m%dT%H%M%SZ)-$MODE-$$.log" # two builds in one second never share a log
|
|
162
|
+
|
|
163
|
+
# ---- one build or browser check at a time (TF-043, TF-048): tf-lock.sh. `run` does not take it.
|
|
164
|
+
source "$(dirname "${BASH_SOURCE[0]}")/tf-lock.sh"
|
|
165
|
+
LOCK="$TF_LOCK"
|
|
166
|
+
[[ "$MODE" != "run" ]] && tf_take_lock "$MODE"
|
|
167
|
+
LOCKED='error MSB302[17]|being used by another process|Access to the path .* is denied'
|
|
168
|
+
# which side of a WSL machine a rung builds on, and the project folders whose obj/ it writes
|
|
169
|
+
side_of() { case "$1" in winrun|cmd.exe|powershell.exe) echo windows ;; *) echo wsl ;; esac; }
|
|
170
|
+
# the projects the target builds, and every project they reference: a web head's static assets come
|
|
171
|
+
# from the library it references, whose obj/ the other side may have written (AppManager TF-004)
|
|
172
|
+
tf_read_lines pdirs < <(python3 - "${base:-.}" ${projects[@]+"${projects[@]}"} <<'PY'
|
|
173
|
+
import os, re, sys
|
|
174
|
+
base, todo, seen = sys.argv[1], [], []
|
|
175
|
+
for p in sys.argv[2:]:
|
|
176
|
+
todo.append(p if os.path.isfile(p) else os.path.join(base, p))
|
|
177
|
+
while todo:
|
|
178
|
+
f = os.path.normpath(todo.pop())
|
|
179
|
+
if not os.path.isfile(f) or os.path.dirname(f) in seen:
|
|
180
|
+
continue
|
|
181
|
+
seen.append(os.path.dirname(f) or ".")
|
|
182
|
+
for ref in re.findall(r'<ProjectReference\s+Include="([^"]+)"', open(f, encoding="utf-8", errors="replace").read()):
|
|
183
|
+
todo.append(os.path.join(os.path.dirname(f), ref.replace("\\", "/")))
|
|
184
|
+
print("\n".join(seen))
|
|
185
|
+
PY
|
|
186
|
+
)
|
|
187
|
+
cross_side() { # side: clear what another side built with its own paths in it, then mark this side
|
|
188
|
+
local d cleared=0
|
|
189
|
+
for d in ${pdirs[@]+"${pdirs[@]}"}; do
|
|
190
|
+
[[ -d "$d/obj" ]] || continue
|
|
191
|
+
if [[ "$(cat "$d/obj/.tf-build-side" 2>/dev/null)" != "$1" ]]; then
|
|
192
|
+
# the scoped stylesheets (TF-035) and the static web asset lists: each side writes its own absolute
|
|
193
|
+
# paths into those, and a Windows-written one (461 C:\ paths in AppManagerUI's) stopped the WSL
|
|
194
|
+
# host at startup with "The path must be absolute (Parameter 'root')" (AppManager TF-004)
|
|
195
|
+
if [[ -n "$(find "$d/obj" -type d -name scopedcss -print -quit 2>/dev/null)" || -n "$(find "$d/obj" "$d/bin" -name '*staticwebassets*.json' -print -quit 2>/dev/null)" ]]; then
|
|
196
|
+
find "$d/obj" -type d -name scopedcss -prune -exec rm -rf {} + 2>/dev/null
|
|
197
|
+
find "$d/obj" "$d/bin" -name '*staticwebassets*.json' -delete 2>/dev/null; cleared=1
|
|
198
|
+
fi
|
|
199
|
+
fi
|
|
200
|
+
echo "$1" > "$d/obj/.tf-build-side"
|
|
201
|
+
done
|
|
202
|
+
[[ $cleared -eq 1 ]] && echo "note the scoped stylesheets and static asset lists were built on the other side of this machine; cleared so the $1 build writes them itself"
|
|
203
|
+
}
|
|
103
204
|
WRONG_RUNG='NETSDK1178|Microsoft\.(iOS|Android|MacCatalyst|tvOS)\.Sdk|Workload ID|not recognized|WindowsAppSDK|command not found|No such file or directory|is not recognized as an internal or external command|The term .* is not recognized|workload.*not installed|Inadequate permissions'
|
|
104
205
|
|
|
206
|
+
# A Mac Catalyst build after Platforms/MacCatalyst/Info.plist (or an .entitlements file) changed: the
|
|
207
|
+
# incremental build refreshed the DLLs and kept the .app's old Info.plist, so a fix that lives there
|
|
208
|
+
# looked as if it had failed (Lekhak TF-026: the scene manifest was in the source and not in the
|
|
209
|
+
# bundle). When such a file is newer than the bundle, that target's bin/ and obj/ are cleared first.
|
|
210
|
+
mac_tfm="$(printf '%s\n' ${EXTRA[@]+"${EXTRA[@]}"} | grep -oE '^net[0-9.]+-maccatalyst[0-9.]*$' | head -1)"
|
|
211
|
+
if [[ -n "$mac_tfm" && "$MODE" == build && "$TARGET" == *.csproj ]]; then
|
|
212
|
+
pd="$(dirname "$TARGET")"
|
|
213
|
+
for cfgdir in "$pd"/bin/*/"$mac_tfm"; do
|
|
214
|
+
[[ -d "$cfgdir" ]] || continue
|
|
215
|
+
plist="$(ls -t "$cfgdir"/*.app/Contents/Info.plist "$cfgdir"/*/*.app/Contents/Info.plist 2>/dev/null | head -1)"
|
|
216
|
+
[[ -n "$plist" ]] || continue
|
|
217
|
+
newer="$(find "$pd/Platforms/MacCatalyst" -maxdepth 1 \( -name '*.plist' -o -name '*.entitlements' \) -newer "$plist" 2>/dev/null | head -1)"
|
|
218
|
+
if [[ -n "$newer" ]]; then
|
|
219
|
+
cfg="$(basename "$(dirname "$cfgdir")")"
|
|
220
|
+
rm -rf "$cfgdir" "$pd/obj/$cfg/$mac_tfm"
|
|
221
|
+
echo "note $newer is newer than the built app ($plist); cleared bin/$cfg/$mac_tfm and obj/$cfg/$mac_tfm so the bundle is built again"
|
|
222
|
+
fi
|
|
223
|
+
done
|
|
224
|
+
fi
|
|
225
|
+
|
|
105
226
|
tried=()
|
|
106
227
|
n=0
|
|
107
228
|
for r in "${rungs[@]}"; do
|
|
@@ -114,9 +235,29 @@ for r in "${rungs[@]}"; do
|
|
|
114
235
|
powershell.exe) cmd=(powershell.exe -Command "dotnet ${args[*]}"); label="powershell.exe dotnet" ;;
|
|
115
236
|
esac
|
|
116
237
|
tried+=("$label")
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
238
|
+
[[ "$PLATFORM" == "wsl" ]] && cross_side "$(side_of "$r")"
|
|
239
|
+
for attempt in $(seq 0 "${TF_BUILD_LOCK_RETRIES:-2}"); do
|
|
240
|
+
from=1; [[ -f "$LOG" ]] && from=$(( $(wc -l < "$LOG") + 1 )) # the redirection itself fails on a log not yet written (TF-037)
|
|
241
|
+
{ echo "### rung $n: ${cmd[*]}"; "${cmd[@]}" 2>&1; echo "### exit $?"; } >> "$LOG" 2>&1
|
|
242
|
+
rc="$(tail -1 "$LOG" | sed 's/### exit //')"
|
|
243
|
+
seg="$(tail -n +"$from" "$LOG")" # this attempt's lines only
|
|
244
|
+
[[ "$rc" != "0" ]] && grep -qE "$LOCKED" <<<"$seg" || break
|
|
245
|
+
[[ $attempt -lt ${TF_BUILD_LOCK_RETRIES:-2} ]] && sleep "${TF_BUILD_LOCK_WAIT:-15}"
|
|
246
|
+
done
|
|
247
|
+
# A Mac Catalyst SDK names the one Xcode it was made for and refuses a newer one ("requires Xcode
|
|
248
|
+
# 26.6. The current version of Xcode is 27.0"): not the code, not the rung, so it fell through to
|
|
249
|
+
# NOT-RUN, while tf-verify-boot.sh built the same head with the check off (Lekhak TF-032). The same
|
|
250
|
+
# rung runs once more with the check off, and a note line says so before the verdict.
|
|
251
|
+
if [[ "$rc" != "0" && "$PLATFORM" == macos ]] && grep -qE 'requires Xcode [0-9.]+[.] The current version of Xcode is' <<<"$seg" \
|
|
252
|
+
&& [[ " ${cmd[*]} " != *ValidateXcodeVersion* ]]; then
|
|
253
|
+
xnote="$(grep -oE 'requires Xcode [0-9.]+[.] The current version of Xcode is [0-9.]+' <<<"$seg" | head -1 | sed 's/[.]$//')"
|
|
254
|
+
echo "note the Mac Catalyst SDK $xnote; built again with -p:ValidateXcodeVersion=false (xcode-check=off)"
|
|
255
|
+
cmd+=(-p:ValidateXcodeVersion=false)
|
|
256
|
+
from=$(( $(wc -l < "$LOG") + 1 ))
|
|
257
|
+
{ echo "### rung $n, Xcode check off: ${cmd[*]}"; "${cmd[@]}" 2>&1; echo "### exit $?"; } >> "$LOG" 2>&1
|
|
258
|
+
rc="$(tail -1 "$LOG" | sed 's/### exit //')"
|
|
259
|
+
seg="$(tail -n +"$from" "$LOG")"
|
|
260
|
+
fi
|
|
120
261
|
if [[ "$rc" == "0" ]]; then
|
|
121
262
|
warns="$(grep -cE 'warning [A-Z]+[0-9]+' <<<"$seg" || true)"
|
|
122
263
|
echo "PASS $MODE on $PLATFORM via $label (rung $n) — $warns warning line(s); log $LOG"
|
|
@@ -127,16 +268,23 @@ for r in "${rungs[@]}"; do
|
|
|
127
268
|
# taken for a wrong rung and reported NOT-RUN "host issue" (MISS-TechieFlow-20260906-03).
|
|
128
269
|
if grep -qE 'error (CS|RZ|BL|XC|XLS)[0-9]{3,5}|error MSB[0-9]{4}: .*(does not exist|could not be found)|error NU1' <<<"$seg" && ! grep -qE "$WRONG_RUNG" <<<"$seg"; then
|
|
129
270
|
errs="$(grep -cE 'error (CS|RZ|BL|XC|XLS|MSB|NU)[0-9]+' <<<"$seg" || true)"
|
|
130
|
-
first="$(grep -E 'error (CS|RZ|BL|XC|XLS|MSB|NU)[0-9]+' <<<"$seg" | head -1 | sed 's
|
|
271
|
+
first="$(grep -E 'error (CS|RZ|BL|XC|XLS|MSB|NU)[0-9]+' <<<"$seg" | head -1 | sed 's/^[[:space:]]*//' | cut -c1-160)"
|
|
131
272
|
echo "FAIL real errors on $PLATFORM via $label (rung $n): $errs error line(s), first: $first; log $LOG"
|
|
132
|
-
grep -E 'error (CS|RZ|BL|XC|XLS|MSB|NU)[0-9]+' <<<"$seg" | sed 's
|
|
273
|
+
grep -E 'error (CS|RZ|BL|XC|XLS|MSB|NU)[0-9]+' <<<"$seg" | sed 's/^[[:space:]]*//' | sort -u | head -10
|
|
133
274
|
exit 1
|
|
134
275
|
fi
|
|
135
|
-
if [[ "$MODE" == "test" ]] && grep -qE 'Failed!|Failed
|
|
276
|
+
if [[ "$MODE" == "test" ]] && grep -qE 'Failed!|Failed:[[:space:]]+[1-9]|Tests? failed' <<<"$seg"; then
|
|
136
277
|
echo "FAIL tests failed on $PLATFORM via $label (rung $n); log $LOG"
|
|
137
278
|
grep -E 'Failed |Failed!|Error Message|Total tests|Passed!' <<<"$seg" | head -12
|
|
138
279
|
exit 1
|
|
139
280
|
fi
|
|
281
|
+
# a locked output file: the rung is right and the code is fine; another rung over the same obj/
|
|
282
|
+
# is exactly what broke the stylesheets (TF-035), so stop here and name the lock
|
|
283
|
+
if grep -qE "$LOCKED" <<<"$seg"; then
|
|
284
|
+
first="$(grep -E "$LOCKED" <<<"$seg" | head -1 | sed 's/^[[:space:]]*//' | cut -c1-200)"
|
|
285
|
+
echo "NOT-RUN the build output is held by a running process (still after $((${TF_BUILD_LOCK_RETRIES:-2} + 1)) tries on $label): $first. Stop that app -- bash .tfcore/utils/tf-verify-boot.sh stop --port <its port> -- and build again. Not a code error; log $LOG"
|
|
286
|
+
exit 2
|
|
287
|
+
fi
|
|
140
288
|
# anything else (workload, wrong rung, tool absent): try the next rung
|
|
141
289
|
done
|
|
142
290
|
echo "NOT-RUN no rung could $MODE on $PLATFORM; tried: ${tried[*]}. This is a host issue, never a project blocker; log $LOG"
|
|
@@ -72,8 +72,26 @@ def set_cells(path, rid, status=None, pct=None, remark=None, append_remark=None)
|
|
|
72
72
|
return prior
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
def
|
|
76
|
-
|
|
75
|
+
def siblings(path):
|
|
76
|
+
"""every checklist of the same application: docs/<App>-Checklist.md and docs/<App>-P<N>-Checklist.md"""
|
|
77
|
+
d, f = os.path.split(path)
|
|
78
|
+
m = re.match(r"^(.+?)(?:-P\d+)?-Checklist\.md$", f)
|
|
79
|
+
if not m:
|
|
80
|
+
return []
|
|
81
|
+
app = re.escape(m.group(1))
|
|
82
|
+
try:
|
|
83
|
+
names = os.listdir(d or ".")
|
|
84
|
+
except OSError:
|
|
85
|
+
return []
|
|
86
|
+
return [os.path.join(d, n) for n in sorted(names) if n != f and re.match(rf"^{app}(?:-P\d+)?-Checklist\.md$", n)]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def next_id(text, prefix, others=()):
|
|
90
|
+
"""one past the highest id of that prefix in this checklist AND every other checklist of the app:
|
|
91
|
+
counting this one alone gave REQ-UI-055 twice, once in phase 1 and once in phase 3 (Chatur TF-011)"""
|
|
92
|
+
ids = []
|
|
93
|
+
for t in (text, *(read(o) for o in others)):
|
|
94
|
+
ids += [int(m.group(1)) for m in re.finditer(rf"REQ-{prefix}-(\d{{3,}})", t)]
|
|
77
95
|
return f"REQ-{prefix}-{(max(ids) + 1 if ids else 1):03d}"
|
|
78
96
|
|
|
79
97
|
|
|
@@ -81,7 +99,7 @@ def add_row(path, prefix, title, acceptance, section=None, remark=None, status="
|
|
|
81
99
|
"""append a row to the Requirements Status table and a detail entry under `section`
|
|
82
100
|
(a new section at the end when it does not exist); returns the new id"""
|
|
83
101
|
text = read(path)
|
|
84
|
-
rid = next_id(text, prefix)
|
|
102
|
+
rid = next_id(text, prefix, siblings(path))
|
|
85
103
|
nl = "\r\n" if "\r\n" in text else "\n"
|
|
86
104
|
lines = text.split(nl)
|
|
87
105
|
# the table: after the last REQ row
|