@zerwiz/ymir 0.1.8 → 0.1.9

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/CHANGELOG.md CHANGED
@@ -1,4 +1,46 @@
1
1
 
2
+ ## 2026-09-17 — 0.1.9: both shapes reach the registry
3
+
4
+ - **`ymir raise` works on a packaged install.** 0.1.8 shipped before the resolver,
5
+ so a user who installed from npm hit `cd …/apps/hlidskjalf: No such file or
6
+ directory` — every package had arrived, and eighteen scripts were looking in the
7
+ clone's `apps/`. `bin/app-lib.sh` resolves a surface in either shape now.
8
+ - **A clone and a package are one tree to the scripts.** Proven against both: the
9
+ five surfaces resolve from `/home/zerwiz/Ymir` and from an npm-installed
10
+ package, and `ymir raise` against a packaged tree fetches the app's
11
+ dependencies, raises the gate API, starts Nornir cron, and brings up Bifrost and
12
+ the well.
13
+ - **The patience words** — `style_patience` — open the installer's long chain and
14
+ the raise path's build, so a long hour says what it is doing.
15
+
16
+ ## 2026-09-17 — both shapes: a clone and an npm install, and the patience words
17
+
18
+ - **`ymir raise` failed on a packaged install** — and the reason was ours, not
19
+ npm's. Every package had arrived; the scripts looked for the apps in the clone's
20
+ `apps/`, where a package keeps nothing. `scripts/start.sh` died on
21
+ `cd …/apps/hlidskjalf: No such file or directory`. **Eighteen files assumed the
22
+ clone's layout.**
23
+ - **One resolver, both shapes:** `bin/app-lib.sh` — `apps/<surface>` in a clone,
24
+ `node_modules/@zerwiz/<package>` in a package, with the surface→package map
25
+ (`smidja` → `@zerwiz/smidja-factory`). Wired into the raise path, the windows,
26
+ the invite door, the seat-hall, Eir, the icons, the placement, the hall snapshot
27
+ and the installer's own SPA and shell steps. `bin/smidja-lib.sh` delegates to it
28
+ now, so there is one truth about where things live.
29
+ - **Proven in both trees**: all five surfaces resolve from `/home/zerwiz/Ymir`
30
+ (a clone) and from an npm-installed package. And `ymir raise` run against the
31
+ packaged tree no longer dies — it fetches the app's dependencies, raises the
32
+ gate API, **starts Nornir cron**, and brings up Bifrost and the well.
33
+ - **A trap worth naming:** `printf -v <name>` writes to the *function's* scope, so
34
+ a helper whose scratch variable shares the caller's requested name swallows the
35
+ answer. Every scratch name in the resolvers is function-prefixed for that
36
+ reason.
37
+ - **The patience words.** A long install should say what it is doing and why it
38
+ takes a while. `style_patience` — the cloth's own line — now opens the
39
+ installer's long chain and the raise path's build:
40
+ *much moves · the halls are being set right · this hour is long, and nothing of
41
+ yours is lost in it — roots come home, shapes are re-cut, names are set true
42
+ again. Your patience is noted, and it is earned.*
43
+
2
44
  ## 2026-09-17 — 0.1.8: the day's work reaches npm
3
45
 
4
46
  - **The doors.** `ymir` now carries the operator's verbs, each named for the
package/bin/app-lib.sh ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env bash
2
+ # app-lib.sh — where an app actually lives.
3
+ #
4
+ # Two installs, one name. In a clone the apps sit at `apps/<surface>` (the
5
+ # registry's `repo: apps/<path>` block clones them there). In a packaged install
6
+ # the tree has no `apps/` at all: each surface arrives as a dependency, at
7
+ # `node_modules/@zerwiz/<package>`.
8
+ #
9
+ # surface package
10
+ # ---------------- ---------------------
11
+ # hlidskjalf hlidskjalf
12
+ # hlidskjalf-mobile hlidskjalf-mobile
13
+ # odrerir odrerir
14
+ # sessrumnir sessrumnir
15
+ # smidja smidja-factory
16
+ #
17
+ # A surface's name is not always its package's name — and a path is not a name at
18
+ # all. Every script that needs an app resolves it HERE, so the two shapes can
19
+ # never disagree (Rule 07). Source-safe; functions only.
20
+ #
21
+ # app_dir <surface> <result-var> the app's directory (empty + exit 1 if absent)
22
+ # app_pkg <surface> the npm package name for that surface
23
+ set -u
24
+
25
+ app_pkg() { # <surface> → the package name npm serves
26
+ case "${1-}" in
27
+ smidja) printf '%s' 'smidja-factory' ;;
28
+ *) printf '%s' "${1-}" ;;
29
+ esac
30
+ }
31
+
32
+ app_dir() { # <surface> <result-var> — a clone's apps/<x>, else the package
33
+ # Scratch names are function-prefixed on purpose: `printf -v <name>` writes to THIS
34
+ # function's scope, so a scratch variable sharing the caller's requested name
35
+ # would swallow the answer (a caller asking for "c" or "root" would get nothing).
36
+ local _apd_surface="${1-}" _apd_rv="${2-}" _apd_root _apd_pkg _apd_c
37
+ [ -n "$_apd_surface" ] && [ -n "$_apd_rv" ] || return 2
38
+ _apd_root="${YMIR_ROOT_DIR:-}"
39
+ if [ -z "$_apd_root" ]; then _apd_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"; fi
40
+ _apd_pkg="$(app_pkg "$_apd_surface")"
41
+ for _apd_c in "$_apd_root/apps/$_apd_surface" "$_apd_root/node_modules/@zerwiz/$_apd_pkg"; do
42
+ [ -d "$_apd_c" ] && { printf -v "$_apd_rv" '%s' "$_apd_c"; return 0; }
43
+ done
44
+ printf -v "$_apd_rv" '%s' ""
45
+ return 1
46
+ }
47
+
48
+ # Some callers need the directory a mint writes INTO (an app's public/, electron/,
49
+ # dist/…). A packaged app is read-only in spirit, so the clone's apps/ is preferred
50
+ # when it exists; otherwise the package is the only truth there is.
51
+ app_root() { # <result-var> — where apps live in THIS tree
52
+ local _apr_rv="${1-}" _apr_root
53
+ [ -n "$_apr_rv" ] || return 2
54
+ _apr_root="${YMIR_ROOT_DIR:-}"
55
+ if [ -z "$_apr_root" ]; then _apr_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"; fi
56
+ if [ -d "$_apr_root/apps" ]; then printf -v "$_apr_rv" '%s' "$_apr_root/apps"; return 0; fi
57
+ printf -v "$_apr_rv" '%s' "$_apr_root/node_modules/@zerwiz"
58
+ }
@@ -19,8 +19,19 @@ set -u
19
19
  VERSION="1.0.0"
20
20
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
21
21
  ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
22
+ # Where an app lives: apps/<surface> in a clone, node_modules/@zerwiz/<pkg> in an
23
+ # npm install — both shapes, one resolver (bin/app-lib.sh).
24
+ if [ -z "${YMIR_APP_LIB_LOADED:-}" ]; then
25
+ _ya="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
26
+ for _yac in "$_ya/app-lib.sh" "$(dirname "$_ya")/bin/app-lib.sh"; do
27
+ [ -r "$_yac" ] && { . "$_yac"; YMIR_APP_LIB_LOADED=1; break; }
28
+ done
29
+ unset _ya _yac
30
+ fi
31
+ app_dir sessrumnir APP_SESSRUMNIR || APP_SESSRUMNIR=""
32
+
22
33
  TOKENS="$ROOT/midgard/design-system/tokens.css"
23
- SEEDS="$ROOT/apps/sessrumnir/src/renderer/src/themes/fensalir.json"
34
+ SEEDS="$APP_SESSRUMNIR/src/renderer/src/themes/fensalir.json"
24
35
 
25
36
  case "${1-}" in
26
37
  -v|-V|--version) printf '%s\n' "$VERSION"; exit 0 ;;
@@ -16,6 +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
+ # Where an app lives: apps/<surface> in a clone, node_modules/@zerwiz/<pkg> in an
20
+ # npm install — both shapes, one resolver (bin/app-lib.sh).
21
+ if [ -z "${YMIR_APP_LIB_LOADED:-}" ]; then
22
+ _ya="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23
+ for _yac in "$_ya/app-lib.sh" "$(dirname "$_ya")/bin/app-lib.sh"; do
24
+ [ -r "$_yac" ] && { . "$_yac"; YMIR_APP_LIB_LOADED=1; break; }
25
+ done
26
+ unset _ya _yac
27
+ fi
28
+ app_dir hlidskjalf APP_HLIDSKJALF || APP_HLIDSKJALF=""
29
+ app_dir hlidskjalf-mobile APP_HLIDSKJALF_MOBILE || APP_HLIDSKJALF_MOBILE=""
30
+ app_dir odrerir APP_ODRERIR || APP_ODRERIR=""
31
+ app_dir sessrumnir APP_SESSRUMNIR || APP_SESSRUMNIR=""
32
+ app_dir smidja-factory APP_SMIDJA_FACTORY || APP_SMIDJA_FACTORY=""
33
+
19
34
  ICONS="$ROOT/midgard/design-system/icons"
20
35
  STONE="#0e0c09"
21
36
 
@@ -29,6 +29,19 @@ fi
29
29
  VERSION="1.0.0"
30
30
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
31
31
  ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
32
+ # Where an app lives: apps/<surface> in a clone, node_modules/@zerwiz/<pkg> in an
33
+ # npm install — both shapes, one resolver (bin/app-lib.sh).
34
+ if [ -z "${YMIR_APP_LIB_LOADED:-}" ]; then
35
+ _ya="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
36
+ for _yac in "$_ya/app-lib.sh" "$(dirname "$_ya")/bin/app-lib.sh"; do
37
+ [ -r "$_yac" ] && { . "$_yac"; YMIR_APP_LIB_LOADED=1; break; }
38
+ done
39
+ unset _ya _yac
40
+ fi
41
+ app_dir hlidskjalf APP_HLIDSKJALF || APP_HLIDSKJALF=""
42
+ app_dir sessrumnir APP_SESSRUMNIR || APP_SESSRUMNIR=""
43
+ app_dir odrerir APP_ODRERIR || APP_ODRERIR=""
44
+
32
45
  HYPR_DIR="$HOME/.config/hypr"
33
46
  RULE_FILE="$HYPR_DIR/ymir-desktops.lua"
34
47
  # The three Ymir surfaces, in the order they should claim desktops.
@@ -46,7 +59,7 @@ CLASS_odrerir="ymir-odrerir"
46
59
  # not a branch of this one.
47
60
  install_entries() {
48
61
  local dst="$HOME/.local/share/applications" n=0
49
- local dirs=("$ROOT/apps/hlidskjalf/electron" "$ROOT/apps/sessrumnir/resources" "$ROOT/apps/odrerir/electron")
62
+ local dirs=("$APP_HLIDSKJALF/electron" "$APP_SESSRUMNIR/resources" "$APP_ODRERIR/electron")
50
63
  if [ "$(ymir_os)" != linux ] && [ "$(ymir_os)" != wsl ]; then
51
64
  printf 'skip: desktop entries are Omarchy/Linux-shaped; this host is %s\n' "$(ymir_os)" >&2
52
65
  return 0
package/bin/eir-doctor.sh CHANGED
@@ -22,6 +22,17 @@ STATE="${BROKK_STATE_OVERRIDE:-$YMIR_HOME/state}"
22
22
  # stdout stay the data (bin/ymir-style.sh).
23
23
  if [ -z "${YMIR_STYLE_LOADED:-}" ]; then . "$SCRIPT_DIR/ymir-style.sh"; YMIR_STYLE_LOADED=1; fi
24
24
  style_init
25
+ # Where an app lives: apps/<surface> in a clone, node_modules/@zerwiz/<pkg> in an
26
+ # npm install — both shapes, one resolver (bin/app-lib.sh).
27
+ if [ -z "${YMIR_APP_LIB_LOADED:-}" ]; then
28
+ _ya="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
29
+ for _yac in "$_ya/app-lib.sh" "$(dirname "$_ya")/bin/app-lib.sh"; do
30
+ [ -r "$_yac" ] && { . "$_yac"; YMIR_APP_LIB_LOADED=1; break; }
31
+ done
32
+ unset _ya _yac
33
+ fi
34
+ app_dir sessrumnir APP_SESSRUMNIR || APP_SESSRUMNIR=""
35
+
25
36
 
26
37
  case "${1-}" in -v|-V|--version) printf '%s\n' "$VERSION"; exit 0 ;; -h|--help|"") sed -n '2,15p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; esac
27
38
  ACTION="${1:-check}"; shift || true
@@ -154,7 +165,7 @@ detail() { # <name> -> one short fact
154
165
  herdr) "have herdr && herdr --version 2>/dev/null | head -1 || echo 'herdr absent'" ;;
155
166
  a2abridge) "have a2abridge && a2abridge --version 2>/dev/null | head -1 || echo 'engine absent'" ;;
156
167
  hermes) "have hermes && echo present || echo absent" ;;
157
- sessrumnir)"[ -d $ROOT/apps/sessrumnir/out ] && echo built || echo 'not built'" ;;
168
+ sessrumnir)"[ -d $APP_SESSRUMNIR/out ] && echo built || echo 'not built'" ;;
158
169
  well) "echo 'engram :4602'" ;;
159
170
  mcp) "echo 'a2abridge + engram'" ;;
160
171
  lock) "cat $STATE/.lock 2>/dev/null | tr -d '[:space:]' | sed 's/^/pid /' || echo none" ;;
@@ -16,6 +16,17 @@
16
16
  # (the Live Hall's own deck; the merged public site takes it from its build).
17
17
  set -u
18
18
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19
+ # Where an app lives: apps/<surface> in a clone, node_modules/@zerwiz/<pkg> in an
20
+ # npm install — both shapes, one resolver (bin/app-lib.sh).
21
+ if [ -z "${YMIR_APP_LIB_LOADED:-}" ]; then
22
+ _ya="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23
+ for _yac in "$_ya/app-lib.sh" "$(dirname "$_ya")/bin/app-lib.sh"; do
24
+ [ -r "$_yac" ] && { . "$_yac"; YMIR_APP_LIB_LOADED=1; break; }
25
+ done
26
+ unset _ya _yac
27
+ fi
28
+ app_dir odrerir APP_ODRERIR || APP_ODRERIR=""
29
+
19
30
  ROOT="${BROKK_ROOT_OVERRIDE:-$(cd "$SCRIPT_DIR/.." && pwd)}"
20
31
 
21
32
  # The operator's settings and secrets live in the home they chose, never in the
@@ -37,7 +48,7 @@ hoard_data_dir YMIR_DATA_DIR
37
48
  # runtime state belong to the home the operator chose at installation, never in
38
49
  # the tree — a packaged install replaces its tree on upgrade (Rule 04).
39
50
  STATE="${BROKK_STATE_OVERRIDE:-$YMIR_STATE_DIR}"
40
- OUT="${1:-$ROOT/apps/odrerir/public/livehall.json}"
51
+ OUT="${1:-$APP_ODRERIR/public/livehall.json}"
41
52
 
42
53
  runes_file="${BROKK_RUNES_FILE:-${YMIR_HOME:-$HOME/Documents/Ymir}/hodd/memory/runes_audit.md}"
43
54
  PROJECTS_FILE="${YMIR_HOME:-$HOME/Documents/Ymir}/hodd/identity/projects.yaml"
@@ -20,7 +20,18 @@ set -u
20
20
  VERSION="1.0.0"
21
21
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
22
22
  ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
23
- APP="$ROOT/apps/sessrumnir"
23
+ # Where an app lives: apps/<surface> in a clone, node_modules/@zerwiz/<pkg> in an
24
+ # npm install — both shapes, one resolver (bin/app-lib.sh).
25
+ if [ -z "${YMIR_APP_LIB_LOADED:-}" ]; then
26
+ _ya="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
27
+ for _yac in "$_ya/app-lib.sh" "$(dirname "$_ya")/bin/app-lib.sh"; do
28
+ [ -r "$_yac" ] && { . "$_yac"; YMIR_APP_LIB_LOADED=1; break; }
29
+ done
30
+ unset _ya _yac
31
+ fi
32
+ app_dir sessrumnir APP_SESSRUMNIR || APP_SESSRUMNIR=""
33
+
34
+ APP="$APP_SESSRUMNIR"
24
35
 
25
36
  case "${1-}" in -v|-V|--version) printf '%s\n' "$VERSION"; exit 0 ;; -h|--help|"") sed -n '2,16p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; esac
26
37
  CMD="${1-}"; shift || true
@@ -24,7 +24,18 @@
24
24
  set -euo pipefail
25
25
 
26
26
  ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
27
- APP="$ROOT/apps/sessrumnir"
27
+ # Where an app lives: apps/<surface> in a clone, node_modules/@zerwiz/<pkg> in an
28
+ # npm install — both shapes, one resolver (bin/app-lib.sh).
29
+ if [ -z "${YMIR_APP_LIB_LOADED:-}" ]; then
30
+ _ya="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
31
+ for _yac in "$_ya/app-lib.sh" "$(dirname "$_ya")/bin/app-lib.sh"; do
32
+ [ -r "$_yac" ] && { . "$_yac"; YMIR_APP_LIB_LOADED=1; break; }
33
+ done
34
+ unset _ya _yac
35
+ fi
36
+ app_dir sessrumnir APP_SESSRUMNIR || APP_SESSRUMNIR=""
37
+
38
+ APP="$APP_SESSRUMNIR"
28
39
  FORK="$APP/fork"
29
40
  UPSTREAM_REPO="${SESSRUMNIR_UPSTREAM:-https://github.com/zerwiz/pi-desktop.git}"
30
41
  OWNED_JSON="$FORK/owned.json"
package/bin/sessrumnir.sh CHANGED
@@ -14,6 +14,17 @@ 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
+ # Where an app lives: apps/<surface> in a clone, node_modules/@zerwiz/<pkg> in an
18
+ # npm install — both shapes, one resolver (bin/app-lib.sh).
19
+ if [ -z "${YMIR_APP_LIB_LOADED:-}" ]; then
20
+ _ya="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
21
+ for _yac in "$_ya/app-lib.sh" "$(dirname "$_ya")/bin/app-lib.sh"; do
22
+ [ -r "$_yac" ] && { . "$_yac"; YMIR_APP_LIB_LOADED=1; break; }
23
+ done
24
+ unset _ya _yac
25
+ fi
26
+ app_dir sessrumnir APP_SESSRUMNIR || APP_SESSRUMNIR=""
27
+
17
28
 
18
29
  # The roots that live OUTSIDE the code tree: this machine's records and the
19
30
  # runtime state belong to the home the operator chose at installation, never in
@@ -27,7 +38,7 @@ if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
27
38
  fi
28
39
  hoard_state_dir YMIR_STATE_DIR
29
40
  hoard_data_dir YMIR_DATA_DIR
30
- APP="$ROOT/apps/sessrumnir"
41
+ APP="$APP_SESSRUMNIR"
31
42
  PID_FILE="$YMIR_STATE_DIR/sessrumnir.pid"
32
43
  LOG_FILE="$YMIR_STATE_DIR/sessrumnir.log"
33
44
 
package/bin/smidja-lib.sh CHANGED
@@ -20,20 +20,21 @@ SMIDJA_SURFACE="smidja"
20
20
  SMIDJA_PACKAGE="smidja-factory"
21
21
 
22
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)"
23
+ # The general resolver (bin/app-lib.sh) knows both shapes; the smithy is one
24
+ # surface among them. The old skill symlink is the last resort, and a dangling
25
+ # one is not a home — the visualizer must be readable there.
26
+ local _smd_rv=${1-} _smd_c
27
+ [ -n "$_smd_rv" ] || return 2
28
+ if [ -z "${YMIR_APP_LIB_LOADED:-}" ]; then
29
+ local _sl; _sl="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
30
+ [ -r "$_sl/app-lib.sh" ] && { . "$_sl/app-lib.sh"; YMIR_APP_LIB_LOADED=1; }
27
31
  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' ""
32
+ if app_dir smidja _smd_c 2>/dev/null && [ -d "$_smd_c/apps/visualizer" ]; then
33
+ printf -v "$_smd_rv" '%s' "$_smd_c"; return 0
34
+ fi
35
+ _smd_c="${YMIR_ROOT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}/.agents/skills/$SMIDJA_PACKAGE"
36
+ [ -d "$_smd_c/apps/visualizer" ] && { printf -v "$_smd_rv" '%s' "$_smd_c"; return 0; }
37
+ printf -v "$_smd_rv" '%s' ""
37
38
  return 1
38
39
  }
39
40
 
@@ -53,6 +53,8 @@ hoard_local_env YMIR_ENV_FILE
53
53
  # repo (Rule 04).
54
54
  # shellcheck source=bin/hoard-lib.sh
55
55
  . "$SCRIPT_DIR/hoard-lib.sh"
56
+ # shellcheck source=bin/app-lib.sh
57
+ . "$SCRIPT_DIR/app-lib.sh"
56
58
  ymir_home_root YMIR_HOME
57
59
  # Where the smithy's parts live: apps/smidja-factory in a clone, or the
58
60
  # @zerwiz/smidja-factory package in an npm install (bin/smidja-lib.sh).
@@ -585,7 +587,8 @@ step_smidja() {
585
587
  # Hlidskjalf installs with npm (its own lockfile), not bun, and its API serves the
586
588
  # UI from ./dist. Without this step a fresh clone has no SPA and no build.
587
589
  step_spa() {
588
- local app="$ROOT/apps/hlidskjalf"
590
+ local app; app_dir hlidskjalf app || app=""
591
+ local app_ok="$app"
589
592
  [ -d "$app" ] || { add hlidskjalf SKIP "no apps/hlidskjalf"; return 0; }
590
593
  if [ "$CHECK" = 0 ]; then
591
594
  if ! have npm; then
@@ -708,8 +711,8 @@ step_desktop() {
708
711
  fi
709
712
  local shell partial=""
710
713
  for shell in hlidskjalf odrerir sessrumnir; do
711
- local dir="$ROOT/apps/$shell" d
712
- [ -d "$dir" ] || dir="$(cd "$ROOT" && npm root 2>/dev/null)/@zerwiz/$shell"
714
+ local dir d
715
+ app_dir "$shell" dir || continue
713
716
  d="$(electron_runtime_state "$dir" 2>/dev/null || true)"
714
717
  [ "$d" = partial ] && partial="$partial $shell"
715
718
  done
@@ -819,6 +822,7 @@ step_panes() {
819
822
 
820
823
  # Ask before touching the machine; --check only previews and never asks.
821
824
  [ "$CHECK" = 0 ] && confirm_install
825
+ [ "$CHECK" = 0 ] && style_patience "the halls are being stood up for the first time"
822
826
 
823
827
  step_panes; step_prereqs; step_home; step_tree; step_apps; step_engines; step_models; step_hermes; step_sessrumnir; step_backend; step_host; step_sandbox; step_memory; step_smidja; step_spa; step_omarchy; step_loaders; step_gates; step_marks
824
828
  # Migrations MOVE private data — that is a write, and `--check` promises none.
@@ -16,8 +16,19 @@
16
16
  set -euo pipefail
17
17
 
18
18
  ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
19
- MODULE="$ROOT/apps/hlidskjalf/server/accounts.ts"
20
- STORE="$ROOT/apps/hlidskjalf/server/accounts.ts" # absolute: one definition of an account, wherever this is run from
19
+ # Where an app lives: apps/<surface> in a clone, node_modules/@zerwiz/<pkg> in an
20
+ # npm install both shapes, one resolver (bin/app-lib.sh).
21
+ if [ -z "${YMIR_APP_LIB_LOADED:-}" ]; then
22
+ _ya="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23
+ for _yac in "$_ya/app-lib.sh" "$(dirname "$_ya")/bin/app-lib.sh"; do
24
+ [ -r "$_yac" ] && { . "$_yac"; YMIR_APP_LIB_LOADED=1; break; }
25
+ done
26
+ unset _ya _yac
27
+ fi
28
+ app_dir hlidskjalf APP_HLIDSKJALF || APP_HLIDSKJALF=""
29
+
30
+ MODULE="$APP_HLIDSKJALF/server/accounts.ts"
31
+ STORE="$APP_HLIDSKJALF/server/accounts.ts" # absolute: one definition of an account, wherever this is run from
21
32
 
22
33
  die() { printf 'ymir-invite: %s\n' "$1" >&2; exit 1; }
23
34
 
@@ -25,7 +36,7 @@ command -v bun >/dev/null 2>&1 || die "bun is required (bin/ymir-install.sh inst
25
36
 
26
37
  # A tiny bun program per action — the module is the single source of truth.
27
38
  accounts() {
28
- ( cd "$ROOT/apps/hlidskjalf" && bun -e "$1" )
39
+ ( cd "$APP_HLIDSKJALF" && bun -e "$1" )
29
40
  }
30
41
 
31
42
  [ -f "$MODULE" ] || die "the account store module is missing: $MODULE"
package/bin/ymir-style.sh CHANGED
@@ -95,6 +95,19 @@ style_line() { # <state> <name> <detail> — the one line per thing
95
95
 
96
96
  style_heading() { printf '\n%s%s%s\n' "$C_BRONZE" "$1" "$C_OFF" >&2; }
97
97
 
98
+ # For a long hour: say what is happening and why it takes a while. A user who
99
+ # knows the halls are being set right waits; a user watching a silent cursor
100
+ # wonders whether it has broken.
101
+ style_patience() { # [what is being set right]
102
+ local what="${1:-the halls are being set right}"
103
+ printf '\n' >&2
104
+ style_line DO "much moves" "$what"
105
+ style_hint " this hour is long, and nothing of yours is lost in it —"
106
+ style_hint " roots come home, shapes are re-cut, names are set true again."
107
+ style_hint " Your patience is noted, and it is earned."
108
+ printf '\n' >&2
109
+ }
110
+
98
111
  # The ending: what stands, then exactly what to type next. Every CLI deserves
99
112
  # to leave the operator with the next step and nothing else to guess.
100
113
  style_next() { # one command per line, as "verb — what it does"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerwiz/ymir",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Ymir \u2014 the single-tenant agent operating system. Omarchy-first, host-aware, self-healing.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/zerwiz/ymir",
@@ -26,6 +26,19 @@ fi
26
26
  VERSION="1.1.0"
27
27
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
28
28
  ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
29
+ # Where an app lives: apps/<surface> in a clone, node_modules/@zerwiz/<pkg> in an
30
+ # npm install — both shapes, one resolver (bin/app-lib.sh).
31
+ if [ -z "${YMIR_APP_LIB_LOADED:-}" ]; then
32
+ _ya="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
33
+ for _yac in "$_ya/app-lib.sh" "$(dirname "$_ya")/bin/app-lib.sh"; do
34
+ [ -r "$_yac" ] && { . "$_yac"; YMIR_APP_LIB_LOADED=1; break; }
35
+ done
36
+ unset _ya _yac
37
+ fi
38
+ app_dir hlidskjalf APP_HLIDSKJALF || APP_HLIDSKJALF=""
39
+ app_dir odrerir APP_ODRERIR || APP_ODRERIR=""
40
+ app_dir sessrumnir APP_SESSRUMNIR || APP_SESSRUMNIR=""
41
+
29
42
 
30
43
  # The roots that live OUTSIDE the code tree: this machine's records and the
31
44
  # runtime state belong to the home the operator chose at installation, never in
@@ -39,8 +52,8 @@ if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
39
52
  fi
40
53
  hoard_state_dir YMIR_STATE_DIR
41
54
  hoard_data_dir YMIR_DATA_DIR
42
- APP="$ROOT/apps/hlidskjalf"
43
- Odrerir_app="$ROOT/apps/odrerir"
55
+ APP="$APP_HLIDSKJALF"
56
+ Odrerir_app="$APP_ODRERIR"
44
57
  NO_INSTALL=0
45
58
  VIEW="${YMIR_DESKTOP_VIEW:-hlidskjalf}"
46
59
  VIEWS=(hlidskjalf smidja odrerir)
package/scripts/start.sh CHANGED
@@ -17,6 +17,21 @@ if [ -z "${YMIR_PLATFORM_LOADED:-}" ]; then
17
17
  fi
18
18
 
19
19
  ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
20
+ # The cloth (bin/ymir-style.sh) — colour and words for the human watching.
21
+ if [ -z "${YMIR_STYLE_LOADED:-}" ] && [ -r "$ROOT/bin/ymir-style.sh" ]; then
22
+ . "$ROOT/bin/ymir-style.sh"; YMIR_STYLE_LOADED=1; style_init
23
+ fi
24
+ # Where an app lives: apps/<surface> in a clone, node_modules/@zerwiz/<pkg> in an
25
+ # npm install — both shapes, one resolver (bin/app-lib.sh).
26
+ if [ -z "${YMIR_APP_LIB_LOADED:-}" ]; then
27
+ _ya="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
28
+ for _yac in "$_ya/app-lib.sh" "$(dirname "$_ya")/bin/app-lib.sh"; do
29
+ [ -r "$_yac" ] && { . "$_yac"; YMIR_APP_LIB_LOADED=1; break; }
30
+ done
31
+ unset _ya _yac
32
+ fi
33
+ app_dir hlidskjalf APP_HLIDSKJALF || APP_HLIDSKJALF=""
34
+
20
35
  # Where the smithy's parts live: apps/smidja-factory in a clone, or the
21
36
  # @zerwiz/smidja-factory package in an npm install (bin/smidja-lib.sh).
22
37
  if [ -z "${YMIR_SMIDJA_LIB_LOADED:-}" ]; then
@@ -48,7 +63,7 @@ hoard_data_dir YMIR_DATA_DIR
48
63
  # The roots that live OUTSIDE the code tree: this machine's records and the
49
64
  # runtime state belong to the home the operator chose at installation, never in
50
65
  # the tree — a packaged install replaces its tree on upgrade (Rule 04).
51
- APP="$ROOT/apps/hlidskjalf"
66
+ APP="$APP_HLIDSKJALF"
52
67
  RUN="$ROOT/.run"
53
68
  PID_FILE="$RUN/hlidskjalf.pid"
54
69
  LOG="$RUN/hlidskjalf.log"
@@ -80,7 +95,8 @@ else
80
95
  fi
81
96
 
82
97
  if [[ ! -d "$APP/node_modules" ]]; then
83
- echo "Installing dependencies"
98
+ style_patience "the seat's own dependencies are being fetched, then the hall is raised"
99
+ echo "Installing dependencies…"
84
100
  (cd "$APP" && npm install --no-audit --no-fund)
85
101
  fi
86
102