chain-studio/tools/today/propose.sh
flemming-it 891acd2ba2
Some checks failed
Security / Security check (push) Failing after 2s
refactor: rename internal Fai* design system + fai_ helpers to chain
The Studio design system, widgets and helpers carried a Fai* / fai_
prefix (FaiSpace, FaiColors, FaiTheme, FaiLog, 17 fai_*.dart files, the
faiBinary* l10n keys). Studio is the Ch∆In product, so rename them to
Chain* / chain_ — carefully preserving English fail/failure/failed.
Also fix stale references: the 'fai' binary in l10n strings -> 'chain',
FAI_* env vars (FAI_BIN/DATA_DIR/MODULES_DIR/TODAY/BOOTSTRAP_TOKEN) ->
CHAIN_*, fai_platform -> fai_chain, fai_hub -> chain_hub. Vendor
security-hook tooling (FAI_BANNED_TERMS_FILE) + the .fai bundle ext left.
flutter analyze + test: clean (20 passed).

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-06-16 17:53:17 +02:00

77 lines
2.4 KiB
Bash
Executable file

#!/usr/bin/env bash
# tools/today/propose.sh
#
# Orchestrates: collect → System-AI → write candidate YAML files.
# Defaults to a local Ollama at 127.0.0.1:11434 with gemma3:4b.
# See README.md for env-var overrides.
#
# Output: ~/.chain/today/proposals/<ISO-DATE>/candidate-<n>.yaml
# Operator then runs accept.sh with the chosen file.
set -euo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"
DATE="$(date -u +%Y-%m-%d)"
OUT_DIR="${CHAIN_TODAY_OUT:-$HOME/.chain/today/proposals/$DATE}"
N="${CHAIN_TODAY_N:-3}"
API="${CHAIN_TODAY_API:-http://127.0.0.1:11434/api/generate}"
MODEL="${CHAIN_TODAY_MODEL:-gemma3:4b}"
KEY="${CHAIN_TODAY_KEY:-}"
mkdir -p "$OUT_DIR"
signals="$("$HERE/collect.sh")"
template="$(cat "$HERE/prompt.template.md")"
prompt="${template//\{\{SIGNAL_INPUT\}\}/$signals}"
call_ollama() {
# Streaming off, single completion. The /api/generate endpoint
# returns one big JSON; we extract `.response`.
jq -n --arg model "$MODEL" --arg prompt "$prompt" \
'{model: $model, prompt: $prompt, stream: false}' \
| curl -fsS -X POST -H 'Content-Type: application/json' \
--data-binary @- "$API" \
| jq -r '.response'
}
call_openai_compatible() {
local body
body=$(jq -n --arg model "$MODEL" --arg prompt "$prompt" '{
model: $model,
messages: [{role: "user", content: $prompt}],
temperature: 0.6
}')
local hdr_args=()
if [ -n "$KEY" ]; then
hdr_args=(-H "Authorization: Bearer $KEY")
fi
printf '%s' "$body" \
| curl -fsS -X POST -H 'Content-Type: application/json' \
"${hdr_args[@]}" --data-binary @- "$API" \
| jq -r '.choices[0].message.content'
}
draft_one() {
case "$API" in
*"/generate"*) call_ollama ;;
*"/chat/completions"*) call_openai_compatible ;;
*)
printf 'unknown API path in %s — aborting\n' "$API" >&2
exit 2 ;;
esac
}
# Strip ```yaml fences if the model adds them despite the prompt.
clean_yaml() {
sed -e '/^```yaml$/d' -e '/^```$/d' -e 's/^```$//'
}
for n in $(seq 1 "$N"); do
out="$OUT_DIR/candidate-$n.yaml"
printf 'Drafting candidate %d/%d via %s (%s)…\n' "$n" "$N" "$API" "$MODEL"
draft_one | clean_yaml > "$out"
printf ' → %s (%d bytes)\n' "$out" "$(wc -c < "$out")"
done
printf '\nDone. Skim with:\n ls -la %s\n for f in %s/*.yaml; do echo "=== $f ==="; cat "$f"; done\n' \
"$OUT_DIR" "$OUT_DIR"
printf '\nAccept with:\n %s/accept.sh <path-to-chosen.yaml>\n' "$HERE"