maybeAutoUpgradeSkill checks the recorded skill version against the running binary's version and, if they differ, refreshes the skill + SessionStart hook. Designed to run on every flow invocation so the user gets a self-healing upgrade flow after replacing the binary. The check is intentionally con
()
| 68 | } |
| 69 | if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil { |
| 70 | return err |
| 71 | } |
| 72 | return os.WriteFile(p, []byte(v+"\n"), 0o644) |
| 73 | } |
| 74 | |
| 75 | // maybeAutoUpgradeSkill checks the recorded skill version against the |
| 76 | // running binary's version and, if they differ, refreshes the skill + |
| 77 | // SessionStart hook. Designed to run on every flow invocation so the |
| 78 | // user gets a self-healing upgrade flow after replacing the binary. |
| 79 | // |
| 80 | // The check is intentionally conservative — it does nothing when: |
| 81 | // - The binary is a "dev" build (Version == "dev"). Local devs use |
| 82 | // `make install` and shouldn't fight an auto-installer. |
| 83 | // - The skill isn't installed at all (sentinel: SKILL.md missing). |
| 84 | // Treat this as an explicit user opt-out; never re-install. |
| 85 | // - The recorded version already matches Version. The common path. |
| 86 | // |
| 87 | // All errors are silent — auto-upgrade is best-effort plumbing, not a |
| 88 | // command. A user-visible failure here would be far more annoying |
| 89 | // than the eventual symptom of a stale skill. |
| 90 | func maybeAutoUpgradeSkill() { |
| 91 | if Version == "" || Version == "dev" { |
| 92 | return |
| 93 | } |
| 94 | h := defaultHarness() |
| 95 | skillPath, err := h.SkillInstallPath() |
| 96 | if err != nil { |
| 97 | return |