tickmarkr 2.1.2 → 2.1.4
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/claude-code.js +18 -3
- package/dist/adapters/pi.d.ts +6 -0
- package/dist/adapters/pi.js +99 -18
- package/dist/cli/commands/beat.js +28 -8
- package/dist/cli/commands/init.js +28 -1
- package/dist/cli/commands/status.d.ts +3 -0
- package/dist/cli/commands/status.js +40 -16
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/compile/gsd.js +21 -1
- package/dist/gates/baseline.d.ts +10 -0
- package/dist/gates/baseline.js +46 -3
- package/dist/run/daemon.d.ts +0 -1
- package/dist/run/daemon.js +54 -19
- package/dist/run/git.d.ts +20 -0
- package/dist/run/git.js +114 -8
- package/dist/run/journal.d.ts +24 -0
- package/dist/run/journal.js +62 -1
- package/dist/run/lock.d.ts +1 -0
- package/dist/run/lock.js +23 -13
- package/dist/run/supervision.d.ts +9 -3
- package/dist/run/supervision.js +185 -38
- package/dist/tui/cockpit/derive.js +5 -10
- package/fixtures/gsd-sample/07-live-check/07-03-SUMMARY.md +4 -0
- package/package.json +2 -2
- package/skills/tickmarkr-auto/SKILL.md +1 -1
- package/skills/tickmarkr-loop/SKILL.md +1 -1
- package/skills/tickmarkr-overseer/SKILL.md +37 -14
- package/skills/tickmarkr-overseer/scripts/watch-context.sh +80 -31
|
@@ -14,26 +14,66 @@
|
|
|
14
14
|
# handoff is stale, the seat is holding state that a clear would destroy, and the correct move is to wake
|
|
15
15
|
# a supervisor — never to clear and hope.
|
|
16
16
|
#
|
|
17
|
-
#
|
|
17
|
+
# THIS WATCHER IS SUPERVISED, and the tier is PER SEAT: `<role>-context`, one per supervising seat, so a
|
|
18
|
+
# live overseer watcher can never make a dead orchestrator one read as covered. Every beat declares the
|
|
19
|
+
# seat it watches (`--seat`), because a tier that is armed and seatless reads as coverage, which is worse
|
|
20
|
+
# than absent. Four rules the shipped version broke, each of which made the tier lie:
|
|
21
|
+
# 1. BEAT ON THE SUPERVISION CADENCE, NOT ON THE POLL. Beats gap by TICK (below), never by POLL, so a
|
|
22
|
+
# poll interval above the supervision beat interval cannot leave the tier stale half of every cycle.
|
|
23
|
+
# 2. BEAT ONLY AFTER A SUCCESSFUL READ. A watcher that cannot see its seat's percentage is not
|
|
24
|
+
# watching it; beating anyway reports coverage it is not providing, and the tier must age out.
|
|
25
|
+
# 3. WARN DOES NOT EXIT. Warn precedes act, so exiting at warn meant the act was never reached and the
|
|
26
|
+
# last beat aged into a permanent stale — gradual growth never reached the auto-clear path at all.
|
|
27
|
+
# 4. EVERY TERMINAL EXIT STANDS THE TIER DOWN, so a watcher that finished reads DISARMED, not dead.
|
|
28
|
+
# Only a killed watcher reads STALE, which is exactly what STALE means.
|
|
29
|
+
#
|
|
30
|
+
# usage: watch-context.sh <orchestrator|overseer> <agent|pane> <warn-pct> <act-pct> [handoff-file] [poll-s] [cap-s]
|
|
18
31
|
# TKR_AUTO_CLEAR=1 at act-pct WITH a fresh handoff, send /clear and re-brief instead of waking.
|
|
19
32
|
# TKR_REBRIEF=<path> the file the re-briefed seat is told to read (defaults to the handoff).
|
|
20
33
|
# TKR_HANDOFF_MAX_AGE_S how fresh "fresh" is (default 900).
|
|
34
|
+
# TKR_CLEAR_SETTLE_S seconds to let a cleared seat settle before the re-brief (default 6).
|
|
21
35
|
|
|
22
36
|
set -u
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
ROLE="${1:?supervising seat role required: orchestrator|overseer}"
|
|
38
|
+
TARGET="${2:?agent name or pane id required}"
|
|
39
|
+
WARN="${3:-60}"
|
|
40
|
+
ACT="${4:-75}"
|
|
41
|
+
HANDOFF="${5:-}"
|
|
42
|
+
POLL="${6:-120}"
|
|
43
|
+
CAP="${7:-28800}"
|
|
29
44
|
MAXAGE="${TKR_HANDOFF_MAX_AGE_S:-900}"
|
|
30
45
|
REBRIEF="${TKR_REBRIEF:-$HANDOFF}"
|
|
46
|
+
SETTLE="${TKR_CLEAR_SETTLE_S:-6}"
|
|
47
|
+
|
|
48
|
+
case "$ROLE" in
|
|
49
|
+
orchestrator|overseer) TIER="${ROLE}-context" ;;
|
|
50
|
+
*) echo "watch-context.sh: unknown seat role '$ROLE' — expected orchestrator or overseer" >&2; exit 64 ;;
|
|
51
|
+
esac
|
|
52
|
+
|
|
53
|
+
# The supervision beat interval (SUPERVISION_BEAT_MS = 10s). The loop ticks at the beat cadence or the
|
|
54
|
+
# caller's poll, whichever is SHORTER: a beat may only follow a successful read (rule 2), so the read
|
|
55
|
+
# cadence is the floor on the beat cadence, and the tier's freshness is never the caller's to widen.
|
|
56
|
+
BEAT_EVERY=5
|
|
57
|
+
TICK=$(( POLL < BEAT_EVERY ? POLL : BEAT_EVERY ))
|
|
58
|
+
[ "$TICK" -ge 1 ] 2>/dev/null || TICK=1 # a zero or junk poll would spin, not watch
|
|
59
|
+
SEAT="$TARGET"
|
|
60
|
+
|
|
61
|
+
beat() { tickmarkr beat "$TIER" --seat "$SEAT" >/dev/null 2>&1; }
|
|
62
|
+
stand_down() { tickmarkr beat "$TIER" --stand-down --seat "$SEAT" >/dev/null 2>&1; }
|
|
63
|
+
# EVERY terminal exit — act, unsafe-act, cap — leaves through here, so none of them can forget to
|
|
64
|
+
# record the hand-off. A killed watcher never runs it, which is the one case that must read STALE.
|
|
65
|
+
trap stand_down EXIT
|
|
31
66
|
|
|
32
|
-
# The seat's own rendered truth.
|
|
33
|
-
#
|
|
67
|
+
# The seat's own rendered truth. Prefer a line carrying a context marker so a percentage elsewhere on
|
|
68
|
+
# screen cannot be mistaken for the gauge — but NEVER require one: the ✳ marker the shipped version
|
|
69
|
+
# anchored on is rendered by a single vendor, so every other seat read empty, beat anyway and slept to
|
|
70
|
+
# its cap while its tier claimed coverage. The last percentage in the statusline window is the fallback.
|
|
34
71
|
context_pct() {
|
|
35
|
-
|
|
36
|
-
|
|
72
|
+
local screen marked
|
|
73
|
+
screen=$(herdr agent read "$TARGET" --source visible --lines 8 2>/dev/null) || return 1
|
|
74
|
+
marked=$(printf '%s\n' "$screen" | grep -iE '✳|context' | grep -oE '[0-9]+%' | tail -1 | tr -d '%')
|
|
75
|
+
[ -n "$marked" ] && { printf '%s\n' "$marked"; return 0; }
|
|
76
|
+
printf '%s\n' "$screen" | grep -oE '[0-9]+%' | tail -1 | tr -d '%'
|
|
37
77
|
}
|
|
38
78
|
|
|
39
79
|
handoff_fresh() {
|
|
@@ -41,46 +81,55 @@ handoff_fresh() {
|
|
|
41
81
|
[ -f "$HANDOFF" ] || return 1
|
|
42
82
|
local age now mt
|
|
43
83
|
now=$(date +%s)
|
|
44
|
-
mt=$(stat -
|
|
84
|
+
mt=$(stat -c %Y "$HANDOFF" 2>/dev/null || stat -f %m "$HANDOFF" 2>/dev/null) || return 1
|
|
45
85
|
age=$((now - mt))
|
|
46
86
|
[ "$age" -le "$MAXAGE" ]
|
|
47
87
|
}
|
|
48
88
|
|
|
89
|
+
act_on() {
|
|
90
|
+
local P="$1"
|
|
91
|
+
if handoff_fresh; then
|
|
92
|
+
if [ "${TKR_AUTO_CLEAR:-0}" = "1" ]; then
|
|
93
|
+
herdr agent prompt "$TARGET" "/clear" >/dev/null 2>&1
|
|
94
|
+
sleep "$SETTLE"
|
|
95
|
+
herdr agent prompt "$TARGET" "Read ${REBRIEF} and continue exactly where it says. Your context was cleared at ${P}% against that handoff; it is current as of $(date '+%H:%M'). Do not reconstruct from memory — everything you need is on disk." >/dev/null 2>&1
|
|
96
|
+
echo "CONTEXT_CLEARED $TARGET at ${P}% — handoff fresh, re-briefed from ${REBRIEF}"
|
|
97
|
+
exit 0
|
|
98
|
+
fi
|
|
99
|
+
echo "CONTEXT_ACT $TARGET ${P}% (>= ${ACT}) — handoff is FRESH, a clear is SAFE now"
|
|
100
|
+
echo " herdr agent prompt $TARGET \"/clear\" then re-brief from ${REBRIEF}"
|
|
101
|
+
exit 0
|
|
102
|
+
fi
|
|
103
|
+
echo "CONTEXT_ACT_UNSAFE $TARGET ${P}% (>= ${ACT}) — NO FRESH HANDOFF (${HANDOFF:-none})"
|
|
104
|
+
echo " the seat is holding state that exists only in its head; a clear would destroy it"
|
|
105
|
+
echo " make it write the handoff FIRST, then clear"
|
|
106
|
+
exit 0
|
|
107
|
+
}
|
|
108
|
+
|
|
49
109
|
warned=0
|
|
50
110
|
elapsed=0
|
|
51
111
|
while [ "$elapsed" -lt "$CAP" ]; do
|
|
52
112
|
P=$(context_pct)
|
|
53
113
|
if [ -z "$P" ]; then
|
|
54
|
-
|
|
114
|
+
# Rule 2: no reading, no beat. The tier ages to STALE and a supervisor comes looking, which is the
|
|
115
|
+
# truth about a watcher that cannot see the seat it was armed on.
|
|
116
|
+
sleep "$TICK"; elapsed=$((elapsed + TICK)); continue
|
|
55
117
|
fi
|
|
118
|
+
beat
|
|
56
119
|
|
|
57
120
|
if [ "$P" -ge "$ACT" ] 2>/dev/null; then
|
|
58
|
-
|
|
59
|
-
if [ "${TKR_AUTO_CLEAR:-0}" = "1" ]; then
|
|
60
|
-
herdr agent prompt "$TARGET" "/clear" >/dev/null 2>&1
|
|
61
|
-
sleep 6
|
|
62
|
-
herdr agent prompt "$TARGET" "Read ${REBRIEF} and continue exactly where it says. Your context was cleared at ${P}% against that handoff; it is current as of $(date '+%H:%M'). Do not reconstruct from memory — everything you need is on disk." >/dev/null 2>&1
|
|
63
|
-
echo "CONTEXT_CLEARED $TARGET at ${P}% — handoff fresh, re-briefed from ${REBRIEF}"
|
|
64
|
-
exit 0
|
|
65
|
-
fi
|
|
66
|
-
echo "CONTEXT_ACT $TARGET ${P}% (>= ${ACT}) — handoff is FRESH, a clear is SAFE now"
|
|
67
|
-
echo " herdr agent prompt $TARGET \"/clear\" then re-brief from ${REBRIEF}"
|
|
68
|
-
exit 0
|
|
69
|
-
fi
|
|
70
|
-
echo "CONTEXT_ACT_UNSAFE $TARGET ${P}% (>= ${ACT}) — NO FRESH HANDOFF (${HANDOFF:-none})"
|
|
71
|
-
echo " the seat is holding state that exists only in its head; a clear would destroy it"
|
|
72
|
-
echo " make it write the handoff FIRST, then clear"
|
|
73
|
-
exit 0
|
|
121
|
+
act_on "$P"
|
|
74
122
|
fi
|
|
75
123
|
|
|
76
124
|
if [ "$P" -ge "$WARN" ] 2>/dev/null && [ "$warned" -eq 0 ]; then
|
|
125
|
+
# Rule 3: warn is a LINE, not an exit — the act is on the far side of it.
|
|
77
126
|
warned=1
|
|
78
127
|
echo "CONTEXT_WARN $TARGET ${P}% (>= ${WARN}) — write the handoff NOW, while judgement is still good"
|
|
128
|
+
echo " re-brief target when it acts: ${REBRIEF:-none}"
|
|
79
129
|
echo " a handoff written at ${ACT}% is written by a seat already degraded; that is the wrong time"
|
|
80
|
-
exit 0
|
|
81
130
|
fi
|
|
82
131
|
|
|
83
|
-
sleep "$
|
|
132
|
+
sleep "$TICK"; elapsed=$((elapsed + TICK))
|
|
84
133
|
done
|
|
85
134
|
|
|
86
135
|
echo "WATCH_CAP_REACHED $TARGET context=$(context_pct)% — no threshold crossed in ${CAP}s"
|