@zerwiz/ymir 0.1.5 → 0.1.8
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 +290 -24
- 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 +1362 -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 +156 -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/einherjar-spawn.sh +9 -3
- package/bin/eir-doctor.sh +89 -1
- package/bin/electron-lib.sh +34 -0
- 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-board.sh +136 -0
- package/bin/smidja-bootstrap.sh +5 -1
- package/bin/smidja-lib.sh +49 -0
- 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 +257 -57
- package/bin/ymir-plan.sh +390 -0
- package/bin/ymir-say.sh +14 -1
- package/bin/ymir-setup-auth.sh +12 -1
- package/bin/ymir-style.sh +108 -0
- package/bin/ymir-validate.sh +64 -11
- package/bin/ymir.js +82 -34
- package/docs/design.md +2 -2
- 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 +65 -3
- 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/hodd.sh
CHANGED
|
@@ -42,6 +42,24 @@ PY
|
|
|
42
42
|
printf 'hodd[1]{action,file}:\n "load","%s"\n' "$f"
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
# Resolve a secrets path: if the plaintext is absent but an .age sibling and the
|
|
46
|
+
# hoard key exist, decrypt to stdout. Prints a path to a readable file (a temp
|
|
47
|
+
# when decrypted) via the result var. Secrets stay encrypted at rest; the agent
|
|
48
|
+
# never reads ciphertext directly — it asks for the resolved path.
|
|
49
|
+
resolve_secret() { # <file> <result-var>
|
|
50
|
+
local f=$1 var=$2 tmp key
|
|
51
|
+
if [ -r "$f" ]; then printf -v "$var" '%s' "$f"; return 0; fi
|
|
52
|
+
if [ -r "$f.age" ]; then
|
|
53
|
+
key="$HOARD/secrets/age.key"
|
|
54
|
+
command -v age >/dev/null 2>&1 || { printf 'error: %s is encrypted but age is not installed\nhelp: sudo pacman -S age\n' "$f.age" >&2; return 1; }
|
|
55
|
+
[ -r "$key" ] || { printf 'error: encrypted %s but no key at %s\n' "$f.age" "$key" >&2; return 1; }
|
|
56
|
+
tmp="$(mktemp)"; chmod 600 "$tmp"
|
|
57
|
+
age -d -i "$key" "$f.age" >"$tmp" 2>/dev/null || { rm -f "$tmp"; printf 'error: cannot decrypt %s\n' "$f.age" >&2; return 1; }
|
|
58
|
+
printf -v "$var" '%s' "$tmp"; return 0
|
|
59
|
+
fi
|
|
60
|
+
printf 'error: not readable: %s (and no %s.age)\n' "$f" "$f" >&2; return 1
|
|
61
|
+
}
|
|
62
|
+
|
|
45
63
|
case "$ACTION" in
|
|
46
64
|
path) printf '%s\n' "$HOARD" ;;
|
|
47
65
|
init)
|
|
@@ -56,23 +74,29 @@ case "$ACTION" in
|
|
|
56
74
|
load)
|
|
57
75
|
f="${1:-}"; [ -n "$f" ] || { printf 'error: load needs a path under the Hoard\n' >&2; exit 2; }
|
|
58
76
|
case "$f" in /*) ;; *) f="$HOARD/$f" ;; esac
|
|
59
|
-
|
|
77
|
+
resolve_secret "$f" rf || exit 1
|
|
78
|
+
load_env "$rf"
|
|
79
|
+
case "$rf" in "$f") ;; *) rm -f "$rf" ;; esac ;;
|
|
60
80
|
emit)
|
|
61
81
|
# Print `export KEY=value` lines (quoting-safe) for the CALLER to eval, so
|
|
62
82
|
# `eval "$(bin/hodd.sh emit <file>)"` sets the vars in the invoking shell.
|
|
83
|
+
# Transparently decrypts an .age sibling when the plaintext is absent.
|
|
63
84
|
f="${1:-}"; [ -n "$f" ] || { printf 'error: emit needs a path under the Hoard\n' >&2; exit 2; }
|
|
64
85
|
case "$f" in /*) ;; *) f="$HOARD/$f" ;; esac
|
|
65
|
-
|
|
66
|
-
python3 - "$
|
|
86
|
+
resolve_secret "$f" rf || exit 1
|
|
87
|
+
python3 - "$rf" <<'PY'
|
|
67
88
|
import re, shlex, sys
|
|
68
89
|
for line in open(sys.argv[1]):
|
|
69
90
|
m = re.match(r'^([A-Za-z_][A-Za-z0-9_]*)=(.*)$', line.rstrip("\n"))
|
|
70
91
|
if m:
|
|
71
92
|
print(f"export {m.group(1)}={shlex.quote(m.group(2))}")
|
|
72
93
|
PY
|
|
94
|
+
case "$rf" in "$f") ;; *) rm -f "$rf" ;; esac
|
|
73
95
|
;;
|
|
74
96
|
tenant)
|
|
75
97
|
t="${1:-}"; [ -n "$t" ] || { printf 'error: tenant needs a name\n' >&2; exit 2; }
|
|
76
|
-
|
|
98
|
+
resolve_secret "$HOARD/tenants/$t/.env" rf || exit 1
|
|
99
|
+
load_env "$rf"
|
|
100
|
+
case "$rf" in "$HOARD/tenants/$t/.env") ;; *) rm -f "$rf" ;; esac ;;
|
|
77
101
|
*) printf 'error: unknown action %s\nhelp: bin/hodd.sh [path|init|ls|load|emit|tenant]\n' "$ACTION" >&2; exit 2 ;;
|
|
78
102
|
esac
|
|
@@ -12,6 +12,19 @@ set -u
|
|
|
12
12
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
13
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
14
14
|
|
|
15
|
+
# The operator's settings and secrets live in the home they chose, never in the
|
|
16
|
+
# code tree — a packaged install replaces its tree on upgrade, and a credential
|
|
17
|
+
# must never sit in a tree that ships (Rule 04).
|
|
18
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
19
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
20
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
21
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
22
|
+
done
|
|
23
|
+
unset _yr _yc
|
|
24
|
+
fi
|
|
25
|
+
hoard_settings_dir YMIR_SETTINGS_DIR
|
|
26
|
+
hoard_local_env YMIR_ENV_FILE
|
|
27
|
+
|
|
15
28
|
BRIEF="" OUTDIR="" MODEL=""
|
|
16
29
|
while [ $# -gt 0 ]; do
|
|
17
30
|
case "$1" in
|
|
@@ -28,7 +41,7 @@ done
|
|
|
28
41
|
mkdir -p "$OUTDIR"
|
|
29
42
|
|
|
30
43
|
# Resolve env — source .env.local if present.
|
|
31
|
-
for f in "$
|
|
44
|
+
for f in "$YMIR_ENV_FILE" "${YMIR_HOARD:-$HOME/Documents/Ymir}/.env.local"; do
|
|
32
45
|
[ -f "$f" ] && . "$f" 2>/dev/null || true
|
|
33
46
|
done
|
|
34
47
|
|
package/bin/local-model-lock.sh
CHANGED
|
@@ -12,8 +12,27 @@ set -u
|
|
|
12
12
|
|
|
13
13
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
14
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
15
|
-
|
|
16
|
-
|
|
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
|
+
hoard_state_dir YMIR_STATE_DIR
|
|
29
|
+
hoard_data_dir YMIR_DATA_DIR
|
|
30
|
+
|
|
31
|
+
# The roots that live OUTSIDE the code tree: this machine's records and the
|
|
32
|
+
# runtime state belong to the home the operator chose at installation, never in
|
|
33
|
+
# the tree — a packaged install replaces its tree on upgrade (Rule 04).
|
|
34
|
+
CFG="${YMIR_AGENTS_YAML:-$YMIR_SETTINGS_DIR/agents.yaml}"
|
|
35
|
+
LOCK="$YMIR_STATE_DIR/local-model.lock"
|
|
17
36
|
WAIT="${LOCAL_MODEL_WAIT:-1800}"
|
|
18
37
|
|
|
19
38
|
[ $# -gt 0 ] || { printf 'error: usage: bin/local-model-lock.sh <command...>\n' >&2; exit 2; }
|
|
@@ -31,7 +50,7 @@ PY
|
|
|
31
50
|
)"
|
|
32
51
|
[ -n "$N" ] || N=1
|
|
33
52
|
|
|
34
|
-
mkdir -p "$
|
|
53
|
+
mkdir -p "$YMIR_STATE_DIR"
|
|
35
54
|
|
|
36
55
|
if [ "$N" -le 1 ]; then
|
|
37
56
|
# one at a time — exclusive lock, wait for the peer to finish
|
package/bin/mimir-bridge.py
CHANGED
|
@@ -49,6 +49,35 @@ def engine(agent: str | None) -> Engram:
|
|
|
49
49
|
return _pool[key]
|
|
50
50
|
|
|
51
51
|
|
|
52
|
+
def layers():
|
|
53
|
+
"""What the well actually holds, layer by layer - the record a UI reads."""
|
|
54
|
+
out = {"facts": 0, "facts_active": 0, "facts_superseded": 0, "entities": 0,
|
|
55
|
+
"edges": 0, "reflections": 0, "last_reflection": None, "vec_index": 0}
|
|
56
|
+
try:
|
|
57
|
+
con = sqlite3.connect(f"file:{STORE}?mode=ro", uri=True)
|
|
58
|
+
for key, sql in (
|
|
59
|
+
("facts", "select count(*) from facts"),
|
|
60
|
+
("facts_active", "select count(*) from facts where superseded_at is null"),
|
|
61
|
+
("facts_superseded", "select count(*) from facts where superseded_at is not null"),
|
|
62
|
+
("entities", "select count(*) from entities"),
|
|
63
|
+
("edges", "select count(*) from edges"),
|
|
64
|
+
("reflections", "select count(*) from reflections"),
|
|
65
|
+
("vec_index", "select count(*) from vec_episodes_rowids"),
|
|
66
|
+
):
|
|
67
|
+
try:
|
|
68
|
+
out[key] = int(con.execute(sql).fetchone()[0])
|
|
69
|
+
except Exception:
|
|
70
|
+
pass
|
|
71
|
+
try:
|
|
72
|
+
out["last_reflection"] = con.execute(
|
|
73
|
+
"select max(finished_at) from reflections").fetchone()[0]
|
|
74
|
+
except Exception:
|
|
75
|
+
pass
|
|
76
|
+
except Exception as e:
|
|
77
|
+
out["error"] = str(e)
|
|
78
|
+
return out
|
|
79
|
+
|
|
80
|
+
|
|
52
81
|
def count_episodes() -> int:
|
|
53
82
|
try:
|
|
54
83
|
con = sqlite3.connect(f"file:{STORE}?mode=ro", uri=True)
|
|
@@ -98,10 +127,14 @@ class Handler(BaseHTTPRequestHandler):
|
|
|
98
127
|
"agents": engine(None).list_agents(),
|
|
99
128
|
})
|
|
100
129
|
if u.path == "/inspect":
|
|
130
|
+
# THE LAYERS, not just the count. The smithy shows what it is told,
|
|
131
|
+
# and it was told three fields while the well holds six: a panel that
|
|
132
|
+
# reads only episodes cannot show that facts and entities exist.
|
|
101
133
|
return self._json(200, {
|
|
102
134
|
"store": str(STORE),
|
|
103
135
|
"episodes": count_episodes(),
|
|
104
136
|
"agents": engine(None).list_agents(),
|
|
137
|
+
**layers(),
|
|
105
138
|
})
|
|
106
139
|
if u.path == "/recent":
|
|
107
140
|
limit = int((q.get("limit") or ["60"])[0])
|
package/bin/mimir-bridge.sh
CHANGED
|
@@ -18,6 +18,19 @@ fi
|
|
|
18
18
|
VERSION="1.0.0"
|
|
19
19
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
20
20
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
21
|
+
|
|
22
|
+
# The roots that live OUTSIDE the code tree: this machine's records and the
|
|
23
|
+
# runtime state belong to the home the operator chose at installation, never in
|
|
24
|
+
# the tree — a packaged install replaces its tree on upgrade (Rule 04).
|
|
25
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
26
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
27
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
28
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
29
|
+
done
|
|
30
|
+
unset _yr _yc
|
|
31
|
+
fi
|
|
32
|
+
hoard_state_dir YMIR_STATE_DIR
|
|
33
|
+
hoard_data_dir YMIR_DATA_DIR
|
|
21
34
|
YMIR_HOME="${YMIR_HOME:-$HOME/Documents/Ymir}"
|
|
22
35
|
BRIDGE="$ROOT/bin/mimir-bridge.py"
|
|
23
36
|
DB="${ENGRAM_DB:-$YMIR_HOME/memory/kaia.engram}"
|
|
@@ -75,7 +88,7 @@ if ! "$PY" -c "import engram" 2>/dev/null; then
|
|
|
75
88
|
printf 'error: engram not installed for %s\nhelp: bin/prereq-ensure.sh engram (installs it into a compatible Python)\n' "$PY" >&2; exit 1
|
|
76
89
|
fi
|
|
77
90
|
|
|
78
|
-
mkdir -p "$
|
|
91
|
+
mkdir -p "$YMIR_STATE_DIR" "$(dirname "$DB")"
|
|
79
92
|
ENGRAM_DB="$DB" MIMIRSBRUNN_PORT="$PORT" nohup "$PY" "$BRIDGE" >"$LOG_FILE" 2>&1 &
|
|
80
93
|
echo $! >"$PID_FILE"
|
|
81
94
|
sleep 3
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# mimir-reflect — smelt the well's episodes into facts, through the LLAMA-ROUTER.
|
|
3
|
+
#
|
|
4
|
+
# The router is Ymir's one door to local models: its seats are llama.cpp on :8080
|
|
5
|
+
# (coding) and Apodex on :1234 (research/planning). NEVER point this at Ollama —
|
|
6
|
+
# ollama is the machine's own server, not a Ymir provider, and one local model
|
|
7
|
+
# rides the router at a time. Swap seats by re-pointing the router, not by
|
|
8
|
+
# reaching past it.
|
|
9
|
+
#
|
|
10
|
+
# bin/mimir-reflect.sh # the well, with the default seat
|
|
11
|
+
# YMIR_ROUTER_URL=http://127.0.0.1:8080/v1 YMIR_REFLECT_MODEL=qwen3.6-35b-a3b bin/mimir-reflect.sh
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
WELL="${YMIR_WELL:-${YMIR_HOME:-$HOME/Documents/Ymir}/memory/kaia.engram}"
|
|
15
|
+
BASE="${YMIR_ROUTER_URL:-http://127.0.0.1:1234/v1}"
|
|
16
|
+
MODEL="${YMIR_REFLECT_MODEL:-apodex-1.0-mini}"
|
|
17
|
+
|
|
18
|
+
[ -f "$WELL" ] || { echo "error: no well at $WELL" >&2; echo "help: set YMIR_WELL or run bin/mimir-bridge.py first" >&2; exit 1; }
|
|
19
|
+
|
|
20
|
+
echo "mimir-reflect[well,seat]:"
|
|
21
|
+
echo " \"$WELL\""
|
|
22
|
+
echo " \"$BASE\" model \"$MODEL\""
|
|
23
|
+
echo
|
|
24
|
+
|
|
25
|
+
# A local seat needs no key; an empty one keeps the OpenAI client quiet.
|
|
26
|
+
OPENAI_API_KEY="${OPENAI_API_KEY:-local}" \
|
|
27
|
+
exec engram reflect "$WELL" --llm openai --model "$MODEL" --base-url "$BASE"
|
package/bin/mjollnir-webhook.sh
CHANGED
|
@@ -13,7 +13,20 @@ set -u
|
|
|
13
13
|
VERSION="1.0.0"
|
|
14
14
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
15
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
# The operator's settings and secrets live in the home they chose, never in the
|
|
18
|
+
# code tree — a packaged install replaces its tree on upgrade, and a credential
|
|
19
|
+
# must never sit in a tree that ships (Rule 04).
|
|
20
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
21
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
22
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
23
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
24
|
+
done
|
|
25
|
+
unset _yr _yc
|
|
26
|
+
fi
|
|
27
|
+
hoard_settings_dir YMIR_SETTINGS_DIR
|
|
28
|
+
hoard_local_env YMIR_ENV_FILE
|
|
29
|
+
ENV_FILE="${BROKK_ENV_FILE:-$YMIR_ENV_FILE}"
|
|
17
30
|
|
|
18
31
|
case "${1-}" in
|
|
19
32
|
-v|-V|--version) printf '%s\n' "$VERSION"; exit 0 ;;
|
package/bin/mjollnir.sh
CHANGED
|
@@ -13,7 +13,26 @@ set -u
|
|
|
13
13
|
VERSION="1.0.0"
|
|
14
14
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
15
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
# The operator's settings and secrets live in the home they chose, never in the
|
|
18
|
+
# code tree — a packaged install replaces its tree on upgrade, and a credential
|
|
19
|
+
# must never sit in a tree that ships (Rule 04).
|
|
20
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
21
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
22
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
23
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
24
|
+
done
|
|
25
|
+
unset _yr _yc
|
|
26
|
+
fi
|
|
27
|
+
hoard_settings_dir YMIR_SETTINGS_DIR
|
|
28
|
+
hoard_local_env YMIR_ENV_FILE
|
|
29
|
+
hoard_state_dir YMIR_STATE_DIR
|
|
30
|
+
hoard_data_dir YMIR_DATA_DIR
|
|
31
|
+
|
|
32
|
+
# The roots that live OUTSIDE the code tree: this machine's records and the
|
|
33
|
+
# runtime state belong to the home the operator chose at installation, never in
|
|
34
|
+
# the tree — a packaged install replaces its tree on upgrade (Rule 04).
|
|
35
|
+
ENV_FILE="${BROKK_ENV_FILE:-$YMIR_ENV_FILE}"
|
|
17
36
|
|
|
18
37
|
usage() { sed -n '2,13p' "$0" | sed 's/^# \{0,1\}//'; }
|
|
19
38
|
CMD="${1-}"; shift || true
|
|
@@ -40,7 +59,7 @@ done
|
|
|
40
59
|
if [ "$CMD" = status ]; then
|
|
41
60
|
printf 'mjollnir[2]{field,value}:\n'
|
|
42
61
|
printf ' "repo","%s"\n' "${REPO:-$ROOT}"
|
|
43
|
-
printf ' "pending","%s"\n' "$(find "$
|
|
62
|
+
printf ' "pending","%s"\n' "$(find "$YMIR_DATA_DIR" -maxdepth 2 -name 'brief.md' -path '*issue-*' 2>/dev/null | wc -l | tr -d ' ')"
|
|
44
63
|
exit 0
|
|
45
64
|
fi
|
|
46
65
|
[ "$CMD" = run ] || { printf 'error: unknown command %s\nhelp: bin/mjollnir.sh [run|status|--version]\n' "$CMD" >&2; exit 2; }
|
|
@@ -69,7 +88,7 @@ printf 'mjollnir[1]{issue,task,mode,repo}:\n "%s","%s","%s","%s"\n' "$ISSUE" "$
|
|
|
69
88
|
|
|
70
89
|
# 2. Scaffold the brief (the worker's contract).
|
|
71
90
|
"$SCRIPT_DIR/erindi-brief.sh" "$ID" "$(basename "$REPO")" --mode "$MODE" >/dev/null 2>&1 || true
|
|
72
|
-
BRIEF="$
|
|
91
|
+
BRIEF="$YMIR_DATA_DIR/$ID/brief.md"
|
|
73
92
|
if [ -f "$BRIEF" ]; then
|
|
74
93
|
{ printf '\n\n## Issue #%s — %s\n\n%s\n' "$ISSUE" "$TITLE" "$BODY"; } >>"$BRIEF"
|
|
75
94
|
fi
|
package/bin/model-hardware.sh
CHANGED
|
@@ -17,7 +17,20 @@ set -u
|
|
|
17
17
|
VERSION="1.0.0"
|
|
18
18
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
19
19
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
20
|
-
|
|
20
|
+
|
|
21
|
+
# The roots that live OUTSIDE the code tree: this machine's records and the
|
|
22
|
+
# runtime state belong to the home the operator chose at installation, never in
|
|
23
|
+
# the tree — a packaged install replaces its tree on upgrade (Rule 04).
|
|
24
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
25
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
26
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
27
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
28
|
+
done
|
|
29
|
+
unset _yr _yc
|
|
30
|
+
fi
|
|
31
|
+
hoard_state_dir YMIR_STATE_DIR
|
|
32
|
+
hoard_data_dir YMIR_DATA_DIR
|
|
33
|
+
OUT="${YMIR_LOCAL_MODELS_DOC:-$YMIR_DATA_DIR/local-models.md}"
|
|
21
34
|
PRINT_ONLY=0
|
|
22
35
|
|
|
23
36
|
case "${1-}" in -v|-V|--version) printf '%s\n' "$VERSION"; exit 0 ;; -h|--help) sed -n '2,14p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; esac
|
|
@@ -53,8 +66,9 @@ block="<!-- model-hardware:begin -->
|
|
|
53
66
|
build/run the CUDA build; keep K and V the same KV type (q8_0).
|
|
54
67
|
- **Coding wants >= 80000 context.** Measure the real ceiling: load more until a
|
|
55
68
|
request OOMs, then drop one step (ctx is per-model).
|
|
56
|
-
- **
|
|
57
|
-
|
|
69
|
+
- **The method** — engines, wiring, and honest measurement — is the Galdr asset
|
|
70
|
+
\`.agents/skills/galdr-ymirsystem/assets/local-models.md\`. Then
|
|
71
|
+
\`bin/models-detect.sh --write\` registers what serves.
|
|
58
72
|
<!-- model-hardware:end -->"
|
|
59
73
|
|
|
60
74
|
# The researched settings are NOT in the managed block, so a re-run never clobbers
|
package/bin/model-resolve.sh
CHANGED
|
@@ -15,7 +15,20 @@ set -u
|
|
|
15
15
|
VERSION="1.0.0"
|
|
16
16
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
17
17
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
18
|
-
|
|
18
|
+
|
|
19
|
+
# The operator's settings and secrets live in the home they chose, never in the
|
|
20
|
+
# code tree — a packaged install replaces its tree on upgrade, and a credential
|
|
21
|
+
# must never sit in a tree that ships (Rule 04).
|
|
22
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
23
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
24
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
25
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
26
|
+
done
|
|
27
|
+
unset _yr _yc
|
|
28
|
+
fi
|
|
29
|
+
hoard_settings_dir YMIR_SETTINGS_DIR
|
|
30
|
+
hoard_local_env YMIR_ENV_FILE
|
|
31
|
+
CFG="${YMIR_AGENTS_YAML:-$YMIR_SETTINGS_DIR/agents.yaml}"
|
|
19
32
|
|
|
20
33
|
case "${1-}" in -v|-V|--version) printf '%s\n' "$VERSION"; exit 0 ;;
|
|
21
34
|
-h|--help|"") sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; esac
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# nornir-job-hall-snapshot.sh — Óðrerir: refresh the Live Hall's board.
|
|
3
|
+
#
|
|
4
|
+
# The Hall is a glass: it reads apps/odrerir/public/livehall.json, written by
|
|
5
|
+
# this job from the real system state (runes · projects · cron · wake queue ·
|
|
6
|
+
# standing smiths · armed when-sources · landed errands). Scheduled at 08:00,
|
|
7
|
+
# after the 06:00 observer and the 07:00 briefing, so the morning's board
|
|
8
|
+
# carries the day's fresh runes. Stateless: read inputs → write the snapshot →
|
|
9
|
+
# carve a Rune → exit.
|
|
10
|
+
#
|
|
11
|
+
# Overrides: BROKK_ROOT_OVERRIDE (hall-snapshot.sh), YMIR_HOME (the hoard).
|
|
12
|
+
set -u
|
|
13
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
|
+
ROOT="${BROKK_ROOT_OVERRIDE:-$(cd "$SCRIPT_DIR/.." && pwd)}"
|
|
15
|
+
|
|
16
|
+
# The snapshot is runtime, never repo: it is gitignored where it lands.
|
|
17
|
+
if ! "$ROOT/bin/hall-snapshot.sh" >/dev/null 2>&1; then
|
|
18
|
+
printf 'error: hall-snapshot.sh failed — the board is stale\n'
|
|
19
|
+
printf 'help: run bin/hall-snapshot.sh by hand to see the reason\n'
|
|
20
|
+
exit 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# Carve the Rune — the ledger lives with the hoard.
|
|
24
|
+
# shellcheck source=bin/runes-append.sh
|
|
25
|
+
. "$ROOT/bin/runes-append.sh"
|
|
26
|
+
runes_append "odrerir" "hall.snapshot" --message "Live Hall board refreshed from real state" >/dev/null \
|
|
27
|
+
|| printf 'hall-snapshot: rune append failed (non-fatal)\n'
|
|
28
|
+
printf 'hall-snapshot: Live Hall board refreshed\n'
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# nornir-job-nsr-compliance.sh — the NorthStar compliance round, nightly.
|
|
3
|
+
#
|
|
4
|
+
# Runs the deterministic NSR gates (.compliance/gates/check_*.sh — danger,
|
|
5
|
+
# env, paths, platform, wiring) and carves one Rune with the verdict. A FAIL
|
|
6
|
+
# is reported loudly in the Rune message — the morning briefing reads the
|
|
7
|
+
# ledger, so a broken door is seen at sunrise, not found by accident.
|
|
8
|
+
#
|
|
9
|
+
# Stateless: run gates → write nothing but state/last + the Rune → exit.
|
|
10
|
+
set -u
|
|
11
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
|
+
ROOT="${BROKK_ROOT_OVERRIDE:-$(cd "$SCRIPT_DIR/.." && pwd)}"
|
|
13
|
+
|
|
14
|
+
# The roots that live OUTSIDE the code tree: this machine's records and the
|
|
15
|
+
# runtime state belong to the home the operator chose at installation, never in
|
|
16
|
+
# the tree — a packaged install replaces its tree on upgrade (Rule 04).
|
|
17
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
18
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
19
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
20
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
21
|
+
done
|
|
22
|
+
unset _yr _yc
|
|
23
|
+
fi
|
|
24
|
+
hoard_state_dir YMIR_STATE_DIR
|
|
25
|
+
hoard_data_dir YMIR_DATA_DIR
|
|
26
|
+
STATE="${BROKK_STATE_OVERRIDE:-$YMIR_STATE_DIR}"
|
|
27
|
+
|
|
28
|
+
GATES_DIR="$ROOT/.compliance/gates"
|
|
29
|
+
[ -d "$GATES_DIR" ] || { printf 'error: no NSR gates at %s\n' "$GATES_DIR"; exit 1; }
|
|
30
|
+
|
|
31
|
+
passed=0; failed=0; failed_names=""
|
|
32
|
+
for g in "$GATES_DIR"/check_*.sh; do
|
|
33
|
+
name=$(basename "$g" .sh)
|
|
34
|
+
if bash "$g" >/dev/null 2>&1; then
|
|
35
|
+
passed=$((passed+1))
|
|
36
|
+
else
|
|
37
|
+
failed=$((failed+1)); failed_names="$failed_names $name"
|
|
38
|
+
fi
|
|
39
|
+
done
|
|
40
|
+
|
|
41
|
+
printf 'nsr-compliance: gates=%d passed=%d failed=%d%s\n' \
|
|
42
|
+
"$((passed+failed))" "$passed" "$failed" "$failed_names"
|
|
43
|
+
|
|
44
|
+
# shellcheck source=bin/runes-append.sh
|
|
45
|
+
. "$ROOT/bin/runes-append.sh"
|
|
46
|
+
if [ "$failed" = 0 ]; then
|
|
47
|
+
runes_append "nornir" "nsr.compliance" --message "NSR compliance: $passed/$passed gates passed" >/dev/null \
|
|
48
|
+
|| printf 'nsr-compliance: rune append failed (non-fatal)\n'
|
|
49
|
+
exit 0
|
|
50
|
+
else
|
|
51
|
+
runes_append "nornir" "nsr.compliance.failed" --message "NSR compliance FAIL: gates $failed_names FAILED — mend at sunrise" >/dev/null \
|
|
52
|
+
|| printf 'nsr-compliance: rune append failed (non-fatal)\n'
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# npm-publish.sh — publish through the HOARD's npm token, every single time.
|
|
3
|
+
#
|
|
4
|
+
# Why this exists: this machine once held two tokens, and the one in ~/.npmrc was
|
|
5
|
+
# stale. A publish then failed with a 2FA refusal that looked like a policy
|
|
6
|
+
# problem but was a credential problem, and a session was spent on it. The token
|
|
7
|
+
# with bypass-2FA lives in the hoard. So the rule is: never trust ~/.npmrc — read
|
|
8
|
+
# the token from the hoard, hand it to npm through a temporary userconfig, and
|
|
9
|
+
# throw the file away.
|
|
10
|
+
#
|
|
11
|
+
# bin/npm-publish.sh # the platform (the repo root manifest)
|
|
12
|
+
# bin/npm-publish.sh apps/hlidskjalf # one package
|
|
13
|
+
# bin/npm-publish.sh --all # the platform + every app package
|
|
14
|
+
# bin/npm-publish.sh --whoami # which account the hoard token is
|
|
15
|
+
# bin/npm-publish.sh --dry-run apps/odrerir
|
|
16
|
+
# bin/npm-publish.sh --unpublish @zerwiz/ymir@0.1.5 # take ONE version back
|
|
17
|
+
# bin/npm-publish.sh --unpublish @zerwiz/ymir@0.1.5 --dry-run
|
|
18
|
+
#
|
|
19
|
+
# Unpublish: npm allows ONE VERSION back for 72 hours after it was published;
|
|
20
|
+
# past that only npm support can remove it, which is why this door names the
|
|
21
|
+
# version and refuses anything vaguer. A whole package is not a one-word act —
|
|
22
|
+
# that needs npm's own tooling and a deliberate decision, not a flag here.
|
|
23
|
+
#
|
|
24
|
+
# A prerelease version (0.1.8-alpha) is published under `--tag next` automatically
|
|
25
|
+
# — npm refuses a prerelease on `latest`, which is the second half of the same
|
|
26
|
+
# lesson. A scoped package always goes out with public access.
|
|
27
|
+
set -u
|
|
28
|
+
|
|
29
|
+
VERSION="1.0.0"
|
|
30
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
31
|
+
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
32
|
+
# shellcheck source=bin/hoard-lib.sh
|
|
33
|
+
. "$SCRIPT_DIR/hoard-lib.sh"
|
|
34
|
+
|
|
35
|
+
DRY=0; WHO=0; ALL=0; UNPUBLISH=0; UNPUB_SPEC=""; TARGETS=()
|
|
36
|
+
for a in "$@"; do
|
|
37
|
+
case "$a" in
|
|
38
|
+
--whoami) WHO=1 ;;
|
|
39
|
+
--dry-run) DRY=1 ;;
|
|
40
|
+
--all) ALL=1 ;;
|
|
41
|
+
--unpublish) UNPUBLISH=1 ;;
|
|
42
|
+
--unpublish=*) UNPUBLISH=1; UNPUB_SPEC="${a#*=}" ;;
|
|
43
|
+
-v|-V|--version) printf '%s\n' "$VERSION"; exit 0 ;;
|
|
44
|
+
-h|--help|"") sed -n '2,22p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
|
45
|
+
-*) printf 'error: unknown flag %s\nhelp: bin/npm-publish.sh [--all|--whoami|--unpublish <spec>|--dry-run] [<package-dir>...]\n' "$a" >&2; exit 2 ;;
|
|
46
|
+
*) TARGETS+=("$a") ;;
|
|
47
|
+
esac
|
|
48
|
+
done
|
|
49
|
+
# --all is the platform plus every app package. The smithy's own repo is
|
|
50
|
+
# cloned at apps/smidja-factory (the registry maps smidja there), so it is a
|
|
51
|
+
# target like any other app: it publishes as @zerwiz/smidja.
|
|
52
|
+
[ "$ALL" = 1 ] && TARGETS=("$ROOT" "$ROOT/apps/hlidskjalf" "$ROOT/apps/hlidskjalf-mobile" "$ROOT/apps/odrerir" "$ROOT/apps/sessrumnir" "$ROOT/apps/smidja-factory")
|
|
53
|
+
[ "${#TARGETS[@]}" -eq 0 ] && [ "$WHO" = 0 ] && [ "$UNPUBLISH" = 0 ] && TARGETS=("$ROOT")
|
|
54
|
+
# `--unpublish @scope/name@1.2.3` — the spec may also arrive positionally.
|
|
55
|
+
[ "$UNPUBLISH" = 1 ] && UNPUB_SPEC="${UNPUB_SPEC:-${TARGETS[0]:-}}"
|
|
56
|
+
|
|
57
|
+
# ── the token, from the hoard ────────────────────────────────────────────────
|
|
58
|
+
envfile=""; hoard_env envfile
|
|
59
|
+
TOKEN=""
|
|
60
|
+
if [ -r "$envfile" ]; then
|
|
61
|
+
TOKEN="$(sed -n 's/^NPM_TOKEN=//p' "$envfile" | head -1 | tr -d '"'"'"' ')"
|
|
62
|
+
fi
|
|
63
|
+
if [ -z "$TOKEN" ] && [ "$WHO" = 1 ]; then
|
|
64
|
+
printf 'npm[1]{token,state}:\n "NPM_TOKEN","absent in %s"\n' "${envfile#"$HOME"/}"
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
if [ -z "$TOKEN" ]; then
|
|
68
|
+
printf 'error: the hoard holds no NPM_TOKEN\nhelp: add NPM_TOKEN=<granular token with bypass 2FA> to %s\n' "${envfile#"$HOME"/}" >&2
|
|
69
|
+
printf 'help: npmjs.com → Access Tokens → Generate → granular, scope @zerwiz, bypass 2FA on\n' >&2
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
cfg="$(mktemp)"; chmod 600 "$cfg"
|
|
74
|
+
printf '//registry.npmjs.org/:_authToken=%s\n' "$TOKEN" >"$cfg"
|
|
75
|
+
trap 'rm -f "$cfg"' EXIT
|
|
76
|
+
|
|
77
|
+
if [ "$WHO" = 1 ]; then
|
|
78
|
+
who="$(npm whoami --userconfig "$cfg" 2>/dev/null || printf 'unknown')"
|
|
79
|
+
printf 'npm[2]{token,account}:\n "source","%s"\n "whoami","%s"\n' "${envfile#"$HOME"/}" "$who"
|
|
80
|
+
exit 0
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# ── unpublish ────────────────────────────────────────────────────────────────
|
|
84
|
+
# Take ONE version back. npm permits it for 72 hours after publication; beyond
|
|
85
|
+
# that it is npm support's door, not this one. The spec must name a version:
|
|
86
|
+
# `@scope/name@1.2.3`, never a bare name.
|
|
87
|
+
if [ "$UNPUBLISH" = 1 ]; then
|
|
88
|
+
case "$UNPUB_SPEC" in
|
|
89
|
+
*@*@*) ;; # @scope/name@version
|
|
90
|
+
*@[0-9]*) ;;
|
|
91
|
+
*) printf 'error: --unpublish needs a package AND a version\nhelp: bin/npm-publish.sh --unpublish @scope/name@<version>\n' >&2; exit 2 ;;
|
|
92
|
+
esac
|
|
93
|
+
if [ "$DRY" = 1 ]; then
|
|
94
|
+
printf 'npm_unpublish[1]{spec,state}:\n "%s","dry-run — nothing was removed"\n' "$UNPUB_SPEC"
|
|
95
|
+
exit 0
|
|
96
|
+
fi
|
|
97
|
+
out="$(npm unpublish "$UNPUB_SPEC" --force --userconfig "$cfg" 2>&1)"; rc=$?
|
|
98
|
+
if [ "$rc" = 0 ]; then
|
|
99
|
+
printf 'npm_unpublish[1]{spec,state}:\n "%s","unpublished"\n' "$UNPUB_SPEC"
|
|
100
|
+
printf 'note: the registry CDN may serve the tarball for a while after this; publishing a\n'
|
|
101
|
+
printf 'note: newer version moves the "latest" tag off it at once.\n'
|
|
102
|
+
else
|
|
103
|
+
why="$(printf '%s' "$out" | grep -m1 -E 'npm error (code )?[A-Z0-9]+|E[0-9]{3}' | cut -c1-90)"
|
|
104
|
+
printf 'error: unpublish failed — %s\nhelp: is it inside the 72-hour window, and is the token the right account? (bin/npm-publish.sh --whoami)\n' "${why:-see npm log}" >&2
|
|
105
|
+
exit 1
|
|
106
|
+
fi
|
|
107
|
+
exit 0
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
# ── publish ──────────────────────────────────────────────────────────────────
|
|
111
|
+
printf 'npm_publish[%d]{package,version,tag,state}:\n' "${#TARGETS[@]}"
|
|
112
|
+
failed=0
|
|
113
|
+
for dir in "${TARGETS[@]}"; do
|
|
114
|
+
pkg="$dir/package.json"
|
|
115
|
+
if [ ! -f "$pkg" ]; then
|
|
116
|
+
printf ' "%s","-","-","SKIP (no package.json)"\n' "${dir#"$ROOT"/}"
|
|
117
|
+
continue
|
|
118
|
+
fi
|
|
119
|
+
name="$(sed -n 's/.*"name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$pkg" | head -1)"
|
|
120
|
+
ver="$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$pkg" | head -1)"
|
|
121
|
+
case "$ver" in *-*) tag=next ;; *) tag=latest ;; esac # a prerelease never rides `latest`
|
|
122
|
+
if [ "$DRY" = 1 ]; then
|
|
123
|
+
printf ' "%s","%s","%s","dry-run"\n' "$name" "$ver" "$tag"
|
|
124
|
+
continue
|
|
125
|
+
fi
|
|
126
|
+
out="$(cd "$dir" && npm publish --access public --tag "$tag" --userconfig "$cfg" 2>&1)"; rc=$?
|
|
127
|
+
if [ "$rc" = 0 ]; then
|
|
128
|
+
printf ' "%s","%s","%s","published"\n' "$name" "$ver" "$tag"
|
|
129
|
+
else
|
|
130
|
+
why="$(printf '%s' "$out" | grep -m1 -E 'npm error (code )?[A-Z0-9]+|E[0-9]{3}' | cut -c1-90)"
|
|
131
|
+
printf ' "%s","%s","%s","FAILED (%s)"\n' "$name" "$ver" "$tag" "${why:-see npm log}"
|
|
132
|
+
failed=$((failed+1))
|
|
133
|
+
fi
|
|
134
|
+
done
|
|
135
|
+
[ "$failed" = 0 ] || { printf 'error: %d package(s) did not publish\nhelp: bin/npm-publish.sh --whoami (is the hoard token still the right account?)\n' "$failed" >&2; exit 1; }
|
|
136
|
+
exit 0
|
package/bin/omarchy-install.sh
CHANGED
|
@@ -24,6 +24,19 @@ VERSION="1.0.0"
|
|
|
24
24
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
25
25
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
26
26
|
|
|
27
|
+
# The operator's settings and secrets live in the home they chose, never in the
|
|
28
|
+
# code tree — a packaged install replaces its tree on upgrade, and a credential
|
|
29
|
+
# must never sit in a tree that ships (Rule 04).
|
|
30
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
31
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
32
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
33
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
34
|
+
done
|
|
35
|
+
unset _yr _yc
|
|
36
|
+
fi
|
|
37
|
+
hoard_settings_dir YMIR_SETTINGS_DIR
|
|
38
|
+
hoard_local_env YMIR_ENV_FILE
|
|
39
|
+
|
|
27
40
|
# portability shim (bin/ymir-platform.sh)
|
|
28
41
|
if [ -z "${YMIR_PLATFORM_LOADED:-}" ]; then
|
|
29
42
|
_ymir_dir="$SCRIPT_DIR"
|
|
@@ -122,15 +135,15 @@ else
|
|
|
122
135
|
fi
|
|
123
136
|
|
|
124
137
|
# ── 6. the away-mode alarm channel + the crash sensor ────────────────────────
|
|
125
|
-
if [ -e "$
|
|
138
|
+
if [ -e "$YMIR_SETTINGS_DIR/wedge-alarm" ]; then
|
|
126
139
|
add alarm OK "channel kept"
|
|
127
140
|
elif [ "$CHECK" = 1 ]; then
|
|
128
141
|
add alarm WARN "channel not written (run without --check)"
|
|
129
|
-
elif mkdir -p "$
|
|
130
|
-
printf '# The channel the away-mode wedge alarm fires on when an escalation\n# cannot be delivered into the pane. See bin/wedge-notify.sh.\ndesktop\n' >"$
|
|
131
|
-
add alarm OK "channel written (
|
|
142
|
+
elif mkdir -p "$YMIR_SETTINGS_DIR" 2>/dev/null && \
|
|
143
|
+
printf '# The channel the away-mode wedge alarm fires on when an escalation\n# cannot be delivered into the pane. See bin/wedge-notify.sh.\ndesktop\n' >"$YMIR_SETTINGS_DIR/wedge-alarm" 2>/dev/null; then
|
|
144
|
+
add alarm OK "channel written ($YMIR_SETTINGS_DIR/wedge-alarm)"
|
|
132
145
|
else
|
|
133
|
-
add alarm WARN "could not write
|
|
146
|
+
add alarm WARN "could not write $YMIR_SETTINGS_DIR/wedge-alarm"
|
|
134
147
|
fi
|
|
135
148
|
|
|
136
149
|
# ── 7. the terminal backend Ymir needs ───────────────────────────────────────
|