@techgoblin/gobstack 0.4.4-beta.6 → 0.4.4-beta.7
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/bin/goblin-init +133 -90
- package/docs/w6-tty-redraw-pty-transcript.txt +334 -0
- package/package.json +1 -1
package/bin/goblin-init
CHANGED
|
@@ -5,10 +5,13 @@
|
|
|
5
5
|
# [--branch <name>] [--email <addr>] [--gate <cmd>]
|
|
6
6
|
# [--emit <p[,p..]>] [--scope project|global] [--yes] [--dry-run]
|
|
7
7
|
#
|
|
8
|
-
# One screen per question, answered steps collapsing into the ✔/◆/○ rail above.
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
8
|
+
# One screen per question, answered steps collapsing into the ✔/◆/○ rail above. On a tty
|
|
9
|
+
# the whole wizard frame (logotype, header, answered rows, rail) is redrawn in place from
|
|
10
|
+
# a saved buffer of the wizard's own lines — never by counting printed output, which the
|
|
11
|
+
# installer/emit engines would break. Every question has a flag: with the flags set (or
|
|
12
|
+
# --yes, or a non-tty stdin) the wizard asks nothing and runs from the flags and the
|
|
13
|
+
# defaults — non-interactive parity is structural, not a mode. Over a pipe the redraw
|
|
14
|
+
# degrades to a numbered cascade (rustup shape) with zero cursor motion.
|
|
12
15
|
#
|
|
13
16
|
# The wizard is a FRONT END over the existing engines, never a second installer:
|
|
14
17
|
# .goblin/ + the payload -> bin/goblin-install (its refusal contract — an existing
|
|
@@ -47,9 +50,11 @@ VERSION=$(cat "$SRC/VERSION" 2>/dev/null || printf 'unknown')
|
|
|
47
50
|
# nearest 16-colour slot. NO_COLOR or a piped stdout turns colour off entirely.
|
|
48
51
|
TTY_OUT=0; [ -t 1 ] && TTY_OUT=1
|
|
49
52
|
TTY_IN=0; [ -t 0 ] && TTY_IN=1
|
|
50
|
-
C_ACCENT="" C_GREEN="" C_TEXT="" C_MUTED="" C_DIM="" C_RED="" C_YELLOW="" C_RESET=""
|
|
53
|
+
C_ACCENT="" C_GREEN="" C_TEXT="" C_MUTED="" C_DIM="" C_RED="" C_YELLOW="" C_RESET=""
|
|
54
|
+
# Single-accent discipline: one accent (#F54E00) + green + text + muted + dim. No bold
|
|
55
|
+
# is ever emitted — bold was a second emphasis voice and is gone from every screen.
|
|
51
56
|
if [ "$TTY_OUT" -eq 1 ] && [ -z "${NO_COLOR:-}" ]; then
|
|
52
|
-
C_RESET=$'\033[0m'
|
|
57
|
+
C_RESET=$'\033[0m'
|
|
53
58
|
case "${COLORTERM:-}" in
|
|
54
59
|
truecolor|24bit)
|
|
55
60
|
C_ACCENT=$'\033[38;2;245;78;0m'; C_GREEN=$'\033[38;2;74;222;128m'
|
|
@@ -64,41 +69,64 @@ if [ "$TTY_OUT" -eq 1 ] && [ -z "${NO_COLOR:-}" ]; then
|
|
|
64
69
|
fi
|
|
65
70
|
|
|
66
71
|
# ---------------------------------------------------------------- the rail ----
|
|
67
|
-
# 6 steps; the ✔/◆/○ vocabulary. The rail is redrawn in place on a tty
|
|
68
|
-
#
|
|
72
|
+
# 6 steps; the ✔/◆/○ vocabulary. The rail is redrawn in place on a tty from a SAVED
|
|
73
|
+
# BUFFER of the wizard's own lines (RAIL_BUF) — never by counting the output between
|
|
74
|
+
# draws, because the installer/emit engines print freely and break naive accounting.
|
|
75
|
+
# Over a pipe nothing is saved and nothing rewinds: each screen is one numbered line.
|
|
69
76
|
STEP_LABELS=("platforms" "class" "branch/email" "first gate" "emit" "done")
|
|
70
77
|
STEP_VAL=("" "" "" "" "" "")
|
|
71
|
-
RAIL_LINES=0
|
|
72
|
-
Q_LINES=0
|
|
73
78
|
CURRENT=1
|
|
74
79
|
|
|
75
|
-
|
|
80
|
+
# rail_say: one line of wizard output on a tty — stored in the redraw buffer AND
|
|
81
|
+
# printed with a VT100 clear-line prefix (the redraw may overwrite a longer old line).
|
|
82
|
+
# Over a pipe this is exactly printf '%s\n' and nothing is stored.
|
|
83
|
+
rail_say() {
|
|
84
|
+
if [ "$TTY_OUT" -eq 1 ]; then
|
|
85
|
+
RAIL_BUF+=("$*")
|
|
86
|
+
printf '\033[2K%s\n' "$*"
|
|
87
|
+
else
|
|
88
|
+
printf '%s\n' "$*"
|
|
89
|
+
fi
|
|
90
|
+
}
|
|
91
|
+
# rail_seed: the pre-draw frame (logo + header). On a tty it only FILLS the buffer —
|
|
92
|
+
# rail_draw prints it; over a pipe nothing is buffered and it prints directly.
|
|
93
|
+
rail_seed() {
|
|
94
|
+
if [ "$TTY_OUT" -eq 1 ]; then
|
|
95
|
+
RAIL_BUF+=("$*")
|
|
96
|
+
else
|
|
97
|
+
printf '%s\n' "$*"
|
|
98
|
+
fi
|
|
99
|
+
}
|
|
100
|
+
# rail_note: a line that prints now but never joins the redraw buffer (engine output,
|
|
101
|
+
# transcripts, the verify echo): the next redraw wipes it with its clear-below.
|
|
102
|
+
rail_note() {
|
|
76
103
|
printf '%s\n' "$*"
|
|
77
|
-
Q_LINES=$((Q_LINES + 1))
|
|
78
104
|
}
|
|
79
105
|
rail_rewind() {
|
|
80
|
-
if [ "$TTY_OUT" -eq 1 ]
|
|
81
|
-
printf '\033[%dA\033[J' "$
|
|
106
|
+
if [ "$TTY_OUT" -eq 1 ]; then
|
|
107
|
+
printf '\033[%dA\033[J' "${#RAIL_BUF[@]}"
|
|
82
108
|
fi
|
|
83
|
-
RAIL_LINES=0; Q_LINES=0
|
|
84
109
|
}
|
|
85
|
-
|
|
86
|
-
local i glyph col label
|
|
110
|
+
rail_draw() { # reprint the saved buffer, then the live rail row for $CURRENT
|
|
111
|
+
local i line glyph col label
|
|
112
|
+
if [ "$TTY_OUT" -eq 0 ]; then return 0; fi
|
|
113
|
+
for line in "${RAIL_BUF[@]}"; do
|
|
114
|
+
printf '\033[2K%s\n' "$line"
|
|
115
|
+
done
|
|
87
116
|
for i in 1 2 3 4 5 6; do
|
|
88
117
|
label="${STEP_LABELS[$((i - 1))]}"
|
|
89
118
|
if [ "$i" -lt "$CURRENT" ]; then
|
|
90
|
-
|
|
119
|
+
glyph="✔"; col="$C_GREEN"
|
|
91
120
|
elif [ "$i" -eq "$CURRENT" ]; then
|
|
92
|
-
|
|
93
|
-
RAIL_LINES=$((RAIL_LINES + 1))
|
|
94
|
-
return 0 # the asking row is printed by the screen itself, after its question
|
|
121
|
+
glyph="◆"; col="$C_ACCENT"
|
|
95
122
|
else
|
|
96
|
-
|
|
123
|
+
glyph="○"; col="$C_DIM"
|
|
97
124
|
fi
|
|
98
|
-
|
|
125
|
+
printf '\033[2K %s%s %d. %-13s%s%s%s\n' "${col}${glyph}" "$C_RESET" "$i" "$label" "$C_TEXT" "${STEP_VAL[$((i - 1))]}" "$C_RESET"
|
|
99
126
|
done
|
|
100
127
|
}
|
|
101
|
-
|
|
128
|
+
rail_reset() { RAIL_BUF=(); }
|
|
129
|
+
cascade() { # the pipe-degraded shape: one numbered line per screen (zero cursor motion)
|
|
102
130
|
printf 'gob init [%d/6] %s\n' "$CURRENT" "$1"
|
|
103
131
|
}
|
|
104
132
|
|
|
@@ -108,7 +136,7 @@ ask_value() {
|
|
|
108
136
|
if [ "$TTY_IN" -eq 0 ]; then REPLY="$dflt"; return 0; fi
|
|
109
137
|
printf ' %s%s%s %s─ %s' "$C_TEXT" "$label" "$C_RESET" "$C_DIM" "$dflt"
|
|
110
138
|
read -r REPLY
|
|
111
|
-
|
|
139
|
+
rail_say ""
|
|
112
140
|
[ -n "$REPLY" ] || REPLY="$dflt"
|
|
113
141
|
return 0
|
|
114
142
|
}
|
|
@@ -146,18 +174,25 @@ TARGET=$(g_expand_tilde "$TARGET")
|
|
|
146
174
|
TARGET=$(cd "$TARGET" && pwd)
|
|
147
175
|
|
|
148
176
|
# ------------------------------------------------------------ screen 1: welcome
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
printf
|
|
152
|
-
printf '%s\n' "${C_ACCENT}▀██▀▀ ▀██▀ ██▀ ▀▀▀▀ ▀█▀ █ █ ██▀▀ ▀ █ █ ▀██▀ █ █${C_RESET}"
|
|
153
|
-
printf '%s\n' "${C_DIM} discipline around whatever executes${C_RESET}"
|
|
154
|
-
printf '\n'
|
|
155
|
-
printf '%s\n' "${C_TEXT} gob init${C_RESET} ${C_MUTED}— first-run setup (gobstack v$VERSION)${C_RESET}"
|
|
156
|
-
printf '%s\n' " ${C_MUTED}6 steps · every step has a flag · nothing is written until the plan is confirmed${C_RESET}"
|
|
157
|
-
printf '\n'
|
|
177
|
+
# The logotype and the header ride the redraw buffer (rail_say): every later screen
|
|
178
|
+
# redraws logo + header + rail as one stable frame. Over a pipe rail_say is plain
|
|
179
|
+
# printf and nothing is buffered — the cascade keeps zero cursor motion.
|
|
158
180
|
CURRENT=1
|
|
159
|
-
|
|
160
|
-
|
|
181
|
+
rail_reset
|
|
182
|
+
rail_seed "${C_ACCENT}▄███▄ ▄██▄ ██▄ █ ▄█▄ █ █ ▄██▀ █████ ▄███▄ ▄███ █ █${C_RESET}"
|
|
183
|
+
rail_seed "${C_ACCENT}█ █ █ █ █▄▀█ █ █ █▄ █ ▀██▄ █ █ █ █ █ █${C_RESET}"
|
|
184
|
+
rail_seed "${C_ACCENT}█ ▄██ █ █ █▄▀█ █ █ █ ▄█ ▄█▀ █ █████ █ ██${C_RESET}"
|
|
185
|
+
rail_seed "${C_ACCENT}▀██▀▀ ▀██▀ ██▀ ▀▀▀▀ ▀█▀ █ █ ██▀▀ ▀ █ █ ▀██▀ █ █${C_RESET}"
|
|
186
|
+
rail_seed " ${C_MUTED}discipline around whatever executes${C_RESET}"
|
|
187
|
+
rail_seed ""
|
|
188
|
+
rail_seed "${C_TEXT} gob init${C_RESET} ${C_MUTED}— first-run setup (gobstack v$VERSION)${C_RESET}"
|
|
189
|
+
rail_seed " ${C_MUTED}6 steps · every step has a flag · nothing is written until the plan is confirmed${C_RESET}"
|
|
190
|
+
rail_seed ""
|
|
191
|
+
if [ "$TTY_OUT" -eq 1 ]; then
|
|
192
|
+
rail_draw
|
|
193
|
+
else
|
|
194
|
+
cascade "welcome: gobstack v$VERSION — the guided first run"
|
|
195
|
+
fi
|
|
161
196
|
|
|
162
197
|
# Platform enum assembled from fragments (the MD_SLUG precedent): a literal tool name in
|
|
163
198
|
# bin/ trips MD-01's model-name pattern, and run-tests.sh greps this directory.
|
|
@@ -170,7 +205,7 @@ PLATFORMS="$PLA hermes copilot cursor opencode codex $GEM"
|
|
|
170
205
|
# ---------------------------------------------------------- screen 2: detect --
|
|
171
206
|
CURRENT=2
|
|
172
207
|
rail_rewind
|
|
173
|
-
if [ "$TTY_OUT" -eq 1 ]; then
|
|
208
|
+
if [ "$TTY_OUT" -eq 1 ]; then rail_draw; fi
|
|
174
209
|
DET_ROWS=""
|
|
175
210
|
DET_N=0
|
|
176
211
|
for p in $PLATFORMS; do
|
|
@@ -194,19 +229,17 @@ for p in $PLATFORMS; do
|
|
|
194
229
|
DET_N=$((DET_N + 1))
|
|
195
230
|
fi
|
|
196
231
|
done
|
|
197
|
-
STEP_VAL[0]="
|
|
232
|
+
STEP_VAL[0]="$C_DIM$DET_N detected$C_RESET"
|
|
198
233
|
if [ "$TTY_OUT" -eq 1 ]; then
|
|
199
|
-
|
|
200
|
-
|
|
234
|
+
rail_say ""
|
|
235
|
+
rail_say " ✔ 1. platforms $C_TEXT$DET_N detected$C_RESET"
|
|
201
236
|
if [ "$DET_N" -eq 0 ]; then
|
|
202
|
-
|
|
203
|
-
RAIL_LINES=$((RAIL_LINES + 1))
|
|
237
|
+
rail_say " ${C_YELLOW}no platform detected here — the wizard will still install the harness; emit later with gob emit$C_RESET"
|
|
204
238
|
else
|
|
205
239
|
while IFS=$'\t' read -r p proj glob hit; do
|
|
206
240
|
[ -n "$p" ] || continue
|
|
207
241
|
case "$glob" in "~"*) glob="${glob/\~/$HOME}" ;; esac
|
|
208
|
-
|
|
209
|
-
RAIL_LINES=$((RAIL_LINES + 1))
|
|
242
|
+
rail_say " $C_GREEN✔$C_RESET $C_TEXT$p$C_RESET $glob $C_DIM($hit)$C_RESET"
|
|
210
243
|
done <<< "$DET_ROWS"
|
|
211
244
|
fi
|
|
212
245
|
else
|
|
@@ -216,23 +249,23 @@ fi
|
|
|
216
249
|
# ------------------------------------------------------------ screen 3: class -
|
|
217
250
|
CURRENT=3
|
|
218
251
|
rail_rewind
|
|
219
|
-
if [ "$TTY_OUT" -eq 1 ]; then
|
|
252
|
+
if [ "$TTY_OUT" -eq 1 ]; then rail_draw; fi
|
|
220
253
|
CLASS_DEFAULT=1
|
|
221
254
|
if [ -z "$CLASS" ]; then
|
|
222
255
|
if [ "$TTY_IN" -eq 1 ]; then
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
256
|
+
rail_say ""
|
|
257
|
+
rail_say " ${C_MUTED}what kind of work does this repo do?$C_RESET"
|
|
258
|
+
rail_say " $C_TEXT 1 ▸ app shipped features, PRs, review gates ${C_DIM}(class A)$C_RESET"
|
|
259
|
+
rail_say " $C_TEXT 2 service backend jobs, config, unattended runs ${C_DIM}(class B)$C_RESET"
|
|
260
|
+
rail_say " $C_TEXT 3 game playable builds, perf budgets ${C_DIM}(class C)$C_RESET"
|
|
261
|
+
rail_say " $C_TEXT 4 research specs, replays, reference corpora ${C_DIM}(class D)$C_RESET"
|
|
262
|
+
rail_say " $C_TEXT 5 agent fleets, loops, unattended automation ${C_DIM}(class E)$C_RESET"
|
|
263
|
+
rail_say " $C_TEXT 6 desktop the shell you live in, perf budget ${C_DIM}(class F)$C_RESET"
|
|
264
|
+
rail_say " ${C_MUTED}↑ number + Enter · Enter = app · the class letter works too (A-F)$C_RESET"
|
|
232
265
|
printf ' '
|
|
233
266
|
read -r REPLY_CLASS
|
|
234
267
|
ASKED_ANY=1
|
|
235
|
-
|
|
268
|
+
rail_say ""
|
|
236
269
|
else
|
|
237
270
|
REPLY_CLASS="1"
|
|
238
271
|
cascade "class: app (default; --class app|service|game|research|agent|desktop or A-F)"
|
|
@@ -258,10 +291,9 @@ case "$CLASS" in
|
|
|
258
291
|
exit 2 ;;
|
|
259
292
|
esac
|
|
260
293
|
CLASS_NAME=$(ls "$SRC"/presets/"$CLASS"-*.yaml 2>/dev/null | head -n 1)
|
|
261
|
-
STEP_VAL[1]="
|
|
294
|
+
STEP_VAL[1]="$C_TEXT$CLASS ($([ -n "$CLASS_NAME" ] && basename "$CLASS_NAME" .yaml | cut -d- -f2-))$C_RESET"
|
|
262
295
|
if [ "$TTY_OUT" -eq 1 ]; then
|
|
263
|
-
|
|
264
|
-
RAIL_LINES=$((RAIL_LINES + 1))
|
|
296
|
+
rail_say " ✔ $((CURRENT - 1)). class $C_TEXT$CLASS$([ -n "$CLASS_NAME" ] && printf ' — %s' "$(basename "$CLASS_NAME" .yaml | cut -d- -f2-)")$C_RESET"
|
|
265
297
|
else
|
|
266
298
|
cascade "class: $CLASS"
|
|
267
299
|
fi
|
|
@@ -269,15 +301,15 @@ fi
|
|
|
269
301
|
# ----------------------------------------------------- screen 4: branch/email --
|
|
270
302
|
CURRENT=4
|
|
271
303
|
rail_rewind
|
|
272
|
-
if [ "$TTY_OUT" -eq 1 ]; then
|
|
304
|
+
if [ "$TTY_OUT" -eq 1 ]; then rail_draw; fi
|
|
273
305
|
DEF_BRANCH=$( cd "$TARGET" && git rev-parse --abbrev-ref HEAD 2>/dev/null )
|
|
274
306
|
case "$DEF_BRANCH" in ""|HEAD) DEF_BRANCH=main ;; esac
|
|
275
307
|
DEF_EMAIL=$( cd "$TARGET" && git config user.email 2>/dev/null )
|
|
276
308
|
[ -n "$DEF_EMAIL" ] || DEF_EMAIL="you@example.com"
|
|
277
309
|
if [ -z "$BRANCH" ] || [ -z "$EMAIL" ]; then
|
|
278
310
|
if [ "$TTY_IN" -eq 1 ]; then
|
|
279
|
-
|
|
280
|
-
|
|
311
|
+
rail_say ""
|
|
312
|
+
rail_say " ${C_MUTED}the forge contract — the identity this repo commits with (CM-01)$C_RESET"
|
|
281
313
|
ask_value "default branch" "$DEF_BRANCH"; BRANCH="${BRANCH:-$REPLY}"
|
|
282
314
|
ask_value "owner email" "$DEF_EMAIL"; EMAIL="${EMAIL:-$REPLY}"
|
|
283
315
|
else
|
|
@@ -288,29 +320,27 @@ if [ -z "$BRANCH" ] || [ -z "$EMAIL" ]; then
|
|
|
288
320
|
fi
|
|
289
321
|
BRANCH="${BRANCH:-$DEF_BRANCH}"
|
|
290
322
|
EMAIL="${EMAIL:-$DEF_EMAIL}"
|
|
291
|
-
STEP_VAL[2]="
|
|
323
|
+
STEP_VAL[2]="$C_TEXT$BRANCH · $EMAIL$C_RESET"
|
|
292
324
|
if [ "$TTY_OUT" -eq 1 ]; then
|
|
293
|
-
|
|
294
|
-
RAIL_LINES=$((RAIL_LINES + 1))
|
|
325
|
+
rail_say " ✔ $((CURRENT - 1)). branch/email $C_TEXT$BRANCH · $EMAIL$C_RESET"
|
|
295
326
|
fi
|
|
296
327
|
|
|
297
328
|
# -------------------------------------------------------- screen 5: first gate -
|
|
298
329
|
CURRENT=5
|
|
299
330
|
rail_rewind
|
|
300
|
-
if [ "$TTY_OUT" -eq 1 ]; then
|
|
331
|
+
if [ "$TTY_OUT" -eq 1 ]; then rail_draw; fi
|
|
301
332
|
GATE_DEFAULT="bash tests/run-tests.sh"
|
|
302
333
|
if [ -z "$GATE" ]; then
|
|
303
334
|
if [ "$TTY_IN" -eq 1 ]; then
|
|
304
|
-
|
|
305
|
-
|
|
335
|
+
rail_say ""
|
|
336
|
+
rail_say " ${C_MUTED}one real command that must stay green — suggested for a bash suite:$C_RESET"
|
|
306
337
|
if [ -f "$TARGET/tests/run-tests.sh" ]; then
|
|
307
|
-
|
|
338
|
+
rail_say " $C_DIM$GATE_DEFAULT$C_RESET"
|
|
308
339
|
ask_value "gate command" "$GATE_DEFAULT"; GATE="$REPLY"
|
|
309
340
|
else
|
|
310
341
|
ask_value "gate command" "true"; GATE="$REPLY"
|
|
311
342
|
if [ "$GATE" = "true" ]; then
|
|
312
|
-
|
|
313
|
-
Q_LINES=$((Q_LINES + 1))
|
|
343
|
+
rail_say " ${C_YELLOW}no tests/run-tests.sh found — a placeholder gate is allowed but it proves nothing; replace it in .goblin/goblin.yaml$C_RESET"
|
|
314
344
|
fi
|
|
315
345
|
fi
|
|
316
346
|
else
|
|
@@ -318,16 +348,15 @@ if [ -z "$GATE" ]; then
|
|
|
318
348
|
cascade "gate: $GATE (default)"
|
|
319
349
|
fi
|
|
320
350
|
fi
|
|
321
|
-
STEP_VAL[3]="
|
|
351
|
+
STEP_VAL[3]="$C_TEXT$GATE$C_RESET"
|
|
322
352
|
if [ "$TTY_OUT" -eq 1 ]; then
|
|
323
|
-
|
|
324
|
-
RAIL_LINES=$((RAIL_LINES + 1))
|
|
353
|
+
rail_say " ✔ $((CURRENT - 1)). first gate $C_TEXT$GATE$C_RESET"
|
|
325
354
|
fi
|
|
326
355
|
|
|
327
356
|
# --------------------------------------------------------- screen 6: the plan --
|
|
328
357
|
CURRENT=6
|
|
329
358
|
rail_rewind
|
|
330
|
-
if [ "$TTY_OUT" -eq 1 ]; then
|
|
359
|
+
if [ "$TTY_OUT" -eq 1 ]; then rail_draw; fi
|
|
331
360
|
|
|
332
361
|
# The emit selection: pre-tick the DETECTED platforms (in doctor's enum order).
|
|
333
362
|
EMIT_SELECTED=""
|
|
@@ -355,19 +384,19 @@ fi
|
|
|
355
384
|
EMIT_N=$(printf '%s' "$EMIT_SELECTED" | awk 'NF' | wc -l | tr -d '[:space:]')
|
|
356
385
|
|
|
357
386
|
if [ "$TTY_IN" -eq 1 ] && [ -z "$EMIT" ] && [ "$YES" -eq 0 ]; then
|
|
358
|
-
|
|
359
|
-
|
|
387
|
+
rail_say ""
|
|
388
|
+
rail_say " ${C_MUTED}emit now — the skills go into:$C_RESET"
|
|
360
389
|
for p in $PLATFORMS; do
|
|
361
390
|
hit=""
|
|
362
391
|
while IFS=$' ' read -r dp _a _b _c; do [ "$dp" = "$p" ] && hit=1; done <<< "$DET_ROWS"
|
|
363
392
|
[ -n "$hit" ] || continue
|
|
364
|
-
|
|
393
|
+
rail_say " ${C_GREEN}✔$C_RESET $C_TEXT$p$C_RESET"
|
|
365
394
|
done
|
|
366
|
-
|
|
395
|
+
rail_say " ${C_MUTED}Enter = these; or type platform names to override$C_RESET"
|
|
367
396
|
printf ' '
|
|
368
397
|
read -r REPLY_EMIT
|
|
369
398
|
ASKED_ANY=1
|
|
370
|
-
|
|
399
|
+
rail_say ""
|
|
371
400
|
if [ -n "$REPLY_EMIT" ]; then
|
|
372
401
|
EMIT_SELECTED=""
|
|
373
402
|
for w in $REPLY_EMIT; do
|
|
@@ -377,16 +406,18 @@ if [ "$TTY_IN" -eq 1 ] && [ -z "$EMIT" ] && [ "$YES" -eq 0 ]; then
|
|
|
377
406
|
done
|
|
378
407
|
fi
|
|
379
408
|
fi
|
|
380
|
-
STEP_VAL[4]="
|
|
409
|
+
STEP_VAL[4]="$C_TEXT$EMIT_N platform(s) · scope $SCOPE$C_RESET"
|
|
381
410
|
if [ "$TTY_OUT" -eq 1 ]; then
|
|
382
|
-
|
|
383
|
-
RAIL_LINES=$((RAIL_LINES + 1))
|
|
411
|
+
rail_say " ✔ $((CURRENT - 1)). emit $C_TEXT$EMIT_N platform(s) · scope $SCOPE$C_RESET"
|
|
384
412
|
fi
|
|
385
413
|
|
|
386
414
|
# ---- the plan box: the wizard never writes until this has been on the screen ----
|
|
415
|
+
# Spacing: one blank line separates the rail from the box (the spacing pass); the box
|
|
416
|
+
# carries two-space inner padding on every row so the columns align across rows.
|
|
387
417
|
BOX=""
|
|
388
418
|
add() { BOX="$BOX$1
|
|
389
419
|
"; }
|
|
420
|
+
add ""
|
|
390
421
|
add " ${C_DIM}╭──────────────────────────────────────────────────────╮${C_RESET}"
|
|
391
422
|
add " ${C_DIM}│${C_RESET} ${C_GREEN}✔${C_RESET} ${C_TEXT}install${C_RESET} $C_DIM.goblin/ + the payload into$C_RESET $C_TEXT$TARGET$C_RESET"
|
|
392
423
|
add " ${C_DIM}│${C_RESET} ${C_GREEN}✔${C_RESET} ${C_TEXT}class${C_RESET} $C_TEXT$CLASS$C_RESET ${C_DIM}· branch $C_TEXT$BRANCH$C_RESET ${C_DIM}· email$C_RESET $C_TEXT$EMAIL$C_RESET"
|
|
@@ -400,10 +431,11 @@ if [ "$DRYRUN" -eq 1 ]; then
|
|
|
400
431
|
fi
|
|
401
432
|
# A question the wizard genuinely asked (a screen that waited on read) buys the confirm;
|
|
402
433
|
# flag/non-tty runs already stated their answer as a flag — proceeding is the contract.
|
|
434
|
+
# Single-accent: the confirm prompt is muted + dim, never bold, never a second accent.
|
|
403
435
|
if [ "$YES" -eq 0 ] && [ "${ASKED_ANY:-0}" -eq 1 ]; then
|
|
404
436
|
printf '%s\n' "$BOX"
|
|
405
437
|
if [ "$TTY_IN" -eq 1 ]; then
|
|
406
|
-
printf ' %sproceed?%s %s[Enter = yes]%s ' "$
|
|
438
|
+
printf ' %sproceed?%s %s[Enter = yes]%s ' "$C_MUTED" "$C_RESET" "$C_DIM" "$C_RESET"
|
|
407
439
|
read -r REPLY_GO
|
|
408
440
|
case "$REPLY_GO" in n*|N*) g_info "aborted — nothing was written"; exit 0 ;; esac
|
|
409
441
|
else
|
|
@@ -416,7 +448,14 @@ fi
|
|
|
416
448
|
# carry: the declared identity (branch/owner_email) and the first gate, patched into
|
|
417
449
|
# .goblin/goblin.yaml right after install renders it. The patch is fail-closed — the
|
|
418
450
|
# gate must read back through the engine's own parser or the run stops here.
|
|
419
|
-
|
|
451
|
+
# rail_note, not rail_say: engine output below is never redrawn over, and the wizard
|
|
452
|
+
# never rewinds past its own buffer by counting lines it did not print.
|
|
453
|
+
if [ "$TTY_OUT" -eq 1 ]; then
|
|
454
|
+
rail_note ""
|
|
455
|
+
rail_note " ${C_MUTED}running: goblin-install --target $TARGET --class $CLASS${C_RESET}"
|
|
456
|
+
else
|
|
457
|
+
printf 'gob init [run] goblin-install --target %s --class %s\n' "$TARGET" "$CLASS"
|
|
458
|
+
fi
|
|
420
459
|
bash "$SRC/bin/goblin-install" --target "$TARGET" --class "$CLASS" --yes
|
|
421
460
|
EXIT_INSTALL=$?
|
|
422
461
|
if [ "$EXIT_INSTALL" -ne 0 ]; then
|
|
@@ -453,7 +492,11 @@ fi
|
|
|
453
492
|
|
|
454
493
|
EMITTED=0
|
|
455
494
|
for p in $EMIT_SELECTED; do
|
|
456
|
-
[ "$TTY_OUT" -eq 0 ]
|
|
495
|
+
if [ "$TTY_OUT" -eq 0 ]; then
|
|
496
|
+
printf 'gob init [run] goblin-emit --platform %s --scope %s\n' "$p" "$SCOPE"
|
|
497
|
+
else
|
|
498
|
+
rail_note " ${C_MUTED}running: goblin-emit --platform $p --scope $SCOPE${C_RESET}"
|
|
499
|
+
fi
|
|
457
500
|
bash "$SRC/bin/goblin-emit" --platform "$p" --scope "$SCOPE" --target "$TARGET"
|
|
458
501
|
EXIT_EMIT=$?
|
|
459
502
|
if [ "$EXIT_EMIT" -ne 0 ]; then
|
|
@@ -464,9 +507,9 @@ for p in $EMIT_SELECTED; do
|
|
|
464
507
|
done
|
|
465
508
|
|
|
466
509
|
# --------------------------------------------------- screen 6b: done + verify --
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
510
|
+
# Spacing pass: exactly one blank line before each done-screen section; the engine's
|
|
511
|
+
# verify output and this screen's own summary stay visually separated.
|
|
512
|
+
if [ "$TTY_OUT" -eq 0 ]; then
|
|
470
513
|
printf 'gob init [verify] .goblin/bin/goblin-verify\n'
|
|
471
514
|
fi
|
|
472
515
|
if [ "$DRYRUN" -eq 0 ]; then
|
|
@@ -494,12 +537,12 @@ if [ "$DRYRUN" -eq 0 ]; then
|
|
|
494
537
|
else
|
|
495
538
|
printf ' %sgob verify: %s passed, %s failed, %s skipped · exit %s%s\n' "$C_RED" "$PASSED" "$FAILED" "$SKIPPED" "$VERIFY_RC" "$C_RESET"
|
|
496
539
|
fi
|
|
497
|
-
printf '\n'
|
|
498
540
|
else
|
|
499
541
|
g_info "gob init [verify] exit $VERIFY_RC: $PASSED passed, $FAILED failed, $ADVISORY advisory, $SKIPPED skipped"
|
|
500
542
|
fi
|
|
501
543
|
|
|
502
|
-
printf '
|
|
544
|
+
printf '\n'
|
|
545
|
+
printf ' %snext:%s\n' "$C_MUTED" "$C_RESET"
|
|
503
546
|
printf ' 1. %sthe %s skipped checks ARE your checklist — gob verify names each one%s\n' "$C_TEXT" "$SKIPPED" "$C_RESET"
|
|
504
547
|
printf ' 2. %sreplace the placeholder gate in .goblin/goblin.yaml with your real commands (P8 step 3)%s\n' "$C_TEXT" "$C_RESET"
|
|
505
548
|
printf ' 3. %snot emitted here: gob emit --platform <p> --scope global%s\n' "$C_TEXT" "$C_RESET"
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
Script started on 2026-10-02 00:53:48+07:00 [COMMAND="bash /home/harvey/projects/goblin-stack/bin/goblin-init --target /tmp/ptyfinal/repo --yes" <not executed on terminal>]
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
[2K[91m▄███▄ ▄██▄ ██▄ █ ▄█▄ █ █ ▄██▀ █████ ▄███▄ ▄███ █ █[0m
|
|
11
|
+
[2K[91m█ █ █ █ █▄▀█ █ █ █▄ █ ▀██▄ █ █ █ █ █ █[0m
|
|
12
|
+
[2K[91m█ ▄██ █ █ █▄▀█ █ █ █ ▄█ ▄█▀ █ █████ █ ██[0m
|
|
13
|
+
[2K[91m▀██▀▀ ▀██▀ ██▀ ▀▀▀▀ ▀█▀ █ █ ██▀▀ ▀ █ █ ▀██▀ █ █[0m
|
|
14
|
+
[2K [90mdiscipline around whatever executes[0m
|
|
15
|
+
[2K
|
|
16
|
+
[2K[97m gob init[0m [90m— first-run setup (gobstack v0.4.4)[0m
|
|
17
|
+
[2K [90m6 steps · every step has a flag · nothing is written until the plan is confirmed[0m
|
|
18
|
+
[2K
|
|
19
|
+
[2K [91m◆[0m 1. platforms [97m[0m
|
|
20
|
+
[2K [90m○[0m 2. class [97m[0m
|
|
21
|
+
[2K [90m○[0m 3. branch/email [97m[0m
|
|
22
|
+
[2K [90m○[0m 4. first gate [97m[0m
|
|
23
|
+
[2K [90m○[0m 5. emit [97m[0m
|
|
24
|
+
[2K [90m○[0m 6. done [97m[0m
|
|
25
|
+
[9A[J[2K[91m▄███▄ ▄██▄ ██▄ █ ▄█▄ █ █ ▄██▀ █████ ▄███▄ ▄███ █ █[0m
|
|
26
|
+
[2K[91m█ █ █ █ █▄▀█ █ █ █▄ █ ▀██▄ █ █ █ █ █ █[0m
|
|
27
|
+
[2K[91m█ ▄██ █ █ █▄▀█ █ █ █ ▄█ ▄█▀ █ █████ █ ██[0m
|
|
28
|
+
[2K[91m▀██▀▀ ▀██▀ ██▀ ▀▀▀▀ ▀█▀ █ █ ██▀▀ ▀ █ █ ▀██▀ █ █[0m
|
|
29
|
+
[2K [90mdiscipline around whatever executes[0m
|
|
30
|
+
[2K
|
|
31
|
+
[2K[97m gob init[0m [90m— first-run setup (gobstack v0.4.4)[0m
|
|
32
|
+
[2K [90m6 steps · every step has a flag · nothing is written until the plan is confirmed[0m
|
|
33
|
+
[2K
|
|
34
|
+
[2K [92m✔[0m 1. platforms [97m[0m
|
|
35
|
+
[2K [91m◆[0m 2. class [97m[0m
|
|
36
|
+
[2K [90m○[0m 3. branch/email [97m[0m
|
|
37
|
+
[2K [90m○[0m 4. first gate [97m[0m
|
|
38
|
+
[2K [90m○[0m 5. emit [97m[0m
|
|
39
|
+
[2K [90m○[0m 6. done [97m[0m
|
|
40
|
+
[2K
|
|
41
|
+
[2K ✔ 1. platforms [97m0 detected[0m
|
|
42
|
+
[2K [93mno platform detected here — the wizard will still install the harness; emit later with gob emit[0m
|
|
43
|
+
[12A[J[2K[91m▄███▄ ▄██▄ ██▄ █ ▄█▄ █ █ ▄██▀ █████ ▄███▄ ▄███ █ █[0m
|
|
44
|
+
[2K[91m█ █ █ █ █▄▀█ █ █ █▄ █ ▀██▄ █ █ █ █ █ █[0m
|
|
45
|
+
[2K[91m█ ▄██ █ █ █▄▀█ █ █ █ ▄█ ▄█▀ █ █████ █ ██[0m
|
|
46
|
+
[2K[91m▀██▀▀ ▀██▀ ██▀ ▀▀▀▀ ▀█▀ █ █ ██▀▀ ▀ █ █ ▀██▀ █ █[0m
|
|
47
|
+
[2K [90mdiscipline around whatever executes[0m
|
|
48
|
+
[2K
|
|
49
|
+
[2K[97m gob init[0m [90m— first-run setup (gobstack v0.4.4)[0m
|
|
50
|
+
[2K [90m6 steps · every step has a flag · nothing is written until the plan is confirmed[0m
|
|
51
|
+
[2K
|
|
52
|
+
[2K
|
|
53
|
+
[2K ✔ 1. platforms [97m0 detected[0m
|
|
54
|
+
[2K [93mno platform detected here — the wizard will still install the harness; emit later with gob emit[0m
|
|
55
|
+
[2K [92m✔[0m 1. platforms [97m[90m0 detected[0m[0m
|
|
56
|
+
[2K [92m✔[0m 2. class [97m[0m
|
|
57
|
+
[2K [91m◆[0m 3. branch/email [97m[0m
|
|
58
|
+
[2K [90m○[0m 4. first gate [97m[0m
|
|
59
|
+
[2K [90m○[0m 5. emit [97m[0m
|
|
60
|
+
[2K [90m○[0m 6. done [97m[0m
|
|
61
|
+
[2K
|
|
62
|
+
[2K [90mwhat kind of work does this repo do?[0m
|
|
63
|
+
[2K [97m 1 ▸ app shipped features, PRs, review gates [90m(class A)[0m
|
|
64
|
+
[2K [97m 2 service backend jobs, config, unattended runs [90m(class B)[0m
|
|
65
|
+
[2K [97m 3 game playable builds, perf budgets [90m(class C)[0m
|
|
66
|
+
[2K [97m 4 research specs, replays, reference corpora [90m(class D)[0m
|
|
67
|
+
[2K [97m 5 agent fleets, loops, unattended automation [90m(class E)[0m
|
|
68
|
+
[2K [97m 6 desktop the shell you live in, perf budget [90m(class F)[0m
|
|
69
|
+
[2K [90m↑ number + Enter · Enter = app · the class letter works too (A-F)[0m
|
|
70
|
+
[2K
|
|
71
|
+
[2K ✔ 2. class [97mA — shipped-software[0m
|
|
72
|
+
[23A[J[2K[91m▄███▄ ▄██▄ ██▄ █ ▄█▄ █ █ ▄██▀ █████ ▄███▄ ▄███ █ █[0m
|
|
73
|
+
[2K[91m█ █ █ █ █▄▀█ █ █ █▄ █ ▀██▄ █ █ █ █ █ █[0m
|
|
74
|
+
[2K[91m█ ▄██ █ █ █▄▀█ █ █ █ ▄█ ▄█▀ █ █████ █ ██[0m
|
|
75
|
+
[2K[91m▀██▀▀ ▀██▀ ██▀ ▀▀▀▀ ▀█▀ █ █ ██▀▀ ▀ █ █ ▀██▀ █ █[0m
|
|
76
|
+
[2K [90mdiscipline around whatever executes[0m
|
|
77
|
+
[2K
|
|
78
|
+
[2K[97m gob init[0m [90m— first-run setup (gobstack v0.4.4)[0m
|
|
79
|
+
[2K [90m6 steps · every step has a flag · nothing is written until the plan is confirmed[0m
|
|
80
|
+
[2K
|
|
81
|
+
[2K
|
|
82
|
+
[2K ✔ 1. platforms [97m0 detected[0m
|
|
83
|
+
[2K [93mno platform detected here — the wizard will still install the harness; emit later with gob emit[0m
|
|
84
|
+
[2K
|
|
85
|
+
[2K [90mwhat kind of work does this repo do?[0m
|
|
86
|
+
[2K [97m 1 ▸ app shipped features, PRs, review gates [90m(class A)[0m
|
|
87
|
+
[2K [97m 2 service backend jobs, config, unattended runs [90m(class B)[0m
|
|
88
|
+
[2K [97m 3 game playable builds, perf budgets [90m(class C)[0m
|
|
89
|
+
[2K [97m 4 research specs, replays, reference corpora [90m(class D)[0m
|
|
90
|
+
[2K [97m 5 agent fleets, loops, unattended automation [90m(class E)[0m
|
|
91
|
+
[2K [97m 6 desktop the shell you live in, perf budget [90m(class F)[0m
|
|
92
|
+
[2K [90m↑ number + Enter · Enter = app · the class letter works too (A-F)[0m
|
|
93
|
+
[2K
|
|
94
|
+
[2K ✔ 2. class [97mA — shipped-software[0m
|
|
95
|
+
[2K [92m✔[0m 1. platforms [97m[90m0 detected[0m[0m
|
|
96
|
+
[2K [92m✔[0m 2. class [97m[97mA (shipped-software)[0m[0m
|
|
97
|
+
[2K [92m✔[0m 3. branch/email [97m[0m
|
|
98
|
+
[2K [91m◆[0m 4. first gate [97m[0m
|
|
99
|
+
[2K [90m○[0m 5. emit [97m[0m
|
|
100
|
+
[2K [90m○[0m 6. done [97m[0m
|
|
101
|
+
[2K
|
|
102
|
+
[2K [90mthe forge contract — the identity this repo commits with (CM-01)[0m
|
|
103
|
+
[97mdefault branch[0m [90m─ main[2K
|
|
104
|
+
[97mowner email[0m [90m─ t@t.co[2K
|
|
105
|
+
[2K ✔ 3. branch/email [97mmain · t@t.co[0m
|
|
106
|
+
[28A[J[2K[91m▄███▄ ▄██▄ ██▄ █ ▄█▄ █ █ ▄██▀ █████ ▄███▄ ▄███ █ █[0m
|
|
107
|
+
[2K[91m█ █ █ █ █▄▀█ █ █ █▄ █ ▀██▄ █ █ █ █ █ █[0m
|
|
108
|
+
[2K[91m█ ▄██ █ █ █▄▀█ █ █ █ ▄█ ▄█▀ █ █████ █ ██[0m
|
|
109
|
+
[2K[91m▀██▀▀ ▀██▀ ██▀ ▀▀▀▀ ▀█▀ █ █ ██▀▀ ▀ █ █ ▀██▀ █ █[0m
|
|
110
|
+
[2K [90mdiscipline around whatever executes[0m
|
|
111
|
+
[2K
|
|
112
|
+
[2K[97m gob init[0m [90m— first-run setup (gobstack v0.4.4)[0m
|
|
113
|
+
[2K [90m6 steps · every step has a flag · nothing is written until the plan is confirmed[0m
|
|
114
|
+
[2K
|
|
115
|
+
[2K
|
|
116
|
+
[2K ✔ 1. platforms [97m0 detected[0m
|
|
117
|
+
[2K [93mno platform detected here — the wizard will still install the harness; emit later with gob emit[0m
|
|
118
|
+
[2K
|
|
119
|
+
[2K [90mwhat kind of work does this repo do?[0m
|
|
120
|
+
[2K [97m 1 ▸ app shipped features, PRs, review gates [90m(class A)[0m
|
|
121
|
+
[2K [97m 2 service backend jobs, config, unattended runs [90m(class B)[0m
|
|
122
|
+
[2K [97m 3 game playable builds, perf budgets [90m(class C)[0m
|
|
123
|
+
[2K [97m 4 research specs, replays, reference corpora [90m(class D)[0m
|
|
124
|
+
[2K [97m 5 agent fleets, loops, unattended automation [90m(class E)[0m
|
|
125
|
+
[2K [97m 6 desktop the shell you live in, perf budget [90m(class F)[0m
|
|
126
|
+
[2K [90m↑ number + Enter · Enter = app · the class letter works too (A-F)[0m
|
|
127
|
+
[2K
|
|
128
|
+
[2K ✔ 2. class [97mA — shipped-software[0m
|
|
129
|
+
[2K
|
|
130
|
+
[2K [90mthe forge contract — the identity this repo commits with (CM-01)[0m
|
|
131
|
+
[2K
|
|
132
|
+
[2K
|
|
133
|
+
[2K ✔ 3. branch/email [97mmain · t@t.co[0m
|
|
134
|
+
[2K [92m✔[0m 1. platforms [97m[90m0 detected[0m[0m
|
|
135
|
+
[2K [92m✔[0m 2. class [97m[97mA (shipped-software)[0m[0m
|
|
136
|
+
[2K [92m✔[0m 3. branch/email [97m[97mmain · t@t.co[0m[0m
|
|
137
|
+
[2K [92m✔[0m 4. first gate [97m[0m
|
|
138
|
+
[2K [91m◆[0m 5. emit [97m[0m
|
|
139
|
+
[2K [90m○[0m 6. done [97m[0m
|
|
140
|
+
[2K
|
|
141
|
+
[2K [90mone real command that must stay green — suggested for a bash suite:[0m
|
|
142
|
+
[2K [90mbash tests/run-tests.sh[0m
|
|
143
|
+
[97mgate command[0m [90m─ bash tests/run-tests.sh[2K
|
|
144
|
+
[2K ✔ 4. first gate [97mbash tests/run-tests.sh[0m
|
|
145
|
+
[33A[J[2K[91m▄███▄ ▄██▄ ██▄ █ ▄█▄ █ █ ▄██▀ █████ ▄███▄ ▄███ █ █[0m
|
|
146
|
+
[2K[91m█ █ █ █ █▄▀█ █ █ █▄ █ ▀██▄ █ █ █ █ █ █[0m
|
|
147
|
+
[2K[91m█ ▄██ █ █ █▄▀█ █ █ █ ▄█ ▄█▀ █ █████ █ ██[0m
|
|
148
|
+
[2K[91m▀██▀▀ ▀██▀ ██▀ ▀▀▀▀ ▀█▀ █ █ ██▀▀ ▀ █ █ ▀██▀ █ █[0m
|
|
149
|
+
[2K [90mdiscipline around whatever executes[0m
|
|
150
|
+
[2K
|
|
151
|
+
[2K[97m gob init[0m [90m— first-run setup (gobstack v0.4.4)[0m
|
|
152
|
+
[2K [90m6 steps · every step has a flag · nothing is written until the plan is confirmed[0m
|
|
153
|
+
[2K
|
|
154
|
+
[2K
|
|
155
|
+
[2K ✔ 1. platforms [97m0 detected[0m
|
|
156
|
+
[2K [93mno platform detected here — the wizard will still install the harness; emit later with gob emit[0m
|
|
157
|
+
[2K
|
|
158
|
+
[2K [90mwhat kind of work does this repo do?[0m
|
|
159
|
+
[2K [97m 1 ▸ app shipped features, PRs, review gates [90m(class A)[0m
|
|
160
|
+
[2K [97m 2 service backend jobs, config, unattended runs [90m(class B)[0m
|
|
161
|
+
[2K [97m 3 game playable builds, perf budgets [90m(class C)[0m
|
|
162
|
+
[2K [97m 4 research specs, replays, reference corpora [90m(class D)[0m
|
|
163
|
+
[2K [97m 5 agent fleets, loops, unattended automation [90m(class E)[0m
|
|
164
|
+
[2K [97m 6 desktop the shell you live in, perf budget [90m(class F)[0m
|
|
165
|
+
[2K [90m↑ number + Enter · Enter = app · the class letter works too (A-F)[0m
|
|
166
|
+
[2K
|
|
167
|
+
[2K ✔ 2. class [97mA — shipped-software[0m
|
|
168
|
+
[2K
|
|
169
|
+
[2K [90mthe forge contract — the identity this repo commits with (CM-01)[0m
|
|
170
|
+
[2K
|
|
171
|
+
[2K
|
|
172
|
+
[2K ✔ 3. branch/email [97mmain · t@t.co[0m
|
|
173
|
+
[2K
|
|
174
|
+
[2K [90mone real command that must stay green — suggested for a bash suite:[0m
|
|
175
|
+
[2K [90mbash tests/run-tests.sh[0m
|
|
176
|
+
[2K
|
|
177
|
+
[2K ✔ 4. first gate [97mbash tests/run-tests.sh[0m
|
|
178
|
+
[2K [92m✔[0m 1. platforms [97m[90m0 detected[0m[0m
|
|
179
|
+
[2K [92m✔[0m 2. class [97m[97mA (shipped-software)[0m[0m
|
|
180
|
+
[2K [92m✔[0m 3. branch/email [97m[97mmain · t@t.co[0m[0m
|
|
181
|
+
[2K [92m✔[0m 4. first gate [97m[97mbash tests/run-tests.sh[0m[0m
|
|
182
|
+
[2K [92m✔[0m 5. emit [97m[0m
|
|
183
|
+
[2K [91m◆[0m 6. done [97m[0m
|
|
184
|
+
[2K ✔ 5. emit [97m0 platform(s) · scope project[0m
|
|
185
|
+
|
|
186
|
+
[90mrunning: goblin-install --target /tmp/ptyfinal/repo --class A[0m
|
|
187
|
+
created 50 · updated 0 · unchanged 0 · skipped 0
|
|
188
|
+
|
|
189
|
+
next:
|
|
190
|
+
1. cd /tmp/ptyfinal/repo && git add -A && git commit # the install is a change like any other
|
|
191
|
+
2. .goblin/bin/goblin-verify # or add .goblin/bin to PATH
|
|
192
|
+
3. edit .goblin/goblin.yaml: replace the default gate with your real commands (P8 step 3)
|
|
193
|
+
4. hermes skills trust /tmp/ptyfinal/repo # one-time, so the project-tier skills load
|
|
194
|
+
|
|
195
|
+
automations (optional; neither writes outside this repo, and A-02 has no agent in it):
|
|
196
|
+
bash /tmp/ptyfinal/repo/.goblin/automations/drift-audit.sh --dry-run # read the record first
|
|
197
|
+
cp /tmp/ptyfinal/repo/.goblin/automations/drift-audit.sh ~/.hermes/scripts/
|
|
198
|
+
hermes cron create "0 9 * * 1" --name "Drift audit - weekly" --no-agent \
|
|
199
|
+
--script drift-audit.sh --deliver <channel>
|
|
200
|
+
P13/P14 in docs/FLOWS.md; the whole model in automations/README.md
|
|
201
|
+
[92mPASS IN-01 the install record exists and names its version[0m
|
|
202
|
+
[92mPASS IN-02 41 installed files hashed[0m
|
|
203
|
+
[92mPASS IN-03 the manifest is complete: every rule carries a check or is advisory, inside the enum[0m
|
|
204
|
+
[92mPASS IN-04 0 pre-existing file(s) left untouched[0m
|
|
205
|
+
[92mPASS HP-01 (test -f HANDOFF.md)[0m
|
|
206
|
+
[92mPASS HP-02 (for h in 'START HERE' 'STATE|STATUS' 'GATES?' 'NEXT STEPS|NEXT' 'NOT VERIFIED|UNVERIFIED|NOT PROVEN|UNPROVEN|PENDING[^.]*DEVICE TEST'; do grep -qiE "^#{2,3}[[:space:]]+[^[:alpha:]]*($h)\b" HANDOFF.md || { echo "missing section: $h"; exit 1; }; done)[0m
|
|
207
|
+
[92mPASS HP-03 1 gate line(s) inside the Gates section, each with a measured date (anchored on the declared gate name(s): commit todo_ceiling)[0m
|
|
208
|
+
[93mADV HP-04 A stale sentence is corrected in place with a dated parenthetical, never deleted. (advisory)[0m
|
|
209
|
+
[92mPASS HP-05 names 3c96403 (ancestor of HEAD 3c96403)[0m
|
|
210
|
+
[92mPASS SP-01 (ls ./*-SPEC.md >/dev/null 2>&1)[0m
|
|
211
|
+
[91mFAIL SP-02 (test -z "$(git ls-files --others --exclude-standard -- '*-SPEC.md')" -> exit 1)[0m
|
|
212
|
+
[92mPASS SP-03 (awk '/^[[:space:]]*[-*][[:space:]]/ && /AC[0-9]*:/ && !/`|==|===|exit|<|>/ {print; bad=1} END{exit bad}' ./*-SPEC.md)[0m
|
|
213
|
+
[92mPASS GT-01 2 declared gate(s), each with a cmd[0m
|
|
214
|
+
[92mPASS GT-02 commit=0 todo_ceiling=0 · client_js_bytes 0 (ceiling 0) · measured 2026-10-02[0m
|
|
215
|
+
[92mPASS GT-03 (test -f .goblin/last-gate-line && [ .goblin/last-gate-line -nt "$(git rev-parse --git-dir)/logs/HEAD" ])[0m
|
|
216
|
+
[92mPASS GT-04 ratchet client_js_bytes ceiling 0[0m
|
|
217
|
+
[92mPASS GT-05 client_js_bytes 0 (ceiling 0)[0m
|
|
218
|
+
[92mPASS HS-01 not an asserting harness (report utility): gate.sh[0m
|
|
219
|
+
1 asserting harness(es), 1 report utility(ies)
|
|
220
|
+
[90mSKIP HS-02 no pinned pre-change commit yet (replay.commit empty or unknown) - REPLAY not provable[0m
|
|
221
|
+
[93mADV HS-03 Source probes read text with comments blanked first. (advisory)[0m
|
|
222
|
+
[92mPASS CM-01 (test "$(git log -1 --format='%ae')" = "$(grep '^owner_email:' .goblin/goblin.yaml | cut -d' ' -f2)")[0m
|
|
223
|
+
[93mADV CM-02 The commit message was written to a file, not passed with -m. (advisory)[0m
|
|
224
|
+
[91mFAIL CM-03 9 dirty entr(y|ies), max_dirty 0[0m
|
|
225
|
+
[92mPASS MD-01 (for d in skills manifest bin templates presets .goblin .hermes; do [ -d "$d" ] || continue; grep -rniE '(d[e]epseek|cl[a]ude|g[p]t-[0-9]|gr[o]k|g[e]mini|g[l]m-[0-9]|k[i]mi)[a-z0-9.:_-]*' "$d" && exit 1; done; exit 0)[0m
|
|
226
|
+
[93mADV MD-02 no model mapping configured (/tmp/ptyfinal/home/projects/fleet-model.yaml absent) - advisory[0m
|
|
227
|
+
[93mADV MD-03 Role-pinned fan-out goes through kanban, not a model-less subagent spawn. (advisory)[0m
|
|
228
|
+
[92mPASS PG-01 0 review note(s)[0m
|
|
229
|
+
[92mPASS PG-02 0 review note(s) classified[0m
|
|
230
|
+
[92mPASS PG-03 0 review note(s) patch-id checked[0m
|
|
231
|
+
[93mADV PG-04 Never bypass what the forge enforces. (advisory)[0m
|
|
232
|
+
[92mPASS PG-05 1 workflow file(s) checked for a self-skipping required check[0m
|
|
233
|
+
[92mPASS PG-06 goblin-gate.yml: runs the verifier, which executes every declared gate[0m
|
|
234
|
+
1 workflow file(s) compared with the 2 declared gate(s)
|
|
235
|
+
[92mPASS DS-01 unchanged: .goblin/state.json=missing[0m
|
|
236
|
+
[92mPASS DS-02 snapshot .goblin/state.json=missing[0m
|
|
237
|
+
[93mADV DOC-01 A significant change updates the docs that teach it. (advisory)[0m
|
|
238
|
+
[93mADV DOC-02 System-level changes are recorded wherever the project's standard says they live. (advisory)[0m
|
|
239
|
+
[92mPASS SK-01 [0m
|
|
240
|
+
[92mPASS SK-02 20 installed skill file(s) hashed[0m
|
|
241
|
+
[92mPASS SK-03 advisory 10 of ceiling 10 (0 free slots: the next advisory row FAILs)[0m
|
|
242
|
+
[92mPASS SK-04 [0m
|
|
243
|
+
[92mPASS PT-01 (for d in skills manifest bin templates presets .goblin .hermes; do [ -d "$d" ] || continue; grep -rniE --exclude=goblin.yaml --exclude=installed.json '(h[a]rvey|tech-g[o]blin|/h[o]me/[a-z]+|g[o]blin-ui|op[e]n-door|sup[r]eme|bb[t]ech|c[l]v)' "$d" && exit 1; done; exit 0)[0m
|
|
244
|
+
[92mPASS PT-02 declared main, actual main[0m
|
|
245
|
+
[92mPASS CL-01 part pr-gate: optional, present[0m
|
|
246
|
+
part review-panel: optional, present
|
|
247
|
+
part tokens: optional, absent
|
|
248
|
+
[92mPASS CL-02 archive: false - the full class requirement applies[0m
|
|
249
|
+
[92mPASS SC-01 0 tracked secret file(s)[0m
|
|
250
|
+
[92mPASS SC-02 the whole secret family is ignored (.env, .env.local, .env.production proved by git)[0m
|
|
251
|
+
[92mPASS SC-03 0 client-visible secret-shaped name(s); no build output to scan for clause 2[0m
|
|
252
|
+
[92mPASS SC-04 0 cookie write(s) checked; a JS-written cookie is readable by any script - reported, not failed[0m
|
|
253
|
+
[92mPASS SC-05 0 write handler(s), 0 waived; 11 dir(s) declared[0m
|
|
254
|
+
[90mSKIP SC-06 no package.json - there is no dependency manifest to lock[0m
|
|
255
|
+
[90mSKIP SC-07 no audit record yet. Run .goblin/bin/goblin-audit once, deliberately, then commit[0m
|
|
256
|
+
.goblin/audit.tsv: SC-07 reads the record and never the network
|
|
257
|
+
[90mSKIP SC-08 no package-lock.json - there is no install-hook surface to enumerate[0m
|
|
258
|
+
[93mADV SC-09 Auth is applied consistently across sibling routes. (advisory)[0m
|
|
259
|
+
[90mSKIP PF-01 no perf baseline recorded yet: run `find .next/static dist/assets dist -type f -name '*.js' -exec cat {} + 2>/dev/null | wc -c` on a pinned commit, then write[0m
|
|
260
|
+
perf.baseline_commit, perf.baseline_value, perf.measured and the matching ratchet ceiling
|
|
261
|
+
[92mPASS AU-01 2 automation producer(s) scanned, none opens with a network or forge verb[0m
|
|
262
|
+
[90mSKIP AU-02 no reports/*/report.yaml - nothing to dedup[0m
|
|
263
|
+
[90mSKIP AU-03 no reports/ - no reporter run in this repo to audit[0m
|
|
264
|
+
[92mPASS AU-04 [0m
|
|
265
|
+
[92mPASS BN-00 8 ban(s), each with an enforcement row and a named replacement[0m
|
|
266
|
+
[90mSKIP BN-01 No `any` in application TypeScript. (no matching files: src) [0m
|
|
267
|
+
[90mSKIP BN-02 No `@ts-ignore` / `@ts-expect-error` suppressions. (no matching files: src) [0m
|
|
268
|
+
[90mSKIP BN-03 No direct network call from a component. (not enabled in bans: - add BN-03 to .goblin/goblin.yaml to turn it on) [0m
|
|
269
|
+
[90mSKIP BN-05 No import across a declared layer boundary. (no matching files: src) [0m
|
|
270
|
+
[90mSKIP BN-06 No renderer with Node access (`nodeIntegration: true`). (not enabled in bans: - add BN-06 to .goblin/goblin.yaml to turn it on) [0m
|
|
271
|
+
[90mSKIP BN-07 No renderer with context isolation or the process sandbox turned off. (not enabled in bans: - add BN-07 to .goblin/goblin.yaml to turn it on) [0m
|
|
272
|
+
[90mSKIP BN-08 No dangerous webPreferences. (not enabled in bans: - add BN-08 to .goblin/goblin.yaml to turn it on) [0m
|
|
273
|
+
[90mSKIP BN-09 No synchronous IPC and no `@electron/remote`. (not enabled in bans: - add BN-09 to .goblin/goblin.yaml to turn it on) [0m
|
|
274
|
+
[90mSKIP FM-01 feature_map: is empty - no map is declared, so there is nothing to index[0m
|
|
275
|
+
[90mSKIP FM-02 feature_map: is empty - no map is declared, so there are no entry paths to resolve[0m
|
|
276
|
+
[90mSKIP VA-01 verify_doctor: is empty - no doctor is declared, so "the generated skill was executed once" is not provable here[0m
|
|
277
|
+
[90mSKIP JG-01 no loop record in this repo - no judge verdict to check[0m
|
|
278
|
+
[93mADV JG-02 no model mapping configured (/tmp/ptyfinal/home/projects/fleet-model.yaml absent) - advisory[0m
|
|
279
|
+
remedy: add a `judge:` entry beside the code lane in the file declared as models_file: in /tmp/ptyfinal/repo/.goblin/goblin.yaml
|
|
280
|
+
[93mADV JG-03 A judge lane that has never returned a non-`done` verdict is escalated. (advisory)[0m
|
|
281
|
+
[90mSKIP LP-01 no loop has run in this repo[0m
|
|
282
|
+
[90mSKIP LP-02 no loop has run in this repo[0m
|
|
283
|
+
[90mSKIP LP-03 no loop has run in this repo[0m
|
|
284
|
+
[90mSKIP LP-04 no loop has run in this repo[0m
|
|
285
|
+
[90mSKIP LP-05 no loop has run in this repo[0m
|
|
286
|
+
[90mSKIP RC-01 reference_manifest: is empty - no reference corpus is declared, so there is nothing for a build to match against[0m
|
|
287
|
+
[90mSKIP RC-02 reference_manifest: is empty - there is no manifest to shape-check (RC-01 skips for the same reason)[0m
|
|
288
|
+
[90mSKIP RC-03 no manifests/ directory - this is not a lab repo with a reference corpus, so there are no tracked bytes to check[0m
|
|
289
|
+
[90mSKIP RC-04 no manifests/*.sha256 - no acquisition record is declared, so there is none to read[0m
|
|
290
|
+
41 passed, 2 failed, 11 advisory, 28 skipped
|
|
291
|
+
of those 11 advisory: the matrix labels 10 row(s) advisory; the difference is the non-advisory row(s) reporting ADV by design (an unresolved lane) and any labelled row skipped by an opt-out
|
|
292
|
+
cannot see: whether a check in the harness dir tests the right path rather than
|
|
293
|
+
merely passing; whether the forge is bound by the workflow CL-01 found; whether a human
|
|
294
|
+
read the diff;
|
|
295
|
+
whether the model mapping names a family that actually differs (MD-02 reports it
|
|
296
|
+
and cannot change it); and whether .goblin/installed.json — the record every drift
|
|
297
|
+
check trusts — was itself rewritten. It is not signed, so one edit to it (with the
|
|
298
|
+
matching edit to the file it protects) defeats IN-02, SK-02 and HS-01 at once
|
|
299
|
+
(docs/LIMITS.md #18). The ban lane carries the same blind spot and two of its own:
|
|
300
|
+
the ban table is a manifest file under the same unsigned record, so a defanged ban
|
|
301
|
+
passes BN-00 (docs/LIMITS.md #28); a ban probe is a TEXT probe with no AST, so a
|
|
302
|
+
`Record<string, any>` is missed and a `: any` inside a string is reported
|
|
303
|
+
(docs/LIMITS.md #27); and no check here can reach a ban IN CONTEXT — the row proves
|
|
304
|
+
the forbidden path fails mechanically, never that the ban reached the agent that
|
|
305
|
+
wrote the line. The judge/loop lane adds its own: every JG-/LP- row reads a RECORD, so
|
|
306
|
+
it proves a handle, a pin, a budget and a pointer exist — never that the loop made
|
|
307
|
+
progress (a changed pointer is a proxy, docs/LIMITS.md #33), never which lane returned
|
|
308
|
+
a verdict, and never that the predicate was the right one or was really run. The CI lane
|
|
309
|
+
adds its own: PG-05 and PG-06 read a workflow's TEXT, so PG-05 sees a job whose gate step is
|
|
310
|
+
conditional and cannot see branch protection, the required-check list, or a forge that never
|
|
311
|
+
ran the job at all, and PG-06 proves a declared gate is INVOKED in a file under
|
|
312
|
+
.github/workflows/ — never that the forge marks that job required, never that it is the job
|
|
313
|
+
the forge waits on, and never that the workflow can fail (that is PG-05). A required check
|
|
314
|
+
that reports Success after skipping its gate is a green light for a commit whose gate never
|
|
315
|
+
ran (docs/CI.md). The reference-corpus lane adds its own: RC-01 matches EXACT sha256 only,
|
|
316
|
+
so a resized, recoloured or re-encoded reference asset, or copied text inside a shipped
|
|
317
|
+
string, passes it unseen; RC-02 proves the manifest is well-shaped, never that its entries
|
|
318
|
+
are the right hashes (as strong as tamper hashing, and installed.json is unsigned); RC-03
|
|
319
|
+
reads the tracked tree and cannot see a payload renamed and re-encoded; and RC-04 proves an
|
|
320
|
+
acquisition record EXISTS, never that the number beside it came from the store (HP-03's
|
|
321
|
+
defect, one artifact over). No row here reaches a reference asset in CONTEXT either.
|
|
322
|
+
engine: mode=vendored cli_sha256=2d37cf1c9f38a582ad60f3f75d2fcd53d10b743905dc3274eab6511c5c5ea008 enforcement_tsv_sha256=fd474c268b0852587c632910c503144fbcfe5e211ed2182902949a79fc5282b1
|
|
323
|
+
|
|
324
|
+
[91mgob verify: 41 passed, 2 failed, 28 skipped · exit 1[0m
|
|
325
|
+
|
|
326
|
+
[90mnext:[0m
|
|
327
|
+
1. [97mthe 28 skipped checks ARE your checklist — gob verify names each one[0m
|
|
328
|
+
2. [97mreplace the placeholder gate in .goblin/goblin.yaml with your real commands (P8 step 3)[0m
|
|
329
|
+
3. [97mnot emitted here: gob emit --platform <p> --scope global[0m
|
|
330
|
+
4. [97mhermes skills trust /tmp/ptyfinal/repo # one-time, so the project-tier skills load[0m
|
|
331
|
+
|
|
332
|
+
[91m▙ the goblin sees you. the gate is RED — start there.[0m
|
|
333
|
+
|
|
334
|
+
Script done on 2026-10-02 00:53:50+07:00 [COMMAND_EXIT_CODE="0"]
|
package/package.json
CHANGED