@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/omarchy-plugins.sh
CHANGED
|
@@ -26,6 +26,19 @@ set -u
|
|
|
26
26
|
VERSION="1.0.0"
|
|
27
27
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
28
28
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
29
|
+
|
|
30
|
+
# The roots that live OUTSIDE the code tree: this machine's records and the
|
|
31
|
+
# runtime state belong to the home the operator chose at installation, never in
|
|
32
|
+
# the tree — a packaged install replaces its tree on upgrade (Rule 04).
|
|
33
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
34
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
35
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
36
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
37
|
+
done
|
|
38
|
+
unset _yr _yc
|
|
39
|
+
fi
|
|
40
|
+
hoard_state_dir YMIR_STATE_DIR
|
|
41
|
+
hoard_data_dir YMIR_DATA_DIR
|
|
29
42
|
YES=0
|
|
30
43
|
|
|
31
44
|
case "${1-}" in
|
|
@@ -77,7 +90,7 @@ is_installed() { # <id>
|
|
|
77
90
|
}
|
|
78
91
|
|
|
79
92
|
repo_for() { # <id> — read the repo from the registry's own catalog when reachable
|
|
80
|
-
local id=$1 cache="$
|
|
93
|
+
local id=$1 cache="$YMIR_STATE_DIR/omarchy-catalog.json"
|
|
81
94
|
if [ -r "$cache" ]; then
|
|
82
95
|
python3 - "$cache" "$id" <<'PY' 2>/dev/null
|
|
83
96
|
import json,sys
|
|
@@ -135,7 +148,7 @@ case "$ACTION" in
|
|
|
135
148
|
printf 'omarchy-plugins[1]{id,state}:\n "%s","already installed"\n' "$id"; exit 0
|
|
136
149
|
fi
|
|
137
150
|
# Resolve the repo from the registry catalog; refresh it if absent.
|
|
138
|
-
cache="$
|
|
151
|
+
cache="$YMIR_STATE_DIR/omarchy-catalog.json"
|
|
139
152
|
if [ ! -r "$cache" ] && have curl; then
|
|
140
153
|
mkdir -p "$(dirname "$cache")"
|
|
141
154
|
curl -fsS --max-time 25 https://plugins.omarchy.org/catalog.json -o "$cache" 2>/dev/null || true
|
package/bin/omarchy-sense.sh
CHANGED
|
@@ -21,7 +21,20 @@ set -u
|
|
|
21
21
|
VERSION="1.0.0"
|
|
22
22
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
23
23
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
# The roots that live OUTSIDE the code tree: this machine's records and the
|
|
26
|
+
# runtime state belong to the home the operator chose at installation, never in
|
|
27
|
+
# the tree — a packaged install replaces its tree on upgrade (Rule 04).
|
|
28
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
29
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
30
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
31
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
32
|
+
done
|
|
33
|
+
unset _yr _yc
|
|
34
|
+
fi
|
|
35
|
+
hoard_state_dir YMIR_STATE_DIR
|
|
36
|
+
hoard_data_dir YMIR_DATA_DIR
|
|
37
|
+
STATE_DIR="${BROKK_STATE_OVERRIDE:-$YMIR_STATE_DIR}"
|
|
25
38
|
SNAP="$STATE_DIR/omarchy-setup.json"
|
|
26
39
|
|
|
27
40
|
# Rule 05: this is the OMARCHY layer's sensor, so it is gated on its host. Ymir
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# pi-model-agnostic — pi must not EXPECT any model. Local and online are peers.
|
|
3
|
+
#
|
|
4
|
+
# The law (Allfather, 2026-09-17): a seat that answers is used; a seat that does not
|
|
5
|
+
# must not stop pi from starting. pi was failing at launch because providers pointed at
|
|
6
|
+
# local ports with nothing behind them:
|
|
7
|
+
# [llama-cpp] failed to reach http://localhost:8080/v1/models: fetch failed
|
|
8
|
+
# An unreachable local seat is a SKIP, not an error.
|
|
9
|
+
#
|
|
10
|
+
# This prunes unreachable LOCAL providers from pi's models config, keeping every seat
|
|
11
|
+
# that answers and every online provider untouched.
|
|
12
|
+
#
|
|
13
|
+
# bin/pi-model-agnostic.sh # report and prune
|
|
14
|
+
# bin/pi-model-agnostic.sh --dry-run # report only
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
CFG="${PI_MODELS_JSON:-$HOME/.pi/agent/models.json}"
|
|
18
|
+
DRY=0
|
|
19
|
+
[ "${1:-}" = "--dry-run" ] && DRY=1
|
|
20
|
+
[ -f "$CFG" ] || { printf 'error: no pi models config at %s\nhelp: set PI_MODELS_JSON\n' "$CFG" >&2; exit 1; }
|
|
21
|
+
|
|
22
|
+
CFG="$CFG" DRY="$DRY" python3 - <<'INNER'
|
|
23
|
+
import json, os, shutil, sys, time, urllib.request
|
|
24
|
+
|
|
25
|
+
cfg = os.environ["CFG"]
|
|
26
|
+
dry = os.environ.get("DRY") == "1"
|
|
27
|
+
d = json.load(open(cfg))
|
|
28
|
+
providers = d.get("providers", {})
|
|
29
|
+
|
|
30
|
+
def reachable(url):
|
|
31
|
+
if not url:
|
|
32
|
+
return False
|
|
33
|
+
probe = url.rstrip("/")
|
|
34
|
+
if not probe.endswith("/v1"):
|
|
35
|
+
probe += "/v1"
|
|
36
|
+
try:
|
|
37
|
+
with urllib.request.urlopen(probe + "/models", timeout=3) as r:
|
|
38
|
+
return r.status == 200
|
|
39
|
+
except Exception:
|
|
40
|
+
return False
|
|
41
|
+
|
|
42
|
+
kept, dropped = [], []
|
|
43
|
+
for name, prov in providers.items():
|
|
44
|
+
base = str(prov.get("baseUrl", ""))
|
|
45
|
+
local = ("127.0.0.1" in base) or ("localhost" in base) or ("0.0.0.0" in base)
|
|
46
|
+
if local and not reachable(base):
|
|
47
|
+
dropped.append((name, base))
|
|
48
|
+
else:
|
|
49
|
+
kept.append(name)
|
|
50
|
+
|
|
51
|
+
print("pi_models[%d]{provider,base,verdict}:" % (len(kept) + len(dropped)))
|
|
52
|
+
for n in kept:
|
|
53
|
+
print(' "%s","%s","kept"' % (n, providers[n].get("baseUrl", "")))
|
|
54
|
+
for n, b in dropped:
|
|
55
|
+
print(' "%s","%s","unreachable local seat - pruned"' % (n, b))
|
|
56
|
+
|
|
57
|
+
if dropped and not dry:
|
|
58
|
+
shutil.copy2(cfg, cfg + ".bak-" + time.strftime("%Y%m%d%H%M%S"))
|
|
59
|
+
d["providers"] = {k: v for k, v in providers.items() if k in kept}
|
|
60
|
+
dm = d.get("defaultProvider")
|
|
61
|
+
if dm and dm not in kept and kept:
|
|
62
|
+
d["defaultProvider"] = kept[0]
|
|
63
|
+
ids = (d["providers"][kept[0]].get("models") or [{}])
|
|
64
|
+
if ids and ids[0].get("id"):
|
|
65
|
+
d["defaultModel"] = ids[0]["id"]
|
|
66
|
+
print(" default -> %s / %s" % (d.get("defaultProvider"), d.get("defaultModel")))
|
|
67
|
+
json.dump(d, open(cfg, "w"), indent=2)
|
|
68
|
+
print("pi_models: %d pruned, backup beside the config" % len(dropped))
|
|
69
|
+
elif dry:
|
|
70
|
+
print("pi_models: dry run - nothing written")
|
|
71
|
+
INNER
|
package/bin/private-guard.sh
CHANGED
|
@@ -18,6 +18,20 @@ FORBID='^(hodd/|svartalfaheim/|state/|data/|workspace/(work|personal|memory|comp
|
|
|
18
18
|
# Allowed tracked exceptions inside those roots.
|
|
19
19
|
ALLOW='^(hodd/(README\.md|\.gitignore|AGENTS\.example\.md|[^/]+\.example(\.md)?)$|svartalfaheim/.*(README\.md|\.gitkeep|\.gitignore|\.example(\.md)?)$|state/\.gitkeep$|data/[^/]+\.example$|assets/reference/state/[^/]+\.example$|\.env\.example|\.env\.sample)$'
|
|
20
20
|
|
|
21
|
+
# Tenant DOCUMENTS — a wiki, policy set, vision, roadmap or strategy file is
|
|
22
|
+
# company/operator knowledge, not a public asset. It belongs at
|
|
23
|
+
# $YMIR_HOME/hodd/identity/companies/<company>/ and nowhere in this repo.
|
|
24
|
+
# Added 2026-09-17 after `midgard/company_wiki/` was found sitting in the
|
|
25
|
+
# public tree: it was an empty placeholder, but the shape invited the leak.
|
|
26
|
+
#
|
|
27
|
+
# The match is deliberately a DIRECTORY or a doc suffixed with tenant content —
|
|
28
|
+
# NOT the bare word. `svartalfaheim/examples/SECRETS.md` is a public how-to (it
|
|
29
|
+
# teaches where secrets go and holds no value), so a bare `secrets` match would
|
|
30
|
+
# be a false positive.
|
|
31
|
+
TENANT_DOC='((^|/)(company_wiki|wiki|policies|handbook|playbook|internal|confidential)(/|\.)|(^|/)(vision|strategy|roadmap|policies)[^/]*\.(md|txt|rst|pdf|docx?)$)'
|
|
32
|
+
# Public exceptions: a wiki-shaped name that is a genuine scaffold or doc.
|
|
33
|
+
TENANT_DOC_ALLOW='(\.example$|\.example\.md$|README\.md$|/\.gitkeep$)'
|
|
34
|
+
|
|
21
35
|
scan_list() {
|
|
22
36
|
local hit=0 f
|
|
23
37
|
while IFS= read -r f; do
|
|
@@ -25,6 +39,12 @@ scan_list() {
|
|
|
25
39
|
if printf '%s\n' "$f" | grep -Eq "$FORBID" && ! printf '%s\n' "$f" | grep -Eq "$ALLOW"; then
|
|
26
40
|
printf 'private-guard: tracked private path: %s\n' "$f" >&2
|
|
27
41
|
hit=1
|
|
42
|
+
continue
|
|
43
|
+
fi
|
|
44
|
+
if printf '%s\n' "$f" | grep -Eq "$TENANT_DOC" && ! printf '%s\n' "$f" | grep -Eq "$TENANT_DOC_ALLOW"; then
|
|
45
|
+
printf 'private-guard: tenant/company document in the public tree: %s\n' "$f" >&2
|
|
46
|
+
printf ' company knowledge belongs at $YMIR_HOME/hodd/identity/companies/, never here\n' >&2
|
|
47
|
+
hit=1
|
|
28
48
|
fi
|
|
29
49
|
done
|
|
30
50
|
return "$hit"
|
package/bin/project-git.sh
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
# remote. Auth is a REFERENCE (app|pat|ssh|gh), never a value.
|
|
5
5
|
#
|
|
6
6
|
# Usage:
|
|
7
|
-
# project-git.sh <project-id> [--field host|owner|repo|remote|default_branch|auth]
|
|
7
|
+
# project-git.sh <project-id> [--field host|owner|repo|remote|default_branch|auth|machine]
|
|
8
8
|
# project-git.sh list
|
|
9
9
|
# project-git.sh --version
|
|
10
10
|
set -u
|
|
11
11
|
|
|
12
|
-
VERSION="1.
|
|
12
|
+
VERSION="1.2.0"
|
|
13
13
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
14
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
15
15
|
# shellcheck source=bin/hoard-lib.sh
|
|
@@ -26,6 +26,14 @@ while [ $# -gt 0 ]; do case "$1" in --field) FIELD=${2-}; shift 2 ;; *) shift ;;
|
|
|
26
26
|
|
|
27
27
|
if [ "$ID" = "list" ]; then
|
|
28
28
|
n=$(grep -cE '^\s*-\s+id:' "$REG" 2>/dev/null || echo 0)
|
|
29
|
+
if [ "$FIELD" = "about" ]; then
|
|
30
|
+
printf 'projects[%s]{id,about}:\n' "$n"
|
|
31
|
+
awk '
|
|
32
|
+
/^[[:space:]]*-[[:space:]]+id:/ { sub(/^[[:space:]]*-[[:space:]]+id:[[:space:]]*/, ""); id=$0 }
|
|
33
|
+
/^[[:space:]]*about:/ { sub(/^[[:space:]]*about:[[:space:]]*"/, ""); sub(/"[[:space:]]*$/, ""); if (id != "") printf " \"%s\",\"%s\"\n", id, $0 }
|
|
34
|
+
' "$REG"
|
|
35
|
+
exit 0
|
|
36
|
+
fi
|
|
29
37
|
printf 'projects[%s]{id}:\n' "$n"
|
|
30
38
|
grep -E '^\s*-\s+id:' "$REG" | sed -E 's/^\s*-\s+id:\s*/ "/; s/\s*$/" /'
|
|
31
39
|
exit 0
|
|
@@ -41,15 +49,21 @@ block="$(awk -v id="$ID" '
|
|
|
41
49
|
|
|
42
50
|
gitline="$(printf '%s\n' "$block" | grep -m1 'git:')"
|
|
43
51
|
val() { printf '%s' "$gitline" | sed -nE "s/.*[ {,]?$1:[[:space:]]*([^,}]+).*/\1/p" | tr -d ' '; }
|
|
52
|
+
# non-git top-level keys resolve from the block itself, not the git line
|
|
53
|
+
blockval() { printf '%s' "$block" | sed -nE "s/^[[:space:]]*$1:[[:space:]]*([^,}]+).*/\1/p" | head -1 | tr -d ' '; }
|
|
44
54
|
|
|
45
55
|
host="$(val host)"; owner="$(val owner)"; repo="$(val repo)"; remote="$(val remote)"; br="$(val default_branch)"; auth="$(val auth)"
|
|
56
|
+
machine="$(blockval machine)"; company="$(blockval company)"; workspace="$(blockval workspace)"
|
|
57
|
+
about="$(printf '%s' "$block" | sed -nE 's/^[[:space:]]*about:[[:space:]]*"(.*)"[[:space:]]*$/\1/p' | head -1)"
|
|
46
58
|
if [ -n "$FIELD" ]; then
|
|
47
59
|
case "$FIELD" in
|
|
48
60
|
host) printf '%s\n' "$host" ;; owner) printf '%s\n' "$owner" ;; repo) printf '%s\n' "$repo" ;;
|
|
49
61
|
remote) printf '%s\n' "$remote" ;; default_branch) printf '%s\n' "$br" ;; auth) printf '%s\n' "$auth" ;;
|
|
62
|
+
machine) printf '%s\n' "$machine" ;; company) printf '%s\n' "$company" ;; workspace) printf '%s\n' "$workspace" ;;
|
|
63
|
+
about) printf '%s\n' "$about" ;;
|
|
50
64
|
*) printf 'error: unknown field %s\n' "$FIELD" >&2; exit 2 ;;
|
|
51
65
|
esac
|
|
52
66
|
exit 0
|
|
53
67
|
fi
|
|
54
|
-
printf 'project[1]{id,host,owner,repo,remote,default_branch,auth}:\n'
|
|
55
|
-
printf ' "%s","%s","%s","%s","%s","%s","%s"\n' "$ID" "$host" "$owner" "$repo" "$remote" "$br" "$auth"
|
|
68
|
+
printf 'project[1]{id,host,owner,repo,remote,default_branch,auth,machine,company,workspace}:\n'
|
|
69
|
+
printf ' "%s","%s","%s","%s","%s","%s","%s","%s","%s","%s"\n' "$ID" "$host" "$owner" "$repo" "$remote" "$br" "$auth" "$machine" "$company" "$workspace"
|
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
|
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# smidja-board.sh — Smíðja's board, by one name.
|
|
3
|
+
#
|
|
4
|
+
# The visualizer can live in two very different trees: a clone's
|
|
5
|
+
# `apps/smidja-factory/apps/visualizer`, or the `@zerwiz/smidja-factory` package
|
|
6
|
+
# a user got from npm. Its database lives in the HOME (`$YMIR_HOME/smidja/smidja.db`),
|
|
7
|
+
# not in either tree. This door resolves all three so the operator never has to.
|
|
8
|
+
#
|
|
9
|
+
# smidja-board.sh build # install deps and build the UI (./dist)
|
|
10
|
+
# smidja-board.sh start # raise the API + UI, detached, ready to answer
|
|
11
|
+
# smidja-board.sh stop
|
|
12
|
+
# smidja-board.sh status
|
|
13
|
+
# smidja-board.sh --version | --help
|
|
14
|
+
#
|
|
15
|
+
# The operator's door is `ymir smidja [build|start|stop|status]` — this is what
|
|
16
|
+
# that door runs.
|
|
17
|
+
#
|
|
18
|
+
# Exit: 0 ok, 1 error, 2 usage.
|
|
19
|
+
set -u
|
|
20
|
+
|
|
21
|
+
VERSION="1.0.0"
|
|
22
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
23
|
+
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
24
|
+
YMIR_HOME="${YMIR_HOME:-$HOME/Documents/Ymir}"
|
|
25
|
+
|
|
26
|
+
# shellcheck source=bin/hoard-lib.sh
|
|
27
|
+
. "$SCRIPT_DIR/hoard-lib.sh"
|
|
28
|
+
ymir_home_root YMIR_HOME
|
|
29
|
+
hoard_state_dir STATE
|
|
30
|
+
# shellcheck source=bin/smidja-lib.sh
|
|
31
|
+
. "$SCRIPT_DIR/smidja-lib.sh"
|
|
32
|
+
|
|
33
|
+
PORT="${SMIDJA_VIZ_API_PORT:-8437}"
|
|
34
|
+
PID_FILE="$STATE/smidja-viz-api.pid"
|
|
35
|
+
LOG_FILE="$STATE/smidja-viz-api.log"
|
|
36
|
+
|
|
37
|
+
# The database follows the HOME; SMIDJA_DB overrides. A tree-local copy is the
|
|
38
|
+
# last resort, for a checkout that keeps its own.
|
|
39
|
+
SMIDJA_DB_PATH="${SMIDJA_DB:-}"
|
|
40
|
+
if [ -z "$SMIDJA_DB_PATH" ]; then
|
|
41
|
+
for _db in "$YMIR_HOME/smidja/smidja.db" "$ROOT/apps/smidja/smidja_data/smidja.db"; do
|
|
42
|
+
[ -f "$_db" ] && { SMIDJA_DB_PATH="$_db"; break; }
|
|
43
|
+
done
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
viz_dir() { # <result-var>
|
|
47
|
+
local result_var=${1-} v
|
|
48
|
+
[ -n "$result_var" ] || return 2
|
|
49
|
+
if smidja_visualizer_dir v; then printf -v "$result_var" '%s' "$v"; return 0; fi
|
|
50
|
+
printf -v "$result_var" '%s' ""; return 1
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
alive() { [ -f "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE" 2>/dev/null)" 2>/dev/null; }
|
|
54
|
+
|
|
55
|
+
case "${1-}" in
|
|
56
|
+
-v|-V|--version) printf '%s\n' "$VERSION"; exit 0 ;;
|
|
57
|
+
-h|--help|"") sed -n '2,18p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
|
58
|
+
esac
|
|
59
|
+
ACTION="$1"
|
|
60
|
+
|
|
61
|
+
VIZ=""
|
|
62
|
+
if ! viz_dir VIZ; then
|
|
63
|
+
printf 'error: the visualizer is not installed in this tree\n'
|
|
64
|
+
printf 'help: npm i -g @zerwiz/ymir (the smithy arrives as @zerwiz/smidja-factory)\n'
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
case "$ACTION" in
|
|
69
|
+
build)
|
|
70
|
+
if ! command -v bun >/dev/null 2>&1; then
|
|
71
|
+
printf 'error: bun is needed to build the UI\nhelp: bin/prereq-ensure.sh bun\n' >&2; exit 1
|
|
72
|
+
fi
|
|
73
|
+
printf 'visualizer_build[1]{step,state}:\n'
|
|
74
|
+
if [ ! -d "$VIZ/node_modules" ]; then
|
|
75
|
+
if (cd "$VIZ" && bun install >/dev/null 2>&1); then printf ' "deps","installed"\n'
|
|
76
|
+
else printf ' "deps","FAILED — (cd %s && bun install)"\n' "$VIZ" >&2; exit 1; fi
|
|
77
|
+
else printf ' "deps","present"\n'; fi
|
|
78
|
+
if (cd "$VIZ" && bun run build >/dev/null 2>&1) || (cd "$VIZ" && bunx vite build >/dev/null 2>&1); then
|
|
79
|
+
printf ' "ui","%s/dist"\n' "$VIZ"
|
|
80
|
+
else
|
|
81
|
+
printf 'error: the UI build failed\nhelp: (cd %s && bun run build)\n' "$VIZ" >&2; exit 1
|
|
82
|
+
fi
|
|
83
|
+
;;
|
|
84
|
+
start)
|
|
85
|
+
command -v bun >/dev/null 2>&1 || { printf 'error: bun is needed to run the visualizer\nhelp: bin/prereq-ensure.sh bun\n' >&2; exit 1; }
|
|
86
|
+
[ -n "$SMIDJA_DB_PATH" ] && [ -f "$SMIDJA_DB_PATH" ] || {
|
|
87
|
+
printf 'error: no smidja.db found\nhelp: bin/smidja-bootstrap.sh (creates $YMIR_HOME/smidja/smidja.db)\n' >&2; exit 1; }
|
|
88
|
+
[ -d "$VIZ/dist" ] || printf 'note: the UI is unbuilt — the API will answer and show no interface\nnote: mend it with: bin/ymir-visualizer.sh build\n' >&2
|
|
89
|
+
if alive; then
|
|
90
|
+
printf 'visualizer[1]{state,pid,url}:\n "already running","%s","http://127.0.0.1:%s/"\n' "$(cat "$PID_FILE")" "$PORT"
|
|
91
|
+
exit 0
|
|
92
|
+
fi
|
|
93
|
+
mkdir -p "$STATE"
|
|
94
|
+
# ymir_detach PRINTS the pid it spawned (setsid/nohup is its business, not
|
|
95
|
+
# ours); reading $! here would read a variable the helper already consumed.
|
|
96
|
+
pid=""
|
|
97
|
+
if command -v ymir_detach >/dev/null 2>&1; then
|
|
98
|
+
pid="$(ymir_detach env CMD_DB="$SMIDJA_DB_PATH" PORT="$PORT" bun run "$VIZ/server/index.ts" 2>>"$LOG_FILE")"
|
|
99
|
+
fi
|
|
100
|
+
if [ -z "$pid" ]; then
|
|
101
|
+
( cd "$VIZ" && exec env CMD_DB="$SMIDJA_DB_PATH" PORT="$PORT" bun run server/index.ts ) >>"$LOG_FILE" 2>&1 &
|
|
102
|
+
pid="$!"
|
|
103
|
+
fi
|
|
104
|
+
[ -n "$pid" ] && printf '%s\n' "$pid" >"$PID_FILE"
|
|
105
|
+
for _i in $(seq 1 20); do
|
|
106
|
+
curl -s -o /dev/null --max-time 1 "http://127.0.0.1:$PORT/api/health" 2>/dev/null && break
|
|
107
|
+
sleep 0.5
|
|
108
|
+
done
|
|
109
|
+
if curl -s --max-time 2 "http://127.0.0.1:$PORT/api/health" >/dev/null 2>&1; then
|
|
110
|
+
printf 'visualizer[1]{state,db,url}:\n "up","%s","http://127.0.0.1:%s/"\n' "$SMIDJA_DB_PATH" "$PORT"
|
|
111
|
+
else
|
|
112
|
+
printf 'error: the visualizer did not answer on :%s\nhelp: see %s\n' "$PORT" "$LOG_FILE" >&2; exit 1
|
|
113
|
+
fi
|
|
114
|
+
;;
|
|
115
|
+
stop)
|
|
116
|
+
if alive; then
|
|
117
|
+
kill "$(cat "$PID_FILE")" 2>/dev/null; rm -f "$PID_FILE"
|
|
118
|
+
printf 'visualizer[1]{state}:\n "stopped"\n'
|
|
119
|
+
else
|
|
120
|
+
rm -f "$PID_FILE"
|
|
121
|
+
printf 'visualizer[1]{state}:\n "not running"\n'
|
|
122
|
+
fi
|
|
123
|
+
;;
|
|
124
|
+
status)
|
|
125
|
+
local_db="${SMIDJA_DB_PATH:-none}"
|
|
126
|
+
if alive && curl -s --max-time 2 "http://127.0.0.1:$PORT/api/health" >/dev/null 2>&1; then
|
|
127
|
+
printf 'visualizer[3]{state,pid,db,url}:\n "up","%s","%s","http://127.0.0.1:%s/"\n' "$(cat "$PID_FILE")" "$local_db" "$PORT"
|
|
128
|
+
elif alive; then
|
|
129
|
+
printf 'visualizer[2]{state,pid,note}:\n "starting or wedged","%s","answers nothing on :%s — see %s"\n' "$(cat "$PID_FILE")" "$PORT" "$LOG_FILE"
|
|
130
|
+
exit 1
|
|
131
|
+
else
|
|
132
|
+
printf 'visualizer[3]{state,tree,db,ui}:\n "down","%s","%s","%s"\n' "$VIZ" "$local_db" "$([ -d "$VIZ/dist" ] && echo built || echo unbuilt)"
|
|
133
|
+
fi
|
|
134
|
+
;;
|
|
135
|
+
*) printf 'error: unknown action %s\nhelp: bin/smidja-board.sh [build|start|stop|status]\n' "$ACTION" >&2; exit 2 ;;
|
|
136
|
+
esac
|
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")
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# smidja-lib.sh — where the smithy's parts actually live.
|
|
3
|
+
#
|
|
4
|
+
# Two installs, one name. In a clone the smithy sits at `apps/smidja-factory`
|
|
5
|
+
# (the registry's `repo: apps/<path>` block clones it there), and
|
|
6
|
+
# `.agents/skills/smidja-factory` is a symlink to it. In a packaged install the
|
|
7
|
+
# tree has no `apps/` at all: the smithy arrives as a dependency, at
|
|
8
|
+
# `node_modules/@zerwiz/smidja-factory`, and that symlink dangles.
|
|
9
|
+
#
|
|
10
|
+
# Every script that needs the visualizer resolves it HERE, so the two shapes can
|
|
11
|
+
# never disagree (Rule 07). Source-safe; defines functions only.
|
|
12
|
+
#
|
|
13
|
+
# smidja_factory_dir <result-var> the smithy: skill, skills/, templates/, apps/
|
|
14
|
+
# smidja_visualizer_dir <result-var> the board: its server, its UI source, its dist
|
|
15
|
+
set -u
|
|
16
|
+
|
|
17
|
+
# A surface has a name the operator knows and a package has a name npm serves;
|
|
18
|
+
# they are not always the same, and the smithy is the pair that proves it.
|
|
19
|
+
SMIDJA_SURFACE="smidja"
|
|
20
|
+
SMIDJA_PACKAGE="smidja-factory"
|
|
21
|
+
|
|
22
|
+
smidja_factory_dir() { # <result-var> — the smithy's directory, or empty
|
|
23
|
+
local result_var=${1-} root="${YMIR_ROOT_DIR:-}" c
|
|
24
|
+
[ -n "$result_var" ] || return 2
|
|
25
|
+
if [ -z "$root" ]; then
|
|
26
|
+
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
27
|
+
fi
|
|
28
|
+
for c in \
|
|
29
|
+
"$root/apps/$SMIDJA_PACKAGE" \
|
|
30
|
+
"$root/node_modules/@zerwiz/$SMIDJA_PACKAGE" \
|
|
31
|
+
"$root/.agents/skills/$SMIDJA_PACKAGE"
|
|
32
|
+
do
|
|
33
|
+
# A dangling symlink is not a home: the visualizer must be readable there.
|
|
34
|
+
[ -d "$c/apps/visualizer" ] && { printf -v "$result_var" '%s' "$c"; return 0; }
|
|
35
|
+
done
|
|
36
|
+
printf -v "$result_var" '%s' ""
|
|
37
|
+
return 1
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
smidja_visualizer_dir() { # <result-var> — the visualizer (server · UI source · dist)
|
|
41
|
+
local result_var=${1-} factory
|
|
42
|
+
[ -n "$result_var" ] || return 2
|
|
43
|
+
if smidja_factory_dir factory; then
|
|
44
|
+
printf -v "$result_var" '%s' "$factory/apps/visualizer"
|
|
45
|
+
return 0
|
|
46
|
+
fi
|
|
47
|
+
printf -v "$result_var" '%s' ""
|
|
48
|
+
return 1
|
|
49
|
+
}
|
|
@@ -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 ;;
|