@zerwiz/ymir 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/agents/huginn-researcher.md +1 -1
- package/.agents/agents/kvasir-scout.md +1 -1
- package/.agents/agents/sindri-developer.md +1 -1
- package/.agents/backend/README.md +74 -0
- package/.agents/backend/model-bridge.py +74 -4
- package/.agents/config/cron.yaml +2 -0
- package/.agents/config/eindri-dispatch.json +6 -6
- package/.agents/migrations/0003-private-data-separation.sh +11 -1
- package/.agents/migrations/0005-roots-out-of-tree.sh +158 -0
- package/.agents/skills/README.md +1 -1
- package/.agents/skills/galdr-ymirsystem/SKILL.md +2 -1
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/README.md +73 -10
- package/.agents/skills/galdr-ymirsystem/assets/hlidskjalf-ui.md +44 -1
- package/.agents/skills/galdr-ymirsystem/assets/installation.md +215 -23
- package/.agents/skills/galdr-ymirsystem/assets/memory-well.md +3 -1
- package/.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md +39 -1
- package/.agents/skills/galdr-ymirsystem/assets/odrerir-hall.md +4 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/pi-profile.yml +7 -2
- package/.agents/skills/galdr-ymirsystem/assets/registry.md +1 -1
- package/.agents/skills/galdr-ymirsystem/assets/runtime-compliance.md +2 -2
- package/.agents/skills/galdr-ymirsystem/assets/smidja.md +16 -11
- package/.agents/skills/galdr-ymirsystem/scripts/compliance-check.sh +147 -4
- package/.agents/skills/groa-update/SKILL.md +20 -0
- package/.agents/skills/hamr-adapters/SKILL.md +2 -2
- package/.agents/skills/lifecycle/smoke_test.sh +7 -2
- package/.agents/skills/ymir-host/SKILL.md +2 -1
- package/.agents/skills/ymir-host/assets/install.md +69 -0
- package/AGENTS.md +78 -34
- package/CHANGELOG.md +1033 -1
- package/README.md +1 -1
- package/RULES/02-agents.md +2 -2
- package/RULES/04-hoard.md +32 -0
- package/RULES/06-append-only.md +50 -0
- package/RULES/07-config.md +56 -0
- package/RULES/09-electron.md +58 -0
- package/RULES/README.md +2 -0
- package/bin/a2a-mcp.sh +42 -7
- package/bin/agents-config.sh +30 -7
- package/bin/apodex-smoke-test.sh +14 -1
- package/bin/bifrost-bridge.sh +25 -6
- package/bin/bootstrap-macos.sh +6 -1
- package/bin/brokk-send.sh +14 -1
- package/bin/changelog-assemble.sh +154 -0
- package/bin/changelog-guard.sh +39 -7
- package/bin/crash-sense.sh +14 -1
- package/bin/design-check.sh +80 -0
- package/bin/design-icon.sh +153 -0
- package/bin/docs-guard.sh +2 -2
- package/bin/editor-place.sh +33 -15
- package/bin/eindri-acclaim.sh +14 -1
- package/bin/eindri-seat.sh +83 -0
- package/bin/eindri-seen.sh +14 -1
- package/bin/eindri-start.sh +14 -1
- package/bin/eir-doctor.sh +47 -1
- package/bin/feature-inventory.sh +73 -0
- package/bin/fleet-apply.sh +15 -2
- package/bin/github-deploy.sh +14 -1
- package/bin/gjallarhorn-expose.sh +43 -9
- package/bin/gjallarhorn-notify.sh +14 -1
- package/bin/gjallarhorn-purge.sh +14 -1
- package/bin/gjallarhorn-tunnel.sh +16 -3
- package/bin/groa-update.sh +9 -1
- package/bin/hall-snapshot.sh +21 -2
- package/bin/herdr-run.sh +23 -2
- package/bin/hlidskjalf-agents.sh +172 -0
- package/bin/hlidskjalf-usage.sh +196 -0
- package/bin/hoard-guard.sh +135 -0
- package/bin/hoard-lib.sh +91 -11
- package/bin/hodd.sh +28 -4
- package/bin/huginn-research-worker.sh +14 -1
- package/bin/local-model-lock.sh +22 -3
- package/bin/mimir-bridge.py +33 -0
- package/bin/mimir-bridge.sh +14 -1
- package/bin/mimir-reflect.sh +27 -0
- package/bin/mjollnir-webhook.sh +14 -1
- package/bin/mjollnir.sh +22 -3
- package/bin/model-hardware.sh +17 -3
- package/bin/model-resolve.sh +14 -1
- package/bin/nornir-job-hall-snapshot.sh +28 -0
- package/bin/nornir-job-nsr-compliance.sh +54 -0
- package/bin/npm-publish.sh +136 -0
- package/bin/omarchy-install.sh +18 -5
- package/bin/omarchy-plugins.sh +15 -2
- package/bin/omarchy-sense.sh +14 -1
- package/bin/pi-model-agnostic.sh +71 -0
- package/bin/private-guard.sh +20 -0
- package/bin/project-git.sh +18 -4
- package/bin/public-guard.sh +3 -2
- package/bin/sessrumnir-ensure.sh +1 -1
- package/bin/sessrumnir.sh +16 -3
- package/bin/smidja-bootstrap.sh +5 -1
- package/bin/syn-asset-pretool-check.sh +14 -1
- package/bin/syn-spawn-pretool-check.sh +58 -0
- package/bin/tailscale-sync.sh +15 -2
- package/bin/telegram-bot.sh +14 -1
- package/bin/ui-truth-check.sh +75 -0
- package/bin/valknut-load.sh +42 -4
- package/bin/wedge-notify.sh +14 -1
- package/bin/workspace-rag.sh +14 -1
- package/bin/ymir-install.sh +219 -54
- package/bin/ymir-plan.sh +356 -0
- package/bin/ymir-say.sh +14 -1
- package/bin/ymir-setup-auth.sh +12 -1
- package/bin/ymir-validate.sh +28 -8
- package/docs/lore.md +5 -1
- package/docs/runbooks/agents.md +1 -1
- package/package.json +13 -3
- package/scripts/electron.sh +74 -15
- package/scripts/lower.sh +34 -0
- package/scripts/raise.sh +42 -0
- package/scripts/start.sh +52 -2
- package/.agents/config/agents.yaml +0 -50
- package/.agents/config/tailscale-sync.yaml +0 -27
- package/.agents/memory/kaia.engram +0 -0
- package/.agents/memory/kaia.engram-shm +0 -0
- package/.agents/memory/kaia.engram-wal +0 -0
- package/.agents/memory/well/episodes.jsonl +0 -367
- package/.agents/memory/well/workspace.jsonl +0 -27
package/bin/public-guard.sh
CHANGED
|
@@ -43,8 +43,9 @@ leaks() { # stdin → prints masked hits, returns 1 on any
|
|
|
43
43
|
scan_one() { # $1 = path in the index; prints a finding, returns 1 when clean
|
|
44
44
|
local f="$1" out
|
|
45
45
|
# This file necessarily contains the patterns it looks for; scanning it would
|
|
46
|
-
# always fail.
|
|
47
|
-
|
|
46
|
+
# always fail. The same is true of every guard whose job is to name a secret
|
|
47
|
+
# shape, so all three are exempt by name — and the patterns in them stay honest.
|
|
48
|
+
case "$f" in bin/public-guard.sh|bin/secret-guard.sh|bin/hoard-guard.sh) return 0 ;; esac
|
|
48
49
|
printf '%s\n' "$f" | grep -Eq "$PUBLIC" || return 0
|
|
49
50
|
printf '%s\n' "$f" | grep -Eq "$APPEND_ONLY" && return 0
|
|
50
51
|
out="$(git -C "$ROOT" show ":$f" 2>/dev/null | leaks)" || true
|
package/bin/sessrumnir-ensure.sh
CHANGED
package/bin/sessrumnir.sh
CHANGED
|
@@ -14,9 +14,22 @@ set -u
|
|
|
14
14
|
VERSION="1.0.0"
|
|
15
15
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
16
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
17
|
+
|
|
18
|
+
# The roots that live OUTSIDE the code tree: this machine's records and the
|
|
19
|
+
# runtime state belong to the home the operator chose at installation, never in
|
|
20
|
+
# the tree — a packaged install replaces its tree on upgrade (Rule 04).
|
|
21
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
22
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
23
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
24
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
25
|
+
done
|
|
26
|
+
unset _yr _yc
|
|
27
|
+
fi
|
|
28
|
+
hoard_state_dir YMIR_STATE_DIR
|
|
29
|
+
hoard_data_dir YMIR_DATA_DIR
|
|
17
30
|
APP="$ROOT/apps/sessrumnir"
|
|
18
|
-
PID_FILE="$
|
|
19
|
-
LOG_FILE="$
|
|
31
|
+
PID_FILE="$YMIR_STATE_DIR/sessrumnir.pid"
|
|
32
|
+
LOG_FILE="$YMIR_STATE_DIR/sessrumnir.log"
|
|
20
33
|
|
|
21
34
|
case "${1-}" in -v|-V|--version) printf '%s\n' "$VERSION"; exit 0 ;; -h|--help|"") sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; esac
|
|
22
35
|
ACTION="${1:-start}"; shift || true
|
|
@@ -72,7 +85,7 @@ fi
|
|
|
72
85
|
exit 1
|
|
73
86
|
}
|
|
74
87
|
|
|
75
|
-
mkdir -p "$
|
|
88
|
+
mkdir -p "$YMIR_STATE_DIR"
|
|
76
89
|
args=()
|
|
77
90
|
[ -n "$WORKSPACE" ] && args+=("$WORKSPACE")
|
|
78
91
|
|
package/bin/smidja-bootstrap.sh
CHANGED
|
@@ -69,7 +69,11 @@ if command -v uv >/dev/null 2>&1; then
|
|
|
69
69
|
python3 -c '
|
|
70
70
|
import os, sys
|
|
71
71
|
from pathlib import Path
|
|
72
|
-
|
|
72
|
+
root = Path.cwd()
|
|
73
|
+
for sub in ("apps/smidja", "smidja"):
|
|
74
|
+
p = root / sub
|
|
75
|
+
if (p / "smidja_modules").is_dir():
|
|
76
|
+
sys.path.insert(0, str(p)); break
|
|
73
77
|
from smidja_modules.tracer import Tracer
|
|
74
78
|
db = os.environ["SMIDJA_BS_DB"]
|
|
75
79
|
events = str(Path(db).parent / "sessions" / "bootstrap" / "events.jsonl")
|
|
@@ -16,7 +16,20 @@ set -u
|
|
|
16
16
|
|
|
17
17
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
18
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
19
|
-
|
|
19
|
+
|
|
20
|
+
# The roots that live OUTSIDE the code tree: this machine's records and the
|
|
21
|
+
# runtime state belong to the home the operator chose at installation, never in
|
|
22
|
+
# the tree — a packaged install replaces its tree on upgrade (Rule 04).
|
|
23
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
24
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
25
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
26
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
27
|
+
done
|
|
28
|
+
unset _yr _yc
|
|
29
|
+
fi
|
|
30
|
+
hoard_state_dir YMIR_STATE_DIR
|
|
31
|
+
hoard_data_dir YMIR_DATA_DIR
|
|
32
|
+
READS="${SYN_ASSET_READS:-$YMIR_STATE_DIR/asset-reads}"
|
|
20
33
|
TARGET=""; NOTE=""
|
|
21
34
|
while [ $# -gt 0 ]; do
|
|
22
35
|
case "$1" in
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# syn-spawn-pretool-check.sh - PreToolUse seatbelt for spawning and for typing.
|
|
3
|
+
#
|
|
4
|
+
# Sýn guards how workers are raised. The failure this exists to end, observed
|
|
5
|
+
# live: an agent (me) hand-fired `herdr-run.sh eindri`, then delivered the brief
|
|
6
|
+
# by TYPING it into the pane — and when the agent had already exited the brief
|
|
7
|
+
# was typed into **bash**, where it sat as a command. Workers were "sent" and
|
|
8
|
+
# never started, and text was executed in a shell. One door exists for this and
|
|
9
|
+
# it is `bin/einherjar-spawn.sh` (firstmate's `fm-spawn.sh`, ported): it creates
|
|
10
|
+
# the worktree, records `state/<id>.meta`, and fails closed on an unverified
|
|
11
|
+
# harness.
|
|
12
|
+
#
|
|
13
|
+
# Usage: syn-spawn-pretool-check.sh --command <bash command>
|
|
14
|
+
# Exit: 0 = allow, 2 = block (stderr carries the reason and the remedy)
|
|
15
|
+
set -u
|
|
16
|
+
|
|
17
|
+
command_text=""
|
|
18
|
+
while [ $# -gt 0 ]; do
|
|
19
|
+
case "$1" in
|
|
20
|
+
--command) command_text=${2-}; shift 2 ;;
|
|
21
|
+
*) shift ;;
|
|
22
|
+
esac
|
|
23
|
+
done
|
|
24
|
+
|
|
25
|
+
# 1. Never type into a pane. A brief is not keystrokes: typing lands in whatever
|
|
26
|
+
# owns the pane, and when the agent has exited that is the shell.
|
|
27
|
+
case "$command_text" in
|
|
28
|
+
*"pane input"*|*"send-keys"*|*"pane type"*)
|
|
29
|
+
printf 'denied: do not type into a pane — a brief delivered as keystrokes lands in whatever owns it (a shell, once the agent has exited)\n' >&2
|
|
30
|
+
printf 'help: seat the worker through the door: bin/einherjar-spawn.sh <task-id> <project-dir> --mode local-only --harness opencode --model <model> --backend herdr\n' >&2
|
|
31
|
+
exit 2 ;;
|
|
32
|
+
esac
|
|
33
|
+
|
|
34
|
+
# 2. Never hand-raise an Eindri. `herdr-run.sh run` (a command in a pane) is
|
|
35
|
+
# fine; raising a WORKER by hand is not — it skips the worktree, the meta
|
|
36
|
+
# record, and the harness verification.
|
|
37
|
+
case "$command_text" in
|
|
38
|
+
*"herdr-run.sh eindri"*|*"herdr-run.sh agent"*)
|
|
39
|
+
printf 'denied: an Eindri is raised through the door, not by hand — herdr-run.sh eindri skips the worktree, state/<id>.meta, and the harness check\n' >&2
|
|
40
|
+
printf 'help: bin/einherjar-spawn.sh <task-id> <project-dir> --mode <direct-PR|local-only|no-mistakes> [--harness <name>] [--model <name>] [--backend tmux|herdr]\n' >&2
|
|
41
|
+
exit 2 ;;
|
|
42
|
+
esac
|
|
43
|
+
|
|
44
|
+
# 3. A LOCAL model needs a live local server. Requesting one while the router is
|
|
45
|
+
# down is how a seat came up, errored, and left a shell behind.
|
|
46
|
+
case "$command_text" in
|
|
47
|
+
*"einherjar-spawn.sh"*)
|
|
48
|
+
case "$command_text" in
|
|
49
|
+
*"llama-cpp/"*|*"llama.cpp/"*|*"lmstudio/"*|*"ollama/"*)
|
|
50
|
+
if ! (exec 3<>/dev/tcp/127.0.0.1/8080) 2>/dev/null; then
|
|
51
|
+
printf 'denied: a local model was requested but no local server answers on :8080 — the worker will start, fail, and leave a shell\n' >&2
|
|
52
|
+
printf 'help: raise the llama-router (bin/models-detect.sh reports what is served), or seat the worker on an online model\n' >&2
|
|
53
|
+
exit 2
|
|
54
|
+
fi ;;
|
|
55
|
+
esac ;;
|
|
56
|
+
esac
|
|
57
|
+
|
|
58
|
+
exit 0
|
package/bin/tailscale-sync.sh
CHANGED
|
@@ -16,7 +16,20 @@ set -u
|
|
|
16
16
|
VERSION="1.0.0"
|
|
17
17
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
18
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
19
|
-
|
|
19
|
+
|
|
20
|
+
# The operator's settings and secrets live in the home they chose, never in the
|
|
21
|
+
# code tree — a packaged install replaces its tree on upgrade, and a credential
|
|
22
|
+
# must never sit in a tree that ships (Rule 04).
|
|
23
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
24
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
25
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
26
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
27
|
+
done
|
|
28
|
+
unset _yr _yc
|
|
29
|
+
fi
|
|
30
|
+
hoard_settings_dir YMIR_SETTINGS_DIR
|
|
31
|
+
hoard_local_env YMIR_ENV_FILE
|
|
32
|
+
CFG="${YMIR_TAILSCALE_SYNC:-$YMIR_SETTINGS_DIR/tailscale-sync.yaml}"
|
|
20
33
|
DRY=0; ACTION=""; PEER=""
|
|
21
34
|
|
|
22
35
|
for a in "$@"; do
|
|
@@ -62,7 +75,7 @@ except Exception: pass' 2>/dev/null)"
|
|
|
62
75
|
fi
|
|
63
76
|
|
|
64
77
|
if [ "$ACTION" = init ]; then
|
|
65
|
-
TPL="$
|
|
78
|
+
TPL="$YMIR_SETTINGS_DIR/tailscale-sync.example.yaml"
|
|
66
79
|
if [ -r "$CFG" ]; then printf 'tailscale-sync[1]{action,state}:\n "init","kept — %s exists"\n' "$CFG"; exit 0; fi
|
|
67
80
|
[ -r "$TPL" ] || { printf 'error: template missing: %s\n' "$TPL" >&2; exit 1; }
|
|
68
81
|
cp "$TPL" "$CFG" && printf 'tailscale-sync[1]{action,path}:\n "init","%s"\n' "$CFG"
|
package/bin/telegram-bot.sh
CHANGED
|
@@ -12,7 +12,20 @@ set -u
|
|
|
12
12
|
VERSION="1.0.0"
|
|
13
13
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
14
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
# The operator's settings and secrets live in the home they chose, never in the
|
|
17
|
+
# code tree — a packaged install replaces its tree on upgrade, and a credential
|
|
18
|
+
# must never sit in a tree that ships (Rule 04).
|
|
19
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
20
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
21
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
22
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
23
|
+
done
|
|
24
|
+
unset _yr _yc
|
|
25
|
+
fi
|
|
26
|
+
hoard_settings_dir YMIR_SETTINGS_DIR
|
|
27
|
+
hoard_local_env YMIR_ENV_FILE
|
|
28
|
+
ENV_FILE="${BROKK_ENV_FILE:-$YMIR_ENV_FILE}"
|
|
16
29
|
|
|
17
30
|
case "${1-}" in
|
|
18
31
|
-v|-V|--version) printf '%s\n' "$VERSION"; exit 0 ;;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ui-truth-check.sh — the panel's number must equal the machine's number.
|
|
3
|
+
#
|
|
4
|
+
# The wiring order's last row, and the one that makes the rest trustworthy: a
|
|
5
|
+
# board can render beautifully and still lie. This compares what the UI is SERVED
|
|
6
|
+
# against what the machine actually holds, per source, and FAILS on a mismatch.
|
|
7
|
+
#
|
|
8
|
+
# bin/ui-truth-check.sh # compare, TOON, exit 0/1
|
|
9
|
+
# bin/ui-truth-check.sh --help
|
|
10
|
+
#
|
|
11
|
+
# It reads endpoints as the DESKTOP SEAT (loopback + the marker), which is the
|
|
12
|
+
# trusted seat rule 09 allows — the web door would answer 401 and prove nothing
|
|
13
|
+
# about the data.
|
|
14
|
+
set -u
|
|
15
|
+
|
|
16
|
+
VERSION="1.0.0"
|
|
17
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
|
+
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
19
|
+
GATE="${HLIDSKJALF_API_PORT:-3889}"
|
|
20
|
+
# shellcheck source=bin/hoard-lib.sh
|
|
21
|
+
. "$SCRIPT_DIR/hoard-lib.sh"
|
|
22
|
+
|
|
23
|
+
case "${1-}" in
|
|
24
|
+
-v|-V|--version) printf '%s\n' "$VERSION"; exit 0 ;;
|
|
25
|
+
-h|--help) sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
|
26
|
+
esac
|
|
27
|
+
|
|
28
|
+
have() { command -v "$1" >/dev/null 2>&1; }
|
|
29
|
+
have curl || { printf 'error: curl is required\nhelp: install curl\n' >&2; exit 1; }
|
|
30
|
+
|
|
31
|
+
json_len() { python3 -c 'import json,sys
|
|
32
|
+
try: print(len(json.load(sys.stdin)))
|
|
33
|
+
except Exception: print(0)' 2>/dev/null || echo 0; }
|
|
34
|
+
|
|
35
|
+
verdict="PASS"; details=""
|
|
36
|
+
|
|
37
|
+
# ── the fleet: herdr vs the connector vs the endpoint ─────────────────────────
|
|
38
|
+
SRC_JSON="$("$SCRIPT_DIR/hlidskjalf-agents.sh" 2>/dev/null || printf '[]')"
|
|
39
|
+
src_n=$(printf '%s' "$SRC_JSON" | json_len)
|
|
40
|
+
UI_JSON="$(curl -s --max-time 8 -H 'x-ymir-surface: desktop' "http://127.0.0.1:${GATE}/api/agents" 2>/dev/null || printf '[]')"
|
|
41
|
+
ui_n=$(printf '%s' "$UI_JSON" | json_len)
|
|
42
|
+
if have "${HERDR_BIN_PATH:-herdr}"; then
|
|
43
|
+
herd_n="$("${HERDR_BIN_PATH:-herdr}" pane list 2>/dev/null | python3 -c 'import json,sys
|
|
44
|
+
try: d=json.load(sys.stdin)
|
|
45
|
+
except Exception: print(0); raise SystemExit
|
|
46
|
+
panes=(d.get("result") or {}).get("panes") or d.get("panes") or []
|
|
47
|
+
print(sum(1 for p in panes if p.get("agent")))' 2>/dev/null || echo 0)"
|
|
48
|
+
else
|
|
49
|
+
herd_n="unknown"
|
|
50
|
+
fi
|
|
51
|
+
[ "$src_n" = "$ui_n" ] || { verdict="FAIL"; details="$details fleet:connector=$src_n,served=$ui_n"; }
|
|
52
|
+
# The connector is ROSTER-FIRST: it reports the agents (the who) and the seats (the
|
|
53
|
+
# where), so its total legitimately exceeds the pane count. What must not happen is
|
|
54
|
+
# FEWER entries than panes - a standing seat hidden from the board. Panes are a subset.
|
|
55
|
+
[ "$herd_n" = "unknown" ] || [ "$src_n" -ge "$herd_n" ] || { verdict="FAIL"; details="$details fleet:connector=$src_n,herdr=$herd_n"; }
|
|
56
|
+
|
|
57
|
+
# ── the ledger: the hoard's, against what the gate serves ─────────────────────
|
|
58
|
+
hoard_root _hoard
|
|
59
|
+
LEDGER="$_hoard/memory/runes_audit.md"
|
|
60
|
+
ledger_n=0
|
|
61
|
+
[ -r "$LEDGER" ] && ledger_n=$(grep -c '^[[:space:]]*{' "$LEDGER" 2>/dev/null || echo 0)
|
|
62
|
+
UI_RUNES="$(curl -s --max-time 8 -H 'x-ymir-surface: desktop' "http://127.0.0.1:${GATE}/api/runes" 2>/dev/null || printf '[]')"
|
|
63
|
+
ui_runes_n=$(printf '%s' "$UI_RUNES" | json_len)
|
|
64
|
+
[ "$ledger_n" = "$ui_runes_n" ] || { verdict="FAIL"; details="$details ledger=$ledger_n,served=$ui_runes_n"; }
|
|
65
|
+
|
|
66
|
+
printf 'ui_truth[6]{source,count,note}:\n'
|
|
67
|
+
printf ' "herdr panes","%s","what the machine holds"\n' "$herd_n"
|
|
68
|
+
printf ' "the connector","%s","bin/hlidskjalf-agents.sh"\n' "$src_n"
|
|
69
|
+
printf ' "the endpoint","%s","/api/agents as the desktop seat"\n' "$ui_n"
|
|
70
|
+
printf ' "ledger entries","%s","the hoard'"'"'s ledger"\n' "$ledger_n"
|
|
71
|
+
printf ' "ledger served","%s","/api/runes as the desktop seat"\n' "$ui_runes_n"
|
|
72
|
+
printf ' "verdict","%s","%s"\n' "$verdict" "$([ -n "$details" ] && printf 'mismatch:%s' "$details" || printf 'the board may be believed')"
|
|
73
|
+
|
|
74
|
+
[ "$verdict" = "PASS" ] || { printf 'error: the UI and the machine disagree\nhelp: %s\n' "${details:-see the rows above}" >&2; exit 1; }
|
|
75
|
+
exit 0
|
package/bin/valknut-load.sh
CHANGED
|
@@ -26,7 +26,7 @@ PI_GLOBAL="${HOME}/.pi/agent/agents"
|
|
|
26
26
|
# seated. This loader DEPLOYS that source into the single home.
|
|
27
27
|
PI_EXT_SRC="$ROOT/.pi/shared/extensions"
|
|
28
28
|
PI_EXT_HOME="${HOME}/.pi/agent/extensions"
|
|
29
|
-
OC_LOCAL="$ROOT/.opencode/
|
|
29
|
+
OC_LOCAL="$ROOT/.opencode/agents"
|
|
30
30
|
SKILLS="$ROOT/.agents/skills"
|
|
31
31
|
|
|
32
32
|
usage() {
|
|
@@ -167,6 +167,18 @@ fi
|
|
|
167
167
|
|
|
168
168
|
if [ "$MODE_OPENCODE" = 1 ]; then
|
|
169
169
|
add opencode-config "$ROOT/opencode.json" "$(config_out "$ROOT/opencode.json.example" "$ROOT/opencode.json")"
|
|
170
|
+
# OpenCode reads `.opencode/agents/` (PLURAL). The singular `.opencode/agent/`
|
|
171
|
+
# was never read by the harness at all — twenty correct symlinks in a directory
|
|
172
|
+
# no loader opens, which is why only the agents declared by hand in
|
|
173
|
+
# opencode.json ever appeared. Migrate a legacy singular dir forward so an old
|
|
174
|
+
# home heals instead of silently keeping its agents invisible.
|
|
175
|
+
if [ -d "$ROOT/.opencode/agent" ] && [ ! -e "$ROOT/.opencode/agents" ]; then
|
|
176
|
+
mv "$ROOT/.opencode/agent" "$ROOT/.opencode/agents" 2>/dev/null \
|
|
177
|
+
&& add opencode-migrate "$ROOT/.opencode/agents" "legacy .opencode/agent/ moved to .opencode/agents/" \
|
|
178
|
+
|| add opencode-migrate "$ROOT/.opencode/agents" "ERROR could not migrate"
|
|
179
|
+
fi
|
|
180
|
+
# Count what is bound here; the binding itself happens further down, after
|
|
181
|
+
# `link_agents` is defined (this block runs before that definition).
|
|
170
182
|
if [ -d "$OC_LOCAL" ]; then
|
|
171
183
|
n=$(ls "$OC_LOCAL"/*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
172
184
|
add opencode "$OC_LOCAL" "native ($n agents)"
|
|
@@ -190,6 +202,17 @@ if [ "$MODE_PI" = 1 ]; then
|
|
|
190
202
|
# Deploy the shared extensions into their single home. Copy, not link: a
|
|
191
203
|
# broken link would silently disable a tool, and pi reads the file directly.
|
|
192
204
|
# Idempotent — identical files are left untouched.
|
|
205
|
+
# The CONTRACT, deployed globally: pi reads an AGENTS.md from its agent home in
|
|
206
|
+
# every session, whatever the workspace. Without this, Sessrumnir (or any pi
|
|
207
|
+
# session) started in another project loads THAT project's rules and knows
|
|
208
|
+
# nothing of Ymir - no Brokk, no laws, no lore. Symlink, so the tree stays the
|
|
209
|
+
# single source and an update is picked up with no re-install.
|
|
210
|
+
if [ -d "$HOME/.pi/agent" ]; then
|
|
211
|
+
ln -sfn "$ROOT/AGENTS.md" "$HOME/.pi/agent/AGENTS.md" 2>/dev/null \
|
|
212
|
+
&& add pi-global-contract "$HOME/.pi/agent/AGENTS.md" "the Ymir contract, loaded in every pi session" \
|
|
213
|
+
|| add pi-global-contract "$HOME/.pi/agent/AGENTS.md" "ERROR"
|
|
214
|
+
fi
|
|
215
|
+
|
|
193
216
|
if [ -d "$PI_EXT_SRC" ]; then
|
|
194
217
|
mkdir -p "$PI_EXT_HOME" 2>/dev/null
|
|
195
218
|
dep_n=0
|
|
@@ -199,7 +222,22 @@ if [ "$MODE_PI" = 1 ]; then
|
|
|
199
222
|
if [ -f "$PI_EXT_HOME/$b" ] && cmp -s "$f" "$PI_EXT_HOME/$b"; then continue; fi
|
|
200
223
|
cp -f "$f" "$PI_EXT_HOME/$b" && dep_n=$((dep_n+1))
|
|
201
224
|
done
|
|
202
|
-
|
|
225
|
+
# Their supporting modules are one level away, under the extensions' own lib:
|
|
226
|
+
# the shared extensions require sibling lib modules, and deploying the
|
|
227
|
+
# top-level files ALONE ships extensions that cannot load. That is exactly
|
|
228
|
+
# what pi reported: Failed to load extension, Cannot find module ./lib/....
|
|
229
|
+
# A deploy that copies a file but not the module it imports is not a deploy.
|
|
230
|
+
PI_EXT_LIB="$ROOT/.pi/extensions/lib"
|
|
231
|
+
if [ -d "$PI_EXT_LIB" ]; then
|
|
232
|
+
mkdir -p "$PI_EXT_HOME/lib" 2>/dev/null
|
|
233
|
+
for f in "$PI_EXT_LIB"/*; do
|
|
234
|
+
[ -e "$f" ] || continue
|
|
235
|
+
b=$(basename "$f")
|
|
236
|
+
if [ -f "$PI_EXT_HOME/lib/$b" ] && cmp -s "$f" "$PI_EXT_HOME/lib/$b"; then continue; fi
|
|
237
|
+
cp -f "$f" "$PI_EXT_HOME/lib/$b" && dep_n=$((dep_n+1))
|
|
238
|
+
done
|
|
239
|
+
fi
|
|
240
|
+
add pi-extensions "$PI_EXT_HOME" "$dep_n deployed (shared single home, lib included)"
|
|
203
241
|
fi
|
|
204
242
|
fi
|
|
205
243
|
|
|
@@ -248,8 +286,8 @@ if [ "$MODE_STATUS" = 0 ]; then
|
|
|
248
286
|
add "${hd#.}-agents" "$ROOT/$hd/agents" "bound ($n)"
|
|
249
287
|
done
|
|
250
288
|
if [ -d "$ROOT/.opencode" ]; then
|
|
251
|
-
n=$(link_agents "$
|
|
252
|
-
add opencode-agents "$
|
|
289
|
+
n=$(link_agents "$OC_LOCAL" short) || n=0
|
|
290
|
+
add opencode-agents "$OC_LOCAL" "bound ($n)"
|
|
253
291
|
fi
|
|
254
292
|
fi
|
|
255
293
|
|
package/bin/wedge-notify.sh
CHANGED
|
@@ -20,7 +20,20 @@ CHANNEL="${1:-unknown}"
|
|
|
20
20
|
SUMMARY="${2:-}"
|
|
21
21
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
22
22
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
23
|
-
|
|
23
|
+
|
|
24
|
+
# The roots that live OUTSIDE the code tree: this machine's records and the
|
|
25
|
+
# runtime state belong to the home the operator chose at installation, never in
|
|
26
|
+
# the tree — a packaged install replaces its tree on upgrade (Rule 04).
|
|
27
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
28
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
29
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
30
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
31
|
+
done
|
|
32
|
+
unset _yr _yc
|
|
33
|
+
fi
|
|
34
|
+
hoard_state_dir YMIR_STATE_DIR
|
|
35
|
+
hoard_data_dir YMIR_DATA_DIR
|
|
36
|
+
STATE_DIR="${BROKK_STATE_OVERRIDE:-$YMIR_STATE_DIR}"
|
|
24
37
|
LOG="$STATE_DIR/wedge-alarm.log"
|
|
25
38
|
|
|
26
39
|
# "discard" is the library-mode default so no test posts a real notification.
|
package/bin/workspace-rag.sh
CHANGED
|
@@ -16,8 +16,21 @@ set -u
|
|
|
16
16
|
VERSION="1.0.0"
|
|
17
17
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
18
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
19
|
+
|
|
20
|
+
# The roots that live OUTSIDE the code tree: this machine's records and the
|
|
21
|
+
# runtime state belong to the home the operator chose at installation, never in
|
|
22
|
+
# the tree — a packaged install replaces its tree on upgrade (Rule 04).
|
|
23
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
24
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
25
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
26
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
27
|
+
done
|
|
28
|
+
unset _yr _yc
|
|
29
|
+
fi
|
|
30
|
+
hoard_state_dir YMIR_STATE_DIR
|
|
31
|
+
hoard_data_dir YMIR_DATA_DIR
|
|
19
32
|
STORE="$ROOT/.agents/memory/well/workspace.jsonl"
|
|
20
|
-
REALM_FILE="$
|
|
33
|
+
REALM_FILE="$YMIR_DATA_DIR/realm.md"
|
|
21
34
|
DEFAULT_REALM="$(head -n1 "$REALM_FILE" 2>/dev/null | tr -d '[:space:]')"
|
|
22
35
|
# Never assume the company's slug: resolve the operator's realm neutrally.
|
|
23
36
|
if [ -z "$DEFAULT_REALM" ]; then . "$SCRIPT_DIR/realm-lib.sh"; ymir_active_realm "$ROOT" DEFAULT_REALM; fi
|