ð¡ïž è€æ°ãªããžããªãæ¯æèªåç£æ»ããä»çµã¿
äŒç€Ÿéœåã§è§£éããæåãŒãã«ãªã£ãå€ãç§ã®æå ã«æ®ã£ãã®ã¯è€æ°ã®å人ãªããžããªã ãã§ããããããåå¹Žã§æå120äžåãŸã§è²ãŠçŽããã®ã¯ãã³ãŒããæžãããå ã«ãç°å¢ããæŽããããã§ããä»åã¯ãã®ç°å¢ã®äžæ žãè€æ°ãªããžããªãæ¯æèªåç£æ»ããã¹ã¯ãªããã®å®è£ ãå ¬éããŸãã
ãªããã®ä»çµã¿ãå¹ãã®ã
坿¥ã§ãããžã§ã¯ããè€æ°äžŠèµ°ãããŠãããšãå¿
ãã人éã®æ³šæåããåŸéã«ãªããŸããç§ã®å Žåãshukatsu-trackerïŒå°±æŽ»é¢é£ã®ãã©ããã³ã°ããŒã«ïŒãš seo-affiliate-siteïŒSEOã¢ãã£ãªãšã€ããµã€ãïŒãåæã«åãããŠããŸããããäžæ¹ã«éäžããŠããéã«ããäžæ¹ã§å°ããªè
æãç©ã¿éãªã£ãŠãããŸããã
å ·äœçã«ã©ãããåé¡ãèµ·ããããæ£çŽã«æžããŸãã
æªã³ããããã¡ã€ã«ã®å±±ããã£ãŒãã£ãŒéçºäžã®äžæçãªãããã°ã³ãŒããã³ãããããªããŸãŸ2é±éæŸçœ®ããããšããããŸããåŸã§ããã®å€æŽããªãã§å
¥ãããã ã£ãããšè¿œããªããªãã30åããŒããªã¿ãŒã³ã®èª¿æ»ã«è²»ãããŸãããä»ã®ã¹ã¯ãªããã§ã¯æªã³ããã50ä»¶è¶
ã§ð¡èŠåãåºãŸãïŒUNCOMMITTED_WARN=50ïŒã50ä»¶ã¯çããšæããããããããŸãããããã³ããããã¹ãå€åéã®ææšããšããŠæ©èœãããããšãç®çã§ãæ¥åžžçãªWIPäœæ¥ã鿀ç¥ããªãæ°Žæºã«èšå®ããŠããŸãã
stale commitã®ææãæçµã³ããããã14æ¥çµéãããšð¡ã«ãªããŸãïŒSTALE_COMMIT_DAYS=14ïŒãããã¯ããããžã§ã¯ããæ»ãã§ããããµã€ã³ã§ã¯ãªãããæèçã«è§Šã£ãŠããªãããµã€ã³ãšããŠäœ¿ããŸãã2é±éãã°ãæŒã£ãŠãçç±ã®ãªãstaleã¯ãäŸåããã±ãŒãžãå€ããªããªã¹ã¯ãšçŽçµããŸãã坿¥ã®å Žåãæ¬æ¥ãšã®å
Œãåãã§æå³çã«åæ¢ããããšãããã®ã§ãã¹ã¯ãªããã¯äºå®ãå ±åããã ãã§èªåçã«pushãissueäœæã¯ããŸãããç£èŠã®è²¬ä»»ã¯èŠã人éã«ããããšããèšèšã§ãã
.envã®èª€trackingãããã¯ðŽã®å³æèŠåã§ããUNCOMMITTED_WARN ã STALE_COMMIT_DAYS ã¯ç·©ããããå€ã§éçšããŸããã.envã®ãã©ããã³ã°ã ãã¯å³ã¢ãŠããgit ls-files ã§ .env.example ãé€ããã¹ãŠã® .env* ãã¿ãŒã³ãæŸããŸããäžåºŠã§ã git add . ãå©ãããšãã« .env ãæ··å
¥ãããçµéšããã人ãªãããã®ææã¯å
±æã§ãããšæããŸããç§ã¯åæã« seo-affiliate-site ã®éçºäžã.gitignore ã®æŽæ°ãåŸåãã«ããŠå±ãã APIããŒãå«ã .env ãã³ããã寞åãŸã§è¡ããŸããããã以æ¥ããã®ãã§ãã¯ãå€ããããšã¯ãããŸããã
node_modules ã®è¥å€§ã820MiBïŒ1GiBã®80%ïŒã§äºåèŠåã1GiBã§ð¡ã«å ¥ããŸãã
NODE_MODULES_WARN_BYTES=$((1024 * 1024 * 1024)) # 1 GiB
NODE_MODULES_NEAR_BYTES=$((1024 * 1024 * 1024 * 80 / 100)) # 820 MiB (80% äºåèŠå)
ãªã2段éããSSDã®ç©ºã容éãäžæã«1GiBãåããšããã«ããDockerã®åäœãæªãããªããŸãããæ¥ã«é
ããªã£ããã®åå 远跡ã«1æé溶ããããã820MiBæç¹ã§ npm prune ãæ€èšããæ¹ãå®ãã
ãããã®åé¡ã«å ±éããã®ã¯ããæ°ã¥ãããšãã«ã¯æé ãããšããæ§é ã§ããã³ãŒããæžã人éããã³ãŒãã®å¥å šæ§ãèœåçã«ãã§ãã¯ãç¶ããããšã¯ã§ããŸãããè³å ã®ã¯ãŒãã³ã°ã¡ã¢ãªã¯åžžã«ãä»äœã£ãŠãããã®ãã«å šæ¯ããããŠããããã§ããã ããããããã§ãã¯ã人éã®å€ã«åºãå¿ èŠããããŸãã
ãããŠããäžã€ãèŠèœãšãããã¡ãªèšèšååããããŸããç£èŠã¹ã¯ãªãããå£ããŠããæ¬æ¥ãæ¢ããŠã¯ãããªãããšããååã§ãã
trap 'exit 0' ERR
ã¹ã¯ãªããåé ã®ãã®1è¡ããèšèšã®æ ¹å¹¹ã§ããset -uïŒæªå®çŸ©å€æ°ããšã©ãŒã«ããïŒãæå¹ã«ããªãããERRã·ã°ãã«ããã£ããã㊠exit 0 ã§æããŸããã€ãŸãã¹ã¯ãªããå
ã®ã©ããã§ãšã©ãŒãåºãŠããlaunchdããèŠããšãæ£åžžçµäºãã§ãã
ãªããããéèŠããlaunchdã¯ãžã§ãã倱æãããšå詊è¡ãã¢ã©ãŒããåºãããšããããŸããç£èŠããŒã«èªäœããšã©ãŒãåãç¶ãããããé£éçãªéç¥ããã°è¥å€§ãåŒãèµ·ããââããããã¢ãã¿ãªã³ã°ã®äºæ¬¡çœå®³ããšåŒã³ãŸãããå人éçºã§ã¯ãããèŽåœçã§ããæå120äžãæ¯ããŠããã®ã¯ã¡ã€ã³ã®ãããã¯ãã³ãŒãã§ãããç£èŠã¹ã¯ãªããã§ã¯ãããŸãããç£èŠããŒã«ã¯éãã«å€±æããŠãããæ£ç¢ºã«ã¯ã倱æãèªåã§åžåããŠæ¬äœã«æ³¢åãããŠã¯ãããªãã
fail-openïŒå€±ææã«ééãããïŒã®èšèšã¯ãã»ãã¥ãªãã£ã®æèã§ã¯å¿é¿ãããŸãããå¯çšæ§åªå
ã®ç£èŠããŒã«ã§ã¯æ£è§£ã§ãããã®ã¹ã¯ãªããã誀åäœã㊠shukatsu-tracker ã®ãã«ããæ¢ãŸããããç£èŠãæ²é»ããæ¹ããã£ãšãŸãã§ãã
å šäœã®æµã
å®éã®é ç·ãå³ã«ãããšæ¬¡ã®éãã§ãã
æ¯æ 7:30ïŒlaunchd ãèµ·åïŒ
â
âŒ
~/.claude/scripts/project-health.sh
â
âââ[ shukatsu-tracker ]
â ââ æªã³ãããä»¶æ°ïŒgit status --porcelainïŒ
â ââ æçµã³ãããçµéæ¥ïŒgit log -1 --format='%ct'ïŒ
â ââ .env* trackingïŒgit ls-filesïŒ
â ââ node_modules ãµã€ãºïŒdu -skïŒ
â
âââ[ seo-affiliate-site ]
ââ åäž 4 軞
ââ package.json ã®äŸåæ°ïŒpython3 ã§ JSON ããŒã¹ïŒ
â
âŒ
~/.claude/logs/project-health-YYYYMMDD.md â æ¥ä»å¥ã¢ãŒã«ã€ã
~/.claude/logs/project-health-latest.md â åžžã«ææ°ïŒcp ã§äžæžãïŒ
åºå㯠Markdown ããŒãã«ã§ããClaude Code ã®ããã·ã¥ããŒããä»»æã®ãšãã£ã¿ã§çŽæ¥åç §ã§ããŸãã
| Project | Uncommitted | Last commit | Deps | node_modules | Status |
|---------|-------------|-------------|------|--------------|--------|
| `shukatsu-tracker` | 3 | 2 days ago - feat: ... | 12+8 | 234MiB | ð¢ |
| `seo-affiliate-site` | 0 | 16 days ago - chore: ... | 9+5 | 187MiB | ð¡ |
Deps å㯠package.json ã® dependencies ãš devDependencies ã®ä»¶æ°ã 12+8 圢åŒã§è¡šç€ºããŸããããã§ python3 ã䜿ã£ãŠããã®ã¯ãbash ã ãã§ JSON ãããŒã¹ãããã確å®ã ããã§ãã
DEPS=$(python3 -c "
import json, sys
try:
p = json.load(open('$PKG'))
d = len(p.get('dependencies', {}) or {})
dd = len(p.get('devDependencies', {}) or {})
print('%d+%d' % (d, dd))
except Exception:
print('?')
" 2>/dev/null)
except Exception: print('?') ã§æ¡ãã€ã¶ããŠããã®ã¯æå³çã§ããpackage.json ã®ããŒã¹ã«å€±æããŠãã¹ã¯ãªããå
šäœãèœãšãçç±ã¯ãããŸããã? ãåºãããã®ãªããžããªã ãåå¥ç¢ºèªããã°ããã
launchd ã«ããé ç·
ã¹ã¯ãªããåäœãã©ãã ãæ£ç¢ºã§ããå®è¡ããç¶ããªããã°æå³ããããŸãããcronãããmacOSãã€ãã£ãã® launchd ãéžãã çç±ã¯2ã€ãããŸããã·ã¹ãã èµ·ååŸã®åå®è¡ä¿èšŒãšãæšæºãšã©ãŒã®ãã¡ã€ã«æ°žç¶åã§ãã
plistã®æ žå¿éšåã瀺ããŸãã
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>7</integer>
<key>Minute</key>
<integer>30</integer>
</dict>
<key>LowPriorityIO</key>
<true/>
<key>Nice</key>
<integer>10</integer>
<key>ProcessType</key>
<string>Background</string>
<key>StandardErrorPath</key>
<string>~/.claude/logs/com.shun.project-health.log</string>
<key>StandardOutPath</key>
<string>~/.claude/logs/com.shun.project-health.log</string>
LowPriorityIO: true ãš Nice: 10 ã®çµã¿åããããã€ã³ãã§ããdu -sk ã¯ãã£ã¹ã¯èªã¿åãã䌎ããããæ®éã«å®è¡ãããšãã«ããIDEã®ã€ã³ããã¯ã¹æŽæ°ãšç«¶åããŸããLowPriorityIO ã¯I/Oã¹ã±ãžã¥ãŒã©ã«ãåŸåãã«ããŠããããšäŒããNice: 10 ã¯CPUã¹ã±ãžã¥ãŒã©ã«åãããšãäŒããŸããæ7:30ã¯ãŸã æ¬æ Œçãªäœæ¥åã§ãããMacBookãéãããšããã«Xcodeã®indexæŽæ°ãnpmã®ãã«ããèµ°ãããšãå€ããç£èŠã¹ã¯ãªããã«æ¬æ¥ã®ãã«ããé
å»¶ãããæš©éã¯äžããŸããã
EnvironmentVariables ã« PATH ãæç€ºããŠããã®ãéèŠã§ãã
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/Users/.../.nvm/versions/node/v24.13.0/bin:/opt/homebrew/bin:...</string>
</dict>
launchd ã¯ã·ã§ã«ãããã¡ã€ã«ïŒ.zshrc çïŒãèªã¿èŸŒãŸãã«èµ·åããŸããnvm çµç±ã§ã€ã³ã¹ããŒã«ãã node ããHomebrew ã® git ã䜿ãã«ã¯ PATH ã plist ã«çŽæžãããå¿
èŠããããŸãããæåå®è¡ã¯åãã®ã«launchdã ãšåããªããã®å€§åã¯ããã§ããã¹ã¯ãªããå
ã® python3 ã /usr/bin/python3ïŒmacOS忢±ïŒã§ã¯ãªã Homebrew é
äžã® python ã䜿ããããã©ããã§æåãå€ãããŸããplist ã® PATH ã« /opt/homebrew/bin ãå«ããããšã§ãéçºç°å¢ãšèªåå®è¡ç°å¢ã®å·®ç°ã朰ããŠããŸãã
ãã°ã®äºéå
OUT="$LOG_DIR/project-health-${DATE_TAG}.md" # äŸ: project-health-20260801.md
LATEST="$LOG_DIR/project-health-latest.md"
...
cp "$OUT" "$LATEST" 2>/dev/null || true
æ¥ä»å¥ãã¡ã€ã«ãš latest ã®2æ¬ç«ãŠã«ããŠããã®ã¯ãçšéãéãããã§ããæ¥ä»å¥ã¯ãå
é±ã®ç«æã¯ã©ãããç¶æ
ã ã£ããããé¡ãããã®ã¢ãŒã«ã€ããlatest ã¯ã仿ã®ç¶æ
ãä»ããç¥ããããã®ã·ã§ãŒãã«ãããClaude Code ã®ã¡ã¢ãªãå¥ã¹ã¯ãªããããåç
§ãããšãã¯åžžã« latest ãèªã¿ãŸããcp ã®åŸãã« || true ãä»ããŠããã®ã fail-open ã®å»¶é·ç·äžã§ãã³ããŒã®å€±æã§ã¹ã¯ãªãããéãŒãçµäºããã®ãé²ããŸãã
mkdir -p "$LOG_DIR" ãæåã«çœ®ããŠããã®ã¯ãååå®è¡æã«ãã£ã¬ã¯ããªããªããŠããã¡ã€ã«æžã蟌ã¿ã«å€±æããªãããã§ãããã®æã®ãŠãŒãã£ãªãã£ã¹ã¯ãªããã¯ãå®å
šã«ã¯ãªãŒã³ãªç°å¢ã§ã®ååå®è¡ãã§æ»ã¬ããšãå€ããèªåã®ç°å¢ã§ã¯ãã§ã«ãã£ã¬ã¯ããªãããã®ã§æ°ã¥ãããå¥ã®ãã·ã³ã«ç§»æ€ãããšããã«åããªããªãããšããçœ ãã€ã¶ããŠããŸãã
bash 3.2 äºæ
ã¹ã¯ãªããã®ã³ã¡ã³ãã« bash 3.2 äºæ (mapfile / assoc array çŠæ¢) ãšãããŸããmacOS ã«å梱ãããŠããããã©ã«ãã® /bin/bash ã¯GPL v2ã®é¢ä¿ã§bash 3.2ã®ãŸãŸã§ãïŒHomebrew ã§ bash 5ç³»ãå
¥ããŠãã/bin/bash ã¯å€ãããªãïŒãplist ã® ProgramArguments ã§ /bin/bash -c ã䜿ã£ãŠãã以äžãã¹ã¯ãªããã¯bash 3.2ã§åãå¿
èŠããããŸãã
bash 4以éã® mapfileïŒé
åãžã®ãã€ãèªã¿èŸŒã¿ïŒã declare -AïŒé£æ³é
åïŒã¯äœ¿ããŸããã代ããã«æååã®è¿œèšïŒWARN_LINES="${WARN_LINES}..."ïŒãš printf "%b" ã§ã®æ¹è¡å±éã§å¯Ÿå¿ããŠããŸãã
WARN_LINES=""
...
WARN_LINES="${WARN_LINES}- ${STATUS_FLAG} \`${NAME}\`: ${REPO_WARNS}\n"
...
printf "%b" "$WARN_LINES"
\n ãªãã©ã«ã printf "%b" ã§å±éããã®ã¯ãecho -e ãbash/shå®è£
éã§æåãæºããããã§ããprintf ã¯POSIXæºæ ã§å®å
šã§ãã
å®è£ ã®è©³çް
git -C ã§ã«ãŒãå ã®ãçŸåšå°ãæ±æãé²ã
ã¹ã¯ãªããã®äžã§ cd "$REPO" ãäžåºŠã䜿ã£ãŠããªãããšã«æ°ã¥ãã§ããããããã¹ãŠã® git ã³ãã³ã㯠-C ãã©ã°ã§å¯Ÿè±¡ãã£ã¬ã¯ããªãçŽæ¥æå®ããŠããŸãã
UNCOMMITTED=$(git -C "$REPO" status --porcelain 2>/dev/null | wc -l | tr -d ' ')
LAST_COMMIT=$(git -C "$REPO" log -1 --format='%cr - %s' 2>/dev/null | LC_ALL=C tr '|' '/' | LC_ALL=C tr -d '\r\n' | cut -c1-80)
LAST_COMMIT_TS=$(git -C "$REPO" log -1 --format='%ct' 2>/dev/null)
TRACKED_ENV=$(git -C "$REPO" ls-files 2>/dev/null | grep -E '(^|/)\.env($|\.)' | grep -v '\.env\.example$' | head -5)
ãªã cd ã䜿ããªãããšãããšãã«ãŒãã®äžã§ cd ãããšãçŸåšå°ããã«ãŒãããŸããã§æ±æãããããã§ãã1ã€ç®ã®ãªããžããªåŠçäžã«äœããã®çç±ã§ cd ã倱æããå Žåã2ã€ç®ä»¥éã¯æå³ããªããã£ã¬ã¯ããªã§ git ã³ãã³ããå®è¡ããŸããset -u ãš trap 'exit 0' ERR ã®çµã¿åããããã£ãŠãããééã£ããªããžããªãæäœããŠãããç¶æ
ã¯æ€ç¥ã§ããŸããã-C ã䜿ãã°åã³ãã³ããç¬ç«ããŠå¯Ÿè±¡ãã£ã¬ã¯ããªãæã€ãããã«ãŒãéã®å¯äœçšãåççã«çºçããŸããã
STATUS_FLAG ã®åæ¹åæŽæ°
STATUS_FLAG="ð¢"
...
if [ "$UNCOMMITTED" -gt "$UNCOMMITTED_WARN" ]; then
STATUS_FLAG="ð¡"
fi
...
if [ "$COMMIT_AGE_DAYS" -gt "$STALE_COMMIT_DAYS" ]; then
[ "$STATUS_FLAG" = "ð¢" ] && STATUS_FLAG="ð¡" # â ð¡ ææ Œã¯ ð¢ ã®ãšãã ã
fi
...
if [ -n "$TRACKED_ENV" ]; then
STATUS_FLAG="ðŽ" # â ðŽ ææ Œã¯ç¡æ¡ä»¶
fi
STATUS_FLAG ã®æŽæ°ã«ãŒã«ã«æ³šç®ããŠãã ãããð¡ ãžã®ææ Œã¯ãçŸåš ð¢ ã®ãšãã ãããšããæ¡ä»¶ä»ãã§ããäžæ¹ãðŽ ãžã®ææ Œã¯ç¡æ¡ä»¶ã§ãã
ããã¯ãé節床ãäœãã»ããžã®éæ»ããé²ããèšèšã§ããuncommitted ãå€ã㊠ð¡ ã«ãªã£ãåŸã« stale-commit ãã§ãã¯ãæ¥ãŠããð¢ ã®ãšãã ã ð¡ ã«å€ãããšæžãããŠããã®ã§ç¶æ
ã¯å€ãããŸããã.env 远跡ïŒðŽïŒã ãã¯äœããã£ãŠãæé«ã¢ã©ãŒããä¿æããŸãã
坿¥ã®å®åã§ããã倧äºãªçç±ã¯ãããŒãã«ã® Status åã å³ç«¯ã®1åã ãèŠãŠç¬æã«å€æããããã§ããè€æ°ã®åé¡ãéãªã£ããšãã«æãæ·±å»ãªã¢ã©ãŒããä¿æãããŠããªããã°ãããŒãã«ãçºãã10ç§éã§èŠèœãšããçãŸããŸãã
uncommitted ã«ãŠã³ãã®è£è¶³ããžãã¯
# uncommitted ã0è¶
ãã€éŸå€ä»¥äžã§ããä»ã®èŠåãããå Žåã¯ä»¶æ°ãä»èš
if [ "$UNCOMMITTED" -gt 0 ] && [ "$UNCOMMITTED" -le "$UNCOMMITTED_WARN" ] && [ -n "$REPO_WARNS" ]; then
REPO_WARNS="${REPO_WARNS}uncommitted=${UNCOMMITTED} (ok); "
fi
ãã®æ¡ä»¶åå²ã¯ãéŸå€ä»¥äžã® uncommitted ã¯åç¬ã§ã¯èŠåããªãããä»ã®åé¡ãšçµã¿åããã£ããšãã¯ä»èšããããšããè€å倿ã§ããããšãã° stale-commitïŒ14æ¥è¶ ïŒãåºãŠãããªããžããªã§ uncommitted ã 23 ä»¶ãã£ããšãããšãã14æ¥è§Šã£ãŠããªã + æªã³ããã23ä»¶ããšããçµã¿åããã Warnings ã»ã¯ã·ã§ã³ã«æ®ããŸããåç¬ã§ã¯ ð¡ ã«ããªãæ°åã§ããå¥ã®åé¡ãšçµã¿åããã£ãæèã§ã¯éèŠãªæ å ±ã«ãªããŸãã
node_modules ã® GiB è¡šç€ºãšæŽæ°æŒç®
NM_KB=$(du -sk "$NM_DIR" 2>/dev/null | awk '{print $1}')
[ -z "$NM_KB" ] && NM_KB=0
NM_BYTES=$((NM_KB * 1024))
NM_MIB=$((NM_KB / 1024))
if [ "$NM_MIB" -ge 1024 ]; then
NM_DISPLAY="$((NM_MIB / 1024)).$((NM_MIB % 1024 * 10 / 1024))GiB"
else
NM_DISPLAY="${NM_MIB}MiB"
fi
du -sk 㯠KB åäœã§è¿ããŸãã1024 åã㊠NM_BYTES ãåŸãŠãããéŸå€ãšã®æ¯èŒã¯ãã€ãåäœã§è¡ããŸãïŒæŽæ°æŒç®ãªã®ã§ç²ŸåºŠãåºãããïŒãGiB 衚瀺㮠$((NM_MIB % 1024 * 10 / 1024)) ã¯ã1024 æªæºã®äœãã 10 åããŠãã 1024 ã§å²ããããšã§ãå°æ°ç¹ä»¥äž1æ¡ã®æ°åãæŽæ°ãšããŠåŸãŠããŸããbash 3.2 ã§ã¯æµ®åå°æ°ç¹æŒç®ã䜿ããªãããããã®æŽæ°æŒç®ã§ä»£æ¿ããŠããŸãã衚瀺㯠1.2GiB ã®ãããªåœ¢ã§åºåãããŸãã
.env 远跡㮠grep ãã¿ãŒã³
TRACKED_ENV=$(git -C "$REPO" ls-files 2>/dev/null \
| grep -E '(^|/)\.env($|\.)' \
| grep -v '\.env\.example$' \
| head -5)
grep -E '(^|/)\.env($|\.)' ã¯ã.env ãã®ãã®ããã.env. ããå§ãŸããã¡ã€ã«ïŒ.env.localã.env.production çïŒããæŸããŸãã(^|/) ãä»ããŠããã®ã¯ããµããã£ã¬ã¯ããªå
ã® .envïŒconfig/.env ãªã©ïŒãæŸãããã§ããgrep -v '\.env\.example$' ã§ .env.example ã ãé€å€ããŸãã
| head -5 ãä»ããŠããã®ã¯ãäœããã®äºæ
ã§å€§éã® .env* ãã¡ã€ã«ã tracked ã«ãªã£ãŠãããšãã«åºåãççºããªãããã«ããããã§ããWarnings ã»ã¯ã·ã§ã³ã«ã¯æåã®1ä»¶ã ã FIRST_ENV=$(echo "$TRACKED_ENV" | head -1) ã§è¡šç€ºããŸãããäœä»¶ããããããããŸã1件瀺ããŠå³æ°ã¥ãããããåªå
ããŠããŸãã
åºåã®äºæ®µæ§ãïŒããŒãã«ãš Warnings ã»ã¯ã·ã§ã³
echo "| \`${NAME}\` | ${UNCOMMITTED} | ${LAST_COMMIT} | ${DEPS} | ${NM_DISPLAY} | ${STATUS_FLAG} |" >> "$OUT"
...
{
echo "## Warnings (${TOTAL_WARN})"
...
printf "%b" "$WARN_LINES"
} >> "$OUT"
ããŒãã«ã¯ãäžèŠ§ææ¡ããWarnings ã»ã¯ã·ã§ã³ã¯ãåé¡ã®è©³çްããæ ããŸããããŒãã«ã¯ãªããžããªæ°ãå¢ããŠãæšªå¹ ãåºå®ã§èªããŸãããèŠåã®è©³çްïŒã©ã®ãã¡ã€ã«ã tracked ããäœæ¥ stale ãïŒãè©°ã蟌ããšã»ã«ãé·ããªããããŸããã ãã詳现ã¯äžã® Warnings ã»ã¯ã·ã§ã³ã«åé¢ããŠããŸãã
TOTAL_WARN ã®ã«ãŠã³ãã¯ãªããžããªåäœïŒ1ãªããžããªã§è€æ°åé¡ãã£ãŠã +1ïŒã§ãã## Warnings (0) ãš ## Warnings (2) ã䞊ã¹ãŠèŠããšããåé¡ãªããžããªæ°ãã²ãšç®ã§ããããŸããã2ä»¶ã®åé¡ããããã§ã¯ãªãã2ã€ã®ãããžã§ã¯ãã«åé¡ãããããšããç²åºŠã§ç®¡çããŠããŸãã
ç§ãè©°ãŸã£ã話
è©°ãŸãâ launchd ã§ãcommand not foundããç¡é³ã§ç¶ãã
æåã« plist ãäœã£ãŠ launchctl load ãããšããã¹ã¯ãªããèªäœã¯ååšããã®ã«ãžã§ããç¡é³ã§å€±æããŠããŸãããStandardErrorPath ã«èšå®ãããã°ãã¡ã€ã«ãèŠã«è¡ããšïŒ
/bin/bash: git: command not found
/bin/bash: python3: command not found
åå 㯠PATH ã§ããã端æ«ã§æåå®è¡ãããšã㯠.zshrc ãèªã¿èŸŒãŸããHomebrew ã® PATH ãéã£ãŠããŸããããã launchd ã¯ã·ã§ã«ãããã¡ã€ã«ãäžåèªãŸãã«èµ·åããŸãã/bin/bash -c ã§åŒã°ããæç¹ã§ã® PATH 㯠/usr/bin:/bin:/usr/sbin:/sbin çšåºŠãããããŸããã
解決㯠plist ãžã® PATH ã®çŽæžãã§ããå®éã®ãã¡ã€ã«ã«ã¯ããæžãããŠããŸãã
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/Users/.../.nvm/versions/node/v24.13.0/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/.../.local/bin</string>
</dict>
nvm é
äžã®ããŒããš Homebrew ãå
ã«äžŠã¹ãããšã§ãã¹ã¯ãªããå
ã® python3 㯠Homebrew é
äžã® Python ã䜿ããã端æ«ã§ã®åäœãšå®å
šã«äžèŽããŸãã
ãã®åé¡ã«æ°ã¥ããŸã§2æ¥ããããŸãããStandardErrorPath ã§ãã°ãã¡ã€ã«ãèšå®ããŠããªããã°ã倱æã®çè·¡ããæ®ããªãã£ããšããã§ããæ°ãã launchd ãžã§ããäœããã³ã«ããŸããã°ãã¡ã€ã«ã®èšå®ãš PATH ã®æç€ºãæåã«è¡ãããã«ããŸããã
è©°ãŸãâ¡ bash 3.2 ã§åããªãæ§æãæžããŠããŸã£ã
æåã®ããŒãžã§ã³ã§ã¯é£æ³é åã䜿ã£ãŠè€æ°ãªããžããªã管çããããšããŠããŸããã
# NGïŒbash 4 以äžã§ããåããªãïŒ
declare -A REPO_MAP
REPO_MAP["shukatsu-tracker"]="$HOME/dev/shukatsu-tracker"
REPO_MAP["seo-affiliate-site"]="$HOME/dev/seo-affiliate-site"
端æ«ã§ã®æåå®è¡ã§ã¯åé¡ãªãåããŸããããã launchd çµç±ïŒ/bin/bashïŒã§å®è¡ãããšïŒ
/bin/bash: declare: -A: invalid option
macOS ã® /bin/bash 㯠bash 3.2.57 ã§ããdeclare -AïŒé£æ³é
åïŒã¯ bash 4.0 ãã远å ãããŸãããHomebrew ã§ bash 5ç³»ãã€ã³ã¹ããŒã«ããŠã /bin/bash ã¯å€ãããŸãããplist ã® ProgramArguments ã /bin/bash ãæããŠãã以äžãã¹ã¯ãªãã㯠bash 3.2 ã§åãå¿
èŠããããŸãã
çŸåšã®ã¹ã¯ãªããã§ã¯ãè€æ°ãªããžããªãæ¹è¡åºåãã®æååã§æã¡ãŸãã
REPOS="
$HOME/dev/shukatsu-tracker
$HOME/dev/seo-affiliate-site
"
for REPO in $REPOS; do
...
done
for REPO in $REPOS ã§ã¯ã©ãŒãããŠããªã $REPOS ã¯ã¯ãŒãåå²ãããŸããæ¹è¡ãã¹ããŒã¹ã IFS ã®ããã©ã«ãå€ã§ã¹ããªãããããããããªããžããªãã¹ã«ç©ºçœãå«ãŸããªãéãããã§åããŸããmapfile ã飿³é
åãäžèŠã§ãbash 3.2 ã§ãã®ãŸãŸåäœããŸãããã·ã³ãã«ã«æžããªãå¶çŽããèŠã€ãã£ããšãã«ãããåçŽãªä»£æ¿ãæ¢ããšå€§æµèŠã€ãããŸãã
è©°ãŸã⢠git log ã®æ¥æ¬èªã tr ã§ããŒãã«ã厩å£ããã
LAST_COMMIT ã®ååŸã¯ git log ã®ã³ãããã¡ãã»ãŒãžãå«ã¿ãŸãã
LAST_COMMIT=$(git -C "$REPO" log -1 --format='%cr - %s' 2>/dev/null \
| LC_ALL=C tr '|' '/' | LC_ALL=C tr -d '\r\n' | cut -c1-80)
åæããŒãžã§ã³ã§ã¯ãã®ãã€ãã©ã€ã³ã« LC_ALL=C ããããŸããã§ãããæ¥æ¬èªã®ã³ãããã¡ãã»ãŒãžïŒfeat: ãã°ã€ã³ç»é¢ã远å ã®ãããªïŒãæ··ãã£ããšããtr ã³ãã³ãããã«ããã€ãæåãæ£ããåŠçã§ãããããŒãã«ã®ãã€ãæå | ã«äŒŒãæååããæ··å
¥ããŸãããMarkdown ããŒãã«ã§ | ãäœåã«å¢ãããšåå
šäœããããã¬ããŒããèªããªããªããŸãã
LC_ALL=C tr '|' '/' ã§ãã€ãæåãã¹ã©ãã·ã¥ã«å€æããããŒãã«ã®å厩å£ãé²ãã§ããŸããLC_ALL=C ãä»ããããšã§ãtr ããã€ãåäœã§åŠçããã¢ãŒãã«ãªãããã«ããã€ãæåã®èª€èªèãæ¶ããŸãã
ã¹ã¯ãªããå
é ã® export LANG=en_US.UTF-8 ãšçµã¿åãããããšã§ãgit log ã®åºåèªäœã¯ UTF-8 ã§ååŸãã€ã€ãtr ã®æååŠçã ããã€ãã¢ãŒãã«åãæ¿ãããšãã䜿ãåããããŠããŸãã
è©°ãŸã⣠set -u ãš trap ã®åã¿åããã§ç¡é³ exit ãçºçãã
set -u ã¯æªå®çŸ©å€æ°ã®åç
§ããšã©ãŒã«ããŸããtrap 'exit 0' ERR ã¯ãšã©ãŒæã«å³ exit 0 ããŸãããã®çµã¿åããã§ãæåã¯æå³ããªãç¡é³ã¹ããããçºçããŠããŸããã
åé¡ã®ã³ãŒãã¯ããã§ããã
# NG ã ã£ãåæããŒãžã§ã³
LAST_COMMIT_TS=$(git -C "$REPO" log -1 --format='%ct' 2>/dev/null)
COMMIT_AGE_DAYS=$(( ($(date +%s) - LAST_COMMIT_TS) / 86400 ))
# â LAST_COMMIT_TS ã空æåã®ãšããç®è¡å±éãæ§æãšã©ãŒ â ERR çºç« â exit 0
LAST_COMMIT_TS ã空æåïŒã³ãããããªããªããžããªïŒã®ãšãã$(( ... - )) ã®ç®è¡å±éãæ§æãšã©ãŒã«ãªããŸããset -u ã®å¯Ÿè±¡å€ã§ãããç®è¡ãšã©ãŒã¯ bash ãéãŒãã¹ããŒã¿ã¹ãè¿ããããtrap 'exit 0' ERR ãå³çºç«ããŠã¹ã¯ãªããå
šäœãçµäºããŸããæ®ãã®ãªããžããªã¯äžåãã§ãã¯ããããã¬ããŒãã¯éäžã§åãããŸãŸ latest.md ã«äžæžããããŸãã
ä¿®æ£ã¯ç©ºæåã¬ãŒããèšããããšã§ããçŸåšã®ã³ãŒãã¯ãããªã£ãŠããŸãã
LAST_COMMIT_TS=$(git -C "$REPO" log -1 --format='%ct' 2>/dev/null)
if [ -n "$LAST_COMMIT_TS" ] && [ "$LAST_COMMIT_TS" -gt 0 ] 2>/dev/null; then
COMMIT_AGE_DAYS=$(( ($(date +%s) - LAST_COMMIT_TS) / 86400 ))
if [ "$COMMIT_AGE_DAYS" -gt "$STALE_COMMIT_DAYS" ]; then
[ "$STATUS_FLAG" = "ð¢" ] && STATUS_FLAG="ð¡"
REPO_WARNS="${REPO_WARNS}stale-commit=${COMMIT_AGE_DAYS}d (>${STALE_COMMIT_DAYS}d); "
fi
fi
[ "$LAST_COMMIT_TS" -gt 0 ] 2>/dev/null ã®æ«å°Ÿ 2>/dev/null ã¯ãLAST_COMMIT_TS ãéæ°å€ã ã£ããšãã« [ ã³ãã³ããåºã "integer expression expected" ã®ã¡ãã»ãŒãžããã°ã«æ®ããªãããã§ãããã®æ¡ä»¶ãåœã«ãªãã°ç®è¡å±éã«ã¯å°éãããERR ãçºç«ããŸããã
trap 'exit 0' ERR ã䜿ãå Žåããã©ããªéãŒãã¹ããŒã¿ã¹ã§ãå³ exit ããããšããããšãåžžã«å¿µé ã«çœ®ãå¿
èŠããããŸããé²åŸ¡çãªã¬ãŒãæ¡ä»¶ãå¢ããã®ã¯åé·ã«èŠããŸãããfail-open ã¹ã¯ãªããã§ã¯ãå°éããªãã¯ãã®ã³ãŒããã¹ã ERR ãåããŠã¹ã¯ãªãããæ®ºããäºæ
ãé²ãããã®ã³ã¹ããšããŠå²ãåã£ãŠããŸããç£èŠã¹ã¯ãªãããéäžã§é»ã£ãŠçµäºããããšã¯ãç£èŠã¹ã¯ãªããèªäœãã¯ã©ãã·ã¥ããããšãšåããããå±éºã§ãã
è©°ãŸã†StandardOutPath ãš StandardErrorPath ãåããã¡ã€ã«ã§äžæžããèµ·ãã
æå㯠StandardOutPath ãš StandardErrorPath ãå¥ã
ã®ãã¡ã€ã«ã«èšå®ããŠããŸããã
<key>StandardOutPath</key>
<string>~/.claude/logs/com.shun.project-health-out.log</string>
<key>StandardErrorPath</key>
<string>~/.claude/logs/com.shun.project-health-err.log</string>
ããã launchd ã¯ãžã§ããå®è¡ãããã³ã«ãã®ãã¡ã€ã«ãäžæžãããŸãïŒappend ã§ã¯ãããŸããïŒãstdout ã¯ã¹ã¯ãªããæ¬äœã®åºåïŒMarkdown ã¬ããŒãïŒã $OUT ã«çŽæ¥æžãã®ã§ç©ºã®ã¯ãã§ãããstderr ã«åºããããã°æ å ±ã¯ååå®è¡åãæ¯ææ¶ããããšã«ãªããŸãã
解決㯠stdout ãš stderr ãåããã¡ã€ã«ã«åããããšã§ããçŸåšã®ãã¡ã€ã«ããããªã£ãŠããŸãã
<key>StandardErrorPath</key>
<string>/Users/.../.claude/logs/com.shun.project-health.log</string>
<key>StandardOutPath</key>
<string>/Users/.../.claude/logs/com.shun.project-health.log</string>
åããã¡ã€ã«ãæãããšã§ãstdout ãš stderr ãæ··åšããç¶æ
ã§åäžãã¡ã€ã«ã«æžã蟌ãŸããŸãã1æ¥1åã®äžæžããªã®ã§åæ¥åã¯æ¶ããŸãããã仿ã®ãžã§ãã¯ã©ãåããããã確èªããã«ã¯ååã§ããããé·æã®ä¿æãå¿
èŠã§ããã° >> ã䜿ã£ãã©ãããŒã§åŒã³åºãæ¹æ³ããããŸãããçŸæç¹ã§ã¯æã®ãããã°1æ¥åã§äºè¶³ããŠããŸãã
launchd ãžã§ãã®ãã°ã远ããšãã¯ãlog show --predicate 'subsystem == "com.apple.launchd"' ãããStandardErrorPath ã«èšå®ãããã¡ã€ã«ãçŽæ¥ tail -f ããæ¹ãå®çšçã§ããåè
㯠launchd ããŒã¢ã³åŽã®ã¡ã¿æ
å ±ãåŸè
ã¯ã¹ã¯ãªããã®å®éã®åºåã§ããæ··åããŠããã°ãèŠã€ãããªãããšè¿·ã£ãããšããããŸãããã¹ã¯ãªããã®åäœç¢ºèªã«å¿
èŠãªã®ã¯ã»ãŒåŸè
ã ãã§ãã
ã€ãŸãããã€ã³ã
p2 ã§è©³è¿°ãã5ä»¶ïŒPATHæªééïŒbash 3.2ã®é£æ³é åïŒæ¥æ¬èªã³ãããã¡ãã»ãŒãžã®æååãïŒset -u ãš trap ã®åã¿åããïŒStandardOutPath ã®äžæžãïŒä»¥å€ã§å®éã«è©°ãŸã£ãããããã¯è©°ãŸããããã€ã³ããç¶²çŸ ããŸãã
-
plist å ã®
~ã¯å±éãããªããStandardErrorPathã«~/.claude/logs/...ãšæžããšãlaunchd ã¯ãããæååãã®ãŸãŸè§£éããŸãã/çŽäžã«~ãšãããã£ã¬ã¯ããªãäœãããšããŠéãã«å€±æããŸããå®éã®ãã¡ã€ã«ã¯ãã¹ãŠ/Users/<username>/...圢åŒã®çµ¶å¯Ÿãã¹ã§èšè¿°ããŠããŸããPATH ã® EnvironmentVariables ãåæ§ã§ã$HOME倿°å±éã¯å¹ããŸããããæåã§åãã®ã« launchd ã§åããªããã®ç¬¬äºã®åå ãããã§ãã -
launchctl load㯠macOS Ventura 以éã§éæšå¥šã«ãªã£ããlaunchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/...plistãçŸè¡ã®æžãæ¹ã§ããloadã§ãåããŸãããmacOS ã®ããŒãžã§ã³ã¢ããã§æåãå€ãããªã¹ã¯ããããŸããæ°èŠäœææããbootstrap/bootoutã«æ £ããŠããæ¹ãå®å šã§ãã -
ã³ãããããªãïŒç©ºã®ïŒãªããžããªã REPOS ãªã¹ãã«å ¥ãããš ERR ãçºç«ããã
git log -1 --format='%ct'ã¯ã³ããããŒãã®ãªããžããªã§ç©ºæåãè¿ããŸããçŸåšã®ã¹ã¯ãªããã¯[ -n "$LAST_COMMIT_TS" ] && [ "$LAST_COMMIT_TS" -gt 0 ] 2>/dev/nullã®ã¬ãŒããéããŠãããåžåããŠããŸããæ°ãããªããžããªãREPOSã«è¿œå ããçŽåŸã®ååå®è¡ã§ãstale ãã§ãã¯ãåºãªããã®ã¯ãã®ã¬ãŒããæ©èœããŠãã蚌æ ã§ããç°åžžã§ã¯ãããŸããã -
macOS 忢±ã®
python3ãXcodeããŒã«ã®ã€ã³ã¹ããŒã«ãã€ã¢ãã°ãåºãã Homebrew æªå°å ¥ã®ã¯ãªãŒã³ç°å¢ã§ã¯ã/usr/bin/python3ã®ååèµ·åæã«GUIãã€ã¢ãã°ãéããŸããlaunchd çµç±ã§ã¯ç»é¢ã衚瀺ãããã³ãã³ãããã³ã°ããŸããplist ã® PATH ã«/opt/homebrew/binãå é ã«å«ããããšã§ Homebrew é äžã®python3ãåªå ããããã®åé¡ã¯çºçããŸãããHomebrew ã䜿ã£ãŠãããªã远å äœæ¥ã¯äžèŠã§ãã -
for REPO in $REPOSã¯ãã¹ã«ã¹ããŒã¹ããããš2ããŒã¯ã³ã«åå²ãããã ã¹ã¯ãªããã¯ã¯ãŒãåå²ãå©çšããŠæ¹è¡åºåãã®ãªã¹ãåŠçãããŠããããã~/dev/my projectã®ãããªã¹ããŒã¹å ¥ããã¹ã¯~/dev/myãšprojectã«åå²ãããŠäž¡æ¹ãããã£ã¬ã¯ããªãèŠã€ãããªããã§ ðŽ ã«ãªããŸããçŸåšç®¡çããŠããshukatsu-trackerãšseo-affiliate-siteã¯ã¹ããŒã¹ãªããªã®ã§åé¡ãããŸããããç§»æ€å ã§ãã£ã¬ã¯ããªåã«æ³šæãå¿ èŠã§ãã -
ã¹ãªãŒãäžã«ééããå®è¡æå»ã¯æ¬¡ã®èµ·åãŸã§é£ã°ãããã
StartCalendarInterval㯠cron ãšåãæåã§ãMac ãã¹ãªãŒãäžã ã£ãå Žåããã®æå»ã®å®è¡ãã¹ãããããŸããç¿æ 7:30 ãŸã§latest.mdã¯åæ¥ä»ãã®ãŸãŸæ®ããŸããã仿¥åã®ã¬ããŒããåºãŠããªãããšæã£ãããŸãã¹ãªãŒãã®ç¢ºèªã§ãã解決çã¯StartIntervalïŒç§æ°ããšïŒã§ãããéçºäžã«äžæãªã¿ã€ãã³ã°ã§èµ°ããã¡ãªããããããŸããæ PC ãéãç¿æ £ãããã°StartCalendarIntervalã®ãŸãŸã§å®çšäžã¯åé¡ãããŸããã -
latest.mdãå€ããŸãŸæ¢ãŸã£ãŠããããéäž exitãã®ãµã€ã³ãšèªããtrap 'exit 0' ERRã«ããç¡é³çµäºã¯ãcp "$OUT" "$LATEST"ã«å°éããåã«çºçããããšããããŸãããã®å Žålatest.mdã¯åæ¥åã®ãŸãŸæ®ããŸãããlatest ãæšæ¥ä»ããã®ç¶æ ãæ€ç¥ããããcom.shun.project-health.logã確èªããã®ãæçã®èšºæã«ãŒãã§ãã -
du -skã®åºåã空ã«ãªãã±ãŒã¹ããããnode_modulesãååšããŠãã¢ã¯ã»ã¹æš©éããªããšdu -skã¯äœãè¿ããŸãããã¹ã¯ãªããã¯NM_KB=$(... 2>/dev/null)ã®ããšã§[ -z "$NM_KB" ] && NM_KB=0ã眮ããŠããããã空ã®å Žå㯠0 ãšããŠåŠçãããŸãããnode_modules ãæããã«ããã®ã«â衚瀺ã«ãªããå Žåã¯ããŒããã·ã§ã³ã確èªããŠãã ããã -
.env.exampleãé€å€ãããªãæžãæ¹ããããšãã€ãºãåºããgrep -E '(^|/)\.env($|\.)' | grep -v '\.env\.example$'ã® 2 段ãã£ã«ã¿ãæ£ããæžãæ¹ã§ããæåã«grep -E '\.env'ã ãã§æžããš.env.exampleãåŒã£ãããããã³ãã¬ãŒããã¡ã€ã«ã ðŽ èŠåãåºãç¶ããŸããæåã®ããŒãžã§ã³ã§ããããããå šãªããžããªãåžžæ ðŽ ãšããç¶æ ãäžæ¥æŸçœ®ããŸããã -
launchctl list | grep com.shun.project-healthã§ PID ãåºãªãã®ã¯æ£åžžã ãã®ãžã§ãã¯ã¹ã±ãžã¥ãŒã«èµ·ååã§ãå®è¡äžä»¥å€ã¯åžžé§ããŸãããPIDåã-ã§ãåé¡ãããŸãããLastExitStatusã 0 ã§ããããšã確èªããæ¹ãæçšã§ããlaunchctl list com.shun.project-healthã§ JSON 圢åŒã®è©³çްãåºãã®ã§ãLastExitStatusãšLastExitDateãèŠãŠæ£åžžåäœã確èªããŸãã
ãã¹ããã©ã¯ãã£ã¹
1. ç£èŠã¹ã¯ãªãã㯠fail-open ã§èšèšãã
trap 'exit 0' ERR ãåé ã«çœ®ããã¹ã¯ãªãããå£ããŠãæ¬æ¥ã®ãã«ãã launchd ã®é£éã¢ã©ãŒããæ¢ããªããå¯çšæ§åªå
ã®ç£èŠããŒã«ã«ããã fail-open ã¯æ£è§£ã§ããã»ãã¥ãªãã£æèãšã¯éã®å€æã§ãã
2. git -C ã䜿ããã«ãŒãå
ã§ cd ãããªã
cd "$REPO" ããããšã次ã®ãªããžããªã«ç§»ãåã« cd ã®å€±æãæ³å®å€ã®ç¶æ
ãåŒãç¶ãããŸããgit -C "$REPO" status ã®ããã«åã³ãã³ããç¬ç«ããŠã¿ãŒã²ãããæãŠã°ãã«ãŒãããŸããå¯äœçšã¯åççã«çºçããŸããã
3. plist ã®å šãã¹ã絶察ãã¹ã§æžã
~ ã $HOME ã launchd ã§ã¯å±éãããŸãããEnvironmentVariables ã® PATH ã StandardErrorPath ã /Users/<username>/... ã®çµ¶å¯Ÿãã¹ã§æžããŸãããæåã§åãã®ã« launchd ã§åããªããã®åå ã®ååã¯ããã§ãã
4. nvm â Homebrew â system ã®é ã§ PATH ãæç€ºãã
launchd ã¯ã·ã§ã«ãããã¡ã€ã«ãèªãŸãªãããã/usr/bin:/bin çšåºŠã®çŽ ã® PATH ã§åããŸããplist ã® EnvironmentVariables ã«éçºç°å¢ãšåã PATH ãæžãããšã§ãpython3ã»gitã»node ã®æåã端æ«ãšå®å
šã«äžèŽããŸããã¹ã¯ãªãããæžããæ¬äººã®ç«¯æ«ä»¥å€ã§ãåãããã«ãªããŸãã
5. LowPriorityIO: true ãš Nice: 10 ãå¿
ãã»ããã«ãã
du -sk ã¯ãã£ã¹ã¯èªã¿åãã䌎ããŸããLowPriorityIO ã§ I/O ã¹ã±ãžã¥ãŒã©ããNice: 10 ã§ CPU ã¹ã±ãžã¥ãŒã©ããåŸåãã«ããŠããããšäŒããŸããç£èŠã¹ã¯ãªãããæ¬æ¥ã®ãã«ãã 1 ç§ã§ãé
å»¶ãããŠã¯ãããŸããã
6. StandardOutPath ãš StandardErrorPath ãåäžãã¡ã€ã«ã«åãã
å¥ãã¡ã€ã«ã«ãããšäž¡æ¹ãæ¯å®è¡ã§äžæžããããstdout ãš stderr ãçªãåãããã®ãé¢åã«ãªããŸããåããã¡ã€ã«ã«åããŠãããšã仿ã®ãžã§ããã©ãåããããã 1 ãã¡ã€ã«ã§å®çµããŸããä¿ææé㯠1 æ¥åã§ååã§ãã
7. STATUS_FLAG ã¯æ·±å»åºŠãå¢ãæ¹åã«ããå€ããªã
ð¡ ãžã®ææ Œã¯ãçŸåš ð¢ ã®ãšãã ãããðŽ ãžã®ææ Œã¯ç¡æ¡ä»¶ãäžåºŠä»ããæ·±å»ãªãã©ã°ã¯åŸã®ãã§ãã¯ã§è»œããªããŸãããè€æ°ã®åé¡ãéãªã£ããšããæãæ·±å»ãªã¢ã©ãŒããããŒãã«ã®å³ç«¯ã«æ®ãããšããäžç®ã§ã®å€æã«çŽçµããŸãã
8. åºåã¯ããŒãã«ãš Warnings ã® 2 段æ§ãã«ãã
ããŒãã«ã¯ãªããžããªæ°ãå¢ããŠã暪å¹
ãåºå®ã§ææ¡ã§ããŸããèŠåã®è©³çްïŒäœæ¥ stale ããã©ã®ãã¡ã€ã«ã tracked ãïŒãã»ã«ã«è©°ã蟌ããšåã厩ããŸãã詳现㯠## Warnings ã»ã¯ã·ã§ã³ã«åé¢ããããšã§ãã1 ç§ã§ãããšèŠããçšãšãæãäžãããçšãåããŸãã
9. bash 3.2 ã§åãããã«æžã
macOS ã® /bin/bash 㯠bash 3.2 ã®ãŸãŸã§ããplist ã /bin/bash -c ã䜿ã以äžãdeclare -AïŒé£æ³é
åïŒã mapfile ã䜿ããŸãããæ¹è¡åºåãã®æåå + ã¯ãŒãåå² + printf "%b" ã§æ¹è¡å±éãšããã·ã³ãã«ãªä»£æ¿ã§ãbash 3.2 ã§ãã®ãŸãŸåããŸãããå¶çŽãããã»ã©åçŽã«ãªããã®å¥œäŸã§ãã
10. tr ã sed ã䜿ãåã« LC_ALL=C ãä»ãã
ãã«ããã€ãæåïŒæ¥æ¬èªã®ã³ãããã¡ãã»ãŒãžãªã©ïŒãæ··ãããš tr ããã€ã誀èªèãèµ·ãããŸããLC_ALL=C tr '|' '/' ã§ãã€ãã¢ãŒãã«åãæ¿ããããšã§ãMarkdown ããŒãã«ã®ãã€ãæåãæååãã§å¢æ®ããåé¡ãé²ããŸãã
11. ç®è¡å±éã®åã«å¿ ã空æåãšæ°å€ã¬ãŒãã眮ã
if [ -n "$LAST_COMMIT_TS" ] && [ "$LAST_COMMIT_TS" -gt 0 ] 2>/dev/null; then
COMMIT_AGE_DAYS=$(( ($(date +%s) - LAST_COMMIT_TS) / 86400 ))
fi
set -u ç°å¢ã§ã¯æªå®çŸ©å€æ°ããšã©ãŒã«ãªããŸããã空æåã®ç®è¡å±éãåæ§ã«ãšã©ãŒã§ããtrap 'exit 0' ERR ãšçµã¿åããããšãã¬ãŒããªãã®ç®è¡å±éãç¡é³ã§ã¹ã¯ãªãããçµäºãããŸããã¬ãŒãã¯åé·ã«èŠããŸãããfail-open ã¹ã¯ãªããã®å¿
èŠã³ã¹ãã§ãã
12. æ¥ä»å¥ãã°ãš latest ã® 2 æ¬ç«ãŠã§åç
§ãåãã
OUT="$LOG_DIR/project-health-${DATE_TAG}.md"
LATEST="$LOG_DIR/project-health-latest.md"
cp "$OUT" "$LATEST" 2>/dev/null || true
æ¥ä»å¥ã¯é¡å確èªçšãlatest ã¯ã仿ã®ç¶æ
ãä»ããèªããããã®ã·ã§ãŒãã«ãããClaude Code ã®ã³ã³ããã¹ããå¥ã¹ã¯ãªããããåç
§ãããšãã¯åžžã« latest ãèªã¿ãŸãã|| true ã§ cp 倱æãã¬ãŒãããã®ã fail-open èšèšã®å»¶é·ã§ãã
13. head -N ã§åºåãå¿
ãæçã«ãã
.env ãã§ãã¯ã® | head -5 ããã®äŸã§ããç°åžžç¶æ
ã§å€§éã®è¡ãè¿ã£ãŠãããšããåºåãééãªãèšããã§ãã°ãã¡ã€ã«ãæ°çŸ MB ã«ããäºæ
ãé²ããŸãããæ£åžžæã¯ 0 è¡ã®ã¯ãã ãããã倧éã«è¿ã£ããããšããæèã§åã³ãã³ãã«äžéãèšããŸãã
14. ã¹ã¯ãªããåé ã§ mkdir -p ãå®è¡ãã
ååå®è¡ãã¯ãªãŒã³ç°å¢ãžã®ç§»æ€ã§ãã°ãã£ã¬ã¯ããªãååšããªãç¶æ
ã§ããæåã® mkdir -p "$LOG_DIR" ãä¿è·ããŸãããèªåã®ç°å¢ã§ã¯åãããå¥ã®ãã·ã³ã«æã£ãŠè¡ã£ããåããªãã£ããã®å
žååå ãæœ°ããŸãã
ãŸãšã
ãã®ä»çµã¿ã®æ žå¿ãäžèšã§èšããšããåé¡ã®çºèŠã人éã®æ³šæåããåãé¢ãã ããšã§ãã
æå120äžåã®ç¶æ
ãç¶æã§ããŠããã®ã¯ãã³ãŒããæžãéãå¢ããããã§ã¯ãããŸãããäŒç€Ÿéœåã§è§£éãããŠãŒãã«ãªã£ãçµéšããåŠãã ã®ã¯ãã䞊走ãããããžã§ã¯ãã¯å¿
ãè
æããããšããäºå®ã§ããã人éã1ã€ã®ãããã¯ãã«éäžããŠããéããã1ã€ã«ã¯èª°ãç®ãåããŠããŸããã.env ã®èª€ tracking ãã14æ¥ä»¥äžæŸçœ®ããã stale commit ããæ°ã¥ãããšãã«ã¯ããªããããªã£ãããã远ãæéã®ã»ããæå€±ã«ãªããŸãã
project-health.sh ãæ¯æ 7:30 ã«èµ°ãã~/.claude/logs/project-health-latest.md ã« Markdown ããŒãã«ãèœãšããŠãããäœæ¥ãå§ãããšãã«ãã®ãã¡ã€ã«ãäžç¥ããã ãã§ããã¹ãŠã®ãªããžããªã®ç¶æ
ãææ¡ã§ããŸããã¹ã¯ãªãããå£ããŠã trap 'exit 0' ERR ãæ¬æ¥ãå®ããlaunchd ã® LowPriorityIO ãš Nice: 10 ããã«ããšç«¶åããŸãããç£èŠãæ¬æ¥ã®éªéãããªãããããèšèšã®å
šäœæ¹éã§ãã
å®è£
ã§æãéèŠãªå€æã¯ãã·ã³ãã«ããå®ãç¶ããããšã§ãããbash 3.2 ã®å¶çŽã®ãããã§é£æ³é
åã䜿ããªãã£ãããšããçµæçã«æ¹è¡åºåãã®æååãšããããåçŽãªå®è£
ãéžã°ããŸãããpython3 ã JSON ããŒã¹ã«ã ã䜿ãããã®ä»ã¯ POSIX æºæ ã®ã·ã§ã«ã³ãã³ãã§å®çµãããããšã§ãHomebrew ã®æç¡ãããããç°å¢äŸåããããŸãããè€æ°ã®ãªããžããªã䞊走ãããå人éçºè
ã«ãšã£ãŠããæ¯æ5ç§ã§å
šäœãææ¡ã§ããç¶æ
ããçç£æ§ã®åå°ã§ãã
ä»çµã¿ã®å šäœåã»æ120äžã®å èš³ã»30æ¥æé ã¯æænoteã«ãŸãšããŠããŸãã
ð Claude CodeèªåŸç°å¢ã§ãå®éã©ã皌ãã â ä»çµã¿ã»å®äŸã»å§ãæ¹ã»ãµããŒã
LilyïŒ@bokuwalilyïŒâ å人éçºè ãClaude Code ã§èªåååºç€ãçµã¿ãªãããiOSã¢ããªãWebãµãŒãã¹ãéç£ããŠããŸã
- AIã§ãå¯ãŠãŠãåãä»çµã¿ããäœã£ãŠæ120äžã«ãã話㯠noteã®ææèšäº ã«ð°
- OSS: github.com/bokuwalily ð
- ææ°æ å ±ã»ãåãåãã㯠X @bokuwalily ãžð
çããã® â€ïž ãã·ã§ã¢ãå±ã¿ã«ãªããŸãïŒ