Documentation
¶
Overview ¶
Package paths resolves absolute, writable locations for the bot's runtime files. Two distinct trees are exposed:
- GetAssetsDir / Resolve: read-only assets (templates, strategies). In a packaged .app this is inside the bundle's Resources/ folder; in dev mode it's the in-tree assets/ dir.
- GetConfigDir / ResolveConfig: writable state (boot_profile, stats, attack_history, last_attack_report, attack_deploy_debug outputs, logs/). The default lives outside the project root on every platform so the wails dev filesystem watcher never sees state writes — wails dev treats any project-tree file change as a Go rebuild trigger and kills the active bot session to relaunch.
Resolution order for GetConfigDir:
- CLASHGO_CONFIG_DIR env var (tests, portable installs, two installs side by side — the only supported way to run two trees).
- os.UserConfigDir()/ClashGO on every platform: on macOS that is ~/Library/Application Support/ClashGO, on linux $XDG_CONFIG_HOME/ClashGO, on windows %APPDATA%/ClashGO.
- fallback → os.TempDir()/ClashGO
ONE TREE PER USER, for both binaries the project ships. This used to split by binary — a bundled .app (which is what `wails dev` runs: build/bin/ClashGO.app) got <base>/ClashGO while the unbundled CLI got <base>/ClashGO/dev — and that split quietly cost a live session its geometry: the display scale is a machine property, tuned with the CLI probe tools (cmd/resprobe, cmd/screendump -anchors) and pinned in config.json, so with the trees split the pin lived in the CLI's file while every app run read a different one, fell back to the geometry-derived scale measured 1.9% off at 1280x720, lost the troop-count label row to that drift, and turned deploy verification into blind top-up batches. A device setting cannot live in a per-binary tree.
GetAssetsDir follows the same one-tree rule as GetConfigDir: a wails-dev build reads the source assets/ tree it was built from rather than the stale copy the app bundle happens to carry, so `make pick-coords` and the running bot always agree about where the user's pins live. DescribeAssets reports which tree won and which one was ignored, so a run can log the pin file it actually obeyed.
Legacy compatibility: the first GetConfigDir() call runs a one-time migration that copies known state files into the resolved directory from every tree in legacyStateTrees (today: the old per-binary "dev" tree, and the project's cwd as before). Copy-not-move — the legacy copy stays where it was so manual recovery is trivial and a failed migration cannot lose data. Re-runs are also harmless: sync.Once + os.OpenFile(O_EXCL) ensure destination files are never truncated or overwritten.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FileAge ¶
FileAge reports how long ago path was last modified, and whether it could be read at all. Deploy logging uses it to say exactly which pin file a run obeyed and how stale it is — a run that names its geometry's mtime can no longer be silently attacking with last month's pins.
func GetAssetsDir ¶
func GetAssetsDir() string
GetAssetsDir returns the absolute path to the assets directory, honoring CLASHGO_ASSETS_DIR at call time so tests and portable installs can override without rebuilding.
ONE ASSET TREE, for the same reason GetConfigDir unified the state trees. The app bundle carries a COPY of assets/, taken when the bundle was last built, so a packaged app that reads its own copy attacks with whatever geometry was pinned at that moment while cmd/pick_coords writes assets/precision_config.json in the project tree and reports success. `wails dev` runs build/bin/ClashGO.app, so the developer loop is exactly the case that hits it: live 2026-09-27 the app spent a night attacking with pins from a bundle built 2026-08-10 (its TopRight deploy line resolved to (1086,263)->(699,130) — the bundle's edges scaled — while the pins the user had just drawn describe (816,130)->(1086,251)), which put troops on refused ground, the siege and every hero on one tile, and the spells on lines that were not the pinned ones.
A wails-dev build output (an executable under .../build/bin) therefore uses the source tree it was built from. An installed .app (anywhere else) still uses its bundle, which is the only tree it ships with.
func GetConfigDir ¶
func GetConfigDir() string
GetConfigDir returns the absolute path to the dir used for writable config and per-run state files. Reads CLASHGO_CONFIG_DIR on every call (via resolveConfigDir) so tests using t.Setenv still redirect, and runs the legacy migration at most once per process via sync.Once.
func Resolve ¶
Resolve joins the assets dir with a subpath (e.g. Resolve("templates") → <assets>/templates). Read-only by intent; callers needing a writable location should use ResolveConfig.
func ResolveConfig ¶
ResolveConfig joins the config dir with a subpath (e.g. ResolveConfig("stats.json") → <configDir>/stats.json). All per-run state reads/writes should funnel through this so the wails dev watcher never sees them.
Types ¶
type AssetsProvenance ¶
type AssetsProvenance struct {
// Dir is the asset tree in use.
Dir string
// Source says which rule picked Dir, in words.
Source string
// IgnoredDir is a second asset tree that was found but NOT used (today:
// the app bundle's own Resources/assets when a wails-dev tree outranks
// it). Empty when only one tree exists. When it is set, Dir and
// IgnoredDir are two different pin files and the run should say so.
IgnoredDir string
}
AssetsProvenance is what DescribeAssets reports.
func DescribeAssets ¶
func DescribeAssets() AssetsProvenance
DescribeAssets reports how GetAssetsDir resolved. Call it after any GetAssetsDir call in the same process (it is set on every resolution).