opencode-skills-collection 3.1.1 → 3.1.3
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/bundled-skills/.antigravity-install-manifest.json +4 -1
- package/bundled-skills/2slides-ppt-generator/SKILL.md +8 -7
- package/bundled-skills/agent-creator/SKILL.md +246 -0
- package/bundled-skills/android-cli/SKILL.md +19 -7
- package/bundled-skills/android-ui-journey-testing/SKILL.md +5 -5
- package/bundled-skills/apple-notes-search/SKILL.md +12 -2
- package/bundled-skills/atlas-ledger/SKILL.md +8 -0
- package/bundled-skills/ax-extract-workflow/SKILL.md +156 -0
- package/bundled-skills/codex-fable5/SKILL.md +10 -2
- package/bundled-skills/competitor-analysis/scripts/gate_candidates.mjs +45 -15
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/sources/sources.md +1 -1
- package/bundled-skills/docs/users/bundles.md +145 -1
- package/bundled-skills/docs/users/claude-code-skills.md +1 -1
- package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
- package/bundled-skills/docs/users/getting-started.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/specialized-plugin-roadmap.md +11 -4
- package/bundled-skills/docs/users/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/dos-verify-done-claims/SKILL.md +16 -4
- package/bundled-skills/ecl-harness-engineer/agents/creator-config.md +1 -1
- package/bundled-skills/ecl-harness-engineer/references/environment-config-guide.md +2 -2
- package/bundled-skills/ecl-harness-engineer/references/environment-detection-guide.md +4 -4
- package/bundled-skills/event-staffing-ordering/SKILL.md +4 -0
- package/bundled-skills/loop-library/SKILL.md +7 -4
- package/bundled-skills/lovable-cleanup/SKILL.md +11 -8
- package/bundled-skills/macos-screen-recorder/SKILL.md +9 -1
- package/bundled-skills/mailtrap-managing-contacts/SKILL.md +1 -1
- package/bundled-skills/mailtrap-sending-emails/SKILL.md +1 -1
- package/bundled-skills/mailtrap-setting-up-sending-domain/SKILL.md +1 -1
- package/bundled-skills/remote-gpu-trainer/.gitattributes +8 -0
- package/bundled-skills/remote-gpu-trainer/LICENSE +21 -0
- package/bundled-skills/remote-gpu-trainer/README.md +267 -0
- package/bundled-skills/remote-gpu-trainer/SKILL.md +249 -0
- package/bundled-skills/remote-gpu-trainer/evals/README.md +57 -0
- package/bundled-skills/remote-gpu-trainer/evals/RESULTS.md +44 -0
- package/bundled-skills/remote-gpu-trainer/evals/cases.jsonl +14 -0
- package/bundled-skills/remote-gpu-trainer/evals/run_evals.py +68 -0
- package/bundled-skills/remote-gpu-trainer/examples/autodl_sweep/README.md +72 -0
- package/bundled-skills/remote-gpu-trainer/examples/autodl_sweep/queue_1.txt +6 -0
- package/bundled-skills/remote-gpu-trainer/profiles/_schema.md +100 -0
- package/bundled-skills/remote-gpu-trainer/profiles/autodl.md +327 -0
- package/bundled-skills/remote-gpu-trainer/profiles/china.md +397 -0
- package/bundled-skills/remote-gpu-trainer/profiles/generic-ssh.md +450 -0
- package/bundled-skills/remote-gpu-trainer/profiles/lambda.md +342 -0
- package/bundled-skills/remote-gpu-trainer/profiles/paperspace.md +365 -0
- package/bundled-skills/remote-gpu-trainer/profiles/runpod.md +164 -0
- package/bundled-skills/remote-gpu-trainer/profiles/vastai.md +355 -0
- package/bundled-skills/remote-gpu-trainer/references/china-network.md +206 -0
- package/bundled-skills/remote-gpu-trainer/references/gotchas_universal.md +704 -0
- package/bundled-skills/remote-gpu-trainer/references/lifecycle_checklist.md +148 -0
- package/bundled-skills/remote-gpu-trainer/references/monitoring_patterns.md +327 -0
- package/bundled-skills/remote-gpu-trainer/references/multinode.md +190 -0
- package/bundled-skills/remote-gpu-trainer/references/parallel_ablation.md +196 -0
- package/bundled-skills/remote-gpu-trainer/references/principles.md +179 -0
- package/bundled-skills/remote-gpu-trainer/references/self-improvement.md +74 -0
- package/bundled-skills/remote-gpu-trainer/references/spot-resilience.md +235 -0
- package/bundled-skills/remote-gpu-trainer/references/ssh_transport.md +270 -0
- package/bundled-skills/remote-gpu-trainer/references/training/by-domain.md +230 -0
- package/bundled-skills/remote-gpu-trainer/references/training/checkpoint-resume.md +368 -0
- package/bundled-skills/remote-gpu-trainer/references/training/convergence-debugging.md +187 -0
- package/bundled-skills/remote-gpu-trainer/references/training/data-pipeline.md +119 -0
- package/bundled-skills/remote-gpu-trainer/references/training/distributed-launch.md +422 -0
- package/bundled-skills/remote-gpu-trainer/references/training/oom-memory.md +338 -0
- package/bundled-skills/remote-gpu-trainer/references/training/precision-stability.md +401 -0
- package/bundled-skills/remote-gpu-trainer/references/training/throughput-profiling.md +451 -0
- package/bundled-skills/remote-gpu-trainer/scripts/aggregate_to_fs.sh +55 -0
- package/bundled-skills/remote-gpu-trainer/scripts/check_staleness.py +70 -0
- package/bundled-skills/remote-gpu-trainer/scripts/download_loop.sh +67 -0
- package/bundled-skills/remote-gpu-trainer/scripts/gpu_health.sh +169 -0
- package/bundled-skills/remote-gpu-trainer/scripts/health_patrol.sh.template +67 -0
- package/bundled-skills/remote-gpu-trainer/scripts/mem_monitor.sh +67 -0
- package/bundled-skills/remote-gpu-trainer/scripts/reap_vram_zombies.sh +175 -0
- package/bundled-skills/remote-gpu-trainer/scripts/run_one.sh.template +104 -0
- package/bundled-skills/remote-gpu-trainer/scripts/run_queue.sh.template +83 -0
- package/bundled-skills/remote-gpu-trainer/scripts/setup-china-mirrors.sh +35 -0
- package/bundled-skills/remote-gpu-trainer/scripts/verify_local.py +145 -0
- package/bundled-skills/screenstudio-alt/SKILL.md +9 -1
- package/bundled-skills/vibecode-production-qa-validator/SKILL.md +1 -1
- package/bundled-skills/youtube-notetaker/scripts/serve.py +63 -14
- package/package.json +1 -1
- package/skills_index.json +128 -49
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Queue iterator for multi-ablation deployment — platform-agnostic.
|
|
3
|
+
#
|
|
4
|
+
# Network-accel hook so every child (incl. the tracker client) inherits it; ":" no-op on a clean box.
|
|
5
|
+
# See references/gotchas_universal.md and references/china-network.md.
|
|
6
|
+
PROXY_HOOK="${PROXY_HOOK:-source /etc/network_turbo}"
|
|
7
|
+
# PROXY_HOOK is an OPERATOR-supplied profile snippet (source a file / module load / export ...), eval'd
|
|
8
|
+
# on purpose to run an arbitrary setup hook. Set it ONLY from your own trusted profile, never from
|
|
9
|
+
# untrusted or remote-derived input.
|
|
10
|
+
eval "${PROXY_HOOK}" 2>/dev/null || true
|
|
11
|
+
#
|
|
12
|
+
# Each queue line: <config_yaml_path> <task> [epochs] (epochs defaults to 20)
|
|
13
|
+
# Calls $RUN_ONE per line — defaults to $DURABLE_DIR/run_one.sh (the durable/shared mount from
|
|
14
|
+
# profiles/<platform>.md §8). Export DURABLE_DIR, or set RUN_ONE directly if run_one.sh lives elsewhere.
|
|
15
|
+
#
|
|
16
|
+
# Usage: ./run_queue.sh <queue_file> [start_index]
|
|
17
|
+
# start_index defaults to 1 (run all). Pass N to RESUME from ablation N (principle #8 — see
|
|
18
|
+
# references/parallel_ablation.md §5).
|
|
19
|
+
#
|
|
20
|
+
# IMPORTANT: tmux/bash loads THIS script into memory at launch. Editing it mid-flight does NOT affect
|
|
21
|
+
# the running queue; only a NEW launch sees changes. Never overwrite it while a queue reads it
|
|
22
|
+
# (references/gotchas_universal.md, never-mutate-inputs-under-a-live-run; principle #6).
|
|
23
|
+
set -u
|
|
24
|
+
|
|
25
|
+
RUN_ONE="${RUN_ONE:-${DURABLE_DIR:-/root/autodl-fs}/run_one.sh}" # = <durable mount>/run_one.sh; export DURABLE_DIR (profile §8) or set RUN_ONE directly
|
|
26
|
+
|
|
27
|
+
# Arg-count guard FIRST — under `set -u`, QUEUE="$1" below would abort with an unbound-variable
|
|
28
|
+
# error before the Usage check could run. Guard so the Usage message is reachable.
|
|
29
|
+
if [ "$#" -lt 1 ]; then
|
|
30
|
+
echo "Usage: $0 <queue_file> [start_index]"
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
QUEUE="$1"
|
|
35
|
+
START="${2:-1}"
|
|
36
|
+
|
|
37
|
+
if [ -z "$QUEUE" ] || [ ! -f "$QUEUE" ]; then
|
|
38
|
+
echo "Usage: $0 <queue_file> [start_index]"
|
|
39
|
+
exit 1
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
HOSTNAME_SHORT=$(hostname -s)
|
|
43
|
+
# Count ablation CELLS only (skip #-comments + blank lines) so $TOTAL and the resume index are
|
|
44
|
+
# CELL numbers, not raw line numbers — `start_index=N` then resumes from ablation N regardless of how
|
|
45
|
+
# many comment/blank lines precede it (the loop below increments i only after the same skip guards).
|
|
46
|
+
TOTAL=$(grep -cvE '^[[:space:]]*(#|$)' "$QUEUE")
|
|
47
|
+
i=0
|
|
48
|
+
fail=0
|
|
49
|
+
failed_names=()
|
|
50
|
+
|
|
51
|
+
echo "=== Queue $(basename "$QUEUE"): $TOTAL ablations, starting from $START on $HOSTNAME_SHORT ==="
|
|
52
|
+
|
|
53
|
+
while IFS=$' \t' read -r cfg task epochs; do
|
|
54
|
+
# Skip comment/blank lines BEFORE counting so i (and the START resume index) count CELLS, not lines.
|
|
55
|
+
if [ -z "$cfg" ]; then continue; fi
|
|
56
|
+
case "$cfg" in \#*) continue ;; esac # skip #-prefixed comment lines
|
|
57
|
+
i=$((i+1))
|
|
58
|
+
if [ "$i" -lt "$START" ]; then continue; fi
|
|
59
|
+
|
|
60
|
+
EPOCHS="${epochs:-20}"
|
|
61
|
+
NAME=$(basename "$cfg" .yaml)
|
|
62
|
+
|
|
63
|
+
echo "================================================================"
|
|
64
|
+
echo "[$(date +'%Y-%m-%d %H:%M:%S')] [$i/$TOTAL] STARTING $NAME ($task, ${EPOCHS}ep)"
|
|
65
|
+
echo "================================================================"
|
|
66
|
+
|
|
67
|
+
bash "$RUN_ONE" "$cfg" "$task" "$EPOCHS"
|
|
68
|
+
RC=$?
|
|
69
|
+
if [ "$RC" -ne 0 ]; then fail=$((fail+1)); failed_names+=("$NAME"); fi
|
|
70
|
+
|
|
71
|
+
echo "[$(date +'%Y-%m-%d %H:%M:%S')] [$i/$TOTAL] FINISHED $NAME (exit=$RC)"
|
|
72
|
+
done < "$QUEUE"
|
|
73
|
+
|
|
74
|
+
echo "================================================================"
|
|
75
|
+
if [ "$fail" -eq 0 ]; then
|
|
76
|
+
echo "[$(date +'%Y-%m-%d %H:%M:%S')] === QUEUE DONE on $HOSTNAME_SHORT -- all $TOTAL cell(s) exited 0 ==="
|
|
77
|
+
else
|
|
78
|
+
echo "[$(date +'%Y-%m-%d %H:%M:%S')] === QUEUE DONE on $HOSTNAME_SHORT -- $fail cell(s) FAILED: ${failed_names[*]} ==="
|
|
79
|
+
fi
|
|
80
|
+
echo "================================================================"
|
|
81
|
+
# Propagate failure: a queue with any failed cell must NOT exit 0, or tmux/patrol
|
|
82
|
+
# automation reads "QUEUE DONE" as success and a broken ablation hides for hours.
|
|
83
|
+
[ "$fail" -eq 0 ] || exit 1
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# One-shot China-network setup for a rented GPU box behind the GFW.
|
|
3
|
+
# scp this to the instance, then `source` it (it exports env vars into the CURRENT shell):
|
|
4
|
+
# scp scripts/setup-china-mirrors.sh <alias>:/root/ && ssh <alias> 'source /root/setup-china-mirrors.sh'
|
|
5
|
+
# Full rationale + the no_proxy trap + the resumable-download ladder: references/china-network.md
|
|
6
|
+
set -u
|
|
7
|
+
|
|
8
|
+
# 1. HuggingFace -> hf-mirror (drop-in; identical repo IDs). MUST be set BEFORE importing
|
|
9
|
+
# huggingface_hub / transformers / datasets — they read HF_ENDPOINT at import time.
|
|
10
|
+
export HF_ENDPOINT="${HF_ENDPOINT:-https://hf-mirror.com}"
|
|
11
|
+
# Keep hf_transfer OFF on flaky CN links — documented hang-with-no-error in exactly these conditions.
|
|
12
|
+
export HF_HUB_ENABLE_HF_TRANSFER=0
|
|
13
|
+
|
|
14
|
+
# 2. Redirect model caches off the small system disk onto the data disk (override DATA_DIR per profile).
|
|
15
|
+
DATA_DIR="${DATA_DIR:-/root/autodl-tmp}"
|
|
16
|
+
export HF_HOME="${HF_HOME:-$DATA_DIR/huggingface}"
|
|
17
|
+
export HF_HUB_CACHE="${HF_HUB_CACHE:-$HF_HOME/hub}"
|
|
18
|
+
export MODELSCOPE_CACHE="${MODELSCOPE_CACHE:-$DATA_DIR/modelscope}"
|
|
19
|
+
mkdir -p "$HF_HOME" "$MODELSCOPE_CACHE"
|
|
20
|
+
|
|
21
|
+
# 3. pip index -> Tsinghua TUNA (Aliyun / USTC are alternates).
|
|
22
|
+
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple 2>/dev/null \
|
|
23
|
+
|| export PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
|
|
24
|
+
|
|
25
|
+
# 4. no_proxy hygiene — ONLY when an overseas proxy is exported in THIS shell. A proxy that fixes
|
|
26
|
+
# huggingface.co will route every domestic mirror overseas and break it unless exempted here.
|
|
27
|
+
# Use leading-dot domains, set BOTH spellings, include loopback.
|
|
28
|
+
if [ -n "${http_proxy:-}${https_proxy:-}" ]; then
|
|
29
|
+
export no_proxy="127.0.0.1,localhost,.tuna.tsinghua.edu.cn,.aliyuncs.com,.modelscope.cn,.hf-mirror.com"
|
|
30
|
+
export NO_PROXY="$no_proxy"
|
|
31
|
+
echo "[setup-china-mirrors] proxy detected -> exempted domestic mirrors via no_proxy"
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
echo "[setup-china-mirrors] HF_ENDPOINT=$HF_ENDPOINT HF_HOME=$HF_HOME"
|
|
35
|
+
echo "[setup-china-mirrors] done. conda: edit ~/.condarc per references/china-network.md (NEVER mirror pytorch-nightly)."
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Verify integrity of downloaded ckpt directories.
|
|
3
|
+
|
|
4
|
+
For each <name>/ in the target dir, check:
|
|
5
|
+
- best.pth exists
|
|
6
|
+
- best.pth loads cleanly via torch.load
|
|
7
|
+
- best.pth contains a weights key ('model_state_dict' / 'model' / 'state_dict')
|
|
8
|
+
- best_metrics.json exists and is valid JSON
|
|
9
|
+
- reports best epoch + main metric per ablation
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
python verify_local.py <path_to_final_ckpts_dir> [--expect N] [--list-metrics]
|
|
13
|
+
|
|
14
|
+
Exit code:
|
|
15
|
+
0 = all OK
|
|
16
|
+
1 = at least one error, an empty input dir, or a dir count != --expect
|
|
17
|
+
"""
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
import argparse
|
|
20
|
+
import json
|
|
21
|
+
import sys
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def main() -> int:
|
|
26
|
+
ap = argparse.ArgumentParser()
|
|
27
|
+
ap.add_argument("ckpt_dir", help="Directory containing ablation subdirs (each with best.pth + best_metrics.json)")
|
|
28
|
+
ap.add_argument("--list-metrics", action="store_true", help="Print per-ablation epoch + main metric")
|
|
29
|
+
ap.add_argument("--expect", type=int, default=None,
|
|
30
|
+
help="Assert exactly N ablation subdirs are present -- guards a teardown gate against a partial/empty pull")
|
|
31
|
+
ap.add_argument("--allow-pickle", action="store_true",
|
|
32
|
+
help="Permit the weights_only=False fallback (executes pickle) for checkpoints you trust -- "
|
|
33
|
+
"needed only when a checkpoint pickles non-tensor objects (e.g. an args Namespace); OFF by default")
|
|
34
|
+
args = ap.parse_args()
|
|
35
|
+
|
|
36
|
+
root = Path(args.ckpt_dir)
|
|
37
|
+
if not root.exists():
|
|
38
|
+
print(f"ERROR: {root} does not exist")
|
|
39
|
+
return 1
|
|
40
|
+
if not root.is_dir():
|
|
41
|
+
print(f"ERROR: {root} is not a directory")
|
|
42
|
+
return 1
|
|
43
|
+
|
|
44
|
+
# Structural checks BEFORE importing torch: an empty (or short) input must fail
|
|
45
|
+
# LOUDLY here -- never silently print "OK: 0/0" and return success, which would let
|
|
46
|
+
# a Phase-5 teardown gate destroy the rented disk having verified nothing
|
|
47
|
+
# (principle #3: trust the artifact, not a success line; the teardown Iron Law).
|
|
48
|
+
dirs = sorted([d for d in root.iterdir() if d.is_dir()])
|
|
49
|
+
if not dirs:
|
|
50
|
+
print(f"ERROR: no ablation subdirectories found in {root} -- refusing to report success on an empty input")
|
|
51
|
+
return 1
|
|
52
|
+
if args.expect is not None and len(dirs) != args.expect:
|
|
53
|
+
print(f"ERROR: expected {args.expect} ablation dirs but found {len(dirs)} in {root} -- partial/incomplete pull")
|
|
54
|
+
return 1
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
import torch
|
|
58
|
+
except ImportError:
|
|
59
|
+
print("ERROR: torch not installed in this environment")
|
|
60
|
+
return 1
|
|
61
|
+
|
|
62
|
+
print(f"Found {len(dirs)} ablation dirs in {root}")
|
|
63
|
+
print()
|
|
64
|
+
|
|
65
|
+
ok = 0
|
|
66
|
+
errors: list[tuple[str, str]] = []
|
|
67
|
+
metrics_rows: list[tuple[str, int, str]] = []
|
|
68
|
+
total_size_bytes = 0
|
|
69
|
+
|
|
70
|
+
for d in dirs:
|
|
71
|
+
name = d.name
|
|
72
|
+
pth = d / "best.pth"
|
|
73
|
+
metrics_path = d / "best_metrics.json"
|
|
74
|
+
|
|
75
|
+
if not pth.exists():
|
|
76
|
+
errors.append((name, "missing best.pth"))
|
|
77
|
+
continue
|
|
78
|
+
if not metrics_path.exists():
|
|
79
|
+
errors.append((name, "missing best_metrics.json"))
|
|
80
|
+
continue
|
|
81
|
+
|
|
82
|
+
# Load safe-by-default: weights_only=True refuses to execute pickle, so a poisoned or
|
|
83
|
+
# compromised remote checkpoint cannot run code on the operator's machine. The unsafe
|
|
84
|
+
# weights_only=False path (which DOES execute pickle) is OPT-IN via --allow-pickle: an attacker
|
|
85
|
+
# who controls the remote file could otherwise craft one that fails the safe load to FORCE the
|
|
86
|
+
# fallback, so auto-falling-back would defeat the gate. Pass --allow-pickle ONLY for your own ckpts.
|
|
87
|
+
try:
|
|
88
|
+
ckpt = torch.load(pth, map_location="cpu", weights_only=True)
|
|
89
|
+
except Exception as e_safe:
|
|
90
|
+
if not args.allow_pickle:
|
|
91
|
+
errors.append((name, f"safe load (weights_only=True) failed: {str(e_safe)[:70]} "
|
|
92
|
+
"-- re-run with --allow-pickle if this is your own checkpoint"))
|
|
93
|
+
continue
|
|
94
|
+
try:
|
|
95
|
+
print(
|
|
96
|
+
f" [warn] {name}: weights_only=True failed; --allow-pickle set, retrying "
|
|
97
|
+
"weights_only=False (executes pickle -- trust this file)"
|
|
98
|
+
)
|
|
99
|
+
ckpt = torch.load(pth, map_location="cpu", weights_only=False)
|
|
100
|
+
except Exception as e:
|
|
101
|
+
errors.append((name, f"torch.load failed: {str(e)[:100]}"))
|
|
102
|
+
continue
|
|
103
|
+
|
|
104
|
+
if not isinstance(ckpt, dict) or not any(k in ckpt for k in ("model_state_dict", "model", "state_dict")):
|
|
105
|
+
errors.append((name, "no model/model_state_dict/state_dict key in checkpoint"))
|
|
106
|
+
continue
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
with open(metrics_path) as f:
|
|
110
|
+
m = json.load(f)
|
|
111
|
+
except Exception as e:
|
|
112
|
+
errors.append((name, f"best_metrics.json invalid: {str(e)[:80]}"))
|
|
113
|
+
continue
|
|
114
|
+
|
|
115
|
+
epoch = m.get("epoch", "?")
|
|
116
|
+
if epoch is None: # {"epoch": null} → .get returns None (not the default); guard the :3 format. `or` would wrongly eat epoch 0.
|
|
117
|
+
epoch = "?"
|
|
118
|
+
# Pick main metric (PSNR for recon, mAP50 for det, dice for seg, fall back to loss)
|
|
119
|
+
main_metric_key = next(
|
|
120
|
+
(k for k in ["psnr", "mAP50", "dice"] if k in m),
|
|
121
|
+
"loss",
|
|
122
|
+
)
|
|
123
|
+
main_metric_val = m.get(main_metric_key, "?")
|
|
124
|
+
metrics_rows.append((name, epoch, f"{main_metric_key}={main_metric_val}"))
|
|
125
|
+
|
|
126
|
+
total_size_bytes += pth.stat().st_size
|
|
127
|
+
ok += 1
|
|
128
|
+
|
|
129
|
+
print(f"OK: {ok}/{len(dirs)}")
|
|
130
|
+
print(f"Errors: {len(errors)}")
|
|
131
|
+
for name, err in errors[:20]:
|
|
132
|
+
print(f" - {name}: {err}")
|
|
133
|
+
print(f"Total best.pth size: {total_size_bytes / 1e9:.1f} GB")
|
|
134
|
+
|
|
135
|
+
if args.list_metrics:
|
|
136
|
+
print()
|
|
137
|
+
print("=== Per-ablation metrics ===")
|
|
138
|
+
for name, epoch, metric in metrics_rows:
|
|
139
|
+
print(f" {name:40s} epoch={epoch:3} {metric}")
|
|
140
|
+
|
|
141
|
+
return 0 if not errors else 1
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
if __name__ == "__main__":
|
|
145
|
+
sys.exit(main())
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: screenstudio-alt
|
|
3
3
|
description: "Open-source headless Screen Studio alternative: auto speed-up of idle, auto-zoom on click clusters, keystroke overlay chips, smoothed synthetic cursor, and 9:16 vertical export that follows the action — post-production for screen recordings from the CLI."
|
|
4
|
-
risk:
|
|
4
|
+
risk: critical
|
|
5
5
|
source: community
|
|
6
6
|
source_type: community
|
|
7
7
|
source_repo: connerkward/screenstudio-alternative-skill
|
|
@@ -21,6 +21,14 @@ tools:
|
|
|
21
21
|
- cursor
|
|
22
22
|
- gemini-cli
|
|
23
23
|
- codex-cli
|
|
24
|
+
plugin:
|
|
25
|
+
targets:
|
|
26
|
+
codex: blocked
|
|
27
|
+
claude: blocked
|
|
28
|
+
setup:
|
|
29
|
+
type: manual
|
|
30
|
+
summary: "Screen/input capture requires sensitive local permissions; keep out of plugin-safe bundles."
|
|
31
|
+
docs: SKILL.md
|
|
24
32
|
---
|
|
25
33
|
## When to Use
|
|
26
34
|
|
|
@@ -58,7 +58,7 @@ qa:code() { npx tsc --noEmit && npx eslint . --ext .js,.jsx,.ts,.tsx --max-warni
|
|
|
58
58
|
- [ ] Build log has no errors
|
|
59
59
|
|
|
60
60
|
```bash
|
|
61
|
-
qa:build() { npm run build 2>&1 | tee
|
|
61
|
+
qa:build() { local log; log="$(mktemp "${TMPDIR:-/tmp}/qa-build.XXXXXX.log")" || return 1; set -o pipefail; npm run build 2>&1 | tee "$log"; local rc=$?; set +o pipefail; [ "$rc" -eq 0 ] && ! grep -qi "error\|failed" "$log"; local ok=$?; rm -f "$log"; return "$ok"; }
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
| Symbol | Meaning |
|
|
@@ -21,6 +21,8 @@ arbitrary and kept only so the same artifact HTML works unmodified):
|
|
|
21
21
|
"""
|
|
22
22
|
import argparse, json, os, sys, re, mimetypes, posixpath
|
|
23
23
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from tempfile import TemporaryDirectory
|
|
24
26
|
|
|
25
27
|
try:
|
|
26
28
|
import yaml
|
|
@@ -29,6 +31,9 @@ except ImportError:
|
|
|
29
31
|
|
|
30
32
|
API = "/api/video-deepdives"
|
|
31
33
|
FM_RE = re.compile(r"^---\n(.*?)\n---\n?(.*)$", re.DOTALL)
|
|
34
|
+
SAFE_SLUG_RE = re.compile(r"^[A-Za-z0-9_-]+$")
|
|
35
|
+
SAFE_MEDIA_RE = re.compile(r"^[A-Za-z0-9_.-]+$")
|
|
36
|
+
SAFE_CTYPE_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*(?:; charset=[A-Za-z0-9._-]+)?$")
|
|
32
37
|
|
|
33
38
|
|
|
34
39
|
def split_frontmatter(text):
|
|
@@ -45,20 +50,37 @@ def dump_file(meta, body):
|
|
|
45
50
|
return out + body
|
|
46
51
|
|
|
47
52
|
|
|
53
|
+
def library_path(lib, *parts):
|
|
54
|
+
root = Path(lib).resolve()
|
|
55
|
+
candidate = root.joinpath(*parts).resolve()
|
|
56
|
+
try:
|
|
57
|
+
candidate.relative_to(root)
|
|
58
|
+
except ValueError:
|
|
59
|
+
return None
|
|
60
|
+
return candidate
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def safe_content_type(ctype):
|
|
64
|
+
return ctype if isinstance(ctype, str) and SAFE_CTYPE_RE.match(ctype) else "application/octet-stream"
|
|
65
|
+
|
|
66
|
+
|
|
48
67
|
def load_item(lib, slug):
|
|
49
|
-
|
|
50
|
-
|
|
68
|
+
if not SAFE_SLUG_RE.match(slug):
|
|
69
|
+
return None
|
|
70
|
+
path = library_path(lib, slug + ".md")
|
|
71
|
+
if not path or not path.is_file():
|
|
51
72
|
return None
|
|
52
|
-
meta, body = split_frontmatter(
|
|
73
|
+
meta, body = split_frontmatter(path.read_text(encoding="utf-8"))
|
|
53
74
|
return path, meta, body
|
|
54
75
|
|
|
55
76
|
|
|
56
77
|
def list_items(lib):
|
|
57
78
|
items = []
|
|
58
|
-
for
|
|
59
|
-
|
|
79
|
+
for path in sorted(Path(lib).iterdir()):
|
|
80
|
+
fn = path.name
|
|
81
|
+
if not path.is_file() or not fn.endswith(".md") or fn.startswith("_"):
|
|
60
82
|
continue
|
|
61
|
-
slug =
|
|
83
|
+
slug = path.stem
|
|
62
84
|
loaded = load_item(lib, slug)
|
|
63
85
|
if not loaded:
|
|
64
86
|
continue
|
|
@@ -74,11 +96,13 @@ def list_items(lib):
|
|
|
74
96
|
class Handler(BaseHTTPRequestHandler):
|
|
75
97
|
lib = None
|
|
76
98
|
artifact = None
|
|
99
|
+
write_token = None
|
|
77
100
|
|
|
78
101
|
def log_message(self, *a):
|
|
79
102
|
pass # quiet
|
|
80
103
|
|
|
81
104
|
def _send(self, code, body, ctype="application/json"):
|
|
105
|
+
ctype = safe_content_type(ctype)
|
|
82
106
|
if isinstance(body, (dict, list)):
|
|
83
107
|
body = json.dumps(body).encode()
|
|
84
108
|
elif isinstance(body, str):
|
|
@@ -87,8 +111,8 @@ class Handler(BaseHTTPRequestHandler):
|
|
|
87
111
|
self.send_header("Content-Type", ctype)
|
|
88
112
|
self.send_header("Content-Length", str(len(body)))
|
|
89
113
|
self.send_header("Access-Control-Allow-Origin", "*")
|
|
90
|
-
self.send_header("Access-Control-Allow-Methods", "GET,
|
|
91
|
-
self.send_header("Access-Control-Allow-Headers", "Content-Type")
|
|
114
|
+
self.send_header("Access-Control-Allow-Methods", "GET, OPTIONS")
|
|
115
|
+
self.send_header("Access-Control-Allow-Headers", "Content-Type, X-Video-Library-Token")
|
|
92
116
|
self.end_headers()
|
|
93
117
|
if self.command != "HEAD":
|
|
94
118
|
self.wfile.write(body)
|
|
@@ -110,12 +134,13 @@ class Handler(BaseHTTPRequestHandler):
|
|
|
110
134
|
|
|
111
135
|
if path.startswith(API + "/_media/"):
|
|
112
136
|
fn = posixpath.basename(path) # strip any traversal
|
|
113
|
-
|
|
114
|
-
|
|
137
|
+
if not SAFE_MEDIA_RE.match(fn):
|
|
138
|
+
return self._send(400, {"error": "bad media name"})
|
|
139
|
+
fp = library_path(self.lib, "_media", fn)
|
|
140
|
+
if not fp or not fp.is_file():
|
|
115
141
|
return self._send(404, {"error": "no such media"})
|
|
116
|
-
ctype = mimetypes.guess_type(fp)[0] or "application/octet-stream"
|
|
117
|
-
|
|
118
|
-
return self._send(200, f.read(), ctype)
|
|
142
|
+
ctype = mimetypes.guess_type(str(fp))[0] or "application/octet-stream"
|
|
143
|
+
return self._send(200, fp.read_bytes(), ctype)
|
|
119
144
|
|
|
120
145
|
if path.startswith(API + "/"):
|
|
121
146
|
slug = posixpath.basename(path)
|
|
@@ -128,6 +153,10 @@ class Handler(BaseHTTPRequestHandler):
|
|
|
128
153
|
return self._send(404, {"error": "not found"})
|
|
129
154
|
|
|
130
155
|
def do_PATCH(self):
|
|
156
|
+
if not self.write_token:
|
|
157
|
+
return self._send(403, {"error": "writes disabled"})
|
|
158
|
+
if self.headers.get("X-Video-Library-Token") != self.write_token:
|
|
159
|
+
return self._send(403, {"error": "bad write token"})
|
|
131
160
|
path = self.path.split("?", 1)[0].rstrip("/")
|
|
132
161
|
if not path.startswith(API + "/"):
|
|
133
162
|
return self._send(404, {"error": "not found"})
|
|
@@ -145,26 +174,46 @@ class Handler(BaseHTTPRequestHandler):
|
|
|
145
174
|
if not isinstance(fields, dict):
|
|
146
175
|
return self._send(400, {"error": "fields must be an object"})
|
|
147
176
|
meta.update(fields)
|
|
148
|
-
|
|
177
|
+
fp.write_text(dump_file(meta, body), encoding="utf-8")
|
|
149
178
|
return self._send(200, {"ok": True, "slug": slug, "updated": list(fields.keys())})
|
|
150
179
|
|
|
151
180
|
|
|
181
|
+
def self_test():
|
|
182
|
+
with TemporaryDirectory() as tmp:
|
|
183
|
+
root = Path(tmp)
|
|
184
|
+
(root / "video_1.md").write_text("---\ntitle: Demo\n---\nBody", encoding="utf-8")
|
|
185
|
+
(root / "_media").mkdir()
|
|
186
|
+
(root / "_media" / "video_1-slide-01.jpg").write_bytes(b"x")
|
|
187
|
+
assert load_item(str(root), "video_1")
|
|
188
|
+
assert load_item(str(root), "../secret") is None
|
|
189
|
+
assert library_path(str(root), "_media", "../video_1.md") == root.resolve() / "video_1.md"
|
|
190
|
+
assert safe_content_type("text/html; charset=utf-8") == "text/html; charset=utf-8"
|
|
191
|
+
assert safe_content_type("text/html\r\nX-Bad: 1") == "application/octet-stream"
|
|
192
|
+
|
|
193
|
+
|
|
152
194
|
def main():
|
|
153
195
|
ap = argparse.ArgumentParser()
|
|
196
|
+
ap.add_argument("--self-test", action="store_true")
|
|
154
197
|
ap.add_argument("--dir", default=os.path.expanduser(os.environ.get("VIDEO_LIBRARY_DIR", "~/video-deepdives")))
|
|
155
198
|
ap.add_argument("--port", type=int, default=int(os.environ.get("VIDEO_LIBRARY_PORT", "8000")))
|
|
156
199
|
ap.add_argument("--host", default="127.0.0.1")
|
|
200
|
+
ap.add_argument("--write-token", default=os.environ.get("VIDEO_LIBRARY_WRITE_TOKEN"))
|
|
157
201
|
here = os.path.dirname(os.path.abspath(__file__))
|
|
158
202
|
ap.add_argument("--artifact", default=os.path.join(here, "..", "reference", "artifact.html"))
|
|
159
203
|
a = ap.parse_args()
|
|
204
|
+
if a.self_test:
|
|
205
|
+
self_test()
|
|
206
|
+
return
|
|
160
207
|
|
|
161
208
|
lib = os.path.abspath(os.path.expanduser(a.dir))
|
|
162
209
|
os.makedirs(lib, exist_ok=True)
|
|
163
210
|
Handler.lib = lib
|
|
164
211
|
Handler.artifact = os.path.abspath(a.artifact)
|
|
212
|
+
Handler.write_token = a.write_token
|
|
165
213
|
n = len([f for f in os.listdir(lib) if f.endswith(".md") and not f.startswith("_")])
|
|
166
214
|
print(f"Library: {lib} ({n} videos)")
|
|
167
215
|
print(f"Artifact: {Handler.artifact}")
|
|
216
|
+
print("Writes: " + ("enabled with X-Video-Library-Token" if Handler.write_token else "disabled (set VIDEO_LIBRARY_WRITE_TOKEN to enable PATCH)"))
|
|
168
217
|
print(f"Serving on http://{a.host}:{a.port}/ (Ctrl-C to stop)")
|
|
169
218
|
ThreadingHTTPServer((a.host, a.port), Handler).serve_forever()
|
|
170
219
|
|
package/package.json
CHANGED