mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-20 12:11:28 -07:00
Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
e35aac6ee0
|
|||
|
fe2da22d29
|
|||
|
2045ffbff8
|
|||
| 478869ff28 | |||
| 9eed37420e | |||
| 99f4d2baaf | |||
|
f4e8c3feec
|
|||
|
d0b308f340
|
|||
| 1b56360a24 | |||
|
68833c76c4
|
|||
| 4d7c80f2e4 | |||
|
2f17859b7b
|
|||
|
9c7e02cbf0
|
|||
|
5f320edab5
|
|||
|
f7ce3371a1
|
|||
|
71805dccd7
|
|||
|
a13b7352d7
|
|||
|
ff5ecdaded
|
|||
|
b32c3cf58c
|
|||
|
b791262860
|
|||
|
29b8c6e02a
|
|||
|
618727d8e8
|
|||
|
fed60c265d
|
|||
|
a34a7489db
|
|||
|
e59192bbe1
|
|||
|
e0f82d28f0
|
|||
|
a0521aeeaf
|
|||
|
2127f759ca
|
|||
|
5e787183d0
|
|||
|
81ca31b899
|
|||
|
e2a7597b4f
|
|||
|
2e59c21078
|
|||
|
7b5ab3294d
|
|||
|
2bbf38f987
|
|||
|
f09c91494d
|
|||
|
58ec9b76e0
|
|||
|
7a196f69d6
|
|||
| c799a8de3c | |||
|
34d2dce8dc
|
|||
|
3a22a97761
|
|||
|
962243e959
|
|||
|
021010a338
|
|||
|
4c0575afe0
|
|||
|
9e46176519
|
|||
|
f10e905dbd
|
|||
| e4aa8ff907 | |||
|
a6ece5388a
|
|||
|
6a44b54b51
|
|||
|
93cd688625
|
|||
|
8e319a417d
|
|||
|
38034db1e4
|
|||
|
f775f90360
|
|||
|
55dff6ced7
|
|||
|
d0c11d347b
|
|||
|
f0418c6e56
|
127
.agents/skills/subminer-change-verification/SKILL.md
Normal file
127
.agents/skills/subminer-change-verification/SKILL.md
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
---
|
||||||
|
name: "subminer-change-verification"
|
||||||
|
description: "Use when working in the SubMiner repo and you need to verify code changes actually work. Covers targeted regression checks during debugging and pre-handoff verification, with cheap-first lane selection for config, docs, launcher/plugin, runtime-compat, and optional real-runtime escalation."
|
||||||
|
---
|
||||||
|
|
||||||
|
# SubMiner Change Verification
|
||||||
|
|
||||||
|
Use this skill for SubMiner code changes. Default to cheap, repo-native verification first. Escalate only when the changed behavior actually depends on Electron, mpv, overlay/window tracking, or other GUI-sensitive runtime behavior.
|
||||||
|
|
||||||
|
## Scripts
|
||||||
|
|
||||||
|
- `scripts/classify_subminer_diff.sh`
|
||||||
|
- Emits suggested lanes and flags from explicit paths or current git changes.
|
||||||
|
- `scripts/verify_subminer_change.sh`
|
||||||
|
- Runs selected lanes, captures artifacts, and writes a compact summary.
|
||||||
|
|
||||||
|
If you need an explicit installed path, use the directory that contains this `SKILL.md`. The helper scripts live under:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export SUBMINER_VERIFY_SKILL="<path-to-skill>"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Default workflow
|
||||||
|
|
||||||
|
1. Inspect the changed files or user-requested area.
|
||||||
|
2. Run the classifier unless you already know the right lane.
|
||||||
|
3. Run the verifier with the cheapest sufficient lane set.
|
||||||
|
4. If the classifier emits `flag:real-runtime-candidate`, do not jump straight to runtime verification. First run the non-runtime lanes.
|
||||||
|
5. Escalate to explicit `--lane real-runtime --allow-real-runtime` only when cheaper lanes cannot validate the behavior claim.
|
||||||
|
6. Return:
|
||||||
|
- verification summary
|
||||||
|
- exact commands run
|
||||||
|
- artifact paths
|
||||||
|
- skipped lanes and blockers
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
Repo-source quick start:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash .agents/skills/subminer-change-verification/scripts/classify_subminer_diff.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Installed-skill quick start:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash "$SUBMINER_VERIFY_SKILL/scripts/classify_subminer_diff.sh"
|
||||||
|
```
|
||||||
|
|
||||||
|
Classify explicit files:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash .agents/skills/subminer-change-verification/scripts/classify_subminer_diff.sh \
|
||||||
|
launcher/main.ts \
|
||||||
|
plugin/subminer/lifecycle.lua \
|
||||||
|
src/main/runtime/mpv-client-runtime-service.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
Run automatic lane selection:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash .agents/skills/subminer-change-verification/scripts/verify_subminer_change.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Installed-skill form:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash "$SUBMINER_VERIFY_SKILL/scripts/verify_subminer_change.sh"
|
||||||
|
```
|
||||||
|
|
||||||
|
Run targeted lanes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash .agents/skills/subminer-change-verification/scripts/verify_subminer_change.sh \
|
||||||
|
--lane launcher-plugin \
|
||||||
|
--lane runtime-compat
|
||||||
|
```
|
||||||
|
|
||||||
|
Dry-run to inspect planned commands and artifact layout:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash .agents/skills/subminer-change-verification/scripts/verify_subminer_change.sh \
|
||||||
|
--dry-run \
|
||||||
|
launcher/main.ts \
|
||||||
|
src/main.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
## Lane guidance
|
||||||
|
|
||||||
|
- `docs`
|
||||||
|
- For `docs-site/`, `docs/`, and doc-only edits.
|
||||||
|
- `config`
|
||||||
|
- For `src/config/` and config-template-sensitive edits.
|
||||||
|
- `core`
|
||||||
|
- For general source changes where `typecheck` + `test:fast` is the best cheap signal.
|
||||||
|
- `launcher-plugin`
|
||||||
|
- For `launcher/`, `plugin/subminer/`, plugin gating scripts, and wrapper/mpv routing work.
|
||||||
|
- `runtime-compat`
|
||||||
|
- For `src/main*`, runtime/composer wiring, mpv/overlay services, window trackers, and dist-sensitive behavior.
|
||||||
|
- `real-runtime`
|
||||||
|
- Only after deliberate escalation.
|
||||||
|
|
||||||
|
## Real Runtime Escalation
|
||||||
|
|
||||||
|
Escalate only when the change claim depends on actual runtime behavior, for example:
|
||||||
|
|
||||||
|
- overlay appears, hides, or tracks a real mpv window
|
||||||
|
- mpv launch flags or pause-until-ready behavior
|
||||||
|
- plugin/socket/auto-start handshake under a real player
|
||||||
|
- macOS/window-tracker/focus-sensitive behavior
|
||||||
|
|
||||||
|
If the environment cannot support authoritative runtime verification, report the blocker explicitly. Do not silently downgrade a runtime-required claim to a pass.
|
||||||
|
|
||||||
|
## Artifact contract
|
||||||
|
|
||||||
|
The verifier writes under `.tmp/skill-verification/<timestamp>/`:
|
||||||
|
|
||||||
|
- `summary.json`
|
||||||
|
- `summary.txt`
|
||||||
|
- `classification.txt`
|
||||||
|
- `env.txt`
|
||||||
|
- `lanes.txt`
|
||||||
|
- `steps.tsv`
|
||||||
|
- `steps/*.stdout.log`
|
||||||
|
- `steps/*.stderr.log`
|
||||||
|
|
||||||
|
On failure, quote the exact failing command and point at the artifact directory.
|
||||||
163
.agents/skills/subminer-change-verification/scripts/classify_subminer_diff.sh
Executable file
163
.agents/skills/subminer-change-verification/scripts/classify_subminer_diff.sh
Executable file
@@ -0,0 +1,163 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: classify_subminer_diff.sh [path ...]
|
||||||
|
|
||||||
|
Emit suggested verification lanes for explicit paths or current local git changes.
|
||||||
|
|
||||||
|
Output format:
|
||||||
|
lane:<name>
|
||||||
|
flag:<name>
|
||||||
|
reason:<text>
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
has_item() {
|
||||||
|
local needle=$1
|
||||||
|
shift || true
|
||||||
|
local item
|
||||||
|
for item in "$@"; do
|
||||||
|
if [[ "$item" == "$needle" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
add_lane() {
|
||||||
|
local lane=$1
|
||||||
|
if ! has_item "$lane" "${LANES[@]:-}"; then
|
||||||
|
LANES+=("$lane")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
add_flag() {
|
||||||
|
local flag=$1
|
||||||
|
if ! has_item "$flag" "${FLAGS[@]:-}"; then
|
||||||
|
FLAGS+=("$flag")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
add_reason() {
|
||||||
|
REASONS+=("$1")
|
||||||
|
}
|
||||||
|
|
||||||
|
collect_git_paths() {
|
||||||
|
local top_level
|
||||||
|
if ! top_level=$(git rev-parse --show-toplevel 2>/dev/null); then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
(
|
||||||
|
cd "$top_level"
|
||||||
|
if git rev-parse --verify HEAD >/dev/null 2>&1; then
|
||||||
|
git diff --name-only --relative HEAD --
|
||||||
|
git diff --name-only --relative --cached --
|
||||||
|
else
|
||||||
|
git diff --name-only --relative --
|
||||||
|
git diff --name-only --relative --cached --
|
||||||
|
fi
|
||||||
|
git ls-files --others --exclude-standard
|
||||||
|
) | awk 'NF' | sort -u
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare -a PATHS=()
|
||||||
|
declare -a LANES=()
|
||||||
|
declare -a FLAGS=()
|
||||||
|
declare -a REASONS=()
|
||||||
|
|
||||||
|
if [[ $# -gt 0 ]]; then
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
PATHS+=("$1")
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
else
|
||||||
|
while IFS= read -r line; do
|
||||||
|
[[ -n "$line" ]] && PATHS+=("$line")
|
||||||
|
done < <(collect_git_paths)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#PATHS[@]} -eq 0 ]]; then
|
||||||
|
add_lane "core"
|
||||||
|
add_reason "no changed paths detected -> default to core"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for path in "${PATHS[@]}"; do
|
||||||
|
specialized=0
|
||||||
|
|
||||||
|
case "$path" in
|
||||||
|
docs-site/*|docs/*|changes/*|README.md)
|
||||||
|
add_lane "docs"
|
||||||
|
add_reason "$path -> docs"
|
||||||
|
specialized=1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$path" in
|
||||||
|
src/config/*|src/generate-config-example.ts|src/verify-config-example.ts|docs-site/public/config.example.jsonc|config.example.jsonc)
|
||||||
|
add_lane "config"
|
||||||
|
add_reason "$path -> config"
|
||||||
|
specialized=1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$path" in
|
||||||
|
launcher/*|plugin/subminer/*|plugin/subminer.conf|scripts/test-plugin-*|scripts/get-mpv-window-*|scripts/configure-plugin-binary-path.mjs)
|
||||||
|
add_lane "launcher-plugin"
|
||||||
|
add_reason "$path -> launcher-plugin"
|
||||||
|
add_flag "real-runtime-candidate"
|
||||||
|
add_reason "$path -> real-runtime-candidate"
|
||||||
|
specialized=1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$path" in
|
||||||
|
src/main.ts|src/main-entry.ts|src/preload.ts|src/main/*|src/core/services/mpv*|src/core/services/overlay*|src/renderer/*|src/window-trackers/*|scripts/prepare-build-assets.mjs)
|
||||||
|
add_lane "runtime-compat"
|
||||||
|
add_reason "$path -> runtime-compat"
|
||||||
|
add_flag "real-runtime-candidate"
|
||||||
|
add_reason "$path -> real-runtime-candidate"
|
||||||
|
specialized=1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ "$specialized" == "0" ]]; then
|
||||||
|
case "$path" in
|
||||||
|
src/*|package.json|tsconfig*.json|scripts/*|Makefile)
|
||||||
|
add_lane "core"
|
||||||
|
add_reason "$path -> core"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$path" in
|
||||||
|
package.json|src/main.ts|src/main-entry.ts|src/preload.ts)
|
||||||
|
add_flag "broad-impact"
|
||||||
|
add_reason "$path -> broad-impact"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#LANES[@]} -eq 0 ]]; then
|
||||||
|
add_lane "core"
|
||||||
|
add_reason "no lane-specific matches -> default to core"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for lane in "${LANES[@]}"; do
|
||||||
|
printf 'lane:%s\n' "$lane"
|
||||||
|
done
|
||||||
|
|
||||||
|
for flag in "${FLAGS[@]}"; do
|
||||||
|
printf 'flag:%s\n' "$flag"
|
||||||
|
done
|
||||||
|
|
||||||
|
for reason in "${REASONS[@]}"; do
|
||||||
|
printf 'reason:%s\n' "$reason"
|
||||||
|
done
|
||||||
566
.agents/skills/subminer-change-verification/scripts/verify_subminer_change.sh
Executable file
566
.agents/skills/subminer-change-verification/scripts/verify_subminer_change.sh
Executable file
@@ -0,0 +1,566 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: verify_subminer_change.sh [options] [path ...]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--lane <name> Force a verification lane. Repeatable.
|
||||||
|
--artifact-dir <dir> Use an explicit artifact directory.
|
||||||
|
--allow-real-runtime Allow explicit real-runtime execution.
|
||||||
|
--allow-real-gui Deprecated alias for --allow-real-runtime.
|
||||||
|
--dry-run Record planned steps without executing commands.
|
||||||
|
--help Show this help text.
|
||||||
|
|
||||||
|
If no lanes are supplied, the script classifies the provided paths. If no paths are
|
||||||
|
provided, it classifies the current local git changes.
|
||||||
|
|
||||||
|
Authoritative real-runtime verification should be requested with explicit path
|
||||||
|
arguments instead of relying on inferred local git changes.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
timestamp() {
|
||||||
|
date +%Y%m%d-%H%M%S
|
||||||
|
}
|
||||||
|
|
||||||
|
timestamp_iso() {
|
||||||
|
date -u +%Y-%m-%dT%H:%M:%SZ
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_session_id() {
|
||||||
|
local tmp_dir
|
||||||
|
tmp_dir=$(mktemp -d "${TMPDIR:-/tmp}/subminer-verify-$(timestamp)-XXXXXX")
|
||||||
|
basename "$tmp_dir"
|
||||||
|
rmdir "$tmp_dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
has_item() {
|
||||||
|
local needle=$1
|
||||||
|
shift || true
|
||||||
|
local item
|
||||||
|
for item in "$@"; do
|
||||||
|
if [[ "$item" == "$needle" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize_lane_name() {
|
||||||
|
case "$1" in
|
||||||
|
real-gui)
|
||||||
|
printf '%s' "real-runtime"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf '%s' "$1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
add_lane() {
|
||||||
|
local lane
|
||||||
|
lane=$(normalize_lane_name "$1")
|
||||||
|
if ! has_item "$lane" "${SELECTED_LANES[@]:-}"; then
|
||||||
|
SELECTED_LANES+=("$lane")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
add_blocker() {
|
||||||
|
BLOCKERS+=("$1")
|
||||||
|
BLOCKED=1
|
||||||
|
}
|
||||||
|
|
||||||
|
append_step_record() {
|
||||||
|
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
|
||||||
|
"$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" >>"$STEPS_TSV"
|
||||||
|
}
|
||||||
|
|
||||||
|
record_env() {
|
||||||
|
{
|
||||||
|
printf 'repo_root=%s\n' "$REPO_ROOT"
|
||||||
|
printf 'session_id=%s\n' "$SESSION_ID"
|
||||||
|
printf 'artifact_dir=%s\n' "$ARTIFACT_DIR"
|
||||||
|
printf 'path_selection_mode=%s\n' "$PATH_SELECTION_MODE"
|
||||||
|
printf 'dry_run=%s\n' "$DRY_RUN"
|
||||||
|
printf 'allow_real_runtime=%s\n' "$ALLOW_REAL_RUNTIME"
|
||||||
|
printf 'session_home=%s\n' "$SESSION_HOME"
|
||||||
|
printf 'session_xdg_config_home=%s\n' "$SESSION_XDG_CONFIG_HOME"
|
||||||
|
printf 'session_mpv_dir=%s\n' "$SESSION_MPV_DIR"
|
||||||
|
printf 'session_logs_dir=%s\n' "$SESSION_LOGS_DIR"
|
||||||
|
printf 'session_mpv_log=%s\n' "$SESSION_MPV_LOG"
|
||||||
|
printf 'pwd=%s\n' "$(pwd)"
|
||||||
|
git rev-parse --short HEAD 2>/dev/null | sed 's/^/git_head=/' || true
|
||||||
|
git status --short 2>/dev/null || true
|
||||||
|
if [[ ${#PATH_ARGS[@]} -gt 0 ]]; then
|
||||||
|
printf 'requested_paths=\n'
|
||||||
|
printf ' %s\n' "${PATH_ARGS[@]}"
|
||||||
|
fi
|
||||||
|
} >"$ARTIFACT_DIR/env.txt"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_step() {
|
||||||
|
local lane=$1
|
||||||
|
local name=$2
|
||||||
|
local command=$3
|
||||||
|
local note=${4:-}
|
||||||
|
local slug=${name//[^a-zA-Z0-9_-]/-}
|
||||||
|
local stdout_rel="steps/${slug}.stdout.log"
|
||||||
|
local stderr_rel="steps/${slug}.stderr.log"
|
||||||
|
local stdout_path="$ARTIFACT_DIR/$stdout_rel"
|
||||||
|
local stderr_path="$ARTIFACT_DIR/$stderr_rel"
|
||||||
|
local status exit_code
|
||||||
|
|
||||||
|
COMMANDS_RUN+=("$command")
|
||||||
|
printf '%s\n' "$command" >"$ARTIFACT_DIR/steps/${slug}.command.txt"
|
||||||
|
|
||||||
|
if [[ "$DRY_RUN" == "1" ]]; then
|
||||||
|
printf '[dry-run] %s\n' "$command" >"$stdout_path"
|
||||||
|
: >"$stderr_path"
|
||||||
|
status="dry-run"
|
||||||
|
exit_code=0
|
||||||
|
else
|
||||||
|
if bash -lc "cd \"$REPO_ROOT\" && $command" >"$stdout_path" 2>"$stderr_path"; then
|
||||||
|
status="passed"
|
||||||
|
exit_code=0
|
||||||
|
EXECUTED_REAL_STEPS=1
|
||||||
|
else
|
||||||
|
exit_code=$?
|
||||||
|
status="failed"
|
||||||
|
FAILED=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
append_step_record "$lane" "$name" "$status" "$exit_code" "$command" "$stdout_rel" "$stderr_rel" "$note"
|
||||||
|
printf '%s\t%s\t%s\n' "$lane" "$name" "$status"
|
||||||
|
|
||||||
|
if [[ "$status" == "failed" ]]; then
|
||||||
|
FAILURE_STEP="$name"
|
||||||
|
FAILURE_COMMAND="$command"
|
||||||
|
FAILURE_STDOUT="$stdout_rel"
|
||||||
|
FAILURE_STDERR="$stderr_rel"
|
||||||
|
return "$exit_code"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
record_nonpassing_step() {
|
||||||
|
local lane=$1
|
||||||
|
local name=$2
|
||||||
|
local status=$3
|
||||||
|
local note=$4
|
||||||
|
local slug=${name//[^a-zA-Z0-9_-]/-}
|
||||||
|
local stdout_rel="steps/${slug}.stdout.log"
|
||||||
|
local stderr_rel="steps/${slug}.stderr.log"
|
||||||
|
printf '%s\n' "$note" >"$ARTIFACT_DIR/$stdout_rel"
|
||||||
|
: >"$ARTIFACT_DIR/$stderr_rel"
|
||||||
|
append_step_record "$lane" "$name" "$status" "0" "" "$stdout_rel" "$stderr_rel" "$note"
|
||||||
|
printf '%s\t%s\t%s\n' "$lane" "$name" "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
record_skipped_step() {
|
||||||
|
record_nonpassing_step "$1" "$2" "skipped" "$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
record_blocked_step() {
|
||||||
|
add_blocker "$3"
|
||||||
|
record_nonpassing_step "$1" "$2" "blocked" "$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
record_failed_step() {
|
||||||
|
FAILED=1
|
||||||
|
FAILURE_STEP=$2
|
||||||
|
FAILURE_COMMAND=${FAILURE_COMMAND:-"(validation)"}
|
||||||
|
FAILURE_STDOUT="steps/${2//[^a-zA-Z0-9_-]/-}.stdout.log"
|
||||||
|
FAILURE_STDERR="steps/${2//[^a-zA-Z0-9_-]/-}.stderr.log"
|
||||||
|
add_blocker "$3"
|
||||||
|
record_nonpassing_step "$1" "$2" "failed" "$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
find_real_runtime_helper() {
|
||||||
|
local candidate
|
||||||
|
for candidate in \
|
||||||
|
"$SCRIPT_DIR/run_real_runtime_smoke.sh" \
|
||||||
|
"$SCRIPT_DIR/run_real_mpv_smoke.sh"; do
|
||||||
|
if [[ -x "$candidate" ]]; then
|
||||||
|
printf '%s' "$candidate"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
acquire_real_runtime_lease() {
|
||||||
|
local lease_root="$REPO_ROOT/.tmp/skill-verification/locks"
|
||||||
|
local lease_dir="$lease_root/exclusive-real-runtime"
|
||||||
|
mkdir -p "$lease_root"
|
||||||
|
if mkdir "$lease_dir" 2>/dev/null; then
|
||||||
|
REAL_RUNTIME_LEASE_DIR="$lease_dir"
|
||||||
|
printf '%s\n' "$SESSION_ID" >"$lease_dir/session_id"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local owner=""
|
||||||
|
if [[ -f "$lease_dir/session_id" ]]; then
|
||||||
|
owner=$(cat "$lease_dir/session_id")
|
||||||
|
fi
|
||||||
|
add_blocker "real-runtime lease already held${owner:+ by $owner}"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
release_real_runtime_lease() {
|
||||||
|
if [[ -n "$REAL_RUNTIME_LEASE_DIR" && -d "$REAL_RUNTIME_LEASE_DIR" ]]; then
|
||||||
|
if [[ -f "$REAL_RUNTIME_LEASE_DIR/session_id" ]]; then
|
||||||
|
local owner
|
||||||
|
owner=$(cat "$REAL_RUNTIME_LEASE_DIR/session_id")
|
||||||
|
if [[ "$owner" != "$SESSION_ID" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
rm -rf "$REAL_RUNTIME_LEASE_DIR"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
compute_final_status() {
|
||||||
|
if [[ "$FAILED" == "1" ]]; then
|
||||||
|
FINAL_STATUS="failed"
|
||||||
|
elif [[ "$BLOCKED" == "1" ]]; then
|
||||||
|
FINAL_STATUS="blocked"
|
||||||
|
elif [[ "$EXECUTED_REAL_STEPS" == "1" ]]; then
|
||||||
|
FINAL_STATUS="passed"
|
||||||
|
else
|
||||||
|
FINAL_STATUS="skipped"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
write_summary_files() {
|
||||||
|
local lane_lines
|
||||||
|
lane_lines=$(printf '%s\n' "${SELECTED_LANES[@]}")
|
||||||
|
printf '%s\n' "$lane_lines" >"$ARTIFACT_DIR/lanes.txt"
|
||||||
|
printf '%s\n' "${BLOCKERS[@]}" >"$ARTIFACT_DIR/blockers.txt"
|
||||||
|
printf '%s\n' "${PATH_ARGS[@]}" >"$ARTIFACT_DIR/requested-paths.txt"
|
||||||
|
|
||||||
|
ARTIFACT_DIR_ENV="$ARTIFACT_DIR" \
|
||||||
|
SESSION_ID_ENV="$SESSION_ID" \
|
||||||
|
FINAL_STATUS_ENV="$FINAL_STATUS" \
|
||||||
|
PATH_SELECTION_MODE_ENV="$PATH_SELECTION_MODE" \
|
||||||
|
ALLOW_REAL_RUNTIME_ENV="$ALLOW_REAL_RUNTIME" \
|
||||||
|
SESSION_HOME_ENV="$SESSION_HOME" \
|
||||||
|
SESSION_XDG_CONFIG_HOME_ENV="$SESSION_XDG_CONFIG_HOME" \
|
||||||
|
SESSION_MPV_DIR_ENV="$SESSION_MPV_DIR" \
|
||||||
|
SESSION_LOGS_DIR_ENV="$SESSION_LOGS_DIR" \
|
||||||
|
SESSION_MPV_LOG_ENV="$SESSION_MPV_LOG" \
|
||||||
|
STARTED_AT_ENV="$STARTED_AT" \
|
||||||
|
FINISHED_AT_ENV="$FINISHED_AT" \
|
||||||
|
FAILED_ENV="$FAILED" \
|
||||||
|
FAILURE_COMMAND_ENV="${FAILURE_COMMAND:-}" \
|
||||||
|
FAILURE_STDOUT_ENV="${FAILURE_STDOUT:-}" \
|
||||||
|
FAILURE_STDERR_ENV="${FAILURE_STDERR:-}" \
|
||||||
|
bun -e '
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
function readLines(filePath) {
|
||||||
|
if (!fs.existsSync(filePath)) return [];
|
||||||
|
return fs.readFileSync(filePath, "utf8").split(/\r?\n/).filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
const artifactDir = process.env.ARTIFACT_DIR_ENV;
|
||||||
|
const reportsDir = path.join(artifactDir, "reports");
|
||||||
|
const lanes = readLines(path.join(artifactDir, "lanes.txt"));
|
||||||
|
const blockers = readLines(path.join(artifactDir, "blockers.txt"));
|
||||||
|
const requestedPaths = readLines(path.join(artifactDir, "requested-paths.txt"));
|
||||||
|
const steps = readLines(path.join(artifactDir, "steps.tsv")).map((line) => {
|
||||||
|
const [lane, name, status, exitCode, command, stdout, stderr, note] = line.split("\t");
|
||||||
|
return {
|
||||||
|
lane,
|
||||||
|
name,
|
||||||
|
status,
|
||||||
|
exitCode: Number(exitCode || 0),
|
||||||
|
command,
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
note,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const summary = {
|
||||||
|
sessionId: process.env.SESSION_ID_ENV || "",
|
||||||
|
artifactDir,
|
||||||
|
reportsDir,
|
||||||
|
status: process.env.FINAL_STATUS_ENV || "failed",
|
||||||
|
selectedLanes: lanes,
|
||||||
|
failed: process.env.FAILED_ENV === "1",
|
||||||
|
failure:
|
||||||
|
process.env.FAILED_ENV === "1"
|
||||||
|
? {
|
||||||
|
command: process.env.FAILURE_COMMAND_ENV || "",
|
||||||
|
stdout: process.env.FAILURE_STDOUT_ENV || "",
|
||||||
|
stderr: process.env.FAILURE_STDERR_ENV || "",
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
blockers,
|
||||||
|
pathSelectionMode: process.env.PATH_SELECTION_MODE_ENV || "git-inferred",
|
||||||
|
requestedPaths,
|
||||||
|
allowRealRuntime: process.env.ALLOW_REAL_RUNTIME_ENV === "1",
|
||||||
|
startedAt: process.env.STARTED_AT_ENV || "",
|
||||||
|
finishedAt: process.env.FINISHED_AT_ENV || "",
|
||||||
|
env: {
|
||||||
|
home: process.env.SESSION_HOME_ENV || "",
|
||||||
|
xdgConfigHome: process.env.SESSION_XDG_CONFIG_HOME_ENV || "",
|
||||||
|
mpvDir: process.env.SESSION_MPV_DIR_ENV || "",
|
||||||
|
logsDir: process.env.SESSION_LOGS_DIR_ENV || "",
|
||||||
|
mpvLog: process.env.SESSION_MPV_LOG_ENV || "",
|
||||||
|
},
|
||||||
|
steps,
|
||||||
|
};
|
||||||
|
|
||||||
|
const summaryJson = JSON.stringify(summary, null, 2) + "\n";
|
||||||
|
fs.writeFileSync(path.join(artifactDir, "summary.json"), summaryJson);
|
||||||
|
fs.writeFileSync(path.join(reportsDir, "summary.json"), summaryJson);
|
||||||
|
|
||||||
|
const lines = [];
|
||||||
|
lines.push(`session_id: ${summary.sessionId}`);
|
||||||
|
lines.push(`artifact_dir: ${artifactDir}`);
|
||||||
|
lines.push(`selected_lanes: ${lanes.join(", ") || "(none)"}`);
|
||||||
|
lines.push(`status: ${summary.status}`);
|
||||||
|
lines.push(`path_selection_mode: ${summary.pathSelectionMode}`);
|
||||||
|
if (requestedPaths.length > 0) {
|
||||||
|
lines.push(`requested_paths: ${requestedPaths.join(", ")}`);
|
||||||
|
}
|
||||||
|
if (blockers.length > 0) {
|
||||||
|
lines.push(`blockers: ${blockers.join(" | ")}`);
|
||||||
|
}
|
||||||
|
for (const step of steps) {
|
||||||
|
lines.push(`${step.lane}/${step.name}: ${step.status}`);
|
||||||
|
if (step.command) lines.push(` command: ${step.command}`);
|
||||||
|
lines.push(` stdout: ${step.stdout}`);
|
||||||
|
lines.push(` stderr: ${step.stderr}`);
|
||||||
|
if (step.note) lines.push(` note: ${step.note}`);
|
||||||
|
}
|
||||||
|
if (summary.failed) {
|
||||||
|
lines.push(`failure_command: ${process.env.FAILURE_COMMAND_ENV || ""}`);
|
||||||
|
}
|
||||||
|
const summaryText = lines.join("\n") + "\n";
|
||||||
|
fs.writeFileSync(path.join(artifactDir, "summary.txt"), summaryText);
|
||||||
|
fs.writeFileSync(path.join(reportsDir, "summary.txt"), summaryText);
|
||||||
|
'
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
release_real_runtime_lease
|
||||||
|
}
|
||||||
|
|
||||||
|
CLASSIFIER_OUTPUT=""
|
||||||
|
ARTIFACT_DIR=""
|
||||||
|
ALLOW_REAL_RUNTIME=0
|
||||||
|
DRY_RUN=0
|
||||||
|
FAILED=0
|
||||||
|
BLOCKED=0
|
||||||
|
EXECUTED_REAL_STEPS=0
|
||||||
|
FINAL_STATUS=""
|
||||||
|
FAILURE_STEP=""
|
||||||
|
FAILURE_COMMAND=""
|
||||||
|
FAILURE_STDOUT=""
|
||||||
|
FAILURE_STDERR=""
|
||||||
|
REAL_RUNTIME_LEASE_DIR=""
|
||||||
|
STARTED_AT=""
|
||||||
|
FINISHED_AT=""
|
||||||
|
|
||||||
|
declare -a EXPLICIT_LANES=()
|
||||||
|
declare -a SELECTED_LANES=()
|
||||||
|
declare -a PATH_ARGS=()
|
||||||
|
declare -a COMMANDS_RUN=()
|
||||||
|
declare -a BLOCKERS=()
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--lane)
|
||||||
|
EXPLICIT_LANES+=("$(normalize_lane_name "$2")")
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--artifact-dir)
|
||||||
|
ARTIFACT_DIR=$2
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--allow-real-runtime|--allow-real-gui)
|
||||||
|
ALLOW_REAL_RUNTIME=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--dry-run)
|
||||||
|
DRY_RUN=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--help|-h)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
PATH_ARGS+=("$1")
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
PATH_ARGS+=("$1")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
|
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
||||||
|
SESSION_ID=$(generate_session_id)
|
||||||
|
PATH_SELECTION_MODE="git-inferred"
|
||||||
|
if [[ ${#PATH_ARGS[@]} -gt 0 ]]; then
|
||||||
|
PATH_SELECTION_MODE="explicit"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$ARTIFACT_DIR" ]]; then
|
||||||
|
mkdir -p "$REPO_ROOT/.tmp/skill-verification"
|
||||||
|
ARTIFACT_DIR="$REPO_ROOT/.tmp/skill-verification/$SESSION_ID"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SESSION_HOME="$ARTIFACT_DIR/home"
|
||||||
|
SESSION_XDG_CONFIG_HOME="$ARTIFACT_DIR/xdg"
|
||||||
|
SESSION_MPV_DIR="$ARTIFACT_DIR/mpv"
|
||||||
|
SESSION_LOGS_DIR="$ARTIFACT_DIR/logs"
|
||||||
|
SESSION_MPV_LOG="$SESSION_LOGS_DIR/mpv.log"
|
||||||
|
|
||||||
|
mkdir -p "$ARTIFACT_DIR/steps" "$ARTIFACT_DIR/reports" "$SESSION_HOME" "$SESSION_XDG_CONFIG_HOME" "$SESSION_MPV_DIR" "$SESSION_LOGS_DIR"
|
||||||
|
STEPS_TSV="$ARTIFACT_DIR/steps.tsv"
|
||||||
|
: >"$STEPS_TSV"
|
||||||
|
|
||||||
|
trap cleanup EXIT
|
||||||
|
STARTED_AT=$(timestamp_iso)
|
||||||
|
|
||||||
|
if [[ ${#EXPLICIT_LANES[@]} -gt 0 ]]; then
|
||||||
|
local_lane=""
|
||||||
|
for local_lane in "${EXPLICIT_LANES[@]}"; do
|
||||||
|
add_lane "$local_lane"
|
||||||
|
done
|
||||||
|
printf 'reason:explicit lanes supplied\n' >"$ARTIFACT_DIR/classification.txt"
|
||||||
|
else
|
||||||
|
if [[ ${#PATH_ARGS[@]} -gt 0 ]]; then
|
||||||
|
CLASSIFIER_OUTPUT=$(bash "$SCRIPT_DIR/classify_subminer_diff.sh" "${PATH_ARGS[@]}")
|
||||||
|
else
|
||||||
|
CLASSIFIER_OUTPUT=$(bash "$SCRIPT_DIR/classify_subminer_diff.sh")
|
||||||
|
fi
|
||||||
|
printf '%s\n' "$CLASSIFIER_OUTPUT" >"$ARTIFACT_DIR/classification.txt"
|
||||||
|
while IFS= read -r line; do
|
||||||
|
case "$line" in
|
||||||
|
lane:*)
|
||||||
|
add_lane "${line#lane:}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done <<<"$CLASSIFIER_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
record_env
|
||||||
|
|
||||||
|
printf 'artifact_dir=%s\n' "$ARTIFACT_DIR"
|
||||||
|
printf 'selected_lanes=%s\n' "$(IFS=,; echo "${SELECTED_LANES[*]}")"
|
||||||
|
|
||||||
|
for lane in "${SELECTED_LANES[@]}"; do
|
||||||
|
case "$lane" in
|
||||||
|
docs)
|
||||||
|
run_step "$lane" "docs-test" "bun run docs:test" || break
|
||||||
|
[[ "$FAILED" == "1" ]] && break
|
||||||
|
run_step "$lane" "docs-build" "bun run docs:build" || break
|
||||||
|
;;
|
||||||
|
config)
|
||||||
|
run_step "$lane" "test-config" "bun run test:config" || break
|
||||||
|
;;
|
||||||
|
core)
|
||||||
|
run_step "$lane" "typecheck" "bun run typecheck" || break
|
||||||
|
[[ "$FAILED" == "1" ]] && break
|
||||||
|
run_step "$lane" "test-fast" "bun run test:fast" || break
|
||||||
|
;;
|
||||||
|
launcher-plugin)
|
||||||
|
run_step "$lane" "launcher-smoke-src" "bun run test:launcher:smoke:src" || break
|
||||||
|
[[ "$FAILED" == "1" ]] && break
|
||||||
|
run_step "$lane" "plugin-src" "bun run test:plugin:src" || break
|
||||||
|
;;
|
||||||
|
runtime-compat)
|
||||||
|
run_step "$lane" "build" "bun run build" || break
|
||||||
|
[[ "$FAILED" == "1" ]] && break
|
||||||
|
run_step "$lane" "test-runtime-compat" "bun run test:runtime:compat" || break
|
||||||
|
[[ "$FAILED" == "1" ]] && break
|
||||||
|
run_step "$lane" "test-smoke-dist" "bun run test:smoke:dist" || break
|
||||||
|
;;
|
||||||
|
real-runtime)
|
||||||
|
if [[ "$PATH_SELECTION_MODE" != "explicit" ]]; then
|
||||||
|
record_blocked_step \
|
||||||
|
"$lane" \
|
||||||
|
"real-runtime-guard" \
|
||||||
|
"real-runtime lane requires explicit paths; inferred local git changes are non-authoritative"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$ALLOW_REAL_RUNTIME" != "1" ]]; then
|
||||||
|
record_blocked_step \
|
||||||
|
"$lane" \
|
||||||
|
"real-runtime-guard" \
|
||||||
|
"real-runtime lane requested but --allow-real-runtime was not supplied"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! acquire_real_runtime_lease; then
|
||||||
|
record_blocked_step \
|
||||||
|
"$lane" \
|
||||||
|
"real-runtime-lease" \
|
||||||
|
"real-runtime lease already held; rerun after the active runtime verification finishes"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! REAL_RUNTIME_HELPER=$(find_real_runtime_helper); then
|
||||||
|
record_blocked_step \
|
||||||
|
"$lane" \
|
||||||
|
"real-runtime-helper" \
|
||||||
|
"real-runtime helper not implemented yet"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf -v REAL_RUNTIME_COMMAND \
|
||||||
|
'SESSION_ID=%q HOME=%q XDG_CONFIG_HOME=%q SUBMINER_MPV_LOG=%q bash %q' \
|
||||||
|
"$SESSION_ID" \
|
||||||
|
"$SESSION_HOME" \
|
||||||
|
"$SESSION_XDG_CONFIG_HOME" \
|
||||||
|
"$SESSION_MPV_LOG" \
|
||||||
|
"$REAL_RUNTIME_HELPER"
|
||||||
|
|
||||||
|
run_step "$lane" "real-runtime-smoke" "$REAL_RUNTIME_COMMAND" || break
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
record_failed_step "$lane" "lane-validation" "unknown lane: $lane"
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ "$FAILED" == "1" || "$BLOCKED" == "1" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
FINISHED_AT=$(timestamp_iso)
|
||||||
|
compute_final_status
|
||||||
|
write_summary_files
|
||||||
|
|
||||||
|
printf 'status=%s\n' "$FINAL_STATUS"
|
||||||
|
printf 'artifact_dir=%s\n' "$ARTIFACT_DIR"
|
||||||
|
|
||||||
|
case "$FINAL_STATUS" in
|
||||||
|
failed)
|
||||||
|
printf 'result=failed\n'
|
||||||
|
printf 'failure_command=%s\n' "$FAILURE_COMMAND"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
blocked)
|
||||||
|
printf 'result=blocked\n'
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf 'result=ok\n'
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
146
.agents/skills/subminer-scrum-master/SKILL.md
Normal file
146
.agents/skills/subminer-scrum-master/SKILL.md
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
---
|
||||||
|
name: "subminer-scrum-master"
|
||||||
|
description: "Use in the SubMiner repo when a request should be turned into planned work and driven through execution. Assesses whether backlog tracking is warranted, creates or updates tasks when needed, records a plan, dispatches one or more subagents, and requires verification before handoff."
|
||||||
|
---
|
||||||
|
|
||||||
|
# SubMiner Scrum Master
|
||||||
|
|
||||||
|
Own workflow, not code by default.
|
||||||
|
|
||||||
|
Use this skill when the user gives a feature request, bug report, issue, refactor, or implementation ask and the agent should manage intake, planning, backlog hygiene, worker dispatch, and verification through completion.
|
||||||
|
|
||||||
|
## Core Rules
|
||||||
|
|
||||||
|
1. Decide first whether backlog tracking is warranted.
|
||||||
|
2. If backlog is needed, search first. Update existing work when it clearly matches.
|
||||||
|
3. If backlog is not needed, keep the process light. Do not invent ticket ceremony.
|
||||||
|
4. Record a plan before dispatching coding work.
|
||||||
|
5. Use parent + subtasks for multi-part work when backlog is used.
|
||||||
|
6. Dispatch conservatively. Parallelize only disjoint write scopes.
|
||||||
|
7. Require verification before handoff, typically via `subminer-change-verification`.
|
||||||
|
8. Report backlog actions, dispatched workers, verification, blockers, and remaining risks.
|
||||||
|
|
||||||
|
## Backlog Decision
|
||||||
|
|
||||||
|
Skip backlog when the request is:
|
||||||
|
- question only
|
||||||
|
- obvious mechanical edit
|
||||||
|
- tiny isolated change with no real planning
|
||||||
|
|
||||||
|
Use backlog when the work:
|
||||||
|
- needs planning or scope decisions
|
||||||
|
- spans multiple phases or subsystems
|
||||||
|
- is likely to need subagent dispatch
|
||||||
|
- should remain traceable for handoff/resume
|
||||||
|
|
||||||
|
If backlog is used:
|
||||||
|
- search existing tasks first
|
||||||
|
- create/update a standalone task for one focused deliverable
|
||||||
|
- create/update a parent task plus subtasks for multi-part work
|
||||||
|
- record the implementation plan in the task before implementation begins
|
||||||
|
|
||||||
|
## Intake Workflow
|
||||||
|
|
||||||
|
1. Parse the request.
|
||||||
|
Classify it as question, mechanical edit, bugfix, feature, refactor, investigation, or follow-up.
|
||||||
|
2. Decide whether backlog is needed.
|
||||||
|
3. If backlog is needed:
|
||||||
|
- search first
|
||||||
|
- update existing task if clearly relevant
|
||||||
|
- otherwise create the right structure
|
||||||
|
- write the implementation plan before dispatch
|
||||||
|
4. If backlog is skipped:
|
||||||
|
- write a short working plan in-thread
|
||||||
|
- proceed without fake ticketing
|
||||||
|
5. Choose execution mode:
|
||||||
|
- no subagents for trivial work
|
||||||
|
- one worker for focused work
|
||||||
|
- parallel workers only for disjoint scopes
|
||||||
|
6. Run verification before handoff.
|
||||||
|
|
||||||
|
## Dispatch Rules
|
||||||
|
|
||||||
|
The scrum master orchestrates. Workers implement.
|
||||||
|
|
||||||
|
- Do not become the default implementer unless delegation is unnecessary.
|
||||||
|
- Do not parallelize overlapping files or tightly coupled runtime work.
|
||||||
|
- Give every worker explicit ownership of files/modules.
|
||||||
|
- Tell every worker other agents may be active and they must not revert unrelated edits.
|
||||||
|
- Require each worker to report:
|
||||||
|
- changed files
|
||||||
|
- tests run
|
||||||
|
- blockers
|
||||||
|
|
||||||
|
Use worker agents for implementation and explorer agents only for bounded codebase questions.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
Every nontrivial code task gets verification.
|
||||||
|
|
||||||
|
Preferred flow:
|
||||||
|
1. use `subminer-change-verification`
|
||||||
|
2. start with the cheapest sufficient lane
|
||||||
|
3. escalate only when needed
|
||||||
|
4. if worker verification is sufficient, accept it or run one final consolidating pass
|
||||||
|
|
||||||
|
Never hand off nontrivial work without stating what was verified and what was skipped.
|
||||||
|
|
||||||
|
## Pre-Handoff Policy Checks (Required)
|
||||||
|
|
||||||
|
Before handoff, always ask and answer both of these questions explicitly:
|
||||||
|
|
||||||
|
1. **Docs update required?**
|
||||||
|
2. **Changelog fragment required?**
|
||||||
|
|
||||||
|
Rules:
|
||||||
|
- Do not assume silence implies "no." Record an explicit yes/no decision for each item.
|
||||||
|
- If the answer is yes, either complete the update or report the blocker before handoff.
|
||||||
|
- Include the final answers in the handoff summary even when both answers are "no."
|
||||||
|
|
||||||
|
## Failure / Scope Handling
|
||||||
|
|
||||||
|
- If a worker hits ambiguity, pause and ask the user.
|
||||||
|
- If verification fails, either:
|
||||||
|
- send the worker back with exact failure context, or
|
||||||
|
- fix it directly if it is tiny and clearly in scope
|
||||||
|
- If new scope appears, revisit backlog structure before silently expanding work.
|
||||||
|
|
||||||
|
## Representative Flows
|
||||||
|
|
||||||
|
### Trivial no-ticket work
|
||||||
|
|
||||||
|
- decide backlog is unnecessary
|
||||||
|
- keep a short plan
|
||||||
|
- implement directly or with one worker if helpful
|
||||||
|
- run targeted verification
|
||||||
|
- report outcome concisely
|
||||||
|
|
||||||
|
### Single-task implementation
|
||||||
|
|
||||||
|
- search/create/update one task
|
||||||
|
- record plan
|
||||||
|
- dispatch one worker
|
||||||
|
- integrate
|
||||||
|
- verify
|
||||||
|
- update task and report outcome
|
||||||
|
|
||||||
|
### Parent + subtasks execution
|
||||||
|
|
||||||
|
- search/create/update parent task
|
||||||
|
- create subtasks for distinct deliverables/phases
|
||||||
|
- record sequencing in the plan
|
||||||
|
- dispatch workers only where scopes are disjoint
|
||||||
|
- integrate
|
||||||
|
- run consolidated verification
|
||||||
|
- update task state and report outcome
|
||||||
|
|
||||||
|
## Output Expectations
|
||||||
|
|
||||||
|
At the end, report:
|
||||||
|
- whether backlog was used and what changed
|
||||||
|
- which workers were dispatched and what they owned
|
||||||
|
- what verification ran
|
||||||
|
- explicit answers to:
|
||||||
|
- docs update required?
|
||||||
|
- changelog fragment required?
|
||||||
|
- blockers, skips, and risks
|
||||||
3
.github/pull_request_template.md
vendored
Normal file
3
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
## Checklist
|
||||||
|
|
||||||
|
- [ ] Added a changelog fragment in `changes/`, or this PR is labeled `skip-changelog`
|
||||||
16
.github/workflows/ci.yml
vendored
16
.github/workflows/ci.yml
vendored
@@ -13,6 +13,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
|
|
||||||
- name: Setup Bun
|
- name: Setup Bun
|
||||||
@@ -20,11 +21,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
bun-version: 1.3.5
|
bun-version: 1.3.5
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 22.12.0
|
|
||||||
|
|
||||||
- name: Cache dependencies
|
- name: Cache dependencies
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
@@ -39,10 +35,20 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: bun install --frozen-lockfile
|
run: bun install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Lint changelog fragments
|
||||||
|
run: bun run changelog:lint
|
||||||
|
|
||||||
|
- name: Enforce pull request changelog fragments (`skip-changelog` label bypass)
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
run: bun run changelog:pr-check --base-ref "origin/${{ github.base_ref }}" --head-ref "HEAD" --labels "${{ join(github.event.pull_request.labels.*.name, ',') }}"
|
||||||
|
|
||||||
- name: Build (TypeScript check)
|
- name: Build (TypeScript check)
|
||||||
# Keep explicit typecheck for fast fail before full build/bundle.
|
# Keep explicit typecheck for fast fail before full build/bundle.
|
||||||
run: bun run typecheck
|
run: bun run typecheck
|
||||||
|
|
||||||
|
- name: Verify generated config examples
|
||||||
|
run: bun run verify:config-example
|
||||||
|
|
||||||
- name: Test suite (source)
|
- name: Test suite (source)
|
||||||
run: bun run test:fast
|
run: bun run test:fast
|
||||||
|
|
||||||
|
|||||||
230
.github/workflows/release.yml
vendored
230
.github/workflows/release.yml
vendored
@@ -9,9 +9,6 @@ concurrency:
|
|||||||
group: release-${{ github.ref }}
|
group: release-${{ github.ref }}
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
quality-gate:
|
quality-gate:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,11 +23,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
bun-version: 1.3.5
|
bun-version: 1.3.5
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 22.12.0
|
|
||||||
|
|
||||||
- name: Cache dependencies
|
- name: Cache dependencies
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
@@ -85,11 +77,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
bun-version: 1.3.5
|
bun-version: 1.3.5
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 22.12.0
|
|
||||||
|
|
||||||
- name: Cache dependencies
|
- name: Cache dependencies
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
@@ -113,8 +100,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Build AppImage
|
- name: Build AppImage
|
||||||
run: bun run build:appimage
|
run: bun run build:appimage
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build unversioned AppImage
|
- name: Build unversioned AppImage
|
||||||
run: |
|
run: |
|
||||||
@@ -147,11 +132,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
bun-version: 1.3.5
|
bun-version: 1.3.5
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 22.12.0
|
|
||||||
|
|
||||||
- name: Cache dependencies
|
- name: Cache dependencies
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
@@ -196,7 +176,6 @@ jobs:
|
|||||||
- name: Build signed + notarized macOS artifacts
|
- name: Build signed + notarized macOS artifacts
|
||||||
run: bun run build:mac
|
run: bun run build:mac
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
CSC_LINK: ${{ secrets.CSC_LINK }}
|
CSC_LINK: ${{ secrets.CSC_LINK }}
|
||||||
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
||||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||||
@@ -211,9 +190,59 @@ jobs:
|
|||||||
release/*.dmg
|
release/*.dmg
|
||||||
release/*.zip
|
release/*.zip
|
||||||
|
|
||||||
|
build-windows:
|
||||||
|
needs: [quality-gate]
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
|
||||||
|
- name: Setup Bun
|
||||||
|
uses: oven-sh/setup-bun@v2
|
||||||
|
with:
|
||||||
|
bun-version: 1.3.5
|
||||||
|
|
||||||
|
- name: Cache dependencies
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.bun/install/cache
|
||||||
|
node_modules
|
||||||
|
vendor/texthooker-ui/node_modules
|
||||||
|
vendor/subminer-yomitan/node_modules
|
||||||
|
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock', 'vendor/texthooker-ui/package.json', 'vendor/subminer-yomitan/package-lock.json') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-bun-
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: bun install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Build texthooker-ui
|
||||||
|
shell: powershell
|
||||||
|
run: |
|
||||||
|
Set-Location vendor/texthooker-ui
|
||||||
|
bun install
|
||||||
|
bun run build
|
||||||
|
|
||||||
|
- name: Build unsigned Windows artifacts
|
||||||
|
run: bun run build:win:unsigned
|
||||||
|
|
||||||
|
- name: Upload Windows artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: windows
|
||||||
|
path: |
|
||||||
|
release/*.exe
|
||||||
|
release/*.zip
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
release:
|
release:
|
||||||
needs: [build-linux, build-macos]
|
needs: [build-linux, build-macos, build-windows]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -232,6 +261,12 @@ jobs:
|
|||||||
name: macos
|
name: macos
|
||||||
path: release
|
path: release
|
||||||
|
|
||||||
|
- name: Download Windows artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: windows
|
||||||
|
path: release
|
||||||
|
|
||||||
- name: Setup Bun
|
- name: Setup Bun
|
||||||
uses: oven-sh/setup-bun@v2
|
uses: oven-sh/setup-bun@v2
|
||||||
with:
|
with:
|
||||||
@@ -259,6 +294,9 @@ jobs:
|
|||||||
- name: Enforce generated launcher workflow
|
- name: Enforce generated launcher workflow
|
||||||
run: bash scripts/verify-generated-launcher.sh
|
run: bash scripts/verify-generated-launcher.sh
|
||||||
|
|
||||||
|
- name: Verify generated config examples
|
||||||
|
run: bun run verify:config-example
|
||||||
|
|
||||||
- name: Package optional assets bundle
|
- name: Package optional assets bundle
|
||||||
run: |
|
run: |
|
||||||
tar -czf "release/subminer-assets.tar.gz" \
|
tar -czf "release/subminer-assets.tar.gz" \
|
||||||
@@ -270,7 +308,7 @@ jobs:
|
|||||||
- name: Generate checksums
|
- name: Generate checksums
|
||||||
run: |
|
run: |
|
||||||
shopt -s nullglob
|
shopt -s nullglob
|
||||||
files=(release/*.AppImage release/*.dmg release/*.zip release/*.tar.gz dist/launcher/subminer)
|
files=(release/*.AppImage release/*.dmg release/*.exe release/*.zip release/*.tar.gz dist/launcher/subminer)
|
||||||
if [ "${#files[@]}" -eq 0 ]; then
|
if [ "${#files[@]}" -eq 0 ]; then
|
||||||
echo "No release artifacts found for checksum generation."
|
echo "No release artifacts found for checksum generation."
|
||||||
exit 1
|
exit 1
|
||||||
@@ -279,25 +317,13 @@ jobs:
|
|||||||
|
|
||||||
- name: Get version from tag
|
- name: Get version from tag
|
||||||
id: version
|
id: version
|
||||||
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Generate changelog
|
- name: Verify changelog is ready for tagged release
|
||||||
id: changelog
|
run: bun run changelog:check --version "${{ steps.version.outputs.VERSION }}"
|
||||||
run: |
|
|
||||||
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
|
- name: Generate release notes from changelog
|
||||||
if [ -n "$PREV_TAG" ]; then
|
run: bun run changelog:release-notes --version "${{ steps.version.outputs.VERSION }}"
|
||||||
CHANGES=$(git log --pretty=format:"- %s" ${PREV_TAG}..HEAD)
|
|
||||||
else
|
|
||||||
COMMIT_COUNT=$(git rev-list --count HEAD)
|
|
||||||
if [ "$COMMIT_COUNT" -gt 10 ]; then
|
|
||||||
CHANGES=$(git log --pretty=format:"- %s" HEAD~10..HEAD)
|
|
||||||
else
|
|
||||||
CHANGES=$(git log --pretty=format:"- %s")
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo "CHANGES<<EOF" >> $GITHUB_OUTPUT
|
|
||||||
echo "$CHANGES" >> $GITHUB_OUTPUT
|
|
||||||
echo "EOF" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Publish Release
|
- name: Publish Release
|
||||||
env:
|
env:
|
||||||
@@ -305,53 +331,23 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
cat > release-body.md <<'EOF'
|
|
||||||
## Changes
|
|
||||||
${{ steps.changelog.outputs.CHANGES }}
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
### AppImage (Recommended)
|
|
||||||
1. Download the AppImage below
|
|
||||||
2. Make it executable: `chmod +x SubMiner.AppImage`
|
|
||||||
3. Run: `./SubMiner.AppImage`
|
|
||||||
|
|
||||||
### macOS
|
|
||||||
1. Download `subminer-*.dmg`
|
|
||||||
2. Open the DMG and drag `SubMiner.app` into `/Applications`
|
|
||||||
3. If needed, use the ZIP artifact as an alternative
|
|
||||||
|
|
||||||
### Manual Installation
|
|
||||||
See the [README](https://github.com/${{ github.repository }}#installation) for manual installation instructions.
|
|
||||||
|
|
||||||
### Optional Assets (config example + mpv plugin + rofi theme)
|
|
||||||
1. Download `subminer-assets.tar.gz`
|
|
||||||
2. Extract and copy `config.example.jsonc` to `~/.config/SubMiner/config.jsonc`
|
|
||||||
3. Copy `plugin/subminer/` directory contents to `~/.config/mpv/scripts/`
|
|
||||||
4. Copy `plugin/subminer.conf` to `~/.config/mpv/script-opts/`
|
|
||||||
5. Copy `assets/themes/subminer.rasi` to:
|
|
||||||
- Linux: `~/.local/share/SubMiner/themes/subminer.rasi`
|
|
||||||
- macOS: `~/Library/Application Support/SubMiner/themes/subminer.rasi`
|
|
||||||
|
|
||||||
Note: the `subminer` wrapper script uses Bun (`#!/usr/bin/env bun`), so `bun` must be installed and on `PATH`.
|
|
||||||
EOF
|
|
||||||
|
|
||||||
if gh release view "${{ steps.version.outputs.VERSION }}" >/dev/null 2>&1; then
|
if gh release view "${{ steps.version.outputs.VERSION }}" >/dev/null 2>&1; then
|
||||||
|
# Do not pass the prerelease flag here; gh defaults to a normal release.
|
||||||
gh release edit "${{ steps.version.outputs.VERSION }}" \
|
gh release edit "${{ steps.version.outputs.VERSION }}" \
|
||||||
|
--draft=false \
|
||||||
--title "${{ steps.version.outputs.VERSION }}" \
|
--title "${{ steps.version.outputs.VERSION }}" \
|
||||||
--notes-file release-body.md \
|
--notes-file release/release-notes.md
|
||||||
--prerelease false
|
|
||||||
else
|
else
|
||||||
gh release create "${{ steps.version.outputs.VERSION }}" \
|
gh release create "${{ steps.version.outputs.VERSION }}" \
|
||||||
--title "${{ steps.version.outputs.VERSION }}" \
|
--title "${{ steps.version.outputs.VERSION }}" \
|
||||||
--notes-file release-body.md \
|
--notes-file release/release-notes.md
|
||||||
--prerelease false
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
shopt -s nullglob
|
shopt -s nullglob
|
||||||
artifacts=(
|
artifacts=(
|
||||||
release/*.AppImage
|
release/*.AppImage
|
||||||
release/*.dmg
|
release/*.dmg
|
||||||
|
release/*.exe
|
||||||
release/*.zip
|
release/*.zip
|
||||||
release/*.tar.gz
|
release/*.tar.gz
|
||||||
release/SHA256SUMS.txt
|
release/SHA256SUMS.txt
|
||||||
@@ -366,3 +362,85 @@ jobs:
|
|||||||
for asset in "${artifacts[@]}"; do
|
for asset in "${artifacts[@]}"; do
|
||||||
gh release upload "${{ steps.version.outputs.VERSION }}" "$asset" --clobber
|
gh release upload "${{ steps.version.outputs.VERSION }}" "$asset" --clobber
|
||||||
done
|
done
|
||||||
|
|
||||||
|
aur-publish:
|
||||||
|
needs: [release]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Get version from tag
|
||||||
|
id: version
|
||||||
|
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Validate AUR SSH secret
|
||||||
|
env:
|
||||||
|
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
if [ -z "${AUR_SSH_PRIVATE_KEY}" ]; then
|
||||||
|
echo "Missing required secret: AUR_SSH_PRIVATE_KEY"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Configure SSH for AUR
|
||||||
|
env:
|
||||||
|
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
install -dm700 ~/.ssh
|
||||||
|
printf '%s\n' "${AUR_SSH_PRIVATE_KEY}" > ~/.ssh/aur
|
||||||
|
chmod 600 ~/.ssh/aur
|
||||||
|
ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts
|
||||||
|
chmod 644 ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- name: Clone AUR repo
|
||||||
|
env:
|
||||||
|
GIT_SSH_COMMAND: ssh -i ~/.ssh/aur -o IdentitiesOnly=yes
|
||||||
|
run: git clone ssh://aur@aur.archlinux.org/subminer-bin.git aur-subminer-bin
|
||||||
|
|
||||||
|
- name: Download release assets for AUR
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
version="${{ steps.version.outputs.VERSION }}"
|
||||||
|
install -dm755 .tmp/aur-release-assets
|
||||||
|
gh release download "$version" \
|
||||||
|
--dir .tmp/aur-release-assets \
|
||||||
|
--pattern "SubMiner-${version#v}.AppImage" \
|
||||||
|
--pattern "subminer" \
|
||||||
|
--pattern "subminer-assets.tar.gz"
|
||||||
|
|
||||||
|
- name: Update AUR packaging metadata
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
version_no_v="${{ steps.version.outputs.VERSION }}"
|
||||||
|
version_no_v="${version_no_v#v}"
|
||||||
|
cp packaging/aur/subminer-bin/PKGBUILD aur-subminer-bin/PKGBUILD
|
||||||
|
cp packaging/aur/subminer-bin/.SRCINFO aur-subminer-bin/.SRCINFO
|
||||||
|
bash scripts/update-aur-package.sh \
|
||||||
|
--pkg-dir aur-subminer-bin \
|
||||||
|
--version "${{ steps.version.outputs.VERSION }}" \
|
||||||
|
--appimage ".tmp/aur-release-assets/SubMiner-${version_no_v}.AppImage" \
|
||||||
|
--wrapper ".tmp/aur-release-assets/subminer" \
|
||||||
|
--assets ".tmp/aur-release-assets/subminer-assets.tar.gz"
|
||||||
|
|
||||||
|
- name: Commit and push AUR update
|
||||||
|
working-directory: aur-subminer-bin
|
||||||
|
env:
|
||||||
|
GIT_SSH_COMMAND: ssh -i ~/.ssh/aur -o IdentitiesOnly=yes
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
if git diff --quiet -- PKGBUILD .SRCINFO; then
|
||||||
|
echo "AUR packaging already up to date."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||||
|
git add PKGBUILD .SRCINFO
|
||||||
|
git commit -m "Update to ${{ steps.version.outputs.VERSION }}"
|
||||||
|
git push origin HEAD:master
|
||||||
|
|||||||
16
.gitignore
vendored
16
.gitignore
vendored
@@ -35,6 +35,20 @@ docs/.vitepress/cache/
|
|||||||
docs/.vitepress/dist/
|
docs/.vitepress/dist/
|
||||||
tests/*
|
tests/*
|
||||||
.worktrees/
|
.worktrees/
|
||||||
|
.tmp/
|
||||||
.codex/*
|
.codex/*
|
||||||
.agents/*
|
.agents/*
|
||||||
docs/*
|
!.agents/skills/
|
||||||
|
.agents/skills/*
|
||||||
|
!.agents/skills/subminer-change-verification/
|
||||||
|
!.agents/skills/subminer-scrum-master/
|
||||||
|
.agents/skills/subminer-change-verification/*
|
||||||
|
!.agents/skills/subminer-change-verification/SKILL.md
|
||||||
|
!.agents/skills/subminer-change-verification/scripts/
|
||||||
|
.agents/skills/subminer-change-verification/scripts/*
|
||||||
|
!.agents/skills/subminer-change-verification/scripts/classify_subminer_diff.sh
|
||||||
|
!.agents/skills/subminer-change-verification/scripts/verify_subminer_change.sh
|
||||||
|
.agents/skills/subminer-scrum-master/*
|
||||||
|
!.agents/skills/subminer-scrum-master/SKILL.md
|
||||||
|
favicon.png
|
||||||
|
.claude/*
|
||||||
|
|||||||
77
AGENTS.md
77
AGENTS.md
@@ -1,3 +1,79 @@
|
|||||||
|
# AGENTS.MD
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
- Read [`docs-site/development.md`](./docs-site/development.md) and [`docs-site/architecture.md`](./docs-site/architecture.md) before substantial changes; follow them unless task requires deviation.
|
||||||
|
- Init workspace: `git submodule update --init --recursive`.
|
||||||
|
- Install deps: `make deps` or `bun install` plus `(cd vendor/texthooker-ui && bun install --frozen-lockfile)`.
|
||||||
|
- Fast dev loop: `make dev-watch`.
|
||||||
|
- Full local run: `bun run dev`.
|
||||||
|
- Verbose Electron debug: `electron . --start --dev --log-level debug`.
|
||||||
|
|
||||||
|
## Build / Test
|
||||||
|
|
||||||
|
- Use repo package manager/runtime only: Bun (`packageManager: bun@1.3.5`).
|
||||||
|
- Default handoff gate:
|
||||||
|
`bun run typecheck`
|
||||||
|
`bun run test:fast`
|
||||||
|
`bun run test:env`
|
||||||
|
`bun run build`
|
||||||
|
`bun run test:smoke:dist`
|
||||||
|
- If `docs-site/` changed, also run:
|
||||||
|
`bun run docs:test`
|
||||||
|
`bun run docs:build`
|
||||||
|
- Formatting: prefer `make pretty` and `bun run format:check:src`; use `bun run format` only intentionally.
|
||||||
|
- Keep verification observable; capture failing command + exact error in notes/handoff.
|
||||||
|
|
||||||
|
## Change-Specific Checks
|
||||||
|
|
||||||
|
- Config/schema/defaults changes: run `bun run test:config`; if config template/defaults changed, run `bun run generate:config-example`.
|
||||||
|
- Launcher/plugin changes: run `bun run test:launcher` or `bun run test:env`; use `bun run test:launcher:smoke:src` for focused launcher e2e checks.
|
||||||
|
- Runtime-compat or compiled/dist-sensitive changes: run `bun run test:runtime:compat`.
|
||||||
|
- Docs-only changes: at least `bun run docs:test` if docs behavior/assertions changed; `bun run docs:build` before handoff.
|
||||||
|
|
||||||
|
## Generated / Sensitive Files
|
||||||
|
|
||||||
|
- Launcher source of truth: `launcher/*.ts`.
|
||||||
|
- Generated launcher artifact: `dist/launcher/subminer`; never hand-edit it.
|
||||||
|
- Repo-root `./subminer` is stale artifact path; do not revive/use it.
|
||||||
|
- `bun run build` rebuilds bundled Yomitan from `vendor/subminer-yomitan`; check submodules before debugging build failures.
|
||||||
|
- Avoid changing packaging/signing identifiers (`build.appId`, mac entitlements, signing-related settings) unless task explicitly requires it.
|
||||||
|
|
||||||
|
## Docs
|
||||||
|
|
||||||
|
- Docs site lives in-repo under [`docs-site/`](./docs-site/).
|
||||||
|
- Update docs for new/breaking behavior; no ship with stale docs.
|
||||||
|
- Make sure [`docs-site/changelog.md`](./docs-site/changelog.md) is updated on each release.
|
||||||
|
|
||||||
|
## PR Feedback
|
||||||
|
|
||||||
|
- Active PR: `gh pr view --json number,title,url --jq '"PR #\\(.number): \\(.title)\\n\\(.url)"'`.
|
||||||
|
- PR comments: `gh pr view …` + `gh api …/comments --paginate`.
|
||||||
|
- Replies: cite fix + file/line; resolve threads only after fix lands.
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
- User-visible PRs: add one fragment in `changes/*.md`.
|
||||||
|
- Fragment format:
|
||||||
|
`type: added|changed|fixed|docs|internal`
|
||||||
|
`area: <short-area>`
|
||||||
|
blank line
|
||||||
|
`- bullet`
|
||||||
|
- `changes/README.md`: instructions only; generator ignores it.
|
||||||
|
- No release-note entry wanted: use PR label `skip-changelog`.
|
||||||
|
- CI runs `bun run changelog:lint` + `bun run changelog:pr-check` on PRs.
|
||||||
|
- Release prep: `bun run changelog:build`, review `CHANGELOG.md` + `release/release-notes.md`, commit generated changelog + fragment deletions, then tag.
|
||||||
|
- Release CI expects committed changelog entry already present; do not rely on tag job to invent notes.
|
||||||
|
|
||||||
|
## Flow & Runtime
|
||||||
|
|
||||||
|
- Use Codex background for long jobs; tmux only for interactive/persistent (debugger/server).
|
||||||
|
- CI red: `gh run list/view`, rerun, fix, push, repeat til green.
|
||||||
|
|
||||||
|
## Language/Stack Notes
|
||||||
|
|
||||||
|
- Swift: use workspace helper/daemon; validate `swift build` + tests; keep concurrency attrs right.
|
||||||
|
- TypeScript: use repo PM; keep files small; follow existing patterns.
|
||||||
|
|
||||||
<!-- BACKLOG.MD MCP GUIDELINES START -->
|
<!-- BACKLOG.MD MCP GUIDELINES START -->
|
||||||
|
|
||||||
@@ -17,6 +93,7 @@ This project uses Backlog.md MCP for all task and project management activities.
|
|||||||
- **When to read it**: BEFORE creating tasks, or when you're unsure whether to track work
|
- **When to read it**: BEFORE creating tasks, or when you're unsure whether to track work
|
||||||
|
|
||||||
These guides cover:
|
These guides cover:
|
||||||
|
|
||||||
- Decision framework for when to create tasks
|
- Decision framework for when to create tasks
|
||||||
- Search-first workflow to avoid duplicates
|
- Search-first workflow to avoid duplicates
|
||||||
- Links to detailed guides for task creation, execution, and finalization
|
- Links to detailed guides for task creation, execution, and finalization
|
||||||
|
|||||||
153
CHANGELOG.md
Normal file
153
CHANGELOG.md
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## v0.6.5 (2026-03-15)
|
||||||
|
|
||||||
|
### Internal
|
||||||
|
- Release: Seed the AUR checkout with the repo `.SRCINFO` template before rewriting metadata so tagged releases do not depend on prior AUR state.
|
||||||
|
|
||||||
|
## v0.6.4 (2026-03-15)
|
||||||
|
|
||||||
|
### Internal
|
||||||
|
- Release: Reworked AUR metadata generation to update `.SRCINFO` directly instead of depending on runner `makepkg`, fixing tagged release publishing for `subminer-bin`.
|
||||||
|
|
||||||
|
## v0.6.3 (2026-03-15)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Overlay: Expanded the `Alt+C` controller modal into an inline config/remap flow with preferred-controller saving and per-action learn mode for buttons, triggers, and stick directions.
|
||||||
|
|
||||||
|
### Internal
|
||||||
|
- Workflow: Hardened the `subminer-scrum-master` skill to explicitly answer whether docs updates and changelog fragments are required before handoff.
|
||||||
|
- Release: Automate `subminer-bin` AUR package updates from the tagged release workflow.
|
||||||
|
|
||||||
|
## v0.6.2 (2026-03-12)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Config: Added `yomitan.externalProfilePath` to reuse another Electron app's Yomitan profile in read-only mode.
|
||||||
|
- Config: SubMiner now reuses external Yomitan dictionaries/settings without writing back to that profile.
|
||||||
|
- Config: Launcher-managed playback now respects `yomitan.externalProfilePath` and no longer forces first-run setup when external Yomitan is configured.
|
||||||
|
- Config: SubMiner now seeds `config.jsonc` even when the default config directory already exists.
|
||||||
|
- Config: First-run setup now allows zero internal dictionaries when `yomitan.externalProfilePath` is configured, and falls back to requiring at least one internal dictionary if that external profile is later removed.
|
||||||
|
|
||||||
|
## v0.6.1 (2026-03-12)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Overlay: Added Chrome Gamepad API controller support for keyboard-only overlay mode, including configurable logical bindings for lookup, mining, popup navigation, Yomitan audio, mpv pause, d-pad fallback navigation, and slower smooth popup scrolling.
|
||||||
|
- Overlay: Added `Alt+C` controller selection and `Alt+Shift+C` controller debug modals, with preferred controller persistence and live raw input inspection.
|
||||||
|
- Overlay: Added a transient in-overlay controller-detected indicator when a controller is first found.
|
||||||
|
- Overlay: Fixed stale keyboard-only token highlight cleanup when keyboard-only mode turns off or the Yomitan popup closes.
|
||||||
|
|
||||||
|
### Docs
|
||||||
|
- Install: Added Arch Linux AUR install docs for `subminer-bin` in the README and installation guide.
|
||||||
|
|
||||||
|
### Internal
|
||||||
|
- Config: add an enforced `verify:config-example` gate so checked-in example config artifacts cannot drift silently
|
||||||
|
- Release: Fixed the release workflow token permissions so tagged builds can download `oven-sh/setup-bun` and publish artifacts again.
|
||||||
|
|
||||||
|
## v0.5.6 (2026-03-10)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Dictionary: Persist merged character-dictionary MRU state as soon as a new retained set is built so revisits do not get dropped if later Yomitan import work fails, and skip merged dictionary rebuilds for reorder-only revisits when the retained anime set itself has not changed.
|
||||||
|
- Startup: Fixed early Electron startup writing config and user data under a lowercase `~/.config/subminer` path instead of the canonical `~/.config/SubMiner` directory.
|
||||||
|
- Overlay: Kept JLPT underline colors stable during Yomitan hover and selection states, even when tokens also use known, N+1, name-match, or frequency styling.
|
||||||
|
|
||||||
|
## v0.5.5 (2026-03-09)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Overlay: Added `f` as the default overlay fullscreen toggle and changed the default AniSkip intro-jump key to `Tab`.
|
||||||
|
- Dictionary: Aligned AniList character dictionary generation more closely with the upstream reference by preserving duplicate shared names across characters, skipping characters without native Japanese names, restoring richer character info fields, and using upstream-style role mapping plus hint-aware kanji readings.
|
||||||
|
- Startup: Ordered startup OSD messages so tokenization loads first, annotation loading appears next if still pending, and character dictionary sync progress waits until annotation loading finishes.
|
||||||
|
- Dictionary: Added a visible startup OSD step for merged character-dictionary building so long rebuilds show progress before the later import/upload phase.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Dictionary: Fixed AniList media guessing for character dictionary auto-sync by using filename-only `guessit` input and preserving multi-part guessit titles instead of truncating them to the first segment.
|
||||||
|
- Dictionary: Refresh the current subtitle after character dictionary auto-sync completes so newly imported character names highlight on the active line instead of waiting for the next subtitle change.
|
||||||
|
- Dictionary: Show character dictionary auto-sync progress on the mpv OSD without sending desktop notifications.
|
||||||
|
- Dictionary: Keep character dictionary auto-sync non-blocking during startup by letting snapshot/build work run in parallel and delaying only the Yomitan import/settings phase until current-media tokenization is already ready.
|
||||||
|
- Overlay: Fixed visible overlay keyboard handling so pressing `Tab` still reaches mpv and triggers the default AniSkip skip-intro binding while the overlay has focus.
|
||||||
|
- Plugin: Fix Windows mpv plugin binary override lookup so `SUBMINER_BINARY_PATH` still resolves to `SubMiner.exe` when no AppImage override is set.
|
||||||
|
|
||||||
|
## v0.5.3 (2026-03-09)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Release: Publish unsigned Windows `.exe` and `.zip` artifacts directly from release CI instead of routing them through SignPath.
|
||||||
|
- Release: Added `bun run build:win:unsigned` for explicit local unsigned Windows packaging.
|
||||||
|
|
||||||
|
## v0.5.2 (2026-03-09)
|
||||||
|
|
||||||
|
### Internal
|
||||||
|
|
||||||
|
- Release: Pinned the Windows SignPath submission workflow to an explicit artifact-configuration slug instead of relying on the SignPath project's default configuration.
|
||||||
|
|
||||||
|
## v0.5.1 (2026-03-09)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Launcher: Removed the YouTube subtitle generation mode switch so YouTube playback always preloads subtitles before mpv starts.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Launcher: Hardened YouTube AI subtitle fixing so fenced SRT output and text-only one-cue-per-block responses can still be applied without losing original cue timing.
|
||||||
|
- Launcher: Skipped AniSkip lookup during URL playback and YouTube subtitle-preload playback, limiting AniSkip to local file targets where it can actually resolve anime metadata.
|
||||||
|
- Launcher: Keep the background SubMiner process running after a launcher-managed mpv session exits so the next mpv instance can reconnect without restarting the app.
|
||||||
|
- Launcher: Reuse prior tokenization readiness after the background app is already warm so reopening a video does not pause again waiting for duplicate warmup completion.
|
||||||
|
- Windows: Acquire the app single-instance lock earlier so Windows overlay/video launches reuse the running background SubMiner process instead of booting a second full app and repeating startup warmups.
|
||||||
|
|
||||||
|
## v0.3.0 (2026-03-05)
|
||||||
|
|
||||||
|
- Added keyboard-driven Yomitan navigation and popup controls, including optional auto-pause.
|
||||||
|
- Added subtitle/jump keyboard handling fixes for smoother subtitle playback control.
|
||||||
|
- Improved Anki/Yomitan reliability with stronger Yomitan proxy syncing and safer extension refresh logic.
|
||||||
|
- Added Subsync `replace` option and deterministic retime naming for subtitle workflows.
|
||||||
|
- Moved aniskip resolution to launcher-script options for better control.
|
||||||
|
- Tuned tokenizer frequency highlighting filters for improved term visibility.
|
||||||
|
- Added release build quality-of-life for CLI publish (`gh`-based clobber upload).
|
||||||
|
- Removed docs Plausible integration and cleaned associated tracker settings.
|
||||||
|
|
||||||
|
## v0.2.3 (2026-03-02)
|
||||||
|
|
||||||
|
- Added performance and tokenization optimizations (faster warmup, persistent MeCab usage, reduced enrichment lookups).
|
||||||
|
- Added subtitle controls for no-jump delay shifts.
|
||||||
|
- Improved subtitle highlight logic with priority and reliability fixes.
|
||||||
|
- Fixed plugin loading behavior to keep OSD visible during startup.
|
||||||
|
- Fixed Jellyfin remote resume behavior and improved autoplay/tokenization interaction.
|
||||||
|
- Updated startup flow to load dictionaries asynchronously and unblock first tokenization sooner.
|
||||||
|
|
||||||
|
## v0.2.2 (2026-03-01)
|
||||||
|
|
||||||
|
- Improved subtitle highlighting reliability for frequency modes.
|
||||||
|
- Fixed Jellyfin misc info formatting cleanup.
|
||||||
|
- Version bump maintenance for 0.2.2.
|
||||||
|
|
||||||
|
## v0.2.1 (2026-03-01)
|
||||||
|
|
||||||
|
- Delivered Jellyfin and Subsync fixes from release patch cycle.
|
||||||
|
- Version bump maintenance for 0.2.1.
|
||||||
|
|
||||||
|
## v0.2.0 (2026-03-01)
|
||||||
|
|
||||||
|
- Added task-related release work for the overlay 2.0 cycle.
|
||||||
|
- Introduced Overlay 2.0.
|
||||||
|
- Improved release automation reliability.
|
||||||
|
|
||||||
|
## v0.1.2 (2026-02-24)
|
||||||
|
|
||||||
|
- Added encrypted AniList token handling and default GNOME keyring support.
|
||||||
|
- Added launcher passthrough for password-store flows (Jellyfin path).
|
||||||
|
- Updated docs for auth and integration behavior.
|
||||||
|
- Version bump maintenance for 0.1.2.
|
||||||
|
|
||||||
|
## v0.1.1 (2026-02-23)
|
||||||
|
|
||||||
|
- Fixed overlay modal focus handling (`grab input`) behavior.
|
||||||
|
- Version bump maintenance for 0.1.1.
|
||||||
|
|
||||||
|
## v0.1.0 (2026-02-23)
|
||||||
|
|
||||||
|
- Bootstrapped Electron runtime, services, and composition model.
|
||||||
|
- Added runtime asset packaging and dependency vendoring.
|
||||||
|
- Added project docs baseline, setup guides, architecture notes, and submodule/runtime assets.
|
||||||
|
- Added CI release job dependency ordering fixes before launcher build.
|
||||||
53
Makefile
53
Makefile
@@ -1,4 +1,4 @@
|
|||||||
.PHONY: help deps build build-launcher install build-linux build-macos build-macos-unsigned clean install-linux install-macos install-plugin uninstall uninstall-linux uninstall-macos print-dirs pretty ensure-bun generate-config generate-example-config dev-start dev-start-macos dev-watch dev-watch-macos dev-toggle dev-stop
|
.PHONY: help deps build build-launcher install build-linux build-macos build-macos-unsigned clean install-linux install-macos install-windows install-plugin uninstall uninstall-linux uninstall-macos uninstall-windows print-dirs pretty ensure-bun generate-config generate-example-config dev-start dev-start-macos dev-watch dev-watch-macos dev-toggle dev-stop
|
||||||
|
|
||||||
APP_NAME := subminer
|
APP_NAME := subminer
|
||||||
THEME_SOURCE := assets/themes/subminer.rasi
|
THEME_SOURCE := assets/themes/subminer.rasi
|
||||||
@@ -20,11 +20,6 @@ MACOS_DATA_DIR ?= $(HOME)/Library/Application Support/SubMiner
|
|||||||
MACOS_APP_DIR ?= $(HOME)/Applications
|
MACOS_APP_DIR ?= $(HOME)/Applications
|
||||||
MACOS_APP_DEST ?= $(MACOS_APP_DIR)/SubMiner.app
|
MACOS_APP_DEST ?= $(MACOS_APP_DIR)/SubMiner.app
|
||||||
|
|
||||||
# mpv plugin install directories.
|
|
||||||
MPV_CONFIG_DIR ?= $(HOME)/.config/mpv
|
|
||||||
MPV_SCRIPTS_DIR ?= $(MPV_CONFIG_DIR)/scripts
|
|
||||||
MPV_SCRIPT_OPTS_DIR ?= $(MPV_CONFIG_DIR)/script-opts
|
|
||||||
|
|
||||||
# If building from source, the AppImage will typically land in release/.
|
# If building from source, the AppImage will typically land in release/.
|
||||||
APPIMAGE_SRC := $(firstword $(wildcard release/SubMiner-*.AppImage))
|
APPIMAGE_SRC := $(firstword $(wildcard release/SubMiner-*.AppImage))
|
||||||
MACOS_APP_SRC := $(firstword $(wildcard release/*.app release/*/*.app))
|
MACOS_APP_SRC := $(firstword $(wildcard release/*.app release/*/*.app))
|
||||||
@@ -41,6 +36,17 @@ else
|
|||||||
PLATFORM := unknown
|
PLATFORM := unknown
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
WINDOWS_APPDATA ?= $(if $(APPDATA),$(subst \,/,$(APPDATA)),$(HOME)/AppData/Roaming)
|
||||||
|
|
||||||
|
# mpv plugin install directories.
|
||||||
|
ifeq ($(PLATFORM),windows)
|
||||||
|
MPV_CONFIG_DIR ?= $(WINDOWS_APPDATA)/mpv
|
||||||
|
else
|
||||||
|
MPV_CONFIG_DIR ?= $(HOME)/.config/mpv
|
||||||
|
endif
|
||||||
|
MPV_SCRIPTS_DIR ?= $(MPV_CONFIG_DIR)/scripts
|
||||||
|
MPV_SCRIPT_OPTS_DIR ?= $(MPV_CONFIG_DIR)/script-opts
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@printf '%s\n' \
|
@printf '%s\n' \
|
||||||
"Targets:" \
|
"Targets:" \
|
||||||
@@ -58,6 +64,7 @@ help:
|
|||||||
" dev-stop Stop a running local Electron app" \
|
" dev-stop Stop a running local Electron app" \
|
||||||
" install-linux Install Linux wrapper/theme/app artifacts" \
|
" install-linux Install Linux wrapper/theme/app artifacts" \
|
||||||
" install-macos Install macOS wrapper/theme/app artifacts" \
|
" install-macos Install macOS wrapper/theme/app artifacts" \
|
||||||
|
" install-windows Install Windows mpv plugin artifacts" \
|
||||||
" install-plugin Install mpv Lua plugin and plugin config" \
|
" install-plugin Install mpv Lua plugin and plugin config" \
|
||||||
" generate-config Generate ~/.config/SubMiner/config.jsonc from centralized defaults" \
|
" generate-config Generate ~/.config/SubMiner/config.jsonc from centralized defaults" \
|
||||||
"" \
|
"" \
|
||||||
@@ -65,6 +72,7 @@ help:
|
|||||||
" deps Install JS dependencies (root + texthooker-ui)" \
|
" deps Install JS dependencies (root + texthooker-ui)" \
|
||||||
" uninstall-linux Remove Linux install artifacts" \
|
" uninstall-linux Remove Linux install artifacts" \
|
||||||
" uninstall-macos Remove macOS install artifacts" \
|
" uninstall-macos Remove macOS install artifacts" \
|
||||||
|
" uninstall-windows Remove Windows mpv plugin artifacts" \
|
||||||
" print-dirs Show resolved install locations" \
|
" print-dirs Show resolved install locations" \
|
||||||
"" \
|
"" \
|
||||||
"Variables:" \
|
"Variables:" \
|
||||||
@@ -74,7 +82,7 @@ help:
|
|||||||
" LINUX_DATA_DIR=... Override Linux app data dir" \
|
" LINUX_DATA_DIR=... Override Linux app data dir" \
|
||||||
" MACOS_DATA_DIR=... Override macOS app data dir" \
|
" MACOS_DATA_DIR=... Override macOS app data dir" \
|
||||||
" MACOS_APP_DIR=... Override macOS app install dir (default: $$HOME/Applications)" \
|
" MACOS_APP_DIR=... Override macOS app install dir (default: $$HOME/Applications)" \
|
||||||
" MPV_CONFIG_DIR=... Override mpv config dir (default: $$HOME/.config/mpv)"
|
" MPV_CONFIG_DIR=... Override mpv config dir (default: $$HOME/.config/mpv or %APPDATA%/mpv on Windows)"
|
||||||
|
|
||||||
print-dirs:
|
print-dirs:
|
||||||
@printf '%s\n' \
|
@printf '%s\n' \
|
||||||
@@ -85,6 +93,10 @@ print-dirs:
|
|||||||
"MACOS_DATA_DIR=$(MACOS_DATA_DIR)" \
|
"MACOS_DATA_DIR=$(MACOS_DATA_DIR)" \
|
||||||
"MACOS_APP_DIR=$(MACOS_APP_DIR)" \
|
"MACOS_APP_DIR=$(MACOS_APP_DIR)" \
|
||||||
"MACOS_APP_DEST=$(MACOS_APP_DEST)" \
|
"MACOS_APP_DEST=$(MACOS_APP_DEST)" \
|
||||||
|
"WINDOWS_APPDATA=$(WINDOWS_APPDATA)" \
|
||||||
|
"MPV_CONFIG_DIR=$(MPV_CONFIG_DIR)" \
|
||||||
|
"MPV_SCRIPTS_DIR=$(MPV_SCRIPTS_DIR)" \
|
||||||
|
"MPV_SCRIPT_OPTS_DIR=$(MPV_SCRIPT_OPTS_DIR)" \
|
||||||
"APPIMAGE_SRC=$(APPIMAGE_SRC)" \
|
"APPIMAGE_SRC=$(APPIMAGE_SRC)" \
|
||||||
"MACOS_APP_SRC=$(MACOS_APP_SRC)" \
|
"MACOS_APP_SRC=$(MACOS_APP_SRC)" \
|
||||||
"MACOS_ZIP_SRC=$(MACOS_ZIP_SRC)"
|
"MACOS_ZIP_SRC=$(MACOS_ZIP_SRC)"
|
||||||
@@ -105,6 +117,7 @@ build:
|
|||||||
@case "$(PLATFORM)" in \
|
@case "$(PLATFORM)" in \
|
||||||
linux) $(MAKE) --no-print-directory build-linux ;; \
|
linux) $(MAKE) --no-print-directory build-linux ;; \
|
||||||
macos) $(MAKE) --no-print-directory build-macos ;; \
|
macos) $(MAKE) --no-print-directory build-macos ;; \
|
||||||
|
windows) printf '%s\n' "[INFO] Windows builds run via: bun run build:win" ;; \
|
||||||
*) printf '%s\n' "[ERROR] Unsupported OS for this Makefile target: $(PLATFORM)"; exit 1 ;; \
|
*) printf '%s\n' "[ERROR] Unsupported OS for this Makefile target: $(PLATFORM)"; exit 1 ;; \
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -113,6 +126,7 @@ install:
|
|||||||
@case "$(PLATFORM)" in \
|
@case "$(PLATFORM)" in \
|
||||||
linux) $(MAKE) --no-print-directory install-linux ;; \
|
linux) $(MAKE) --no-print-directory install-linux ;; \
|
||||||
macos) $(MAKE) --no-print-directory install-macos ;; \
|
macos) $(MAKE) --no-print-directory install-macos ;; \
|
||||||
|
windows) $(MAKE) --no-print-directory install-windows ;; \
|
||||||
*) printf '%s\n' "[ERROR] Unsupported OS for this Makefile target: $(PLATFORM)"; exit 1 ;; \
|
*) printf '%s\n' "[ERROR] Unsupported OS for this Makefile target: $(PLATFORM)"; exit 1 ;; \
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -151,7 +165,6 @@ generate-config: ensure-bun
|
|||||||
@bun run electron . --generate-config
|
@bun run electron . --generate-config
|
||||||
|
|
||||||
generate-example-config: ensure-bun
|
generate-example-config: ensure-bun
|
||||||
@bun run build
|
|
||||||
@bun run generate:config-example
|
@bun run generate:config-example
|
||||||
|
|
||||||
dev-start: ensure-bun
|
dev-start: ensure-bun
|
||||||
@@ -210,18 +223,31 @@ install-macos: build-launcher
|
|||||||
fi
|
fi
|
||||||
@printf '%s\n' "Installed to:" " $(BINDIR)/subminer" " $(MACOS_DATA_DIR)/themes/$(THEME_FILE)" " $(MACOS_APP_DEST)"
|
@printf '%s\n' "Installed to:" " $(BINDIR)/subminer" " $(MACOS_DATA_DIR)/themes/$(THEME_FILE)" " $(MACOS_APP_DEST)"
|
||||||
|
|
||||||
|
install-windows:
|
||||||
|
@printf '%s\n' "[INFO] Installing Windows mpv plugin artifacts"
|
||||||
|
@$(MAKE) --no-print-directory install-plugin
|
||||||
|
|
||||||
install-plugin:
|
install-plugin:
|
||||||
@printf '%s\n' "[INFO] Installing mpv plugin artifacts"
|
@printf '%s\n' "[INFO] Installing mpv plugin artifacts"
|
||||||
@install -d "$(MPV_SCRIPTS_DIR)"
|
@install -d "$(MPV_SCRIPTS_DIR)"
|
||||||
@rm -f "$(MPV_SCRIPTS_DIR)/subminer.lua"
|
@rm -f "$(MPV_SCRIPTS_DIR)/subminer.lua" "$(MPV_SCRIPTS_DIR)/subminer-loader.lua"
|
||||||
@install -d "$(MPV_SCRIPTS_DIR)/subminer"
|
@install -d "$(MPV_SCRIPTS_DIR)/subminer"
|
||||||
@install -d "$(MPV_SCRIPT_OPTS_DIR)"
|
@install -d "$(MPV_SCRIPT_OPTS_DIR)"
|
||||||
@cp -R ./plugin/subminer/. "$(MPV_SCRIPTS_DIR)/subminer/"
|
@cp -R ./plugin/subminer/. "$(MPV_SCRIPTS_DIR)/subminer/"
|
||||||
@install -m 0644 "./$(PLUGIN_CONF)" "$(MPV_SCRIPT_OPTS_DIR)/subminer.conf"
|
@install -m 0644 "./$(PLUGIN_CONF)" "$(MPV_SCRIPT_OPTS_DIR)/subminer.conf"
|
||||||
|
@if [ "$(PLATFORM)" = "windows" ]; then \
|
||||||
|
bun ./scripts/configure-plugin-binary-path.mjs "$(MPV_SCRIPT_OPTS_DIR)/subminer.conf" "$(CURDIR)" win32; \
|
||||||
|
fi
|
||||||
@printf '%s\n' "Installed to:" " $(MPV_SCRIPTS_DIR)/subminer/main.lua" " $(MPV_SCRIPTS_DIR)/subminer/" " $(MPV_SCRIPT_OPTS_DIR)/subminer.conf"
|
@printf '%s\n' "Installed to:" " $(MPV_SCRIPTS_DIR)/subminer/main.lua" " $(MPV_SCRIPTS_DIR)/subminer/" " $(MPV_SCRIPT_OPTS_DIR)/subminer.conf"
|
||||||
|
|
||||||
# Uninstall behavior kept unchanged by default.
|
uninstall:
|
||||||
uninstall: uninstall-linux
|
@printf '%s\n' "[INFO] Detected platform: $(PLATFORM)"
|
||||||
|
@case "$(PLATFORM)" in \
|
||||||
|
linux) $(MAKE) --no-print-directory uninstall-linux ;; \
|
||||||
|
macos) $(MAKE) --no-print-directory uninstall-macos ;; \
|
||||||
|
windows) $(MAKE) --no-print-directory uninstall-windows ;; \
|
||||||
|
*) printf '%s\n' "[ERROR] Unsupported OS for this Makefile target: $(PLATFORM)"; exit 1 ;; \
|
||||||
|
esac
|
||||||
|
|
||||||
uninstall-linux:
|
uninstall-linux:
|
||||||
@rm -f "$(BINDIR)/subminer" "$(BINDIR)/SubMiner.AppImage"
|
@rm -f "$(BINDIR)/subminer" "$(BINDIR)/SubMiner.AppImage"
|
||||||
@@ -233,3 +259,8 @@ uninstall-macos:
|
|||||||
@rm -f "$(MACOS_DATA_DIR)/themes/$(THEME_FILE)"
|
@rm -f "$(MACOS_DATA_DIR)/themes/$(THEME_FILE)"
|
||||||
@rm -rf "$(MACOS_APP_DEST)"
|
@rm -rf "$(MACOS_APP_DEST)"
|
||||||
@printf '%s\n' "Removed:" " $(BINDIR)/subminer" " $(MACOS_DATA_DIR)/themes/$(THEME_FILE)" " $(MACOS_APP_DEST)"
|
@printf '%s\n' "Removed:" " $(BINDIR)/subminer" " $(MACOS_DATA_DIR)/themes/$(THEME_FILE)" " $(MACOS_APP_DEST)"
|
||||||
|
|
||||||
|
uninstall-windows:
|
||||||
|
@rm -rf "$(MPV_SCRIPTS_DIR)/subminer"
|
||||||
|
@rm -f "$(MPV_SCRIPTS_DIR)/subminer.lua" "$(MPV_SCRIPTS_DIR)/subminer-loader.lua" "$(MPV_SCRIPT_OPTS_DIR)/subminer.conf"
|
||||||
|
@printf '%s\n' "Removed:" " $(MPV_SCRIPTS_DIR)/subminer" " $(MPV_SCRIPT_OPTS_DIR)/subminer.conf"
|
||||||
|
|||||||
66
README.md
66
README.md
@@ -5,7 +5,7 @@
|
|||||||
<br /><br />
|
<br /><br />
|
||||||
|
|
||||||
[](https://www.gnu.org/licenses/gpl-3.0)
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
||||||
[]()
|
[]()
|
||||||
[](https://docs.subminer.moe)
|
[](https://docs.subminer.moe)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -24,23 +24,33 @@
|
|||||||
|
|
||||||
SubMiner is an Electron overlay that sits on top of mpv. It turns your video player into a full sentence-mining workstation:
|
SubMiner is an Electron overlay that sits on top of mpv. It turns your video player into a full sentence-mining workstation:
|
||||||
|
|
||||||
- **Hover to look up** — Yomitan dictionary popups directly on subtitles
|
- **Look up words as you watch** — Yomitan dictionary popups on hover or keyboard-driven token-by-token navigation
|
||||||
- **Keyboard-driven lookup mode** — Navigate token-by-token, keep lookup open across tokens, and control popup scrolling/audio/mining without leaving the overlay
|
- **One-key Anki mining** — Creates cards with sentence, audio, screenshot, and translation; optional local AnkiConnect proxy auto-enriches Yomitan cards instantly
|
||||||
- **One-key mining** — Creates Anki cards with sentence, audio, screenshot, and translation
|
- **Reading annotations** — N+1 targeting, frequency-dictionary highlighting, JLPT underlining, and character name dictionary for anime/manga proper nouns
|
||||||
- **Instant auto-enrichment** — Optional local AnkiConnect proxy enriches new Yomitan cards immediately
|
|
||||||
- **Reading annotations** — Combines N+1 targeting, frequency-dictionary highlighting, and JLPT underlining while you read
|
|
||||||
- **Hover-aware playback** — By default, hovering subtitle text pauses mpv and resumes on mouse leave (`subtitleStyle.autoPauseVideoOnHover`)
|
|
||||||
- **Subtitle tools** — Download from Jimaku, sync with alass/ffsubsync
|
- **Subtitle tools** — Download from Jimaku, sync with alass/ffsubsync
|
||||||
- **Immersion tracking** — SQLite-powered stats on your watch time and mining activity
|
- **Jellyfin & AniList integration** — Remote playback, cast device mode, and automatic episode progress tracking
|
||||||
- **Custom texthooker page** — Built-in custom texthooker page and websocket, no extra setup
|
- **Texthooker & API** — Built-in texthooker page and annotated websocket feed for external clients
|
||||||
- **Annotated websocket API** — Dedicated annotation feed can serve bundled texthooker or external clients with rendered `sentence` HTML plus structured `tokens`
|
|
||||||
- **Jellyfin integration** — Remote playback setup, cast device mode, and direct playback launch
|
|
||||||
- **AniList progress** — Track episode completion and push watching progress automatically
|
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
### 1. Install
|
### 1. Install
|
||||||
|
|
||||||
|
**Arch Linux (AUR):**
|
||||||
|
|
||||||
|
Install [`subminer-bin`](https://aur.archlinux.org/packages/subminer-bin) from the AUR. It installs the packaged AppImage plus the `subminer` wrapper:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
paru -S subminer-bin
|
||||||
|
```
|
||||||
|
|
||||||
|
Or manually:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://aur.archlinux.org/subminer-bin.git
|
||||||
|
cd subminer-bin
|
||||||
|
makepkg -si
|
||||||
|
```
|
||||||
|
|
||||||
**Linux (AppImage):**
|
**Linux (AppImage):**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -54,15 +64,22 @@ chmod +x ~/.local/bin/subminer
|
|||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> The `subminer` wrapper uses a [Bun](https://bun.sh) shebang. Make sure `bun` is on your `PATH`.
|
> The `subminer` wrapper uses a [Bun](https://bun.sh) shebang. Make sure `bun` is on your `PATH`.
|
||||||
|
|
||||||
**From source** or **macOS** — initialize submodules first (`git submodule update --init --recursive`). Source builds now also require Node.js 22 + npm because bundled Yomitan is built from the `vendor/subminer-yomitan` submodule into `build/yomitan` during `bun run build`. Full install guide: [docs.subminer.moe/installation#from-source](https://docs.subminer.moe/installation#from-source).
|
**macOS (DMG/ZIP):** download the latest packaged build from [GitHub Releases](https://github.com/ksyasuda/SubMiner/releases/latest) and drag `SubMiner.app` into `/Applications`.
|
||||||
|
|
||||||
|
**Windows (Installer/ZIP):** download the latest `SubMiner-<version>.exe` installer or portable `.zip` from [GitHub Releases](https://github.com/ksyasuda/SubMiner/releases/latest). Keep `mpv` installed and available on `PATH`.
|
||||||
|
|
||||||
|
**From source** — initialize submodules first (`git submodule update --init --recursive`). Bundled Yomitan is built from the `vendor/subminer-yomitan` submodule into `build/yomitan` during `bun run build`, so source builds only need Bun for the JS toolchain. Packaged macOS and Windows installs do not require Bun. Windows installer builds go through `electron-builder`; its bundled `app-builder-lib` NSIS templates already use the third-party `WinShell` plugin for shortcut AppUserModelID assignment, and the `WinShell.dll` binary is supplied by electron-builder's cached `nsis-resources` bundle, so `bun run build:win` does not need a separate repo-local plugin install step. Full install guide: [docs.subminer.moe/installation#from-source](https://docs.subminer.moe/installation#from-source).
|
||||||
|
|
||||||
### 2. Launch the app once
|
### 2. Launch the app once
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Linux
|
||||||
SubMiner.AppImage
|
SubMiner.AppImage
|
||||||
```
|
```
|
||||||
|
|
||||||
On first launch, SubMiner now:
|
On macOS, launch `SubMiner.app`. On Windows, launch `SubMiner.exe` from the Start menu or install directory.
|
||||||
|
|
||||||
|
On first launch, SubMiner:
|
||||||
|
|
||||||
- starts in the tray/background
|
- starts in the tray/background
|
||||||
- creates the default config directory and `config.jsonc`
|
- creates the default config directory and `config.jsonc`
|
||||||
@@ -70,8 +87,6 @@ On first launch, SubMiner now:
|
|||||||
- can install the mpv plugin to the default mpv scripts location for you
|
- can install the mpv plugin to the default mpv scripts location for you
|
||||||
- links directly to Yomitan settings so you can install dictionaries before finishing setup
|
- links directly to Yomitan settings so you can install dictionaries before finishing setup
|
||||||
|
|
||||||
Existing installs that already have a valid config plus at least one Yomitan dictionary are auto-detected as complete and will not be re-prompted.
|
|
||||||
|
|
||||||
### 3. Finish setup
|
### 3. Finish setup
|
||||||
|
|
||||||
- click `Install mpv plugin` if you want the default plugin auto-start flow
|
- click `Install mpv plugin` if you want the default plugin auto-start flow
|
||||||
@@ -92,31 +107,22 @@ subminer --start video.mkv # optional explicit overlay start when plugin auto_st
|
|||||||
|
|
||||||
| Required | Optional |
|
| Required | Optional |
|
||||||
| ------------------------------------------ | -------------------------------------------------- |
|
| ------------------------------------------ | -------------------------------------------------- |
|
||||||
| `bun`, `node` 22, `npm` | |
|
| `bun` (source builds, Linux `subminer`) | |
|
||||||
| `mpv` with IPC socket | `yt-dlp` |
|
| `mpv` with IPC socket | `yt-dlp` |
|
||||||
| `ffmpeg` | `guessit` (better AniSkip title/episode detection) |
|
| `ffmpeg` | `guessit` (better AniSkip title/episode detection) |
|
||||||
| `mecab` + `mecab-ipadic` | `fzf` / `rofi` |
|
| `mecab` + `mecab-ipadic` | `fzf` / `rofi` |
|
||||||
| Linux: `hyprctl` or `xdotool` + `xwininfo` | `chafa`, `ffmpegthumbnailer` |
|
| Linux: `hyprctl` or `xdotool` + `xwininfo` | `chafa`, `ffmpegthumbnailer` |
|
||||||
| macOS: Accessibility permission | |
|
| macOS: Accessibility permission | |
|
||||||
|
|
||||||
|
Windows builds use native window tracking and do not require the Linux compositor helper tools.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
For full guides on configuration, Anki, Jellyfin, and more, see [docs.subminer.moe](https://docs.subminer.moe).
|
For full guides on configuration, Anki, Jellyfin, and more, see [docs.subminer.moe](https://docs.subminer.moe). The VitePress source for that site lives in [`docs-site/`](./docs-site/).
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
- Run `bun run test` or `bun run test:fast` for the default fast lane: config/core coverage plus representative entry/runtime, Anki integration, and main runtime checks.
|
|
||||||
- Run `bun run test:full` for the maintained test surface: Bun-compatible `src/**` coverage, Bun-compatible launcher unit coverage, and a Node compatibility lane for suites that depend on Electron named exports or `node:sqlite` behavior.
|
|
||||||
- Run `bun run test:node:compat` directly when you only need the Node-backed compatibility slice: `ipc`, `anki-jimaku-ipc`, `overlay-manager`, `config-validation`, `startup-config`, and runtime registry coverage.
|
|
||||||
- Run `bun run test:env` for environment-specific verification: launcher smoke/plugin checks plus the SQLite-backed immersion tracker lane.
|
|
||||||
- Run `bun run test:immersion:sqlite` when you specifically need real SQLite persistence coverage under Node with `--experimental-sqlite`.
|
|
||||||
- Run `bun run test:subtitle` for the maintained `alass`/`ffsubsync` subtitle surface.
|
|
||||||
|
|
||||||
The Bun-managed discovery lanes intentionally exclude a small set of suites that are currently Node-only because of Bun runtime/tooling gaps rather than product behavior: Electron named-export tests in `src/core/services/ipc.test.ts`, `src/core/services/anki-jimaku-ipc.test.ts`, and `src/core/services/overlay-manager.test.ts`, plus runtime/config tests in `src/main/config-validation.test.ts`, `src/main/runtime/startup-config.test.ts`, and `src/main/runtime/registry.test.ts`. `bun run test:node:compat` keeps those suites in the standard workflow instead of leaving them untracked.
|
|
||||||
|
|
||||||
## Acknowledgments
|
## Acknowledgments
|
||||||
|
|
||||||
Built on the shoulders of [GameSentenceMiner](https://github.com/bpwhelan/GameSentenceMiner), [Renji's Texthooker Page](https://github.com/Renji-XD/texthooker-ui), [mpvacious](https://github.com/Ajatt-Tools/mpvacious), [Anacreon-Script](https://github.com/friedrich-de/Anacreon-Script), and [Bee's Character Dictionary](https://github.com/bee-san/Japanese_Character_Name_Dictionary). Subtitles powered by [Jimaku.cc](https://jimaku.cc). Dictionary lookups via [Yomitan](https://github.com/yomidevs/yomitan).
|
Built on the shoulders of [GameSentenceMiner](https://github.com/bpwhelan/GameSentenceMiner), [Renji's Texthooker Page](https://github.com/Renji-XD/texthooker-ui), [Anacreon-Script](https://github.com/friedrich-de/Anacreon-Script), and [Bee's Character Dictionary](https://github.com/bee-san/Japanese_Character_Name_Dictionary). Subtitles powered by [Jimaku.cc](https://jimaku.cc). Dictionary lookups via [Yomitan](https://github.com/yomidevs/yomitan), and JLPT tags from [yomitan-jlpt-vocab](https://github.com/stephenmk/yomitan-jlpt-vocab).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 141 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 114 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 21 MiB After Width: | Height: | Size: 3.0 MiB |
@@ -1,11 +1,11 @@
|
|||||||
project_name: "SubMiner"
|
project_name: 'SubMiner'
|
||||||
default_status: "To Do"
|
default_status: 'To Do'
|
||||||
statuses: ["To Do", "In Progress", "Done"]
|
statuses: ['To Do', 'In Progress', 'Done']
|
||||||
labels: []
|
labels: []
|
||||||
definition_of_done: []
|
definition_of_done: []
|
||||||
date_format: yyyy-mm-dd
|
date_format: yyyy-mm-dd
|
||||||
max_column_width: 20
|
max_column_width: 20
|
||||||
default_editor: "nvim"
|
default_editor: 'nvim'
|
||||||
auto_open_browser: false
|
auto_open_browser: false
|
||||||
default_port: 6420
|
default_port: 6420
|
||||||
remote_operations: true
|
remote_operations: true
|
||||||
@@ -13,4 +13,4 @@ auto_commit: false
|
|||||||
bypass_git_hooks: false
|
bypass_git_hooks: false
|
||||||
check_active_branches: true
|
check_active_branches: true
|
||||||
active_branch_days: 30
|
active_branch_days: 30
|
||||||
task_prefix: "task"
|
task_prefix: 'task'
|
||||||
|
|||||||
@@ -18,11 +18,15 @@ priority: high
|
|||||||
## Description
|
## Description
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
Index AniList character alternative names in generated character dictionaries so aliases like Shadow resolve during subtitle lookup instead of falling through to unrelated generic dictionary entries.
|
Index AniList character alternative names in generated character dictionaries so aliases like Shadow resolve during subtitle lookup instead of falling through to unrelated generic dictionary entries.
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:END -->
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
<!-- AC:BEGIN -->
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
- [x] #1 Character fetch reads AniList alternative character names needed for lookup coverage
|
- [x] #1 Character fetch reads AniList alternative character names needed for lookup coverage
|
||||||
- [x] #2 Generated term banks include alias-derived terms for subtitle lookups like シャドウ
|
- [x] #2 Generated term banks include alias-derived terms for subtitle lookups like シャドウ
|
||||||
- [x] #3 Regression coverage proves alternative-name indexing works end to end
|
- [x] #3 Regression coverage proves alternative-name indexing works end to end
|
||||||
@@ -31,9 +35,11 @@ Index AniList character alternative names in generated character dictionaries so
|
|||||||
## Final Summary
|
## Final Summary
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
Character dictionary generation now requests AniList `name.alternative`, indexes those aliases as term candidates, and expands mixed aliases like `Minoru Kagenou (影野ミノル)` into usable outer/inner variants. Also extended kana alias synthesis so the AniList alias `Shadow` emits `シャドウ`, which matches the subtitle token the user hit in The Eminence in Shadow.
|
Character dictionary generation now requests AniList `name.alternative`, indexes those aliases as term candidates, and expands mixed aliases like `Minoru Kagenou (影野ミノル)` into usable outer/inner variants. Also extended kana alias synthesis so the AniList alias `Shadow` emits `シャドウ`, which matches the subtitle token the user hit in The Eminence in Shadow.
|
||||||
|
|
||||||
Bumped the character-dictionary snapshot format to invalidate stale cached snapshots, and updated merged-dictionary rebuilds to refresh invalid snapshots before composing the ZIP so old cache files do not hard-fail the merge path.
|
Bumped the character-dictionary snapshot format to invalidate stale cached snapshots, and updated merged-dictionary rebuilds to refresh invalid snapshots before composing the ZIP so old cache files do not hard-fail the merge path.
|
||||||
|
|
||||||
Verified with `bun test src/main/character-dictionary-runtime.test.ts` and `bun run tsc --noEmit`.
|
Verified with `bun test src/main/character-dictionary-runtime.test.ts` and `bun run tsc --noEmit`.
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ priority: medium
|
|||||||
## Description
|
## Description
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
Make the packaged Linux no-arg launch path behave like a quiet background start instead of surfacing startup-only noise.
|
Make the packaged Linux no-arg launch path behave like a quiet background start instead of surfacing startup-only noise.
|
||||||
|
|
||||||
Scope:
|
Scope:
|
||||||
@@ -31,6 +32,7 @@ Scope:
|
|||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
<!-- AC:BEGIN -->
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
- [x] #1 Initial background launch reaches the start path without logging `No running instance. Use --start to launch the app.`
|
- [x] #1 Initial background launch reaches the start path without logging `No running instance. Use --start to launch the app.`
|
||||||
- [x] #2 Default startup no longer emits the `Applied --password-store gnome-libsecret` line at normal log levels.
|
- [x] #2 Default startup no longer emits the `Applied --password-store gnome-libsecret` line at normal log levels.
|
||||||
- [x] #3 Entry/background launch sanitization suppresses the observed `ExperimentalWarning: SQLite...` and `lsfg-vk ... unsupported configuration version` startup noise.
|
- [x] #3 Entry/background launch sanitization suppresses the observed `ExperimentalWarning: SQLite...` and `lsfg-vk ... unsupported configuration version` startup noise.
|
||||||
@@ -40,6 +42,7 @@ Scope:
|
|||||||
## Implementation Notes
|
## Implementation Notes
|
||||||
|
|
||||||
<!-- SECTION:NOTES:BEGIN -->
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
Normalized no-arg/password-store-only entry launches to append implicit `--start --background`, and upgraded `--background`-only entry launches to include `--start`.
|
Normalized no-arg/password-store-only entry launches to append implicit `--start --background`, and upgraded `--background`-only entry launches to include `--start`.
|
||||||
|
|
||||||
Applied shared entry env sanitization before loading the main process so default startup strips the `lsfg-vk` Vulkan layer and sets `NODE_NO_WARNINGS=1`; background children keep the same sanitized env.
|
Applied shared entry env sanitization before loading the main process so default startup strips the `lsfg-vk` Vulkan layer and sets `NODE_NO_WARNINGS=1`; background children keep the same sanitized env.
|
||||||
@@ -52,11 +55,13 @@ Verification:
|
|||||||
- `bun run test:fast`
|
- `bun run test:fast`
|
||||||
|
|
||||||
Note: the final `node --experimental-sqlite --test dist/main/runtime/registry.test.js` step in `bun run test:fast` still prints Node's own experimental SQLite warning because that test command explicitly enables the feature flag outside the app entrypoint.
|
Note: the final `node --experimental-sqlite --test dist/main/runtime/registry.test.js` step in `bun run test:fast` still prints Node's own experimental SQLite warning because that test command explicitly enables the feature flag outside the app entrypoint.
|
||||||
|
|
||||||
<!-- SECTION:NOTES:END -->
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
## Final Summary
|
## Final Summary
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
Default packaged startup is now quiet and behaves like an implicit `--start --background` launch.
|
Default packaged startup is now quiet and behaves like an implicit `--start --background` launch.
|
||||||
|
|
||||||
- No-arg AppImage entry launches now append `--start --background`, and `--background`-only launches append the missing `--start`.
|
- No-arg AppImage entry launches now append `--start --background`, and `--background`-only launches append the missing `--start`.
|
||||||
|
|||||||
@@ -17,12 +17,15 @@ priority: medium
|
|||||||
## Description
|
## Description
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
Add a separate annotated subtitle websocket for bundled texthooker so token/JLPT/frequency markup is available on a stable dedicated port even when the regular websocket is in `auto` mode and skipped because `mpv_websocket` is installed.
|
Add a separate annotated subtitle websocket for bundled texthooker so token/JLPT/frequency markup is available on a stable dedicated port even when the regular websocket is in `auto` mode and skipped because `mpv_websocket` is installed.
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:END -->
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
<!-- AC:BEGIN -->
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
- [x] #1 Regular `websocket.enabled: "auto"` behavior remains unchanged and still skips the regular websocket when `mpv_websocket` is installed.
|
- [x] #1 Regular `websocket.enabled: "auto"` behavior remains unchanged and still skips the regular websocket when `mpv_websocket` is installed.
|
||||||
- [x] #2 A separate `annotationWebsocket` config controls an independent annotated websocket with default port `6678`.
|
- [x] #2 A separate `annotationWebsocket` config controls an independent annotated websocket with default port `6678`.
|
||||||
- [x] #3 Bundled texthooker is pointed at the annotation websocket when it is enabled.
|
- [x] #3 Bundled texthooker is pointed at the annotation websocket when it is enabled.
|
||||||
@@ -32,7 +35,9 @@ Add a separate annotated subtitle websocket for bundled texthooker so token/JLPT
|
|||||||
## Final Summary
|
## Final Summary
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
Added `annotationWebsocket.enabled`/`annotationWebsocket.port` with defaults of `true`/`6678`, started that websocket independently from the regular auto-managed websocket, and injected the bundled texthooker websocket URL so it connects to the annotation feed by default.
|
Added `annotationWebsocket.enabled`/`annotationWebsocket.port` with defaults of `true`/`6678`, started that websocket independently from the regular auto-managed websocket, and injected the bundled texthooker websocket URL so it connects to the annotation feed by default.
|
||||||
|
|
||||||
Also added focused regression coverage and regenerated the checked-in config examples.
|
Also added focused regression coverage and regenerated the checked-in config examples.
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
|
|||||||
@@ -23,12 +23,15 @@ priority: medium
|
|||||||
## Description
|
## Description
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
Bring bundled texthooker annotation rendering closer to the visible overlay. Keep the lightweight texthooker UX, but preserve token metadata for hover, match overlay color-precedence rules across known/N+1/name/frequency/JLPT, expose name-match highlighting as a toggle, and emit a structured annotation payload on the dedicated websocket so non-SubMiner clients can treat it as an API.
|
Bring bundled texthooker annotation rendering closer to the visible overlay. Keep the lightweight texthooker UX, but preserve token metadata for hover, match overlay color-precedence rules across known/N+1/name/frequency/JLPT, expose name-match highlighting as a toggle, and emit a structured annotation payload on the dedicated websocket so non-SubMiner clients can treat it as an API.
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:END -->
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
<!-- AC:BEGIN -->
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
- [x] #1 Annotation websocket payload includes both rendered `sentence` HTML and structured token metadata for generic clients.
|
- [x] #1 Annotation websocket payload includes both rendered `sentence` HTML and structured token metadata for generic clients.
|
||||||
- [x] #2 Vendored texthooker preserves annotation metadata attrs needed for hover labels and uses overlay-matching color precedence rules.
|
- [x] #2 Vendored texthooker preserves annotation metadata attrs needed for hover labels and uses overlay-matching color precedence rules.
|
||||||
- [x] #3 Vendored texthooker supports character-name highlighting with a user-facing toggle and standalone-web note.
|
- [x] #3 Vendored texthooker supports character-name highlighting with a user-facing toggle and standalone-web note.
|
||||||
@@ -39,5 +42,7 @@ Bring bundled texthooker annotation rendering closer to the visible overlay. Kee
|
|||||||
## Final Summary
|
## Final Summary
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
Extended the dedicated annotation websocket payload to ship `version`, plain `text`, rendered `sentence`, and structured `tokens` metadata while keeping backward-compatible `sentence` consumers working. Updated the vendored texthooker to preserve hover metadata attrs, follow overlay color precedence for known/N+1/name/frequency/JLPT annotations, add a character-name highlight toggle plus standalone-web dictionary note, and render lightweight hover labels for frequency/JLPT metadata. Added focused regression coverage and rebuilt both the vendored texthooker bundle and SubMiner.
|
Extended the dedicated annotation websocket payload to ship `version`, plain `text`, rendered `sentence`, and structured `tokens` metadata while keeping backward-compatible `sentence` consumers working. Updated the vendored texthooker to preserve hover metadata attrs, follow overlay color precedence for known/N+1/name/frequency/JLPT annotations, add a character-name highlight toggle plus standalone-web dictionary note, and render lightweight hover labels for frequency/JLPT metadata. Added focused regression coverage and rebuilt both the vendored texthooker bundle and SubMiner.
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ ordinal: 10600
|
|||||||
## Description
|
## Description
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
Replace the current manual install flow with a first-run setup gate:
|
Replace the current manual install flow with a first-run setup gate:
|
||||||
|
|
||||||
- bootstrap the default config dir/config file automatically
|
- bootstrap the default config dir/config file automatically
|
||||||
@@ -33,6 +34,7 @@ Replace the current manual install flow with a first-run setup gate:
|
|||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
<!-- AC:BEGIN -->
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
- [x] #1 First app launch seeds the default config dir/config file without manual copy steps.
|
- [x] #1 First app launch seeds the default config dir/config file without manual copy steps.
|
||||||
- [x] #2 Existing installs with config plus at least one Yomitan dictionary are auto-detected as already complete.
|
- [x] #2 Existing installs with config plus at least one Yomitan dictionary are auto-detected as already complete.
|
||||||
- [x] #3 Incomplete installs get a first-run setup popup with mpv plugin install, Yomitan settings, refresh, skip, and finish actions.
|
- [x] #3 Incomplete installs get a first-run setup popup with mpv plugin install, Yomitan settings, refresh, skip, and finish actions.
|
||||||
@@ -43,6 +45,7 @@ Replace the current manual install flow with a first-run setup gate:
|
|||||||
## Implementation Notes
|
## Implementation Notes
|
||||||
|
|
||||||
<!-- SECTION:NOTES:BEGIN -->
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
Added shared setup-state/config/mpv path helpers so Electron and launcher read the same onboarding state file.
|
Added shared setup-state/config/mpv path helpers so Electron and launcher read the same onboarding state file.
|
||||||
|
|
||||||
Introduced a first-run setup service plus compact BrowserWindow popup using Catppuccin Macchiato styling. The popup supports optional mpv plugin install, opening Yomitan settings, status refresh, skip-plugin, and gated finish once at least one Yomitan dictionary is installed.
|
Introduced a first-run setup service plus compact BrowserWindow popup using Catppuccin Macchiato styling. The popup supports optional mpv plugin install, opening Yomitan settings, status refresh, skip-plugin, and gated finish once at least one Yomitan dictionary is installed.
|
||||||
@@ -60,6 +63,7 @@ Verification:
|
|||||||
## Final Summary
|
## Final Summary
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
SubMiner now supports a download-and-launch install flow.
|
SubMiner now supports a download-and-launch install flow.
|
||||||
|
|
||||||
- First launch auto-creates config and opens setup only when needed.
|
- First launch auto-creates config and opens setup only when needed.
|
||||||
|
|||||||
@@ -20,11 +20,15 @@ references:
|
|||||||
## Description
|
## Description
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
When cycling subtitle tracks with the default J/Shift+J keybindings, the mpv OSD currently shows raw template text like `${sid}` instead of a resolved subtitle label. Update the keybinding OSD behavior so users see the active subtitle selection clearly when cycling tracks, and ensure placeholder-based OSD messages sent through the mpv client API render correctly.
|
When cycling subtitle tracks with the default J/Shift+J keybindings, the mpv OSD currently shows raw template text like `${sid}` instead of a resolved subtitle label. Update the keybinding OSD behavior so users see the active subtitle selection clearly when cycling tracks, and ensure placeholder-based OSD messages sent through the mpv client API render correctly.
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:END -->
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
<!-- AC:BEGIN -->
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
- [x] #1 Pressing the primary subtitle cycle keybinding shows a resolved subtitle label on the OSD instead of a raw `${sid}` placeholder.
|
- [x] #1 Pressing the primary subtitle cycle keybinding shows a resolved subtitle label on the OSD instead of a raw `${sid}` placeholder.
|
||||||
- [x] #2 Pressing the secondary subtitle cycle keybinding shows a resolved subtitle label on the OSD instead of a raw `${secondary-sid}` placeholder.
|
- [x] #2 Pressing the secondary subtitle cycle keybinding shows a resolved subtitle label on the OSD instead of a raw `${secondary-sid}` placeholder.
|
||||||
- [x] #3 Proxy OSD messages that rely on mpv property expansion render resolved values when sent through the mpv client API.
|
- [x] #3 Proxy OSD messages that rely on mpv property expansion render resolved values when sent through the mpv client API.
|
||||||
@@ -34,6 +38,7 @@ When cycling subtitle tracks with the default J/Shift+J keybindings, the mpv OSD
|
|||||||
## Implementation Plan
|
## Implementation Plan
|
||||||
|
|
||||||
<!-- SECTION:PLAN:BEGIN -->
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
1. Add focused failing tests for subtitle-cycle OSD labels and mpv placeholder-expansion behavior.
|
1. Add focused failing tests for subtitle-cycle OSD labels and mpv placeholder-expansion behavior.
|
||||||
2. Update the IPC mpv command handler to resolve primary and secondary subtitle track labels from mpv `track-list` data after cycling subtitle tracks.
|
2. Update the IPC mpv command handler to resolve primary and secondary subtitle track labels from mpv `track-list` data after cycling subtitle tracks.
|
||||||
3. Update the mpv OSD runtime path so placeholder-based `show-text` messages sent through the client API opt into property expansion.
|
3. Update the mpv OSD runtime path so placeholder-based `show-text` messages sent through the client API opt into property expansion.
|
||||||
@@ -43,6 +48,7 @@ When cycling subtitle tracks with the default J/Shift+J keybindings, the mpv OSD
|
|||||||
## Implementation Notes
|
## Implementation Notes
|
||||||
|
|
||||||
<!-- SECTION:NOTES:BEGIN -->
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
Initial triage: `ipc-command.ts` emits raw `${sid}`/`${secondary-sid}` placeholder strings, and `showMpvOsdRuntime` sends `show-text` via mpv client API without enabling property expansion.
|
Initial triage: `ipc-command.ts` emits raw `${sid}`/`${secondary-sid}` placeholder strings, and `showMpvOsdRuntime` sends `show-text` via mpv client API without enabling property expansion.
|
||||||
|
|
||||||
User approved implementation plan on 2026-03-07.
|
User approved implementation plan on 2026-03-07.
|
||||||
@@ -58,14 +64,17 @@ Testing: `bun x tsc --noEmit` passed.
|
|||||||
Testing: `bun run test:core:src` passed (423 pass, 6 skip, 0 fail).
|
Testing: `bun run test:core:src` passed (423 pass, 6 skip, 0 fail).
|
||||||
|
|
||||||
Docs: no update required because no checked-in docs or help text describe the J/Shift+J OSD output behavior.
|
Docs: no update required because no checked-in docs or help text describe the J/Shift+J OSD output behavior.
|
||||||
|
|
||||||
<!-- SECTION:NOTES:END -->
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
## Final Summary
|
## Final Summary
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
Fixed subtitle-cycle OSD handling for the default J/Shift+J keybindings. The IPC mpv command path now supports resolving proxy OSD text asynchronously, and the main-runtime resolver reads mpv `track-list` state so primary and secondary subtitle cycling show human-readable track labels instead of raw `${sid}` / `${secondary-sid}` placeholders.
|
Fixed subtitle-cycle OSD handling for the default J/Shift+J keybindings. The IPC mpv command path now supports resolving proxy OSD text asynchronously, and the main-runtime resolver reads mpv `track-list` state so primary and secondary subtitle cycling show human-readable track labels instead of raw `${sid}` / `${secondary-sid}` placeholders.
|
||||||
|
|
||||||
Also fixed the lower-level mpv OSD transport so placeholder-based `show-text` messages sent through the client API opt into `expand-properties`. That preserves existing template-based OSD messages like subtitle delay and subtitle position without leaking the raw `${...}` syntax.
|
Also fixed the lower-level mpv OSD transport so placeholder-based `show-text` messages sent through the client API opt into `expand-properties`. That preserves existing template-based OSD messages like subtitle delay and subtitle position without leaking the raw `${...}` syntax.
|
||||||
|
|
||||||
Added regression coverage for the async proxy OSD path, the placeholder-expansion `showMpvOsdRuntime` path, and the runtime subtitle-track label resolver. Verification run: `bun x tsc --noEmit`; focused mpv/IPC tests; and the maintained `bun run test:core:src` lane (423 pass, 6 skip, 0 fail).
|
Added regression coverage for the async proxy OSD path, the placeholder-expansion `showMpvOsdRuntime` path, and the runtime subtitle-track label resolver. Verification run: `bun x tsc --noEmit`; focused mpv/IPC tests; and the maintained `bun run test:core:src` lane (423 pass, 6 skip, 0 fail).
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
|
|||||||
@@ -23,11 +23,15 @@ priority: medium
|
|||||||
## Description
|
## Description
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
Review Claude's PR feedback on PR #15, implement only the technically valid fixes on the current branch, and document which comments are non-actionable or already acceptable.
|
Review Claude's PR feedback on PR #15, implement only the technically valid fixes on the current branch, and document which comments are non-actionable or already acceptable.
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:END -->
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
<!-- AC:BEGIN -->
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
- [x] #1 Validated Claude's concrete PR review items against current branch state and repo conventions
|
- [x] #1 Validated Claude's concrete PR review items against current branch state and repo conventions
|
||||||
- [x] #2 Implemented the accepted fixes with regression coverage or verification where applicable
|
- [x] #2 Implemented the accepted fixes with regression coverage or verification where applicable
|
||||||
- [x] #3 Documented which review items are non-blocking or intentionally left unchanged
|
- [x] #3 Documented which review items are non-blocking or intentionally left unchanged
|
||||||
@@ -36,6 +40,7 @@ Review Claude's PR feedback on PR #15, implement only the technically valid fixe
|
|||||||
## Implementation Plan
|
## Implementation Plan
|
||||||
|
|
||||||
<!-- SECTION:PLAN:BEGIN -->
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
1. Validate each Claude review item against current branch files and repo workflow.
|
1. Validate each Claude review item against current branch files and repo workflow.
|
||||||
2. Patch release quality-gate to match CI ordering and add explicit typecheck.
|
2. Patch release quality-gate to match CI ordering and add explicit typecheck.
|
||||||
3. Remove duplicate .gitmodules stanza and normalize the TASK-101 reference path through Backlog MCP.
|
3. Remove duplicate .gitmodules stanza and normalize the TASK-101 reference path through Backlog MCP.
|
||||||
@@ -45,17 +50,21 @@ Review Claude's PR feedback on PR #15, implement only the technically valid fixe
|
|||||||
## Implementation Notes
|
## Implementation Notes
|
||||||
|
|
||||||
<!-- SECTION:NOTES:BEGIN -->
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
User asked to address Claude PR comments on PR #15 and assess whether any action items remain. Treat review suggestions skeptically; only fix validated defects.
|
User asked to address Claude PR comments on PR #15 and assess whether any action items remain. Treat review suggestions skeptically; only fix validated defects.
|
||||||
|
|
||||||
Validated Claude's five review items. Fixed release workflow ordering/typecheck, removed the duplicate .gitmodules entry, and normalized TASK-101 references to repo-relative paths via Backlog MCP.
|
Validated Claude's five review items. Fixed release workflow ordering/typecheck, removed the duplicate .gitmodules entry, and normalized TASK-101 references to repo-relative paths via Backlog MCP.
|
||||||
|
|
||||||
Left the vendor/subminer-yomitan branch-pin suggestion unchanged. The committed submodule SHA already controls reproducibility; adding a branch would only affect update ergonomics and was not required to address a concrete defect.
|
Left the vendor/subminer-yomitan branch-pin suggestion unchanged. The committed submodule SHA already controls reproducibility; adding a branch would only affect update ergonomics and was not required to address a concrete defect.
|
||||||
|
|
||||||
<!-- SECTION:NOTES:END -->
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
## Final Summary
|
## Final Summary
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
Validated Claude's PR #15 review summary against the current branch and applied the actionable fixes. In `.github/workflows/release.yml`, the release `quality-gate` job now restores the dependency cache before installation, no longer installs twice, and runs `bun run typecheck` before the fast test suite to match CI expectations. In `.gitmodules`, removed the duplicate `vendor/yomitan-jlpt-vocab` stanza with the conflicting duplicate path. Through Backlog MCP, updated `TASK-101` references from an absolute local path to repo-relative paths so the task metadata is portable across contributors.
|
Validated Claude's PR #15 review summary against the current branch and applied the actionable fixes. In `.github/workflows/release.yml`, the release `quality-gate` job now restores the dependency cache before installation, no longer installs twice, and runs `bun run typecheck` before the fast test suite to match CI expectations. In `.gitmodules`, removed the duplicate `vendor/yomitan-jlpt-vocab` stanza with the conflicting duplicate path. Through Backlog MCP, updated `TASK-101` references from an absolute local path to repo-relative paths so the task metadata is portable across contributors.
|
||||||
|
|
||||||
Verification: `git diff --check`, `git config -f .gitmodules --get-regexp '^submodule\..*\.path$'`, `bun run typecheck`, and `bun run test:fast` all passed. `bun run format:check` still fails on many pre-existing unrelated files already present on the branch, including multiple backlog task files and existing source/docs files; this review patch did not attempt a repo-wide formatting sweep.
|
Verification: `git diff --check`, `git config -f .gitmodules --get-regexp '^submodule\..*\.path$'`, `bun run typecheck`, and `bun run test:fast` all passed. `bun run format:check` still fails on many pre-existing unrelated files already present on the branch, including multiple backlog task files and existing source/docs files; this review patch did not attempt a repo-wide formatting sweep.
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
|
|||||||
@@ -19,11 +19,15 @@ priority: medium
|
|||||||
## Description
|
## Description
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
Change the `make pretty` workflow so it formats only the maintained source/config files we intentionally keep under Prettier, instead of sweeping backlog/docs/generated content across the whole repository.
|
Change the `make pretty` workflow so it formats only the maintained source/config files we intentionally keep under Prettier, instead of sweeping backlog/docs/generated content across the whole repository.
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:END -->
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
<!-- AC:BEGIN -->
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
- [x] #1 `make pretty` formats only the approved maintained source/config paths
|
- [x] #1 `make pretty` formats only the approved maintained source/config paths
|
||||||
- [x] #2 The allowlist is reusable for check/write flows instead of duplicating path logic
|
- [x] #2 The allowlist is reusable for check/write flows instead of duplicating path logic
|
||||||
- [x] #3 Verification shows the scoped formatting command targets the intended files without touching backlog or vendored content
|
- [x] #3 Verification shows the scoped formatting command targets the intended files without touching backlog or vendored content
|
||||||
@@ -32,6 +36,7 @@ Change the `make pretty` workflow so it formats only the maintained source/confi
|
|||||||
## Implementation Plan
|
## Implementation Plan
|
||||||
|
|
||||||
<!-- SECTION:PLAN:BEGIN -->
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
1. Inspect current Prettier config/ignore behavior and keep the broad repo-wide format command unchanged.
|
1. Inspect current Prettier config/ignore behavior and keep the broad repo-wide format command unchanged.
|
||||||
2. Add a reusable scoped Prettier script that targets maintained source/config paths only.
|
2. Add a reusable scoped Prettier script that targets maintained source/config paths only.
|
||||||
3. Update `make pretty` to call the scoped script.
|
3. Update `make pretty` to call the scoped script.
|
||||||
@@ -41,6 +46,7 @@ Change the `make pretty` workflow so it formats only the maintained source/confi
|
|||||||
## Implementation Notes
|
## Implementation Notes
|
||||||
|
|
||||||
<!-- SECTION:NOTES:BEGIN -->
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
User approved the allowlist approach: keep repo-wide `format` intact, make `make pretty` use a maintained-path formatter scope.
|
User approved the allowlist approach: keep repo-wide `format` intact, make `make pretty` use a maintained-path formatter scope.
|
||||||
|
|
||||||
Added `scripts/prettier-scope.sh` as the single allowlist for scoped Prettier paths and wired `format:src` / `format:check:src` to it.
|
Added `scripts/prettier-scope.sh` as the single allowlist for scoped Prettier paths and wired `format:src` / `format:check:src` to it.
|
||||||
@@ -48,12 +54,15 @@ Added `scripts/prettier-scope.sh` as the single allowlist for scoped Prettier pa
|
|||||||
Updated `make pretty` to call `bun run format:src`. Verified with `make -n pretty` and shell tracing that the helper only targets the maintained allowlist and does not traverse `backlog/` or `vendor/`.
|
Updated `make pretty` to call `bun run format:src`. Verified with `make -n pretty` and shell tracing that the helper only targets the maintained allowlist and does not traverse `backlog/` or `vendor/`.
|
||||||
|
|
||||||
Excluded `Makefile` and `.prettierignore` from the allowlist after verification showed Prettier cannot infer parsers for them.
|
Excluded `Makefile` and `.prettierignore` from the allowlist after verification showed Prettier cannot infer parsers for them.
|
||||||
|
|
||||||
<!-- SECTION:NOTES:END -->
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
## Final Summary
|
## Final Summary
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
Scoped the repo's day-to-day formatting entrypoint without changing the existing broad repo-wide Prettier scripts. Added `scripts/prettier-scope.sh` as the shared allowlist for maintained source/config paths (`.github`, `build`, `launcher`, `scripts`, `src`, plus selected root JSON config files), added `format:src` and `format:check:src` in `package.json`, and updated `make pretty` to run the scoped formatter.
|
Scoped the repo's day-to-day formatting entrypoint without changing the existing broad repo-wide Prettier scripts. Added `scripts/prettier-scope.sh` as the shared allowlist for maintained source/config paths (`.github`, `build`, `launcher`, `scripts`, `src`, plus selected root JSON config files), added `format:src` and `format:check:src` in `package.json`, and updated `make pretty` to run the scoped formatter.
|
||||||
|
|
||||||
Verification: `make -n pretty` now resolves to `bun run format:src`. `bash -n scripts/prettier-scope.sh` passed, and shell-traced `bash -x scripts/prettier-scope.sh --check` confirmed the exact allowlist passed to Prettier. `bun run format:check:src` fails only because existing files inside the allowed source scope are not currently formatted; it no longer touches `backlog/` or `vendor/`.
|
Verification: `make -n pretty` now resolves to `bun run format:src`. `bash -n scripts/prettier-scope.sh` passed, and shell-traced `bash -x scripts/prettier-scope.sh --check` confirmed the exact allowlist passed to Prettier. `bun run format:check:src` fails only because existing files inside the allowed source scope are not currently formatted; it no longer touches `backlog/` or `vendor/`.
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
|
|||||||
@@ -20,11 +20,15 @@ priority: high
|
|||||||
## Description
|
## Description
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
Investigate the failing GitHub Actions CI run for PR #15 on branch `yomitan-fork`, fix the underlying test or code regression, and verify the affected local test/CI lane passes.
|
Investigate the failing GitHub Actions CI run for PR #15 on branch `yomitan-fork`, fix the underlying test or code regression, and verify the affected local test/CI lane passes.
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:END -->
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
<!-- AC:BEGIN -->
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
- [x] #1 Identified the concrete failing CI job and captured the relevant failure context
|
- [x] #1 Identified the concrete failing CI job and captured the relevant failure context
|
||||||
- [x] #2 Implemented the minimal code or test change needed to resolve the CI failure
|
- [x] #2 Implemented the minimal code or test change needed to resolve the CI failure
|
||||||
- [x] #3 Verified the affected local test target and the broader fast CI test lane pass
|
- [x] #3 Verified the affected local test target and the broader fast CI test lane pass
|
||||||
@@ -33,6 +37,7 @@ Investigate the failing GitHub Actions CI run for PR #15 on branch `yomitan-fork
|
|||||||
## Implementation Plan
|
## Implementation Plan
|
||||||
|
|
||||||
<!-- SECTION:PLAN:BEGIN -->
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
1. Inspect the failing GitHub Actions run and confirm the exact failing test/assertion.
|
1. Inspect the failing GitHub Actions run and confirm the exact failing test/assertion.
|
||||||
2. Reproduce the failing renderer stylesheet test locally and compare the assertion against current CSS.
|
2. Reproduce the failing renderer stylesheet test locally and compare the assertion against current CSS.
|
||||||
3. Apply the minimal test or stylesheet fix needed to restore the intended hover/selection behavior.
|
3. Apply the minimal test or stylesheet fix needed to restore the intended hover/selection behavior.
|
||||||
@@ -42,6 +47,7 @@ Investigate the failing GitHub Actions CI run for PR #15 on branch `yomitan-fork
|
|||||||
## Implementation Notes
|
## Implementation Notes
|
||||||
|
|
||||||
<!-- SECTION:NOTES:BEGIN -->
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
GitHub Actions run 22810400921 failed in job build-test-audit, step `Test suite (source)`, with a single failing test: `JLPT CSS rules use underline-only styling in renderer stylesheet` in src/renderer/subtitle-render.test.ts.
|
GitHub Actions run 22810400921 failed in job build-test-audit, step `Test suite (source)`, with a single failing test: `JLPT CSS rules use underline-only styling in renderer stylesheet` in src/renderer/subtitle-render.test.ts.
|
||||||
|
|
||||||
Reproduced the failing test locally with `bun test src/renderer/subtitle-render.test.ts`. The failure was a brittle stylesheet assertion, not a renderer behavior regression.
|
Reproduced the failing test locally with `bun test src/renderer/subtitle-render.test.ts`. The failure was a brittle stylesheet assertion, not a renderer behavior regression.
|
||||||
@@ -49,14 +55,17 @@ Reproduced the failing test locally with `bun test src/renderer/subtitle-render.
|
|||||||
Updated the renderer stylesheet test helper to split selectors safely across `:is(...)` commas and normalize multiline selector whitespace, then switched the failing hover/JLPT assertions to inspect extracted rule blocks instead of matching the entire CSS file text.
|
Updated the renderer stylesheet test helper to split selectors safely across `:is(...)` commas and normalize multiline selector whitespace, then switched the failing hover/JLPT assertions to inspect extracted rule blocks instead of matching the entire CSS file text.
|
||||||
|
|
||||||
Verification passed with `bun test src/renderer/subtitle-render.test.ts` and `bun run test`.
|
Verification passed with `bun test src/renderer/subtitle-render.test.ts` and `bun run test`.
|
||||||
|
|
||||||
<!-- SECTION:NOTES:END -->
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
## Final Summary
|
## Final Summary
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
Investigated GitHub Actions CI run `22810400921` for PR #15 and confirmed the only failing job was `build-test-audit`, step `Test suite (source)`, with a single failure in `src/renderer/subtitle-render.test.ts` (`JLPT CSS rules use underline-only styling in renderer stylesheet`).
|
Investigated GitHub Actions CI run `22810400921` for PR #15 and confirmed the only failing job was `build-test-audit`, step `Test suite (source)`, with a single failure in `src/renderer/subtitle-render.test.ts` (`JLPT CSS rules use underline-only styling in renderer stylesheet`).
|
||||||
|
|
||||||
The renderer CSS itself was still correct; the regression was in the test helper. `extractClassBlock` was splitting selector lists on every comma, which breaks selectors containing `:is(...)`, and the affected assertions fell back to brittle whole-file regex matching against a multiline selector. Fixed the test by teaching the helper to split selectors only at top-level commas, normalizing selector whitespace around multiline `:not(...)` / `:is(...)` clauses, and asserting on extracted rule blocks for the plain-word hover and JLPT-only hover/selection rules.
|
The renderer CSS itself was still correct; the regression was in the test helper. `extractClassBlock` was splitting selector lists on every comma, which breaks selectors containing `:is(...)`, and the affected assertions fell back to brittle whole-file regex matching against a multiline selector. Fixed the test by teaching the helper to split selectors only at top-level commas, normalizing selector whitespace around multiline `:not(...)` / `:is(...)` clauses, and asserting on extracted rule blocks for the plain-word hover and JLPT-only hover/selection rules.
|
||||||
|
|
||||||
Verification: `bun test src/renderer/subtitle-render.test.ts` passed, and `bun run test` passed end to end (the same fast lane that failed in CI).
|
Verification: `bun test src/renderer/subtitle-render.test.ts` passed, and `bun run test` passed end to end (the same fast lane that failed in CI).
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
|
|||||||
@@ -20,11 +20,15 @@ priority: medium
|
|||||||
## Description
|
## Description
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
Update the sibling `subminer-docs` repo so contributor/development docs match the current SubMiner repo workflow after the docs split and recent tooling changes, including removing stale in-repo docs build steps and documenting the scoped formatting command.
|
Update the sibling `subminer-docs` repo so contributor/development docs match the current SubMiner repo workflow after the docs split and recent tooling changes, including removing stale in-repo docs build steps and documenting the scoped formatting command.
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:END -->
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
<!-- AC:BEGIN -->
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
- [x] #1 Contributor docs in `subminer-docs` no longer reference stale in-repo docs build commands for the app repo
|
- [x] #1 Contributor docs in `subminer-docs` no longer reference stale in-repo docs build commands for the app repo
|
||||||
- [x] #2 Contributor docs mention the current scoped formatting workflow (`make pretty` / `format:src`) where relevant
|
- [x] #2 Contributor docs mention the current scoped formatting workflow (`make pretty` / `format:src`) where relevant
|
||||||
- [x] #3 Removed stale or no-longer-needed instructions that no longer match the current repo layout
|
- [x] #3 Removed stale or no-longer-needed instructions that no longer match the current repo layout
|
||||||
@@ -33,6 +37,7 @@ Update the sibling `subminer-docs` repo so contributor/development docs match th
|
|||||||
## Implementation Plan
|
## Implementation Plan
|
||||||
|
|
||||||
<!-- SECTION:PLAN:BEGIN -->
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
1. Inspect `subminer-docs` for contributor/development instructions that drifted after the docs repo split and recent tooling changes.
|
1. Inspect `subminer-docs` for contributor/development instructions that drifted after the docs repo split and recent tooling changes.
|
||||||
2. Update contributor docs to remove stale app-repo docs commands and document the current scoped formatting workflow.
|
2. Update contributor docs to remove stale app-repo docs commands and document the current scoped formatting workflow.
|
||||||
3. Verify the modified docs page and build the docs site from the sibling docs repo when local dependencies are available.
|
3. Verify the modified docs page and build the docs site from the sibling docs repo when local dependencies are available.
|
||||||
@@ -41,6 +46,7 @@ Update the sibling `subminer-docs` repo so contributor/development docs match th
|
|||||||
## Implementation Notes
|
## Implementation Notes
|
||||||
|
|
||||||
<!-- SECTION:NOTES:BEGIN -->
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
Detected concrete doc drift in `subminer-docs/development.md`: stale in-repo docs build commands and no mention of the scoped `make pretty` formatter.
|
Detected concrete doc drift in `subminer-docs/development.md`: stale in-repo docs build commands and no mention of the scoped `make pretty` formatter.
|
||||||
|
|
||||||
Updated `../subminer-docs/development.md` to remove stale app-repo docs build steps from the local gate, document `make pretty` / `format:check:src`, and point docs-site work to the sibling docs repo explicitly.
|
Updated `../subminer-docs/development.md` to remove stale app-repo docs build steps from the local gate, document `make pretty` / `format:check:src`, and point docs-site work to the sibling docs repo explicitly.
|
||||||
@@ -48,12 +54,15 @@ Updated `../subminer-docs/development.md` to remove stale app-repo docs build st
|
|||||||
Installed docs repo dependencies locally with `bun install` and verified the docs site with `bun run docs:build` in `../subminer-docs`.
|
Installed docs repo dependencies locally with `bun install` and verified the docs site with `bun run docs:build` in `../subminer-docs`.
|
||||||
|
|
||||||
Did not change `../subminer-docs/README.md`; it was already accurate for the docs repo itself.
|
Did not change `../subminer-docs/README.md`; it was already accurate for the docs repo itself.
|
||||||
|
|
||||||
<!-- SECTION:NOTES:END -->
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
## Final Summary
|
## Final Summary
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
Refreshed the contributor/development docs in the sibling `subminer-docs` repo to match the current SubMiner workflow. In `development.md`, removed the stale app-repo `bun run docs:build` step from the local CI-equivalent gate, added an explicit note to run docs builds from `../subminer-docs` when docs change, documented the scoped formatting workflow (`make pretty` and `bun run format:check:src`), and replaced the old in-repo `make docs*` instructions with the correct sibling-repo `bun run docs:*` commands. Also updated the Makefile reference to include `make pretty` and removed the obsolete `make docs-dev` entry.
|
Refreshed the contributor/development docs in the sibling `subminer-docs` repo to match the current SubMiner workflow. In `development.md`, removed the stale app-repo `bun run docs:build` step from the local CI-equivalent gate, added an explicit note to run docs builds from `../subminer-docs` when docs change, documented the scoped formatting workflow (`make pretty` and `bun run format:check:src`), and replaced the old in-repo `make docs*` instructions with the correct sibling-repo `bun run docs:*` commands. Also updated the Makefile reference to include `make pretty` and removed the obsolete `make docs-dev` entry.
|
||||||
|
|
||||||
Verification: installed docs repo dependencies with `bun install` in `../subminer-docs` and ran `bun run docs:build` successfully. Left `README.md` unchanged because it was already accurate for the standalone docs repo.
|
Verification: installed docs repo dependencies with `bun install` in `../subminer-docs` and ran `bun run docs:build` successfully. Left `README.md` unchanged because it was already accurate for the standalone docs repo.
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
|
|||||||
@@ -20,11 +20,15 @@ priority: medium
|
|||||||
## Description
|
## Description
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
Review recent `yomitan-fork` commits against the sibling `subminer-docs` repo, identify any concrete documentation drift that remains after the earlier contributor-doc updates, and patch the docs for behavior/tooling changes that are now outdated or misleading.
|
Review recent `yomitan-fork` commits against the sibling `subminer-docs` repo, identify any concrete documentation drift that remains after the earlier contributor-doc updates, and patch the docs for behavior/tooling changes that are now outdated or misleading.
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:END -->
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
<!-- AC:BEGIN -->
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
- [x] #1 Reviewed recent branch commits for user-facing or contributor-facing changes that may require docs updates
|
- [x] #1 Reviewed recent branch commits for user-facing or contributor-facing changes that may require docs updates
|
||||||
- [x] #2 Updated `subminer-docs` pages where branch changes introduced concrete doc drift
|
- [x] #2 Updated `subminer-docs` pages where branch changes introduced concrete doc drift
|
||||||
- [x] #3 Verified the docs site still builds after the updates
|
- [x] #3 Verified the docs site still builds after the updates
|
||||||
@@ -33,6 +37,7 @@ Review recent `yomitan-fork` commits against the sibling `subminer-docs` repo, i
|
|||||||
## Implementation Plan
|
## Implementation Plan
|
||||||
|
|
||||||
<!-- SECTION:PLAN:BEGIN -->
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
1. Review branch commit themes against `subminer-docs` and identify only concrete drift introduced by recent workflow/runtime changes.
|
1. Review branch commit themes against `subminer-docs` and identify only concrete drift introduced by recent workflow/runtime changes.
|
||||||
2. Patch docs for the Yomitan submodule build workflow, updated source-build prerequisites, and current runtime Yomitan search paths/manual fallback path.
|
2. Patch docs for the Yomitan submodule build workflow, updated source-build prerequisites, and current runtime Yomitan search paths/manual fallback path.
|
||||||
3. Rebuild the docs site to verify the updated pages render cleanly.
|
3. Rebuild the docs site to verify the updated pages render cleanly.
|
||||||
@@ -41,13 +46,17 @@ Review recent `yomitan-fork` commits against the sibling `subminer-docs` repo, i
|
|||||||
## Implementation Notes
|
## Implementation Notes
|
||||||
|
|
||||||
<!-- SECTION:NOTES:BEGIN -->
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
Concrete remaining drift after commit audit: installation/development docs still understate the Node/npm + submodule requirements for the Yomitan build flow, and troubleshooting still points at obsolete `vendor/yomitan` / `extensions/yomitan` paths.
|
Concrete remaining drift after commit audit: installation/development docs still understate the Node/npm + submodule requirements for the Yomitan build flow, and troubleshooting still points at obsolete `vendor/yomitan` / `extensions/yomitan` paths.
|
||||||
|
|
||||||
Audited branch commits against subminer-docs coverage. Existing docs already cover first-run setup, texthooker startup/annotated websocket config, AniList merged character dictionaries, configurable collapsible sections, and subtitle name highlighting. Patched remaining drift around source-build prerequisites and Yomitan build/install paths in installation.md, development.md, and troubleshooting.md. Verified with `bun run docs:build` in ../subminer-docs.
|
Audited branch commits against subminer-docs coverage. Existing docs already cover first-run setup, texthooker startup/annotated websocket config, AniList merged character dictionaries, configurable collapsible sections, and subtitle name highlighting. Patched remaining drift around source-build prerequisites and Yomitan build/install paths in installation.md, development.md, and troubleshooting.md. Verified with `bun run docs:build` in ../subminer-docs.
|
||||||
|
|
||||||
<!-- SECTION:NOTES:END -->
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
## Final Summary
|
## Final Summary
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
Audited branch commits for missing documentation updates in ../subminer-docs. Updated installation, development, and troubleshooting docs to match the current Yomitan submodule build flow, source-build prerequisites, and runtime extension search/manual fallback paths. Confirmed other recent branch features were already documented and rebuilt the docs site successfully.
|
Audited branch commits for missing documentation updates in ../subminer-docs. Updated installation, development, and troubleshooting docs to match the current Yomitan submodule build flow, source-build prerequisites, and runtime extension search/manual fallback paths. Confirmed other recent branch features were already documented and rebuilt the docs site successfully.
|
||||||
|
|
||||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
id: TASK-117
|
||||||
|
title: Prepare initial Windows release docs and version bump
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-08 15:17'
|
||||||
|
updated_date: '2026-03-08 15:17'
|
||||||
|
labels:
|
||||||
|
- release
|
||||||
|
- docs
|
||||||
|
- windows
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- package.json
|
||||||
|
- README.md
|
||||||
|
- ../subminer-docs/installation.md
|
||||||
|
- ../subminer-docs/usage.md
|
||||||
|
- ../subminer-docs/changelog.md
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Prepare the initial packaged Windows release by bumping the app version and refreshing the release-facing README/backlog/docs surfaces so install and direct-command guidance no longer reads Linux-only.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 App version is bumped for the Windows release cut
|
||||||
|
- [x] #2 README and sibling docs describe Windows packaged installation alongside Linux/macOS guidance
|
||||||
|
- [x] #3 Backlog records the release-doc/version update with the modified references
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Bump the package version for the release cut.
|
||||||
|
2. Update the root README install/start guidance to mention Windows packaged builds.
|
||||||
|
3. Patch the sibling docs repo installation, usage, and changelog pages for the Windows release.
|
||||||
|
4. Record the work in Backlog and run targeted verification on the touched surfaces.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
The public README still advertised Linux/macOS only, while the sibling docs had Windows-specific runtime notes but no actual Windows install section and several direct-command examples still assumed `SubMiner.AppImage`.
|
||||||
|
|
||||||
|
Bumped `package.json` to `0.5.0`, expanded the README platform/install copy to include Windows, added a Windows install section to `../subminer-docs/installation.md`, clarified in `../subminer-docs/usage.md` that direct packaged-app examples use `SubMiner.exe` on Windows, and added a `v0.5.0` changelog entry covering the initial Windows release plus the latest overlay behavior polish.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Prepared the initial Windows release documentation pass and version bump. `package.json` now reports `0.5.0`. The root `README.md` now advertises Linux, macOS, and Windows support, includes Windows packaged-install guidance, and clarifies first-launch behavior across platforms. In the sibling docs repo, `installation.md` now includes a dedicated Windows install section, `usage.md` explains that direct packaged-app examples use `SubMiner.exe` on Windows, and `changelog.md` now includes the `v0.5.0` release notes for the initial Windows build and recent overlay behavior changes.
|
||||||
|
|
||||||
|
Verification: targeted `bun run tsc --noEmit -p tsconfig.typecheck.json` in the app repo and `bun run docs:build` in `../subminer-docs`.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
id: TASK-117
|
||||||
|
title: >-
|
||||||
|
Replace YouTube subtitle generation with pure TypeScript pipeline and shared
|
||||||
|
AI config
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-08 03:16'
|
||||||
|
updated_date: '2026-03-08 03:35'
|
||||||
|
labels: []
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/launcher/youtube.ts
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/src/anki-integration/ai.ts
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/src/types.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/src/config/definitions/defaults-integrations.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/src/config/resolve/subtitle-domains.ts
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/config.example.jsonc
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Replace the launcher YouTube subtitle generation flow with a pure TypeScript pipeline that prefers real downloadable YouTube subtitles, never uses YouTube auto-generated subtitles, locally generates missing tracks with whisper.cpp, and can optionally fix generated subtitles via a shared OpenAI-compatible AI provider config. This feature also introduces a breaking config cleanup: move provider settings to a new top-level ai section and reduce ankiConnect.ai to a boolean feature toggle.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Launcher YouTube subtitle generation prefers downloadable manual YouTube subtitles, never uses YouTube auto-generated subtitles, and locally generates only missing tracks with whisper.cpp.
|
||||||
|
- [x] #2 Generated whisper subtitle tracks can optionally be post-processed with an OpenAI-compatible AI provider using shared top-level ai config, with validation and fallback to raw whisper output on failure.
|
||||||
|
- [x] #3 Configuration is updated so top-level ai is canonical shared provider config, ankiConnect.ai is boolean-only, and youtubeSubgen includes whisperVadModel, whisperThreads, and fixWithAi.
|
||||||
|
- [x] #4 Launcher CLI/config parsing, config example, and docs reflect the new breaking config shape with no migration layer.
|
||||||
|
- [x] #5 Automated tests cover the new YouTube generation behavior, AI-fix fallback/validation behavior, shared AI config usage, and breaking config validation.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Introduce canonical top-level ai config plus youtubeSubgen runtime knobs (whisperVadModel, whisperThreads, fixWithAi) and convert ankiConnect.ai to a boolean-only toggle across types, defaults, validation, option registries, launcher config parsing, and config example/docs.
|
||||||
|
2. Extract shared OpenAI-compatible AI client helpers from the current Anki translation code, including base URL normalization, API key / apiKeyCommand resolution, timeout handling, and response text extraction.
|
||||||
|
3. Update Anki translation flow and hot-reload/runtime plumbing to consume global ai config while treating ankiConnect.ai as a feature gate only.
|
||||||
|
4. Replace launcher/youtube.ts with a modular launcher/youtube pipeline that fetches only manual YouTube subtitles, generates missing tracks locally with ffmpeg + whisper.cpp + optional VAD/thread controls, and preserves preprocess/automatic playback behavior.
|
||||||
|
5. Add optional AI subtitle-fix processing for whisper-generated tracks using the shared ai client, with strict SRT batching/validation and fallback to raw whisper output on provider or format failure.
|
||||||
|
6. Expand automated coverage for config validation, shared AI usage, launcher config parsing, and YouTube subtitle generation behavior including removal of yt-dlp auto-subs and AI-fix fallback rules.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Implemented pure TypeScript launcher/youtube pipeline modules for manual subtitle fetch, audio extraction, whisper runs, SRT utilities, and optional AI subtitle fixing. Removed yt-dlp auto-subtitle usage from the generation path.
|
||||||
|
|
||||||
|
Added shared top-level ai config plus shared AI client helpers; converted ankiConnect.ai to a boolean feature gate and updated Anki runtime wiring to consume global ai config.
|
||||||
|
|
||||||
|
Updated launcher config parsing, config template sections, and config.example.jsonc for the breaking config shape including youtubeSubgen.whisperVadModel, youtubeSubgen.whisperThreads, and youtubeSubgen.fixWithAi.
|
||||||
|
|
||||||
|
Verification: bun run test:config:src passed; targeted AI/Anki/runtime tests passed; bun run typecheck passed. bun run test:launcher:unit:src reported one unrelated existing failure in launcher/aniskip-metadata.test.ts (resolveAniSkipMetadataForFile resolves MAL id and intro payload).
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Replaced the launcher YouTube subtitle flow with a modular TypeScript pipeline that prefers manual YouTube subtitles, transcribes only missing tracks with whisper.cpp, and can optionally post-fix whisper output through a shared OpenAI-compatible AI client with strict SRT validation/fallback. Introduced canonical top-level ai config, reduced ankiConnect.ai to a boolean feature gate, updated launcher/config parsing and checked-in config artifacts, and added coverage for YouTube orchestration, whisper args, SRT validation, AI fix behavior, and breaking config validation.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
id: TASK-117.1
|
||||||
|
title: Harden AI subtitle fix against non-SRT model responses
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- '@codex'
|
||||||
|
created_date: '2026-03-08 08:22'
|
||||||
|
updated_date: '2026-03-08 08:25'
|
||||||
|
labels: []
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/launcher/youtube/subtitle-fix-ai.ts
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/launcher/youtube/srt.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/launcher/youtube/subtitle-fix-ai.test.ts
|
||||||
|
parent_task_id: TASK-117
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Prevent optional YouTube AI subtitle post-processing from bailing out whenever the model returns usable cue text in a non-SRT wrapper or text-only format. The launcher should recover safe cases, preserve original timing, and fall back cleanly when the response cannot be mapped back to the source cues.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 AI subtitle fixing accepts safe AI responses that omit SRT framing but still provide one corrected text payload per original cue while preserving original cue timing.
|
||||||
|
- [x] #2 AI subtitle fixing still rejects responses that cannot be mapped back to the original cue batch without guessing and falls back to the raw subtitle file with a warning.
|
||||||
|
- [x] #3 Automated tests cover wrapped-SRT and text-only AI responses plus an unrecoverable invalid response case.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Add failing tests in launcher/youtube/subtitle-fix-ai.test.ts for three cases: wrapped valid SRT, text-only one-block-per-cue output, and unrecoverable invalid output.
|
||||||
|
2. Extend launcher/youtube/subtitle-fix-ai.ts with a small response-normalization path that first strips markdown/code-fence wrappers, then accepts deterministic text-only cue batches only when they map 1:1 to the original cues without changing timestamps.
|
||||||
|
3. Keep existing safety rules: preserve cue count and timing, log a warning, and fall back to the raw subtitle file when normalization cannot recover a trustworthy batch.
|
||||||
|
4. Run focused launcher unit tests for subtitle-fix-ai and SRT parsing; expand only if the change affects adjacent behavior.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Implemented deterministic AI subtitle-response recovery for fenced SRT, embedded SRT payloads, and text-only 1:1 cue batches while preserving original timing and existing fallback behavior.
|
||||||
|
|
||||||
|
Verification: bun test launcher/youtube/_.test.ts passed; bun run typecheck passed; repo-wide format check still reports unrelated pre-existing warnings in launcher/youtube/orchestrator.ts and scripts/build-changelog_.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Hardened the launcher AI subtitle-fix path so it can recover deterministic non-SRT model responses instead of immediately falling back. Added `parseAiSubtitleFixResponse` in `launcher/youtube/subtitle-fix-ai.ts` to normalize markdown-fenced or embedded SRT payloads first, then accept text-only responses only when they map 1:1 onto the original cue batch and preserve source timings. Added regression coverage in `launcher/youtube/subtitle-fix-ai.test.ts` for fenced SRT, text-only cue batches, and unrecoverable invalid output, plus a changelog fragment in `changes/task-117.1.md`.
|
||||||
|
|
||||||
|
Verification: `bun test launcher/youtube/*.test.ts`, `bun run typecheck`, `bunx prettier --check launcher/youtube/subtitle-fix-ai.ts launcher/youtube/subtitle-fix-ai.test.ts`, and `bun run changelog:lint` passed. Repo-wide `bun run format:check:src` still reports unrelated pre-existing warnings in `launcher/youtube/orchestrator.ts` and `scripts/build-changelog*`.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
id: TASK-118
|
||||||
|
title: Add Windows release build and SignPath signing
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-08 15:17'
|
||||||
|
updated_date: '2026-03-08 15:17'
|
||||||
|
labels:
|
||||||
|
- release
|
||||||
|
- windows
|
||||||
|
- signing
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- .github/workflows/release.yml
|
||||||
|
- build/installer.nsh
|
||||||
|
- build/signpath-windows-artifact-config.xml
|
||||||
|
- package.json
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Extend the tag-driven release workflow so Windows artifacts are built on GitHub-hosted runners and submitted to SignPath for free open-source Authenticode signing, while preserving the existing macOS notarization path.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Release workflow builds Windows installer and ZIP artifacts on `windows-latest`
|
||||||
|
- [x] #2 Workflow submits unsigned Windows artifacts to SignPath and uploads the signed outputs for release publication
|
||||||
|
- [x] #3 Repository includes a checked-in SignPath artifact-configuration source of truth for the Windows release files
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Inspect the existing release workflow and current Windows packaging configuration.
|
||||||
|
2. Add a Windows release job that builds unsigned artifacts, uploads them as a workflow artifact, and submits them to SignPath.
|
||||||
|
3. Update the release aggregation job to publish signed Windows assets and mention Windows install steps in the generated release notes.
|
||||||
|
4. Check in the Windows SignPath artifact configuration XML used to define what gets signed.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
The repository already had Windows packaging configuration (`build:win`, NSIS include script, Windows helper asset packaging), but the release workflow still built Linux and macOS only.
|
||||||
|
|
||||||
|
Added a `build-windows` job to `.github/workflows/release.yml` that runs on `windows-latest`, validates required SignPath secrets, builds unsigned Windows artifacts, uploads them with `actions/upload-artifact@v4`, and then calls the official `signpath/github-action-submit-signing-request@v2` action to retrieve signed outputs.
|
||||||
|
|
||||||
|
Checked in `build/signpath-windows-artifact-config.xml` as the source-of-truth artifact configuration for SignPath. It signs the top-level NSIS installer EXE and deep-signs `.exe` and `.dll` files inside the portable ZIP artifact.
|
||||||
|
|
||||||
|
Updated the release aggregation job to download the signed Windows artifacts and added a Windows install section to the generated GitHub release body.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Windows release publishing is now wired into the tag-driven workflow. `.github/workflows/release.yml` builds Windows artifacts on `windows-latest`, submits them to SignPath using the official GitHub action, and publishes the signed `.exe` and `.zip` outputs alongside the Linux and macOS artifacts. The workflow now requests the additional `actions: read` permission required by the SignPath GitHub integration, and the generated release notes now include Windows installation steps.
|
||||||
|
|
||||||
|
The checked-in `build/signpath-windows-artifact-config.xml` file defines the SignPath artifact structure expected by the workflow artifact ZIP: sign the top-level `SubMiner-*.exe` installer and deep-sign `.exe` and `.dll` files inside `SubMiner-*.zip`.
|
||||||
|
|
||||||
|
Verification: workflow/static changes were checked with `git diff --check` on the touched files. Actual signing requires configured SignPath secrets and a matching artifact configuration in your SignPath project.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
id: TASK-118
|
||||||
|
title: Fix GitHub release workflow publish step failure
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- Codex
|
||||||
|
created_date: '2026-03-08 03:34'
|
||||||
|
updated_date: '2026-03-08 03:38'
|
||||||
|
labels:
|
||||||
|
- ci
|
||||||
|
- release
|
||||||
|
- github-actions
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/.github/workflows/release.yml
|
||||||
|
- 'https://github.com/ksyasuda/SubMiner/actions/runs/22812335927'
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
The GitHub Actions Release workflow fails during the Publish Release step for tag releases because the gh CLI invocation passes invalid arguments when creating or editing the GitHub release. Restore successful release publication for tagged builds without changing unrelated release packaging behavior.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Tagged Release workflow completes the Publish Release step without gh CLI argument errors.
|
||||||
|
- [x] #2 Release workflow still creates or updates the GitHub release as a non-prerelease for normal version tags.
|
||||||
|
- [x] #3 A regression check covers the publish command shape or workflow behavior that caused this failure.
|
||||||
|
- [x] #4 Any release workflow behavior change is documented in repository docs or workflow comments if needed.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Add a targeted regression test for .github/workflows/release.yml that fails if the publish step passes an argument to the gh --prerelease boolean flag or otherwise omits explicit non-prerelease behavior.
|
||||||
|
2. Run the targeted test to confirm the current workflow fails for the expected reason.
|
||||||
|
3. Patch the Publish Release step in .github/workflows/release.yml to remove the invalid gh CLI usage while preserving non-prerelease release creation/update behavior.
|
||||||
|
4. Re-run the targeted regression test and any relevant lightweight verification, then record results in task notes.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Identified root cause from GitHub Actions run 22812335927: Publish Release failed with `accepts 1 arg(s), received 2` because the workflow passed a value to gh's boolean prerelease flag.
|
||||||
|
|
||||||
|
Added a workflow comment clarifying that omitting the prerelease flag keeps normal releases as non-prerelease releases.
|
||||||
|
|
||||||
|
Added src/release-workflow.test.ts and wired it into `bun run test:fast` so CI catches the invalid workflow shape before the next tag.
|
||||||
|
|
||||||
|
Verification: `bun test src/release-workflow.test.ts`, `bun run typecheck`, and `bun run test:fast` all passed locally.
|
||||||
|
|
||||||
|
Code-review pass found no issues; remaining caveat is that prerelease tag semantics are still not modeled for tags like `v1.0.0-beta.1`, which is outside this fix scope.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Fixed the GitHub Actions release publish step so tagged releases no longer fail on invalid gh CLI usage. The workflow now omits the prerelease flag when creating or editing normal releases, which preserves existing non-prerelease behavior and avoids the `accepts 1 arg(s), received 2` failure seen in run 22812335927.
|
||||||
|
|
||||||
|
Added a small regression test that reads `.github/workflows/release.yml` and asserts the publish step does not set the prerelease flag, then included that test in `bun run test:fast` so the main verification lane catches this class of workflow regression before the next release.
|
||||||
|
|
||||||
|
Validation run locally: `bun test src/release-workflow.test.ts`, `bun run typecheck`, and `bun run test:fast`. Residual risk: prerelease-tag semantics remain unchanged for tags such as `v1.0.0-beta.1`; this fix is intentionally scoped to restoring normal tagged release publication.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
id: TASK-119
|
||||||
|
title: Add Jellyfin remote-session subtitle streaming to texthooker
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-08 03:46'
|
||||||
|
labels:
|
||||||
|
- jellyfin
|
||||||
|
- texthooker
|
||||||
|
- subtitle
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/src/main/runtime/jellyfin-remote-commands.ts
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/src/core/services/jellyfin.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/src/core/services/subtitle-processing-controller.ts
|
||||||
|
- 'https://api.jellyfin.org/'
|
||||||
|
documentation:
|
||||||
|
- 'https://api.jellyfin.org/'
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Allow SubMiner to follow subtitles from a separate Jellyfin client session, such as a TV app, without requiring local mpv playback. The feature should fetch the active subtitle stream from Jellyfin, map the remote playback position to subtitle cues, and feed the existing subtitle tokenization plus annotated texthooker websocket pipeline so texthooker-only mode can be used while watching on another device.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [ ] #1 User can target a remote Jellyfin session and stream its current subtitle cue into SubMiner's existing subtitle-processing pipeline without launching local Jellyfin playback in mpv.
|
||||||
|
- [ ] #2 Texthooker-only mode can display subtitle updates from the tracked remote Jellyfin session through the existing annotation websocket feed.
|
||||||
|
- [ ] #3 Remote session changes are handled safely: item changes, subtitle-track changes, pause/seek/stop, and session disconnects clear or refresh subtitle state without crashing.
|
||||||
|
- [ ] #4 The feature degrades clearly when the remote session has no usable text subtitle stream or uses an unsupported subtitle format.
|
||||||
|
- [ ] #5 Automated tests cover session tracking, subtitle cue selection, and feed integration; user-facing docs/config docs are updated.
|
||||||
|
<!-- AC:END -->
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
id: TASK-120
|
||||||
|
title: 'Replace node:sqlite with libsql and remove Yomitan Node wrapper'
|
||||||
|
status: Done
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-08 04:14'
|
||||||
|
updated_date: '2026-03-08 04:39'
|
||||||
|
labels:
|
||||||
|
- runtime
|
||||||
|
- bun
|
||||||
|
- sqlite
|
||||||
|
- tech-debt
|
||||||
|
dependencies: []
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Remove the remaining root Node requirement caused by immersion tracking SQLite usage and the old Yomitan build wrapper by migrating the local SQLite layer off node:sqlite, running the SQLite-backed verification lanes under Bun, and switching the vendored Yomitan build flow to Bun-native scripts.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Immersion tracker runtime no longer imports or requires node:sqlite
|
||||||
|
- [x] #2 SQLite-backed immersion tracker tests run under Bun without Node --experimental-sqlite
|
||||||
|
- [x] #3 Root build/test scripts no longer require the Yomitan Node wrapper or Node-based SQLite verification lanes
|
||||||
|
- [x] #4 README requirements/testing docs reflect the Bun-native workflow
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Replaced the immersion tracker SQLite dependency with a local libsql-backed wrapper, updated Bun/runtime compatibility tests to avoid process.exitCode side effects, switched Yomitan builds to run directly inside the vendored Bun-native project, deleted scripts/build-yomitan.mjs, and verified typecheck plus Bun build/test lanes (`build:yomitan`, `test:immersion:sqlite`, `test:runtime:compat`, `test:fast`).
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
---
|
||||||
|
id: TASK-121
|
||||||
|
title: >-
|
||||||
|
Fix YouTube manual subtitle selection regression when downloadable tracks
|
||||||
|
exist
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- '@codex'
|
||||||
|
created_date: '2026-03-08 05:37'
|
||||||
|
updated_date: '2026-03-08 05:42'
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
- youtube
|
||||||
|
- subtitles
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/launcher/youtube/manual-subs.ts
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/launcher/youtube/orchestrator.ts
|
||||||
|
- 'https://www.youtube.com/watch?v=MXzQRLmN9hE'
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Ensure launcher YouTube subtitle generation reuses downloadable manual subtitle tracks when the video already has requested languages available, instead of falling back to whisper generation. Reproduce against videos like MXzQRLmN9hE that expose manual en/ja subtitles via yt-dlp.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 When requested primary/secondary manual YouTube subtitle tracks exist, planning selects them and schedules no whisper generation for those tracks.
|
||||||
|
- [x] #2 Filename normalization handles manual subtitle outputs produced by yt-dlp for language-tagged downloads.
|
||||||
|
- [x] #3 Automated tests cover the reproduced manual en/ja selection case.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Reproduced against https://www.youtube.com/watch?v=MXzQRLmN9hE with yt-dlp --list-subs: manual zh/en/ja/ko subtitle tracks are available from YouTube.
|
||||||
|
|
||||||
|
Adjusted launcher YouTube orchestration so detected manual subtitle tracks suppress whisper generation but are no longer materialized as external subtitle files. SubMiner now relies on the native YouTube/mpv subtitle tracks for those languages.
|
||||||
|
|
||||||
|
Added orchestration tests covering the manual-track reuse plan and ran a direct runtime probe against MXzQRLmN9hE. Probe result: primary/secondary native tracks detected, no external subtitle aliases emitted, output directory remained empty.
|
||||||
|
|
||||||
|
Verification: bun test launcher/youtube/orchestrator.test.ts launcher/config-domain-parsers.test.ts launcher/mpv.test.ts passed; bun run typecheck passed.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Fixed the YouTube subtitle regression where videos with real downloadable subtitle tracks still ended up with duplicate external subtitle files. Manual subtitle availability now suppresses whisper generation and external subtitle publication, so videos like MXzQRLmN9hE use the native YouTube/mpv subtitle tracks directly. Launcher preprocess logging was also updated to report native subtitle availability instead of misleading missing statuses.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
---
|
||||||
|
id: TASK-122
|
||||||
|
title: Harden changelog workflow and CI enforcement
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- Codex
|
||||||
|
created_date: '2026-03-08 06:13'
|
||||||
|
updated_date: '2026-03-08 06:28'
|
||||||
|
labels:
|
||||||
|
- release
|
||||||
|
- changelog
|
||||||
|
- ci
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/scripts/build-changelog.ts
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/scripts/build-changelog.test.ts
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/.github/workflows/ci.yml
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/.github/workflows/release.yml
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/docs/RELEASING.md
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/changes/README.md
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Improve the release changelog workflow so changelog fragments are reliable, release output is more readable, and pull requests get early feedback when changelog metadata is missing or malformed.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 `scripts/build-changelog.ts` ignores non-fragment files in `changes/` and validates fragment structure before generating changelog output.
|
||||||
|
- [x] #2 Generated `CHANGELOG.md` and `release/release-notes.md` group public changes into readable sections instead of a flat bullet list.
|
||||||
|
- [x] #3 CI enforces changelog validation on pull requests and provides an explicit opt-out path for changes that should not produce release notes.
|
||||||
|
- [x] #4 Contributor docs explain the fragment format and the PR/release workflow for changelog generation.
|
||||||
|
- [x] #5 Automated tests cover fragment parsing/building behavior and workflow enforcement expectations.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Add failing tests for changelog fragment discovery, structured fragment parsing/rendering, release-note output, and CI workflow expectations.
|
||||||
|
2. Update scripts/build-changelog.ts to ignore non-fragment files, parse fragment metadata, group generated output by change type, add lint/PR-check commands, and simplify output paths to repo-local artifacts.
|
||||||
|
3. Update CI and PR workflow files to run changelog validation on pull requests with an explicit skip path, and keep release workflow using committed changelog output.
|
||||||
|
4. Refresh changes/README.md, docs/RELEASING.md, and any PR template text so contributors know how to write fragments and when opt-out is allowed.
|
||||||
|
5. Run targeted tests and changelog commands, then record results and finalize the task.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Implemented structured changelog fragments with required `type` and `area` metadata; `changes/README.md` is now ignored by the generator and verified by regression tests.
|
||||||
|
|
||||||
|
Added `changelog:lint` and `changelog:pr-check`, plus PR CI enforcement with `skip-changelog` opt-out. PR check now reads git name-status output so deleted fragment files do not satisfy the requirement.
|
||||||
|
|
||||||
|
Changed generated changelog/release notes output to grouped sections (`Added`, `Changed`, `Fixed`, etc.) and simplified release notes to highlights + install/assets pointers.
|
||||||
|
|
||||||
|
Kept changelog output repo-local. This aligns with existing repo direction where docs updates happen in the sibling docs repo explicitly rather than implicit local writes from app-repo generators.
|
||||||
|
|
||||||
|
Verification: `bun test scripts/build-changelog.test.ts src/ci-workflow.test.ts src/release-workflow.test.ts` passed; `bun run typecheck` passed; `bun run changelog:lint` passed. `bun run test:fast` still fails in unrelated existing `src/core/services/subsync.test.ts` cases (`runSubsyncManual keeps internal alass source file alive until sync finishes`, `runSubsyncManual resolves string sid values from mpv stream properties`).
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Hardened the changelog workflow end-to-end. `scripts/build-changelog.ts` now ignores helper files like `changes/README.md`, requires structured fragment metadata (`type` + `area`), groups generated release sections by change type, and emits shorter release notes focused on highlights plus install/assets pointers. Added explicit `changelog:lint` and `changelog:pr-check` commands, with PR validation based on git name-status so deleted fragment files do not satisfy the fragment requirement.
|
||||||
|
|
||||||
|
Updated contributor-facing workflow docs in `changes/README.md`, `docs/RELEASING.md`, and a new PR template so authors know to add a fragment or apply the `skip-changelog` label. CI now runs fragment linting on every run and enforces fragment presence on pull requests. Added regression coverage in `scripts/build-changelog.test.ts` and a new `src/ci-workflow.test.ts` to lock the workflow contract.
|
||||||
|
|
||||||
|
Verification completed: `bun test scripts/build-changelog.test.ts src/ci-workflow.test.ts src/release-workflow.test.ts`, `bun run typecheck`, and `bun run changelog:lint` all passed. A broader `bun run test:fast` run still fails in unrelated existing `src/core/services/subsync.test.ts` cases outside the changelog/workflow scope.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
---
|
||||||
|
id: TASK-123
|
||||||
|
title: Add progress logging for YouTube subtitle generation phases
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- '@codex'
|
||||||
|
created_date: '2026-03-08 07:07'
|
||||||
|
updated_date: '2026-03-08 07:15'
|
||||||
|
labels:
|
||||||
|
- ux
|
||||||
|
- logging
|
||||||
|
- youtube
|
||||||
|
- subtitles
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/launcher/youtube/orchestrator.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/launcher/youtube/audio-extraction.ts
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/launcher/youtube/whisper.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/launcher/youtube/subtitle-fix-ai.ts
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Improve launcher YouTube subtitle generation observability so users can tell that work is happening and roughly how long each phase is taking. Cover manual subtitle probe, audio extraction, ffmpeg prep, whisper generation, and optional AI subtitle fix phases without flooding normal logs.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Users see clear info-level phase logs for YouTube subtitle generation work including subtitle probe, fallback audio extraction, whisper, and optional AI fix phases.
|
||||||
|
- [x] #2 Long-running phases surface elapsed-time progress or explicit start/finish timing so it is obvious the process is still active.
|
||||||
|
- [x] #3 Automated tests cover the new logging/progress helper behavior where practical.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Implemented a shared timed YouTube phase logger in launcher/youtube/progress.ts with info-level start/finish messages and warn-level failure messages that include elapsed time.
|
||||||
|
|
||||||
|
Wired phase logging into YouTube metadata probe, manual subtitle probe, fallback audio extraction, ffmpeg whisper prep, whisper primary/secondary generation, and optional AI subtitle fix phases.
|
||||||
|
|
||||||
|
Verification: bun test launcher/youtube/progress.test.ts launcher/youtube/orchestrator.test.ts passed; bun run typecheck passed.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Added clear phase-level observability for YouTube subtitle generation without noisy tool output. Users now see start/finish logs with elapsed time for subtitle probe, fallback audio extraction, ffmpeg prep, whisper generation, and optional AI subtitle-fix phases, making it obvious when generation is active and roughly how long each step took.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
---
|
||||||
|
id: TASK-124
|
||||||
|
title: >-
|
||||||
|
Remove YouTube subtitle generation modes and make YouTube playback always
|
||||||
|
generate/load subtitles
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-08 07:18'
|
||||||
|
updated_date: '2026-03-08 07:28'
|
||||||
|
labels:
|
||||||
|
- launcher
|
||||||
|
- youtube
|
||||||
|
- subtitles
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/launcher/commands/playback-command.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/launcher/config/args-normalizer.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/launcher/config/youtube-subgen-config.ts
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/launcher/types.ts
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/config.example.jsonc
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/src/config/definitions/options-integrations.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/src/config/resolve/subtitle-domains.ts
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Simplify launcher YouTube playback by removing the configurable subtitle generation mode. For YouTube targets, the launcher should treat subtitle generation/loading as the canonical behavior instead of supporting off/preprocess/automatic branches. This change should remove the unreliable automatic/background path and the mode concept from config/CLI/env/docs, while preserving the core YouTube subtitle generation pipeline and mpv loading flow.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Launcher playback no longer supports or branches on a YouTube subtitle generation mode; YouTube URLs follow a single generation-and-load flow.
|
||||||
|
- [x] #2 Configuration, CLI parsing, and environment handling no longer expose a YouTube subtitle generation mode option, and stale automatic/preprocess/off values are not part of the supported interface.
|
||||||
|
- [x] #3 Tests cover the new single-flow behavior and the removal of mode parsing/branching.
|
||||||
|
- [x] #4 User-facing config/docs/examples are updated to reflect the removed mode concept.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Remove the YouTube subtitle generation mode concept from launcher/shared types, config parsing, CLI options, and environment normalization so no supported interface accepts automatic/preprocess/off.
|
||||||
|
2. Update playback orchestration so YouTube targets always run subtitle generation/loading before mpv startup and delete the background automatic path.
|
||||||
|
3. Adjust mpv YouTube URL argument construction to no longer branch on mode while preserving subtitle/audio language behavior and preloaded subtitle file injection.
|
||||||
|
4. Add/modify tests first to cover removed mode parsing and the single YouTube preload flow, then update config/docs/examples to match the simplified interface.
|
||||||
|
5. Run focused launcher/config tests plus typecheck, then summarize any remaining gaps.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Removed launcher/shared youtubeSubgen.mode handling and collapsed YouTube playback onto a single preload-before-mpv subtitle generation flow.
|
||||||
|
|
||||||
|
Added launcher integration coverage proving YouTube subtitle generation runs before mpv startup and that the removed --mode flag now errors.
|
||||||
|
|
||||||
|
Verification: bun test launcher/config-domain-parsers.test.ts launcher/parse-args.test.ts launcher/mpv.test.ts launcher/main.test.ts src/config/config.test.ts; bun run test:config:src; bun run typecheck.
|
||||||
|
|
||||||
|
Broader repo checks still show pre-existing issues outside this change: bun run test:launcher:unit:src fails in launcher/aniskip-metadata.test.ts (MAL id assertion), and format scope check reports unrelated existing files launcher/youtube/orchestrator.ts, scripts/build-changelog.test.ts, scripts/build-changelog.ts.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Removed the launcher YouTube subtitle generation mode surface so YouTube playback now always runs the subtitle generation pipeline before starting mpv. The launcher no longer accepts youtubeSubgen.mode from shared config, CLI, or env normalization, and the old automatic/background loading path has been deleted from playback.
|
||||||
|
|
||||||
|
Updated mpv YouTube startup options to keep manual subtitle discovery enabled without requesting auto subtitles, and refreshed user-facing config/docs to describe a single YouTube subtitle generation flow. Added regression coverage for mode removal, config/template cleanup, and launcher ordering so YouTube subtitle work is confirmed to happen before mpv launch.
|
||||||
|
|
||||||
|
Verification: bun test launcher/config-domain-parsers.test.ts launcher/parse-args.test.ts launcher/mpv.test.ts launcher/main.test.ts src/config/config.test.ts; bun run test:config:src; bun run typecheck. Broader unrelated repo issues remain in launcher/aniskip-metadata.test.ts and existing formatting drift in launcher/youtube/orchestrator.ts plus scripts/build-changelog files.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
id: TASK-125
|
||||||
|
title: Add native AI API key secret storage
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-08 07:25'
|
||||||
|
labels:
|
||||||
|
- ai
|
||||||
|
- config
|
||||||
|
- security
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/src/ai/client.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/src/core/services/anilist/anilist-token-store.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/src/core/services/jellyfin-token-store.ts
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/src/main.ts
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Store the shared AI provider API key using the app's native secret-storage pattern so users do not need to keep the OpenRouter key in config files or shell commands.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [ ] #1 Users can configure the shared AI provider without storing the API key in config.jsonc.
|
||||||
|
- [ ] #2 The app persists and reloads the shared AI API key using encrypted native secret storage when available.
|
||||||
|
- [ ] #3 Behavior is defined for existing ai.apiKey and ai.apiKeyCommand configs, including compatibility during migration.
|
||||||
|
- [ ] #4 The feature has regression tests covering key resolution and storage behavior.
|
||||||
|
- [ ] #5 User-facing configuration/docs are updated to describe the supported setup.
|
||||||
|
<!-- AC:END -->
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
id: TASK-126
|
||||||
|
title: >-
|
||||||
|
Improve secondary subtitle readability with hover-only background and stronger
|
||||||
|
text separation
|
||||||
|
status: Done
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-08 07:35'
|
||||||
|
updated_date: '2026-03-08 07:40'
|
||||||
|
labels:
|
||||||
|
- overlay
|
||||||
|
- subtitles
|
||||||
|
- ui
|
||||||
|
dependencies: []
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Adjust overlay secondary subtitle styling so translation text stays readable on bright video backgrounds. Keep the dark background hidden by default in hover mode and show it only while hovered. Increase secondary subtitle weight to 600 and strengthen edge separation without changing primary subtitle styling.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Secondary subtitles render with stronger edge separation than today.
|
||||||
|
- [x] #2 Secondary subtitle font weight defaults to 600.
|
||||||
|
- [x] #3 When secondary subtitle mode is hover, the secondary background appears only while hovered.
|
||||||
|
- [x] #4 Primary subtitle styling behavior remains unchanged.
|
||||||
|
- [x] #5 Renderer tests cover the new secondary hover background behavior and default secondary style values.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Adjusted secondary subtitle defaults to use stronger shadowing, 600 font weight, and a translucent dark background. Routed secondary background/backdrop styling through CSS custom properties so hover mode can keep the background hidden until the secondary subtitle is actually hovered. Added renderer and config tests covering default values and hover-only background behavior.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Improved secondary subtitle readability by strengthening default text separation, increasing the default secondary weight to 600, and making the configured dark background appear only while hovered in secondary hover mode. Added config and renderer coverage for the new defaults and hover-aware style routing.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
---
|
||||||
|
id: TASK-127
|
||||||
|
title: Skip AniSkip lookup for YouTube and URL playback targets
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- '@codex'
|
||||||
|
created_date: '2026-03-08 08:24'
|
||||||
|
updated_date: '2026-03-08 10:12'
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
- launcher
|
||||||
|
- youtube
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/launcher/mpv.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/launcher/commands/playback-command.ts
|
||||||
|
- /Users/sudacode/projects/japanese/SubMiner/launcher/mpv.test.ts
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Prevent launcher playback from attempting AniSkip metadata resolution when the user is playing a YouTube target or any URL target. AniSkip only works for local anime files, so URL-driven playback and YouTube subtitle-generation flows should bypass it entirely.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Launcher playback skips AniSkip metadata resolution for explicit URL targets, including YouTube URLs.
|
||||||
|
- [x] #2 YouTube subtitle-generation playback does not invoke AniSkip lookup before mpv launch.
|
||||||
|
- [x] #3 Automated launcher tests cover the URL/YouTube skip behavior.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Add a launcher mpv unit test that intercepts AniSkip resolution and proves URL/YouTube playback does not call it before spawning mpv.
|
||||||
|
2. Run the focused launcher mpv test to confirm the new case fails or exposes the current gap.
|
||||||
|
3. Patch launcher playback/AniSkip gating so URL and YouTube subtitle-generation paths always bypass AniSkip lookup.
|
||||||
|
4. Re-run focused launcher tests and record the verification results in task notes.
|
||||||
|
|
||||||
|
5. Add a Lua plugin regression test covering overlay-start on URL playback so AniSkip never runs after auto-start.
|
||||||
|
|
||||||
|
6. Patch plugin/subminer/aniskip.lua to short-circuit all AniSkip lookup triggers for remote URL media paths.
|
||||||
|
|
||||||
|
7. Re-run plugin regression plus touched launcher checks and update the task summary with the plugin-side fix.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Added explicit AniSkip gating in launcher/mpv.ts via shouldResolveAniSkipMetadata(target, targetKind, preloadedSubtitles).
|
||||||
|
|
||||||
|
URL targets now always bypass AniSkip. File targets with preloaded subtitles also bypass AniSkip, covering YouTube subtitle-preload playback.
|
||||||
|
|
||||||
|
Added launcher/mpv.test.ts coverage for local-file vs URL vs preloaded-subtitle AniSkip gating.
|
||||||
|
|
||||||
|
Verification: bun test launcher/mpv.test.ts passed.
|
||||||
|
|
||||||
|
Verification: bun run typecheck passed.
|
||||||
|
|
||||||
|
Verification: bunx prettier --check launcher/mpv.ts launcher/mpv.test.ts passed.
|
||||||
|
|
||||||
|
Verification: bun run changelog:lint passed.
|
||||||
|
|
||||||
|
Verification: bun run test:launcher:unit:src remains blocked by unrelated existing failure in launcher/aniskip-metadata.test.ts (`resolveAniSkipMetadataForFile resolves MAL id and intro payload`: expected malId 1234, got null).
|
||||||
|
|
||||||
|
Added plugin regression in scripts/test-plugin-start-gate.lua for URL playback with auto-start/overlay-start; it now asserts no MAL or AniSkip curl requests occur.
|
||||||
|
|
||||||
|
Patched plugin/subminer/aniskip.lua to short-circuit AniSkip lookup for remote media paths (`scheme://...`), which covers YouTube URL playback inside the mpv plugin lifecycle.
|
||||||
|
|
||||||
|
Verification: lua scripts/test-plugin-start-gate.lua passed.
|
||||||
|
|
||||||
|
Verification: bun run test:plugin:src passed.
|
||||||
|
|
||||||
|
Verification: bun test launcher/mpv.test.ts passed after plugin-side fix.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Fixed AniSkip suppression end-to-end for URL playback. The launcher now skips AniSkip before mpv launch, and the mpv plugin now also refuses AniSkip lookups for remote URL media during file-loaded, overlay-start, or later refresh triggers. Added regression coverage in both launcher/mpv.test.ts and scripts/test-plugin-start-gate.lua, plus a changelog fragment. Wider `bun run test:launcher:unit:src` is still blocked by the unrelated existing launcher/aniskip-metadata.test.ts MAL-id failure.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
id: TASK-128
|
||||||
|
title: >-
|
||||||
|
Prevent AI subtitle fix from translating primary YouTube subtitles into the
|
||||||
|
wrong language
|
||||||
|
status: Done
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-08 09:02'
|
||||||
|
updated_date: '2026-03-08 09:17'
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
- youtube-subgen
|
||||||
|
- ai
|
||||||
|
dependencies: []
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
AI subtitle cleanup can preserve cue structure while changing subtitle language, causing primary Japanese subtitle files to come back in English. Add guards so AI-fixed subtitles preserve expected language and fall back to raw Whisper output when language drifts.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Primary AI subtitle fix rejects output that drifts away from the expected source language.
|
||||||
|
- [x] #2 Rejected AI fixes fall back to the raw Whisper subtitle without corrupting published subtitle language.
|
||||||
|
- [x] #3 Regression tests cover a primary Japanese subtitle batch being translated into English by the AI fixer.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Added a primary-language guard to AI subtitle fixing so Japanese source subtitles are rejected if the AI rewrites them into English while preserving SRT structure. The fixer now receives the expected source language from the YouTube orchestrator, and regression coverage verifies that language drift falls back to the raw Whisper subtitle path.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
id: TASK-129
|
||||||
|
title: >-
|
||||||
|
Split AI model and system prompt config between Anki and YouTube subtitle
|
||||||
|
generation
|
||||||
|
status: Done
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-08 09:40'
|
||||||
|
updated_date: '2026-03-08 09:57'
|
||||||
|
labels:
|
||||||
|
- config
|
||||||
|
- ai
|
||||||
|
- anki
|
||||||
|
- youtube-subgen
|
||||||
|
dependencies: []
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
The current top-level shared AI config forces Anki translation and YouTube subtitle fixing to share the same model and system prompt, which caused subtitle-fix requests to inherit a translation prompt and translate Japanese primary subtitles into English. Refactor config so provider credentials stay shared while model and system prompt can be configured per feature.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Anki integration can use its own AI model and system prompt independently of YouTube subtitle generation.
|
||||||
|
- [x] #2 YouTube subtitle generation can use its own AI model and system prompt independently of Anki integration.
|
||||||
|
- [x] #3 Existing shared provider credentials remain reusable without duplicating API key/base URL config.
|
||||||
|
- [x] #4 Config example, defaults, validation, and regression tests cover the new per-feature override shape.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Added per-feature AI model/systemPrompt overrides for Anki and YouTube subtitle generation while keeping shared provider transport settings reusable. Anki now accepts `ankiConnect.ai` object config with `enabled`, `model`, and `systemPrompt`; YouTube subtitle generation accepts `youtubeSubgen.ai` overrides and merges them over the shared AI provider config. Updated config resolution, launcher parsing, runtime wiring, hot-reload handling, example config, and regression coverage.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
---
|
||||||
|
id: TASK-130
|
||||||
|
title: Keep background SubMiner alive after launcher-managed mpv exits
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-08 10:08'
|
||||||
|
updated_date: '2026-03-08 11:00'
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
- launcher
|
||||||
|
- mpv
|
||||||
|
- overlay
|
||||||
|
dependencies: []
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
The launcher currently tears down the running SubMiner background process when a launcher-managed mpv session exits. Background SubMiner should remain alive so a later mpv instance can reconnect and request the overlay without restarting the app.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Closing a launcher-managed mpv session does not send `--stop` to the running SubMiner background process.
|
||||||
|
- [x] #2 Closing a launcher-managed mpv session does not SIGTERM the tracked SubMiner process just because mpv exited.
|
||||||
|
- [x] #3 Launcher cleanup still terminates mpv and launcher-owned helper children without regressing existing overlay start behavior.
|
||||||
|
- [x] #4 Automated tests cover the no-stop-on-mpv-exit behavior.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Add a launcher regression test that proves mpv exit no longer triggers SubMiner `--stop` or launcher SIGTERM of the tracked overlay process.
|
||||||
|
2. Update launcher teardown so normal mpv-session cleanup only stops mpv/helper children and preserves the background SubMiner process for future reconnects.
|
||||||
|
3. Run the focused launcher tests and smoke coverage for the affected behavior, then record results in the task.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Split launcher cleanup so normal mpv-session shutdown no longer sends `--stop` to SubMiner or SIGTERM to the tracked overlay process. Added `cleanupPlaybackSession()` for mpv/helper-child cleanup only, and switched playback finalization to use it.
|
||||||
|
|
||||||
|
Updated launcher smoke coverage to assert the background app stays alive after mpv exits, and added a focused unit regression for the new cleanup path.
|
||||||
|
|
||||||
|
Validation: `bun test launcher/mpv.test.ts launcher/smoke.e2e.test.ts` passed; `bun run typecheck` passed. `bun run test:launcher:unit:src` still reports an unrelated pre-existing failure in `launcher/aniskip-metadata.test.ts`.
|
||||||
|
|
||||||
|
Added changelog fragment `changes/task-130.md` for the launcher fix and verified it with `bun run changelog:lint`.
|
||||||
|
|
||||||
|
User verified the bug still reproduces when closing playback with `q`. Root cause narrowed further: the mpv plugin `plugin/subminer/lifecycle.lua` calls `process.stop_overlay()` on mpv `shutdown`, which still sends SubMiner `--stop` even after launcher cleanup was fixed.
|
||||||
|
|
||||||
|
Patched the remaining stop path in `plugin/subminer/lifecycle.lua`: mpv `shutdown` no longer calls `process.stop_overlay()`. Pressing mpv `q` should now preserve the background app and only tear down the mpv session.
|
||||||
|
|
||||||
|
Validation update: `lua scripts/test-plugin-start-gate.lua` passed after adding a shutdown regression, and `bun test launcher/mpv.test.ts launcher/smoke.e2e.test.ts` still passed.
|
||||||
|
|
||||||
|
Fixed a second-instance reconnect bug in `src/core/services/cli-command.ts`: `--start` on an already-initialized running instance now still updates the MPV socket path and reconnects the MPV client instead of treating the command as a no-op. This keeps the already-warmed background app reusable for later mpv launches.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Kept the background SubMiner process reusable across both mpv shutdown and later reconnects. The first fix separated launcher playback cleanup from full app shutdown. The second fix removed the mpv plugin `shutdown` stop call so default mpv `q` no longer sends SubMiner `--stop`. The third fix corrected second-instance CLI handling so `--start` on an already-running, already-initialized instance still reconnects MPV instead of being ignored.
|
||||||
|
|
||||||
|
Net effect: background SubMiner can stay alive, keep its warm state, and reconnect to later mpv instances without rerunning startup/warmup work in a fresh app instance.
|
||||||
|
|
||||||
|
Coverage now includes: launcher playback cleanup (`launcher/mpv.test.ts`), launcher smoke reconnect/keep-alive flow (`launcher/smoke.e2e.test.ts`), mpv plugin shutdown preservation (`scripts/test-plugin-start-gate.lua`), and second-instance start/reconnect behavior (`src/core/services/cli-command.test.ts`).
|
||||||
|
|
||||||
|
Tests run:
|
||||||
|
|
||||||
|
- `bun test src/core/services/cli-command.test.ts launcher/mpv.test.ts launcher/smoke.e2e.test.ts`
|
||||||
|
- `lua scripts/test-plugin-start-gate.lua`
|
||||||
|
- `bun run typecheck`
|
||||||
|
- `bun run changelog:lint`
|
||||||
|
|
||||||
|
Note: the broader `bun run test:launcher:unit:src` lane still has an unrelated pre-existing failure in `launcher/aniskip-metadata.test.ts`.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
---
|
||||||
|
id: TASK-131
|
||||||
|
title: Avoid duplicate tokenization warmup after background startup
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-08 10:12'
|
||||||
|
updated_date: '2026-03-08 12:00'
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/src/main/runtime/composers/mpv-runtime-composer.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/src/main/runtime/startup-warmups.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/src/main/runtime/composers/mpv-runtime-composer.test.ts
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
When SubMiner is already running in the background and mpv is launched from the launcher or mpv plugin, the live app should reuse startup tokenization warmup state instead of re-entering the Yomitan/tokenization/annotation warmup path on first overlay use.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Background startup tokenization warmup is recorded in the runtime state used by later mpv/tokenization flows.
|
||||||
|
- [x] #2 Launching mpv from the launcher or plugin against an already-running background app does not re-run duplicate Yomitan/tokenization annotation warmup work in the live process.
|
||||||
|
- [x] #3 Regression tests cover the warmed-background path and protect against re-entering duplicate warmup work.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Add a regression test covering the case where background startup warmups already completed and a later tokenize call must not re-enter Yomitan/MeCab/dictionary warmups.
|
||||||
|
2. Update mpv tokenization warmup composition so startup background warmups and on-demand tokenization share the same completion state.
|
||||||
|
3. Run the focused composer/runtime tests and update acceptance criteria/notes with results.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Root-cause hypothesis: startup background warmups and on-demand tokenization warmups use separate state, so later mpv launch can re-enter warmup bookkeeping even though background startup already warmed dependencies.
|
||||||
|
|
||||||
|
Implemented shared warmup state between startup background warmups and on-demand tokenization warmups by forwarding scheduled Yomitan/tokenization promises into the mpv runtime composer. Added regression coverage for the warmed-background path. Verified with `bun run test:fast` plus focused composer/startup warmup tests.
|
||||||
|
|
||||||
|
Follow-up root cause from live retest: second mpv open could still pause on the startup gate because the runtime only treated full background tokenization warmup completion as reusable readiness. In practice, first-file tokenization could already be ready while slower dictionary prewarm work was still finishing, so reopening a video waited on duplicate warmup completion even though annotations were already usable.
|
||||||
|
|
||||||
|
Adjusted `src/main/runtime/composers/mpv-runtime-composer.ts` so autoplay reuse keys off a separate playback-ready latch. The latch flips true either when background warmups fully cover tokenization or when `onTokenizationReady` fires for a real subtitle line. `src/main.ts` already uses `isTokenizationWarmupReady()` to fast-signal `subminer-autoplay-ready` on a fresh media-path change, so reopened videos can now resume immediately once tokenization has succeeded once in the persistent app.
|
||||||
|
|
||||||
|
Validation update: `bun test src/core/services/cli-command.test.ts src/main/runtime/mpv-main-event-actions.test.ts src/main/runtime/composers/mpv-runtime-composer.test.ts launcher/mpv.test.ts launcher/smoke.e2e.test.ts` passed, `lua scripts/test-plugin-start-gate.lua` passed, and `bun run typecheck` passed.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Background startup tokenization warmups now feed the same in-memory warmup state used by later mpv tokenization. When the app is already running and warmed in the background, launcher/plugin-driven mpv startup reuses that state instead of re-entering Yomitan/tokenization annotation warmups. Added a regression test for the warmed-background path and verified with `bun run test:fast`.
|
||||||
|
|
||||||
|
A later follow-up fixed the remaining second-open delay: autoplay reuse no longer waits for the entire background dictionary warmup pipeline to finish. After the persistent app has produced one tokenization-ready event, later mpv reconnects reuse that readiness immediately, so reopening the same or another video does not pause again on duplicate warmup bookkeeping.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
---
|
||||||
|
id: TASK-131
|
||||||
|
title: Make default overlay fullscreen and AniSkip end-jump keybindings easier to reach
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-09 00:00'
|
||||||
|
updated_date: '2026-03-09 00:30'
|
||||||
|
labels:
|
||||||
|
- enhancement
|
||||||
|
- overlay
|
||||||
|
- mpv
|
||||||
|
- aniskip
|
||||||
|
dependencies: []
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Make two default keyboard actions easier to hit during playback: add `f` as the built-in overlay fullscreen toggle, and make AniSkip's default intro-end jump use `Tab`.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Default overlay keybindings include `KeyF` mapped to mpv fullscreen toggle.
|
||||||
|
- [x] #2 Default AniSkip hint/button key defaults to `Tab` and the plugin registers that binding.
|
||||||
|
- [x] #3 Automated regression coverage exists for both default bindings.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Add a failing TypeScript regression proving default overlay keybindings include fullscreen on `KeyF`.
|
||||||
|
2. Add a failing Lua/plugin regression proving AniSkip defaults to `Tab`, updates the OSD hint text, and registers the expected keybinding.
|
||||||
|
3. Patch the default keybinding/config values with minimal behavior changes and keep fallback binding behavior intentional.
|
||||||
|
4. Run focused tests plus touched verification commands, then record results and a short changelog fragment.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Added `KeyF -> ['cycle', 'fullscreen']` to the built-in overlay keybindings in `src/config/definitions/shared.ts`.
|
||||||
|
|
||||||
|
Changed the mpv plugin AniSkip default button key from `y-k` to `TAB` in both the runtime default options and the shipped `plugin/subminer.conf`. The AniSkip OSD hint now also falls back to `TAB` when no explicit key is configured.
|
||||||
|
|
||||||
|
Adjusted `plugin/subminer/ui.lua` fallback registration so the legacy `y-k` binding is only added for custom non-default AniSkip bindings, instead of always shadowing the new default.
|
||||||
|
|
||||||
|
Extended regression coverage:
|
||||||
|
|
||||||
|
- `src/config/definitions/domain-registry.test.ts` now asserts the default fullscreen binding on `KeyF`.
|
||||||
|
- `scripts/test-plugin-start-gate.lua` now isolates plugin runs correctly, records keybinding/observer registration, and asserts the default AniSkip keybinding/prompt behavior for `TAB`.
|
||||||
|
|
||||||
|
Verification:
|
||||||
|
|
||||||
|
- `bun test src/config/definitions/domain-registry.test.ts`
|
||||||
|
- `bun run test:config:src`
|
||||||
|
- `lua scripts/test-plugin-start-gate.lua`
|
||||||
|
- `bun run changelog:lint`
|
||||||
|
- `bun run typecheck`
|
||||||
|
|
||||||
|
Known unrelated verification gap:
|
||||||
|
|
||||||
|
- `bun run test:plugin:src` still fails in `scripts/test-plugin-binary-windows.lua` on this Linux host (`windows env override should resolve .exe suffix`), outside the keybinding changes in this task.
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Default overlay playback now has an easier fullscreen toggle on `f`, and AniSkip's default intro-end jump now uses `Tab`. The mpv plugin hint text and registration logic were updated to match the new default, while keeping legacy `y-k` fallback behavior limited to custom non-default bindings.
|
||||||
|
|
||||||
|
Regression coverage was added for both defaults, and the plugin test harness now resets plugin bootstrap state between scenarios so keybinding assertions can run reliably.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
---
|
||||||
|
id: TASK-132
|
||||||
|
title: Gate macOS overlay shortcuts to the focused mpv window
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-08 18:24'
|
||||||
|
updated_date: '2026-03-08 18:55'
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
- macos
|
||||||
|
- shortcuts
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/src/core/services/overlay-shortcut.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/src/window-trackers/macos-tracker.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/scripts/get-mpv-window-macos.swift
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Fix the macOS shortcut handling so SubMiner overlay keybinds do not intercept system or other-app shortcuts while SubMiner is in the background. Overlay shortcuts should only be active while the tracked mpv window is present and focused, and should stop grabbing keyboard input when mpv is not the frontmost window.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 On macOS, overlay shortcuts do not trigger while mpv is not the focused/frontmost window.
|
||||||
|
- [x] #2 On macOS, overlay shortcuts remain available while the tracked mpv window is open and focused.
|
||||||
|
- [x] #3 Existing non-macOS shortcut behavior is unchanged.
|
||||||
|
- [x] #4 Automated tests cover the macOS focus-gating behavior and guard against background shortcut interception.
|
||||||
|
- [x] #5 Any user-facing docs/config notes affected by the behavior change are updated in the same task if needed.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Add a failing macOS-focused shortcut lifecycle test that proves overlay shortcuts stay inactive when the tracked mpv window exists but is not frontmost, and activate when that tracked window becomes frontmost.
|
||||||
|
2. Add a failing tracker/helper test that covers the focused/frontmost signal parsed from the macOS helper output.
|
||||||
|
3. Extend the macOS helper/tracker contract to surface both geometry and focused/frontmost state for the tracked mpv window.
|
||||||
|
4. Wire overlay shortcut activation to require both overlay runtime initialization and tracked-mpv focus on macOS, while leaving non-macOS behavior unchanged.
|
||||||
|
5. Re-run the targeted shortcut/tracker tests, then the broader related shortcut/runtime suite, and update task notes/acceptance criteria based on results.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Added a macOS-specific shortcut activation predicate so global overlay shortcuts now require both overlay runtime readiness and a focused tracked mpv window; non-macOS behavior still keys off runtime readiness only.
|
||||||
|
|
||||||
|
Extended the base window tracker with optional focus-state callbacks/getters and wired initializeOverlayRuntime to re-sync overlay shortcuts whenever tracker focus changes.
|
||||||
|
|
||||||
|
Updated the macOS helper/tracker contract to return geometry plus frontmost/focused state for the tracked mpv process and added parser coverage for focused and unfocused output.
|
||||||
|
|
||||||
|
Verified with `bun x tsc -p tsconfig.json --noEmit`, targeted shortcut/tracker tests, and `bun run test:core:src` (439 passing).
|
||||||
|
|
||||||
|
No user-facing config or documentation surface changed, so no docs update was required for this fix.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Fixed the macOS background shortcut interception bug by gating SubMiner's global overlay shortcuts on tracked mpv focus instead of overlay-runtime initialization alone. The macOS window helper now reports whether the tracked mpv process is frontmost, the tracker exposes focus change callbacks, and overlay shortcut synchronization re-runs when that focus state flips so `Ctrl+C`/`Ctrl+V` and similar shortcuts are no longer captured while mpv is in the background.
|
||||||
|
|
||||||
|
The change keeps existing non-macOS shortcut behavior unchanged. Added regression coverage for the activation decision, tracker focus-change re-sync, and macOS helper output parsing. Verification: `bun x tsc -p tsconfig.json --noEmit`, targeted shortcut/tracker tests, and `bun run test:core:src` (439 passing).
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
---
|
||||||
|
id: TASK-133
|
||||||
|
title: Improve AniList character dictionary parity with upstream guide
|
||||||
|
status: In Progress
|
||||||
|
assignee:
|
||||||
|
- OpenCode
|
||||||
|
created_date: '2026-03-08 21:06'
|
||||||
|
updated_date: '2026-03-10 06:18'
|
||||||
|
labels:
|
||||||
|
- dictionary
|
||||||
|
- anilist
|
||||||
|
- planning
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- >-
|
||||||
|
https://github.com/bee-san/Japanese_Character_Name_Dictionary/blob/main/docs/agents_read_me.md
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/src/main/character-dictionary-runtime.ts
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/src/main/character-dictionary-runtime.test.ts
|
||||||
|
documentation:
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/docs/plans/2026-03-08-anilist-character-dictionary-parity-design.md
|
||||||
|
- >-
|
||||||
|
/Users/sudacode/projects/japanese/SubMiner/docs/plans/2026-03-08-anilist-character-dictionary-parity.md
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Plan and implement guide-faithful parity improvements for the AniList character dictionary flow inside SubMiner's current single-media generation path. Scope includes AniList first/last name hints, hint-aware reading generation for kanji/native names, expanded honorific coverage, 160x200 JPEG thumbnail handling, and AniList 429 retry/backoff behavior.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 AniList character queries include first/last name fields and preserve them through runtime data models.
|
||||||
|
- [ ] #2 Dictionary generation uses hint-aware name splitting and reading generation for kanji and mixed native names, not only kana-only readings.
|
||||||
|
- [ ] #3 Honorific generation is expanded substantially toward upstream coverage and is covered by regression tests.
|
||||||
|
- [ ] #4 Character and voice-actor images are resized or re-encoded to bounded JPEG thumbnails with fallback behavior.
|
||||||
|
- [ ] #5 AniList requests handle 429 responses with bounded exponential backoff and tests cover retry behavior.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
1. Add targeted regression tests in `src/main/character-dictionary-runtime.test.ts` for AniList 429 retry behavior and thumbnail conversion/fallback image paths before changing runtime code.
|
||||||
|
2. Update `fetchAniList` in `src/main/character-dictionary-runtime.ts` to retry 429 responses with bounded exponential backoff or `Retry-After` delays, while preserving existing request pacing hook behavior.
|
||||||
|
3. Update `downloadCharacterImage` to run downloaded bytes through `convertImageToThumbnail`, returning `.jpg` paths when conversion succeeds and preserving original bytes/extensions on fallback.
|
||||||
|
4. Run focused character-dictionary tests first, then broader required verification commands if the focused lane passes.
|
||||||
|
5. Record progress against acceptance criteria #4 and #5 in TASK-133 notes/final checklist once verified.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
Approved design and implementation plan captured on 2026-03-08. Scope stays within current single-media AniList dictionary flow; excludes username-driven CURRENT-list fetching and Yomitan auto-update schema work.
|
||||||
|
|
||||||
|
Resumed TASK-133 to finish remaining AC #4 image thumbnail wiring and AC #5 AniList 429 retry handling. Existing code already contains helper constants/functions; next work is wiring plus regression coverage.
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
id: TASK-134
|
||||||
|
title: Harden Windows release signing against transient SignPath failures
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-09 00:00'
|
||||||
|
updated_date: '2026-03-08 20:23'
|
||||||
|
labels:
|
||||||
|
- ci
|
||||||
|
- release
|
||||||
|
- windows
|
||||||
|
- signing
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- .github/workflows/release.yml
|
||||||
|
- package.json
|
||||||
|
- src/release-workflow.test.ts
|
||||||
|
- https://github.com/ksyasuda/SubMiner/actions/runs/22836585479
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
The tag-driven Release workflow currently fails the Windows lane if the SignPath connector returns transient 502 errors during submission, and the tagged build scripts also allow electron-builder to implicitly publish unsigned artifacts before the final release job runs. Harden the workflow so transient SignPath outages get bounded retries and release packaging never auto-publishes unsigned assets.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [ ] #1 Windows release signing retries transient SignPath submission failures within the release workflow before failing the job.
|
||||||
|
- [ ] #2 Release packaging scripts disable electron-builder implicit publish so build jobs do not upload unsigned assets on tag builds.
|
||||||
|
- [ ] #3 Regression coverage fails if SignPath retry scaffolding or publish suppression is removed.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Add a regression test for the release workflow/package script shape covering SignPath retries and `--publish never`.
|
||||||
|
2. Patch the Windows release job to retry SignPath submission a bounded number of times and still fail hard if every attempt fails.
|
||||||
|
3. Update tagged package build scripts to disable implicit electron-builder publishing during release builds.
|
||||||
|
4. Run targeted release-workflow verification and capture any remaining manual release cleanup needed for `v0.5.0`.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
The failed Windows signing step in GitHub Actions run `22836585479` was not caused by missing secrets or an artifact-shape mismatch. The SignPath GitHub action retried repeated `502` responses from the SignPath connector for several minutes and then failed the job.
|
||||||
|
|
||||||
|
Hardened `.github/workflows/release.yml` by replacing the single SignPath submission with three bounded attempts. The second and third submissions only run if the previous attempt failed, and the job now fails with an explicit rerun message only after all three attempts fail. Signed-artifact upload is keyed to the successful attempt so the release job still consumes the normal `windows` artifact name.
|
||||||
|
|
||||||
|
Also fixed a separate release regression exposed by the same run: `electron-builder` was implicitly publishing unsigned release assets during tag builds because the packaging scripts did not set `--publish never` and the workflow injected `GH_TOKEN` into build jobs. Updated the relevant package scripts to pass `--publish never`, removed `GH_TOKEN` from the packaging jobs, and made the final publish step force `--draft=false` when editing an existing tag release so previously-created draft releases get published.
|
||||||
|
|
||||||
|
Verification: `bun test src/release-workflow.test.ts`, `bun run typecheck`, and `bun run test:fast` all passed locally after restoring the missing local `libsql` install with `bun install --frozen-lockfile`.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Windows release signing is now resilient to transient SignPath connector outages. The release workflow retries the SignPath submission up to three times before failing, and only uploads the signed Windows artifact from the attempt that succeeded.
|
||||||
|
|
||||||
|
Release packaging also no longer auto-publishes unsigned assets on tag builds. The `electron-builder` scripts now force `--publish never`, the build jobs no longer pass `GH_TOKEN` into packaging steps, and the final GitHub release publish step explicitly clears draft state when updating an existing tag release.
|
||||||
|
|
||||||
|
Validation: `bun test src/release-workflow.test.ts`, `bun run typecheck`, `bun run test:fast`.
|
||||||
|
Manual follow-up for the failed `v0.5.0` release: rerun the `Release` workflow after merging/pushing this fix, then clean up the stray draft/untagged release assets created by the failed run if they remain.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
id: TASK-135
|
||||||
|
title: Cut patch release v0.5.1 for Windows signing fix
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-08 20:24'
|
||||||
|
updated_date: '2026-03-08 20:28'
|
||||||
|
labels:
|
||||||
|
- release
|
||||||
|
- patch
|
||||||
|
dependencies:
|
||||||
|
- TASK-134
|
||||||
|
references:
|
||||||
|
- package.json
|
||||||
|
- CHANGELOG.md
|
||||||
|
- release/release-notes.md
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Publish a patch release from the workflow-signing fix on `main` by bumping the app version, generating the committed changelog artifacts for the new version, and pushing a new `v0.5.1` tag instead of rewriting the failed `v0.5.0` tag.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [ ] #1 Repository version metadata is updated to `0.5.1`.
|
||||||
|
- [ ] #2 `CHANGELOG.md` and `release/release-notes.md` contain the committed `v0.5.1` section and released fragments are removed.
|
||||||
|
- [ ] #3 New `v0.5.1` commit and tag are pushed to `origin`.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Bump the package version to `0.5.1`.
|
||||||
|
2. Run the changelog builder so `CHANGELOG.md`/`release-notes.md` match the release workflow contract.
|
||||||
|
3. Run the relevant verification commands.
|
||||||
|
4. Commit the release-prep changes, create `v0.5.1`, and push both commit and tag.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Bumped `package.json` from `0.5.0` to `0.5.1`, then ran `bun run changelog:build` so the committed release artifacts match the release workflow contract. That prepended the `v0.5.1` section to `CHANGELOG.md`, regenerated `release/release-notes.md`, and removed the consumed changelog fragments from `changes/`.
|
||||||
|
|
||||||
|
Verification before tagging: `bun run changelog:lint`, `bun run changelog:check --version 0.5.1`, `bun run typecheck`, and `bun run test:fast`.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Prepared patch release `v0.5.1` from the signing-workflow fix on `main` instead of rewriting the failed `v0.5.0` tag. Repository version metadata, changelog, and committed release notes are all aligned with the new release tag, and the consumed changelog fragments were removed.
|
||||||
|
|
||||||
|
Validation: `bun run changelog:lint`, `bun run changelog:check --version 0.5.1`, `bun run typecheck`, `bun run test:fast`.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
---
|
||||||
|
id: TASK-136
|
||||||
|
title: Pin SignPath artifact configuration in release workflow
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-08 20:41'
|
||||||
|
updated_date: '2026-03-08 20:58'
|
||||||
|
labels:
|
||||||
|
- ci
|
||||||
|
- release
|
||||||
|
- windows
|
||||||
|
- signing
|
||||||
|
dependencies:
|
||||||
|
- TASK-134
|
||||||
|
references:
|
||||||
|
- .github/workflows/release.yml
|
||||||
|
- build/signpath-windows-artifact-config.xml
|
||||||
|
- src/release-workflow.test.ts
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
The Windows release workflow currently relies on the default SignPath artifact configuration configured in the SignPath UI. Pin the workflow to an explicit artifact-configuration slug so the checked-in signing configuration and CI behavior stay deterministic across future SignPath project changes.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [ ] #1 The Windows release workflow validates a dedicated SignPath artifact-configuration secret/input.
|
||||||
|
- [ ] #2 Every SignPath submission attempt passes `artifact-configuration-slug`.
|
||||||
|
- [ ] #3 Regression coverage fails if the explicit SignPath artifact-configuration binding is removed.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Add a failing workflow regression test for the explicit SignPath artifact-configuration slug.
|
||||||
|
2. Patch the Windows signing secret validation and SignPath action inputs to require the slug.
|
||||||
|
3. Run targeted release-workflow verification plus the standard fast lane.
|
||||||
|
4. Cut a new patch release so the tag-triggered release workflow runs with the pinned SignPath configuration.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Added regression coverage in `src/release-workflow.test.ts` for an explicit SignPath artifact-configuration slug so the release workflow test now fails if the slug validation or action input is removed.
|
||||||
|
|
||||||
|
Patched `.github/workflows/release.yml` so Windows signing now requires `SIGNPATH_ARTIFACT_CONFIGURATION_SLUG` during secret validation and passes `artifact-configuration-slug: ${{ secrets.SIGNPATH_ARTIFACT_CONFIGURATION_SLUG }}` on every SignPath submission attempt.
|
||||||
|
|
||||||
|
Verification: `bun test src/release-workflow.test.ts`, `bun run typecheck`, `bun run test:fast`.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
The release workflow is now pinned to an explicit SignPath artifact configuration instead of relying on whichever SignPath artifact config is marked default in the UI. Windows signing secret validation fails fast if `SIGNPATH_ARTIFACT_CONFIGURATION_SLUG` is missing, and every SignPath submission attempt now includes the pinned slug.
|
||||||
|
|
||||||
|
Validation: `bun test src/release-workflow.test.ts`, `bun run typecheck`, `bun run test:fast`.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
id: TASK-137
|
||||||
|
title: Cut patch release v0.5.2 for SignPath artifact config pinning
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-08 20:44'
|
||||||
|
updated_date: '2026-03-08 20:58'
|
||||||
|
labels:
|
||||||
|
- release
|
||||||
|
- patch
|
||||||
|
dependencies:
|
||||||
|
- TASK-136
|
||||||
|
references:
|
||||||
|
- package.json
|
||||||
|
- CHANGELOG.md
|
||||||
|
- release/release-notes.md
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Publish a patch release from the SignPath artifact-configuration pinning change by bumping the app version, generating the committed changelog artifacts for the new version, and pushing a new `v0.5.2` tag.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [ ] #1 Repository version metadata is updated to `0.5.2`.
|
||||||
|
- [ ] #2 `CHANGELOG.md` and `release/release-notes.md` contain the committed `v0.5.2` section and consumed fragments are removed.
|
||||||
|
- [ ] #3 New `v0.5.2` commit and tag are pushed to `origin`.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Add the release fragment for the SignPath configuration pinning change.
|
||||||
|
2. Bump `package.json` to `0.5.2` and run the changelog builder.
|
||||||
|
3. Run changelog/typecheck/test verification.
|
||||||
|
4. Commit the release-prep change set, create `v0.5.2`, and push commit plus tag.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Bumped `package.json` from `0.5.1` to `0.5.2`, ran `bun run changelog:build`, and committed the generated release artifacts. That prepended the `v0.5.2` section to `CHANGELOG.md`, regenerated `release/release-notes.md`, and removed the consumed `changes/signpath-artifact-config-pin.md` fragment.
|
||||||
|
|
||||||
|
Verification before tagging: `bun run changelog:lint`, `bun run changelog:check --version 0.5.2`, `bun run typecheck`, and `bun run test:fast`.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Prepared patch release `v0.5.2` so the explicit SignPath artifact-configuration pin ships on a fresh release tag. Version metadata, committed changelog artifacts, and release notes are aligned with the new patch version.
|
||||||
|
|
||||||
|
Validation: `bun run changelog:lint`, `bun run changelog:check --version 0.5.2`, `bun run typecheck`, `bun run test:fast`.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
---
|
||||||
|
id: TASK-138
|
||||||
|
title: Publish unsigned Windows release artifacts and add local unsigned build script
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-09 00:00'
|
||||||
|
updated_date: '2026-03-09 00:00'
|
||||||
|
labels:
|
||||||
|
- release
|
||||||
|
- windows
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- .github/workflows/release.yml
|
||||||
|
- package.json
|
||||||
|
- src/release-workflow.test.ts
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Stop the tag-driven release workflow from depending on SignPath and publish unsigned Windows `.exe` and `.zip` artifacts directly. Add an explicit local `build:win:unsigned` script without changing the existing `build:win` command.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Windows release CI builds unsigned artifacts without requiring SignPath secrets.
|
||||||
|
- [x] #2 The Windows release job uploads `release/*.exe` and `release/*.zip` directly as the `windows` artifact.
|
||||||
|
- [x] #3 The repo exposes a local `build:win:unsigned` script for explicit unsigned Windows packaging.
|
||||||
|
- [x] #4 Regression coverage fails if the workflow reintroduces SignPath submission or drops the unsigned script.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Update workflow regression tests to assert unsigned Windows release behavior and the new local script.
|
||||||
|
2. Patch `package.json` to add `build:win:unsigned`.
|
||||||
|
3. Patch `.github/workflows/release.yml` to build unsigned Windows artifacts and upload them directly.
|
||||||
|
4. Add the release changelog fragment and run focused verification.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Removed the Windows SignPath secret validation and submission steps from `.github/workflows/release.yml`. The Windows release job now runs `bun run build:win:unsigned` and uploads `release/*.exe` and `release/*.zip` directly as the `windows` artifact consumed by the release job.
|
||||||
|
|
||||||
|
Added `scripts/build-win-unsigned.mjs` plus the `build:win:unsigned` package script. The wrapper clears Windows code-signing environment variables and disables identity auto-discovery before invoking `electron-builder`, so release CI stays unsigned even if signing credentials are configured elsewhere.
|
||||||
|
|
||||||
|
Updated `src/release-workflow.test.ts` to assert the unsigned workflow contract and added the release changelog fragment in `changes/unsigned-windows-release-builds.md`.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Windows release CI now publishes unsigned artifacts directly and no longer depends on SignPath. Local developers also have an explicit `bun run build:win:unsigned` path for unsigned packaging without changing the existing `build:win` command.
|
||||||
|
|
||||||
|
Verification:
|
||||||
|
|
||||||
|
- `bun test src/release-workflow.test.ts`
|
||||||
|
- `bun run typecheck`
|
||||||
|
- `node --check scripts/build-win-unsigned.mjs`
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
id: TASK-139
|
||||||
|
title: Cut patch release v0.5.3 for unsigned Windows release builds
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-09 00:00'
|
||||||
|
updated_date: '2026-03-09 00:00'
|
||||||
|
labels:
|
||||||
|
- release
|
||||||
|
- patch
|
||||||
|
dependencies:
|
||||||
|
- TASK-138
|
||||||
|
references:
|
||||||
|
- package.json
|
||||||
|
- CHANGELOG.md
|
||||||
|
- release/release-notes.md
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Publish a patch release from the unsigned Windows release-build change by bumping the app version, generating committed changelog artifacts for `v0.5.3`, and pushing the release-prep commit.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Repository version metadata is updated to `0.5.3`.
|
||||||
|
- [x] #2 `CHANGELOG.md` and `release/release-notes.md` contain the committed `v0.5.3` section and consumed fragments are removed.
|
||||||
|
- [x] #3 New `v0.5.3` release-prep commit is pushed to `origin/main`.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Bump `package.json` from `0.5.2` to `0.5.3`.
|
||||||
|
2. Run `bun run changelog:build` so committed changelog artifacts match the new patch version.
|
||||||
|
3. Run changelog/typecheck/test verification.
|
||||||
|
4. Commit the release-prep change set and push `main`.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Bumped `package.json` from `0.5.2` to `0.5.3`, ran `bun run changelog:build`, and committed the generated release artifacts. That prepended the `v0.5.3` section to `CHANGELOG.md`, regenerated `release/release-notes.md`, and removed the consumed `changes/unsigned-windows-release-builds.md` fragment.
|
||||||
|
|
||||||
|
Verification before push: `bun run changelog:lint`, `bun run changelog:check --version 0.5.3`, `bun run typecheck`, and `bun run test:fast`.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Prepared patch release `v0.5.3` so the unsigned Windows release-build change is captured in committed release metadata on `main`. Version metadata, changelog output, and release notes are aligned with the new patch version.
|
||||||
|
|
||||||
|
Validation: `bun run changelog:lint`, `bun run changelog:check --version 0.5.3`, `bun run typecheck`, `bun run test:fast`.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
id: TASK-140
|
||||||
|
title: Fix guessit title parsing for character dictionary sync
|
||||||
|
status: Done
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-09 00:00'
|
||||||
|
updated_date: '2026-03-09 00:25'
|
||||||
|
labels:
|
||||||
|
- dictionary
|
||||||
|
- anilist
|
||||||
|
- bug
|
||||||
|
- guessit
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/core/services/anilist/anilist-updater.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/core/services/anilist/anilist-updater.test.ts
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Fix AniList character dictionary auto-sync for filenames where `guessit` misparses the full path and our title extraction keeps only the first array segment, causing AniList resolution to match the wrong anime and abort merged dictionary refresh.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 AniList media guessing passes basename-only targets to `guessit` so parent folder names do not corrupt series title detection.
|
||||||
|
- [x] #2 Guessit title arrays are combined into one usable title instead of truncating to the first segment.
|
||||||
|
- [x] #3 Regression coverage includes the Bunny Girl Senpai filename shape that previously resolved to the wrong AniList entry.
|
||||||
|
- [x] #4 Verification confirms the targeted AniList guessing tests pass.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Root repro: `guessit` parsed the Bunny Girl Senpai full path as `title: ["Rascal", "Does-not-Dream-of-Bunny-Girl-Senapi"]`, and our `firstString` helper kept only `Rascal`, which resolved to AniList 3490 (`rayca`) and produced zero character results. Fixed by sending basename-only input to `guessit` and joining multi-part guessit title arrays.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
---
|
||||||
|
id: TASK-141
|
||||||
|
title: Refresh current subtitle after character dictionary sync completes
|
||||||
|
status: Done
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-09 00:00'
|
||||||
|
updated_date: '2026-03-09 00:55'
|
||||||
|
labels:
|
||||||
|
- dictionary
|
||||||
|
- overlay
|
||||||
|
- bug
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main/runtime/character-dictionary-auto-sync.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main.ts
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
When character dictionary auto-sync finishes after startup tokenization, invalidate cached subtitle tokenization and refresh the current subtitle so character-name highlighting catches up without waiting for the next subtitle line.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Successful character dictionary sync exposes a completion hook for main runtime follow-up.
|
||||||
|
- [x] #2 Main runtime clears Yomitan parser caches and refreshes the current subtitle after sync completion.
|
||||||
|
- [x] #3 Regression coverage verifies the sync completion callback fires on successful sync.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Observed on Bunny Girl Senpai startup: autoplay/tokenization became ready around 8s, but snapshot/import/state write completed roughly 31s after launch, leaving the current subtitle tokenized without the newly imported character dictionary. Fixed by adding an auto-sync completion hook that clears parser caches and refreshes the current subtitle.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
id: TASK-142
|
||||||
|
title: Show character dictionary auto-sync progress on OSD
|
||||||
|
status: Done
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-09 01:10'
|
||||||
|
updated_date: '2026-03-09 01:10'
|
||||||
|
labels:
|
||||||
|
- dictionary
|
||||||
|
- overlay
|
||||||
|
- ux
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main/runtime/character-dictionary-auto-sync.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main/runtime/character-dictionary-auto-sync-notifications.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main.ts
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
When character dictionary auto-sync runs for a newly opened anime, surface progress so users know why character-name lookup/highlighting is temporarily unavailable via the mpv OSD without desktop notification popups.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Character dictionary auto-sync emits progress events for syncing, importing, ready, and failure states.
|
||||||
|
- [x] #2 Main runtime routes those progress events through OSD notifications without desktop notifications.
|
||||||
|
- [x] #3 Regression coverage verifies progress events and notification routing behavior.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
OSD now shows auto-sync phase changes while the dictionary updates. Desktop notifications were removed for this path to avoid startup popup spam.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
id: TASK-143
|
||||||
|
title: Keep character dictionary auto-sync non-blocking during startup
|
||||||
|
status: Done
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-09 01:45'
|
||||||
|
updated_date: '2026-03-09 01:45'
|
||||||
|
labels:
|
||||||
|
- dictionary
|
||||||
|
- startup
|
||||||
|
- performance
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main/runtime/character-dictionary-auto-sync.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main/runtime/current-media-tokenization-gate.ts
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Keep character dictionary auto-sync running in parallel during startup without delaying playback. Only tokenization readiness should gate playback; character dictionary import/settings updates should wait until tokenization is already ready and then refresh annotations afterward.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Character dictionary snapshot/build work can run immediately during startup.
|
||||||
|
- [x] #2 Yomitan dictionary mutation work waits until current-media tokenization is ready.
|
||||||
|
- [x] #3 Regression coverage verifies auto-sync builds before the gate and only mutates Yomitan after the gate resolves.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Added a small current-media tokenization gate in main runtime. Media changes reset the gate, the first tokenization-ready event marks it ready, and auto-sync now waits on that gate only before Yomitan dictionary inspection/import/settings updates. Snapshot generation and merged ZIP build still run immediately in parallel.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
id: TASK-144
|
||||||
|
title: Sequence startup OSD notifications for tokenization, annotations, and character dictionary sync
|
||||||
|
status: Done
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-09 10:40'
|
||||||
|
updated_date: '2026-03-09 10:40'
|
||||||
|
labels:
|
||||||
|
- startup
|
||||||
|
- overlay
|
||||||
|
- ux
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main/runtime/startup-osd-sequencer.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main/runtime/subtitle-tokenization-main-deps.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main/runtime/character-dictionary-auto-sync-notifications.ts
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Keep startup OSD progress ordered. While tokenization is still pending, only show the tokenization loading message. After tokenization becomes ready, show annotation loading if annotation warmup still remains. Only surface character dictionary auto-sync progress after annotation loading clears, and only if the dictionary work is still active.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Character dictionary progress stays hidden while tokenization startup loading is still active.
|
||||||
|
- [x] #2 Annotation loading OSD appears after tokenization readiness and before any later character dictionary progress.
|
||||||
|
- [x] #3 Regression coverage verifies buffered dictionary progress/failure ordering during startup.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Added a small startup OSD sequencer in main runtime. Annotation warmup OSD now flows through that sequencer, and character dictionary sync notifications buffer until tokenization plus annotation loading clear. Buffered `ready` updates are dropped if dictionary progress finished before it ever became visible, while buffered failures still surface after annotation loading completes.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
id: TASK-145
|
||||||
|
title: Show character dictionary build progress on startup OSD before import
|
||||||
|
status: Done
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-09 11:20'
|
||||||
|
updated_date: '2026-03-09 11:20'
|
||||||
|
labels:
|
||||||
|
- startup
|
||||||
|
- dictionary
|
||||||
|
- ux
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main/runtime/character-dictionary-auto-sync.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main/runtime/startup-osd-sequencer.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main/runtime/character-dictionary-auto-sync.test.ts
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Surface an explicit character-dictionary build phase on startup OSD so there is visible progress between subtitle annotation loading and the later import/upload step when merged dictionary generation is still running.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Auto-sync emits a dedicated in-flight status while merged dictionary generation is running.
|
||||||
|
- [x] #2 Startup OSD sequencing treats that build phase as progress and can surface it after annotation loading clears.
|
||||||
|
- [x] #3 Regression coverage verifies the build phase is emitted before import begins.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Added a `building` progress phase before `buildMergedDictionary(...)` and included it in the startup OSD sequencer's buffered progress set. This gives startup a visible dictionary-progress step even when snapshot checking/generation finished too early to still be relevant by the time annotation loading completes.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
id: TASK-145
|
||||||
|
title: Show checking and generation OSD for character dictionary auto-sync
|
||||||
|
status: Done
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-09 11:20'
|
||||||
|
updated_date: '2026-03-09 11:20'
|
||||||
|
labels:
|
||||||
|
- dictionary
|
||||||
|
- overlay
|
||||||
|
- ux
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main/runtime/character-dictionary-auto-sync.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main/runtime/startup-osd-sequencer.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main/character-dictionary-runtime.ts
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Surface an immediate startup OSD that the character dictionary is being checked, and show a distinct generating message only when the current AniList media actually needs a fresh snapshot build instead of reusing a cached one.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Auto-sync emits a `checking` progress event before snapshot resolution completes.
|
||||||
|
- [x] #2 Auto-sync emits `generating` only for snapshot cache misses and keeps `updating`/`importing` as later phases.
|
||||||
|
- [x] #3 Startup OSD sequencing still prioritizes tokenization then annotation loading before buffered dictionary progress.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Character dictionary auto-sync now emits `Checking character dictionary...` as soon as the AniList media is resolved, then emits `Generating character dictionary...` only when the snapshot layer misses and a real rebuild begins. Cached snapshots skip the generating phase and continue straight into the later update/import flow.
|
||||||
|
|
||||||
|
Wired those progress callbacks through the character-dictionary runtime boundary, updated the startup OSD sequencer to treat checking/generating as dictionary-progress phases with the same tokenization and annotation precedence, and added regression coverage for cache-hit vs cache-miss behavior plus buffered startup ordering.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
id: TASK-146
|
||||||
|
title: Forward overlay Tab to mpv for AniSkip
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-09 00:00'
|
||||||
|
updated_date: '2026-03-09 00:00'
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
- overlay
|
||||||
|
- aniskip
|
||||||
|
- linux
|
||||||
|
dependencies: []
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Fix visible-overlay keyboard handling so bare `Tab` is forwarded to mpv instead of being consumed by Electron focus navigation. This restores the default AniSkip `TAB` binding while the overlay has focus, especially on Linux.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Visible overlay forwards bare `Tab` to mpv as `keypress TAB`.
|
||||||
|
- [x] #2 Modal overlays keep their existing local `Tab` behavior.
|
||||||
|
- [x] #3 Automated regression coverage exists for the input handler and overlay factory wiring.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Add a failing regression around visible-overlay `before-input-event` handling for bare `Tab`.
|
||||||
|
2. Add/extend overlay factory tests so the new mpv-forward callback is wired through runtime construction.
|
||||||
|
3. Patch overlay input handling to intercept visible-overlay `Tab` and send mpv `keypress TAB`.
|
||||||
|
4. Run focused overlay tests, typecheck, and changelog validation.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Extracted visible-overlay input handling into `src/core/services/overlay-window-input.ts` so the `Tab` forwarding decision can be unit tested without loading Electron window primitives.
|
||||||
|
|
||||||
|
Visible overlay `before-input-event` now intercepts bare `Tab`, prevents the browser default, and forwards mpv `keypress TAB` through the existing mpv runtime command path. Modal overlays remain unchanged.
|
||||||
|
|
||||||
|
Verification:
|
||||||
|
|
||||||
|
- `bun test src/core/services/overlay-window.test.ts src/main/runtime/overlay-window-factory.test.ts src/main/runtime/overlay-window-factory-main-deps.test.ts src/main/runtime/overlay-window-runtime-handlers.test.ts`
|
||||||
|
- `bun x tsc --noEmit`
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Visible overlay focus no longer blocks the default AniSkip `Tab` binding. Bare `Tab` is now forwarded straight to mpv while the visible overlay is active, and modal overlays still retain their own normal focus behavior.
|
||||||
|
|
||||||
|
Added regression coverage for both the input-routing decision and the runtime plumbing that carries the new mpv forwarder into overlay window creation.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
id: TASK-148
|
||||||
|
title: Fix Windows plugin env binary override resolution
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-09 00:00'
|
||||||
|
updated_date: '2026-03-09 00:00'
|
||||||
|
labels:
|
||||||
|
- windows
|
||||||
|
- plugin
|
||||||
|
- regression
|
||||||
|
dependencies: []
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Fix the mpv plugin's Windows binary override lookup so `SUBMINER_BINARY_PATH` still resolves when `SUBMINER_APPIMAGE_PATH` is unset. The current Lua resolver builds an array with a leading `nil`, which causes `ipairs` iteration to stop before the later Windows override candidate.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 `scripts/test-plugin-binary-windows.lua` passes the env override regression that expects `.exe` suffix resolution from `SUBMINER_BINARY_PATH`.
|
||||||
|
- [x] #2 Existing plugin start/binary test gate stays green after the fix.
|
||||||
|
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Updated `plugin/subminer/binary.lua` so env override lookup checks `SUBMINER_APPIMAGE_PATH` and `SUBMINER_BINARY_PATH` sequentially instead of via a Lua array literal that truncates at the first `nil`. This restores Windows `.exe` suffix resolution for `SUBMINER_BINARY_PATH` when the AppImage env var is unset.
|
||||||
|
|
||||||
|
Verification:
|
||||||
|
|
||||||
|
- `lua scripts/test-plugin-binary-windows.lua`
|
||||||
|
- `bun run test:plugin:src`
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
---
|
||||||
|
id: TASK-149
|
||||||
|
title: Cut patch release v0.5.5 for character dictionary updates and release guarding
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-09 01:10'
|
||||||
|
updated_date: '2026-03-09 01:14'
|
||||||
|
labels:
|
||||||
|
- release
|
||||||
|
- patch
|
||||||
|
dependencies:
|
||||||
|
- TASK-140
|
||||||
|
- TASK-141
|
||||||
|
- TASK-142
|
||||||
|
- TASK-143
|
||||||
|
- TASK-144
|
||||||
|
- TASK-145
|
||||||
|
- TASK-146
|
||||||
|
- TASK-148
|
||||||
|
references:
|
||||||
|
- package.json
|
||||||
|
- CHANGELOG.md
|
||||||
|
- scripts/build-changelog.ts
|
||||||
|
- scripts/build-changelog.test.ts
|
||||||
|
- docs/RELEASING.md
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Prepare and publish patch release `v0.5.5` after the failed `v0.5.4` tag by aligning package version metadata, generating committed changelog output from the pending release fragments, and hardening release validation so a future tag cannot ship with a mismatched `package.json` version.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Repository version metadata is updated to `0.5.5`.
|
||||||
|
- [x] #2 `CHANGELOG.md` contains the committed `v0.5.5` section and the consumed fragments are removed.
|
||||||
|
- [x] #3 Release validation rejects a requested release version when it differs from `package.json`.
|
||||||
|
- [x] #4 Release docs capture the required version/changelog prep before tagging.
|
||||||
|
- [x] #5 New `v0.5.5` release-prep commit and tag are pushed to `origin/main`.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Add a regression test for tagged-release/package version mismatch.
|
||||||
|
2. Update changelog validation to reject mismatched explicit release versions.
|
||||||
|
3. Bump `package.json`, generate committed `v0.5.5` changelog output, and remove consumed fragments.
|
||||||
|
4. Add a short `docs/RELEASING.md` checklist for the prep flow.
|
||||||
|
5. Run release verification, commit, tag, and push.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Added a regression test in `scripts/build-changelog.test.ts` that proves `changelog:check --version ...` rejects tag/package mismatches. Updated `scripts/build-changelog.ts` so tagged release validation now compares the explicit requested version against `package.json` before looking for pending fragments or the committed changelog section.
|
||||||
|
|
||||||
|
Bumped `package.json` from `0.5.3` to `0.5.5`, ran `bun run changelog:build --version 0.5.5 --date 2026-03-09`, and committed the generated `CHANGELOG.md` output while removing the consumed task fragments. Added `docs/RELEASING.md` with the required release-prep checklist so version bump + changelog generation happen before tagging.
|
||||||
|
|
||||||
|
Verification: `bun run changelog:lint`, `bun run changelog:check --version 0.5.5`, `bun run typecheck`, `bun run test:fast`, and `bun test scripts/build-changelog.test.ts src/release-workflow.test.ts`. `bun run format:check` still reports many unrelated pre-existing repo-wide Prettier warnings, so touched files were checked/formatted separately with `bunx prettier`.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Prepared patch release `v0.5.5` after the failed `v0.5.4` release attempt. Release metadata now matches the upcoming tag, the pending character-dictionary/overlay/plugin fragments are committed into `CHANGELOG.md`, and release validation now blocks future tag/package mismatches before publish.
|
||||||
|
|
||||||
|
Docs now include a short release checklist in `docs/RELEASING.md`. Validation passed for changelog lint/check, typecheck, targeted workflow tests, and the full fast test suite. Repo-wide Prettier remains noisy from unrelated existing files, but touched release files were formatted and verified.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
id: TASK-150
|
||||||
|
title: Restore repo-wide Prettier cleanliness after release prep
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-09 01:11'
|
||||||
|
updated_date: '2026-03-09 01:11'
|
||||||
|
labels:
|
||||||
|
- tooling
|
||||||
|
- formatting
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- backlog/config.yml
|
||||||
|
- backlog/tasks
|
||||||
|
- config.example.jsonc
|
||||||
|
- launcher/types.ts
|
||||||
|
- launcher/util.ts
|
||||||
|
- launcher/youtube/orchestrator.ts
|
||||||
|
- scripts/build-win-unsigned.mjs
|
||||||
|
- src
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Bring `bun run format:check` back to green after the `v0.5.5` release-prep work exposed repo-wide Prettier drift across backlog markdown, config files, and maintained TypeScript sources.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 `bun run format:check` passes.
|
||||||
|
- [x] #2 `bun run changelog:lint` still passes.
|
||||||
|
- [x] #3 Typecheck and fast tests stay green after the formatting-only rewrite.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
|
||||||
|
1. Re-run format and lint checks to confirm failing files.
|
||||||
|
2. Apply Prettier to the warned repo-managed files.
|
||||||
|
3. Re-run formatting, lint, typecheck, and fast tests.
|
||||||
|
4. Commit and push the formatting-only cleanup.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
|
||||||
|
Ran `bunx prettier --write` across the repo-managed files reported by `bun run format:check`, covering backlog markdown/YAML, `config.example.jsonc`, selected launcher/scripts files, and maintained TypeScript sources under `src/`.
|
||||||
|
|
||||||
|
Verification: `bun run format:check`, `bun run changelog:lint`, `bun run typecheck`, and `bun run test:fast`.
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Repo-wide Prettier drift is cleaned up, including backlog task markdown, config/example files, and the maintained code files that `format:check` was flagging. Formatting and lint checks are green again, and typecheck/fast tests stayed green after the formatting-only rewrite.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
---
|
||||||
|
id: TASK-151
|
||||||
|
title: Keep JLPT underline color stable during Yomitan text selection
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- OpenCode
|
||||||
|
created_date: '2026-03-10 06:42'
|
||||||
|
updated_date: '2026-03-10 07:54'
|
||||||
|
labels: []
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- src/renderer/style.css
|
||||||
|
- src/renderer/subtitle-render.test.ts
|
||||||
|
documentation:
|
||||||
|
- ../subminer-docs/development.md
|
||||||
|
- ../subminer-docs/architecture.md
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Fix the subtitle overlay so JLPT underlines keep their JLPT color when Yomitan lookups trigger hover/selection styling on tokens that are also known, N+1, or frequency-highlighted.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [x] #1 JLPT-tagged subtitle tokens keep their JLPT underline color during hover/selection states used by Yomitan lookup.
|
||||||
|
- [x] #2 Tokens that combine JLPT with known, N+1, name-match, or frequency styling preserve their primary text color while keeping the JLPT underline color.
|
||||||
|
- [x] #3 Renderer regression coverage verifies the JLPT underline color remains explicit in the stylesheet for combined styling states.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
1. Revert the temporary box-shadow JLPT marker experiment and restore native JLPT underline styling in `src/renderer/style.css`.
|
||||||
|
2. Add explicit JLPT hover/selection color rules with higher specificity so Yomitan lookup highlight states cannot repaint the underline to the token hover color.
|
||||||
|
3. Update `src/renderer/subtitle-render.test.ts` to verify JLPT hover/selection rules keep the predefined JLPT underline color, then rerun focused and relevant verification commands.
|
||||||
|
|
||||||
|
4. Add JLPT-specific `text-decoration-color` overrides directly on child `.c` spans and their hover/selection states, since Yomitan lookup likely paints the decorated child text runs rather than only the parent token span.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
Added a renderer regression test that asserts JLPT underline color stays explicit through hover and selection styling.
|
||||||
|
|
||||||
|
Updated `src/renderer/style.css` to route JLPT underline color through `--subtitle-jlpt-underline-color` and re-apply it on word/character hover and selection states.
|
||||||
|
|
||||||
|
Verification: `bun test src/renderer/subtitle-render.test.ts`, `bun run typecheck`, `bun run test:fast`, `bun run build`, `bun run changelog:lint`, `bunx prettier --check src/renderer/style.css src/renderer/subtitle-render.test.ts changes/jlpt-underline-yomitan.md`. `bun run format:check:src` still fails because of unrelated existing formatting issues in `src/main-entry-runtime.test.ts` and `src/main-entry-runtime.ts`.
|
||||||
|
|
||||||
|
User verified the original CSS variable propagation fix did not resolve the live issue; continuing investigation and reopening the task.
|
||||||
|
|
||||||
|
Confirmed Chromium was repainting native `text-decoration` underlines with the selected text color; reproduced it in a temporary browser repro and verified that switching the JLPT marker to an inset box-shadow keeps the JLPT color stable during selection.
|
||||||
|
|
||||||
|
Replaced the previous native underline approach with a fragment-safe JLPT marker using `box-shadow` plus `box-decoration-break`, then updated stylesheet regression coverage to match the new implementation.
|
||||||
|
|
||||||
|
Verification: `bun test src/renderer/subtitle-render.test.ts`, `bunx prettier --check src/renderer/style.css src/renderer/subtitle-render.test.ts`, `bun run typecheck`, `bun run test:fast`, `bun run build`.
|
||||||
|
|
||||||
|
User requested reverting the box-shadow marker experiment. Narrowing the fix to preserve native JLPT underline color during Yomitan hover/selection instead of changing the underline rendering method.
|
||||||
|
|
||||||
|
Reverted the box-shadow experiment per user request. Restored native JLPT underline styling and added explicit JLPT hover/selection rules so Yomitan lookup states keep the predefined JLPT underline color with `!important`.
|
||||||
|
|
||||||
|
Verification after revert/fix: `bun test src/renderer/subtitle-render.test.ts`, `bunx prettier --check src/renderer/style.css src/renderer/subtitle-render.test.ts`, `bun run typecheck`, `bun run build`.
|
||||||
|
|
||||||
|
Issue still reproduces specifically during Shift-held Yomitan lookup. Investigating decoration propagation onto child `.c` spans during lookup-triggered hover/selection states.
|
||||||
|
|
||||||
|
Added JLPT-specific `text-decoration-color` overrides directly to child `.c` spans and their hover/selection states, in addition to the token span itself, so lookup-triggered decoration painting on child runs keeps the JLPT color.
|
||||||
|
|
||||||
|
Verification: `bun test src/renderer/subtitle-render.test.ts`, `bunx prettier --check src/renderer/style.css src/renderer/subtitle-render.test.ts`, `bun run typecheck`, `bun run build`.
|
||||||
|
|
||||||
|
Added a final high-specificity combined-state JLPT override after the annotation hover/selection rules. It targets tokens that are both JLPT-tagged and known/N+1/name-match/frequency-highlighted, forcing `text-decoration-color` back to the JLPT variable after the later annotation state blocks.
|
||||||
|
|
||||||
|
Verification: `bun test src/renderer/subtitle-render.test.ts`, `bunx prettier --check src/renderer/style.css src/renderer/subtitle-render.test.ts`, `bun run build`.
|
||||||
|
|
||||||
|
Switched the JLPT underline from native `text-decoration` to a separate painted underline layer using `background-image` on JLPT tokens. Also changed hover token highlight rules to use `background-color` so the JLPT underline layer survives Shift+Yomitan hover/lookup interactions.
|
||||||
|
|
||||||
|
Verification: `bun test src/renderer/subtitle-render.test.ts`, `bunx prettier --check src/renderer/style.css src/renderer/subtitle-render.test.ts`, `bun run build`.
|
||||||
|
|
||||||
|
User reports the latest background-image JLPT underline change introduced grey-looking token highlights. Investigating the interaction between the new underline layer and hover background styling.
|
||||||
|
|
||||||
|
The background-image underline layer interacts poorly with hover fills and makes highlighted tokens look grey. Switching the separate JLPT underline layer to an inset box-shadow so hover background color and JLPT underline paint can coexist cleanly.
|
||||||
|
|
||||||
|
Adjusted the separate JLPT underline layer from `background-image` to inset `box-shadow`. This keeps the underline decoupled from Yomitan hover color while avoiding the grey-looking underline artifact introduced by the background-image approach.
|
||||||
|
|
||||||
|
User reports the separate underline layer still disappears/greys out during lookup. Switching strategy again: use a dedicated `border-bottom` JLPT marker instead of box-shadow/background so the underline stays independent from Yomitan hover paint without blending artifacts.
|
||||||
|
|
||||||
|
Replaced the separate JLPT underline layer with `border-bottom` plus a small bottom padding. This keeps the underline visually separate from Yomitan hover paint and avoids the disappearing/grey artifact seen with background-image and box-shadow.
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
Switched the JLPT underline layer in `src/renderer/style.css` to `border-bottom` plus `padding-bottom`, keeping it independent from Yomitan hover/selection repainting while avoiding the disappearing or grey artifact seen with the background-image and box-shadow approaches.
|
||||||
|
|
||||||
|
Updated `src/renderer/subtitle-render.test.ts` to assert the border-bottom-based JLPT underline layer.
|
||||||
|
|
||||||
|
Verification: `bun test src/renderer/subtitle-render.test.ts`, `bunx prettier --check src/renderer/style.css src/renderer/subtitle-render.test.ts`, `bun run build`.
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
id: TASK-152
|
||||||
|
title: Fix early Electron userData path casing to stay under SubMiner config dir
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-10 06:46'
|
||||||
|
updated_date: '2026-03-10 06:51'
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
- config
|
||||||
|
- electron
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main-entry.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/main.ts
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/src/config/path-resolution.ts
|
||||||
|
documentation:
|
||||||
|
- /home/sudacode/projects/japanese/subminer-docs/development.md
|
||||||
|
- /home/sudacode/projects/japanese/subminer-docs/architecture.md
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Electron startup touches the app object before the main-process bootstrap overrides userData, which can create/write the default lowercase ~/.config/subminer directory on Linux/macOS. Ensure early startup pins the app identity and userData path to the canonical SubMiner config directory before any Electron APIs can materialize the default path, and keep regression coverage around the bootstrap path behavior.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [x] #1 Electron startup uses the canonical SubMiner config directory as userData before other Electron app calls can create the default lowercase directory.
|
||||||
|
- [x] #2 Regression tests cover the early bootstrap path setup and fail if startup falls back to a lowercase subminer config path.
|
||||||
|
- [x] #3 Existing config path resolution behavior for SubMiner casing remains intact.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
1. Add regression coverage for early Electron bootstrap path setup, including a case that would otherwise fall back to lowercase subminer.
|
||||||
|
2. Extract a pure helper that computes and applies the canonical app name/userData path from config resolution.
|
||||||
|
3. Call the helper from main-entry before any Electron app interactions that could materialize the default userData directory.
|
||||||
|
4. Run focused tests for startup/config path behavior, then the relevant fast gate if green.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
Added early Electron bootstrap path setup in src/main-entry so app name and userData are pinned to the canonical SubMiner config dir before single-instance/whenReady handling.
|
||||||
|
|
||||||
|
Added a regression test in src/main-entry-runtime.test.ts covering the lowercase subminer fallback case.
|
||||||
|
|
||||||
|
Validation: bun test src/main-entry-runtime.test.ts src/config/path-resolution.test.ts; bun run typecheck. bun run test:fast still fails on an existing unrelated renderer JLPT CSS test in src/renderer/subtitle-render.test.ts.
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
Pinned Electron's app identity and userData path during entry bootstrap so startup uses the canonical SubMiner config directory before any other Electron app calls can materialize the default lowercase path. Added a regression test covering the lowercase subminer fallback case and kept existing config-path resolution coverage green.
|
||||||
|
|
||||||
|
Validation:
|
||||||
|
- bun test src/main-entry-runtime.test.ts src/config/path-resolution.test.ts
|
||||||
|
- bun run typecheck
|
||||||
|
- bun run test:fast (fails on existing unrelated JLPT CSS renderer test in src/renderer/subtitle-render.test.ts)
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
id: TASK-153
|
||||||
|
title: Fix character dictionary MRU eviction after revisits
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- '@codex'
|
||||||
|
created_date: '2026-03-10 07:56'
|
||||||
|
updated_date: '2026-03-10 08:48'
|
||||||
|
labels:
|
||||||
|
- character-dictionary
|
||||||
|
- yomitan
|
||||||
|
- anilist
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- >-
|
||||||
|
/home/sudacode/projects/japanese/SubMiner/src/main/runtime/character-dictionary-auto-sync.ts
|
||||||
|
- >-
|
||||||
|
/home/sudacode/projects/japanese/SubMiner/src/main/runtime/character-dictionary-auto-sync.test.ts
|
||||||
|
- >-
|
||||||
|
/home/sudacode/projects/japanese/SubMiner/src/main/character-dictionary-runtime.ts
|
||||||
|
documentation:
|
||||||
|
- /home/sudacode/projects/japanese/subminer-docs/development.md
|
||||||
|
- /home/sudacode/projects/japanese/subminer-docs/architecture.md
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Keep merged character dictionary retention truly MRU-based when a currently retained anime is revisited before opening a new title, so the oldest retained title is evicted instead of the revisited one.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [x] #1 Revisiting an anime already retained in the merged character dictionary updates MRU ordering before the next new title is added.
|
||||||
|
- [x] #2 When retention exceeds maxLoaded after that revisit-plus-new-title sequence, the least recently used retained anime is evicted rather than the revisited title.
|
||||||
|
- [x] #3 Auto-sync rebuilds or reloads the merged dictionary so an evicted anime becomes available again when reopened.
|
||||||
|
- [x] #4 Regression tests cover the revisit-before-eviction flow.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
1. Reproduce the revisit-before-eviction scenario with a focused regression test in `src/main/runtime/character-dictionary-auto-sync.test.ts` using a retained set that revisits an existing anime before introducing a new anime.
|
||||||
|
2. Run the focused test to confirm current behavior fails for the expected MRU ordering / eviction case.
|
||||||
|
3. Adjust `src/main/runtime/character-dictionary-auto-sync.ts` so retained ordering stays MRU-correct across revisits and subsequent additions without regressing unchanged revisit behavior.
|
||||||
|
4. Re-run the focused auto-sync suite, then run the relevant broader checks required for handoff.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
Added a focused regression in `src/main/runtime/character-dictionary-auto-sync.test.ts` for the `1,2,3,1,4,1` revisit-before-eviction flow. The current MRU auto-sync logic passed: merged builds were `[1]`, `[2,1]`, `[3,2,1]`, `[1,3,2]`, `[4,1,3]`, `[1,4,3]`, so I have not reproduced the reported eviction bug in the in-process auto-sync service yet.
|
||||||
|
|
||||||
|
Inspected local cache under `~/.config/SubMiner/character-dictionaries/` and found Little Witch Academia snapshot `anilist-21858.json` already present, so the reported regeneration path was not a snapshot-cache miss. The on-disk `merged.zip` revision (`9251ae23e136`) also differed from `auto-sync-state.json` (`bc16c5b5af17`), indicating a rebuilt merged dictionary artifact could land without the MRU state being persisted.
|
||||||
|
|
||||||
|
Fixed `src/main/runtime/character-dictionary-auto-sync.ts` to persist the rebuilt retained-set state immediately after a merged dictionary revision/title is known, before later Yomitan mutation steps. This keeps MRU eviction state aligned even if import/settings work fails after the rebuild artifact is written.
|
||||||
|
|
||||||
|
Added regression coverage in `src/main/runtime/character-dictionary-auto-sync.test.ts` for the revisit-before-eviction sequence and for post-build import failure preserving the rebuilt MRU state. Verified with `bun test src/main/runtime/character-dictionary-auto-sync.test.ts src/main/character-dictionary-runtime.test.ts`, `bun run typecheck`, `bun run changelog:lint`, and `bun run test:fast`.
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
Persisted merged character-dictionary MRU state as soon as a rebuilt retained set is known in `src/main/runtime/character-dictionary-auto-sync.ts`, so revisits are not lost if later Yomitan import/settings work fails after `merged.zip` has already been rewritten. Added regression coverage for revisit-before-eviction ordering and import-failure state preservation in `src/main/runtime/character-dictionary-auto-sync.test.ts`, plus a changelog fragment in `changes/character-dictionary-mru-state-recovery.md`.
|
||||||
|
|
||||||
|
Validation: `bun test src/main/runtime/character-dictionary-auto-sync.test.ts src/main/character-dictionary-runtime.test.ts`, `bun run typecheck`, `bun run changelog:lint`, `bun run test:fast`.
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
id: TASK-154
|
||||||
|
title: Avoid merged dictionary rebuilds on MRU reorder-only revisits
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- '@codex'
|
||||||
|
created_date: '2026-03-10 09:16'
|
||||||
|
updated_date: '2026-03-10 09:22'
|
||||||
|
labels:
|
||||||
|
- character-dictionary
|
||||||
|
- yomitan
|
||||||
|
- anilist
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- >-
|
||||||
|
/home/sudacode/projects/japanese/SubMiner/src/main/runtime/character-dictionary-auto-sync.ts
|
||||||
|
- >-
|
||||||
|
/home/sudacode/projects/japanese/SubMiner/src/main/runtime/character-dictionary-auto-sync.test.ts
|
||||||
|
- >-
|
||||||
|
/home/sudacode/projects/japanese/SubMiner/src/main/character-dictionary-runtime.ts
|
||||||
|
- >-
|
||||||
|
/home/sudacode/projects/japanese/SubMiner/src/main/character-dictionary-runtime.test.ts
|
||||||
|
documentation:
|
||||||
|
- /home/sudacode/projects/japanese/subminer-docs/development.md
|
||||||
|
- /home/sudacode/projects/japanese/subminer-docs/architecture.md
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Keep per-title MRU retention ordering for eviction decisions, but do not rebuild or reimport the merged character dictionary when the retained set membership is unchanged and only the MRU order changes.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [x] #1 Revisiting an anime already inside the retained set updates MRU ordering used for later eviction decisions without rebuilding or reimporting the merged dictionary when retained membership is unchanged.
|
||||||
|
- [x] #2 Merged dictionary revisions and contents are stable for the same retained membership regardless of MRU ordering.
|
||||||
|
- [x] #3 Adding a new anime that changes retained membership still rebuilds and imports the merged dictionary with the correct eviction behavior.
|
||||||
|
- [x] #4 Regression tests cover reorder-only revisits and stable merged revisions for equivalent retained sets.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
1. Add a failing auto-sync regression showing that a revisit which only reorders MRU state should update `activeMediaIds` but skip merged rebuild/import.
|
||||||
|
2. Add a runtime-level regression showing `buildMergedDictionary` produces a stable revision for equivalent retained memberships regardless of input order.
|
||||||
|
3. Update merged-dictionary build normalization and auto-sync rebuild gating so rebuilds are driven by retained membership changes (or snapshot changes), not MRU reordering alone.
|
||||||
|
4. Re-run focused dictionary tests plus the local verification lanes impacted by the change.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
Changed `src/main/runtime/character-dictionary-auto-sync.ts` so MRU order still updates in `activeMediaIds`, but merged rebuild/import now keys off retained membership changes rather than order-only reordering. Order-only revisits no longer force a merged ZIP rewrite or Yomitan reimport.
|
||||||
|
|
||||||
|
Changed `src/main/character-dictionary-runtime.ts` to canonicalize merged dictionary media ids before building, which makes merged revisions stable for equivalent retained memberships regardless of MRU ordering.
|
||||||
|
|
||||||
|
Updated regression coverage in `src/main/runtime/character-dictionary-auto-sync.test.ts` for reorder-only revisits and membership-change rebuilds, and extended `src/main/character-dictionary-runtime.test.ts` to assert stable merged revisions for reordered inputs. Verified with `bun test src/main/runtime/character-dictionary-auto-sync.test.ts src/main/character-dictionary-runtime.test.ts`, `bun run typecheck`, `bun run changelog:lint`, and `bun run test:fast`.
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
Updated merged character-dictionary syncing so MRU ordering is still tracked for eviction in `src/main/runtime/character-dictionary-auto-sync.ts`, but reorder-only revisits no longer rebuild or reimport the merged dictionary unless retained membership or snapshot data changes. Canonicalized merged build input ordering in `src/main/character-dictionary-runtime.ts` so revisions remain stable for the same retained set regardless of MRU order, and added regressions in `src/main/runtime/character-dictionary-auto-sync.test.ts` plus `src/main/character-dictionary-runtime.test.ts`. Also updated `changes/character-dictionary-mru-state-recovery.md` to cover the new behavior.
|
||||||
|
|
||||||
|
Validation: `bun test src/main/runtime/character-dictionary-auto-sync.test.ts src/main/character-dictionary-runtime.test.ts`, `bun run typecheck`, `bun run changelog:lint`, `bun run test:fast`.
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
id: TASK-155
|
||||||
|
title: Move user docs site back into main repo
|
||||||
|
status: Done
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-10 19:20'
|
||||||
|
updated_date: '2026-03-10 19:38'
|
||||||
|
labels: []
|
||||||
|
dependencies: []
|
||||||
|
priority: medium
|
||||||
|
ordinal: 15500
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Move the standalone VitePress docs site from the sibling `../subminer-docs` checkout back into the main `SubMiner` repo so docs can be updated alongside code and local tooling can reference one repository.
|
||||||
|
|
||||||
|
Scope:
|
||||||
|
|
||||||
|
- import the tracked docs-site source into a dedicated in-repo subdirectory
|
||||||
|
- update scripts/tests/docs instructions that assume a sibling `../subminer-docs` checkout
|
||||||
|
- preserve Cloudflare Pages deployability from a repo subdirectory
|
||||||
|
- verify the app repo and docs site both still build/test from the new layout
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 The user-facing VitePress docs source lives inside the `SubMiner` repo in a dedicated subdirectory.
|
||||||
|
- [x] #2 First-party scripts/tests/docs no longer require `../subminer-docs` for normal operation.
|
||||||
|
- [x] #3 In-repo docs instructions include the Cloudflare Pages subdirectory deploy settings.
|
||||||
|
- [x] #4 Verification covers the relocated docs site build/tests plus affected app-repo checks.
|
||||||
|
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
|
||||||
|
Imported the VitePress site into `docs-site/` inside the main repo and updated project instructions, docs contributor guidance, generator logic, and regression tests to treat that in-repo directory as the docs source of truth.
|
||||||
|
|
||||||
|
Added root proxy scripts for `docs:dev`, `docs:build`, `docs:preview`, and `docs:test`, repointed config-example generation to `docs-site/public/config.example.jsonc`, switched docs edit links to the main `SubMiner` repo, and documented the Cloudflare Pages subdirectory settings (`docs-site` root, `.vitepress/dist` output, `docs-site/**` watch path).
|
||||||
|
|
||||||
|
Verified with `bun run format:check:src`, `bun run typecheck`, `bun run docs:test`, `bun run docs:build`, `bun run test:config:src`, and `bun run test:fast`.
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
id: TASK-156
|
||||||
|
title: Fix docs-site Plausible geo attribution through analytics worker
|
||||||
|
status: In Progress
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-11 02:19'
|
||||||
|
updated_date: '2026-03-11 02:44'
|
||||||
|
labels:
|
||||||
|
- docs-site
|
||||||
|
- analytics
|
||||||
|
dependencies: []
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Investigate and fix missing city/region data for docs.subminer.moe visits in Plausible. The docs site already proxies analytics events to worker.subminer.moe, so the remaining work is to verify and correct the worker-side forwarding contract Plausible needs for geolocation.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 The analytics worker forwards Plausible event requests in a way that preserves the original client IP information needed for location attribution.
|
||||||
|
- [ ] #2 The docs-site analytics flow remains proxied through worker.subminer.moe after the fix.
|
||||||
|
- [ ] #3 Coverage or documentation records the worker-side header/forwarding requirement for Plausible geo reporting.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
Worker implementation lives in `/home/sudacode/projects/blog-proxy`, not in the SubMiner repo.
|
||||||
|
|
||||||
|
Patched `worker.js` to forward client IP via `x-forwarded-for`/`x-real-ip` from `cf-connecting-ip` (fallbacks retained) and added `worker.test.js` regression coverage.
|
||||||
|
|
||||||
|
Local verification in `blog-proxy`: `node --test worker.test.js` passes. Deployment not performed in this session.
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
id: TASK-157
|
||||||
|
title: Fix Cloudflare Pages watch path for docs-site
|
||||||
|
status: In Progress
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-10 20:15'
|
||||||
|
updated_date: '2026-03-10 20:15'
|
||||||
|
labels:
|
||||||
|
- docs-site
|
||||||
|
- cloudflare
|
||||||
|
dependencies: []
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Cloudflare Pages skipped a docs-site deployment after the docs repo moved into the main `SubMiner` repository. The documented/configured watch path uses `docs-site/**`, but Pages monorepo watch paths use a single `*` wildcard pattern. Correct the documented setting and leave a regression test so future repo moves or docs rewrites do not reintroduce the bad pattern.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 Docs contributor guidance points Cloudflare Pages watch paths at `docs-site/*`, not `docs-site/**`.
|
||||||
|
- [ ] #2 Regression coverage fails if the docs revert to the incorrect watch-path string.
|
||||||
|
- [ ] #3 Implementation notes record that the Cloudflare dashboard setting must be updated manually and the docs deploy retriggered.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
Added docs regression coverage in `docs-site/docs-sync.test.ts` for the Pages watch-path string, then corrected the Cloudflare Pages instructions in `docs-site/README.md` and `docs-site/development.md`.
|
||||||
|
|
||||||
|
Manual follow-up still required outside git: update the Cloudflare Pages project include path from `docs-site/**` to `docs-site/*`, then trigger a fresh deployment against `main`.
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
id: TASK-158
|
||||||
|
title: Enforce generated config example drift checks
|
||||||
|
status: Done
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-10 20:35'
|
||||||
|
updated_date: '2026-03-10 20:35'
|
||||||
|
labels:
|
||||||
|
- config
|
||||||
|
- docs-site
|
||||||
|
dependencies: []
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
The generated `config.example.jsonc` artifact is covered by generation-path tests, but there is no hard gate that fails when the checked-in example drifts from the canonical template. The in-repo docs-site copy can also drift silently.
|
||||||
|
|
||||||
|
Scope:
|
||||||
|
|
||||||
|
- add a first-party verification path that compares generated config-example content against committed artifacts
|
||||||
|
- fail fast when repo-root `config.example.jsonc` is stale or missing
|
||||||
|
- fail fast when `docs-site/public/config.example.jsonc` is stale or missing, when the docs site exists
|
||||||
|
- wire the verification into the normal gate and release flow
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [x] #1 Automated verification fails when repo-root `config.example.jsonc` is missing or stale.
|
||||||
|
- [x] #2 Automated verification fails when in-repo docs-site `public/config.example.jsonc` is missing or stale, when docs-site exists.
|
||||||
|
- [x] #3 CI/release or equivalent project gates run the verification automatically.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
Added `src/verify-config-example.ts`, which renders the canonical config template and compares it against the checked-in repo-root `config.example.jsonc` plus `docs-site/public/config.example.jsonc` when the docs site exists.
|
||||||
|
|
||||||
|
Wired the new verification into `package.json` as `bun run verify:config-example`, added regression coverage for missing and stale artifacts, and enforced the new check in both CI and release workflows.
|
||||||
|
|
||||||
|
Regenerated the checked-in config example artifacts so the new gate passes in the repo-local docs-site layout, and documented the release-step expectation in `docs/RELEASING.md`.
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
id: TASK-159
|
||||||
|
title: Add overlay controller support for keyboard-only mode
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-11 00:30'
|
||||||
|
updated_date: '2026-03-11 04:05'
|
||||||
|
labels:
|
||||||
|
- enhancement
|
||||||
|
- renderer
|
||||||
|
- overlay
|
||||||
|
- input
|
||||||
|
dependencies:
|
||||||
|
- TASK-86
|
||||||
|
references:
|
||||||
|
- src/renderer/handlers/keyboard.ts
|
||||||
|
- src/renderer/renderer.ts
|
||||||
|
- src/renderer/state.ts
|
||||||
|
- src/renderer/index.html
|
||||||
|
- src/renderer/style.css
|
||||||
|
- src/preload.ts
|
||||||
|
- src/types.ts
|
||||||
|
- src/config/definitions/defaults-core.ts
|
||||||
|
- src/config/definitions/options-core.ts
|
||||||
|
- src/config/definitions/template-sections.ts
|
||||||
|
- config.example.jsonc
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Add Chrome Gamepad API support to the visible overlay as a supplement to keyboard-only mode. By default SubMiner should bind to the first available controller, allow the user to pick and persist a preferred controller, expose a raw-input debug modal, and map controller actions onto the existing keyboard-only/Yomitan flow without breaking keyboard input. Also fix the current keyboard-only cleanup bug so the selected-token highlight clears when keyboard-only mode turns off or when the Yomitan popup closes.
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [x] #1 Controller input is ignored unless keyboard-only mode is enabled, except the controller binding for toggling keyboard-only mode itself.
|
||||||
|
- [x] #2 Default logical mappings work: smooth popup scroll, token selection, lookup toggle/close, mining, Yomitan audio navigation/play, and mpv play/pause.
|
||||||
|
- [x] #3 Controller config supports named logical bindings plus tuning knobs (preferred controller, deadzones, smooth-scroll speed/repeat), not raw axis/button maps.
|
||||||
|
- [x] #4 `Alt+C` opens a controller selection modal listing connected controllers; saving a choice persists the preferred controller for next launch.
|
||||||
|
- [x] #5 `Alt+Shift+C` opens a debug modal showing live raw controller axes/buttons as seen by SubMiner.
|
||||||
|
- [x] #6 Keyboard-only selection highlight clears immediately when keyboard-only mode is disabled or the Yomitan popup closes.
|
||||||
|
- [x] #7 Renderer/config regression tests cover controller gating, mappings, modal behavior, persisted selection, and highlight cleanup.
|
||||||
|
- [x] #8 Docs/config example describe the controller feature and new shortcuts.
|
||||||
|
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
- Added renderer-side gamepad polling and logical action mapping in `src/renderer/handlers/gamepad-controller.ts`.
|
||||||
|
- Added controller select/debug modals, persisted preferred-controller IPC, and top-level `controller` config defaults/schema/template output.
|
||||||
|
- Added a transient in-overlay controller status indicator when a controller is first detected.
|
||||||
|
- Tuned controller defaults and routing after live testing: d-pad fallback navigation, slower repeat timing, DOM-backed popup-open detection, and direct pixel scroll/audio-source popup bridge commands.
|
||||||
|
- Reused existing keyboard-only lookup/mining/navigation flows so controller input stays a supplement to keyboard-only mode instead of a parallel input path.
|
||||||
|
- Verified keyboard-only highlight cleanup on mode-off and popup-close paths with renderer tests.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- `bun test src/config/config.test.ts src/config/definitions/domain-registry.test.ts src/renderer/handlers/keyboard.test.ts src/renderer/handlers/gamepad-controller.test.ts src/renderer/modals/controller-select.test.ts src/renderer/modals/controller-debug.test.ts src/core/services/ipc.test.ts`
|
||||||
|
- `bun test src/main/runtime/composers/ipc-runtime-composer.test.ts`
|
||||||
|
- `bun run generate:config-example`
|
||||||
|
- `bun run typecheck`
|
||||||
|
- `bun run docs:test`
|
||||||
|
- `bun run test:fast`
|
||||||
|
- `bun run test:env`
|
||||||
|
- `bun run build`
|
||||||
|
- `bun run docs:build`
|
||||||
|
- `bun run test:smoke:dist`
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
id: TASK-159
|
||||||
|
title: Create SubMiner automated testing skill for agents
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-11 05:55'
|
||||||
|
updated_date: '2026-03-11 06:13'
|
||||||
|
labels:
|
||||||
|
- tooling
|
||||||
|
- testing
|
||||||
|
- skills
|
||||||
|
dependencies: []
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Design and implement a SubMiner-specific skill that agents can use to verify code changes with automated checks across launcher, mpv, overlay, and related workflows.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [x] #1 Define the skill trigger surface and intended use cases for SubMiner change verification.
|
||||||
|
- [x] #2 Implement a SubMiner-specific skill package with concise workflow guidance and any required helper scripts or references.
|
||||||
|
- [x] #3 Document how agents should run automated verification for common SubMiner change types, including launcher/mpv/overlay-sensitive changes.
|
||||||
|
- [x] #4 Verify the skill itself is usable in this repo context.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
1. Add a design doc at `docs/plans/2026-03-10-subminer-change-verification-design.md` capturing the approved skill contract, lane selection rules, helper script design, and trigger/workflow guidance.
|
||||||
|
2. Create an in-repo source package for the new SubMiner-specific verification skill with `SKILL.md` plus helper shell scripts for diff classification and coordinated verification/artifact capture.
|
||||||
|
3. Implement cheap-first verification logic: map changed paths to verification lanes, run repo-native commands, capture stdout/stderr and metadata under `.tmp/skill-verification/<timestamp>/`, and report pass/fail/skipped states with artifact paths.
|
||||||
|
4. Encode repo-specific heuristics for docs/config, launcher/plugin, runtime/dist, and optional real-GUI escalation guidance without making GUI launch the default.
|
||||||
|
5. Verify the skill locally by running the classifier/verifier against representative paths and confirming artifact generation and summaries.
|
||||||
|
6. Optionally install the finished skill to `~/.codex/skills/subminer-change-verification/` after user approval because that target is outside the writable sandbox.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
Planned outputs: SKILL.md plus small helper shell scripts for diff classification and coordinated verification/artifact capture. Default to repo-native commands; only escalate to real GUI/mpv verification when affected paths or requested behavior require it.
|
||||||
|
|
||||||
|
2026-03-10: Brainstorming completed with user approval for a SubMiner-specific automated verification skill. Chosen shape: auto-triggering, cheap-first verification workflow with optional real GUI/mpv escalation and artifact capture.
|
||||||
|
|
||||||
|
2026-03-10: Added design doc at docs/plans/2026-03-10-subminer-change-verification-design.md and created the in-repo skill source at tools/skills/subminer-change-verification/.
|
||||||
|
|
||||||
|
2026-03-10: Verified classifier output with representative launcher/runtime/config/docs paths and ran the verifier in dry-run mode plus one real config lane (`bun run test:config`). Artifacts written under .tmp/skill-verification/20260310-231320 and .tmp/skill-verification/20260310-231326.
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
Implemented a SubMiner-specific change verification skill source with a concise SKILL.md, a diff classifier, and a cheap-first verifier that captures artifacts under `.tmp/skill-verification/`. Verified the flow with representative path classification, a dry-run multi-lane plan, and a passing real config verification run.
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
id: TASK-160
|
||||||
|
title: Create repo-local scrum master orchestration skill
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-11 06:32'
|
||||||
|
updated_date: '2026-03-11 06:45'
|
||||||
|
labels:
|
||||||
|
- skills
|
||||||
|
- workflow
|
||||||
|
- backlog
|
||||||
|
- subagents
|
||||||
|
- automation
|
||||||
|
dependencies: []
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Design and implement a repo-local skill that can turn incoming requests/issues into well-scoped Backlog tasks, then coordinate one or more subagents to implement and verify the resulting work using the repo's established skills and verification workflow.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [x] #1 Define the trigger surface, responsibilities, and limits of the scrum master skill for request intake, backlog updates, and execution orchestration.
|
||||||
|
- [x] #2 Implement the skill package with concise guidance for intake, task search/create/update, planning, and subagent dispatch.
|
||||||
|
- [x] #3 Specify how the skill coordinates with existing repo workflows, including Backlog.md requirements and SubMiner change verification.
|
||||||
|
- [x] #4 Verify the skill is usable in this repo context for at least one representative request flow.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
1. Add a design doc at `docs/plans/2026-03-10-subminer-scrum-master-design.md` capturing the approved contract, backlog decision rules, orchestration policy, and verification handoff.
|
||||||
|
2. Create the repo-local skill at `.agents/skills/subminer-scrum-master/` with a concise `SKILL.md`.
|
||||||
|
3. Keep v1 instruction-heavy: backlog-or-not decision first, search/create/update task structure when needed, require planning before dispatch, use parent + subtasks for multi-part work, dispatch conservatively with explicit ownership, and require `subminer-change-verification` before handoff.
|
||||||
|
4. Include representative flows for trivial no-ticket work, single-task implementation, and multi-part parent+subtask execution.
|
||||||
|
5. Verify the skill in-repo with one representative request flow and update `TASK-160` with results.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
V1 will be instruction-heavy rather than script-heavy. The skill will decide whether backlog is warranted, record plans before dispatch, create parent+subtasks when needed, dispatch conservatively with explicit ownership, and require `subminer-change-verification` before handoff.
|
||||||
|
|
||||||
|
2026-03-10: Added design doc at docs/plans/2026-03-10-subminer-scrum-master-design.md and created the repo-local skill at .agents/skills/subminer-scrum-master/.
|
||||||
|
|
||||||
|
2026-03-10: Verified the skill against a representative request flow ('Fix launcher auto-start pause bug and make sure it is verified') by checking that the instructions cover backlog decisioning, planning-before-dispatch, single-task execution, explicit worker ownership, and verification via subminer-change-verification.
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
Implemented a repo-local `subminer-scrum-master` skill that assesses whether backlog tracking is needed, manages task structure and planning when appropriate, dispatches subagents conservatively, and requires verification before handoff. Verified the skill in-repo against a representative launcher bug workflow.
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
id: TASK-161
|
||||||
|
title: Add Arch Linux PKGBUILD and .SRCINFO for SubMiner release artifacts
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-11 07:50'
|
||||||
|
updated_date: '2026-03-11 07:56'
|
||||||
|
labels:
|
||||||
|
- packaging
|
||||||
|
- linux
|
||||||
|
- docs
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- package.json
|
||||||
|
- .github/workflows/release.yml
|
||||||
|
- README.md
|
||||||
|
documentation:
|
||||||
|
- docs-site/development.md
|
||||||
|
- docs-site/installation.md
|
||||||
|
- docs/RELEASING.md
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Add repo-maintained Arch packaging metadata so Arch/AUR users can install the packaged SubMiner release artifacts without relying on npm. Cover the binary package flow that matches the current GitHub Releases distribution model and document the install path for Arch users.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [x] #1 A dedicated Arch packaging directory exists with a PKGBUILD and matching .SRCINFO for the SubMiner binary release flow.
|
||||||
|
- [x] #2 The package installs the shipped Linux release artifact and wrapper in paths consistent with current runtime auto-detection expectations.
|
||||||
|
- [x] #3 Package metadata declares the required Arch runtime dependencies for the packaged workflow.
|
||||||
|
- [x] #4 The packaging files remain isolated from the main app/release/docs surfaces so they can be moved to a separate repository later.
|
||||||
|
- [x] #5 The packaging metadata is validated with an appropriate local Arch packaging check or an explicitly documented limitation if the tool is unavailable in this environment.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
1. Add isolated Arch packaging under packaging/arch/subminer-bin for the binary release flow that matches current GitHub Releases artifacts.
|
||||||
|
2. Install the Linux AppImage to /opt/SubMiner/SubMiner.AppImage, add PATH symlinks for SubMiner.AppImage and subminer, and ship optional plugin/theme/config assets under /usr/share/subminer.
|
||||||
|
3. Generate and commit matching .SRCINFO metadata in the same packaging directory.
|
||||||
|
4. Validate the PKGBUILD metadata locally with shell parsing plus makepkg --printsrcinfo and namcap if available.
|
||||||
|
5. Leave the new files isolated so they can be moved to a separate packaging repository later.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
User requested no commit and no broad repo integration; keep the Arch packaging files isolated in a dedicated directory for later extraction.
|
||||||
|
|
||||||
|
Created isolated Arch packaging under packaging/arch/subminer-bin with PKGBUILD and generated .SRCINFO only; no docs or release workflow changes.
|
||||||
|
|
||||||
|
Validation run: bash -n PKGBUILD, makepkg --printsrcinfo > .SRCINFO, namcap PKGBUILD.
|
||||||
|
|
||||||
|
PKGBUILD uses current v0.5.6 GitHub release assets and recorded SHA-256 values for SubMiner-0.5.6.AppImage, subminer, and subminer-assets.tar.gz.
|
||||||
|
|
||||||
|
Per user follow-up, moved packaging/arch/subminer-bin out of the repo to /home/sudacode/packages/maintaining/subminer-bin for separate maintenance. Repo docs/workflows were still left untouched.
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
Added an isolated Arch Linux packaging directory at packaging/arch/subminer-bin containing a `subminer-bin` PKGBUILD and generated `.SRCINFO`. The package installs the current GitHub release AppImage to `/opt/SubMiner/SubMiner.AppImage`, adds PATH access for `SubMiner.AppImage` and `subminer`, and ships optional plugin/theme/config assets under `/usr/share/subminer`. Verified locally with `bash -n PKGBUILD`, `makepkg --printsrcinfo`, and `namcap PKGBUILD`.
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
---
|
||||||
|
id: TASK-162
|
||||||
|
title: Normalize packaged Linux paths to canonical SubMiner directories
|
||||||
|
status: In Progress
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-11 08:28'
|
||||||
|
updated_date: '2026-03-11 08:29'
|
||||||
|
labels:
|
||||||
|
- linux
|
||||||
|
- packaging
|
||||||
|
- docs
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- launcher/mpv.ts
|
||||||
|
- launcher/picker.ts
|
||||||
|
- plugin/subminer/binary.lua
|
||||||
|
- plugin/subminer.conf
|
||||||
|
- docs-site/installation.md
|
||||||
|
- docs-site/launcher-script.md
|
||||||
|
- README.md
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Align packaged Linux path conventions so system-installed assets use canonical `SubMiner` directories and match runtime auto-detection. Cover AppImage binary discovery, rofi theme discovery/docs, and related path references while preserving lowercase names only for the launcher wrapper, rofi theme filename, and mpv Lua plugin/conf.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 Launcher/runtime path discovery prefers canonical packaged Linux locations that use `SubMiner` casing for shared data and config directories.
|
||||||
|
- [ ] #2 Tests cover the expected packaged Linux discovery paths for the AppImage and rofi theme search behavior.
|
||||||
|
- [ ] #3 User-facing docs reference the canonical packaged Linux locations consistently.
|
||||||
|
- [ ] #4 Lowercase names remain only where intentionally required for the launcher wrapper, rofi theme filename, and mpv Lua plugin/conf.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
1. Add failing launcher tests for canonical packaged Linux discovery paths: /usr/lib/subminer/SubMiner.AppImage via PATH symlink flow and /usr/share/SubMiner/themes/subminer.rasi for rofi theme lookup.
|
||||||
|
2. Update launcher runtime path discovery to prefer canonical packaged Linux shared-data locations using SubMiner casing.
|
||||||
|
3. Update plugin auto-detection comments and binary search defaults so packaged Linux paths stay consistent with launcher/runtime expectations.
|
||||||
|
4. Update user-facing docs to reference canonical SubMiner-cased config/share paths while keeping lowercase names only for the launcher wrapper, rofi theme filename, and mpv Lua plugin/conf.
|
||||||
|
5. Run targeted launcher tests plus docs checks.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
id: TASK-163
|
||||||
|
title: 'Resolve current lint, format, and style check failures'
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- Codex
|
||||||
|
created_date: '2026-03-11 08:48'
|
||||||
|
updated_date: '2026-03-11 08:49'
|
||||||
|
labels:
|
||||||
|
- maintenance
|
||||||
|
- tooling
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/package.json
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/docs-site/development.md
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/docs-site/architecture.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Run the repo's maintained static/style gates, fix any failures they report, and leave the working tree with those checks passing without disturbing unrelated in-progress work.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [x] #1 The repo's maintained static/style commands for this cleanup are identified and recorded.
|
||||||
|
- [x] #2 Any failures from those commands are fixed in-scope in the codebase.
|
||||||
|
- [x] #3 The same static/style commands pass after the fixes.
|
||||||
|
- [x] #4 Verification results and any skipped checks are documented before handoff.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
1. Run the maintained static/style gates for this repo: `bun run typecheck` and `bun run format:check:src`.
|
||||||
|
2. Inspect each failure and patch only the files implicated by the failing command, preserving unrelated user changes.
|
||||||
|
3. Re-run the failing gate after each fix until both commands pass.
|
||||||
|
4. Run one final consolidated verification pass, record exact commands/results, and note any intentionally skipped broader gates outside lint/style scope.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
Identified maintained commands from repo docs/scripts: `bun run typecheck` and `bun run format:check:src`. `changelog:lint` exists but is release-fragment specific, not a general lint/style gate for this request.
|
||||||
|
|
||||||
|
Ran `bun run typecheck` at 2026-03-11 01:48 PDT: passed.
|
||||||
|
|
||||||
|
Ran `bun run format:check:src` at 2026-03-11 01:48 PDT: failed on `src/release-workflow.test.ts`.
|
||||||
|
|
||||||
|
Applied a scoped Prettier rewrite with `./node_modules/.bin/prettier --write src/release-workflow.test.ts`.
|
||||||
|
|
||||||
|
Re-ran `bun run format:check:src` at 2026-03-11 01:49 PDT: passed.
|
||||||
|
|
||||||
|
Re-ran `bun run typecheck` at 2026-03-11 01:49 PDT: passed.
|
||||||
|
|
||||||
|
Skipped broader test/build/docs gates because the user asked specifically for lint/format/style cleanup and the only required change was a formatting-only update in one test file.
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
Resolved the repo's current static/style failure by reformatting `src/release-workflow.test.ts` to match the maintained Prettier scope. The only code change was line wrapping in the `generate:config-example` assertion; behavior did not change.
|
||||||
|
|
||||||
|
Verification run:
|
||||||
|
- `bun run typecheck`
|
||||||
|
- `bun run format:check:src`
|
||||||
|
- `./node_modules/.bin/prettier --write src/release-workflow.test.ts`
|
||||||
|
- `bun run format:check:src`
|
||||||
|
- `bun run typecheck`
|
||||||
|
|
||||||
|
Result: both maintained gates requested for this cleanup now pass. Broader build/test/docs lanes were intentionally not run because this task was limited to lint/format/style checks and required a formatting-only fix.
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
id: TASK-164
|
||||||
|
title: Run maintained test gate and fix failing regressions
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- Codex
|
||||||
|
created_date: '2026-03-11 08:52'
|
||||||
|
updated_date: '2026-03-11 08:54'
|
||||||
|
labels:
|
||||||
|
- maintenance
|
||||||
|
- testing
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/package.json
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/docs-site/development.md
|
||||||
|
- /home/sudacode/projects/japanese/SubMiner/docs-site/architecture.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Execute the repo's maintained test verification flow, fix any regressions surfaced by those commands, and leave the requested test gate passing without disturbing unrelated in-progress work.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [x] #1 The maintained test commands chosen for this pass are recorded in the task plan.
|
||||||
|
- [x] #2 Any test failures encountered in that gate are fixed in-scope with appropriate regression coverage when needed.
|
||||||
|
- [x] #3 The same maintained test gate passes after the fixes.
|
||||||
|
- [x] #4 Verification results, skips, and remaining risks are documented before handoff.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
1. Run the maintained verification gate documented for local handoff: `bun run test:fast`, `bun run test:env`, `bun run build`, and `bun run test:smoke:dist`.
|
||||||
|
2. Stop at the first failing command, inspect the exact failure, and use a red/green loop with the smallest targeted failing test before writing any production-code fix.
|
||||||
|
3. Re-run the targeted failing test, then the original failing command, and continue through the remaining gate.
|
||||||
|
4. Record results, any skips, and residual risks before handoff.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
Using the docs-site recommended local gate as the maintained test/build verification flow for this request.
|
||||||
|
|
||||||
|
Ran `bun run test:fast` at 2026-03-11 01:52 PDT: passed.
|
||||||
|
|
||||||
|
Ran `bun run test:env` at 2026-03-11 01:53 PDT: passed.
|
||||||
|
|
||||||
|
Ran `bun run build` at 2026-03-11 01:53 PDT: passed.
|
||||||
|
|
||||||
|
Ran `bun run test:smoke:dist` at 2026-03-11 01:53 PDT: passed.
|
||||||
|
|
||||||
|
No failing tests surfaced in the maintained gate, so no production-code or test changes were required in this pass.
|
||||||
|
|
||||||
|
Working tree still includes unrelated user edits plus the previously-applied formatting change in `src/release-workflow.test.ts`; this task did not add new source changes.
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
Executed the repo's maintained local verification gate from the development docs: `bun run test:fast`, `bun run test:env`, `bun run build`, and `bun run test:smoke:dist`.
|
||||||
|
|
||||||
|
Result: every command passed. No failing tests surfaced, so no additional fixes or new regression tests were required for this task.
|
||||||
|
|
||||||
|
Working tree note: existing unrelated user changes remain in place, along with the prior formatting-only change to `src/release-workflow.test.ts` from TASK-163. This task introduced no new code changes.
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
---
|
||||||
|
id: TASK-165
|
||||||
|
title: Automate AUR publish on tagged releases
|
||||||
|
status: Done
|
||||||
|
assignee:
|
||||||
|
- codex
|
||||||
|
created_date: '2026-03-14 15:55'
|
||||||
|
updated_date: '2026-03-14 18:40'
|
||||||
|
labels:
|
||||||
|
- release
|
||||||
|
- packaging
|
||||||
|
- linux
|
||||||
|
dependencies:
|
||||||
|
- TASK-161
|
||||||
|
references:
|
||||||
|
- .github/workflows/release.yml
|
||||||
|
- src/release-workflow.test.ts
|
||||||
|
- docs/RELEASING.md
|
||||||
|
- packaging/aur/subminer-bin/PKGBUILD
|
||||||
|
documentation:
|
||||||
|
- docs/plans/2026-03-14-aur-release-sync-design.md
|
||||||
|
- docs/plans/2026-03-14-aur-release-sync.md
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Extend the tagged release workflow so a successful GitHub release automatically updates the `subminer-bin` AUR package over SSH. Keep the PKGBUILD source-of-truth in this repo so release automation is reviewable and testable instead of depending on an external maintainer checkout.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [x] #1 Repo-tracked AUR packaging source exists for `subminer-bin` and matches the current release artifact layout.
|
||||||
|
- [x] #2 The release workflow clones `ssh://aur@aur.archlinux.org/subminer-bin.git` with a dedicated secret-backed SSH key only after release artifacts are ready.
|
||||||
|
- [x] #3 The workflow updates `pkgver`, regenerates `sha256sums` from the built release artifacts, regenerates `.SRCINFO`, and pushes only when packaging files changed.
|
||||||
|
- [x] #4 Regression coverage fails if the AUR publish job, secret contract, or update steps are removed from the release workflow.
|
||||||
|
- [x] #5 Release docs mention the required `AUR_SSH_PRIVATE_KEY` setup and the new tagged-release side effect.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
1. Record the approved design and implementation plan for direct AUR publishing from the release workflow.
|
||||||
|
2. Add failing release workflow regression tests covering the new AUR publish job, SSH secret, and PKGBUILD/.SRCINFO regeneration steps.
|
||||||
|
3. Reintroduce repo-tracked `packaging/aur/subminer-bin` source files as the maintained AUR template.
|
||||||
|
4. Add a small helper script that updates `pkgver`, computes checksums from release artifacts, and regenerates `.SRCINFO` deterministically.
|
||||||
|
5. Extend `.github/workflows/release.yml` with an AUR publish job that clones the AUR repo over SSH, runs the helper, commits only when needed, and pushes to `aur`.
|
||||||
|
6. Update release docs for the new secret/setup requirements and tagged-release behavior.
|
||||||
|
7. Run targeted workflow tests plus the SubMiner verification lane needed for workflow/docs changes, then update this task with results.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
Added repo-tracked AUR packaging source under `packaging/aur/subminer-bin/` plus `scripts/update-aur-package.sh` to stamp `pkgver`, compute SHA-256 sums from release assets, and regenerate `.SRCINFO` with `makepkg --printsrcinfo`.
|
||||||
|
|
||||||
|
Extended `.github/workflows/release.yml` with a terminal `aur-publish` job that runs after `release`, validates `AUR_SSH_PRIVATE_KEY`, installs `makepkg`, configures SSH/known_hosts, clones `ssh://aur@aur.archlinux.org/subminer-bin.git`, downloads the just-published `SubMiner-<version>.AppImage`, `subminer`, and `subminer-assets.tar.gz` assets, updates packaging metadata, and pushes only when `PKGBUILD` or `.SRCINFO` changed.
|
||||||
|
|
||||||
|
Updated `src/release-workflow.test.ts` with regression assertions for the AUR publish contract and updated `docs/RELEASING.md` with the new secret/setup requirement.
|
||||||
|
|
||||||
|
Verification run:
|
||||||
|
- `bun test src/release-workflow.test.ts src/ci-workflow.test.ts`
|
||||||
|
- `bash -n scripts/update-aur-package.sh && bash -n packaging/aur/subminer-bin/PKGBUILD`
|
||||||
|
- `cd packaging/aur/subminer-bin && makepkg --printsrcinfo > .SRCINFO`
|
||||||
|
- updater smoke via temp package dir with fake assets and `v9.9.9`
|
||||||
|
- `bun run typecheck`
|
||||||
|
- `bun run test:fast`
|
||||||
|
- `bun run test:env`
|
||||||
|
- `git submodule update --init --recursive` (required because the worktree lacked release submodules)
|
||||||
|
- `bun run build`
|
||||||
|
- `bun run test:smoke:dist`
|
||||||
|
|
||||||
|
Docs update required: yes, completed in `docs/RELEASING.md`.
|
||||||
|
Changelog fragment required: no; internal release automation only.
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
Tagged releases now attempt a direct AUR sync for `subminer-bin` using a dedicated SSH private key stored in `AUR_SSH_PRIVATE_KEY`. The release workflow clones the AUR repo after GitHub Release publication, rewrites `PKGBUILD` and `.SRCINFO` from the published release assets, and skips empty pushes. Repo-owned packaging source and workflow regression coverage were added so the automation remains reviewable and testable.
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
---
|
||||||
|
id: TASK-165
|
||||||
|
title: Make controller configuration easier with inline remapping modal
|
||||||
|
status: To Do
|
||||||
|
assignee:
|
||||||
|
- Codex
|
||||||
|
created_date: '2026-03-13 00:10'
|
||||||
|
updated_date: '2026-03-13 00:10'
|
||||||
|
labels:
|
||||||
|
- enhancement
|
||||||
|
- renderer
|
||||||
|
- overlay
|
||||||
|
- input
|
||||||
|
- config
|
||||||
|
dependencies:
|
||||||
|
- TASK-159
|
||||||
|
references:
|
||||||
|
- src/renderer/modals/controller-select.ts
|
||||||
|
- src/renderer/modals/controller-debug.ts
|
||||||
|
- src/renderer/handlers/gamepad-controller.ts
|
||||||
|
- src/renderer/index.html
|
||||||
|
- src/renderer/style.css
|
||||||
|
- src/renderer/utils/dom.ts
|
||||||
|
- src/preload.ts
|
||||||
|
- src/core/services/ipc.ts
|
||||||
|
- src/main.ts
|
||||||
|
- src/types.ts
|
||||||
|
- src/config/definitions/defaults-core.ts
|
||||||
|
- src/config/definitions/options-core.ts
|
||||||
|
- config.example.jsonc
|
||||||
|
- docs/plans/2026-03-13-overlay-controller-config-remap-design.md
|
||||||
|
- docs/plans/2026-03-13-overlay-controller-config-remap.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Replace the current controller-selection-only modal with a denser controller configuration surface that keeps device selection and adds inline controller remapping. The new flow should feel like emulator configuration: pick an overlay action, arm capture, then press the matching controller button, trigger, d-pad direction, or stick direction to bind it. Keep the current overlay-local renderer architecture, preserve controller gating to keyboard-only mode, and retain the separate raw debug modal for troubleshooting.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 `Alt+C` opens a controller modal that includes both preferred-controller selection and controller-config editing in one surface.
|
||||||
|
- [ ] #2 Controller device selection uses a compact dropdown or equivalent compact picker instead of the current full-height device list.
|
||||||
|
- [ ] #3 Each remappable controller action shows its current binding and supports learn/capture, clear, and reset-to-default flows.
|
||||||
|
- [ ] #4 Learn mode captures the next fresh controller input edge or stick/d-pad direction, not a held/stale input.
|
||||||
|
- [ ] #5 Captured bindings can represent non-standard controllers without depending only on the browser's standard semantic button names.
|
||||||
|
- [ ] #6 Updated bindings persist through the existing config pipeline and take effect in the renderer without restart unless a field explicitly requires reopen/reload.
|
||||||
|
- [ ] #7 Existing controller behavior remains gated to keyboard-only mode except for the controller action that toggles keyboard-only mode itself.
|
||||||
|
- [ ] #8 Renderer/config/IPC regression tests cover the new modal layout, capture flow, persistence, and runtime mapping behavior.
|
||||||
|
- [ ] #9 Docs/config example explain the new controller-config flow and when to use the debug modal.
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
1. Add the design doc and implementation plan for inline controller remapping, tied to a new backlog task instead of reopening the already-completed base controller-support task.
|
||||||
|
2. Expand controller config types/defaults/template output so action bindings can store captured input descriptors, not only semantic button-name enums.
|
||||||
|
3. Extend preload/main/IPC write paths from preferred-controller-only saves to full controller-config patching needed by the modal.
|
||||||
|
4. Redesign the controller modal UI into a compact device picker plus action-binding editor with learn, clear, and reset affordances.
|
||||||
|
5. Add renderer capture state and a learn-mode runtime that waits for neutral-to-active transitions before saving a binding.
|
||||||
|
6. Update the gamepad runtime to resolve the new stored descriptors into actions while preserving current gating and repeat/deadzone behavior.
|
||||||
|
7. Keep the raw debug modal as a separate advanced surface; optionally expose copyable input-descriptor text for troubleshooting.
|
||||||
|
8. Add focused regression tests first, then run the maintained gate needed for docs/config/renderer/main changes.
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
<!-- SECTION:NOTES:BEGIN -->
|
||||||
|
Planning only in this pass.
|
||||||
|
|
||||||
|
Current-state findings:
|
||||||
|
|
||||||
|
- `src/renderer/modals/controller-select.ts` only persists `preferredGamepadId` / `preferredGamepadLabel`.
|
||||||
|
- `src/preload.ts`, `src/core/services/ipc.ts`, and `src/main.ts` only expose a narrow save path for preferred controller, not general controller config writes.
|
||||||
|
- `src/renderer/handlers/gamepad-controller.ts` currently resolves actions from semantic button bindings plus a few axis slots; this is fine for defaults but too narrow for emulator-style learn mode on non-standard controllers.
|
||||||
|
- `src/renderer/modals/controller-debug.ts` already provides the raw input surface needed for troubleshooting and for validating capture behavior.
|
||||||
|
|
||||||
|
Recommended direction:
|
||||||
|
|
||||||
|
- keep `Alt+C` as the single controller-config entrypoint
|
||||||
|
- keep `Alt+Shift+C` as raw debug
|
||||||
|
- introduce stored input descriptors for discrete bindings so learn mode can capture buttons, triggers, d-pad directions, and stick directions directly
|
||||||
|
- defer per-controller profiles; keep one global binding set plus preferred-controller selection for this pass
|
||||||
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|
||||||
|
## Final Summary
|
||||||
|
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||||
|
Planned follow-up work to make controller configuration materially easier than the current “pick preferred device” modal. The proposed change keeps existing controller runtime/debug foundations, but upgrades the selection modal into a compact controller-config surface with inline learn-mode remapping and persistent binding storage.
|
||||||
|
|
||||||
|
Main architectural change in scope: move from semantic-button-only binding storage toward captured input descriptors so the UI can reliably learn from buttons, triggers, d-pad directions, and stick directions on non-standard controllers.
|
||||||
|
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user