- adapters/README.md: the harness boundary contract (env in, response on stdout, diagnostics stderr, exit 0 success) - adapters/pi: extracted current invocation unchanged - adapters/mock: deterministic MOSAIC_MOCK_RESPONSE echo (test-only) - run-agent.sh: name-validated dispatch to adapters/<name>/adapter.sh - config: optional execution.adapter (pi|mock), default pi, configVersion stays 1 — existing configs remain valid; selection authority is the config file (load_config exports it) - compose: MOSAIC_ADAPTER / MOSAIC_MOCK_RESPONSE passthrough; Containerfile installs adapters read-only; RELEASE -> 0.0.5 Verified: hello unchanged; mock verbatim via config; unknown adapter and path-traversal names refused in-container; invalid adapter exits 2. Closes #16
56 lines
1.7 KiB
Bash
Executable File
56 lines
1.7 KiB
Bash
Executable File
#!/bin/sh
|
|
# Load the four immutable contract files in fixed order and write the
|
|
# generated system prompt to /var/lib/mosaic/system-prompt.md.
|
|
#
|
|
# Order is normative: CONSTITUTION.md, STANDARDS.md, SOUL.md, USER.md.
|
|
set -eu
|
|
|
|
CONTRACT_DIR="${1:-/opt/mosaic/contracts}"
|
|
OUT="${2:-/var/lib/mosaic/system-prompt.md}"
|
|
|
|
FILES="CONSTITUTION.md STANDARDS.md SOUL.md USER.md"
|
|
|
|
if [ ! -d "$CONTRACT_DIR" ]; then
|
|
echo "load-contracts: contract directory not found: $CONTRACT_DIR" >&2
|
|
exit 1
|
|
fi
|
|
|
|
PARENT="$(dirname "$OUT")"
|
|
mkdir -p "$PARENT"
|
|
|
|
TEMP="$OUT.partial"
|
|
: > "$TEMP"
|
|
|
|
for f in $FILES; do
|
|
path="$CONTRACT_DIR/$f"
|
|
if [ ! -r "$path" ]; then
|
|
echo "load-contracts: missing contract file: $path" >&2
|
|
rm -f "$TEMP"
|
|
exit 1
|
|
fi
|
|
printf '===== CONTRACT: %s =====\n' "$f" >> "$TEMP"
|
|
cat "$path" >> "$TEMP"
|
|
printf '\n' >> "$TEMP"
|
|
done
|
|
|
|
# Sanctioned mission injection point (M4): when the task runner provides a
|
|
# mission snapshot, its objective and directives are appended AFTER the
|
|
# immutable contracts. Runtime data; never part of the contract fixtures.
|
|
if [ -n "${MOSAIC_MISSION_FILE:-}" ]; then
|
|
if [ ! -r "$MOSAIC_MISSION_FILE" ]; then
|
|
echo "load-contracts: MOSAIC_MISSION_FILE set but not readable: $MOSAIC_MISSION_FILE" >&2
|
|
rm -f "$TEMP"
|
|
exit 1
|
|
fi
|
|
printf '===== MISSION (runtime) =====\n' >> "$TEMP"
|
|
node -e '
|
|
const m = JSON.parse(require("fs").readFileSync(process.env.MOSAIC_MISSION_FILE, "utf8"));
|
|
process.stdout.write("Objective: " + m.objective + "\n");
|
|
for (const d of m.directives ?? []) process.stdout.write("- " + d + "\n");
|
|
' >> "$TEMP"
|
|
printf '\n' >> "$TEMP"
|
|
fi
|
|
|
|
mv "$TEMP" "$OUT"
|
|
echo "load-contracts: wrote $OUT from $CONTRACT_DIR" >&2
|