@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.
Files changed (44) hide show
  1. package/.agents/skills/galdr-ymirsystem/assets/installation.md +122 -0
  2. package/.agents/skills/groa-update/SKILL.md +9 -0
  3. package/.agents/skills/ymir-host/assets/install.md +29 -0
  4. package/CHANGELOG.md +119 -0
  5. package/README.md +54 -0
  6. package/bin/design-icon.sh +18 -3
  7. package/bin/desktop-place.sh +20 -5
  8. package/bin/ymir-config.sh +76 -0
  9. package/bin/ymir-install.sh +16 -3
  10. package/bin/ymir-style.sh +24 -0
  11. package/bin/ymir.js +35 -0
  12. package/midgard/README.md +16 -0
  13. package/midgard/design-system/.gitkeep +0 -0
  14. package/midgard/design-system/ember.d.ts +13 -0
  15. package/midgard/design-system/ember.js +183 -0
  16. package/midgard/design-system/icons/algiz.svg +4 -0
  17. package/midgard/design-system/icons/ansuz.svg +4 -0
  18. package/midgard/design-system/icons/berkana.svg +4 -0
  19. package/midgard/design-system/icons/dagaz.svg +4 -0
  20. package/midgard/design-system/icons/ehwaz.svg +4 -0
  21. package/midgard/design-system/icons/fehu.svg +4 -0
  22. package/midgard/design-system/icons/gjallarhorn.svg +4 -0
  23. package/midgard/design-system/icons/gungnir.svg +4 -0
  24. package/midgard/design-system/icons/heimdall.svg +4 -0
  25. package/midgard/design-system/icons/ingwaz.svg +4 -0
  26. package/midgard/design-system/icons/jera.svg +4 -0
  27. package/midgard/design-system/icons/kaunan.svg +4 -0
  28. package/midgard/design-system/icons/midgard.svg +4 -0
  29. package/midgard/design-system/icons/mimirsbrunn.svg +4 -0
  30. package/midgard/design-system/icons/othala.svg +4 -0
  31. package/midgard/design-system/icons/raidho.svg +4 -0
  32. package/midgard/design-system/icons/ratatoskr.svg +4 -0
  33. package/midgard/design-system/icons/sowilo.svg +4 -0
  34. package/midgard/design-system/icons/tiwaz.svg +4 -0
  35. package/midgard/design-system/icons/utgard.svg +4 -0
  36. package/midgard/design-system/icons/valhalla.svg +4 -0
  37. package/midgard/design-system/icons/yggdrasil.svg +4 -0
  38. package/midgard/design-system/icons.md +59 -0
  39. package/midgard/design-system/runes.md +78 -0
  40. package/midgard/design-system/tokens.css +109 -0
  41. package/midgard/design-system/ymir-mark.svg +62 -0
  42. package/package.json +2 -1
  43. package/scripts/electron.sh +18 -2
  44. 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.9",
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",
@@ -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
- printf 'error: the Electron binary is missing (the package installed but its postinstall was blocked)\nhelp: cd apps/hlidskjalf && node node_modules/electron/install.js\nhelp: if npm blocks install scripts, run: npm install --foreground-scripts\n' >&2
189
- exit 1
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
- (cd "$APP" && npm install --no-audit --no-fund)
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="$ROOT/apps/odrerir"
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
- [ -d "$HALL_DIR/node_modules" ] || (cd "$HALL_DIR" && npm install --no-audit --no-fund >/dev/null 2>&1 || true)
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
- ymir_detach bash -c "cd '$HALL_DIR' && exec npm run dev -- --port '$HALL_PORT' --host" >"$HALL_LOG" 2>&1
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
- for _ in $(seq 1 30); do curl -s -o /dev/null "http://127.0.0.1:${HALL_PORT}/" && break; sleep 0.5; done
211
- echo "Óðrerir Live Hall raised (pid $(cat "$HALL_PID_FILE")) → http://127.0.0.1:${HALL_PORT}/"
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 (missing apps/odrerir)." >&2
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 npm run dev
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
- ymir_detach npm run dev >"$LOG" 2>&1
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 the port did not answer yet check $LOG" >&2
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