halfcycle 0.4.12 → 0.4.14
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/.claude-plugin/plugin.json +1 -1
- package/bin/bin.bundle.mjs +9366 -567
- package/bin/pre-tool-use-filter.sh +470 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.d.ts.map +1 -1
- package/dist/build-record/pair-io.d.ts +49 -0
- package/dist/build-record/pair-io.d.ts.map +1 -0
- package/dist/build-record/render-change.d.ts +25 -0
- package/dist/build-record/render-change.d.ts.map +1 -0
- package/dist/build-record/render-v2.d.ts +10 -5
- package/dist/build-record/render-v2.d.ts.map +1 -1
- package/dist/build-record/write-change.d.ts +63 -0
- package/dist/build-record/write-change.d.ts.map +1 -0
- package/dist/build-record/write.d.ts +5 -15
- package/dist/build-record/write.d.ts.map +1 -1
- package/dist/change.d.ts +136 -0
- package/dist/change.d.ts.map +1 -0
- package/dist/check-tasks.d.ts +71 -0
- package/dist/check-tasks.d.ts.map +1 -0
- package/dist/claude-plan.d.ts +114 -0
- package/dist/claude-plan.d.ts.map +1 -0
- package/dist/cli-contract.d.ts +12 -1
- package/dist/cli-contract.d.ts.map +1 -1
- package/dist/cli.js +9017 -5228
- package/dist/cli.js.map +3 -3
- package/dist/close-phase.d.ts +113 -10
- package/dist/close-phase.d.ts.map +1 -1
- package/dist/halfcycle-monorepo.d.ts +26 -0
- package/dist/halfcycle-monorepo.d.ts.map +1 -0
- package/dist/index.js +1617 -845
- package/dist/index.js.map +3 -3
- package/dist/install-manifest.d.ts +18 -1
- package/dist/install-manifest.d.ts.map +1 -1
- package/dist/install.d.ts +225 -3
- package/dist/install.d.ts.map +1 -1
- package/dist/merge-settings.d.ts +25 -2
- package/dist/merge-settings.d.ts.map +1 -1
- package/dist/open-phase.d.ts +1 -1
- package/dist/open-phase.d.ts.map +1 -1
- package/dist/pace.d.ts +138 -0
- package/dist/pace.d.ts.map +1 -0
- package/dist/phase-work.d.ts +37 -0
- package/dist/phase-work.d.ts.map +1 -0
- package/dist/plan.d.ts +5 -2
- package/dist/plan.d.ts.map +1 -1
- package/dist/prove.d.ts +77 -0
- package/dist/prove.d.ts.map +1 -0
- package/dist/review.d.ts +19 -1
- package/dist/review.d.ts.map +1 -1
- package/dist/system-report.d.ts +4 -4
- package/dist/system-report.d.ts.map +1 -1
- package/dist/uninstall.d.ts +4 -1
- package/dist/uninstall.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
# --- Halfcycle cheap pass before a tool runs (generated; do not edit) ---
|
|
2
|
+
# Before each tool call: when the call is one Halfcycle's check could not ask
|
|
3
|
+
# about, answer here, write the call's time line, and do not start the check.
|
|
4
|
+
# Generated from the check's own list of risky spellings; anything it is not
|
|
5
|
+
# sure of goes on to the check.
|
|
6
|
+
halfcycle_pt_skip() {
|
|
7
|
+
local hc_t=${EPOCHREALTIME:-} hc_status
|
|
8
|
+
[ "${BASH_VERSINFO[0]:-0}" -ge 5 ] || return 1
|
|
9
|
+
case $hc_t in [0-9]*[.,][0-9][0-9][0-9]*) ;; *) return 1 ;; esac
|
|
10
|
+
hc_pt_live_text= hc_pt_live_sid= hc_pt_live_agent= hc_pt_live_dir=
|
|
11
|
+
halfcycle_pt_quiet || return 1
|
|
12
|
+
halfcycle_pt_live || return 1
|
|
13
|
+
halfcycle_pt_own_copy || return 1
|
|
14
|
+
halfcycle_pt_time_line "$hc_t"
|
|
15
|
+
}
|
|
16
|
+
halfcycle_pt_live() {
|
|
17
|
+
local LC_ALL=C hc_val hc_sid hc_agent= hc_cwd hc_dir hc_file hc_text= hc_ng=0 hc_re='^[A-Za-z0-9_-]{1,128}$'
|
|
18
|
+
local -a hc_files
|
|
19
|
+
halfcycle_pt_string session_id
|
|
20
|
+
case $? in 0) hc_sid=$hc_val ;; 1) return 0 ;; *) return 1 ;; esac
|
|
21
|
+
[[ $hc_sid =~ $hc_re ]] || return 0
|
|
22
|
+
halfcycle_pt_string agent_id
|
|
23
|
+
case $? in 0) hc_agent=$hc_val ;; 1) ;; *) return 1 ;; esac
|
|
24
|
+
if [ -n "$hc_agent" ]; then
|
|
25
|
+
[[ $hc_agent =~ $hc_re ]] || return 0
|
|
26
|
+
hc_agent=-$hc_agent
|
|
27
|
+
fi
|
|
28
|
+
halfcycle_pt_string cwd
|
|
29
|
+
case $? in 0) hc_cwd=$hc_val ;; 1) return 0 ;; *) return 1 ;; esac
|
|
30
|
+
[ -n "$hc_cwd" ] || return 0
|
|
31
|
+
case $hc_cwd in *'\'*|*[$'\n\r']*) return 1 ;; esac
|
|
32
|
+
hc_dir=${TMPDIR:-/tmp}
|
|
33
|
+
while [ "${hc_dir%/}" != "$hc_dir" ]; do hc_dir=${hc_dir%/}; done
|
|
34
|
+
shopt -q nullglob && hc_ng=1
|
|
35
|
+
shopt -s nullglob
|
|
36
|
+
hc_files=("$hc_dir"/halfcycle-live-"$hc_sid"/halfcycle-session-[0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]-"$hc_sid".live"$hc_agent")
|
|
37
|
+
[ "$hc_ng" = 1 ] || shopt -u nullglob
|
|
38
|
+
[ "${#hc_files[@]}" -eq 1 ] || return 1
|
|
39
|
+
hc_file=$hc_dir/${hc_files[0]##*/}
|
|
40
|
+
IFS= read -r -d '' hc_text < "$hc_file" 2>/dev/null
|
|
41
|
+
[ "${hc_text%%$'\n'*}" = "$hc_cwd" ] || return 1
|
|
42
|
+
{ printf '%s' "$hc_text" > "$hc_file"; } 2>/dev/null || return 1
|
|
43
|
+
hc_pt_live_text=$hc_text hc_pt_live_sid=$hc_sid hc_pt_live_agent=${hc_agent#-} hc_pt_live_dir=$hc_dir
|
|
44
|
+
return 0
|
|
45
|
+
}
|
|
46
|
+
halfcycle_pt_own_copy() {
|
|
47
|
+
local LC_ALL=C hc_val hc_top hc_rest hc_d hc_f hc_text= hc_ng=0 hc_others=0
|
|
48
|
+
local -a hc_files
|
|
49
|
+
halfcycle_pt_string tool_name || return 1
|
|
50
|
+
case $hc_val in
|
|
51
|
+
Write|Edit|MultiEdit) ;;
|
|
52
|
+
*) return 0 ;;
|
|
53
|
+
esac
|
|
54
|
+
halfcycle_pt_string file_path || return 1
|
|
55
|
+
case $hc_val in /*) ;; *) return 1 ;; esac
|
|
56
|
+
case $hc_val in *'\'*|*[$'\n\r']*) return 1 ;; esac
|
|
57
|
+
hc_rest=${hc_pt_live_text#*$'\n'}
|
|
58
|
+
hc_top=${hc_rest%%$'\n'*}
|
|
59
|
+
case $hc_top in /?*) ;; *) return 1 ;; esac
|
|
60
|
+
shopt -q nullglob && hc_ng=1
|
|
61
|
+
shopt -s nullglob
|
|
62
|
+
hc_files=("$hc_pt_live_dir"/halfcycle-live-"$hc_pt_live_sid"/halfcycle-session-[0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]-"$hc_pt_live_sid".live-*)
|
|
63
|
+
[ "$hc_ng" = 1 ] || shopt -u nullglob
|
|
64
|
+
for hc_f in "${hc_files[@]}"; do
|
|
65
|
+
if [ -n "$hc_pt_live_agent" ]; then
|
|
66
|
+
case $hc_f in *.live-"$hc_pt_live_agent") continue ;; esac
|
|
67
|
+
fi
|
|
68
|
+
hc_others=1
|
|
69
|
+
done
|
|
70
|
+
case $hc_val in
|
|
71
|
+
"$hc_top"/?*) ;;
|
|
72
|
+
*) [ -z "$hc_pt_live_agent" ] && [ "$hc_others" = 0 ] && return 0; return 1 ;;
|
|
73
|
+
esac
|
|
74
|
+
hc_rest=${hc_val#"$hc_top"/}
|
|
75
|
+
case /$hc_rest/ in *//*|*/./*|*/../*) return 1 ;; esac
|
|
76
|
+
hc_d=$hc_top
|
|
77
|
+
while :; do
|
|
78
|
+
case $hc_rest in */*) ;; *) break ;; esac
|
|
79
|
+
hc_d=$hc_d/${hc_rest%%/*}
|
|
80
|
+
hc_rest=${hc_rest#*/}
|
|
81
|
+
[ -h "$hc_d" ] && return 1
|
|
82
|
+
[ -d "$hc_d" ] || break
|
|
83
|
+
{ [ -e "$hc_d/.git" ] || [ -h "$hc_d/.git" ]; } && return 1
|
|
84
|
+
done
|
|
85
|
+
[ -z "$hc_pt_live_agent" ] && return 0
|
|
86
|
+
[ "$hc_others" = 0 ] && return 0
|
|
87
|
+
shopt -q nullglob && hc_ng=1
|
|
88
|
+
shopt -s nullglob
|
|
89
|
+
hc_files=("$hc_pt_live_dir"/halfcycle-live-"$hc_pt_live_sid"/halfcycle-session-[0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]-"$hc_pt_live_sid".live)
|
|
90
|
+
[ "$hc_ng" = 1 ] || shopt -u nullglob
|
|
91
|
+
[ "${#hc_files[@]}" -eq 1 ] || return 1
|
|
92
|
+
IFS= read -r -d '' hc_text < "$hc_pt_live_dir/${hc_files[0]##*/}" 2>/dev/null
|
|
93
|
+
case $hc_text in *$'\n'*$'\n'*) ;; *) return 1 ;; esac
|
|
94
|
+
hc_text=${hc_text#*$'\n'}
|
|
95
|
+
hc_text=${hc_text%%$'\n'*}
|
|
96
|
+
[ -n "$hc_text" ] || return 1
|
|
97
|
+
[ "$hc_text" = "$hc_top" ] && return 1
|
|
98
|
+
return 0
|
|
99
|
+
}
|
|
100
|
+
halfcycle_pt_quiet() {
|
|
101
|
+
local LC_ALL=C hc_status hc_ext=0
|
|
102
|
+
shopt -q extglob && hc_ext=1
|
|
103
|
+
shopt -s nocasematch extglob
|
|
104
|
+
halfcycle_pt_quiet_input
|
|
105
|
+
hc_status=$?
|
|
106
|
+
shopt -u nocasematch
|
|
107
|
+
[ "$hc_ext" = 1 ] || shopt -u extglob
|
|
108
|
+
return $hc_status
|
|
109
|
+
}
|
|
110
|
+
halfcycle_pt_quiet_input() {
|
|
111
|
+
local hc_tool hc_val hc_c hc_w hc_q hc_a hc_marked
|
|
112
|
+
case $hc_input in '{'*'}'*) ;; *) return 1 ;; esac
|
|
113
|
+
case $hc_input in *$'\xe2\x84\xaa'*) return 1 ;; esac
|
|
114
|
+
halfcycle_pt_string tool_name || return 1
|
|
115
|
+
hc_tool=$hc_val
|
|
116
|
+
case $hc_input in *'"tool_input":{'*) ;; *) return 1 ;; esac
|
|
117
|
+
halfcycle_pt_once '"tool_input"' || return 1
|
|
118
|
+
case $hc_tool in
|
|
119
|
+
Bash)
|
|
120
|
+
halfcycle_pt_string command
|
|
121
|
+
case $? in 1) return 0 ;; 2) return 1 ;; esac
|
|
122
|
+
halfcycle_pt_normalise "$hc_val" || return 1
|
|
123
|
+
halfcycle_pt_glued && return 1
|
|
124
|
+
halfcycle_pt_words || return 1
|
|
125
|
+
halfcycle_pt_credential || return 1
|
|
126
|
+
halfcycle_pt_redirects
|
|
127
|
+
return ;;
|
|
128
|
+
Read)
|
|
129
|
+
halfcycle_pt_string file_path
|
|
130
|
+
case $? in 1) return 0 ;; 2) return 1 ;; esac
|
|
131
|
+
halfcycle_pt_normalise "$hc_val" || return 1
|
|
132
|
+
halfcycle_pt_credential
|
|
133
|
+
return ;;
|
|
134
|
+
Grep)
|
|
135
|
+
halfcycle_pt_string path
|
|
136
|
+
case $? in
|
|
137
|
+
0) halfcycle_pt_normalise "$hc_val" || return 1; halfcycle_pt_credential || return 1 ;;
|
|
138
|
+
2) return 1 ;;
|
|
139
|
+
esac
|
|
140
|
+
halfcycle_pt_string glob
|
|
141
|
+
case $? in 1) return 0 ;; 2) return 1 ;; esac
|
|
142
|
+
halfcycle_pt_normalise "$hc_val" || return 1
|
|
143
|
+
halfcycle_pt_credential
|
|
144
|
+
return ;;
|
|
145
|
+
Write|Edit|MultiEdit)
|
|
146
|
+
halfcycle_pt_string file_path
|
|
147
|
+
case $? in 1) return 0 ;; 2) return 1 ;; esac
|
|
148
|
+
case $hc_val in *'\'*) return 1 ;; esac
|
|
149
|
+
case $hc_val in /*|'~'*) ;; *) return 1 ;; esac
|
|
150
|
+
hc_c=$hc_val hc_marked=
|
|
151
|
+
halfcycle_pt_records
|
|
152
|
+
return ;;
|
|
153
|
+
*) return 1 ;;
|
|
154
|
+
esac
|
|
155
|
+
}
|
|
156
|
+
halfcycle_pt_once() {
|
|
157
|
+
local hc_rest
|
|
158
|
+
case $hc_input in *"$1"*) ;; *) return 1 ;; esac
|
|
159
|
+
hc_rest=${hc_input#*"$1"}
|
|
160
|
+
case $hc_rest in *"$1"*) return 1 ;; esac
|
|
161
|
+
return 0
|
|
162
|
+
}
|
|
163
|
+
halfcycle_pt_string() {
|
|
164
|
+
local hc_k="\"$1\"" hc_rest hc_piece hc_run hc_v=
|
|
165
|
+
hc_val=
|
|
166
|
+
case $hc_input in *"$hc_k"*) ;; *) return 1 ;; esac
|
|
167
|
+
hc_rest=${hc_input#*"$hc_k"}
|
|
168
|
+
case $hc_rest in *"$hc_k"*) return 2 ;; esac
|
|
169
|
+
case $hc_rest in ':"'*) hc_rest=${hc_rest#:\"} ;; *) return 2 ;; esac
|
|
170
|
+
while :; do
|
|
171
|
+
case $hc_rest in *'"'*) ;; *) return 2 ;; esac
|
|
172
|
+
hc_piece=${hc_rest%%\"*}
|
|
173
|
+
hc_rest=${hc_rest#*\"}
|
|
174
|
+
hc_run=${hc_piece##*[!\\]}
|
|
175
|
+
hc_v=$hc_v$hc_piece
|
|
176
|
+
case ${#hc_run} in *[13579]) hc_v=$hc_v\" ;; *) break ;; esac
|
|
177
|
+
done
|
|
178
|
+
hc_val=$hc_v
|
|
179
|
+
return 0
|
|
180
|
+
}
|
|
181
|
+
halfcycle_pt_optional() {
|
|
182
|
+
halfcycle_pt_string "$1"
|
|
183
|
+
case $? in
|
|
184
|
+
0) if [ -n "$hc_val" ]; then hc_val="\"$hc_val\""; else hc_val=null; fi ;;
|
|
185
|
+
1) hc_val=null ;;
|
|
186
|
+
*) return 1 ;;
|
|
187
|
+
esac
|
|
188
|
+
return 0
|
|
189
|
+
}
|
|
190
|
+
halfcycle_pt_normalise() {
|
|
191
|
+
local hc_v=$1 hc_m=$'\x01' hc_breaks=$' \x09\x0a\x0d\x0b\x0c;&|()<>`/$='
|
|
192
|
+
hc_w= hc_q= hc_c= hc_marked=
|
|
193
|
+
[ "${#hc_v}" -le 16384 ] || return 1
|
|
194
|
+
case $hc_v in *'\u'*|*"$hc_m"*) return 1 ;; esac
|
|
195
|
+
hc_v=${hc_v//\\\\/$hc_m}
|
|
196
|
+
hc_v=${hc_v//"$hc_m"\\n/}
|
|
197
|
+
hc_v=${hc_v//\\[nrtbf]/ }
|
|
198
|
+
hc_v=${hc_v//\\\//\/}
|
|
199
|
+
hc_v=${hc_v//\\\"/\"}
|
|
200
|
+
case $hc_v in *'\'*) return 1 ;; esac
|
|
201
|
+
case $hc_v in *"$hc_m"*) hc_marked=1 ;; esac
|
|
202
|
+
hc_q=$hc_v
|
|
203
|
+
hc_c=${hc_v//[\"\']/}
|
|
204
|
+
hc_w=" ${hc_c//[$hc_breaks]/ } "
|
|
205
|
+
hc_a=${hc_c//$hc_m/}
|
|
206
|
+
hc_a=${hc_a//[*?]/}
|
|
207
|
+
return 0
|
|
208
|
+
}
|
|
209
|
+
halfcycle_pt_glued() {
|
|
210
|
+
local hc_b=$' \x09\x0a\x0d\x0b\x0c;&|()<>`/=' hc_re
|
|
211
|
+
case $hc_c in *[A-Za-z0-9_]=*) ;; *) return 1 ;; esac
|
|
212
|
+
hc_re="[^$hc_b]\\$|}[^$hc_b\$]|\\$[A-Za-z_][A-Za-z0-9_]*[^A-Za-z0-9_$hc_b\$\\{]"
|
|
213
|
+
[[ $hc_c =~ $hc_re ]]
|
|
214
|
+
}
|
|
215
|
+
halfcycle_pt_has() {
|
|
216
|
+
if [ -n "$hc_marked" ]; then
|
|
217
|
+
[[ $hc_a == *"${1// /}"* && $hc_w == *$2* ]]
|
|
218
|
+
else
|
|
219
|
+
[[ $hc_w == *"$1"* ]]
|
|
220
|
+
fi
|
|
221
|
+
}
|
|
222
|
+
halfcycle_pt_words() {
|
|
223
|
+
halfcycle_pt_has ' rm ' $'[ \x01]?(\x01)r?(\x01)m[ \x01]' && return 1
|
|
224
|
+
halfcycle_pt_has ' unlink ' $'[ \x01]?(\x01)u?(\x01)n?(\x01)l?(\x01)i?(\x01)n?(\x01)k[ \x01]' && return 1
|
|
225
|
+
halfcycle_pt_has ' find ' $'[ \x01]?(\x01)f?(\x01)i?(\x01)n?(\x01)d[ \x01]' && { halfcycle_pt_has ' -delete ' $'[ \x01]?(\x01)-?(\x01)d?(\x01)e?(\x01)l?(\x01)e?(\x01)t?(\x01)e[ \x01]' || halfcycle_pt_has ' rm ' $'[ \x01]?(\x01)r?(\x01)m[ \x01]' || halfcycle_pt_has ' unlink ' $'[ \x01]?(\x01)u?(\x01)n?(\x01)l?(\x01)i?(\x01)n?(\x01)k[ \x01]'; } && return 1
|
|
226
|
+
halfcycle_pt_has ' git ' $'[ \x01]?(\x01)g?(\x01)i?(\x01)t[ \x01]' && halfcycle_pt_has ' rm ' $'[ \x01]?(\x01)r?(\x01)m[ \x01]' && return 1
|
|
227
|
+
halfcycle_pt_has ' git ' $'[ \x01]?(\x01)g?(\x01)i?(\x01)t[ \x01]' && halfcycle_pt_has ' reset ' $'[ \x01]?(\x01)r?(\x01)e?(\x01)s?(\x01)e?(\x01)t[ \x01]' && return 1
|
|
228
|
+
halfcycle_pt_has ' git ' $'[ \x01]?(\x01)g?(\x01)i?(\x01)t[ \x01]' && halfcycle_pt_has ' checkout ' $'[ \x01]?(\x01)c?(\x01)h?(\x01)e?(\x01)c?(\x01)k?(\x01)o?(\x01)u?(\x01)t[ \x01]' && return 1
|
|
229
|
+
halfcycle_pt_has ' git ' $'[ \x01]?(\x01)g?(\x01)i?(\x01)t[ \x01]' && halfcycle_pt_has ' switch ' $'[ \x01]?(\x01)s?(\x01)w?(\x01)i?(\x01)t?(\x01)c?(\x01)h[ \x01]' && return 1
|
|
230
|
+
halfcycle_pt_has ' git ' $'[ \x01]?(\x01)g?(\x01)i?(\x01)t[ \x01]' && halfcycle_pt_has ' restore ' $'[ \x01]?(\x01)r?(\x01)e?(\x01)s?(\x01)t?(\x01)o?(\x01)r?(\x01)e[ \x01]' && return 1
|
|
231
|
+
halfcycle_pt_has ' git ' $'[ \x01]?(\x01)g?(\x01)i?(\x01)t[ \x01]' && halfcycle_pt_has ' clean ' $'[ \x01]?(\x01)c?(\x01)l?(\x01)e?(\x01)a?(\x01)n[ \x01]' && return 1
|
|
232
|
+
halfcycle_pt_has ' git ' $'[ \x01]?(\x01)g?(\x01)i?(\x01)t[ \x01]' && halfcycle_pt_has ' stash ' $'[ \x01]?(\x01)s?(\x01)t?(\x01)a?(\x01)s?(\x01)h[ \x01]' && { halfcycle_pt_has ' drop ' $'[ \x01]?(\x01)d?(\x01)r?(\x01)o?(\x01)p[ \x01]' || halfcycle_pt_has ' clear ' $'[ \x01]?(\x01)c?(\x01)l?(\x01)e?(\x01)a?(\x01)r[ \x01]'; } && return 1
|
|
233
|
+
halfcycle_pt_has ' git ' $'[ \x01]?(\x01)g?(\x01)i?(\x01)t[ \x01]' && halfcycle_pt_has ' worktree ' $'[ \x01]?(\x01)w?(\x01)o?(\x01)r?(\x01)k?(\x01)t?(\x01)r?(\x01)e?(\x01)e[ \x01]' && halfcycle_pt_has ' remove ' $'[ \x01]?(\x01)r?(\x01)e?(\x01)m?(\x01)o?(\x01)v?(\x01)e[ \x01]' && return 1
|
|
234
|
+
halfcycle_pt_has ' git ' $'[ \x01]?(\x01)g?(\x01)i?(\x01)t[ \x01]' && halfcycle_pt_has ' push ' $'[ \x01]?(\x01)p?(\x01)u?(\x01)s?(\x01)h[ \x01]' && return 1
|
|
235
|
+
halfcycle_pt_has ' git ' $'[ \x01]?(\x01)g?(\x01)i?(\x01)t[ \x01]' && halfcycle_pt_has ' branch ' $'[ \x01]?(\x01)b?(\x01)r?(\x01)a?(\x01)n?(\x01)c?(\x01)h[ \x01]' && return 1
|
|
236
|
+
halfcycle_pt_has ' psql ' $'[ \x01]?(\x01)p?(\x01)s?(\x01)q?(\x01)l[ \x01]' && return 1
|
|
237
|
+
halfcycle_pt_has ' mysql ' $'[ \x01]?(\x01)m?(\x01)y?(\x01)s?(\x01)q?(\x01)l[ \x01]' && return 1
|
|
238
|
+
halfcycle_pt_has ' mariadb ' $'[ \x01]?(\x01)m?(\x01)a?(\x01)r?(\x01)i?(\x01)a?(\x01)d?(\x01)b[ \x01]' && return 1
|
|
239
|
+
halfcycle_pt_has ' sqlite3 ' $'[ \x01]?(\x01)s?(\x01)q?(\x01)l?(\x01)i?(\x01)t?(\x01)e?(\x01)3[ \x01]' && return 1
|
|
240
|
+
halfcycle_pt_has ' dropdb ' $'[ \x01]?(\x01)d?(\x01)r?(\x01)o?(\x01)p?(\x01)d?(\x01)b[ \x01]' && return 1
|
|
241
|
+
halfcycle_pt_has ' redis-cli ' $'[ \x01]?(\x01)r?(\x01)e?(\x01)d?(\x01)i?(\x01)s?(\x01)-?(\x01)c?(\x01)l?(\x01)i[ \x01]' && return 1
|
|
242
|
+
halfcycle_pt_has ' prisma ' $'[ \x01]?(\x01)p?(\x01)r?(\x01)i?(\x01)s?(\x01)m?(\x01)a[ \x01]' && return 1
|
|
243
|
+
halfcycle_pt_has ' rails ' $'[ \x01]?(\x01)r?(\x01)a?(\x01)i?(\x01)l?(\x01)s[ \x01]' && return 1
|
|
244
|
+
halfcycle_pt_has ' rake ' $'[ \x01]?(\x01)r?(\x01)a?(\x01)k?(\x01)e[ \x01]' && return 1
|
|
245
|
+
halfcycle_pt_has ' bundle ' $'[ \x01]?(\x01)b?(\x01)u?(\x01)n?(\x01)d?(\x01)l?(\x01)e[ \x01]' && return 1
|
|
246
|
+
halfcycle_pt_has ' auth ' $'[ \x01]?(\x01)a?(\x01)u?(\x01)t?(\x01)h[ \x01]' && return 1
|
|
247
|
+
halfcycle_pt_has ' find-generic-password ' $'[ \x01]?(\x01)f?(\x01)i?(\x01)n?(\x01)d?(\x01)-?(\x01)g?(\x01)e?(\x01)n?(\x01)e?(\x01)r?(\x01)i?(\x01)c?(\x01)-?(\x01)p?(\x01)a?(\x01)s?(\x01)s?(\x01)w?(\x01)o?(\x01)r?(\x01)d[ \x01]' && return 1
|
|
248
|
+
halfcycle_pt_has ' find-internet-password ' $'[ \x01]?(\x01)f?(\x01)i?(\x01)n?(\x01)d?(\x01)-?(\x01)i?(\x01)n?(\x01)t?(\x01)e?(\x01)r?(\x01)n?(\x01)e?(\x01)t?(\x01)-?(\x01)p?(\x01)a?(\x01)s?(\x01)s?(\x01)w?(\x01)o?(\x01)r?(\x01)d[ \x01]' && return 1
|
|
249
|
+
halfcycle_pt_has ' publish ' $'[ \x01]?(\x01)p?(\x01)u?(\x01)b?(\x01)l?(\x01)i?(\x01)s?(\x01)h[ \x01]' && return 1
|
|
250
|
+
halfcycle_pt_has ' npm ' $'[ \x01]?(\x01)n?(\x01)p?(\x01)m[ \x01]' && halfcycle_pt_has ' publish ' $'[ \x01]?(\x01)p?(\x01)u?(\x01)b?(\x01)l?(\x01)i?(\x01)s?(\x01)h[ \x01]' && return 1
|
|
251
|
+
halfcycle_pt_has ' upload ' $'[ \x01]?(\x01)u?(\x01)p?(\x01)l?(\x01)o?(\x01)a?(\x01)d[ \x01]' && return 1
|
|
252
|
+
halfcycle_pt_has ' push ' $'[ \x01]?(\x01)p?(\x01)u?(\x01)s?(\x01)h[ \x01]' && return 1
|
|
253
|
+
halfcycle_pt_has ' release ' $'[ \x01]?(\x01)r?(\x01)e?(\x01)l?(\x01)e?(\x01)a?(\x01)s?(\x01)e[ \x01]' && halfcycle_pt_has ' create ' $'[ \x01]?(\x01)c?(\x01)r?(\x01)e?(\x01)a?(\x01)t?(\x01)e[ \x01]' && return 1
|
|
254
|
+
halfcycle_pt_has ' nuget ' $'[ \x01]?(\x01)n?(\x01)u?(\x01)g?(\x01)e?(\x01)t[ \x01]' && halfcycle_pt_has ' push ' $'[ \x01]?(\x01)p?(\x01)u?(\x01)s?(\x01)h[ \x01]' && return 1
|
|
255
|
+
halfcycle_pt_has ' deploy ' $'[ \x01]?(\x01)d?(\x01)e?(\x01)p?(\x01)l?(\x01)o?(\x01)y[ \x01]' && return 1
|
|
256
|
+
halfcycle_pt_has ' apply ' $'[ \x01]?(\x01)a?(\x01)p?(\x01)p?(\x01)l?(\x01)y[ \x01]' && return 1
|
|
257
|
+
halfcycle_pt_has ' destroy ' $'[ \x01]?(\x01)d?(\x01)e?(\x01)s?(\x01)t?(\x01)r?(\x01)o?(\x01)y[ \x01]' && return 1
|
|
258
|
+
halfcycle_pt_has ' delete ' $'[ \x01]?(\x01)d?(\x01)e?(\x01)l?(\x01)e?(\x01)t?(\x01)e[ \x01]' && return 1
|
|
259
|
+
halfcycle_pt_has ' --prod ' $'[ \x01]?(\x01)-?(\x01)-?(\x01)p?(\x01)r?(\x01)o?(\x01)d[ \x01]' && return 1
|
|
260
|
+
halfcycle_pt_has ' --production ' $'[ \x01]?(\x01)-?(\x01)-?(\x01)p?(\x01)r?(\x01)o?(\x01)d?(\x01)u?(\x01)c?(\x01)t?(\x01)i?(\x01)o?(\x01)n[ \x01]' && return 1
|
|
261
|
+
halfcycle_pt_has ' truncate ' $'[ \x01]?(\x01)t?(\x01)r?(\x01)u?(\x01)n?(\x01)c?(\x01)a?(\x01)t?(\x01)e[ \x01]' && return 1
|
|
262
|
+
halfcycle_pt_has ' cp ' $'[ \x01]?(\x01)c?(\x01)p[ \x01]' && halfcycle_pt_has ' dev ' $'[ \x01]?(\x01)d?(\x01)e?(\x01)v[ \x01]' && halfcycle_pt_has ' null ' $'[ \x01]?(\x01)n?(\x01)u?(\x01)l?(\x01)l[ \x01]' && return 1
|
|
263
|
+
return 0
|
|
264
|
+
}
|
|
265
|
+
halfcycle_pt_in() {
|
|
266
|
+
if [ -n "$hc_marked" ]; then
|
|
267
|
+
[[ $hc_a == *"${1// /}"* && ( $hc_x == *$2* || $hc_y == *$2* ) ]] ||
|
|
268
|
+
[[ ${hc_y//$'\x01'/} == *"${1// /}"* && $hc_y == *$2* ]]
|
|
269
|
+
else
|
|
270
|
+
[[ $hc_x == *"$1"* || $hc_y == *"$1"* ]]
|
|
271
|
+
fi
|
|
272
|
+
}
|
|
273
|
+
halfcycle_pt_credential() {
|
|
274
|
+
local hc_x=${hc_w//[*?]/} hc_y=${hc_w//[*?]/x}
|
|
275
|
+
halfcycle_pt_in ' .env' $'[ \x01]?(\x01).?(\x01)e?(\x01)n?(\x01)v' && return 1
|
|
276
|
+
halfcycle_pt_in ' id_rsa' $'[ \x01]?(\x01)i?(\x01)d?(\x01)_?(\x01)r?(\x01)s?(\x01)a' && return 1
|
|
277
|
+
halfcycle_pt_in ' id_ed25519' $'[ \x01]?(\x01)i?(\x01)d?(\x01)_?(\x01)e?(\x01)d?(\x01)2?(\x01)5?(\x01)5?(\x01)1?(\x01)9' && return 1
|
|
278
|
+
halfcycle_pt_in ' id_ecdsa' $'[ \x01]?(\x01)i?(\x01)d?(\x01)_?(\x01)e?(\x01)c?(\x01)d?(\x01)s?(\x01)a' && return 1
|
|
279
|
+
halfcycle_pt_in ' service-account' $'[ \x01]?(\x01)s?(\x01)e?(\x01)r?(\x01)v?(\x01)i?(\x01)c?(\x01)e?(\x01)-?(\x01)a?(\x01)c?(\x01)c?(\x01)o?(\x01)u?(\x01)n?(\x01)t' && return 1
|
|
280
|
+
halfcycle_pt_in '.pem ' $'.?(\x01)p?(\x01)e?(\x01)m[ \x01]' && return 1
|
|
281
|
+
halfcycle_pt_in '.key ' $'.?(\x01)k?(\x01)e?(\x01)y[ \x01]' && return 1
|
|
282
|
+
halfcycle_pt_in '.p12 ' $'.?(\x01)p?(\x01)1?(\x01)2[ \x01]' && return 1
|
|
283
|
+
halfcycle_pt_in '.pfx ' $'.?(\x01)p?(\x01)f?(\x01)x[ \x01]' && return 1
|
|
284
|
+
halfcycle_pt_in ' .netrc ' $'[ \x01]?(\x01).?(\x01)n?(\x01)e?(\x01)t?(\x01)r?(\x01)c[ \x01]' && return 1
|
|
285
|
+
halfcycle_pt_in ' .npmrc ' $'[ \x01]?(\x01).?(\x01)n?(\x01)p?(\x01)m?(\x01)r?(\x01)c[ \x01]' && return 1
|
|
286
|
+
halfcycle_pt_in ' .pypirc ' $'[ \x01]?(\x01).?(\x01)p?(\x01)y?(\x01)p?(\x01)i?(\x01)r?(\x01)c[ \x01]' && return 1
|
|
287
|
+
halfcycle_pt_in ' credentials.json ' $'[ \x01]?(\x01)c?(\x01)r?(\x01)e?(\x01)d?(\x01)e?(\x01)n?(\x01)t?(\x01)i?(\x01)a?(\x01)l?(\x01)s?(\x01).?(\x01)j?(\x01)s?(\x01)o?(\x01)n[ \x01]' && return 1
|
|
288
|
+
halfcycle_pt_in ' .credentials.json ' $'[ \x01]?(\x01).?(\x01)c?(\x01)r?(\x01)e?(\x01)d?(\x01)e?(\x01)n?(\x01)t?(\x01)i?(\x01)a?(\x01)l?(\x01)s?(\x01).?(\x01)j?(\x01)s?(\x01)o?(\x01)n[ \x01]' && return 1
|
|
289
|
+
halfcycle_pt_in ' .aws ' $'[ \x01]?(\x01).?(\x01)a?(\x01)w?(\x01)s[ \x01]' && halfcycle_pt_in ' credentials ' $'[ \x01]?(\x01)c?(\x01)r?(\x01)e?(\x01)d?(\x01)e?(\x01)n?(\x01)t?(\x01)i?(\x01)a?(\x01)l?(\x01)s[ \x01]' && return 1
|
|
290
|
+
halfcycle_pt_in ' .docker ' $'[ \x01]?(\x01).?(\x01)d?(\x01)o?(\x01)c?(\x01)k?(\x01)e?(\x01)r[ \x01]' && halfcycle_pt_in ' config.json ' $'[ \x01]?(\x01)c?(\x01)o?(\x01)n?(\x01)f?(\x01)i?(\x01)g?(\x01).?(\x01)j?(\x01)s?(\x01)o?(\x01)n[ \x01]' && return 1
|
|
291
|
+
halfcycle_pt_in ' .config ' $'[ \x01]?(\x01).?(\x01)c?(\x01)o?(\x01)n?(\x01)f?(\x01)i?(\x01)g[ \x01]' && halfcycle_pt_in ' gh ' $'[ \x01]?(\x01)g?(\x01)h[ \x01]' && halfcycle_pt_in ' hosts.yml ' $'[ \x01]?(\x01)h?(\x01)o?(\x01)s?(\x01)t?(\x01)s?(\x01).?(\x01)y?(\x01)m?(\x01)l[ \x01]' && return 1
|
|
292
|
+
halfcycle_pt_in ' .halfcycle ' $'[ \x01]?(\x01).?(\x01)h?(\x01)a?(\x01)l?(\x01)f?(\x01)c?(\x01)y?(\x01)c?(\x01)l?(\x01)e[ \x01]' && halfcycle_pt_in ' account.json ' $'[ \x01]?(\x01)a?(\x01)c?(\x01)c?(\x01)o?(\x01)u?(\x01)n?(\x01)t?(\x01).?(\x01)j?(\x01)s?(\x01)o?(\x01)n[ \x01]' && return 1
|
|
293
|
+
halfcycle_pt_in ' .halfcycle ' $'[ \x01]?(\x01).?(\x01)h?(\x01)a?(\x01)l?(\x01)f?(\x01)c?(\x01)y?(\x01)c?(\x01)l?(\x01)e[ \x01]' && halfcycle_pt_in ' engagements ' $'[ \x01]?(\x01)e?(\x01)n?(\x01)g?(\x01)a?(\x01)g?(\x01)e?(\x01)m?(\x01)e?(\x01)n?(\x01)t?(\x01)s[ \x01]' && halfcycle_pt_in ' env ' $'[ \x01]?(\x01)e?(\x01)n?(\x01)v[ \x01]' && return 1
|
|
294
|
+
return 0
|
|
295
|
+
}
|
|
296
|
+
halfcycle_pt_holds() {
|
|
297
|
+
if [ -n "$hc_marked" ]; then
|
|
298
|
+
[[ $hc_a == *"$1"* && $hc_c == *$2* ]]
|
|
299
|
+
else
|
|
300
|
+
[[ $hc_c == *"$1"* ]]
|
|
301
|
+
fi
|
|
302
|
+
}
|
|
303
|
+
halfcycle_pt_records() {
|
|
304
|
+
halfcycle_pt_holds 'ENGAGEMENT.md' $'E?(\x01)N?(\x01)G?(\x01)A?(\x01)G?(\x01)E?(\x01)M?(\x01)E?(\x01)N?(\x01)T?(\x01).?(\x01)m?(\x01)d' && return 1
|
|
305
|
+
halfcycle_pt_holds 'project-log.md' $'p?(\x01)r?(\x01)o?(\x01)j?(\x01)e?(\x01)c?(\x01)t?(\x01)-?(\x01)l?(\x01)o?(\x01)g?(\x01).?(\x01)m?(\x01)d' && return 1
|
|
306
|
+
halfcycle_pt_holds 'product-spec.md' $'p?(\x01)r?(\x01)o?(\x01)d?(\x01)u?(\x01)c?(\x01)t?(\x01)-?(\x01)s?(\x01)p?(\x01)e?(\x01)c?(\x01).?(\x01)m?(\x01)d' && return 1
|
|
307
|
+
halfcycle_pt_holds 'architecture-overview.md' $'a?(\x01)r?(\x01)c?(\x01)h?(\x01)i?(\x01)t?(\x01)e?(\x01)c?(\x01)t?(\x01)u?(\x01)r?(\x01)e?(\x01)-?(\x01)o?(\x01)v?(\x01)e?(\x01)r?(\x01)v?(\x01)i?(\x01)e?(\x01)w?(\x01).?(\x01)m?(\x01)d' && return 1
|
|
308
|
+
halfcycle_pt_holds 'invariants.md' $'i?(\x01)n?(\x01)v?(\x01)a?(\x01)r?(\x01)i?(\x01)a?(\x01)n?(\x01)t?(\x01)s?(\x01).?(\x01)m?(\x01)d' && return 1
|
|
309
|
+
halfcycle_pt_holds 'system.json' $'s?(\x01)y?(\x01)s?(\x01)t?(\x01)e?(\x01)m?(\x01).?(\x01)j?(\x01)s?(\x01)o?(\x01)n' && return 1
|
|
310
|
+
halfcycle_pt_holds 'phases' $'p?(\x01)h?(\x01)a?(\x01)s?(\x01)e?(\x01)s' && return 1
|
|
311
|
+
halfcycle_pt_holds 'features' $'f?(\x01)e?(\x01)a?(\x01)t?(\x01)u?(\x01)r?(\x01)e?(\x01)s' && return 1
|
|
312
|
+
halfcycle_pt_holds 'decisions' $'d?(\x01)e?(\x01)c?(\x01)i?(\x01)s?(\x01)i?(\x01)o?(\x01)n?(\x01)s' && return 1
|
|
313
|
+
halfcycle_pt_holds 'build-tasks.json' $'b?(\x01)u?(\x01)i?(\x01)l?(\x01)d?(\x01)-?(\x01)t?(\x01)a?(\x01)s?(\x01)k?(\x01)s?(\x01).?(\x01)j?(\x01)s?(\x01)o?(\x01)n' && return 1
|
|
314
|
+
halfcycle_pt_holds 'task-plan.json' $'t?(\x01)a?(\x01)s?(\x01)k?(\x01)-?(\x01)p?(\x01)l?(\x01)a?(\x01)n?(\x01).?(\x01)j?(\x01)s?(\x01)o?(\x01)n' && return 1
|
|
315
|
+
halfcycle_pt_holds 'build-records' $'b?(\x01)u?(\x01)i?(\x01)l?(\x01)d?(\x01)-?(\x01)r?(\x01)e?(\x01)c?(\x01)o?(\x01)r?(\x01)d?(\x01)s' && return 1
|
|
316
|
+
halfcycle_pt_holds '.claude' $'.?(\x01)c?(\x01)l?(\x01)a?(\x01)u?(\x01)d?(\x01)e' && return 1
|
|
317
|
+
return 0
|
|
318
|
+
}
|
|
319
|
+
halfcycle_pt_redirects() {
|
|
320
|
+
local hc_s=$hc_c hc_rest hc_pre hc_qc hc_body hc_abs= hc_bt=$'\x60'
|
|
321
|
+
case $hc_c in *'>'*) ;; *) return 0 ;; esac
|
|
322
|
+
if [ -z "$hc_marked" ] && ! { halfcycle_pt_has ' bash ' $'[ \x01]?(\x01)b?(\x01)a?(\x01)s?(\x01)h[ \x01]' || halfcycle_pt_has ' sh ' $'[ \x01]?(\x01)s?(\x01)h[ \x01]' || halfcycle_pt_has ' zsh ' $'[ \x01]?(\x01)z?(\x01)s?(\x01)h[ \x01]' || halfcycle_pt_has ' dash ' $'[ \x01]?(\x01)d?(\x01)a?(\x01)s?(\x01)h[ \x01]' || halfcycle_pt_has ' ksh ' $'[ \x01]?(\x01)k?(\x01)s?(\x01)h[ \x01]' || halfcycle_pt_has ' eval ' $'[ \x01]?(\x01)e?(\x01)v?(\x01)a?(\x01)l[ \x01]' || halfcycle_pt_has ' -S ' $'[ \x01]?(\x01)-?(\x01)S[ \x01]' || halfcycle_pt_has ' --split-string ' $'[ \x01]?(\x01)-?(\x01)-?(\x01)s?(\x01)p?(\x01)l?(\x01)i?(\x01)t?(\x01)-?(\x01)s?(\x01)t?(\x01)r?(\x01)i?(\x01)n?(\x01)g[ \x01]'; }; then
|
|
323
|
+
case $hc_q in *'<<'*|*'${'*|*'$(('*) ;; *)
|
|
324
|
+
case " $hc_q" in *[[:space:]\;\&\|\(\)$hc_bt]'#'*) ;; *)
|
|
325
|
+
hc_s= hc_rest=$hc_q
|
|
326
|
+
while :; do
|
|
327
|
+
case $hc_rest in *[\"\']*) ;; *) hc_s=$hc_s$hc_rest; break ;; esac
|
|
328
|
+
hc_pre=${hc_rest%%[\"\']*}
|
|
329
|
+
hc_rest=${hc_rest:${#hc_pre}}
|
|
330
|
+
hc_qc=${hc_rest:0:1}
|
|
331
|
+
hc_rest=${hc_rest:1}
|
|
332
|
+
case $hc_rest in *"$hc_qc"*) ;; *) return 1 ;; esac
|
|
333
|
+
hc_body=${hc_rest%%"$hc_qc"*}
|
|
334
|
+
hc_rest=${hc_rest#*"$hc_qc"}
|
|
335
|
+
case $hc_qc$hc_body in '"'*'$('*|'"'*"$hc_bt"*) hc_s=$hc_c; break ;; esac
|
|
336
|
+
hc_s=$hc_s$hc_pre${hc_body//'>'/}
|
|
337
|
+
done
|
|
338
|
+
;;
|
|
339
|
+
esac
|
|
340
|
+
;;
|
|
341
|
+
esac
|
|
342
|
+
fi
|
|
343
|
+
while :; do
|
|
344
|
+
case $hc_s in *'>'*) ;; *) break ;; esac
|
|
345
|
+
hc_s=${hc_s#*'>'}
|
|
346
|
+
case $hc_s in
|
|
347
|
+
'>'*) hc_s=${hc_s#'>'}; continue ;;
|
|
348
|
+
'&'*|'('*) continue ;;
|
|
349
|
+
'|'*) hc_s=${hc_s#'|'} ;;
|
|
350
|
+
esac
|
|
351
|
+
hc_pre=${hc_s%%[![:space:]]*}
|
|
352
|
+
hc_pre=${hc_s:${#hc_pre}}
|
|
353
|
+
case $hc_pre in /*|'~'*) hc_abs=1 ;; *) return 1 ;; esac
|
|
354
|
+
done
|
|
355
|
+
[ -z "$hc_abs" ] && return 0
|
|
356
|
+
halfcycle_pt_records
|
|
357
|
+
}
|
|
358
|
+
halfcycle_pt_resolve() {
|
|
359
|
+
local - IFS=/ hc_part hc_out=
|
|
360
|
+
local -a hc_parts
|
|
361
|
+
set -f
|
|
362
|
+
hc_parts=($1)
|
|
363
|
+
for hc_part in "${hc_parts[@]}"; do
|
|
364
|
+
case $hc_part in
|
|
365
|
+
''|.) ;;
|
|
366
|
+
..) hc_out=${hc_out%/*} ;;
|
|
367
|
+
*) hc_out=$hc_out/$hc_part ;;
|
|
368
|
+
esac
|
|
369
|
+
done
|
|
370
|
+
hc_path=${hc_out:-/}
|
|
371
|
+
}
|
|
372
|
+
halfcycle_pt_branch() {
|
|
373
|
+
local hc_dir hc_dotgit hc_gitdir hc_text hc_line hc_ptr hc_path
|
|
374
|
+
hc_branch=null
|
|
375
|
+
case $1 in /*) ;; *) return 0 ;; esac
|
|
376
|
+
hc_dir=$1
|
|
377
|
+
while [ -n "$hc_dir" ] && [ "$hc_dir" != / ]; do
|
|
378
|
+
[ -L "$hc_dir" ] && return 1
|
|
379
|
+
hc_dir=${hc_dir%/*}
|
|
380
|
+
done
|
|
381
|
+
halfcycle_pt_resolve "$1"
|
|
382
|
+
hc_dir=$hc_path
|
|
383
|
+
[ -d "$hc_dir" ] || return 0
|
|
384
|
+
while :; do
|
|
385
|
+
hc_dotgit=${hc_dir%/}/.git
|
|
386
|
+
if [ -e "$hc_dotgit" ]; then
|
|
387
|
+
if [ -d "$hc_dotgit" ]; then
|
|
388
|
+
hc_gitdir=$hc_dotgit
|
|
389
|
+
else
|
|
390
|
+
hc_text=
|
|
391
|
+
IFS= read -r -d '' hc_text < "$hc_dotgit" 2>/dev/null
|
|
392
|
+
hc_ptr=
|
|
393
|
+
while IFS= read -r hc_line || [ -n "$hc_line" ]; do
|
|
394
|
+
case $hc_line in
|
|
395
|
+
gitdir:*)
|
|
396
|
+
hc_line=${hc_line#gitdir:}
|
|
397
|
+
hc_line=${hc_line#"${hc_line%%[!$' \t']*}"}
|
|
398
|
+
hc_line=${hc_line%"${hc_line##*[!$' \t']}"}
|
|
399
|
+
[ -n "$hc_line" ] && { hc_ptr=$hc_line; break; }
|
|
400
|
+
;;
|
|
401
|
+
esac
|
|
402
|
+
done <<< "$hc_text"
|
|
403
|
+
[ -n "$hc_ptr" ] || return 0
|
|
404
|
+
case $hc_ptr in /*) halfcycle_pt_resolve "$hc_ptr" ;; *) halfcycle_pt_resolve "$hc_dir/$hc_ptr" ;; esac
|
|
405
|
+
hc_gitdir=$hc_path
|
|
406
|
+
fi
|
|
407
|
+
hc_text=
|
|
408
|
+
IFS= read -r -d '' hc_text < "$hc_gitdir/HEAD" 2>/dev/null || [ -n "$hc_text" ] || return 0
|
|
409
|
+
case $hc_text in *[!$'\x01'-$'\x7f']*) return 1 ;; esac
|
|
410
|
+
hc_text=${hc_text#"${hc_text%%[![:space:]]*}"}
|
|
411
|
+
hc_text=${hc_text%"${hc_text##*[![:space:]]}"}
|
|
412
|
+
case $hc_text in ref:*) ;; *) return 0 ;; esac
|
|
413
|
+
hc_text=${hc_text#ref:}
|
|
414
|
+
hc_text=${hc_text#"${hc_text%%[!$' \t']*}"}
|
|
415
|
+
case $hc_text in refs/heads/?*) ;; *) return 0 ;; esac
|
|
416
|
+
hc_text=${hc_text#refs/heads/}
|
|
417
|
+
case $hc_text in *[$'\n\r']*) return 0 ;; esac
|
|
418
|
+
case $hc_text in *[$'\x01'-$'\x1f']*) return 1 ;; esac
|
|
419
|
+
hc_text=${hc_text//\\/\\\\}
|
|
420
|
+
hc_text=${hc_text//\"/\\\"}
|
|
421
|
+
hc_branch="\"$hc_text\""
|
|
422
|
+
return 0
|
|
423
|
+
fi
|
|
424
|
+
[ "$hc_dir" = / ] && return 0
|
|
425
|
+
hc_dir=${hc_dir%/*}
|
|
426
|
+
[ -n "$hc_dir" ] || hc_dir=/
|
|
427
|
+
done
|
|
428
|
+
}
|
|
429
|
+
halfcycle_pt_time_line() {
|
|
430
|
+
local LC_ALL=C hc_val hc_id hc_home hc_folder hc_branch hc_at hc_secs hc_frac hc_dir hc_line hc_f_session_id hc_f_agent_id hc_f_transcript_path hc_f_tool_use_id
|
|
431
|
+
local hc_re='^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$'
|
|
432
|
+
[ -n "${GUARD_SERVICE_TOKEN:-}" ] || return 0
|
|
433
|
+
[ -n "${GUARD_ENGAGEMENT_ID:-}" ] || return 0
|
|
434
|
+
hc_id=$GUARD_ENGAGEMENT_ID
|
|
435
|
+
[[ $hc_id =~ $hc_re ]] || return 0
|
|
436
|
+
hc_home=${HOME:-}
|
|
437
|
+
[ -n "$hc_home" ] || return 1
|
|
438
|
+
halfcycle_pt_optional 'session_id' || return 1
|
|
439
|
+
hc_f_session_id=$hc_val
|
|
440
|
+
halfcycle_pt_optional 'agent_id' || return 1
|
|
441
|
+
hc_f_agent_id=$hc_val
|
|
442
|
+
halfcycle_pt_optional 'transcript_path' || return 1
|
|
443
|
+
hc_f_transcript_path=$hc_val
|
|
444
|
+
halfcycle_pt_optional 'tool_use_id' || return 1
|
|
445
|
+
hc_f_tool_use_id=$hc_val
|
|
446
|
+
halfcycle_pt_string cwd
|
|
447
|
+
case $? in
|
|
448
|
+
0) hc_folder=$hc_val ;;
|
|
449
|
+
1) hc_folder= ;;
|
|
450
|
+
*) return 1 ;;
|
|
451
|
+
esac
|
|
452
|
+
case $hc_folder in *'\'*) return 1 ;; esac
|
|
453
|
+
if [ -z "$hc_folder" ]; then
|
|
454
|
+
cd -P . 2>/dev/null || return 1
|
|
455
|
+
hc_folder=$PWD
|
|
456
|
+
case $hc_folder in *[$'\x01'-$'\x1f']*|*'\'*|*'"'*) return 1 ;; esac
|
|
457
|
+
fi
|
|
458
|
+
halfcycle_pt_branch "$hc_folder" || return 1
|
|
459
|
+
hc_secs=${1%%[.,]*}
|
|
460
|
+
hc_frac=${1#*[.,]}
|
|
461
|
+
TZ=UTC0 printf -v hc_at '%(%Y-%m-%dT%H:%M:%S)T' "$hc_secs" || return 1
|
|
462
|
+
hc_at=$hc_at.${hc_frac:0:3}Z
|
|
463
|
+
printf -v hc_line '{"at":"%s","event":"action","session":%s,"agent":%s,"folder":"%s","branch":%s,"transcript":%s,"toolUse":%s}' "$hc_at" "$hc_f_session_id" "$hc_f_agent_id" "$hc_folder" "$hc_branch" "$hc_f_transcript_path" "$hc_f_tool_use_id"
|
|
464
|
+
hc_dir=$hc_home/.halfcycle/engagements/$hc_id/time-log
|
|
465
|
+
umask 077
|
|
466
|
+
{ printf '%s\n' "$hc_line" >> "$hc_dir/events.jsonl"; } 2>/dev/null ||
|
|
467
|
+
{ mkdir -p "$hc_dir" && printf '%s\n' "$hc_line" >> "$hc_dir/events.jsonl"; } 2>/dev/null
|
|
468
|
+
return 0
|
|
469
|
+
}
|
|
470
|
+
# --- end Halfcycle cheap pass ---------------------------------------------
|
package/dist/bin.d.ts
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* halfcycle draw architecture|phase <phase> — draw the architecture or a phase's pictures into docs/diagrams (`draw/`)
|
|
16
16
|
* halfcycle plan <phase> [--show] — check a phase's plan and report it; list it (`plan.ts`)
|
|
17
17
|
* halfcycle review <phase> --show | --answer <part> "…" — list a phase's close review; answer a question (`review.ts`)
|
|
18
|
+
* halfcycle prove <phase> <task> --label "…" (--before|--after) [-- <cmd>] — run a check once on this machine and record what it saw (`prove.ts`)
|
|
18
19
|
* halfcycle uninstall [--remove-credential] — take back what the installer wrote here
|
|
19
20
|
*
|
|
20
21
|
* NO `ci` VERB (T-25, operator decision 2026-09-22(c)) — `ci bind`/`ci unbind`
|
package/dist/bin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The file discipline every record-pair writer shares: exclusive create, the
|
|
3
|
+
* write-then-rename replace, and the no-half-pair create of a `.json` beside its `.md`.
|
|
4
|
+
*
|
|
5
|
+
* ONE COPY FOR TWO WRITERS. A phase's Build Record (`write.ts`, `writeRecordPair`) and
|
|
6
|
+
* a small change's record (`write-change.ts`, `writeChangeRecordPair`) write their pairs
|
|
7
|
+
* through these helpers, and `draw`'s three-file writer goes through the same seam, so
|
|
8
|
+
* there is one exclusive-create on disk, not one per writer. What each writer decides
|
|
9
|
+
* for itself is only what to do when a file is already in the way: the phase writer may
|
|
10
|
+
* replace its own earlier record, the small-change writer, whose record is write-once,
|
|
11
|
+
* never replaces.
|
|
12
|
+
*
|
|
13
|
+
* Nothing here builds a path. Every caller composes and checks its own paths before it
|
|
14
|
+
* hands them over (INV-023).
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* The file operations a pair writer makes, behind one seam so a test can make
|
|
18
|
+
* the SECOND write fail and watch the first come back out. `createExclusive` opens
|
|
19
|
+
* with `wx` (never truncates an existing file) and removes what it created if the
|
|
20
|
+
* write itself fails; `rename` replaces in one step on the same filesystem.
|
|
21
|
+
*
|
|
22
|
+
* ONE SEAM FOR TEXT AND BYTES. `draw`'s three-file writer (`../draw/write.ts`) goes
|
|
23
|
+
* through this same seam with a PNG's bytes, so a string is written as UTF-8 and a
|
|
24
|
+
* byte array as itself.
|
|
25
|
+
*/
|
|
26
|
+
export interface RecordPairIo {
|
|
27
|
+
createExclusive(path: string, data: string | Uint8Array): void;
|
|
28
|
+
rename(from: string, to: string): void;
|
|
29
|
+
}
|
|
30
|
+
export declare const NODE_RECORD_PAIR_IO: RecordPairIo;
|
|
31
|
+
/** Serialise a served record for the `.json`: 2-space indent, trailing newline. */
|
|
32
|
+
export declare function serialiseServedRecord(rawRecord: unknown): string;
|
|
33
|
+
/** Is `err` the file system saying the file is already there? */
|
|
34
|
+
export declare function isEexist(err: unknown): boolean;
|
|
35
|
+
/** The text at `path`, or `null` when it cannot be read as a file. */
|
|
36
|
+
export declare function readIfPresent(path: string): string | null;
|
|
37
|
+
/**
|
|
38
|
+
* Create both files of a pair exclusively, `.json` first. `created`: both are down.
|
|
39
|
+
* `exists`: one of the two was already there, and nothing this call created is left
|
|
40
|
+
* behind (a `.json` it created is removed again), so the caller's own replace rule
|
|
41
|
+
* decides from a clean state. Any other failure is thrown, with nothing left behind.
|
|
42
|
+
*/
|
|
43
|
+
export declare function createPairExclusive(io: RecordPairIo, jsonPath: string, jsonText: string, mdPath: string, mdText: string): 'created' | 'exists';
|
|
44
|
+
/**
|
|
45
|
+
* Write `text` to `tmp` and rename it over `finalPath`. A `.tmp` left by an earlier
|
|
46
|
+
* crash is removed first and never read. On failure the temporary file is removed.
|
|
47
|
+
*/
|
|
48
|
+
export declare function replaceOne(io: RecordPairIo, tmp: string, finalPath: string, text: string): void;
|
|
49
|
+
//# sourceMappingURL=pair-io.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pair-io.d.ts","sourceRoot":"","sources":["../../src/build-record/pair-io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;IAC/D,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AA2BD,eAAO,MAAM,mBAAmB,EAAE,YAGjC,CAAC;AAEF,mFAAmF;AACnF,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAEhE;AAED,iEAAiE;AACjE,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAE9C;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMzD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,YAAY,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,SAAS,GAAG,QAAQ,CAYtB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAS/F"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Markdown half of a small change's record pair (feature `three-paths`, *The
|
|
3
|
+
* writer*): `renderChangeRecordMarkdown` turns a frozen `smallChangeRecordSchema` value
|
|
4
|
+
* into the `.md` written beside its `.json` under `docs/build-records/changes/`.
|
|
5
|
+
*
|
|
6
|
+
* A SMALL CHANGE IS NOT A PHASE, and its record never reads as one: no line here says
|
|
7
|
+
* approved, unapproved, or asks for an approval (three-paths AC6, INV-024). A small
|
|
8
|
+
* change carries no approval to give or to lack, so the words never appear.
|
|
9
|
+
*
|
|
10
|
+
* WHOSE WORDS ARE WHOSE (INV-025). What Halfcycle counted is under "What Halfcycle
|
|
11
|
+
* saw"; the agent's one line, a reviewer's finding, a diagnosis and a call are each
|
|
12
|
+
* marked as the agent's own. A change that ended without a count (stopped, or moved up
|
|
13
|
+
* by the person) says Halfcycle did not count it, never that nothing changed. A window
|
|
14
|
+
* with no recorded check run reads as not observed, never as nothing found (INV-021).
|
|
15
|
+
*
|
|
16
|
+
* Every string from the record is printed through the Build Record renderer's own
|
|
17
|
+
* escapers (`printRecordText` for a slot with a line of its own, `printStrictText` for
|
|
18
|
+
* a slot sharing a line), so record text cannot become markup. One home for that rule.
|
|
19
|
+
*
|
|
20
|
+
* SHIPS TO CLIENT DISK inside the CLI: no comment sits beside an object member.
|
|
21
|
+
*/
|
|
22
|
+
import type { SmallChangeRecord } from '@halfcycle/events';
|
|
23
|
+
/** The `.md` of a small change's record. Pure: the same record renders the same text. */
|
|
24
|
+
export declare function renderChangeRecordMarkdown(record: SmallChangeRecord): string;
|
|
25
|
+
//# sourceMappingURL=render-change.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-change.d.ts","sourceRoot":"","sources":["../../src/build-record/render-change.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAsH3D,yFAAyF;AACzF,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CA4C5E"}
|
|
@@ -16,10 +16,12 @@
|
|
|
16
16
|
* bytes, whatever key order a database hands back.
|
|
17
17
|
*
|
|
18
18
|
* IT DOES NOT PARSE. The caller parses the record first; the type here is the
|
|
19
|
-
* contract's own inferred type.
|
|
19
|
+
* contract's own inferred type. Four of the contract's functions are imported at
|
|
20
20
|
* runtime, because each is the one home of what it composes: `codeLinkLine`, the
|
|
21
|
-
* code line every reader prints for a part
|
|
22
|
-
* review leaves to take out of the system description
|
|
21
|
+
* code line every reader prints for a part; `removalsOf`, the parts a closed
|
|
22
|
+
* review leaves to take out of the system description; `hasOwnerReview`, whether a
|
|
23
|
+
* record kept the owner's review (v3 and v4 did, v2 did not); and `keptPathOf`, the
|
|
24
|
+
* phase's path a v4 record kept. None is restated here, and no format is compared.
|
|
23
25
|
* The one cross-half rule it relies
|
|
24
26
|
* on — both halves describe the same closes, paired by `sequence` — it checks
|
|
25
27
|
* itself and throws on, because printing a close without its other half would
|
|
@@ -77,8 +79,11 @@ export declare function latestCloseHeadline(record: BuildRecord): string;
|
|
|
77
79
|
* learned an earlier round said something else).
|
|
78
80
|
*
|
|
79
81
|
* Render a parsed Build Record as markdown: v2's observed and attested halves, which
|
|
80
|
-
* a v3 record carries unchanged
|
|
81
|
-
* latest close (RM1–RM3, feature
|
|
82
|
+
* a v3 or v4 record carries unchanged; for a v4 record its path; for a v3 or v4
|
|
83
|
+
* record the owner's review after the latest close (RM1–RM3, feature
|
|
84
|
+
* `close-review-and-carry-drop`); and for a v4 record alone the calls made without asking
|
|
85
|
+
* (C1–C5) and the owner's answers to checks Halfcycle never ran, after the review. An
|
|
86
|
+
* older record prints neither section, so its Markdown is unchanged.
|
|
82
87
|
*
|
|
83
88
|
* Throws, in client words, if the two halves describe different closes — which a
|
|
84
89
|
* parsed record cannot do. Output uses `\n` only and ends in exactly one `\n`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-v2.d.ts","sourceRoot":"","sources":["../../src/build-record/render-v2.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"render-v2.d.ts","sourceRoot":"","sources":["../../src/build-record/render-v2.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAgBL,KAAK,WAAW,EAQjB,MAAM,mBAAmB,CAAC;AA8J3B;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAepD;AAKD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASpD;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOvD;AA2MD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAO/D;AAyTD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAgFvE"}
|