@zerwiz/ymir 0.1.9 → 0.1.11
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/skills/galdr-ymirsystem/assets/installation.md +122 -0
- package/.agents/skills/groa-update/SKILL.md +9 -0
- package/.agents/skills/ymir-host/assets/install.md +29 -0
- package/CHANGELOG.md +119 -0
- package/README.md +54 -0
- package/bin/design-icon.sh +18 -3
- package/bin/desktop-place.sh +20 -5
- package/bin/ymir-config.sh +76 -0
- package/bin/ymir-install.sh +16 -3
- package/bin/ymir-style.sh +24 -0
- package/bin/ymir.js +35 -0
- package/midgard/README.md +16 -0
- package/midgard/design-system/.gitkeep +0 -0
- package/midgard/design-system/ember.d.ts +13 -0
- package/midgard/design-system/ember.js +183 -0
- package/midgard/design-system/icons/algiz.svg +4 -0
- package/midgard/design-system/icons/ansuz.svg +4 -0
- package/midgard/design-system/icons/berkana.svg +4 -0
- package/midgard/design-system/icons/dagaz.svg +4 -0
- package/midgard/design-system/icons/ehwaz.svg +4 -0
- package/midgard/design-system/icons/fehu.svg +4 -0
- package/midgard/design-system/icons/gjallarhorn.svg +4 -0
- package/midgard/design-system/icons/gungnir.svg +4 -0
- package/midgard/design-system/icons/heimdall.svg +4 -0
- package/midgard/design-system/icons/ingwaz.svg +4 -0
- package/midgard/design-system/icons/jera.svg +4 -0
- package/midgard/design-system/icons/kaunan.svg +4 -0
- package/midgard/design-system/icons/midgard.svg +4 -0
- package/midgard/design-system/icons/mimirsbrunn.svg +4 -0
- package/midgard/design-system/icons/othala.svg +4 -0
- package/midgard/design-system/icons/raidho.svg +4 -0
- package/midgard/design-system/icons/ratatoskr.svg +4 -0
- package/midgard/design-system/icons/sowilo.svg +4 -0
- package/midgard/design-system/icons/tiwaz.svg +4 -0
- package/midgard/design-system/icons/utgard.svg +4 -0
- package/midgard/design-system/icons/valhalla.svg +4 -0
- package/midgard/design-system/icons/yggdrasil.svg +4 -0
- package/midgard/design-system/icons.md +59 -0
- package/midgard/design-system/runes.md +78 -0
- package/midgard/design-system/tokens.css +109 -0
- package/midgard/design-system/ymir-mark.svg +62 -0
- package/package.json +2 -1
- package/scripts/electron.sh +18 -2
- package/scripts/start.sh +66 -12
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
YMIR — Design Tokens · Canonical (the carved cloth of the halls)
|
|
3
|
+
Source of truth: docs/design.md §4.
|
|
4
|
+
The cloth is cut from the landing page (CodeP/ymir-homepage/src/lore.html
|
|
5
|
+
:root): stone and bone, bronze and blood, and the three faces Cormorant /
|
|
6
|
+
Newsreader / IBM Plex Mono. The landing is the reference — a token change
|
|
7
|
+
here re-themes every hall (Hlidskjalf, Smíðja, and the seat).
|
|
8
|
+
House accents are heraldry, not chrome: they stay, exactly as the landing
|
|
9
|
+
keeps its house seals.
|
|
10
|
+
Consume via CSS variables — never hardcode hex in components.
|
|
11
|
+
============================================================ */
|
|
12
|
+
|
|
13
|
+
:root {
|
|
14
|
+
/* --- Canvas: the stone ------------------------------- */
|
|
15
|
+
--ymir-bg-0: #0e0c09; /* stone — the ground */
|
|
16
|
+
--ymir-bg-1: #151209; /* panel */
|
|
17
|
+
--ymir-bg-2: #1a1610; /* panel2 — elevated surface, cards */
|
|
18
|
+
--ymir-bg-3: #221d14; /* line-soft — hover, wells */
|
|
19
|
+
|
|
20
|
+
/* --- Accents: the bronze light of the forge ---------- */
|
|
21
|
+
--ymir-cyan-1: #c9973f; /* bronze — primary accent, active states, focus, links */
|
|
22
|
+
--ymir-cyan-2: #7d5f2a; /* bronze-deep — hover/darker accent */
|
|
23
|
+
--ymir-violet-1: #96a0a8; /* steel — realm identity, secondary accent */
|
|
24
|
+
--ymir-violet-2: #5f686e; /* steel-dim */
|
|
25
|
+
|
|
26
|
+
/* --- Structure: bone and brass ----------------------- */
|
|
27
|
+
--ymir-steel-1: #2b241a; /* line — borders, bevel exteriors */
|
|
28
|
+
--ymir-steel-2: #7d5f2a; /* bronze-deep — stronger rules, dividers */
|
|
29
|
+
--ymir-steel-3: #9a8f75; /* bone-dim — secondary text, muted glyphs */
|
|
30
|
+
--ymir-chisel: #c9973f; /* bronze — the lit chisel edge (emblem, focus) */
|
|
31
|
+
|
|
32
|
+
/* --- Semantics: state of the forge ------------------- */
|
|
33
|
+
--ymir-ok: #96a0a8; /* steel — the metal proved true */
|
|
34
|
+
--ymir-warn: #c9973f; /* bronze — hot, heed it */
|
|
35
|
+
--ymir-danger: #c2584a; /* blood-lit — the wound */
|
|
36
|
+
--ymir-info: #9a8f75; /* bone-dim — the note */
|
|
37
|
+
--ymir-ok-dim: rgba(150, 160, 168, 0.15);
|
|
38
|
+
--ymir-warn-dim: rgba(201, 151, 79, 0.15);
|
|
39
|
+
--ymir-danger-dim: rgba(194, 88, 74, 0.15);
|
|
40
|
+
--ymir-info-dim: rgba(154, 143, 117, 0.15);
|
|
41
|
+
|
|
42
|
+
/* --- Text on stone ----------------------------------- */
|
|
43
|
+
--ymir-text-0: #cfc3a9; /* bone — primary text */
|
|
44
|
+
--ymir-text-1: rgba(207, 195, 169, 0.82); /* bone, blunted — secondary text */
|
|
45
|
+
--ymir-text-2: #9a8f75; /* bone-dim — tertiary, disabled */
|
|
46
|
+
--ymir-text-3: #6b6250; /* bone-faint — placeholder */
|
|
47
|
+
|
|
48
|
+
/* --- House accents (structural only, never chrome) ---------- */
|
|
49
|
+
--ymir-house-ymirlabs: #c9973f; /* bronze — the platform's own house wears the forge accent (was blue) */
|
|
50
|
+
--ymir-house-brokkforge: #f59e0b;
|
|
51
|
+
--ymir-house-runestone: #f43f5e;
|
|
52
|
+
--ymir-house-muninn: #8b5cf6;
|
|
53
|
+
--ymir-house-dvalin: #94a3b8;
|
|
54
|
+
--ymir-house-utgard: #d946ef;
|
|
55
|
+
--ymir-house-askr: #34d399;
|
|
56
|
+
--ymir-house-mannheim: #64748b;
|
|
57
|
+
|
|
58
|
+
/* --- Type: the cloth's three faces --------------------------- */
|
|
59
|
+
/* Runic glyphs fall through to Noto Sans Runic inside every stack, so a rune
|
|
60
|
+
renders in the rune family wherever it is written. */
|
|
61
|
+
--ymir-font-head: 'Cormorant', 'Noto Sans Runic', Georgia, serif;
|
|
62
|
+
--ymir-font-mono: 'IBM Plex Mono', 'Noto Sans Runic', ui-monospace, 'Cascadia Mono', monospace;
|
|
63
|
+
--ymir-font-body: 'Newsreader', Georgia, 'Noto Sans Runic', serif;
|
|
64
|
+
|
|
65
|
+
--ymir-s-mono-s: 12px / 16px;
|
|
66
|
+
--ymir-s-mono-m: 14px / 20px;
|
|
67
|
+
--ymir-s-mono-l: 18px / 24px;
|
|
68
|
+
--ymir-s-display: clamp(28px, 4vw, 44px) / 1.1;
|
|
69
|
+
--ymir-s-body: 15px / 22px;
|
|
70
|
+
--ymir-s-caption: 13px / 18px;
|
|
71
|
+
|
|
72
|
+
/* --- Space & structure ----------------------------------------- */
|
|
73
|
+
--ymir-space-1: 4px;
|
|
74
|
+
--ymir-space-2: 8px;
|
|
75
|
+
--ymir-space-3: 12px;
|
|
76
|
+
--ymir-space-4: 16px;
|
|
77
|
+
--ymir-space-5: 24px;
|
|
78
|
+
--ymir-space-6: 32px;
|
|
79
|
+
--ymir-space-7: 48px;
|
|
80
|
+
|
|
81
|
+
--ymir-radius: 8px;
|
|
82
|
+
--ymir-radius-panel: 12px;
|
|
83
|
+
--ymir-border: 1px solid var(--ymir-steel-1);
|
|
84
|
+
|
|
85
|
+
/* Bevel: sell the carved edge — a brass hairline inside the stone */
|
|
86
|
+
--ymir-bevel: inset 0 0 0 1px rgba(201, 151, 79, 0.12);
|
|
87
|
+
--ymir-shadow-panel: 0 1px 2px rgba(0, 0, 0, 0.5);
|
|
88
|
+
--ymir-shadow-raise: 0 8px 24px rgba(0, 0, 0, 0.55);
|
|
89
|
+
|
|
90
|
+
/* --- Motion ------------------------------------------------------- */
|
|
91
|
+
--ymir-dur-fast: 120ms;
|
|
92
|
+
--ymir-dur-task: 180ms;
|
|
93
|
+
--ymir-dur-hop: 220ms;
|
|
94
|
+
--ymir-dur-roll: 240ms;
|
|
95
|
+
--ymir-ease: cubic-bezier(0.4, 0, 0.2, 1);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* Numeric safety for all telemetry */
|
|
99
|
+
.tabular { font-variant-numeric: tabular-nums; font-family: var(--ymir-font-mono); }
|
|
100
|
+
|
|
101
|
+
/* Status chips: color + rune + label — never color alone */
|
|
102
|
+
.status-ok { color: var(--ymir-ok); background: var(--ymir-ok-dim); }
|
|
103
|
+
.status-warn { color: var(--ymir-warn); background: var(--ymir-warn-dim); }
|
|
104
|
+
.status-danger{ color: var(--ymir-danger); background: var(--ymir-danger-dim); }
|
|
105
|
+
.status-info { color: var(--ymir-info); background: var(--ymir-info-dim); }
|
|
106
|
+
|
|
107
|
+
@media (prefers-reduced-motion: reduce) {
|
|
108
|
+
* { transition-duration: 120ms !important; animation-duration: 120ms !important; }
|
|
109
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="100%" height="100%">
|
|
2
|
+
<defs>
|
|
3
|
+
<!-- Background Dark Steel Gradient -->
|
|
4
|
+
<linearGradient id="bg-grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
5
|
+
<stop offset="0%" stop-color="#0f172a" />
|
|
6
|
+
<stop offset="100%" stop-color="#020617" />
|
|
7
|
+
</linearGradient>
|
|
8
|
+
|
|
9
|
+
<!-- Base Metal Color for the Rune -->
|
|
10
|
+
<linearGradient id="metal-base" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
11
|
+
<stop offset="0%" stop-color="#38bdf8" />
|
|
12
|
+
<stop offset="50%" stop-color="#475569" />
|
|
13
|
+
<stop offset="100%" stop-color="#1e293b" />
|
|
14
|
+
</linearGradient>
|
|
15
|
+
|
|
16
|
+
<!-- Advanced 3D Forge Filter -->
|
|
17
|
+
<filter id="heavy-metal-3d" x="-20%" y="-20%" width="140%" height="140%">
|
|
18
|
+
<!-- 1. Generate Hammered Iron Texture -->
|
|
19
|
+
<feTurbulence type="fractalNoise" baseFrequency="0.04" numOctaves="4" result="noise" />
|
|
20
|
+
<feColorMatrix type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.15 0" in="noise" result="coloredNoise" />
|
|
21
|
+
|
|
22
|
+
<!-- 2. Blend Texture with Base Color -->
|
|
23
|
+
<feComposite operator="in" in="coloredNoise" in2="SourceGraphic" result="textured" />
|
|
24
|
+
<feBlend mode="multiply" in="textured" in2="SourceGraphic" result="baseTex" />
|
|
25
|
+
|
|
26
|
+
<!-- 3. Create 3D Bevel / Depth Map -->
|
|
27
|
+
<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur" />
|
|
28
|
+
|
|
29
|
+
<!-- 4. Apply 3D Lighting (Cyan/Blue Specular Highlight) -->
|
|
30
|
+
<feSpecularLighting in="blur" surfaceScale="6" specularConstant="1.2" specularExponent="25" lighting-color="#bae6fd" result="specOut">
|
|
31
|
+
<!-- Light Source Positioned Top-Left -->
|
|
32
|
+
<fePointLight x="-100" y="-100" z="300" />
|
|
33
|
+
</feSpecularLighting>
|
|
34
|
+
|
|
35
|
+
<!-- 5. Mask Lighting to the Shape -->
|
|
36
|
+
<feComposite operator="in" in="specOut" in2="SourceAlpha" result="specularMasked" />
|
|
37
|
+
|
|
38
|
+
<!-- 6. Combine Lighting and Textured Base -->
|
|
39
|
+
<feComposite operator="arithmetic" k1="0" k2="1" k3="1" k4="0" in="specularMasked" in2="baseTex" result="litModel" />
|
|
40
|
+
|
|
41
|
+
<!-- 7. Heavy Drop Shadow for Canvas Depth -->
|
|
42
|
+
<feDropShadow in="litModel" dx="0" dy="16" stdDeviation="12" flood-opacity="0.85" flood-color="#000000" result="finalShadow" />
|
|
43
|
+
</filter>
|
|
44
|
+
</defs>
|
|
45
|
+
|
|
46
|
+
<!-- Canvas -->
|
|
47
|
+
<rect width="512" height="512" rx="40" fill="url(#bg-grad)" stroke="#1e293b" stroke-width="4"/>
|
|
48
|
+
|
|
49
|
+
<!-- Master Group with 3D Rendering Filter Applied -->
|
|
50
|
+
<g filter="url(#heavy-metal-3d)" fill="url(#metal-base)">
|
|
51
|
+
|
|
52
|
+
<!-- Algiz Y-Stem (Solid Geometric Polygon) -->
|
|
53
|
+
<polygon points="120,100 168,100 256,188 344,100 392,100 276,216 276,340 236,340 236,216" />
|
|
54
|
+
|
|
55
|
+
<!-- Top Anvil Bar -->
|
|
56
|
+
<polygon points="100,340 412,340 400,388 112,388" />
|
|
57
|
+
|
|
58
|
+
<!-- Bottom Anvil Bar (Slightly narrower base) -->
|
|
59
|
+
<polygon points="132,408 380,408 368,440 144,440" />
|
|
60
|
+
|
|
61
|
+
</g>
|
|
62
|
+
</svg>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zerwiz/ymir",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
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",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
".agents/",
|
|
31
31
|
"scripts/",
|
|
32
32
|
"RULES/",
|
|
33
|
+
"midgard/design-system/",
|
|
33
34
|
"docs/",
|
|
34
35
|
"packaging/",
|
|
35
36
|
"AGENTS.md",
|
package/scripts/electron.sh
CHANGED
|
@@ -184,9 +184,25 @@ ensure_electron_binary() {
|
|
|
184
184
|
return 1
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
# npm gates install scripts by default (11.16+ warns, 12 refuses), and Electron's
|
|
188
|
+
# postinstall is what downloads the runtime — so a fresh install can build the web
|
|
189
|
+
# app perfectly and still have no window. Before refusing, do the mending a user
|
|
190
|
+
# would otherwise be told to do by hand: approve the script and rebuild.
|
|
191
|
+
repair_electron() { # <app-dir>
|
|
192
|
+
local dir="$1"
|
|
193
|
+
command -v npm >/dev/null 2>&1 || return 1
|
|
194
|
+
( cd "$dir" && npm install-scripts approve electron >/dev/null 2>&1 || true
|
|
195
|
+
cd "$dir" && npm rebuild electron >/dev/null 2>&1 )
|
|
196
|
+
}
|
|
187
197
|
if ! ensure_electron_binary; then
|
|
188
|
-
|
|
189
|
-
|
|
198
|
+
# Try the mending ourselves before telling the user to do it by hand: npm's
|
|
199
|
+
# gating is the cause, and the cure is one command we can run.
|
|
200
|
+
echo "the Electron runtime is partial — mending it (npm rebuild electron)…" >&2
|
|
201
|
+
repair_electron "$APP" >/dev/null 2>&1 || true
|
|
202
|
+
ensure_electron_binary || {
|
|
203
|
+
printf 'error: the Electron runtime could not be mended\nhelp: cd <the app> && npm install-scripts approve electron && npm rebuild electron\nhelp: or run the web surfaces only: ymir install --no-desktop\n' >&2
|
|
204
|
+
exit 1
|
|
205
|
+
}
|
|
190
206
|
fi
|
|
191
207
|
|
|
192
208
|
app_dir() { case "$1" in odrerir) printf '%s' "$Odrerir_app" ;; *) printf '%s' "$APP" ;; esac; }
|
package/scripts/start.sh
CHANGED
|
@@ -31,6 +31,7 @@ if [ -z "${YMIR_APP_LIB_LOADED:-}" ]; then
|
|
|
31
31
|
unset _ya _yac
|
|
32
32
|
fi
|
|
33
33
|
app_dir hlidskjalf APP_HLIDSKJALF || APP_HLIDSKJALF=""
|
|
34
|
+
app_dir odrerir HALL_DIR || HALL_DIR=""
|
|
34
35
|
|
|
35
36
|
# Where the smithy's parts live: apps/smidja-factory in a clone, or the
|
|
36
37
|
# @zerwiz/smidja-factory package in an npm install (bin/smidja-lib.sh).
|
|
@@ -97,7 +98,21 @@ fi
|
|
|
97
98
|
if [[ ! -d "$APP/node_modules" ]]; then
|
|
98
99
|
style_patience "the seat's own dependencies are being fetched, then the hall is raised"
|
|
99
100
|
echo "Installing dependencies…"
|
|
100
|
-
(
|
|
101
|
+
(# Sessrúmnir — the seat-hall. Its own Electron app (not a browser surface), so it
|
|
102
|
+
# rises here rather than with the SPA: four surfaces, one raise.
|
|
103
|
+
if [ -x "$ROOT/bin/sessrumnir.sh" ]; then
|
|
104
|
+
if app_dir sessrumnir APP_SESSRUMNIR; then
|
|
105
|
+
if "$ROOT/bin/sessrumnir.sh" start >/dev/null 2>&1; then
|
|
106
|
+
echo "Sessrúmnir — the seat-hall raised → (its own window)"
|
|
107
|
+
else
|
|
108
|
+
echo "Sessrúmnir — the seat-hall did not rise (run: bin/sessrumnir.sh start)" >&2
|
|
109
|
+
fi
|
|
110
|
+
else
|
|
111
|
+
echo "Sessrúmnir — skipped (the sessrumnir surface is not present)" >&2
|
|
112
|
+
fi
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
cd "$APP" && npm install --no-audit --no-fund)
|
|
101
116
|
fi
|
|
102
117
|
|
|
103
118
|
# NOTE: when the SPA is already up we still raise the API and the services
|
|
@@ -196,28 +211,59 @@ fi
|
|
|
196
211
|
|
|
197
212
|
# Óðrerir — the Live Hall. Its own Astro board on :4322, the carved planning
|
|
198
213
|
# glass every hall door opens. Raised before the SPA so a window never waits.
|
|
199
|
-
HALL_DIR="
|
|
214
|
+
app_dir odrerir HALL_DIR || HALL_DIR=""
|
|
200
215
|
HALL_PORT="${ODRERIR_PORT:-4322}"
|
|
201
216
|
HALL_PID_FILE="$RUN/odrerir.pid"
|
|
202
217
|
HALL_LOG="$RUN/odrerir.log"
|
|
203
|
-
if [ -d "$HALL_DIR" ]; then
|
|
204
|
-
|
|
218
|
+
if [ -d "$HALL_DIR" ] && [ -n "$HALL_DIR" ]; then
|
|
219
|
+
# Its dependencies are not optional and their absence is not silent: an Astro
|
|
220
|
+
# dev server without them dies with MODULE_NOT_FOUND while the raise claims it
|
|
221
|
+
# was "raised" — the failure the truth-telling above exists to prevent.
|
|
222
|
+
if [ ! -d "$HALL_DIR/node_modules" ]; then
|
|
223
|
+
echo "Óðrerir — fetching its dependencies…"
|
|
224
|
+
if ! (cd "$HALL_DIR" && npm install --no-audit --no-fund >/dev/null 2>&1); then
|
|
225
|
+
echo "Óðrerir — Live Hall NOT raised: its dependencies could not be installed" >&2
|
|
226
|
+
echo "help: (cd ${HALL_DIR#"$ROOT"/} && npm install)" >&2
|
|
227
|
+
HALL_DIR=""
|
|
228
|
+
fi
|
|
229
|
+
fi
|
|
230
|
+
fi
|
|
231
|
+
if [ -n "$HALL_DIR" ] && [ -d "$HALL_DIR" ]; then
|
|
205
232
|
if [ -f "$HALL_PID_FILE" ] && kill -0 "$(cat "$HALL_PID_FILE")" 2>/dev/null; then
|
|
206
233
|
echo "Óðrerir — Live Hall already running (pid $(cat "$HALL_PID_FILE")) → http://127.0.0.1:${HALL_PORT}/"
|
|
207
234
|
else
|
|
208
|
-
|
|
235
|
+
# A packaged app ships a BUILD (odrerir's tarball carries dist/, and its dev
|
|
236
|
+
# command calls a script the tarball does not carry — so `npm run dev` could
|
|
237
|
+
# never work from a package). Serve the build where there is one; develop
|
|
238
|
+
# where there is not.
|
|
239
|
+
if [ -d "$HALL_DIR/dist" ]; then
|
|
240
|
+
ymir_detach bash -c "cd '$HALL_DIR' && exec npx --no-install astro preview --port '$HALL_PORT' --host" >"$HALL_LOG" 2>&1
|
|
241
|
+
else
|
|
242
|
+
ymir_detach bash -c "cd '$HALL_DIR' && exec npm run dev -- --port '$HALL_PORT' --host" >"$HALL_LOG" 2>&1
|
|
243
|
+
fi
|
|
209
244
|
echo $! > "$HALL_PID_FILE"
|
|
210
|
-
|
|
211
|
-
|
|
245
|
+
_hall_up=0
|
|
246
|
+
for _ in $(seq 1 40); do
|
|
247
|
+
curl -s -o /dev/null "http://127.0.0.1:${HALL_PORT}/" && { _hall_up=1; break; }
|
|
248
|
+
kill -0 "$(cat "$HALL_PID_FILE")" 2>/dev/null || break
|
|
249
|
+
sleep 0.5
|
|
250
|
+
done
|
|
251
|
+
if [ "$_hall_up" = 1 ]; then
|
|
252
|
+
echo "Óðrerir — Live Hall raised (pid $(cat "$HALL_PID_FILE")) → http://127.0.0.1:${HALL_PORT}/"
|
|
253
|
+
else
|
|
254
|
+
echo "Óðrerir — Live Hall started (pid $(cat "$HALL_PID_FILE")) but :${HALL_PORT} did not answer — see $HALL_LOG" >&2
|
|
255
|
+
tail -5 "$HALL_LOG" >&2 2>/dev/null || true
|
|
256
|
+
fi
|
|
212
257
|
fi
|
|
213
258
|
else
|
|
214
|
-
echo "Óðrerir — Live Hall skipped (
|
|
259
|
+
echo "Óðrerir — Live Hall skipped (the odrerir surface is not present)." >&2
|
|
215
260
|
fi
|
|
216
261
|
|
|
217
262
|
cd "$APP"
|
|
218
263
|
|
|
219
264
|
if [[ "${1:-}" == "--foreground" ]]; then
|
|
220
|
-
exec
|
|
265
|
+
if [ -d "$APP/dist" ]; then exec npx --no-install vite preview --port "$PORT" --strictPort --host
|
|
266
|
+
else exec npm run dev -- --port "$PORT" --strictPort --host; fi
|
|
221
267
|
fi
|
|
222
268
|
|
|
223
269
|
# The SPA is already serving — nothing more for us to raise here.
|
|
@@ -227,11 +273,18 @@ if [[ "$SPA_UP" == "1" ]]; then
|
|
|
227
273
|
fi
|
|
228
274
|
|
|
229
275
|
# New session so we can signal the whole process group on stop.
|
|
230
|
-
|
|
276
|
+
# The port is OUR decision, not Vite's: a bare `npm run dev` takes 5173 and the
|
|
277
|
+
# hall never answers on the port every other door expects. A packaged install
|
|
278
|
+
# ships ./dist, so it is served; a clone gets the dev server — both on $PORT.
|
|
279
|
+
if [ -d "$APP/dist" ]; then
|
|
280
|
+
ymir_detach bash -c "cd '$APP' && exec npx --no-install vite preview --port '$PORT' --strictPort --host" >"$LOG" 2>&1
|
|
281
|
+
else
|
|
282
|
+
ymir_detach bash -c "cd '$APP' && exec npm run dev -- --port '$PORT' --strictPort --host" >"$LOG" 2>&1
|
|
283
|
+
fi
|
|
231
284
|
PID=$!
|
|
232
285
|
echo "$PID" > "$PID_FILE"
|
|
233
286
|
|
|
234
|
-
# Wait for the port to answer (max ~15s).
|
|
287
|
+
# Wait for the port to answer (max ~15s), then say what is true.
|
|
235
288
|
for _ in $(seq 1 30); do
|
|
236
289
|
if curl -s -o /dev/null "http://127.0.0.1:${PORT}/"; then
|
|
237
290
|
echo "Hlidskjalf raised (pid $PID) → http://127.0.0.1:${PORT}/"
|
|
@@ -241,5 +294,6 @@ for _ in $(seq 1 30); do
|
|
|
241
294
|
sleep 0.5
|
|
242
295
|
done
|
|
243
296
|
|
|
244
|
-
echo "Hlidskjalf started (pid $PID) but
|
|
297
|
+
echo "Hlidskjalf started (pid $PID) but :${PORT} did not answer — see $LOG" >&2
|
|
298
|
+
tail -5 "$LOG" >&2 2>/dev/null || true
|
|
245
299
|
exit 1
|