mirror of
https://github.com/seanbetts/steam-hardware-watch.git
synced 2026-10-06 01:00:18 +02:00
Add Komodo-only watch mode
This commit is contained in:
1 parent
935e6cc450
commit
427e92daf7
6 files changed
+544
-17
No files matched your search
@@ -41,6 +41,39 @@ scripts/run_frame_watch.sh YYYY-MM-DD /custom/run-base /path/to/SteamTracking
|
|||||||
|
|
||||||
Use `scripts/run_watch.sh` when you explicitly want the broader all-hardware view or when debugging an individual source helper.
|
Use `scripts/run_watch.sh` when you explicitly want the broader all-hardware view or when debugging an individual source helper.
|
||||||
|
|
||||||
|
For a quick Komodo-only recheck, use:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
scripts/run_frame_watch.sh --komodo-only YYYY-MM-DD
|
||||||
|
```
|
||||||
|
|
||||||
|
This initializes the dated run folder, runs `check_komodo.sh`, prints whether Komodo product timestamps changed since the previous run, reports any newly discovered Komodo asset URLs, writes `run-summary.md`, and skips SteamKit/PICS, SteamDB, SteamTracking, SteamVR, SteamOS, Valve endpoint, customs, comparison, and status-draft steps.
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Run dir: /Users/sean/Coding/steam-hardware-watch/runs/2026-07-28
|
||||||
|
Run note: /Users/sean/Coding/steam-hardware-watch/status/runs/2026-07-28.md
|
||||||
|
Saved Komodo API responses to /Users/sean/Coding/steam-hardware-watch/runs/2026-07-28/api/komodo
|
||||||
|
Saved Komodo summaries to /Users/sean/Coding/steam-hardware-watch/runs/2026-07-28/reports
|
||||||
|
Komodo updated: yes (changed since previous run 2026-07-27)
|
||||||
|
Komodo changes:
|
||||||
|
- frame: 2026-07-03T15:56:30 -> 2026-07-28T10:11:12
|
||||||
|
Komodo timestamps: controller=2026-07-27T15:46:17, machine=2026-07-27T15:39:56, frame=2026-07-28T10:11:12
|
||||||
|
Komodo new assets: yes (1 new, 3 current, since previous run 2026-07-27)
|
||||||
|
Komodo new asset URLs:
|
||||||
|
- https://komodostation.com/wp-content/uploads/2026/07/new-frame-asset.jpg
|
||||||
|
Run summary: /Users/sean/Coding/steam-hardware-watch/runs/2026-07-28/reports/run-summary.md
|
||||||
|
Komodo-only run complete.
|
||||||
|
```
|
||||||
|
|
||||||
|
If nothing changed, the key lines should read:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Komodo updated: no (matches previous run 2026-07-27)
|
||||||
|
Komodo new assets: no (2 current, matches previous run 2026-07-27)
|
||||||
|
```
|
||||||
|
|
||||||
## Repository Layout
|
## Repository Layout
|
||||||
|
|
||||||
```text
|
```text
|
||||||
@@ -120,6 +153,14 @@ scripts/close_komodo.sh
|
|||||||
|
|
||||||
That keeps Komodo access isolated from your normal Chrome profile and gives the agent a reusable trusted browser session when Komodo blocks normal automation.
|
That keeps Komodo access isolated from your normal Chrome profile and gives the agent a reusable trusted browser session when Komodo blocks normal automation.
|
||||||
|
|
||||||
|
For a focused Komodo recheck, use the same bootstrap with the Komodo-only flag:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
scripts/bootstrap_komodo.sh
|
||||||
|
scripts/run_frame_watch.sh --komodo-only 2026-07-28
|
||||||
|
scripts/close_komodo.sh
|
||||||
|
```
|
||||||
|
|
||||||
SteamDB can require the same live-browser treatment:
|
SteamDB can require the same live-browser treatment:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@@ -218,6 +259,24 @@ Then use:
|
|||||||
- `RUN_DIR/reports/run-summary.md`
|
- `RUN_DIR/reports/run-summary.md`
|
||||||
- `RUN_DIR/reports/compare-vs-*.md`
|
- `RUN_DIR/reports/compare-vs-*.md`
|
||||||
|
|
||||||
|
## Agent Checklist
|
||||||
|
|
||||||
|
For a fresh coding agent, the normal operating loop is:
|
||||||
|
|
||||||
|
1. Read `SKILL.md` before running or editing anything.
|
||||||
|
2. Choose the narrowest relevant command:
|
||||||
|
- `scripts/run_frame_watch.sh YYYY-MM-DD` for the normal Frame-focused pass.
|
||||||
|
- `scripts/run_frame_watch.sh --komodo-only YYYY-MM-DD` for a quick Komodo recheck.
|
||||||
|
- `scripts/run_watch.sh YYYY-MM-DD` only for the broader all-hardware view or source-helper debugging.
|
||||||
|
3. Inspect `frame-focus.md` first for full runs, then `run-summary.md`, `status-draft.md`, and `compare-vs-*.md`.
|
||||||
|
4. Put primary package/store gates first when reporting: SteamKit/PICS, Valve APIs, SteamDB package pages, then Komodo.
|
||||||
|
5. Treat SteamTracking, SteamVR, SteamOS, and customs rows as secondary context unless they connect directly to Frame package/API, public-page, or shipment evidence.
|
||||||
|
6. Update `status/current.md` only for material movement or a new clean baseline.
|
||||||
|
7. Append `status/evidence.jsonl` only for evidence-grade findings, using `scripts/append_evidence.py`.
|
||||||
|
8. Keep raw artifacts under gitignored `runs/`; never commit `.local/`, browser profiles, sessions, cookies, or one-time auth codes.
|
||||||
|
9. Validate before finishing: parse `status/evidence.jsonl` if touched, run `git diff --check`, inspect staged scope, and finish with `git status --short`.
|
||||||
|
10. Commit only the intended files.
|
||||||
|
|
||||||
## Agent Usage
|
## Agent Usage
|
||||||
|
|
||||||
This repo is meant to be used by coding agents, not only by a human at a shell.
|
This repo is meant to be used by coding agents, not only by a human at a shell.
|
||||||
@@ -472,6 +531,13 @@ Normal use:
|
|||||||
3. inspect the comparison report if something changed
|
3. inspect the comparison report if something changed
|
||||||
4. update `status/current.md` and `status/evidence.jsonl` only for material changes
|
4. update `status/current.md` and `status/evidence.jsonl` only for material changes
|
||||||
|
|
||||||
|
Quick Komodo recheck:
|
||||||
|
|
||||||
|
1. run `scripts/run_frame_watch.sh --komodo-only YYYY-MM-DD`
|
||||||
|
2. scan the CLI lines for product timestamp changes and new asset URLs
|
||||||
|
3. read `run-summary.md` and the Komodo reports under `reports/`
|
||||||
|
4. rerun the full Frame watcher only if Komodo exposes material movement
|
||||||
|
|
||||||
Escalation:
|
Escalation:
|
||||||
|
|
||||||
1. if Komodo blocks, continue the run
|
1. if Komodo blocks, continue the run
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ Asset discovery should be dynamic:
|
|||||||
Default agent entry point:
|
Default agent entry point:
|
||||||
|
|
||||||
- use [scripts/run_frame_watch.sh](scripts/run_frame_watch.sh) for normal Frame-focused runs
|
- use [scripts/run_frame_watch.sh](scripts/run_frame_watch.sh) for normal Frame-focused runs
|
||||||
|
- use `scripts/run_frame_watch.sh --komodo-only YYYY-MM-DD` when the user asks for a focused Komodo-only recheck
|
||||||
- use [scripts/run_watch.sh](scripts/run_watch.sh) when the user asks for the broader all-hardware view or when debugging a source helper directly
|
- use [scripts/run_watch.sh](scripts/run_watch.sh) when the user asks for the broader all-hardware view or when debugging a source helper directly
|
||||||
- treat the helper scripts as agent-owned implementation details
|
- treat the helper scripts as agent-owned implementation details
|
||||||
- summarize results for the human from `frame-focus.md`, `run-summary.md`, `status-draft.md`, and the comparison report
|
- summarize results for the human from `frame-focus.md`, `run-summary.md`, `status-draft.md`, and the comparison report
|
||||||
@@ -125,6 +126,14 @@ Interpretation rules:
|
|||||||
|
|
||||||
Read [references/komodo-api-notes.md](references/komodo-api-notes.md) first.
|
Read [references/komodo-api-notes.md](references/komodo-api-notes.md) first.
|
||||||
|
|
||||||
|
For a quick Komodo-only check, prefer:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
scripts/run_frame_watch.sh --komodo-only YYYY-MM-DD
|
||||||
|
```
|
||||||
|
|
||||||
|
This initializes the run folder, runs only the Komodo helper, prints product timestamp changes and newly discovered asset URLs versus the previous run, writes `run-summary.md`, and skips the full watcher sources and comparison/status-draft steps.
|
||||||
|
|
||||||
Check:
|
Check:
|
||||||
|
|
||||||
- product records for `Steam Controller`, `Steam Machine`, `Steam Frame`
|
- product records for `Steam Controller`, `Steam Machine`, `Steam Frame`
|
||||||
|
|||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
version: 1
|
version: 1
|
||||||
display_name: Steam Hardware Watch
|
display_name: Steam Hardware Watch
|
||||||
short_description: Reusable workflow for monitoring Valve hardware launch signals across Komodo, SteamDB, SteamTracking, Valve endpoints, and related evidence sources.
|
short_description: Frame-first workflow for monitoring Valve hardware launch signals across Komodo, SteamKit/PICS, SteamDB, SteamTracking, Valve endpoints, and related evidence sources.
|
||||||
default_prompt: Check the current status of rumored or upcoming Valve hardware, save artifacts, and update the status ledger.
|
default_prompt: Run the Steam Frame-focused hardware watch, or a Komodo-only recheck when requested, save artifacts, compare against the previous run, and update the status ledger only for material movement.
|
||||||
@@ -1,8 +1,34 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "usage: $0 [--komodo-only] YYYY-MM-DD [base_dir] [tracking_dir]" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
KOMODO_ONLY=0
|
||||||
|
|
||||||
|
while [ "$#" -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--komodo-only)
|
||||||
|
KOMODO_ONLY=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
if [ "$#" -lt 1 ]; then
|
if [ "$#" -lt 1 ]; then
|
||||||
echo "usage: $0 YYYY-MM-DD [base_dir] [tracking_dir]" >&2
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -13,6 +39,15 @@ REPO_DIR="$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)"
|
|||||||
BASE_DIR="${2:-$REPO_DIR/runs}"
|
BASE_DIR="${2:-$REPO_DIR/runs}"
|
||||||
TRACKING_DIR="${3:-/tmp/SteamTracking-master}"
|
TRACKING_DIR="${3:-/tmp/SteamTracking-master}"
|
||||||
|
|
||||||
|
if [ "$KOMODO_ONLY" = "1" ]; then
|
||||||
|
if [ "$#" -ge 3 ]; then
|
||||||
|
"$SCRIPT_DIR/run_watch.sh" --komodo-only "$RUN_DATE" "$BASE_DIR" "$TRACKING_DIR"
|
||||||
|
else
|
||||||
|
"$SCRIPT_DIR/run_watch.sh" --komodo-only "$RUN_DATE" "$BASE_DIR"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$#" -ge 3 ]; then
|
if [ "$#" -ge 3 ]; then
|
||||||
"$SCRIPT_DIR/run_watch.sh" "$RUN_DATE" "$BASE_DIR" "$TRACKING_DIR"
|
"$SCRIPT_DIR/run_watch.sh" "$RUN_DATE" "$BASE_DIR" "$TRACKING_DIR"
|
||||||
else
|
else
|
||||||
|
|||||||
+187
-14
@@ -1,8 +1,34 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "usage: $0 [--komodo-only] YYYY-MM-DD [base_dir] [tracking_dir]" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
KOMODO_ONLY=0
|
||||||
|
|
||||||
|
while [ "$#" -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--komodo-only)
|
||||||
|
KOMODO_ONLY=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
if [ "$#" -lt 1 ]; then
|
if [ "$#" -lt 1 ]; then
|
||||||
echo "usage: $0 YYYY-MM-DD [base_dir] [tracking_dir]" >&2
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -31,6 +57,152 @@ cleanup() {
|
|||||||
|
|
||||||
trap cleanup EXIT INT TERM
|
trap cleanup EXIT INT TERM
|
||||||
|
|
||||||
|
find_previous_run_dir() {
|
||||||
|
previous_dir=""
|
||||||
|
for candidate in $(find "$BASE_DIR" -mindepth 1 -maxdepth 1 -type d -name '????-??-??' | sort); do
|
||||||
|
if [ "$candidate" = "$RUN_DIR" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
case "$(basename "$candidate")" in
|
||||||
|
"$RUN_DATE") ;;
|
||||||
|
*)
|
||||||
|
if [ "$(basename "$candidate")" \< "$RUN_DATE" ]; then
|
||||||
|
previous_dir="$candidate"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
printf '%s\n' "$previous_dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
komodo_timestamp_summary() {
|
||||||
|
awk -F '\t' 'NF >= 2 {
|
||||||
|
if (out != "") {
|
||||||
|
out = out ", "
|
||||||
|
}
|
||||||
|
out = out $1 "=" $2
|
||||||
|
} END {
|
||||||
|
print out
|
||||||
|
}' "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
komodo_timestamp_changes() {
|
||||||
|
awk -F '\t' 'NR == FNR {
|
||||||
|
previous[$1] = $2
|
||||||
|
previous_order[++previous_count] = $1
|
||||||
|
next
|
||||||
|
}
|
||||||
|
NF >= 2 {
|
||||||
|
current_seen[$1] = 1
|
||||||
|
if (!($1 in previous)) {
|
||||||
|
print "- " $1 ": added " $2
|
||||||
|
} else if (previous[$1] != $2) {
|
||||||
|
print "- " $1 ": " previous[$1] " -> " $2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END {
|
||||||
|
for (i = 1; i <= previous_count; i++) {
|
||||||
|
key = previous_order[i]
|
||||||
|
if (!(key in current_seen)) {
|
||||||
|
print "- " key ": removed " previous[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}' "$1" "$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
komodo_asset_count() {
|
||||||
|
awk -F '\t' 'NF >= 3 && $3 ~ /^https?:/ {
|
||||||
|
count++
|
||||||
|
} END {
|
||||||
|
print count + 0
|
||||||
|
}' "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
komodo_new_asset_urls() {
|
||||||
|
awk -F '\t' 'NR == FNR {
|
||||||
|
if (NF >= 3 && $3 ~ /^https?:/) {
|
||||||
|
previous[$3] = 1
|
||||||
|
}
|
||||||
|
next
|
||||||
|
}
|
||||||
|
NF >= 3 && $3 ~ /^https?:/ && !($3 in previous) {
|
||||||
|
print "- " $3
|
||||||
|
}' "$1" "$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_komodo_update_status() {
|
||||||
|
current_report="$RUN_DIR/reports/komodo-product-modified.tsv"
|
||||||
|
|
||||||
|
if [ ! -s "$current_report" ]; then
|
||||||
|
printf '%s\n' "Komodo updated: unknown (current Komodo timestamps unavailable)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
current_summary="$(komodo_timestamp_summary "$current_report")"
|
||||||
|
previous_dir="$(find_previous_run_dir)"
|
||||||
|
|
||||||
|
if [ -z "$previous_dir" ]; then
|
||||||
|
printf '%s\n' "Komodo updated: unknown (no previous run found)"
|
||||||
|
printf '%s\n' "Komodo timestamps: $current_summary"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
previous_report="$previous_dir/reports/komodo-product-modified.tsv"
|
||||||
|
previous_date="$(basename "$previous_dir")"
|
||||||
|
|
||||||
|
if [ ! -s "$previous_report" ]; then
|
||||||
|
printf '%s\n' "Komodo updated: unknown (previous run $previous_date has no Komodo timestamp report)"
|
||||||
|
printf '%s\n' "Komodo timestamps: $current_summary"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if cmp -s "$previous_report" "$current_report"; then
|
||||||
|
printf '%s\n' "Komodo updated: no (matches previous run $previous_date)"
|
||||||
|
else
|
||||||
|
printf '%s\n' "Komodo updated: yes (changed since previous run $previous_date)"
|
||||||
|
printf '%s\n' "Komodo changes:"
|
||||||
|
komodo_timestamp_changes "$previous_report" "$current_report"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s\n' "Komodo timestamps: $current_summary"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_komodo_asset_status() {
|
||||||
|
current_report="$RUN_DIR/reports/komodo-visual-assets.tsv"
|
||||||
|
|
||||||
|
if [ ! -s "$current_report" ]; then
|
||||||
|
printf '%s\n' "Komodo new assets: unknown (current Komodo asset report unavailable)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
current_count="$(komodo_asset_count "$current_report")"
|
||||||
|
previous_dir="$(find_previous_run_dir)"
|
||||||
|
|
||||||
|
if [ -z "$previous_dir" ]; then
|
||||||
|
printf '%s\n' "Komodo new assets: unknown ($current_count current, no previous run found)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
previous_report="$previous_dir/reports/komodo-visual-assets.tsv"
|
||||||
|
previous_date="$(basename "$previous_dir")"
|
||||||
|
|
||||||
|
if [ ! -s "$previous_report" ]; then
|
||||||
|
printf '%s\n' "Komodo new assets: unknown ($current_count current, previous run $previous_date has no Komodo asset report)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
new_urls="$(komodo_new_asset_urls "$previous_report" "$current_report")"
|
||||||
|
new_count="$(printf '%s\n' "$new_urls" | sed '/^$/d' | wc -l | tr -d ' ')"
|
||||||
|
|
||||||
|
if [ "$new_count" = "0" ]; then
|
||||||
|
printf '%s\n' "Komodo new assets: no ($current_count current, matches previous run $previous_date)"
|
||||||
|
else
|
||||||
|
printf '%s\n' "Komodo new assets: yes ($new_count new, $current_count current, since previous run $previous_date)"
|
||||||
|
printf '%s\n' "Komodo new asset URLs:"
|
||||||
|
printf '%s\n' "$new_urls"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
INIT_OUTPUT="$("$SCRIPT_DIR/init_run.sh" "$RUN_DATE" "$BASE_DIR")"
|
INIT_OUTPUT="$("$SCRIPT_DIR/init_run.sh" "$RUN_DATE" "$BASE_DIR")"
|
||||||
RUN_DIR="$(printf '%s\n' "$INIT_OUTPUT" | awk -F= '/^RUN_DIR=/{print $2}')"
|
RUN_DIR="$(printf '%s\n' "$INIT_OUTPUT" | awk -F= '/^RUN_DIR=/{print $2}')"
|
||||||
RUN_NOTE="$(printf '%s\n' "$INIT_OUTPUT" | awk -F= '/^RUN_NOTE=/{print $2}')"
|
RUN_NOTE="$(printf '%s\n' "$INIT_OUTPUT" | awk -F= '/^RUN_NOTE=/{print $2}')"
|
||||||
@@ -44,6 +216,19 @@ printf '%s\n' "Run dir: $RUN_DIR"
|
|||||||
printf '%s\n' "Run note: $RUN_NOTE"
|
printf '%s\n' "Run note: $RUN_NOTE"
|
||||||
|
|
||||||
"$SCRIPT_DIR/check_komodo.sh" "$RUN_DIR"
|
"$SCRIPT_DIR/check_komodo.sh" "$RUN_DIR"
|
||||||
|
|
||||||
|
if [ "$KOMODO_ONLY" = "1" ]; then
|
||||||
|
print_komodo_update_status
|
||||||
|
print_komodo_asset_status
|
||||||
|
RUN_SUMMARY_OUT="$RUN_DIR/reports/run-summary.md"
|
||||||
|
python3 "$SCRIPT_DIR/write_run_summary.py" \
|
||||||
|
--run-dir "$RUN_DIR" \
|
||||||
|
--output "$RUN_SUMMARY_OUT"
|
||||||
|
printf '%s\n' "Run summary: $RUN_SUMMARY_OUT"
|
||||||
|
printf '%s\n' "Komodo-only run complete."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
"$SCRIPT_DIR/check_steamkit_pics.sh" "$RUN_DIR"
|
"$SCRIPT_DIR/check_steamkit_pics.sh" "$RUN_DIR"
|
||||||
"$SCRIPT_DIR/check_steamdb.sh" "$RUN_DIR"
|
"$SCRIPT_DIR/check_steamdb.sh" "$RUN_DIR"
|
||||||
"$SCRIPT_DIR/check_steamtracking.sh" "$RUN_DIR" "$TRACKING_DIR"
|
"$SCRIPT_DIR/check_steamtracking.sh" "$RUN_DIR" "$TRACKING_DIR"
|
||||||
@@ -54,19 +239,7 @@ printf '%s\n' "Run note: $RUN_NOTE"
|
|||||||
python3 "$SCRIPT_DIR/save_visual_assets.py" --run-dir "$RUN_DIR" --base-dir "$BASE_DIR"
|
python3 "$SCRIPT_DIR/save_visual_assets.py" --run-dir "$RUN_DIR" --base-dir "$BASE_DIR"
|
||||||
|
|
||||||
PREVIOUS_DIR=""
|
PREVIOUS_DIR=""
|
||||||
for candidate in $(find "$BASE_DIR" -mindepth 1 -maxdepth 1 -type d -name '????-??-??' | sort); do
|
PREVIOUS_DIR="$(find_previous_run_dir)"
|
||||||
if [ "$candidate" = "$RUN_DIR" ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
case "$(basename "$candidate")" in
|
|
||||||
"$RUN_DATE") ;;
|
|
||||||
*)
|
|
||||||
if [ "$(basename "$candidate")" \< "$RUN_DATE" ]; then
|
|
||||||
PREVIOUS_DIR="$candidate"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -n "$PREVIOUS_DIR" ]; then
|
if [ -n "$PREVIOUS_DIR" ]; then
|
||||||
COMPARE_OUT="$RUN_DIR/reports/compare-vs-$(basename "$PREVIOUS_DIR").md"
|
COMPARE_OUT="$RUN_DIR/reports/compare-vs-$(basename "$PREVIOUS_DIR").md"
|
||||||
|
|||||||
@@ -0,0 +1,244 @@
|
|||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import textwrap
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
|
class RunWatchCliTests(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.tmp = tempfile.TemporaryDirectory()
|
||||||
|
self.addCleanup(self.tmp.cleanup)
|
||||||
|
self.repo = Path(self.tmp.name)
|
||||||
|
self.scripts = self.repo / "scripts"
|
||||||
|
self.scripts.mkdir()
|
||||||
|
(self.repo / "status" / "runs").mkdir(parents=True)
|
||||||
|
self.log = self.repo / "calls.log"
|
||||||
|
|
||||||
|
os.symlink(ROOT / "scripts" / "run_watch.sh", self.scripts / "run_watch.sh")
|
||||||
|
os.symlink(ROOT / "scripts" / "run_frame_watch.sh", self.scripts / "run_frame_watch.sh")
|
||||||
|
|
||||||
|
self._write_script(
|
||||||
|
"init_run.sh",
|
||||||
|
"""
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
run_date="$1"
|
||||||
|
base_dir="$2"
|
||||||
|
run_dir="$base_dir/$run_date"
|
||||||
|
mkdir -p "$run_dir/reports" "$run_dir/api"
|
||||||
|
run_note="$PWD/status/runs/$run_date.md"
|
||||||
|
printf 'init_run %s %s\\n' "$run_date" "$base_dir" >> "$CALL_LOG"
|
||||||
|
printf 'RUN_DIR=%s\\nRUN_NOTE=%s\\n' "$run_dir" "$run_note"
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
self._write_script(
|
||||||
|
"check_komodo.sh",
|
||||||
|
"""
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
printf 'check_komodo %s\\n' "$1" >> "$CALL_LOG"
|
||||||
|
mkdir -p "$1/reports"
|
||||||
|
{
|
||||||
|
printf 'controller\\t%s\\n' "${KOMODO_CONTROLLER_MODIFIED:-2026-07-27T15:46:17}"
|
||||||
|
printf 'machine\\t%s\\n' "${KOMODO_MACHINE_MODIFIED:-2026-07-27T15:39:56}"
|
||||||
|
printf 'frame\\t%s\\n' "${KOMODO_FRAME_MODIFIED:-2026-07-03T15:56:30}"
|
||||||
|
} > "$1/reports/komodo-product-modified.tsv"
|
||||||
|
{
|
||||||
|
printf '413804\\timage/png\\thttps://komodostation.com/wp-content/uploads/2025/11/Frame_BG.png\\n'
|
||||||
|
printf '456489\\timage/jpeg\\thttps://komodostation.com/wp-content/uploads/2025/11/source_SF_headsetControllers_front_2.jpg\\n'
|
||||||
|
if [ -n "${KOMODO_EXTRA_ASSET_URL:-}" ]; then
|
||||||
|
printf '999999\\timage/jpeg\\t%s\\n' "$KOMODO_EXTRA_ASSET_URL"
|
||||||
|
fi
|
||||||
|
} > "$1/reports/komodo-visual-assets.tsv"
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
self._write_python(
|
||||||
|
"write_run_summary.py",
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
Path(__import__("os").environ["CALL_LOG"]).open("a").write("write_run_summary " + " ".join(sys.argv[1:]) + "\\n")
|
||||||
|
output = Path(sys.argv[sys.argv.index("--output") + 1])
|
||||||
|
output.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
output.write_text("# Summary\\n", encoding="utf-8")
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
|
for name in [
|
||||||
|
"check_steamkit_pics.sh",
|
||||||
|
"check_steamdb.sh",
|
||||||
|
"check_steamtracking.sh",
|
||||||
|
"check_steamvr_depots.sh",
|
||||||
|
"check_steamos_mirror.sh",
|
||||||
|
"check_valve_endpoints.sh",
|
||||||
|
"check_customs_shipments.sh",
|
||||||
|
"save_visual_assets.py",
|
||||||
|
"compare_runs.py",
|
||||||
|
"write_frame_focus_report.py",
|
||||||
|
"draft_status_update.py",
|
||||||
|
]:
|
||||||
|
if name.endswith(".py"):
|
||||||
|
self._write_python(name, f"raise SystemExit('unexpected {name}')\n")
|
||||||
|
else:
|
||||||
|
self._write_script(
|
||||||
|
name,
|
||||||
|
f"""
|
||||||
|
#!/bin/sh
|
||||||
|
echo 'unexpected {name}' >&2
|
||||||
|
exit 42
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
|
def _write_script(self, name, body):
|
||||||
|
path = self.scripts / name
|
||||||
|
path.write_text(textwrap.dedent(body).lstrip(), encoding="utf-8")
|
||||||
|
path.chmod(0o755)
|
||||||
|
|
||||||
|
def _write_python(self, name, body):
|
||||||
|
path = self.scripts / name
|
||||||
|
path.write_text(textwrap.dedent(body).lstrip(), encoding="utf-8")
|
||||||
|
path.chmod(0o755)
|
||||||
|
|
||||||
|
def run_script(self, *args):
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["CALL_LOG"] = str(self.log)
|
||||||
|
return subprocess.run(
|
||||||
|
list(args),
|
||||||
|
cwd=self.repo,
|
||||||
|
env=env,
|
||||||
|
text=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
def write_previous_komodo_report(
|
||||||
|
self,
|
||||||
|
run_date,
|
||||||
|
frame_modified,
|
||||||
|
controller_modified="2026-07-27T15:46:17",
|
||||||
|
machine_modified="2026-07-27T15:39:56",
|
||||||
|
):
|
||||||
|
report = self.repo / "runs" / run_date / "reports" / "komodo-product-modified.tsv"
|
||||||
|
report.parent.mkdir(parents=True)
|
||||||
|
report.write_text(
|
||||||
|
"\n".join(
|
||||||
|
[
|
||||||
|
f"controller\t{controller_modified}",
|
||||||
|
f"machine\t{machine_modified}",
|
||||||
|
f"frame\t{frame_modified}",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
def write_previous_komodo_assets(self, run_date, extra_urls=None):
|
||||||
|
report = self.repo / "runs" / run_date / "reports" / "komodo-visual-assets.tsv"
|
||||||
|
report.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
rows = [
|
||||||
|
"413804\timage/png\thttps://komodostation.com/wp-content/uploads/2025/11/Frame_BG.png",
|
||||||
|
"456489\timage/jpeg\thttps://komodostation.com/wp-content/uploads/2025/11/source_SF_headsetControllers_front_2.jpg",
|
||||||
|
]
|
||||||
|
for index, url in enumerate(extra_urls or [], start=1):
|
||||||
|
rows.append(f"99999{index}\timage/jpeg\t{url}")
|
||||||
|
report.write_text("\n".join(rows + [""]), encoding="utf-8")
|
||||||
|
|
||||||
|
def test_run_watch_komodo_only_runs_komodo_and_skips_other_sources(self):
|
||||||
|
base_dir = self.repo / "runs"
|
||||||
|
self.write_previous_komodo_report("2099-01-01", "2026-07-03T15:56:30")
|
||||||
|
self.write_previous_komodo_assets("2099-01-01")
|
||||||
|
|
||||||
|
result = self.run_script(
|
||||||
|
str(self.scripts / "run_watch.sh"),
|
||||||
|
"--komodo-only",
|
||||||
|
"2099-01-02",
|
||||||
|
str(base_dir),
|
||||||
|
"/tmp/not-used",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual("", result.stderr)
|
||||||
|
self.assertEqual(0, result.returncode)
|
||||||
|
self.assertIn(f"Run dir: {base_dir / '2099-01-02'}", result.stdout)
|
||||||
|
self.assertIn("Komodo updated: no (matches previous run 2099-01-01)", result.stdout)
|
||||||
|
self.assertIn(
|
||||||
|
"Komodo timestamps: controller=2026-07-27T15:46:17, machine=2026-07-27T15:39:56, frame=2026-07-03T15:56:30",
|
||||||
|
result.stdout,
|
||||||
|
)
|
||||||
|
self.assertIn("Komodo new assets: no (2 current, matches previous run 2099-01-01)", result.stdout)
|
||||||
|
self.assertIn("Komodo-only run complete.", result.stdout)
|
||||||
|
calls = self.log.read_text(encoding="utf-8")
|
||||||
|
self.assertIn("check_komodo", calls)
|
||||||
|
self.assertIn("write_run_summary", calls)
|
||||||
|
self.assertNotIn("unexpected", calls)
|
||||||
|
|
||||||
|
def test_run_frame_watch_komodo_only_does_not_write_frame_focus_report(self):
|
||||||
|
base_dir = self.repo / "runs"
|
||||||
|
|
||||||
|
result = self.run_script(
|
||||||
|
str(self.scripts / "run_frame_watch.sh"),
|
||||||
|
"--komodo-only",
|
||||||
|
"2099-01-03",
|
||||||
|
str(base_dir),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual("", result.stderr)
|
||||||
|
self.assertEqual(0, result.returncode)
|
||||||
|
self.assertIn("Komodo-only run complete.", result.stdout)
|
||||||
|
calls = self.log.read_text(encoding="utf-8")
|
||||||
|
self.assertIn("check_komodo", calls)
|
||||||
|
self.assertNotIn("write_frame_focus_report", calls)
|
||||||
|
|
||||||
|
def test_run_watch_komodo_only_reports_when_komodo_changed(self):
|
||||||
|
base_dir = self.repo / "runs"
|
||||||
|
self.write_previous_komodo_report("2099-01-03", "2026-07-03T15:56:30")
|
||||||
|
self.write_previous_komodo_assets("2099-01-03")
|
||||||
|
os.environ["KOMODO_FRAME_MODIFIED"] = "2026-07-28T10:11:12"
|
||||||
|
self.addCleanup(lambda: os.environ.pop("KOMODO_FRAME_MODIFIED", None))
|
||||||
|
|
||||||
|
result = self.run_script(
|
||||||
|
str(self.scripts / "run_watch.sh"),
|
||||||
|
"--komodo-only",
|
||||||
|
"2099-01-04",
|
||||||
|
str(base_dir),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual("", result.stderr)
|
||||||
|
self.assertEqual(0, result.returncode)
|
||||||
|
self.assertIn("Komodo updated: yes (changed since previous run 2099-01-03)", result.stdout)
|
||||||
|
self.assertIn("Komodo changes:", result.stdout)
|
||||||
|
self.assertIn("- frame: 2026-07-03T15:56:30 -> 2026-07-28T10:11:12", result.stdout)
|
||||||
|
self.assertIn(
|
||||||
|
"Komodo timestamps: controller=2026-07-27T15:46:17, machine=2026-07-27T15:39:56, frame=2026-07-28T10:11:12",
|
||||||
|
result.stdout,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_run_watch_komodo_only_reports_new_asset_urls(self):
|
||||||
|
base_dir = self.repo / "runs"
|
||||||
|
self.write_previous_komodo_report("2099-01-05", "2026-07-03T15:56:30")
|
||||||
|
self.write_previous_komodo_assets("2099-01-05")
|
||||||
|
new_url = "https://komodostation.com/wp-content/uploads/2026/07/new-frame-asset.jpg"
|
||||||
|
os.environ["KOMODO_EXTRA_ASSET_URL"] = new_url
|
||||||
|
self.addCleanup(lambda: os.environ.pop("KOMODO_EXTRA_ASSET_URL", None))
|
||||||
|
|
||||||
|
result = self.run_script(
|
||||||
|
str(self.scripts / "run_watch.sh"),
|
||||||
|
"--komodo-only",
|
||||||
|
"2099-01-06",
|
||||||
|
str(base_dir),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual("", result.stderr)
|
||||||
|
self.assertEqual(0, result.returncode)
|
||||||
|
self.assertIn("Komodo new assets: yes (1 new, 3 current, since previous run 2099-01-05)", result.stdout)
|
||||||
|
self.assertIn("Komodo new asset URLs:", result.stdout)
|
||||||
|
self.assertIn(f"- {new_url}", result.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in new issue
Block a user