pincer-workflow 0.4.1 → 0.6.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 (63) hide show
  1. package/README.md +9 -7
  2. package/bin/pincer.js +58 -5
  3. package/package.json +3 -3
  4. package/template/.agents/skills/pincer-code/SKILL.md +117 -12
  5. package/template/.agents/skills/pincer-evaluate/SKILL.md +57 -10
  6. package/template/.agents/skills/pincer-narrow/SKILL.md +48 -8
  7. package/template/.agents/skills/pincer-plan/SKILL.md +12 -4
  8. package/template/.agents/skills/pincer-release/SKILL.md +32 -3
  9. package/template/.agents/skills/pincer-status/SKILL.md +25 -2
  10. package/template/.claude/commands/pincer-code.md +117 -12
  11. package/template/.claude/commands/pincer-evaluate.md +57 -10
  12. package/template/.claude/commands/pincer-narrow.md +48 -8
  13. package/template/.claude/commands/pincer-plan.md +12 -4
  14. package/template/.claude/commands/pincer-release.md +32 -3
  15. package/template/.claude/commands/pincer-status.md +25 -2
  16. package/template/.claude/hooks/hook-policy.cjs +24 -3
  17. package/template/.claude/references/prd-template.md +11 -4
  18. package/template/.claude/references/ticket-template.md +4 -0
  19. package/template/.codex/README.md +3 -2
  20. package/template/.github/prompts/pincer-code.prompt.md +117 -12
  21. package/template/.github/prompts/pincer-evaluate.prompt.md +57 -10
  22. package/template/.github/prompts/pincer-narrow.prompt.md +48 -8
  23. package/template/.github/prompts/pincer-plan.prompt.md +12 -4
  24. package/template/.github/prompts/pincer-release.prompt.md +32 -3
  25. package/template/.github/prompts/pincer-status.prompt.md +25 -2
  26. package/template/AGENTS.md +22 -0
  27. package/template/docs/dry-run-checklist.md +70 -6
  28. package/template/docs/release-checklist.md +5 -2
  29. package/template/docs/runtime-contracts.md +1683 -0
  30. package/template/scripts/pincer-evidence.cjs +13 -229
  31. package/template/scripts/pincer-runtime/adopt.cjs +132 -0
  32. package/template/scripts/pincer-runtime/agreement.cjs +240 -0
  33. package/template/scripts/pincer-runtime/authorization.cjs +167 -0
  34. package/template/scripts/pincer-runtime/changes.cjs +517 -0
  35. package/template/scripts/pincer-runtime/checks.cjs +48 -0
  36. package/template/scripts/pincer-runtime/coverage.cjs +361 -0
  37. package/template/scripts/pincer-runtime/dispositions.cjs +95 -0
  38. package/template/scripts/pincer-runtime/evidence.cjs +676 -0
  39. package/template/scripts/pincer-runtime/fsutil.cjs +37 -0
  40. package/template/scripts/pincer-runtime/gates.cjs +73 -0
  41. package/template/scripts/pincer-runtime/identity.cjs +163 -0
  42. package/template/scripts/pincer-runtime/impact.cjs +177 -0
  43. package/template/scripts/pincer-runtime/io.cjs +41 -0
  44. package/template/scripts/pincer-runtime/lifecycle.cjs +311 -0
  45. package/template/scripts/pincer-runtime/locator.cjs +158 -0
  46. package/template/scripts/pincer-runtime/migrate.cjs +204 -0
  47. package/template/scripts/pincer-runtime/parse.cjs +316 -0
  48. package/template/scripts/pincer-runtime/phases.cjs +245 -0
  49. package/template/scripts/pincer-runtime/readiness.cjs +97 -0
  50. package/template/scripts/pincer-runtime/requirements.cjs +255 -0
  51. package/template/scripts/pincer-runtime/resume.cjs +205 -0
  52. package/template/scripts/pincer-runtime/routing.cjs +54 -0
  53. package/template/scripts/pincer-runtime/runner.cjs +242 -0
  54. package/template/scripts/pincer-runtime/sanitize.cjs +63 -0
  55. package/template/scripts/pincer-runtime/source.cjs +129 -0
  56. package/template/scripts/pincer-runtime/state.cjs +314 -0
  57. package/template/scripts/pincer-runtime/status.cjs +514 -0
  58. package/template/scripts/pincer-runtime/transaction.cjs +200 -0
  59. package/template/scripts/pincer-runtime/transitions.cjs +134 -0
  60. package/template/scripts/pincer-runtime.cjs +661 -0
  61. package/template/scripts/pincer-status.sh +11 -162
  62. package/template/scripts/pincer-ticket.sh +19 -139
  63. package/template/scripts/pincer-ticket-lib.sh +0 -321
@@ -2,167 +2,16 @@
2
2
  # PINCER status — where the workflow stands, read from the artifacts on disk.
3
3
  # Read-only. Every playbook runs this first; /pincer-status wraps it.
4
4
  #
5
- # scripts/pincer-status.sh
5
+ # scripts/pincer-status.sh [--json]
6
6
  #
7
- # Elapsed times come from the `started` / `finished` stamps that
8
- # scripts/pincer-ticket.sh writes, i.e. from the wall clock — never estimated
9
- # and never a measure of active execution time. The build-wide elapsed line is
10
- # printed only while a ticket is in progress or an explicit budget is set.
11
- # Optional build budget: PINCER_BUILD_BUDGET_MIN.
12
- set -uo pipefail
13
-
14
- source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/pincer-ticket-lib.sh"
15
- ROOT=${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}
16
- cd "$ROOT"
17
- BUDGET=${PINCER_BUILD_BUDGET_MIN:-}
18
- NOW=$(date -u +%s)
19
-
20
- to_epoch() { # ISO-8601 UTC -> seconds (GNU date, then BSD date)
21
- date -u -d "$1" +%s 2>/dev/null || date -u -j -f '%Y-%m-%dT%H:%M:%SZ' "$1" +%s 2>/dev/null || echo 0
7
+ # Compatibility wrapper: the report is computed by scripts/pincer-runtime.cjs
8
+ # (`status`), which prints the PRD state and profile, every ticket with its
9
+ # state and clock-based elapsed time, the wall-clock elapsed build line while a
10
+ # ticket is in progress or PINCER_BUILD_BUDGET_MIN is set, the evidence verdict,
11
+ # readiness warnings, and the next command. Exit codes follow
12
+ # docs/runtime-contracts.md (0 inspected, 4 invalid input).
13
+ command -v node >/dev/null 2>&1 || {
14
+ echo 'pincer-status: Node.js 22+ is required — the runtime is scripts/pincer-runtime.cjs' >&2
15
+ exit 4
22
16
  }
23
- mins() { echo "$(( ($2 - $1) / 60 ))m"; }
24
- hhmm() { [ -n "$1" ] && printf '%s' "$1" | cut -c12-16 || printf '—'; }
25
-
26
- echo "PINCER status · $(date -u +%Y-%m-%dT%H:%MZ) · $ROOT"
27
-
28
- # ── PRD ──
29
- if ! prd=$(latest_prd 2>&1); then
30
- printf 'WARN invalid PRD: %s\n' "$prd"
31
- echo 'Next repair PRD input before continuing'
32
- exit 1
33
- fi
34
- prd_status=""
35
- if [ -z "$prd" ]; then
36
- echo "PRD none"
37
- else
38
- prd_status=$(fm_get "$prd" status)
39
- echo "PRD $prd · status: ${prd_status:-?} · profile: $(prd_profile "$prd") · date: $(fm_get "$prd" date)"
40
- fi
41
-
42
- # Reject malformed/ambiguous tickets instead of treating unknown states as open.
43
- if ! errors=$(validate_ticket_set 2>&1); then
44
- printf 'WARN invalid tickets: %s\n' "$errors"
45
- echo "Next repair ticket input before continuing"
46
- exit 1
47
- fi
48
-
49
- # ── Tickets ──
50
- n_open=0; n_prog=0; n_done=0; first_start=""; in_prog=""; next_open=""; warn=""; reverify=""
51
- files=""; historical=0; unresolved=0
52
- for f in tickets/T-*.md; do
53
- [ -e "$f" ] || continue
54
- if ! associated=$(ticket_prd "$f" 2>&1); then
55
- printf 'WARN unresolved ticket PRD: %s\n' "$associated"
56
- unresolved=$((unresolved + 1)); continue
57
- fi
58
- if [ "$associated" = "$prd" ]; then
59
- files="$files$f
60
- "
61
- else
62
- historical=$((historical + 1))
63
- fi
64
- done
65
- [ "$historical" -eq 0 ] || echo "History $historical ticket(s) associated with other PRDs"
66
- if [ -z "$files" ]; then
67
- echo "Tickets none"
68
- else
69
- rows=""
70
- while IFS= read -r f; do
71
- [ -n "$f" ] || continue
72
- id=$(fm_get "$f" ticket); [ -n "$id" ] || id=$(basename "$f" | cut -c1-4)
73
- st=$(fm_get "$f" status); size=$(fm_get "$f" size)
74
- started=$(fm_get "$f" started); verified=$(fm_get "$f" verified); finished=$(fm_get "$f" finished)
75
- attempt=$(fm_get "$f" last_check)
76
- # Done tickets report through ticket_readiness below, so each problem is printed once.
77
- if [ "$st" != done ] && [ -n "$attempt" ] && ! printf '%s' "$attempt" | grep -q ' passed '; then
78
- warn="$warn WARN $id latest verification: $attempt — re-run verify\n"
79
- fi
80
- deps=$(fm_get "$f" depends_on | grep -oE 'T-[0-9]+' | tr '\n' ' ' || true)
81
- if [ -n "$started" ]; then
82
- se=$(to_epoch "$started")
83
- [ -z "$first_start" ] || [ "$se" -lt "$first_start" ] && first_start=$se
84
- fi
85
- case "$st" in
86
- done)
87
- n_done=$((n_done + 1))
88
- detail="started $(hhmm "$started") · finished $(hhmm "$finished")"
89
- [ -n "$started" ] && [ -n "$finished" ] && detail="$detail ($(mins "$(to_epoch "$started")" "$(to_epoch "$finished")"))"
90
- if ! readiness=$(ticket_readiness "$f"); then
91
- warn="$warn WARN $id $readiness\n"
92
- reverify="$reverify $id"
93
- fi
94
- ;;
95
- in_progress)
96
- n_prog=$((n_prog + 1)); in_prog="$in_prog $id"
97
- detail="started $(hhmm "$started")"
98
- [ -n "$started" ] && detail="$detail · elapsed $(mins "$(to_epoch "$started")" "$NOW")"
99
- if [ -n "$verified" ]; then detail="$detail · receipt ✓"; else detail="$detail · no receipt yet"; fi
100
- ;;
101
- *)
102
- n_open=$((n_open + 1)); st=${st:-open}
103
- blocked=""
104
- for d in $deps; do
105
- df=$(ticket_file "$d" 2>/dev/null || true)
106
- dep_prd=""
107
- [ -z "$df" ] || dep_prd=$(ticket_prd "$df" 2>/dev/null || true)
108
- if [ -z "$df" ] || [ "$(fm_get "$df" status)" != done ] ||
109
- [ "$dep_prd" != "$prd" ] || ! usable_ticket_prd "$df" >/dev/null 2>&1 ||
110
- ! ticket_readiness "$df" >/dev/null; then
111
- blocked="$blocked $d"
112
- fi
113
- done
114
- if [ -n "$blocked" ]; then detail="blocked by${blocked}"; else detail="ready"; [ -n "$next_open" ] || next_open=$id; fi
115
- ;;
116
- esac
117
- rows="$rows$(printf ' %-5s %-12s %-2s %s' "$id" "$st" "${size:-?}" "$detail")\n"
118
- done <<< "$files"
119
- echo "Tickets $((n_open + n_prog + n_done)) total · $n_done done · $n_prog in progress · $n_open open"
120
- printf '%b' "$rows"
121
- printf '%b' "$warn"
122
- # Wall-clock elapsed is shown only while work is active or against an explicit
123
- # budget; on a finished build it is noise and it never measures execution time.
124
- if [ -n "$first_start" ] && { [ "$n_prog" -gt 0 ] || [ -n "$BUDGET" ]; }; then
125
- build="Build wall-clock elapsed $(mins "$first_start" "$NOW") since the first ticket started (not active execution time)"
126
- [ -z "$BUDGET" ] || build="$build · budget ${BUDGET}m"
127
- echo "$build"
128
- fi
129
- fi
130
-
131
- notes_valid=no
132
- if notes=$(notes_current "$prd"); then notes_valid=yes; fi
133
- echo "Notes NOTES.md: $notes"
134
- # The evidence line reports the shared validator's verdict for the manifest the
135
- # notes name, independent of whether the candidate is still current.
136
- manifest=""
137
- [ -f NOTES.md ] && validate_metadata NOTES.md >/dev/null 2>&1 && manifest=$(fm_get NOTES.md evidence)
138
- if [ -n "$manifest" ]; then
139
- if ev=$(evidence_validate "$manifest" "$(fm_get NOTES.md candidate)" "$(fm_get NOTES.md base)" "$prd"); then
140
- echo "Evidence $manifest · ok"
141
- else
142
- echo "Evidence $manifest · $(evidence_reason "$ev")"
143
- fi
144
- fi
145
-
146
- # ── Next action ──
147
- if [ -z "$prd" ]; then
148
- next="/pincer-plan <brief> — no PRD yet"
149
- elif [ "$unresolved" -gt 0 ]; then
150
- next="resolve PRD association with pincer-ticket.sh bind T-NN .prd/prd-vN.md before continuing"
151
- elif [ "$prd_status" = draft ]; then
152
- next="/pincer-narrow — current PRD is draft; earlier tickets and notes do not complete it"
153
- elif [ -z "$files" ]; then
154
- next="/pincer-narrow — PRD exists, no tickets yet"
155
- elif [ -n "$in_prog" ]; then
156
- next="resume${in_prog}: /pincer-code${in_prog} (check git status for uncommitted work; then verify → done)"
157
- elif [ "$n_open" -gt 0 ]; then
158
- next="/pincer-code — next ready ticket: ${next_open:-none (all remaining are blocked — check depends_on)}"
159
- elif [ -n "$reverify" ]; then
160
- next="/pincer-code — re-run verify for${reverify}; resolve readiness warnings before evaluation or release"
161
- elif [ "$notes_valid" = no ] || [ "$prd_status" != built ]; then
162
- next="/pincer-evaluate — all tickets done"
163
- [ "$prd_status" = built ] || next="$next (PRD status is '${prd_status:-?}', expected 'built')"
164
- else
165
- next="/pincer-release — evaluation matches the current PRD and candidate; audit the artifacts"
166
- fi
167
- echo "Next $next"
168
- [ "$unresolved" -eq 0 ] || exit 1
17
+ exec node "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/pincer-runtime.cjs" status "$@"
@@ -1,145 +1,25 @@
1
1
  #!/bin/bash
2
- # PINCER ticket state machine — the ONLY writer of a ticket's state fields
3
- # (status / started / verified / finished). Works on every platform; on Claude
4
- # Code a PreToolUse hook (.claude/hooks/ticket-guard.sh) blocks hand edits of
5
- # those fields so "done" can only be reached through a passing check.
2
+ # PINCER ticket state machine — the ONLY writer of a ticket's lifecycle fields.
3
+ # Compatibility wrapper: every call is executed by scripts/pincer-runtime.cjs
4
+ # (docs/runtime-contracts.md). On Claude Code a PreToolUse hook
5
+ # (.claude/hooks/ticket-guard.sh) blocks hand edits of those fields so "done"
6
+ # can only be reached through a passing check.
6
7
  #
7
- # scripts/pincer-ticket.sh start T-03 open -> in_progress; refuses while a depends_on ticket isn't done
8
- # scripts/pincer-ticket.sh verify T-03 runs the ticket's Verification block; exit 0 stamps a receipt
9
- # scripts/pincer-ticket.sh done T-03 needs a receipt matching the current Verification block
10
- # and no unticked acceptance criteria; in_progress -> done
8
+ # scripts/pincer-ticket.sh start T-03 open -> in_progress; refuses while a depends_on ticket isn't ready
9
+ # scripts/pincer-ticket.sh verify T-03 runs the ticket's Verification block and records the outcome
10
+ # scripts/pincer-ticket.sh done T-03 closes the ticket on a current passing check with all criteria ticked
11
+ # scripts/pincer-ticket.sh bind T-03 .prd/prd-vN.md associates a legacy ticket with its PRD
11
12
  #
12
- # The receipt is `verified: <UTC time> <12-hex hash of the Verification block>`.
13
- # Change the check after it passed and `done` refuses until it passes again.
14
- # Every attempt revokes its predecessor; done runs a fresh final check.
15
- set -euo pipefail
16
-
17
- source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/pincer-ticket-lib.sh"
18
-
19
- ROOT=${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}
20
- cd "$ROOT"
21
-
22
- die() { printf 'pincer-ticket: %b\n' "$*" >&2; exit 1; }
23
- now() { date -u +%Y-%m-%dT%H:%M:%SZ; }
24
-
25
-
26
- fm_set() { # file key value — replace inside the frontmatter (keeping an inline comment) or add before the closing ---
27
- local tmp; tmp=$(mktemp)
28
- awk -v k="$2" -v v="$3" '
29
- NR == 1 { print; next }
30
- !closed && !done && index($0, k ":") == 1 {
31
- c = $0; if (sub(/^[^#]*#/, "#", c)) print k ": " v " " c; else print k ": " v
32
- done = 1; next
33
- }
34
- !closed && $0 == "---" { if (!done) print k ": " v; closed = 1 }
35
- { print }' "$1" > "$tmp" && mv "$tmp" "$1"
13
+ # Unmigrated (legacy) projects keep the v0.4.1 receipts: `verify` writes
14
+ # `last_check` and `verified` into the ticket and `done` re-runs the check.
15
+ # Migrated projects record attempts under .pincer/runtime/ and `done` consumes
16
+ # the current passing attempt. Exit codes follow docs/runtime-contracts.md.
17
+ command -v node >/dev/null 2>&1 || {
18
+ echo 'pincer-ticket: Node.js 22+ is required — the runtime is scripts/pincer-runtime.cjs' >&2
19
+ exit 4
36
20
  }
37
-
38
- fm_unset() {
39
- local tmp; tmp=$(mktemp)
40
- awk -v k="$2" 'NR > 1 && $0 == "---" { closed = 1 }
41
- !closed && index($0, k ":") == 1 { next } { print }' "$1" > "$tmp" && mv "$tmp" "$1"
42
- }
43
-
44
- cmd_bind() {
45
- local f ref existing
46
- f=$(ticket_file "$1"); ref=$2
47
- validate_prd "$ref" || exit 1
48
- existing=$(fm_get "$f" prd)
49
- [ -z "$existing" ] || [ "$existing" = "$ref" ] || die "$1 already references $existing; refusing to rebind it to $ref"
50
- [ "$existing" = "$ref" ] || fm_set "$f" prd "$ref"
51
- echo "$1 bound to PRD $ref"
52
- }
53
-
54
- cmd_start() {
55
- local f id st dep df ref dep_ref readiness
56
- f=$(ticket_file "$1"); id=$(normalize "$1"); st=$(fm_get "$f" status)
57
- ref=$(usable_ticket_prd "$f") || exit 1
58
- case "$st" in
59
- in_progress)
60
- [ -n "$(fm_get "$f" prd)" ] || fm_set "$f" prd "$ref"
61
- echo "$id already in progress (started $(fm_get "$f" started))"; return 0 ;;
62
- done) die "$id is already done" ;;
63
- esac
64
- for dep in $(fm_get "$f" depends_on | grep -oE 'T-[0-9]+' || true); do
65
- df=$(ticket_file "$dep")
66
- [ "$(fm_get "$df" status)" = done ] || die "$id depends on $dep, which is '$(fm_get "$df" status)' — finish $dep first (or fix depends_on in $f)"
67
- dep_ref=$(usable_ticket_prd "$df") || exit 1
68
- [ "$dep_ref" = "$ref" ] || die "$id references $ref but dependency $dep references $dep_ref"
69
- if ! readiness=$(ticket_readiness "$df"); then die "$id depends on $dep: $readiness"; fi
70
- done
71
- [ -n "$(fm_get "$f" prd)" ] || fm_set "$f" prd "$ref"
72
- fm_set "$f" status in_progress
73
- [ -n "$(fm_get "$f" started)" ] || fm_set "$f" started "$(now)"
74
- echo "▶ $id started $(fm_get "$f" started) — $f"
75
- }
76
-
77
- cmd_verify() {
78
- local f id st cmds rc hash child
79
- f=$(ticket_file "$1"); id=$(normalize "$1"); st=$(fm_get "$f" status)
80
- usable_ticket_prd "$f" >/dev/null || exit 1
81
- case "$st" in
82
- open) cmd_start "$id" ;;
83
- done) echo "$id is done — re-running its check and updating the latest outcome" ;;
84
- esac
85
- cmds=$(verification_cmds "$f")
86
- fm_unset "$f" verified
87
- hash=$(verify_hash "$f")
88
- fm_set "$f" last_check "$(now) running $hash"
89
- printf '%s\n' "$cmds" | grep -vE '^[[:space:]]*(#|$)' >/dev/null || die "no runnable command in the Verification block of $f"
90
- echo "── $id verification ──"
91
- printf '%s\n' "$cmds" | sed 's/^/ $ /'
92
- bash -eo pipefail -c "$cmds" & child=$!
93
- trap 'kill "$child" 2>/dev/null || true; fm_set "$f" last_check "$(now) interrupted $hash"; exit 130' INT TERM
94
- set +e; wait "$child"; rc=$?; set -e
95
- trap - INT TERM
96
- if [ "$rc" -ne 0 ]; then
97
- fm_set "$f" last_check "$(now) failed $hash"
98
- echo "✗ $id verification FAILED (exit $rc) — failure recorded in last_check of $f; any prior successful receipt was revoked. Fix, then re-run verify." >&2
99
- exit "$rc"
100
- fi
101
- if [ "$hash" != "$(verify_hash "$f")" ]; then
102
- fm_set "$f" last_check "$(now) failed $hash"
103
- die "Verification block changed during execution — re-run verify"
104
- fi
105
- if ! validate_ticket "$f" || ! usable_ticket_prd "$f" >/dev/null; then
106
- fm_set "$f" last_check "$(now) failed $hash"
107
- die "ticket became invalid during verification — fix it and re-run verify"
108
- fi
109
- fm_set "$f" last_check "$(now) passed $hash"
110
- fm_set "$f" verified "$(now) $hash"
111
- echo "✓ $id verified — receipt: $(fm_get "$f" verified)"
112
- }
113
-
114
- cmd_done() {
115
- local f id st rec cur u slug
116
- f=$(ticket_file "$1"); id=$(normalize "$1"); st=$(fm_get "$f" status)
117
- usable_ticket_prd "$f" >/dev/null || exit 1
118
- [ "$st" = in_progress ] || [ "$st" = done ] || die "$id is '$st' — run '$0 verify $id' first"
119
- rec=$(fm_get "$f" verified)
120
- [ -n "$rec" ] || die "no verification receipt on $id — run '$0 verify $id' and get a green check first"
121
- cur=$(verify_hash "$f")
122
- [ "${rec##* }" = "$cur" ] || die "receipt hash ${rec##* } does not match the current Verification block ($cur): the check changed after it passed — run '$0 verify $id' again"
123
- u=$(unticked "$f")
124
- [ -z "$u" ] || die "unticked acceptance criteria on $id:\n$u\nTick each verified criterion; a criterion that was cut is a scope change to record in the PRD, not a box to skip."
125
- cmd_verify "$id"
126
- u=$(unticked "$f")
127
- [ -z "$u" ] || die "unticked acceptance criteria on $id after verification:\n$u"
128
- [ "$st" = done ] && { echo "$id already done — current check passed"; return 0; }
129
- fm_set "$f" status done
130
- fm_set "$f" finished "$(now)"
131
- slug=$(basename "$f" .md); slug=${slug#T-[0-9][0-9]-}
132
- echo "✓ $id done. Inspect staged work, stage only this ticket's paths, review git diff --cached, then commit: $id: ${slug//-/ }"
133
- }
134
-
135
- case "${1:-}" in
136
- start|verify|done|bind) validate_ticket_set || exit 1 ;;
137
- esac
138
-
139
21
  case "${1:-}" in
140
- start) [ $# -eq 2 ] || die "usage: $0 start T-NN"; cmd_start "$2" ;;
141
- verify) [ $# -eq 2 ] || die "usage: $0 verify T-NN"; cmd_verify "$2" ;;
142
- done) [ $# -eq 2 ] || die "usage: $0 done T-NN"; cmd_done "$2" ;;
143
- bind) [ $# -eq 3 ] || die "usage: $0 bind T-NN .prd/prd-vN.md"; cmd_bind "$2" "$3" ;;
144
- *) sed -n '2,13p' "$0" | sed 's/^# \{0,1\}//'; exit 1 ;;
22
+ start|verify|done|bind) ;;
23
+ *) sed -n '8,11p' "$0" | sed 's/^# \{0,1\}//'; exit 2 ;;
145
24
  esac
25
+ exec node "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/pincer-runtime.cjs" "$@"