deepflow 0.1.64 → 0.1.66
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/deepflow-auto.sh +113 -65
- package/package.json +1 -1
package/bin/deepflow-auto.sh
CHANGED
|
@@ -168,32 +168,28 @@ discover_specs() {
|
|
|
168
168
|
# Context-monitored claude -p wrapper
|
|
169
169
|
# ---------------------------------------------------------------------------
|
|
170
170
|
|
|
171
|
-
# run_claude_monitored <working_dir> <prompt_text>
|
|
171
|
+
# run_claude_monitored <working_dir> <prompt_text>
|
|
172
172
|
#
|
|
173
173
|
# Runs `claude -p --output-format stream-json` and monitors token usage in
|
|
174
174
|
# real time. If usage reaches CONTEXT_THRESHOLD_PCT% of the context window the
|
|
175
|
-
# process is killed and
|
|
176
|
-
#
|
|
175
|
+
# process is killed and restarted with a fresh context (same prompt, clean
|
|
176
|
+
# session). Prior work persists in the worktree via committed files.
|
|
177
177
|
#
|
|
178
178
|
# The final result text is written to stdout. A side-effect context.json is
|
|
179
179
|
# written to <working_dir>/.deepflow/context.json for statusline consumption.
|
|
180
180
|
run_claude_monitored() {
|
|
181
181
|
local working_dir="$1"
|
|
182
182
|
local prompt_text="$2"
|
|
183
|
-
local session_id="${3:-}"
|
|
184
183
|
|
|
185
184
|
local result_tmp
|
|
186
185
|
result_tmp="$(mktemp)"
|
|
187
186
|
local error_log
|
|
188
187
|
error_log="$(mktemp)"
|
|
189
188
|
|
|
190
|
-
# Outer loop:
|
|
189
|
+
# Outer loop: restart with fresh context when threshold is hit
|
|
191
190
|
while true; do
|
|
192
191
|
# Build command arguments
|
|
193
192
|
local -a cmd_args=(claude -p --output-format stream-json --dangerously-skip-permissions)
|
|
194
|
-
if [[ -n "$session_id" ]]; then
|
|
195
|
-
cmd_args+=(--resume --session-id "$session_id")
|
|
196
|
-
fi
|
|
197
193
|
|
|
198
194
|
# Accumulated token count and context window size across events
|
|
199
195
|
local total_tokens=0
|
|
@@ -207,13 +203,8 @@ run_claude_monitored() {
|
|
|
207
203
|
fifo_path="$(mktemp -u)"
|
|
208
204
|
mkfifo "$fifo_path"
|
|
209
205
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
claude_pid=$!
|
|
213
|
-
else
|
|
214
|
-
echo "$prompt_text" | "${cmd_args[@]}" > "$fifo_path" 2>>"$error_log" &
|
|
215
|
-
claude_pid=$!
|
|
216
|
-
fi
|
|
206
|
+
echo "$prompt_text" | "${cmd_args[@]}" > "$fifo_path" 2>>"$error_log" &
|
|
207
|
+
claude_pid=$!
|
|
217
208
|
|
|
218
209
|
# Read the FIFO line-by-line (set +e to tolerate EINTR from signals)
|
|
219
210
|
local capturing_result=false
|
|
@@ -304,12 +295,10 @@ run_claude_monitored() {
|
|
|
304
295
|
: > "$error_log"
|
|
305
296
|
fi
|
|
306
297
|
|
|
307
|
-
if [[ "$threshold_hit" == "true"
|
|
308
|
-
# Restart with
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
context_window=0
|
|
312
|
-
auto_log "Restarting claude -p with --resume session_id=${session_id}"
|
|
298
|
+
if [[ "$threshold_hit" == "true" ]]; then
|
|
299
|
+
# Restart with fresh context — the prompt is re-sent but prior work
|
|
300
|
+
# persists in the worktree (committed files, etc.)
|
|
301
|
+
auto_log "Restarting claude -p with fresh context (prior work is in worktree)"
|
|
313
302
|
continue
|
|
314
303
|
fi
|
|
315
304
|
|
|
@@ -1149,70 +1138,129 @@ generate_report() {
|
|
|
1149
1138
|
# Build report
|
|
1150
1139
|
# -----------------------------------------------------------------
|
|
1151
1140
|
{
|
|
1152
|
-
#
|
|
1153
|
-
echo "
|
|
1141
|
+
# Header
|
|
1142
|
+
echo "# deepflow auto report"
|
|
1154
1143
|
echo ""
|
|
1155
|
-
echo "Status
|
|
1144
|
+
echo "**Status:** ${overall_status} "
|
|
1145
|
+
echo "**Date:** $(date -u '+%Y-%m-%d %H:%M UTC')"
|
|
1156
1146
|
echo ""
|
|
1157
1147
|
|
|
1158
|
-
#
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1148
|
+
# Per-spec details
|
|
1149
|
+
for sname in "${all_spec_names[@]}"; do
|
|
1150
|
+
local s="$(_spec_get STATUS "$sname" "unknown")"
|
|
1151
|
+
local w="$(_spec_get WINNER "$sname")"
|
|
1152
|
+
|
|
1153
|
+
echo "---"
|
|
1154
|
+
echo ""
|
|
1155
|
+
echo "## ${sname}"
|
|
1156
|
+
echo ""
|
|
1157
|
+
echo "**Status:** ${s}"
|
|
1158
|
+
if [[ -n "$w" ]]; then
|
|
1159
|
+
echo "**Winner:** ${w}"
|
|
1160
|
+
fi
|
|
1161
|
+
echo ""
|
|
1162
|
+
|
|
1163
|
+
# Hypotheses
|
|
1164
|
+
local hyp_file="${PROJECT_ROOT}/.deepflow/hypotheses/${sname}-cycle-0.json"
|
|
1165
|
+
if [[ -f "$hyp_file" ]]; then
|
|
1166
|
+
echo "### Hypotheses"
|
|
1167
|
+
echo ""
|
|
1168
|
+
# Parse each hypothesis slug + description
|
|
1169
|
+
local slug_list hyp_list
|
|
1170
|
+
slug_list="$(grep -o '"slug"[[:space:]]*:[[:space:]]*"[^"]*"' "$hyp_file" | sed 's/.*"\([^"]*\)".*/\1/')" || slug_list=""
|
|
1171
|
+
hyp_list="$(grep -o '"hypothesis"[[:space:]]*:[[:space:]]*"[^"]*"' "$hyp_file" | sed 's/.*"hypothesis"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')" || hyp_list=""
|
|
1172
|
+
|
|
1173
|
+
paste <(echo "$slug_list") <(echo "$hyp_list") | while IFS=$'\t' read -r hslug hhyp; do
|
|
1174
|
+
[[ -z "$hslug" ]] && continue
|
|
1175
|
+
echo "- **${hslug}:** ${hhyp}"
|
|
1176
|
+
done
|
|
1177
|
+
echo ""
|
|
1178
|
+
fi
|
|
1179
|
+
|
|
1180
|
+
# Spike results
|
|
1181
|
+
local has_spikes=false
|
|
1182
|
+
for wt_dir in "${PROJECT_ROOT}/.deepflow/worktrees/${sname}-"*; do
|
|
1183
|
+
[[ -d "$wt_dir" ]] || continue
|
|
1184
|
+
local wt_slug
|
|
1185
|
+
wt_slug="$(basename "$wt_dir")"
|
|
1186
|
+
wt_slug="${wt_slug#${sname}-}"
|
|
1187
|
+
|
|
1188
|
+
local spike_yaml="${wt_dir}/.deepflow/results/spike-${wt_slug}.yaml"
|
|
1189
|
+
if [[ -f "$spike_yaml" ]]; then
|
|
1190
|
+
if [[ "$has_spikes" == "false" ]]; then
|
|
1191
|
+
echo "### Spike Results"
|
|
1192
|
+
echo ""
|
|
1193
|
+
has_spikes=true
|
|
1167
1194
|
fi
|
|
1168
|
-
|
|
1195
|
+
local spike_status spike_summary
|
|
1196
|
+
spike_status="$(grep -m1 '^status:' "$spike_yaml" | sed 's/^status:[[:space:]]*//')" || spike_status="unknown"
|
|
1197
|
+
spike_summary="$(grep -m1 '^summary:' "$spike_yaml" | sed 's/^summary:[[:space:]]*//')" || spike_summary=""
|
|
1198
|
+
local status_icon="✅"
|
|
1199
|
+
[[ "$spike_status" =~ fail ]] && status_icon="❌"
|
|
1200
|
+
echo "- ${status_icon} **${wt_slug}** — ${spike_summary}"
|
|
1169
1201
|
fi
|
|
1170
1202
|
done
|
|
1171
|
-
|
|
1172
|
-
|
|
1203
|
+
if [[ "$has_spikes" == "true" ]]; then
|
|
1204
|
+
echo ""
|
|
1205
|
+
fi
|
|
1173
1206
|
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
local w="$(_spec_get WINNER "$sname" "-")"
|
|
1180
|
-
echo "| ${sname} | ${s} | ${w} |"
|
|
1181
|
-
done
|
|
1182
|
-
echo ""
|
|
1207
|
+
# Selection rationale
|
|
1208
|
+
local winner_file="${PROJECT_ROOT}/.deepflow/selection/${sname}-winner.json"
|
|
1209
|
+
if [[ -f "$winner_file" ]]; then
|
|
1210
|
+
echo "### Selection Rationale"
|
|
1211
|
+
echo ""
|
|
1183
1212
|
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1213
|
+
# Parse rankings from winner file
|
|
1214
|
+
local rankings
|
|
1215
|
+
rankings="$(node -e "
|
|
1216
|
+
try {
|
|
1217
|
+
const d = JSON.parse(require('fs').readFileSync('${winner_file}','utf8'));
|
|
1218
|
+
if (d.selection_output && d.selection_output.rankings) {
|
|
1219
|
+
d.selection_output.rankings.forEach(r => {
|
|
1220
|
+
const icon = r.rank === 1 ? '🏆' : ' ';
|
|
1221
|
+
console.log(icon + ' **#' + r.rank + ' ' + r.slug + ':** ' + r.rationale);
|
|
1222
|
+
});
|
|
1223
|
+
}
|
|
1224
|
+
} catch(e) {}
|
|
1225
|
+
" 2>/dev/null)" || rankings=""
|
|
1226
|
+
|
|
1227
|
+
if [[ -n "$rankings" ]]; then
|
|
1228
|
+
echo "$rankings"
|
|
1229
|
+
fi
|
|
1230
|
+
echo ""
|
|
1231
|
+
fi
|
|
1187
1232
|
|
|
1188
|
-
|
|
1189
|
-
for sname in "${all_spec_names[@]}"; do
|
|
1190
|
-
local w="$(_spec_get WINNER "$sname")"
|
|
1233
|
+
# Changes (git diff stat)
|
|
1191
1234
|
if [[ -n "$w" ]]; then
|
|
1192
|
-
has_changes=true
|
|
1193
1235
|
local branch_name="df/${sname}-${w}"
|
|
1194
|
-
echo "###
|
|
1236
|
+
echo "### Changes"
|
|
1195
1237
|
echo ""
|
|
1196
1238
|
echo '```'
|
|
1197
|
-
git diff --stat "main...${branch_name}" 2>/dev/null || echo "(branch ${branch_name} not found)"
|
|
1239
|
+
git -C "$PROJECT_ROOT" diff --stat "main...${branch_name}" 2>/dev/null || echo "(branch ${branch_name} not found)"
|
|
1198
1240
|
echo '```'
|
|
1199
1241
|
echo ""
|
|
1200
1242
|
fi
|
|
1201
1243
|
done
|
|
1202
|
-
if [[ "$has_changes" == "false" ]]; then
|
|
1203
|
-
echo "No changes selected"
|
|
1204
|
-
echo ""
|
|
1205
|
-
fi
|
|
1206
1244
|
|
|
1207
|
-
#
|
|
1208
|
-
echo "
|
|
1245
|
+
# Next steps
|
|
1246
|
+
echo "---"
|
|
1209
1247
|
echo ""
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
if [[
|
|
1213
|
-
|
|
1248
|
+
echo "## Next Steps"
|
|
1249
|
+
echo ""
|
|
1250
|
+
if [[ "$overall_status" == "converged" ]]; then
|
|
1251
|
+
for sname in "${all_spec_names[@]}"; do
|
|
1252
|
+
local w="$(_spec_get WINNER "$sname")"
|
|
1253
|
+
if [[ -n "$w" ]]; then
|
|
1254
|
+
echo "To merge the winner:"
|
|
1255
|
+
echo '```bash'
|
|
1256
|
+
echo "git merge df/${sname}-${w}"
|
|
1257
|
+
echo '```'
|
|
1258
|
+
fi
|
|
1259
|
+
done
|
|
1260
|
+
elif [[ "$overall_status" == "in-progress" ]]; then
|
|
1261
|
+
echo "Run \`deepflow auto --continue\` to resume."
|
|
1214
1262
|
else
|
|
1215
|
-
echo "
|
|
1263
|
+
echo "Review the spec and run \`deepflow auto\` again."
|
|
1216
1264
|
fi
|
|
1217
1265
|
echo ""
|
|
1218
1266
|
} > "$report_file"
|