task-pipeline-skill 1.60.1 → 1.61.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 +37 -0
- package/SKILL-CARD.md +1 -1
- package/package.json +1 -1
- package/plugins/task-pipeline/.claude-plugin/plugin.json +1 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/adoption.md +2 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/exposure.md +24 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/README.md +1 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/exposure.sh +187 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.61.0 — the command that was built, parked, and lost
|
|
4
|
+
|
|
5
|
+
**The exposure command lands, two days after it was declared built.** B-43 recorded
|
|
6
|
+
`templates/exposure.sh` and its fixtures as finished and parked in a session scratchpad,
|
|
7
|
+
blocked only on a concurrent release. The scratchpad was cleaned; nothing on disk, in git
|
|
8
|
+
history, in a stash or in a dangling object held any of it. **The row described work that
|
|
9
|
+
no longer existed**, and nothing would have said so until someone went to merge it.
|
|
10
|
+
|
|
11
|
+
So it is rebuilt, and this time the validator asserts it: a seeded shell script must
|
|
12
|
+
exist, must carry a shebang, and must still be named by the doctrine that tells a project
|
|
13
|
+
to copy it. All three watched failing.
|
|
14
|
+
|
|
15
|
+
`exposure.sh` turns [`verification.md`](plugins/task-pipeline/skills/task-pipeline/references/verification.md)
|
|
16
|
+
into the line and the check-list `references/exposure.md` specifies, so a host project
|
|
17
|
+
gets the number without an agent in the room. **It exits 0 whatever the number is** — a
|
|
18
|
+
threshold here would be a target on `never`, and the cheapest way to satisfy such a
|
|
19
|
+
target is a date nobody earned.
|
|
20
|
+
|
|
21
|
+
Three of its fourteen fixtures caught real defects in the first draft, all of them lying
|
|
22
|
+
in the reassuring direction:
|
|
23
|
+
|
|
24
|
+
- `$(grep -c "" f || echo 0)` prints **two** zeroes when nothing matches — grep prints its
|
|
25
|
+
own 0 and exits 1, so the fallback runs as well. The variable became `"0\n0"`, every
|
|
26
|
+
numeric test after it died with *integer expression expected*, and the script fell over
|
|
27
|
+
precisely in the case that means "everything is confirmed".
|
|
28
|
+
- BSD `sort` exits with *Illegal byte sequence* on the non-ASCII `What` column under a
|
|
29
|
+
UTF-8 locale. The error went to stderr, the check-list came out **empty**, and the
|
|
30
|
+
count above it still said 126 unverified. A list that silently empties is worse than no
|
|
31
|
+
list.
|
|
32
|
+
- Byte-wise `substr` cut a Cyrillic letter in half. Truncation is by whole words now, which
|
|
33
|
+
cannot land inside a character.
|
|
34
|
+
|
|
35
|
+
Guards: 344 → **347**. Property checks: 9 → 9. Three new plants: the seeded script
|
|
36
|
+
disappearing, the doctrine that stops naming it, and a percentage reaching the exposure
|
|
37
|
+
line — the last because the doctrine says *no percentage, ever*, and a later hand adding
|
|
38
|
+
`(N%)` would be adding it to look helpful.
|
|
39
|
+
|
|
3
40
|
## v1.60.1 — the gate can see an invariant it breaks elsewhere
|
|
4
41
|
|
|
5
42
|
**This gate can now see an invariant it breaks one repository away.** The family umbrella
|
package/SKILL-CARD.md
CHANGED
|
@@ -12,7 +12,7 @@ harmless.
|
|
|
12
12
|
|---|---|
|
|
13
13
|
| **Purpose** | Runs a substantial task through ten gated delivery stages — intake grill, docs study, brainstorm, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs+registers, acceptance — refusing to advance until each gate passes |
|
|
14
14
|
| **Owner** | ssheleg ([github.com/ssheleg/task-pipeline](https://github.com/ssheleg/task-pipeline)) |
|
|
15
|
-
| **Version** | 1.
|
|
15
|
+
| **Version** | 1.61.0 |
|
|
16
16
|
| **Surface** | Claude Code (filesystem skill + plugin) and the vercel `skills` CLI. **Not** uploaded to the Skills API; custom Skills do not sync across surfaces |
|
|
17
17
|
| **Dependencies** | None required. Optional: `context7` (MCP), `figma` (MCP), super-ux, agent-sync, graphify, obsidian-wiki, and **one of two browser channels** — `playwright` (CLI or MCP) or `chrome-devtools` (MCP); either satisfies the browser step and neither is required. Every stage's doctrine ships in-repo; the one conditional requirement is super-ux for the stage-3 UX track on a user-facing task |
|
|
18
18
|
| **Evaluation status** | Suite authored, 5 categories. One recorded run, **self-observed by the author**; **zero blind runs on zero of three models** — the split, and the numbers, live in [`evals/RESULTS.md`](evals/RESULTS.md) and are computed by `evals/run.py` |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "task-pipeline-skill",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.61.0",
|
|
4
4
|
"description": "Full-cycle delivery pipeline for coding agents: a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine ships inside the skill — no companion plugin required. This package is the installer CLI.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"task-pipeline": "bin/task-pipeline.js"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "task-pipeline",
|
|
3
3
|
"displayName": "Task Pipeline",
|
|
4
4
|
"description": "Runs a substantial task through a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine is built into the skill — no companion plugin required — with typed auto/manual gates, a frozen requirement spine that closes with evidence, a work board and a verification ledger that outlive a run, an exposure line naming what shipped unconfirmed, a progress rail computed from the project's own config, a loop guard whose review ceiling measures rather than stops, and stage-3 tracks for what a product does, how it sounds and how it looks. Two modes need no task: `checkup` (what is unverified) and `setup` (audit existing docs). Retro insights can publish upstream as issues, opt-in and redacted.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.61.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ssheleg",
|
|
8
8
|
"url": "https://x.com/sshlg93"
|
|
@@ -82,7 +82,8 @@ Usually the map and the gate; often the register already exists in some shape.
|
|
|
82
82
|
```bash
|
|
83
83
|
cp <skill>/templates/docmap.md docs/DOCMAP.md # only if absent
|
|
84
84
|
cp <skill>/templates/docgate.sh scripts/check-docs.sh # only if absent
|
|
85
|
-
|
|
85
|
+
cp <skill>/templates/exposure.sh scripts/exposure.sh # only if absent
|
|
86
|
+
chmod +x scripts/check-docs.sh scripts/exposure.sh
|
|
86
87
|
```
|
|
87
88
|
|
|
88
89
|
**Seeding never overwrites.** An existing brief, register or map is the project's
|
|
@@ -15,6 +15,7 @@ list `/task-pipeline checkup` hands an operator.
|
|
|
15
15
|
- The components, each named
|
|
16
16
|
- The check-list, and how it is ordered
|
|
17
17
|
- `/task-pipeline checkup`
|
|
18
|
+
- The seeded script
|
|
18
19
|
- What the loop does with it
|
|
19
20
|
- Rationalizations
|
|
20
21
|
|
|
@@ -89,6 +90,29 @@ ledgers' unresolved count, and the code graph's staleness where one exists.
|
|
|
89
90
|
names the checkup and its date — so a row a machine created is distinguishable from one a
|
|
90
91
|
run surfaced. It prints what it would add first. Never silently.
|
|
91
92
|
|
|
93
|
+
## The seeded script
|
|
94
|
+
|
|
95
|
+
[`../templates/exposure.sh`](../templates/exposure.sh) computes the line and the
|
|
96
|
+
check-list from the two files above, so a project gets the number without an agent in the
|
|
97
|
+
room. Seed it the way the gate is seeded:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
cp <skill>/templates/exposure.sh scripts/exposure.sh # only if absent
|
|
101
|
+
chmod +x scripts/exposure.sh
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**It exits 0 whatever the number is, and that is load-bearing.** A threshold here would
|
|
105
|
+
be a target on `never`, and this file has already said that column may never have one —
|
|
106
|
+
the moment *"unverified must be under ten"* exists, the cheapest way to satisfy it is a
|
|
107
|
+
date nobody earned. Exit 1 means the ledger is present and unreadable, which is a
|
|
108
|
+
different fact and deserves a different code.
|
|
109
|
+
|
|
110
|
+
Two of its behaviours exist because the alternative lies in the reassuring direction. A
|
|
111
|
+
project with no ledger prints `dormant:` rather than a clean zero, and a check-list that
|
|
112
|
+
cannot be built is a failure rather than an empty section under a non-zero count — the
|
|
113
|
+
first draft's `sort` died on a non-ASCII `What` column, printed its error to stderr, and
|
|
114
|
+
left a confident number above nothing at all.
|
|
115
|
+
|
|
92
116
|
## What the loop does with it
|
|
93
117
|
|
|
94
118
|
[`continuity.md`](continuity.md) has always required each iteration to re-measure the
|
|
@@ -20,6 +20,7 @@ from `super-ux`.
|
|
|
20
20
|
| `decisions.md` | `docs/DECISIONS.md` — the decision register | 0 seeds it, the Doc Loop appends |
|
|
21
21
|
| `open-questions.md` | `docs/OPEN_QUESTIONS.md` | 0 seeds it, the Doc Loop resolves rows |
|
|
22
22
|
| `docgate.sh` | `scripts/check-docs.sh` | 0 seeds it · 9 runs it · 10 proves it |
|
|
23
|
+
| `exposure.sh` | `scripts/exposure.sh` | 0 reads it · 10 recomputes it · `checkup` prints it |
|
|
23
24
|
| `hygiene.sh` | `scripts/check-hygiene.sh` | 0 seeds it · **5 runs it after every task** · 6 and 9 run it · 10 proves it |
|
|
24
25
|
| `stage-coverage.sh` | `scripts/stage-coverage.sh` | 0 seeds it · **10 runs it before the coverage table** — every stage the flow declares must carry a verdict, or the flow stops declaring one it merges |
|
|
25
26
|
| `hooks.example.json` | the project's `.claude/settings.json` | 0 — offered, never installed silently |
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# exposure.sh — how much unverified work has piled up in <project>, and what to look at.
|
|
3
|
+
#
|
|
4
|
+
# Seeded by task-pipeline (references/exposure.md). IT IS YOURS NOW.
|
|
5
|
+
#
|
|
6
|
+
# SCOPE: reads the verification ledger and the git tag list. It does NOT know whether a
|
|
7
|
+
# confirmation was any good, whether a `pass` in the Auto column was watched failing,
|
|
8
|
+
# or anything about code. Read this header before quoting a number from here.
|
|
9
|
+
#
|
|
10
|
+
# IT IS A MEASUREMENT, NOT A GATE, AND THAT IS LOAD-BEARING. It exits 0 whatever the
|
|
11
|
+
# number is. A threshold here would be a target on `never`, and the ledger's own
|
|
12
|
+
# doctrine says that column may never have one — the moment "unverified must be under
|
|
13
|
+
# ten" exists, the cheapest way to satisfy it is to write a date nobody earned.
|
|
14
|
+
# Exit 1 is reserved for "the ledger is here and I could not read it".
|
|
15
|
+
#
|
|
16
|
+
# NO PERCENTAGE, EVER. The request that produced this asked for "the probability of an
|
|
17
|
+
# error". That is not computable from these inputs, and a number wearing a
|
|
18
|
+
# measurement's clothes is the failure this whole pipeline exists to remove. What
|
|
19
|
+
# prints is a vector with its components named, and a guard below refuses a `%`.
|
|
20
|
+
#
|
|
21
|
+
# PORTABLE to macOS bash 3.2: no grep -P, no readarray, no mapfile, no date -d.
|
|
22
|
+
#
|
|
23
|
+
# DORMANT, NOT SILENT: a project with no ledger yet prints why and exits 0. Dormant is
|
|
24
|
+
# visible so it is not forgotten, and green so a freshly seeded project is not red.
|
|
25
|
+
|
|
26
|
+
set -u
|
|
27
|
+
|
|
28
|
+
DOCS_DIR=${DOCS_DIR:-docs}
|
|
29
|
+
# The artifact root is RESOLVED, not assumed — renamed `superpowers` → `evidence` on
|
|
30
|
+
# 2026-08-13, and every gate that hardcoded the old name went dormant in migrated
|
|
31
|
+
# projects, which reads exactly like having nothing to check.
|
|
32
|
+
if [ -z "${EVIDENCE_DIR:-}" ]; then
|
|
33
|
+
if [ -d "$DOCS_DIR/evidence" ]; then EVIDENCE_DIR="$DOCS_DIR/evidence"
|
|
34
|
+
elif [ -d "$DOCS_DIR/superpowers" ]; then EVIDENCE_DIR="$DOCS_DIR/superpowers"
|
|
35
|
+
else EVIDENCE_DIR="$DOCS_DIR/evidence"
|
|
36
|
+
fi
|
|
37
|
+
fi
|
|
38
|
+
LEDGER=${LEDGER:-$EVIDENCE_DIR/verification.md}
|
|
39
|
+
BOARD=${BOARD:-$EVIDENCE_DIR/backlog.md}
|
|
40
|
+
LIST_MAX=${LIST_MAX:-8}
|
|
41
|
+
|
|
42
|
+
if [ ! -f "$LEDGER" ]; then
|
|
43
|
+
echo "dormant: exposure — no $LEDGER yet, so nothing has been shipped-and-unconfirmed"
|
|
44
|
+
exit 0
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
TMP=$(mktemp -d 2>/dev/null || mktemp -d -t exposure)
|
|
48
|
+
trap 'rm -rf "$TMP"' EXIT
|
|
49
|
+
|
|
50
|
+
# ---------- the ledger's rows ----------
|
|
51
|
+
# A row is a table line whose first cell is a REQ id. The header and the |---| separator
|
|
52
|
+
# are excluded by that shape rather than by counting lines, because a ledger grows
|
|
53
|
+
# sections and a line offset stops being true on the first one added.
|
|
54
|
+
awk -F'|' '
|
|
55
|
+
NF >= 7 && $2 ~ /^[[:space:]]*[A-Za-z][A-Za-z0-9-]*-?[0-9]*[[:space:]]*$/ &&
|
|
56
|
+
$2 !~ /^[[:space:]]*REQ[[:space:]]*$/ { print }
|
|
57
|
+
' "$LEDGER" > "$TMP/rows" 2>/dev/null
|
|
58
|
+
|
|
59
|
+
# `$(grep -c … || echo 0)` prints TWO zeroes when there are no matches: grep prints its
|
|
60
|
+
# 0 and exits 1, so the fallback runs too and the variable becomes "0\n0" — which then
|
|
61
|
+
# fails `[ "$ROWS" -eq 0 ]` with *integer expression expected* and takes the rest of the
|
|
62
|
+
# script with it. The fallback belongs OUTSIDE the substitution.
|
|
63
|
+
ROWS=$(grep -c '' "$TMP/rows" 2>/dev/null) || ROWS=0
|
|
64
|
+
if [ "$ROWS" -eq 0 ]; then
|
|
65
|
+
echo "dormant: exposure — $LEDGER has no REQ rows yet"
|
|
66
|
+
exit 0
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
# Column order is the template's: REQ | What | Run | Shipped in | Auto | Human | Note.
|
|
70
|
+
# With awk -F'|' on a leading-pipe line those are $2..$8.
|
|
71
|
+
|
|
72
|
+
awk -F'|' '{ h=$7; gsub(/^[ \t]+|[ \t]+$/, "", h); if (h == "never") print }' \
|
|
73
|
+
"$TMP/rows" > "$TMP/unverified"
|
|
74
|
+
UNVERIFIED=$(grep -c '' "$TMP/unverified" 2>/dev/null) || UNVERIFIED=0
|
|
75
|
+
|
|
76
|
+
# ---------- since: a date, or the literal `never checked` ----------
|
|
77
|
+
# ZERO WOULD BE A LIE IN THE DANGEROUS DIRECTION. "0 days" reads as *checked today*,
|
|
78
|
+
# which is the exact opposite of "nobody has ever looked", so the two cases print
|
|
79
|
+
# different words rather than different numbers.
|
|
80
|
+
awk -F'|' '{ h=$7; gsub(/^[ \t]+|[ \t]+$/, "", h);
|
|
81
|
+
if (h ~ /^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$/) print h }' \
|
|
82
|
+
"$TMP/rows" | sort > "$TMP/dates"
|
|
83
|
+
NEWEST=$(tail -1 "$TMP/dates" 2>/dev/null)
|
|
84
|
+
|
|
85
|
+
if [ -z "$NEWEST" ]; then
|
|
86
|
+
SINCE="never checked"
|
|
87
|
+
else
|
|
88
|
+
# Portable day arithmetic: BSD date and GNU date disagree on every flag that matters,
|
|
89
|
+
# so ask python, which both platforms have and which will not silently return today.
|
|
90
|
+
DAYS=$(python3 - "$NEWEST" <<'PY' 2>/dev/null
|
|
91
|
+
import datetime, sys
|
|
92
|
+
try:
|
|
93
|
+
d = datetime.date.fromisoformat(sys.argv[1])
|
|
94
|
+
except ValueError:
|
|
95
|
+
sys.exit(1)
|
|
96
|
+
print((datetime.date.today() - d).days)
|
|
97
|
+
PY
|
|
98
|
+
)
|
|
99
|
+
if [ -z "${DAYS:-}" ]; then
|
|
100
|
+
echo "FAIL: exposure — $LEDGER has a Human date this script cannot parse: $NEWEST"
|
|
101
|
+
exit 1
|
|
102
|
+
fi
|
|
103
|
+
SINCE="$DAYS days since the last human confirmation"
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
# ---------- releases: what has gone out on top of it ----------
|
|
107
|
+
# Tags, not commits: a release is what an operator feels. Counted since the newest
|
|
108
|
+
# confirmation date where there is one, and over the whole tag list where there is not —
|
|
109
|
+
# because "no release has ever followed a confirmation" and "no confirmation exists" are
|
|
110
|
+
# the same fact from two directions.
|
|
111
|
+
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
112
|
+
if [ -z "$NEWEST" ]; then
|
|
113
|
+
RELEASES=$(git tag --list 'v*' 2>/dev/null | grep -c '') || RELEASES=0
|
|
114
|
+
else
|
|
115
|
+
RELEASES=$(git log --tags --simplify-by-decoration --since="$NEWEST" \
|
|
116
|
+
--pretty='%d' 2>/dev/null | grep -o 'tag: v[0-9][^,)]*' | sort -u | grep -c '') || RELEASES=0
|
|
117
|
+
fi
|
|
118
|
+
else
|
|
119
|
+
RELEASES="?"
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
LINE="exposure: $UNVERIFIED unverified · $SINCE · $RELEASES releases carry one"
|
|
123
|
+
|
|
124
|
+
# ---------- the guard the doctrine names ----------
|
|
125
|
+
# Not decoration: a later hand adding "(N%)" here is exactly how the estimate-wearing-a-
|
|
126
|
+
# measurement's-clothes returns, and it would return looking helpful.
|
|
127
|
+
case "$LINE" in
|
|
128
|
+
*%*) echo "FAIL: exposure — the line contains a percentage: $LINE"
|
|
129
|
+
echo " references/exposure.md: no percentage, ever. A single score invites a"
|
|
130
|
+
echo " threshold, and a threshold here is a target on \`never\`."
|
|
131
|
+
exit 1 ;;
|
|
132
|
+
esac
|
|
133
|
+
|
|
134
|
+
echo "$LINE"
|
|
135
|
+
|
|
136
|
+
# ---------- the check-list: a number without it says there is a problem, not where ----------
|
|
137
|
+
if [ "$UNVERIFIED" -eq 0 ]; then
|
|
138
|
+
echo " every shipped row carries a human confirmation"
|
|
139
|
+
exit 0
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
# Oldest first by `Shipped in`, which is the only ordering this repository can defend.
|
|
143
|
+
# Version sort, so v1.9.0 precedes v1.10.0 — a lexical sort puts the newer one first and
|
|
144
|
+
# hands the operator the wrong end of the list.
|
|
145
|
+
awk -F'|' '{ req=$2; ship=$5; what=$3;
|
|
146
|
+
gsub(/^[ \t]+|[ \t]+$/, "", req);
|
|
147
|
+
gsub(/^[ \t]+|[ \t]+$/, "", ship);
|
|
148
|
+
gsub(/^[ \t]+|[ \t]+$/, "", what);
|
|
149
|
+
# Truncated on a WORD boundary, never mid-character: awk counts bytes
|
|
150
|
+
# here, so `substr(what, 1, 56)` cut a Cyrillic letter in half and printed
|
|
151
|
+
# a replacement glyph. Appending whole words cannot land inside one.
|
|
152
|
+
short = ""; n = split(what, w, " ");
|
|
153
|
+
for (i = 1; i <= n; i++) {
|
|
154
|
+
if (length(short) + length(w[i]) + 1 > 56) break;
|
|
155
|
+
short = (short == "" ? w[i] : short " " w[i]);
|
|
156
|
+
}
|
|
157
|
+
if (short == "") short = substr(what, 1, 20);
|
|
158
|
+
printf "%s\t%s\t%s\n", ship, req, short }' \
|
|
159
|
+
"$TMP/unverified" | LC_ALL=C sort -t"$(printf '\t')" -k1,1V > "$TMP/sorted"
|
|
160
|
+
# LC_ALL=C, and not for speed: the `What` column carries em-dashes and Cyrillic, and BSD
|
|
161
|
+
# sort exits with `Illegal byte sequence` on them under a UTF-8 locale — printing the
|
|
162
|
+
# error to stderr, producing an EMPTY list, and leaving the exposure line above it
|
|
163
|
+
# looking perfectly fine. A check-list that silently becomes empty is worse than no
|
|
164
|
+
# check-list, because the number above it still says there is work.
|
|
165
|
+
# The delimiter is a literal tab: the first draft said `-t.` and version-sorted on
|
|
166
|
+
# nothing.
|
|
167
|
+
|
|
168
|
+
echo " oldest first, by the release that shipped it:"
|
|
169
|
+
head -"$LIST_MAX" "$TMP/sorted" | while IFS="$(printf '\t')" read -r ship req what; do
|
|
170
|
+
# Blast radius from the board where it carries a row, reusing its stated input rather
|
|
171
|
+
# than inventing a weight here. Absent is printed as absent, never as a default.
|
|
172
|
+
blast=""
|
|
173
|
+
if [ -f "$BOARD" ]; then
|
|
174
|
+
blast=$(grep -m1 "| $req |" "$BOARD" 2>/dev/null | awk -F'|' '{ b=$5; gsub(/^[ \t]+|[ \t]+$/, "", b); print b }')
|
|
175
|
+
fi
|
|
176
|
+
if [ -n "$blast" ]; then
|
|
177
|
+
printf ' %-10s %-12s %s [blast %s]\n' "$ship" "$req" "$what" "$blast"
|
|
178
|
+
else
|
|
179
|
+
printf ' %-10s %-12s %s\n' "$ship" "$req" "$what"
|
|
180
|
+
fi
|
|
181
|
+
done
|
|
182
|
+
|
|
183
|
+
REST=$((UNVERIFIED - LIST_MAX))
|
|
184
|
+
if [ "$REST" -gt 0 ]; then
|
|
185
|
+
echo " … and $REST more — the full list is \`/task-pipeline checkup\`"
|
|
186
|
+
fi
|
|
187
|
+
exit 0
|