@zerwiz/ymir 0.1.7 → 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/skills/galdr-ymirsystem/assets/installation.md +74 -0
- package/CHANGELOG.md +330 -1
- package/bin/design-icon.sh +7 -4
- package/bin/einherjar-spawn.sh +9 -3
- package/bin/eir-doctor.sh +43 -1
- package/bin/electron-lib.sh +34 -0
- package/bin/smidja-board.sh +136 -0
- package/bin/smidja-lib.sh +49 -0
- package/bin/ymir-install.sh +41 -6
- package/bin/ymir-plan.sh +48 -14
- package/bin/ymir-style.sh +108 -0
- package/bin/ymir-validate.sh +36 -3
- package/bin/ymir.js +82 -34
- package/docs/design.md +2 -2
- package/package.json +1 -1
- package/scripts/start.sh +13 -1
package/bin/ymir.js
CHANGED
|
@@ -1,19 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* ymir — the CLI the npm package publishes.
|
|
3
|
+
* ymir — the CLI the npm package publishes, and the operator's front door.
|
|
4
4
|
*
|
|
5
5
|
* It is a thin, honest wrapper: the real work lives in the shell scripts under
|
|
6
|
-
* bin
|
|
7
|
-
* npm needs a Node entry point (`bin: ymir`) and because
|
|
8
|
-
*
|
|
6
|
+
* bin/ and scripts/ — the same scripts a git clone runs. This file exists
|
|
7
|
+
* because npm needs a Node entry point (`bin: ymir`) and because an operator
|
|
8
|
+
* should never have to know where the package landed.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* ymir
|
|
10
|
+
* The doors are named for the figure whose work they do (the naming law):
|
|
11
|
+
* Eir heals, Gróa renews, Heimdall keeps the way in, Smíðja is the smithy and
|
|
12
|
+
* its board, Hlidskjalf the high seat, Sessrúmnir the seat-hall, Mímir the well.
|
|
13
|
+
*
|
|
14
|
+
* ymir first setup (the same as `ymir install`)
|
|
15
|
+
* ymir install [...] first setup, idempotent and self-healing
|
|
16
|
+
* ymir raise / lower lift the hall, or lay it down
|
|
17
|
+
* ymir eir what stands, and mend what does not
|
|
18
|
+
* ymir groa take the latest, and mend this home forward
|
|
19
|
+
* ymir heimdall the way in: your credential, and invites
|
|
20
|
+
* ymir smidja the smithy's board (:8437) — build · start · stop · status
|
|
21
|
+
* ymir hlidskjalf the high seat's window
|
|
22
|
+
* ymir sessrumnir the seat-hall's window
|
|
23
|
+
* ymir mimir the memory well
|
|
24
|
+
* ymir sense what THIS machine is
|
|
15
25
|
* ymir --version
|
|
16
26
|
*
|
|
27
|
+
* Colour appears only where a human is watching (a TTY, no NO_COLOR); the data
|
|
28
|
+
* on stdout is always plain TOON.
|
|
29
|
+
*
|
|
17
30
|
* Exit codes follow the scripts: 0 ok, 1 error, 2 usage.
|
|
18
31
|
*/
|
|
19
32
|
'use strict';
|
|
@@ -27,32 +40,65 @@ const pkg = (() => {
|
|
|
27
40
|
try { return require(path.join(ROOT, 'package.json')); } catch { return { version: '0.0.0' }; }
|
|
28
41
|
})();
|
|
29
42
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
// ── the cloth (the same palette as bin/ymir-style.sh, cut from the tokens) ───
|
|
44
|
+
const colour = process.stderr.isTTY && !process.env.NO_COLOR && process.env.TERM !== 'dumb';
|
|
45
|
+
const wrap = (code) => (s) => (colour ? `\u001b[${code}m${s}\u001b[0m` : `${s}`);
|
|
46
|
+
const bone = wrap('38;2;207;195;169');
|
|
47
|
+
const bronze = wrap('38;2;201;151;79');
|
|
48
|
+
const faint = wrap('38;2;107;98;80');
|
|
49
|
+
const blood = wrap('38;2;194;88;74');
|
|
50
|
+
const bold = wrap('1');
|
|
51
|
+
|
|
52
|
+
// ── the doors ────────────────────────────────────────────────────────────────
|
|
53
|
+
// verb → { script, args } — args are prepended to whatever the operator passes,
|
|
54
|
+
// so a verb can be a doorway to a sub-verb of a script that has several.
|
|
55
|
+
const DOORS = {
|
|
56
|
+
install: { script: 'bin/ymir-install.sh', about: 'first setup (idempotent, self-healing)' },
|
|
57
|
+
raise: { script: 'scripts/start.sh', about: 'lift the hall — SPA, gate API, Nornir, bridges, the board' },
|
|
58
|
+
lower: { script: 'scripts/stop.sh', about: 'lay the hall down' },
|
|
59
|
+
eir: { script: 'bin/eir-doctor.sh', about: 'diagnose every surface; mend what is broken' },
|
|
60
|
+
groa: { script: 'bin/groa-update.sh', about: 'take the latest, then mend this home forward' },
|
|
61
|
+
heimdall: { script: 'bin/ymir-setup-auth.sh', about: 'the way in — your credential (status · set · github)' },
|
|
62
|
+
invite: { script: 'bin/ymir-invite.sh', about: 'let someone else in (mint · list · revoke)' },
|
|
63
|
+
smidja: { script: 'bin/smidja-board.sh', about: "the smithy's board on :8437 (build · start · stop · status)" },
|
|
64
|
+
hlidskjalf: { script: 'scripts/electron.sh', about: "the high seat's window", args: ['start', '--view', 'hlidskjalf'] },
|
|
65
|
+
sessrumnir: { script: 'scripts/electron.sh', about: "the seat-hall's window", args: ['start', '--view', 'sessrumnir'] },
|
|
66
|
+
mimir: { script: 'bin/mimir.sh', about: 'the memory well' },
|
|
67
|
+
sense: { script: 'bin/host-sense.sh', about: 'what THIS machine is' },
|
|
68
|
+
plan: { script: 'bin/ymir-plan.sh', about: 'what an install would do here — writes nothing' },
|
|
69
|
+
migrate: { script: 'bin/ymir-migrate.sh', about: "heal this home's structure forward (Gr\u00f3a's mend)" },
|
|
70
|
+
validate: { script: 'bin/ymir-validate.sh', about: 'alias of `ymir eir`' },
|
|
35
71
|
};
|
|
36
72
|
|
|
73
|
+
// Names the law has not given a home are kept for a while, so a muscle memory
|
|
74
|
+
// built yesterday still works — and says what to type instead.
|
|
75
|
+
const RENAMED = { validate: 'eir', auth: 'heimdall', desktop: 'hlidskjalf', doctor: 'eir', update: 'groa' };
|
|
76
|
+
|
|
37
77
|
function usage() {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
);
|
|
78
|
+
const lines = [];
|
|
79
|
+
lines.push('');
|
|
80
|
+
lines.push(` ${bronze('\u16c9')} ${bold('Ymir')} ${faint(pkg.version)}`);
|
|
81
|
+
lines.push(` ${faint('the single-tenant agent operating system')}`);
|
|
82
|
+
lines.push('');
|
|
83
|
+
lines.push(bold(' The doors'));
|
|
84
|
+
for (const [verb, d] of Object.entries(DOORS)) {
|
|
85
|
+
lines.push(` ${bronze(verb.padEnd(11))} ${faint(d.about)}`);
|
|
86
|
+
}
|
|
87
|
+
lines.push('');
|
|
88
|
+
lines.push(bold(' Composed by hand'));
|
|
89
|
+
lines.push(` ${bronze('ymir groa migrate'.padEnd(11))} ${faint("heal this home's structure (run by groa / install)")}`);
|
|
90
|
+
lines.push(` ${bronze('ymir heimdall set'.padEnd(11))} ${faint('set the operator password (or `github`)')}`);
|
|
91
|
+
lines.push('');
|
|
92
|
+
lines.push(faint(' A bare `ymir` runs the first setup. Output is TOON; colour only on a TTY.'));
|
|
93
|
+
lines.push('');
|
|
94
|
+
process.stdout.write(lines.join('\n') + '\n');
|
|
49
95
|
}
|
|
50
96
|
|
|
51
97
|
function run(script, args) {
|
|
52
|
-
const file = path.join(ROOT,
|
|
98
|
+
const file = path.join(ROOT, script);
|
|
53
99
|
if (!fs.existsSync(file)) {
|
|
54
|
-
process.stderr.write(
|
|
55
|
-
process.stderr.write('help: reinstall — npm i -g @zerwiz/ymir, or git clone the distro\n
|
|
100
|
+
process.stderr.write(`${blood('error:')} ${script} is missing from this install\n`);
|
|
101
|
+
process.stderr.write(`${faint('help: reinstall — npm i -g @zerwiz/ymir, or git clone the distro')}\n`);
|
|
56
102
|
process.exit(1);
|
|
57
103
|
}
|
|
58
104
|
const r = spawnSync('bash', [file, ...args], { stdio: 'inherit' });
|
|
@@ -62,17 +108,19 @@ function run(script, args) {
|
|
|
62
108
|
const argv = process.argv.slice(2);
|
|
63
109
|
const first = argv[0];
|
|
64
110
|
|
|
65
|
-
if (!first) run(
|
|
111
|
+
if (!first) run(DOORS.install.script, []);
|
|
66
112
|
if (first === '--version' || first === '-v' || first === '-V') {
|
|
67
113
|
process.stdout.write(`${pkg.version}\n`);
|
|
68
114
|
process.exit(0);
|
|
69
115
|
}
|
|
70
116
|
if (first === '--help' || first === '-h' || first === 'help') { usage(); process.exit(0); }
|
|
71
117
|
|
|
72
|
-
|
|
73
|
-
if (!
|
|
74
|
-
|
|
75
|
-
process.stderr.write('
|
|
118
|
+
let door = DOORS[first];
|
|
119
|
+
if (!door) {
|
|
120
|
+
const replacement = RENAMED[first];
|
|
121
|
+
process.stderr.write(`${blood('error:')} unknown door ${bold(first)}\n`);
|
|
122
|
+
if (replacement) process.stderr.write(`${faint(`help: the door is named \`ymir ${replacement}\` now (the naming law — a figure does the work)`)}\n`);
|
|
123
|
+
process.stderr.write(`${faint('help: `ymir --help` lists every door')}\n`);
|
|
76
124
|
process.exit(2);
|
|
77
125
|
}
|
|
78
|
-
run(script, argv.slice(1));
|
|
126
|
+
run(door.script, [...(door.args || []), ...argv.slice(1)]);
|
package/docs/design.md
CHANGED
|
@@ -226,7 +226,7 @@ everywhere; never put bronze text on bronze.
|
|
|
226
226
|
- **Runecoded, not emoji.** A minimal, hand-drawn-style rune set replaces emoji
|
|
227
227
|
in all UI: 16×16 and 24×24 grid, 2px stroke, chisel bevel on primary.
|
|
228
228
|
- System subsystems each carry one rune-glyph (reuse Algiz-family geometry:
|
|
229
|
-
Bifrost gate, Ratatoskr squirrel, the Well). Map is in `midgard/design-system/icons.md`
|
|
229
|
+
Bifrost gate, Ratatoskr squirrel, the Well). Map is in `midgard/design-system/icons.md` and the library in `midgard/design-system/runes.md`.
|
|
230
230
|
- Status dot: filled rune ring (ok) / half-ring (warn) / broken ring (danger), never color-only.
|
|
231
231
|
|
|
232
232
|
### 4.5 Surface & texture
|
|
@@ -345,7 +345,7 @@ All components read tokens from `tokens.css`; color-only states are forbidden
|
|
|
345
345
|
|
|
346
346
|
- `docs/design.md` — this document (master).
|
|
347
347
|
- `midgard/design-system/tokens.css` — the consumable design tokens.
|
|
348
|
-
- `midgard/design-system/icons.md` — rune-glyph map (
|
|
348
|
+
- `midgard/design-system/icons.md` — rune-glyph map (21 glyphs, drawn in `icons/*.svg`).
|
|
349
349
|
- `docs/ymir-rut.md` Part 3 — the original Rut design-system specification this
|
|
350
350
|
document implements.
|
|
351
351
|
- `docs/lore.md` §VI — house lineage behind the house accents.
|
package/package.json
CHANGED
package/scripts/start.sh
CHANGED
|
@@ -17,6 +17,18 @@ if [ -z "${YMIR_PLATFORM_LOADED:-}" ]; then
|
|
|
17
17
|
fi
|
|
18
18
|
|
|
19
19
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
20
|
+
# Where the smithy's parts live: apps/smidja-factory in a clone, or the
|
|
21
|
+
# @zerwiz/smidja-factory package in an npm install (bin/smidja-lib.sh).
|
|
22
|
+
if [ -z "${YMIR_SMIDJA_LIB_LOADED:-}" ]; then
|
|
23
|
+
_ys="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
24
|
+
for _yc in "$_ys/smidja-lib.sh" "$(dirname "$_ys")/bin/smidja-lib.sh"; do
|
|
25
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_SMIDJA_LIB_LOADED=1; break; }
|
|
26
|
+
done
|
|
27
|
+
unset _ys _yc
|
|
28
|
+
fi
|
|
29
|
+
smidja_visualizer_dir SMIDJA_VIZ
|
|
30
|
+
smidja_factory_dir SMIDJA_FACTORY
|
|
31
|
+
|
|
20
32
|
|
|
21
33
|
# The operator's settings and secrets live in the home they chose, never in the
|
|
22
34
|
# code tree — a packaged install replaces its tree on upgrade, and a credential
|
|
@@ -116,7 +128,7 @@ fi
|
|
|
116
128
|
# Smíðja's eye — the Vue trace visualizer (API :8437, UI :8438). Reads the repo's
|
|
117
129
|
# own smidja.db and exposes the Sessions/Trace/Decisions/Stats views behind the
|
|
118
130
|
# Hlidskjalf Sessions gate's "Open visualizer" button.
|
|
119
|
-
VIZ_DIR="$
|
|
131
|
+
VIZ_DIR="${SMIDJA_VIZ:-}"
|
|
120
132
|
VIZ_API_PORT="${SMIDJA_VIZ_API_PORT:-8437}"
|
|
121
133
|
VIZ_UI_PORT="${SMIDJA_VIZ_UI_PORT:-8438}"
|
|
122
134
|
VIZ_API_PID_FILE="$RUN/smidja-viz-api.pid"
|