From fe21c7edbbf7df65498f647b5d4a45c5dcc10fc6 Mon Sep 17 00:00:00 2001 From: YoungjaeDev Date: Tue, 28 Jul 2026 14:26:50 +0900 Subject: [PATCH 1/3] fix(ml-toolkit,ppt-yeong-style,project-init): close the macOS portability remainder ml-toolkit: python -> python3 in the three places it is resolved from PATH. environment-setup.md:318 is the one that mattered -- `python -m venv .venv` runs BEFORE the venv is activated, so it resolves against the system PATH, and macOS 12.3 removed /usr/bin/python; the block labels itself "# Linux/Mac", so a Mac reader following it could not create the environment at all. Lines 329 and 348 run after activation and are deliberately left alone. The gpu-parallel-pipeline call site and check_gpu_memory.py's shebang + usage docstring follow for consistency; those two only change the error message, since the script exits on torch.cuda.is_available() anyway. ppt-yeong-style: render-qa.sh iterated grep -REl output with `for f in $b_hits`, which word-splits on IFS and glob-expands. Reproduced with a spaced DECK_ROOT: "/tmp/qa test/svg_output/P03.svg" arrived as "/tmp/qa (0)" and "test/svg_output/P03.svg (0)" -- two half-paths whose grep failed into a discarded stderr. Now newline-bounded, giving the whole path and a real count. The gate verdict was never affected (fail=1 is set before this loop); this is the report the user reads to locate the leak. Not macOS-specific. project-init: backported cr-fix's cache resolver, which fixes two independent defects. The fallback was a plain lexicographic sort, so 0.6.1 outranked 0.10.0 and the resolver would pick an older cached version once a component reached two digits. Sorting the full path is worse and is not what the audit found: measured with zeta/0.4.0 against alpha/0.10.0, both plain sort AND sort -V pick zeta/0.4.0, because the marketplace directory name is compared before the version ever is. Prefixing the basename as the sort key closes both. The comment claiming macOS lacks sort -V is also wrong -- Apple's FreeBSD sort has had it since 10.13 -- and it was being used to justify the lexicographic fallback, so the reasoning is corrected while the capability probe stays for older userlands. Also in project-init: gh-repo-create-flow.md used ${VISIBILITY,,} twice, a Bash 4 expansion that is a bad substitution on macOS /bin/bash 3.2. Replaced with the POSIX to_lower + case token match the executable procedure already uses, so the raw answer is never passed straight into a CLI flag. And HAS_CODE was built with `| head -1 | wc -l`, which BSD wc right-pads; it now returns yes/no like the HAS_GIT and HAS_CLAUDE lines beside it, and stops at the first match. Closes #177 Closes #178 Closes #179 --- .claude-plugin/marketplace.json | 8 +++--- plugins/ml-toolkit/.claude-plugin/plugin.json | 2 +- plugins/ml-toolkit/.codex-plugin/plugin.json | 2 +- plugins/ml-toolkit/plugin.yaml | 2 +- .../references/environment-setup.md | 2 +- .../skills/gpu-parallel-pipeline/SKILL.md | 2 +- .../scripts/check_gpu_memory.py | 6 ++-- .../.claude-plugin/plugin.json | 2 +- .../ppt-yeong-style/.codex-plugin/plugin.json | 2 +- plugins/ppt-yeong-style/plugin.yaml | 2 +- .../skills/lecture-deck/scripts/render-qa.sh | 9 +++++- .../project-init/.claude-plugin/plugin.json | 2 +- .../project-init/.codex-plugin/plugin.json | 2 +- .../references/gh-repo-create-flow.md | 28 +++++++++++++++++-- .../project-init/references/new-procedure.md | 23 ++++++++++----- 15 files changed, 67 insertions(+), 27 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index b7738663..b0820018 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -5,7 +5,7 @@ }, "metadata": { "description": "Personal Claude Code plugin collection with 24 specialized plugins. Codex 0.135 + Hermes Agent native — generated `.agents/plugins/marketplace.json` + per-plugin `.codex-plugin/plugin.json` (`scripts/sync-codex-manifests.mjs`) and Hermes `plugin.yaml` + `__init__.py` adapters (`scripts/sync-hermes-manifests.mjs`).", - "version": "2.7.2" + "version": "2.7.3" }, "plugins": [ { @@ -61,7 +61,7 @@ "name": "ml-toolkit", "source": "./plugins/ml-toolkit", "description": "ML/multimodal development principles, GPU parallel processing, Gradio CV apps, CV notebook generation, interactive CV data exploration", - "version": "1.4.3", + "version": "1.4.4", "category": "development" }, { @@ -124,7 +124,7 @@ "name": "project-init", "source": "./plugins/project-init", "description": "Agent-harness project lifecycle. `new` — one-shot first-day bootstrap (interview, .claude/ scaffold, minimal CLAUDE.md, AGENTS.md with Codex GitHub cloud reviewer guidelines in general/ml/web variants, README/CHANGELOG seed, gh repo create + initial push) behind a hardened preflight guard that refuses a non-empty cwd. `wiring` — its inverse for existing repos: a read-only 14-axis setup diagnostic (FAIL / WARN / ASK / INFO / SKIP / OK) covering guidance files, .claude/rules paths: scoping defeated by @import, llm-wiki layout + staging backlog, Serena onboarding, memory posture, MCP duplicate registration, Codex CLI posture + AGENTS.md byte budget, spec homes, gws-sync, .tmp, core.hooksPath, .gitignore coverage. ASK answers persist to .claude/state/wiring.json. Shared read-only detector: scripts/project_state.sh.", - "version": "0.6.1", + "version": "0.6.2", "category": "planning" }, { @@ -152,7 +152,7 @@ "name": "ppt-yeong-style", "source": "./plugins/ppt-yeong-style", "description": "yeong 스타일 강의·제안 덱 작성 규약 — ppt-master 빌드 엔진 위에 얹는 작성 레이어(엔진 자체가 아님). 스킬 3종: 메인 ppt-yeong-style(미감 시그니처 §0 'Editorial restraint, one committed accent'·md 소스 규약·작성 원칙 16종·밀도 리듬·역할 기반 색·codex-image vs SVG 경계·앱 UI 실물 강제·레버 조합 차별화·윤문·렌더 QA + references/ 6종 + 주입 페이로드) + lecture-deck(강의 덱 운영 — 실습 handouts 생성 규약·프롬프트 카드·placeholder→실캡처 스크린샷 슬롯·리넘버링 4중 동기화·전사 회고 루프·강사 노트 태그 + cc-common 47장 레퍼런스) + deck-review(관점별 리뷰 서브에이전트 4종 audience-fit·story-flow·fact-check·design-qa 병렬 오케스트레이션 + codex:rescue 교차 리뷰, 페르소나는 파라미터). 의존 스킬은 있으면 사용, 없으면 생략 + 설치 제안 문구(ppt-master만 prerequisite-stop). ppt-master로 그냥 'PPT 만들기'와 달리 yeong 규약이 필요할 때.", - "version": "0.9.3", + "version": "0.9.4", "category": "design" }, { diff --git a/plugins/ml-toolkit/.claude-plugin/plugin.json b/plugins/ml-toolkit/.claude-plugin/plugin.json index d6b838cf..f68c5783 100644 --- a/plugins/ml-toolkit/.claude-plugin/plugin.json +++ b/plugins/ml-toolkit/.claude-plugin/plugin.json @@ -1,5 +1,5 @@ { "name": "ml-toolkit", - "version": "1.4.3", + "version": "1.4.4", "description": "ML/multimodal development principles, GPU parallel processing, Gradio CV apps, CV notebook generation, interactive CV data exploration" } diff --git a/plugins/ml-toolkit/.codex-plugin/plugin.json b/plugins/ml-toolkit/.codex-plugin/plugin.json index d6a28d1f..f840ca3d 100644 --- a/plugins/ml-toolkit/.codex-plugin/plugin.json +++ b/plugins/ml-toolkit/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "ml-toolkit", - "version": "1.4.3", + "version": "1.4.4", "description": "ML/multimodal development principles, GPU parallel processing, Gradio CV apps, CV notebook generation, interactive CV data exploration", "author": { "name": "YoungjaeDev" diff --git a/plugins/ml-toolkit/plugin.yaml b/plugins/ml-toolkit/plugin.yaml index 4ed8859a..b336920e 100644 --- a/plugins/ml-toolkit/plugin.yaml +++ b/plugins/ml-toolkit/plugin.yaml @@ -1,5 +1,5 @@ name: ml-toolkit -version: "1.4.3" +version: "1.4.4" description: "ML/multimodal development principles, GPU parallel processing, Gradio CV apps, CV notebook generation, interactive CV data exploration" author: "YoungjaeDev" kind: standalone diff --git a/plugins/ml-toolkit/skills/cv-notebook/references/environment-setup.md b/plugins/ml-toolkit/skills/cv-notebook/references/environment-setup.md index 0295aedf..9dc28cba 100644 --- a/plugins/ml-toolkit/skills/cv-notebook/references/environment-setup.md +++ b/plugins/ml-toolkit/skills/cv-notebook/references/environment-setup.md @@ -315,7 +315,7 @@ HF_HOME=/path/to/huggingface/cache #### Using venv ```bash # Create virtual environment -python -m venv .venv +python3 -m venv .venv # Activate source .venv/bin/activate # Linux/Mac diff --git a/plugins/ml-toolkit/skills/gpu-parallel-pipeline/SKILL.md b/plugins/ml-toolkit/skills/gpu-parallel-pipeline/SKILL.md index f90103f7..e1a787ec 100644 --- a/plugins/ml-toolkit/skills/gpu-parallel-pipeline/SKILL.md +++ b/plugins/ml-toolkit/skills/gpu-parallel-pipeline/SKILL.md @@ -127,7 +127,7 @@ else SKILL_DIR="$HOME/.hermes/plugins/ml-toolkit/skills/gpu-parallel-pipeline" # Hermes default install fi [ -d "$SKILL_DIR" ] || { echo "gpu-parallel-pipeline: skill dir not resolved" >&2; exit 1; } -python "$SKILL_DIR/scripts/check_gpu_memory.py" +python3 "$SKILL_DIR/scripts/check_gpu_memory.py" ``` **Rule of thumb:** diff --git a/plugins/ml-toolkit/skills/gpu-parallel-pipeline/scripts/check_gpu_memory.py b/plugins/ml-toolkit/skills/gpu-parallel-pipeline/scripts/check_gpu_memory.py index 79556b92..dd0c749c 100644 --- a/plugins/ml-toolkit/skills/gpu-parallel-pipeline/scripts/check_gpu_memory.py +++ b/plugins/ml-toolkit/skills/gpu-parallel-pipeline/scripts/check_gpu_memory.py @@ -1,11 +1,11 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """GPU memory check utility for parallel pipeline planning. Reports available GPU memory and recommends workers per GPU based on model size. Usage: - python check_gpu_memory.py - python check_gpu_memory.py --model-memory 5.0 # Specify model memory in GB + python3 check_gpu_memory.py + python3 check_gpu_memory.py --model-memory 5.0 # Specify model memory in GB """ from __future__ import annotations diff --git a/plugins/ppt-yeong-style/.claude-plugin/plugin.json b/plugins/ppt-yeong-style/.claude-plugin/plugin.json index e9c85feb..3d1ec1cb 100644 --- a/plugins/ppt-yeong-style/.claude-plugin/plugin.json +++ b/plugins/ppt-yeong-style/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "ppt-yeong-style", - "version": "0.9.3", + "version": "0.9.4", "description": "yeong 스타일 강의·제안 덱 작성 규약 — ppt-master 빌드 엔진 위에 얹는 작성 레이어(엔진 자체가 아님). 스킬 3종: 메인 ppt-yeong-style(미감 시그니처 §0 'Editorial restraint, one committed accent'·md 소스 규약·작성 원칙 16종·밀도 리듬·역할 기반 색·codex-image vs SVG 경계·앱 UI 실물 강제·레버 조합 차별화·윤문·렌더 QA + references/ 6종 + 주입 페이로드) + lecture-deck(강의 덱 운영 — 실습 handouts 생성 규약·프롬프트 카드·placeholder→실캡처 스크린샷 슬롯·리넘버링 4중 동기화·전사 회고 루프·강사 노트 태그 + cc-common 47장 레퍼런스) + deck-review(관점별 리뷰 서브에이전트 4종 audience-fit·story-flow·fact-check·design-qa 병렬 오케스트레이션 + codex:rescue 교차 리뷰, 페르소나는 파라미터). 의존 스킬은 있으면 사용, 없으면 생략 + 설치 제안 문구(ppt-master만 prerequisite-stop). ppt-master로 그냥 'PPT 만들기'와 달리 yeong 규약이 필요할 때.", "skills": [ "./skills/ppt-yeong-style", diff --git a/plugins/ppt-yeong-style/.codex-plugin/plugin.json b/plugins/ppt-yeong-style/.codex-plugin/plugin.json index 21bc3013..7a12b7c3 100644 --- a/plugins/ppt-yeong-style/.codex-plugin/plugin.json +++ b/plugins/ppt-yeong-style/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "ppt-yeong-style", - "version": "0.9.3", + "version": "0.9.4", "description": "yeong 스타일 강의·제안 덱 작성 규약 — ppt-master 빌드 엔진 위에 얹는 작성 레이어(엔진 자체가 아님). 스킬 3종: 메인 ppt-yeong-style(미감 시그니처 §0 'Editorial restraint, one committed accent'·md 소스 규약·작성 원칙 16종·밀도 리듬·역할 기반 색·codex-image vs SVG 경계·앱 UI 실물 강제·레버 조합 차별화·윤문·렌더 QA + references/ 6종 + 주입 페이로드) + lecture-deck(강의 덱 운영 — 실습 handouts 생성 규약·프롬프트 카드·placeholder→실캡처 스크린샷 슬롯·리넘버링 4중 동기화·전사 회고 루프·강사 노트 태그 + cc-common 47장 레퍼런스) + deck-review(관점별 리뷰 서브에이전트 4종 audience-fit·story-flow·fact-check·design-qa 병렬 오케스트레이션 + codex:rescue 교차 리뷰, 페르소나는 파라미터). 의존 스킬은 있으면 사용, 없으면 생략 + 설치 제안 문구(ppt-master만 prerequisite-stop). ppt-master로 그냥 'PPT 만들기'와 달리 yeong 규약이 필요할 때.", "author": { "name": "YoungjaeDev" diff --git a/plugins/ppt-yeong-style/plugin.yaml b/plugins/ppt-yeong-style/plugin.yaml index 859945c9..25692c8a 100644 --- a/plugins/ppt-yeong-style/plugin.yaml +++ b/plugins/ppt-yeong-style/plugin.yaml @@ -1,5 +1,5 @@ name: ppt-yeong-style -version: "0.9.3" +version: "0.9.4" description: "yeong 스타일 강의·제안 덱 작성 규약 — ppt-master 빌드 엔진 위에 얹는 작성 레이어(엔진 자체가 아님). 스킬 3종: 메인 ppt-yeong-style(미감 시그니처 §0 'Editorial restraint, one committed accent'·md 소스 규약·작성 원칙 16종·밀도 리듬·역할 기반 색·codex-image vs SVG 경계·앱 UI 실물 강제·레버 조합 차별화·윤문·렌더 QA + references/ 6종 + 주입 페이로드) + lecture-deck(강의 덱 운영 — 실습 handouts 생성 규약·프롬프트 카드·placeholder→실캡처 스크린샷 슬롯·리넘버링 4중 동기화·전사 회고 루프·강사 노트 태그 + cc-common 47장 레퍼런스) + deck-review(관점별 리뷰 서브에이전트 4종 audience-fit·story-flow·fact-check·design-qa 병렬 오케스트레이션 + codex:rescue 교차 리뷰, 페르소나는 파라미터). 의존 스킬은 있으면 사용, 없으면 생략 + 설치 제안 문구(ppt-master만 prerequisite-stop). ppt-master로 그냥 'PPT 만들기'와 달리 yeong 규약이 필요할 때." author: "YoungjaeDev" kind: standalone diff --git a/plugins/ppt-yeong-style/skills/lecture-deck/scripts/render-qa.sh b/plugins/ppt-yeong-style/skills/lecture-deck/scripts/render-qa.sh index 4abf36e5..1db4656b 100755 --- a/plugins/ppt-yeong-style/skills/lecture-deck/scripts/render-qa.sh +++ b/plugins/ppt-yeong-style/skills/lecture-deck/scripts/render-qa.sh @@ -43,7 +43,14 @@ b_hits=$(grep -REl '>[^<]*\[[^]]*\][^<]*<' "$SVG_DIR" 2>/dev/null || true) if [ -n "$b_hits" ]; then fail=1 echo " FAIL — bracket placeholder(s) leaked into rendered text:" - for f in $b_hits; do + # Iterate on newline boundaries: `for f in $b_hits` word-splits on IFS and + # glob-expands, so an absolute DECK_ROOT containing a space arrives here as two + # fragments, the grep below fails on both, and its stderr is discarded -- the + # FAIL detail degrades to half-paths with (0) counts. The gate itself is + # unaffected (fail=1 is already set above); this is the report, which is what + # the user reads to find the leak. + printf '%s\n' "$b_hits" | while IFS= read -r f; do + [ -n "$f" ] || continue c=$(grep -Eo '>[^<]*\[[^]]*\][^<]*<' "$f" 2>/dev/null | wc -l | tr -d ' ') echo " $f ($c)" done diff --git a/plugins/project-init/.claude-plugin/plugin.json b/plugins/project-init/.claude-plugin/plugin.json index cee58246..2901cd76 100644 --- a/plugins/project-init/.claude-plugin/plugin.json +++ b/plugins/project-init/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "project-init", - "version": "0.6.1", + "version": "0.6.2", "description": "Agent-harness project lifecycle. `new` — one-shot first-day bootstrap (interview, .claude/ scaffold, minimal CLAUDE.md, AGENTS.md with Codex GitHub cloud reviewer guidelines in general/ml/web variants, README/CHANGELOG seed, gh repo create + initial push) behind a hardened preflight guard that refuses a non-empty cwd. `wiring` — its inverse for existing repos: a read-only 14-axis setup diagnostic (FAIL / WARN / ASK / INFO / SKIP / OK) covering guidance files, .claude/rules paths: scoping defeated by @import, llm-wiki layout + staging backlog, Serena onboarding, memory posture, MCP duplicate registration, Codex CLI posture + AGENTS.md byte budget, spec homes, gws-sync, .tmp, core.hooksPath, .gitignore coverage. ASK answers persist to .claude/state/wiring.json. Shared read-only detector: scripts/project_state.sh.", "author": { "name": "YoungjaeDev" diff --git a/plugins/project-init/.codex-plugin/plugin.json b/plugins/project-init/.codex-plugin/plugin.json index 2297c1d2..686e87f7 100644 --- a/plugins/project-init/.codex-plugin/plugin.json +++ b/plugins/project-init/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "project-init", - "version": "0.6.1", + "version": "0.6.2", "description": "Agent-harness project lifecycle. `new` — one-shot first-day bootstrap (interview, .claude/ scaffold, minimal CLAUDE.md, AGENTS.md with Codex GitHub cloud reviewer guidelines in general/ml/web variants, README/CHANGELOG seed, gh repo create + initial push) behind a hardened preflight guard that refuses a non-empty cwd. `wiring` — its inverse for existing repos: a read-only 14-axis setup diagnostic (FAIL / WARN / ASK / INFO / SKIP / OK) covering guidance files, .claude/rules paths: scoping defeated by @import, llm-wiki layout + staging backlog, Serena onboarding, memory posture, MCP duplicate registration, Codex CLI posture + AGENTS.md byte budget, spec homes, gws-sync, .tmp, core.hooksPath, .gitignore coverage. ASK answers persist to .claude/state/wiring.json. Shared read-only detector: scripts/project_state.sh.", "author": { "name": "YoungjaeDev" diff --git a/plugins/project-init/references/gh-repo-create-flow.md b/plugins/project-init/references/gh-repo-create-flow.md index 272fc395..3ac0c755 100644 --- a/plugins/project-init/references/gh-repo-create-flow.md +++ b/plugins/project-init/references/gh-repo-create-flow.md @@ -66,8 +66,20 @@ The `--license ` flag of `gh repo create` can auto-generate a LICENSE file ```bash # Auto-seed the license +# ${VISIBILITY,,} is a Bash 4 expansion; macOS /bin/bash is 3.2 and fails with +# "bad substitution". Normalize with the POSIX tr helper the executable +# procedure already uses (new-procedure.md Phase 4/6), and match on a token +# rather than passing the raw answer straight into a CLI flag. +to_lower() { printf '%s' "$1" | tr '[:upper:]' '[:lower:]'; } +case "$(to_lower "$VISIBILITY")" in + *private*) VIS_FLAG="private" ;; + *public*) VIS_FLAG="public" ;; + *internal*) VIS_FLAG="internal" ;; + *) echo "unknown visibility: $VISIBILITY" >&2; exit 1 ;; +esac + gh repo create "${OWNER}/${PROJECT_NAME}" \ - --${VISIBILITY,,} \ + --${VIS_FLAG} \ --description "${ONE_LINER}" \ --license "${LICENSE}" \ --source=. --remote=origin --push @@ -88,8 +100,20 @@ git add .claude/ CLAUDE.md AGENTS.md README.md CHANGELOG.md git commit -m "chore: bootstrap project skeleton via project-init" # 3. gh repo create + auto push +# ${VISIBILITY,,} is a Bash 4 expansion; macOS /bin/bash is 3.2 and fails with +# "bad substitution". Normalize with the POSIX tr helper the executable +# procedure already uses (new-procedure.md Phase 4/6), and match on a token +# rather than passing the raw answer straight into a CLI flag. +to_lower() { printf '%s' "$1" | tr '[:upper:]' '[:lower:]'; } +case "$(to_lower "$VISIBILITY")" in + *private*) VIS_FLAG="private" ;; + *public*) VIS_FLAG="public" ;; + *internal*) VIS_FLAG="internal" ;; + *) echo "unknown visibility: $VISIBILITY" >&2; exit 1 ;; +esac + gh repo create "${OWNER}/${PROJECT_NAME}" \ - --${VISIBILITY,,} \ + --${VIS_FLAG} \ --description "${ONE_LINER}" \ --source=. --remote=origin --push ``` diff --git a/plugins/project-init/references/new-procedure.md b/plugins/project-init/references/new-procedure.md index 84583b20..d31fd9b9 100644 --- a/plugins/project-init/references/new-procedure.md +++ b/plugins/project-init/references/new-procedure.md @@ -30,14 +30,19 @@ if [ -z "$PLUGIN_ROOT" ]; then # Best-effort Codex cache lookup. Order: latest version directory under the # configured marketplace name; user override via $CODEX_PLUGIN_CACHE. cache_root="${CODEX_PLUGIN_CACHE:-$HOME/.codex/plugins/cache}" - # Prefer `sort -V` (GNU) for proper semver ordering; macOS / BSD sort lacks - # -V and would fail silently, so fall back to plain lexicographic sort. - # Picks fine for typical X.Y.Z under 10 — covers the realistic version range - # the plugin cache will ever hold for a single plugin. + # Sort on the version basename, not the full path: with two marketplace dirs a + # name like zeta/project-init/0.4.0 would otherwise outrank alpha/project-init/0.6.0. + # `sort -V` orders X.Y.Z properly and is present on GNU and on Apple's FreeBSD + # sort (10.13+), but the probe stays for userlands that predate it; the fallback + # is a numeric dotted-field sort, because plain lexicographic ranks 0.6.0 above + # 0.10.0 and would resolve to an older cached version. Same form as + # plugins/github-dev/skills/cr-fix/SKILL.md, whose regression test guards it. if sort -V /dev/null 2>&1; then - candidate=$(ls -1d "$cache_root"/*/project-init/* 2>/dev/null | sort -V | tail -1) + candidate=$(ls -1d "$cache_root"/*/project-init/* 2>/dev/null \ + | awk -F/ '{print $NF "\t" $0}' | sort -V | tail -1 | cut -f2-) else - candidate=$(ls -1d "$cache_root"/*/project-init/* 2>/dev/null | sort | tail -1) + candidate=$(ls -1d "$cache_root"/*/project-init/* 2>/dev/null \ + | awk -F/ '{print $NF "\t" $0}' | sort -t. -k1,1n -k2,2n -k3,3n | tail -1 | cut -f2-) fi [ -n "$candidate" ] && [ -d "$candidate" ] && PLUGIN_ROOT="$candidate" fi @@ -61,7 +66,11 @@ CWD=$(pwd) DIR_NAME=$(basename "$CWD") HAS_GIT=$([ -d .git ] && echo "yes" || echo "no") HAS_CLAUDE=$([ -d .claude ] && echo "yes" || echo "no") -HAS_CODE=$(find . -maxdepth 2 -type f \( -name "*.py" -o -name "*.ts" -o -name "*.js" -o -name "*.go" -o -name "*.rs" -o -name "*.java" \) 2>/dev/null | head -1 | wc -l) +# yes/no like its neighbours, not a count: BSD `wc -l` right-pads its output, so +# the old `| head -1 | wc -l` form yielded " 1" here while HAS_GIT and +# HAS_CLAUDE were clean tokens. `-print -quit` also stops at the first match +# instead of walking the whole tree. +HAS_CODE=$([ -n "$(find . -maxdepth 2 -type f \( -name "*.py" -o -name "*.ts" -o -name "*.js" -o -name "*.go" -o -name "*.rs" -o -name "*.java" \) -print -quit 2>/dev/null)" ] && echo "yes" || echo "no") # Collect GitHub owner candidates bash "$PLUGIN_ROOT/scripts/infer-github-context.sh" From 580120c1008b6fd9b64b33149b69821cf3ace7dc Mon Sep 17 00:00:00 2001 From: YoungjaeDev Date: Tue, 28 Jul 2026 14:38:07 +0900 Subject: [PATCH 2/3] fix(ml-toolkit): do not trade the macOS venv fix for a Windows one The venv-creation line is shared by a block that carries a Windows branch two lines down (`.venv\Scripts\activate # Windows`), so it has to serve all three platforms. Switching it to `python3 -m venv` fixed macOS 12.3+, which has no `python`, and broke a python.org Windows install, which ships `python.exe` and the `py` launcher but no `python3.exe`. Both spellings are now given with per-OS comments, matching the idiom the activation line two rows below already uses. The comment says why the line is sensitive at all: it runs before activation, so it resolves against the system PATH rather than the venv. Swept the rest of the file: the other Windows-branch block uses `uv venv` and names no interpreter, and the two `python -c` calls run after activation, where a venv provides `python` on every platform. No sibling occurrences. Addresses the Codex P1 on PR #186. --- .../skills/cv-notebook/references/environment-setup.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/ml-toolkit/skills/cv-notebook/references/environment-setup.md b/plugins/ml-toolkit/skills/cv-notebook/references/environment-setup.md index 9dc28cba..aa43aa3c 100644 --- a/plugins/ml-toolkit/skills/cv-notebook/references/environment-setup.md +++ b/plugins/ml-toolkit/skills/cv-notebook/references/environment-setup.md @@ -314,8 +314,11 @@ HF_HOME=/path/to/huggingface/cache #### Using venv ```bash -# Create virtual environment -python3 -m venv .venv +# Create virtual environment (runs before activation, so it resolves against the +# system PATH: macOS 12.3+ has no `python`, and a python.org Windows install has +# no `python3` -- only `python` and the `py` launcher) +python3 -m venv .venv # Linux/Mac +# py -3 -m venv .venv # Windows # Activate source .venv/bin/activate # Linux/Mac From d56e71a86ca9554aa4e70cd17f6bcb58f4943761 Mon Sep 17 00:00:00 2001 From: YoungjaeDev Date: Tue, 28 Jul 2026 14:44:26 +0900 Subject: [PATCH 3/3] fix(ml-toolkit): detect the interpreter instead of guessing its name The audit rated this call site cosmetic, reasoning that macOS has no CUDA so the script exits either way and only the error message differs. That holds for macOS and not for Windows, where CUDA is available and the memory-planning step is a real feature -- so switching `python` to `python3` traded a macOS-only message change for a Windows functional break. No single spelling covers all three platforms: macOS 12.3+ dropped `python`, and a python.org Windows install ships `python` and the `py` launcher but no `python3`. Probes python3 -> python -> py -3 and fails loudly when none is present. Held in an indexed array (Bash 2+, so 3.2-safe; only associative arrays need Bash 4) so `py -3` survives as two words under quoting -- `"$PY" script.py` would look for an executable literally named "py -3", and dropping the quotes would break on a SKILL_DIR containing a space. Verified across four PATH scenarios: python3-only picks python3, python-only picks python, py-only picks `py -3`, and an empty PATH exits 1 with a message. Addresses the second Codex P1 on PR #186. --- .../ml-toolkit/skills/gpu-parallel-pipeline/SKILL.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/plugins/ml-toolkit/skills/gpu-parallel-pipeline/SKILL.md b/plugins/ml-toolkit/skills/gpu-parallel-pipeline/SKILL.md index e1a787ec..4606a5d5 100644 --- a/plugins/ml-toolkit/skills/gpu-parallel-pipeline/SKILL.md +++ b/plugins/ml-toolkit/skills/gpu-parallel-pipeline/SKILL.md @@ -127,7 +127,16 @@ else SKILL_DIR="$HOME/.hermes/plugins/ml-toolkit/skills/gpu-parallel-pipeline" # Hermes default install fi [ -d "$SKILL_DIR" ] || { echo "gpu-parallel-pipeline: skill dir not resolved" >&2; exit 1; } -python3 "$SKILL_DIR/scripts/check_gpu_memory.py" + +# No single interpreter name works everywhere: macOS 12.3+ dropped `python`, and +# a python.org Windows install ships `python` plus the `py` launcher but no +# `python3`. Windows matters here because CUDA is actually available there. +# Indexed array (Bash 2+, so 3.2-safe) so `py -3` stays two words under quoting. +if command -v python3 >/dev/null 2>&1; then PY=(python3) +elif command -v python >/dev/null 2>&1; then PY=(python) +elif command -v py >/dev/null 2>&1; then PY=(py -3) +else echo "gpu-parallel-pipeline: no Python interpreter on PATH" >&2; exit 1; fi +"${PY[@]}" "$SKILL_DIR/scripts/check_gpu_memory.py" ``` **Rule of thumb:**