fix(higgsfield): report upstream drift on every enable; final review fixes
This commit is contained in:
+1
-1
@@ -401,7 +401,7 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).
|
||||
`verification-before-completion` to the verifier gates.
|
||||
|
||||
### Security
|
||||
- `settings.json` `permissions.deny` now refuses `npm i -g`, `npm install --global` and `npm i --global`: the rule matched `npm install -g` only, so the other spellings of the same global install went through.
|
||||
- `settings.json` `permissions.deny` now refuses three more spellings of a global npm install (`npm i -g`, `npm install --global`, `npm i --global`): the rule matched `npm install -g` only. Not a complete list: forms with the flag after the package name, such as `npm i <pkg> -g`, still pass.
|
||||
- **Ten secret-reader deny rules added**: `sed`, `awk`, `cut`, `tr`,
|
||||
`sort`, `uniq`, `diff`, `od`, `xxd`, `strings` against `.env*`. Six of
|
||||
those tools sat in `permissions.allow`, so reading a `.env` through
|
||||
|
||||
@@ -380,11 +380,12 @@ bash lib/toggle-external.sh disable higgsfield
|
||||
`higgsfield` links a fixed list of seven media skills: generate, soul-id,
|
||||
product-photoshoot, brandkit, marketplace-cards, video-explainer and
|
||||
youtube-thumbnail. The list is `HIGGSFIELD_MEDIA_SKILLS` in
|
||||
`lib/toggle-external.sh`. A skill that upstream adds later is synced and
|
||||
reported, and stays unlinked until it is added there.
|
||||
`lib/toggle-external.sh`. A skill that upstream adds later is synced, and
|
||||
every `enable higgsfield` names it, the pack being on or not. It stays
|
||||
unlinked until it is added to the list.
|
||||
|
||||
`higgsfield-websites` is kept apart. Here it helps with landing pages inside
|
||||
the design stack (assets, references), and `higgsfield website
|
||||
`higgsfield-websites` is kept apart. It helps with landing pages inside the
|
||||
design stack (assets, references), and `higgsfield website
|
||||
create|deploy|publish` stays unused. Claude enables either toggle itself on
|
||||
an explicit ask (Skill routing in `CLAUDE.global.md`) and checks the price
|
||||
with `higgsfield generate cost` before a paid run.
|
||||
@@ -393,6 +394,10 @@ The skills are cloned, not installed with `npx skills add`: that installer
|
||||
links every skill into `~/.claude/skills` on each refresh, which would undo
|
||||
the off-by-default state.
|
||||
|
||||
After the first login, select a workspace once: `higgsfield workspace list`,
|
||||
then `higgsfield workspace set <id>`. Until then the account commands answer
|
||||
"No workspace selected", even though the session is active.
|
||||
|
||||
The package ships its binary through a postinstall script. If npm holds that
|
||||
script back, `higgsfield` exists on PATH and fails at once; reinstall with
|
||||
`npm install -g --allow-scripts=@higgsfield/cli @higgsfield/cli`.
|
||||
|
||||
@@ -59,15 +59,19 @@ higgsfield_sync_skills() {
|
||||
}
|
||||
|
||||
# _higgsfield_probe <args...>
|
||||
# Run `higgsfield <args>` silently, 15 s at most when `timeout` exists. The
|
||||
# CLI is closed source: a probe must never hang an installer, and what it
|
||||
# prints (a token, for `auth token`) must never reach a terminal or a log.
|
||||
# Run `higgsfield <args>` silently, 15 s at most when a timeout tool exists
|
||||
# (`timeout`, or `gtimeout` from Homebrew coreutils on macOS). The CLI is
|
||||
# closed source: a probe must never hang an installer, and what it prints
|
||||
# (a token, for `auth token`) must never reach a terminal or a log.
|
||||
_higgsfield_probe() {
|
||||
if command -v timeout >/dev/null 2>&1; then
|
||||
timeout 15 higgsfield "$@" </dev/null >/dev/null 2>&1
|
||||
else
|
||||
higgsfield "$@" </dev/null >/dev/null 2>&1
|
||||
local tool
|
||||
for tool in timeout gtimeout; do
|
||||
if command -v "$tool" >/dev/null 2>&1; then
|
||||
"$tool" 15 higgsfield "$@" </dev/null >/dev/null 2>&1
|
||||
return
|
||||
fi
|
||||
done
|
||||
higgsfield "$@" </dev/null >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# higgsfield_cli_ok — 0 when the binary answers. `command -v` alone only
|
||||
|
||||
@@ -110,6 +110,7 @@ probe() {
|
||||
|
||||
# ── sync ────────────────────────────────────────────────────
|
||||
UP="$WORK/upstream"; mk_upstream "$UP"
|
||||
# The repo path carries a space on purpose: every expansion must be quoted.
|
||||
R1="$WORK/r 1"; mkdir -p "$R1/skills" "$R1/skills-disabled"
|
||||
EXT="$R1/skills-external"
|
||||
|
||||
@@ -162,6 +163,12 @@ expect shim-only \
|
||||
"$(FAKE_HF_BINARY=missing probe "$BIN:$PATH" higgsfield_cli_ok)" "rc=1"
|
||||
expect no-cli "$(probe "$CLEAN" higgsfield_cli_ok)" "rc=127"
|
||||
expect no-timeout "$(probe "$BIN:$CLEAN" higgsfield_cli_ok)" "rc=0"
|
||||
# macOS spelling: only `gtimeout` exists. A wrapper, not a symlink: a
|
||||
# multi-call coreutils binary dispatches on the name it is invoked under.
|
||||
GT="$WORK/gtbin"; mkdir -p "$GT"
|
||||
printf '#!/bin/sh\nexec %s "$@"\n' "$(command -v timeout)" > "$GT/gtimeout"
|
||||
chmod +x "$GT/gtimeout"
|
||||
expect gtimeout "$(probe "$BIN:$GT:$CLEAN" higgsfield_signed_in)" "rc=0"
|
||||
verdict PROBES_SILENT
|
||||
|
||||
# ── toggle ──────────────────────────────────────────────────
|
||||
@@ -227,6 +234,11 @@ expect brandkit-off "$(yn test -e "$F8/skills/higgsfield-brandkit")" no
|
||||
expect_has reported "$out" "higgsfield-newcomer"
|
||||
expect_not noskill-quiet "$out" "higgsfield-noskill"
|
||||
expect links "$(entries "$F8/skills")" 2
|
||||
# Enabled is the steady state: a re-run must still name the drift.
|
||||
out="$(tog "$F8" enable higgsfield)"; rc=$?
|
||||
expect again-rc "$rc" 0
|
||||
expect_has again-state "$out" "higgsfield already enabled"
|
||||
expect_has again-reported "$out" "higgsfield-newcomer"
|
||||
verdict UNLISTED_NOT_LINKED
|
||||
|
||||
F3="$WORK/f3"; mk_toggle_fx "$F3" "${PACK[@]}"
|
||||
|
||||
+16
-9
@@ -113,17 +113,21 @@ pack_skills() {
|
||||
esac
|
||||
}
|
||||
|
||||
# bounded <cmd...> — run a CLI probe silently, 15 s at most when `timeout`
|
||||
# exists: a closed-source binary must never hang a toggle, and what it
|
||||
# prints (a token) must never reach the terminal. Twin of
|
||||
# _higgsfield_probe in lib/higgsfield-skills.sh, kept here because this
|
||||
# script takes no extra `source` (the fixture suites copy it alone).
|
||||
# bounded <cmd...> — run a CLI probe silently, 15 s at most when a timeout
|
||||
# tool exists (`timeout`, or `gtimeout` from Homebrew coreutils on macOS):
|
||||
# a closed-source binary must never hang a toggle, and what it prints (a
|
||||
# token) must never reach the terminal. Twin of _higgsfield_probe in
|
||||
# lib/higgsfield-skills.sh, kept here because this script takes no extra
|
||||
# `source` (the fixture suites copy it alone).
|
||||
bounded() {
|
||||
if command -v timeout >/dev/null 2>&1; then
|
||||
timeout 15 "$@" </dev/null >/dev/null 2>&1
|
||||
else
|
||||
"$@" </dev/null >/dev/null 2>&1
|
||||
local tool
|
||||
for tool in timeout gtimeout; do
|
||||
if command -v "$tool" >/dev/null 2>&1; then
|
||||
"$tool" 15 "$@" </dev/null >/dev/null 2>&1
|
||||
return
|
||||
fi
|
||||
done
|
||||
"$@" </dev/null >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Post-enable notes for a pack. Its skills shell out to a CLI: without it
|
||||
@@ -322,6 +326,9 @@ enable_tool() {
|
||||
return 1
|
||||
fi
|
||||
warn "$tool already enabled"
|
||||
# Enabled is the steady state, and Claude re-runs this on every
|
||||
# media ask: the hints (upstream drift, CLI, session) show here too.
|
||||
if [ "$tool" = "higgsfield" ]; then pack_hints higgsfield; fi
|
||||
return 0
|
||||
fi
|
||||
ok "$tool enabled ($((restored + linked)) skills: $restored restored, $linked linked)"
|
||||
|
||||
+10
-3
@@ -489,14 +489,21 @@ print(d.get('higgsfield',{}).get('version','latest'))
|
||||
HF_PKG="@higgsfield/cli@latest"
|
||||
[ -n "$HF_VER" ] && [ "$HF_VER" != "latest" ] \
|
||||
&& HF_PKG="@higgsfield/cli@${HF_VER}"
|
||||
HF_NPM_OK=true
|
||||
npm install -g "$HF_PKG" 2>/dev/null || HF_NPM_OK=false
|
||||
# npm updates only a copy npm installed: a CLI that came from Homebrew
|
||||
# or the vendor's installer would otherwise gain a second, competing copy.
|
||||
HF_NPM=skipped
|
||||
if npm ls -g @higgsfield/cli >/dev/null 2>&1; then
|
||||
HF_NPM=ok
|
||||
npm install -g "$HF_PKG" 2>/dev/null || HF_NPM=failed
|
||||
fi
|
||||
# The probe first, then npm's status: an update that skips the package's
|
||||
# postinstall script exits 0 and leaves the shim with no binary behind it.
|
||||
if ! higgsfield_cli_ok; then
|
||||
warn "Higgsfield CLI does not answer after the update — run: npm install -g --allow-scripts=@higgsfield/cli @higgsfield/cli"
|
||||
elif [ "$HF_NPM_OK" = true ]; then
|
||||
elif [ "$HF_NPM" = ok ]; then
|
||||
ok "Higgsfield CLI updated (${HF_VER:-latest})"
|
||||
elif [ "$HF_NPM" = skipped ]; then
|
||||
info "Higgsfield CLI was not installed through npm — left to its own updater"
|
||||
else
|
||||
warn "Higgsfield CLI update failed — existing binary kept"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user