diff options
Diffstat (limited to 'link')
| -rwxr-xr-x | link/pi.sh | 88 |
1 files changed, 88 insertions, 0 deletions
@@ -229,3 +229,91 @@ case "${pi_status%%:*}" in locked) yellow "pi settings: pi holds its settings lock; left as is, the next link catches up" ;; error) red "pi settings: ${pi_status#*:}" ;; esac + +# pi's models.json, generated too. It used to be a plain symlink to the tracked +# file, which left a machine whose models come from somewhere other than a +# vendor's own API with nowhere to say so: pi reads providers from exactly one +# path (join(getAgentDir(), "models.json")), and a `providers` block in a +# settings fragment is inert, since the settings schema has no such key. +# +# So the same shape as the settings above: the repo's file, then every +# ~/.config/pi/models.d/*.json another layer or this machine puts there. Unlike +# the settings this is a plain generated file with no three-way merge -- pi +# never writes it, keeping its runtime state in the sibling models-store.json -- +# so what lands is whatever the repo and the fragments say. A hand-edit of +# ~/.pi/agent/models.json does not survive a relink; put it in a fragment. +pi_models_out="$(DRY_RUN="$is_dry_run" python3 - \ + "$config_dir/pi/models.json" \ + "$xdg_config_dir/pi/models.d" \ + "$pi_dir/models.json" <<'PY' +import glob, json, os, sys + +base_path, frag_dir, target = sys.argv[1:4] + + +def load(path): + with open(path) as f: + return json.load(f) + + +# The repo's providers, then each fragment's. A fragment may add a provider or +# replace one of the same name; any other top-level key takes the last file's +# value. Which provider came from where is reported: a fragment quietly +# shadowing a provider the repo ships would otherwise be invisible. +desired = {} +notes = [] +for path in [base_path] + sorted(glob.glob(os.path.join(frag_dir, "*.json"))): + try: + layer = load(path) + except (OSError, ValueError) as e: + print("error:cannot read %s: %s" % (path, e)) + sys.exit(0) + for key, value in layer.items(): + if key == "providers": + providers = desired.setdefault("providers", {}) + if path != base_path: + for name in value: + notes.append("%s %s by %s" % ( + name, + "replaced" if name in providers else "added", + os.path.basename(path), + )) + providers.update(value) + else: + desired[key] = value + +# A symlink is the pre-generation state: replace it, even with no fragments, so +# the live file is never the tracked one. +was_link = os.path.islink(target) +try: + current = None if was_link else load(target) +except (OSError, ValueError): + current = None + +for note in notes: + print("note:" + note) + +if current == desired: + print("unchanged:") +elif os.environ.get("DRY_RUN"): + print("would-write:" + ("replacing the link" if was_link else "merged changes")) +else: + tmp = target + ".dotfiles-tmp" + with open(tmp, "w") as f: + json.dump(desired, f, indent=2) + f.write("\n") + os.replace(tmp, target) + print("wrote:" + ("replaced the link" if was_link else "merged changes")) +PY +)" + +while IFS= read -r line +do + case "${line%%:*}" in + note) yellow "pi models: ${line#*:}" ;; + wrote) green "pi models: ${line#*:}" ;; + unchanged) green "pi models: unchanged" ;; + would-write) yellow "pi models will be generated: ${line#*:}" ;; + error) red "pi models: ${line#*:}" ;; + esac +done <<< "$pi_models_out" |
