tickmarkr 1.92.1 → 1.96.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/dist/adapters/model-lints.d.ts +1 -1
- package/dist/adapters/model-lints.js +116 -52
- package/dist/cli/commands/beat.d.ts +1 -0
- package/dist/cli/commands/beat.js +50 -0
- package/dist/cli/commands/status.js +166 -9
- package/dist/cli/commands/verify.js +52 -26
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +3 -1
- package/dist/compile/gsd.js +34 -1
- package/dist/compile/native.js +26 -1
- package/dist/drivers/herdr.d.ts +26 -1
- package/dist/drivers/herdr.js +77 -29
- package/dist/gates/acceptance.js +26 -4
- package/dist/gates/baseline.d.ts +10 -1
- package/dist/gates/baseline.js +35 -6
- package/dist/run/daemon.d.ts +5 -0
- package/dist/run/daemon.js +25 -4
- package/dist/run/merge.d.ts +6 -1
- package/dist/run/merge.js +46 -11
- package/fixtures/gsd-sample/07-live-check/07-01-PLAN.md +1 -1
- package/fixtures/gsd-sample/PROJECT.md +19 -0
- package/fixtures/payload-shape/p99-shaped.spec.md +68 -0
- package/package.json +1 -1
- package/skills/tickmarkr-auto/SKILL.md +2 -1
- package/skills/tickmarkr-loop/SKILL.md +2 -1
- package/skills/tickmarkr-overseer/SKILL.md +189 -15
- package/skills/tickmarkr-overseer/scripts/seat-send.sh +140 -0
- package/skills/tickmarkr-overseer/scripts/watch-artifacts.sh +5 -2
- package/skills/tickmarkr-overseer/scripts/watch-pending-input.sh +17 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Deliver ONE directive to a seat with VERIFIED submission — the send path that failed five distinct
|
|
3
|
+
# ways in one leg (2026-08-17, P98): front-truncation at the PTY (~1024B), text sitting unsubmitted,
|
|
4
|
+
# two silent losses, and probes that mistook presence for delivery. A prose protocol loses one step
|
|
5
|
+
# under load; this encodes the steps.
|
|
6
|
+
#
|
|
7
|
+
# seat-send.sh <agent-name-or-pane> <message>
|
|
8
|
+
#
|
|
9
|
+
# TKR_INTERRUPT=1 end a `working` seat's turn first (Esc, at most twice, verified between) so the
|
|
10
|
+
# directive is READ now instead of queued behind the turn. A message to a working
|
|
11
|
+
# claude seat lands in its queue and drains only at the turn boundary — with
|
|
12
|
+
# in-process teammates that is 20–40 minutes, so A QUEUED HOLD IS NOT A HOLD.
|
|
13
|
+
# Measured 2026-08-18: two freeze-class directives sat queued behind a planner's
|
|
14
|
+
# teammate fan-out and THE OPERATOR pressed Esc by hand because no seat owned the
|
|
15
|
+
# interrupt. The interrupt loses the seat's in-flight step; for a correctness-class
|
|
16
|
+
# directive that is the price, and it is cheaper than a voided verdict.
|
|
17
|
+
#
|
|
18
|
+
# ⚠ WHY THE READ-BACK IS THE PROMPT LINE AND NOTHING ELSE (measured 2026-08-18, three methods failing
|
|
19
|
+
# identically): `herdr pane read` INCLUDES THE INPUT BOX, so an unsubmitted message renders exactly
|
|
20
|
+
# like a submitted one and every content-based probe — token grep, tail token, full-text match —
|
|
21
|
+
# returns the same answer in both states. A freeze hold was "verified delivered" three ways and had
|
|
22
|
+
# never been submitted; the receiving seat stopped 19 minutes later without ever reading it. Only the
|
|
23
|
+
# PROMPT LINE discriminates: text sitting on `❯` is exactly what will not run. Prompt-line state
|
|
24
|
+
# alone, or nothing — a decorative check beside a real one reads as corroboration.
|
|
25
|
+
#
|
|
26
|
+
# First output line is the machine-greppable verdict:
|
|
27
|
+
# DELIVERED_SUBMITTED | QUEUED_BEHIND_TURN | SEND_UNSUBMITTED | INTERRUPT_FAILED | TARGET_GONE
|
|
28
|
+
# | REFUSED_SIZE | REFUSED_BOX_OCCUPIED
|
|
29
|
+
#
|
|
30
|
+
# This verifies SUBMISSION — the text left the input box — never that the seat understood or acted.
|
|
31
|
+
# Read the seat's ARTIFACT for that; a send receipt is not a response.
|
|
32
|
+
set -u
|
|
33
|
+
|
|
34
|
+
TARGET="${1:?usage: seat-send.sh <agent-name-or-pane> <message>}"
|
|
35
|
+
MSG="${2:?message required}"
|
|
36
|
+
|
|
37
|
+
# PTY input front-truncates around 1KB and a truncated brief silently drops policy — the drop is at
|
|
38
|
+
# the FRONT, so what survives still reads as a complete message. Long content goes in a FILE; the
|
|
39
|
+
# pane gets one line pointing at it.
|
|
40
|
+
if [ "${#MSG}" -gt 900 ]; then
|
|
41
|
+
echo "REFUSED_SIZE ${#MSG} bytes — write a brief file and send a one-line pointer instead"; exit 2
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
status_of() {
|
|
45
|
+
herdr agent get "$TARGET" 2>/dev/null \
|
|
46
|
+
| sed -n 's/.*"agent_status":"\([a-z_]*\)".*/\1/p' | head -1
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# The rendered `❯` line — the only state that discriminates submitted from sitting. head -1 returns
|
|
50
|
+
# the first rendered line, i.e. a PREFIX of a wrapped draft, so callers compare prefixes, never
|
|
51
|
+
# whole sentences (OBS-396: a full-sentence match returns false on a message that arrived intact).
|
|
52
|
+
prompt_line() {
|
|
53
|
+
herdr agent read "$TARGET" --source visible --lines 14 2>/dev/null \
|
|
54
|
+
| sed -n 's/^[[:space:]]*❯[[:space:]]*//p' | head -1 | sed 's/[[:space:]]*$//'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Is $1 a rendered prefix of our message? (first line of a wrapped draft = prefix of MSG)
|
|
58
|
+
is_ours() {
|
|
59
|
+
case "$MSG" in "$1"*) return 0 ;; *) return 1 ;; esac
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# GHOST DISCRIMINATOR (OBS-482): claude-code AUTOSUGGEST renders its suggestion on the prompt line
|
|
63
|
+
# wrapped in SGR dim; typed text renders default. A dim-wrapped line is rendering, not state.
|
|
64
|
+
is_ghost() {
|
|
65
|
+
herdr agent read "$TARGET" --source visible --lines 14 --format ansi 2>/dev/null \
|
|
66
|
+
| grep -F -- "❯" | grep -F -- "$1" | head -1 | grep -q "$(printf '\033')\[2m"
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
S=$(status_of)
|
|
70
|
+
if [ -z "$S" ]; then
|
|
71
|
+
echo "TARGET_GONE $TARGET — agent get returned nothing (pane closed, or the name resolves nowhere)"
|
|
72
|
+
exit 1
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# A pre-existing draft in the box is a decision, not an obstacle: `agent prompt` would APPEND to it
|
|
76
|
+
# and submit both. Superseding someone else's text needs an author and the arrow form — refuse and
|
|
77
|
+
# surface it rather than silently stomping it (D-206: an unattributed line in a box, origin never
|
|
78
|
+
# resolved because it was cleared).
|
|
79
|
+
PRE=$(prompt_line)
|
|
80
|
+
if [ -n "$PRE" ] && ! is_ghost "$PRE"; then
|
|
81
|
+
echo "REFUSED_BOX_OCCUPIED $TARGET — input box already holds: $PRE"
|
|
82
|
+
echo " ANSI-verify first (dim SGR = autosuggest ghost, ignorable). A real draft is superseded by a"
|
|
83
|
+
echo " DECISION, not by this script: send the arrow form naming what you are overriding."
|
|
84
|
+
exit 2
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
QUEUED=""
|
|
88
|
+
if [ "$S" = "working" ]; then
|
|
89
|
+
if [ "${TKR_INTERRUPT:-0}" = "1" ]; then
|
|
90
|
+
# Esc at most twice, VERIFIED between: the first Esc can merely dismiss a UI surface or stop one
|
|
91
|
+
# step (the operator needed two on 2026-08-18). Unbounded Esc into an idle seat starts clearing
|
|
92
|
+
# state that is not yours to clear.
|
|
93
|
+
for _ in 1 2; do
|
|
94
|
+
herdr agent send-keys "$TARGET" esc >/dev/null 2>&1
|
|
95
|
+
sleep 3
|
|
96
|
+
S=$(status_of)
|
|
97
|
+
[ "$S" != "working" ] && break
|
|
98
|
+
done
|
|
99
|
+
if [ "$S" = "working" ]; then
|
|
100
|
+
echo "INTERRUPT_FAILED $TARGET still working after 2x esc — NOT sending; a directive queued now lands after the turn, which is the failure you set TKR_INTERRUPT to avoid"
|
|
101
|
+
exit 1
|
|
102
|
+
fi
|
|
103
|
+
else
|
|
104
|
+
QUEUED=1
|
|
105
|
+
fi
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
# Atomic text+Enter honouring the pane's live bracketed-paste mode — never send-text + separate
|
|
109
|
+
# Enter, which is the "sitting unsubmitted" failure by construction.
|
|
110
|
+
herdr agent prompt "$TARGET" "$MSG" >/dev/null 2>&1
|
|
111
|
+
|
|
112
|
+
sleep 2
|
|
113
|
+
PL=$(prompt_line)
|
|
114
|
+
if [ -n "$PL" ] && is_ours "$PL"; then
|
|
115
|
+
# The text is SITTING, not sent — the swallowed-Enter shape. Submitting the existing draft is not a
|
|
116
|
+
# re-send (nothing is duplicated); one bounded Enter, then re-read.
|
|
117
|
+
herdr agent send-keys "$TARGET" enter >/dev/null 2>&1
|
|
118
|
+
sleep 2
|
|
119
|
+
PL=$(prompt_line)
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
if [ -n "$PL" ] && is_ours "$PL"; then
|
|
123
|
+
echo "SEND_UNSUBMITTED $TARGET — the message is SITTING on the prompt line after send + one Enter."
|
|
124
|
+
echo " Do NOT re-send (it appends and submits both). Read the pane; supersede with the arrow form."
|
|
125
|
+
exit 1
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
if [ -n "$PL" ]; then
|
|
129
|
+
# Not ours: either autosuggest ghost (dim SGR — benign) or a draft that appeared under us.
|
|
130
|
+
echo "DELIVERED_SUBMITTED $TARGET — prompt line clear of our text; NOTE it now holds: $PL"
|
|
131
|
+
echo " ANSI-verify (dim = ghost). If typed, treat per D-206: discriminate before anyone clears it."
|
|
132
|
+
exit 0
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
if [ -n "$QUEUED" ]; then
|
|
136
|
+
echo "QUEUED_BEHIND_TURN $TARGET — submitted into a working seat's queue; it is READ at turn end. A freeze-class or superseding directive belongs behind TKR_INTERRUPT=1."
|
|
137
|
+
else
|
|
138
|
+
echo "DELIVERED_SUBMITTED $TARGET"
|
|
139
|
+
fi
|
|
140
|
+
exit 0
|
|
@@ -115,7 +115,7 @@ while :; do
|
|
|
115
115
|
echo "WAKE: ${#ready[@]} of $# artifact(s) complete with marker '$MARKER' — ${#pending[@]} still outstanding"
|
|
116
116
|
for f in ${ready[@]+"${ready[@]}"}; do echo " READY $(wc -c <"$f" | tr -d ' ') bytes sha1 $(shasum -a 1 "$f" | cut -c1-12) $f"; done
|
|
117
117
|
for f in ${pending[@]+"${pending[@]}"}; do
|
|
118
|
-
if [ -s "$f" ]; then echo " PARTIAL $(wc -c <"$f" | tr -d ' ') bytes, no marker yet $f"
|
|
118
|
+
if [ -s "$f" ]; then echo " PARTIAL $(wc -c <"$f" | tr -d ' ') bytes, no marker yet $f last-line: $(tail -n 1 "$f" | tr -d '\0' | cut -c1-72)"
|
|
119
119
|
else echo " NOT STARTED $f <- check whether that seat is BLOCKED; a stalled seat writes nothing"; fi
|
|
120
120
|
done
|
|
121
121
|
exit 0
|
|
@@ -147,7 +147,10 @@ while :; do
|
|
|
147
147
|
echo "WAKE: cap ${CAP}s reached — ${#ready[@]} of $# complete, re-arm"
|
|
148
148
|
for f in ${ready[@]+"${ready[@]}"}; do echo " READY $(wc -c <"$f" | tr -d ' ') bytes $f"; done
|
|
149
149
|
for f in ${pending[@]+"${pending[@]}"}; do
|
|
150
|
-
|
|
150
|
+
# PARTIAL prints the file's ACTUAL last line: a seat that reports the wrong marker for its own
|
|
151
|
+
# artifact leaves the file complete while this watcher waits forever, and the mismatch is visible
|
|
152
|
+
# only here (measured 2026-08-17: demanded/reported `SWEEP-END`, written `ORDER4-END`).
|
|
153
|
+
if [ -s "$f" ]; then echo " PARTIAL $(wc -c <"$f" | tr -d ' ') bytes, no '$MARKER' yet $f last-line: $(tail -n 1 "$f" | tr -d '\0' | cut -c1-72)"
|
|
151
154
|
else echo " ABSENT $f"; fi
|
|
152
155
|
done
|
|
153
156
|
exit 0
|
|
@@ -162,7 +162,7 @@ while [ "$elapsed" -lt "$CAP" ]; do
|
|
|
162
162
|
&& printf '%s' "$T" | grep -qEi -- "$AUTO_ALLOW_RE"; then
|
|
163
163
|
auto=$((auto + 1))
|
|
164
164
|
herdr agent prompt "$TARGET" \
|
|
165
|
-
" <-- disregard everything before this arrow (stale unsubmitted draft, auto-detected). ACTUAL: proceed exactly as that draft said: ${T}" \
|
|
165
|
+
" <-- [watch-pending-input auto-supersede] disregard everything before this arrow (stale unsubmitted draft, auto-detected). ACTUAL: proceed exactly as that draft said: ${T}" \
|
|
166
166
|
>/dev/null 2>&1
|
|
167
167
|
echo "$(date '+%H:%M:%S') auto-superseded #${auto}: ${T}" >> "${AUTO_LOG}"
|
|
168
168
|
streak=0
|
|
@@ -198,4 +198,20 @@ while [ "$elapsed" -lt "$CAP" ]; do
|
|
|
198
198
|
esac
|
|
199
199
|
done
|
|
200
200
|
|
|
201
|
+
# The negative alone is not evidence: a draft can arrive inside the final poll window, and a draft
|
|
202
|
+
# sitting in the box while the seat is WORKING is invisible to the loop above by design (working
|
|
203
|
+
# resets the streak). Measured 2026-08-17 (D-206): this watcher capped with "no sustained pending
|
|
204
|
+
# input in 1800s" while an unattributed instruction sat in the target's box, and blind-vs-timing
|
|
205
|
+
# could not be distinguished afterwards. So the cap line carries one FINAL unsustained read — the
|
|
206
|
+
# last frame of the window, whatever the seat's status — plus the styled bytes so ghost text is
|
|
207
|
+
# discriminable at the only moment it can be.
|
|
201
208
|
echo "WATCH_CAP_REACHED $TARGET status=$(status_of) — no sustained pending input in ${CAP}s"
|
|
209
|
+
FINAL=$(pending_text)
|
|
210
|
+
if [ -n "$FINAL" ]; then
|
|
211
|
+
echo " final read (UNSUSTAINED — present at cap, not confirmed across polls): $FINAL"
|
|
212
|
+
echo " styling evidence (dim/grey SGR = autosuggest ghost, NOT a draft):"
|
|
213
|
+
herdr agent read "$TARGET" --source visible --lines 14 --format ansi 2>/dev/null \
|
|
214
|
+
| grep -F -- "$FINAL" | head -2 | cat -v | sed 's/^/ /'
|
|
215
|
+
else
|
|
216
|
+
echo " final read: input box empty"
|
|
217
|
+
fi
|