@glassmkr/crucible 0.8.1 → 0.9.1

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/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
4
4
  [![npm version](https://img.shields.io/npm/v/@glassmkr/crucible.svg)](https://www.npmjs.com/package/@glassmkr/crucible)
5
5
 
6
+ <!-- Canonical rule count: see RULES_COUNT.md in the Glassmkr monorepo. -->
6
7
  Lightweight bare metal server monitoring agent. Collects hardware and OS health every 5 minutes and pushes snapshots to a [Forge](https://forge.glassmkr.com) dashboard, which evaluates 38 alert rules and sends notifications.
7
8
 
8
9
  Open source. MIT licensed. Built by [Glassmkr](https://glassmkr.com). See also [Bench](https://github.com/glassmkr/bench), the MCP server collection.
@@ -24,16 +25,27 @@ Open source. MIT licensed. Built by [Glassmkr](https://glassmkr.com). See also [
24
25
 
25
26
  ## Install
26
27
 
28
+ The fastest path: bootstrap script. Detects Node and npm, installs the
29
+ agent, and runs `glassmkr-crucible init` to validate your key, write
30
+ `/etc/glassmkr/collector.yaml`, write the systemd unit, and start the
31
+ service.
32
+
27
33
  ```bash
28
- npm install -g @glassmkr/crucible
34
+ curl -sf https://forge.glassmkr.com/install | bash -s -- --api-key gmk_cru_live_<your-key>
29
35
  ```
30
36
 
31
- Or use the bootstrap script:
37
+ Or run the steps yourself:
32
38
 
33
39
  ```bash
34
- curl -sf https://forge.glassmkr.com/install | bash
40
+ sudo npm install -g @glassmkr/crucible
41
+ sudo glassmkr-crucible init --api-key gmk_cru_live_<your-key>
35
42
  ```
36
43
 
44
+ `init` is the canonical first-run path. It validates the key shape,
45
+ optionally probes the ingest endpoint, writes config + systemd unit
46
+ with the right binary path for your distro, and enables the service.
47
+ Run `glassmkr-crucible init --help` for the full flag list.
48
+
37
49
  ## Docker
38
50
 
39
51
  ```bash
@@ -65,33 +77,31 @@ Images are published to [ghcr.io/glassmkr/crucible](https://github.com/glassmkr/
65
77
 
66
78
  ## Quick Start
67
79
 
68
- 1. Create an API key in the Forge dashboard (Servers, then Add server).
69
- 2. Drop a config at `/etc/glassmkr/collector.yaml`:
70
-
71
- ```yaml
72
- server_name: "web-01"
73
- collection:
74
- interval_seconds: 300
75
- ipmi: true
76
- smart: true
77
- forge:
78
- enabled: true
79
- url: "https://forge.glassmkr.com"
80
- api_key: "col_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
81
- ```
82
-
83
- 3. Run as a systemd service (recommended) or directly:
80
+ 1. Create an API key in the Forge dashboard (Servers Add server).
81
+ 2. Run `init`:
84
82
 
85
83
  ```bash
86
- sudo glassmkr-crucible
84
+ sudo glassmkr-crucible init --api-key gmk_cru_live_<your-key>
87
85
  ```
88
86
 
89
- Snapshots appear in the Forge dashboard within seconds of the first push.
87
+ This writes `/etc/glassmkr/collector.yaml`, writes the systemd unit,
88
+ and starts the service. Pass `--name` to override the dashboard
89
+ server name (defaults to the host's hostname). Pass `--no-start` if
90
+ you want to inspect the unit before enabling it. Pass `--api-key -`
91
+ to read the key from stdin (handy for password-manager pipes).
92
+
93
+ Snapshots appear in the Forge dashboard within seconds of the first
94
+ push.
95
+
96
+ If you can't or won't run `init` (config-management is doing it for
97
+ you, or you're customising the systemd unit), the manual flow is in
98
+ the **Manual install** section below.
90
99
 
91
100
  ## CLI Reference
92
101
 
93
102
  ```
94
103
  glassmkr-crucible [options]
104
+ glassmkr-crucible init --api-key <K> [--name <N>] [--ingest-url <U>] [--no-start] [--force] [--no-verify]
95
105
  glassmkr-crucible mark-reboot [--reason TEXT] [--ttl DURATION]
96
106
  glassmkr-crucible reboot [--reason TEXT] [--ttl DURATION]
97
107
 
@@ -103,6 +113,39 @@ Options:
103
113
 
104
114
  `--config=PATH` and the legacy positional form `glassmkr-crucible /path/to.yaml` both work. Without options, Crucible runs as a long-lived collector daemon.
105
115
 
116
+ ## Configuration
117
+
118
+ `init` writes `/etc/glassmkr/collector.yaml`. The schema:
119
+
120
+ ```yaml
121
+ server_name: "web-01"
122
+ collection:
123
+ interval_seconds: 300
124
+ ipmi: true
125
+ smart: true
126
+ forge:
127
+ enabled: true
128
+ url: "https://forge.glassmkr.com"
129
+ api_key: "gmk_cru_live_<...>_<4>"
130
+ ```
131
+
132
+ Hand-edit any time. The agent re-reads on restart. Run
133
+ `glassmkr-crucible init --help` for the full flag list.
134
+
135
+ ### Migrating from a manual install
136
+
137
+ Existing 0.9.0 installs with a hand-written `collector.yaml` and
138
+ systemd unit continue working unchanged on 0.9.1. No migration is
139
+ required.
140
+
141
+ For new boxes, prefer `init`. To migrate an existing manual install
142
+ to the canonical layout, stop the service, run `init --force`, restart:
143
+
144
+ ```bash
145
+ sudo systemctl stop glassmkr-crucible
146
+ sudo glassmkr-crucible init --api-key <K> --force
147
+ ```
148
+
106
149
  ## Rebooting without noise
107
150
 
108
151
  Crucible distinguishes planned reboots from unplanned ones and gives each rule a short grace period after boot so that transient conditions (bond slave still negotiating, clock not synced yet) do not page you.
@@ -126,11 +169,27 @@ The marker is single-use and expires 10 minutes after it is written (override wi
126
169
 
127
170
  Per-rule grace windows are applied separately: bond-slave-down and CPU-temperature get 60 s, interface errors 120 s, clock-sync / NTP 300 s, others 0 s. Suppressed evaluations are recorded in alert history with status `suppressed_boot_grace` or `suppressed_planned_reboot` so you can audit exactly why a rule didn't fire during a given boot.
128
171
 
129
- ## Systemd Service
172
+ ## Manual install
173
+
174
+ The canonical install path is `glassmkr-crucible init` (see "Install"
175
+ above). For ops engineers writing config-management modules, `init`
176
+ gives you a stable interface that's covered by the test suite; prefer
177
+ it over hand-rolling the equivalent.
130
178
 
131
- Create `/etc/systemd/system/glassmkr-crucible.service`:
179
+ If you need or want to do this by hand, the npm prefix differs across
180
+ distros: Ubuntu's global npm puts binaries in `/usr/bin/`, while
181
+ Debian's defaults to `/usr/local/bin/`. The systemd unit's
182
+ `ExecStart` must point at wherever `glassmkr-crucible` actually landed
183
+ on your host, so detect the path before writing the unit:
132
184
 
133
- ```ini
185
+ ```bash
186
+ BIN_PATH=$(command -v glassmkr-crucible)
187
+ if [ -z "$BIN_PATH" ]; then
188
+ echo "ERROR: glassmkr-crucible binary not found on PATH after npm install. Aborting." >&2
189
+ exit 1
190
+ fi
191
+
192
+ sudo tee /etc/systemd/system/glassmkr-crucible.service >/dev/null <<UNIT
134
193
  [Unit]
135
194
  Description=Glassmkr Crucible - Bare Metal Monitoring
136
195
  After=network.target
@@ -138,12 +197,13 @@ After=network.target
138
197
  [Service]
139
198
  Type=simple
140
199
  User=root
141
- ExecStart=/usr/bin/glassmkr-crucible /etc/glassmkr/collector.yaml
200
+ ExecStart=$BIN_PATH /etc/glassmkr/collector.yaml
142
201
  Restart=on-failure
143
202
  RestartSec=10
144
203
 
145
204
  [Install]
146
205
  WantedBy=multi-user.target
206
+ UNIT
147
207
  ```
148
208
 
149
209
  Enable and start:
@@ -154,6 +214,11 @@ sudo systemctl enable --now glassmkr-crucible
154
214
  sudo systemctl status glassmkr-crucible
155
215
  ```
156
216
 
217
+ If you ever upgrade `@glassmkr/crucible` and the binary moves (rare, but
218
+ possible on a distro change), re-run the `command -v` step and update the
219
+ unit file. The bootstrap script at `https://forge.glassmkr.com/install` does
220
+ this detection automatically; the manual flow above is just the equivalent.
221
+
157
222
  ## What It Collects
158
223
 
159
224
  | Module | Data |
@@ -173,6 +238,7 @@ sudo systemctl status glassmkr-crucible
173
238
  | NTP | Sync state and source |
174
239
  | File descriptors | System-wide allocation |
175
240
 
241
+ <!-- Canonical rule count: see RULES_COUNT.md in the Glassmkr monorepo. -->
176
242
  Forge evaluates 38 alert rules server-side across OS, Storage, Network, Hardware, ZFS, Security, and Service Health, with priorities P1 Urgent through P4 Low. Full list: [forge.glassmkr.com/docs/alerts](https://forge.glassmkr.com/docs/alerts).
177
243
 
178
244
  ## Requirements
@@ -186,7 +252,7 @@ Forge evaluates 38 alert rules server-side across OS, Storage, Network, Hardware
186
252
 
187
253
  - [Getting Started](https://forge.glassmkr.com/docs/getting-started)
188
254
  - [Configuration Reference](https://forge.glassmkr.com/docs/configuration)
189
- - [Alert Rules (36)](https://forge.glassmkr.com/docs/alerts)
255
+ - [Alert Rules (38)](https://forge.glassmkr.com/docs/alerts)
190
256
  - [Troubleshooting](https://forge.glassmkr.com/docs/troubleshooting)
191
257
  - [API Reference](https://forge.glassmkr.com/docs/api)
192
258
 
@@ -60,5 +60,47 @@ describe("helpText", () => {
60
60
  expect(txt).toContain("-h, --help");
61
61
  expect(txt).toContain("-c, --config");
62
62
  });
63
+ it("lists init in the subcommands section", () => {
64
+ const txt = helpText("0.9.1");
65
+ expect(txt).toContain("init");
66
+ });
67
+ });
68
+ describe("init subcommand parsing", () => {
69
+ it("init --api-key K -> mode=init with the key captured", () => {
70
+ const { result } = parseCliArgs(["init", "--api-key", "gmk_cru_live_abc"], "0.9.1");
71
+ expect(result.mode).toBe("init");
72
+ expect(result.init?.apiKey).toBe("gmk_cru_live_abc");
73
+ expect(result.init?.noStart).toBe(false);
74
+ expect(result.init?.force).toBe(false);
75
+ });
76
+ it("init --api-key=K equals form works", () => {
77
+ const { result } = parseCliArgs(["init", "--api-key=col_xyz"], "0.9.1");
78
+ expect(result.init?.apiKey).toBe("col_xyz");
79
+ });
80
+ it("init --api-key - (stdin marker) is preserved as the literal -", () => {
81
+ const { result } = parseCliArgs(["init", "--api-key", "-"], "0.9.1");
82
+ expect(result.init?.apiKey).toBe("-");
83
+ });
84
+ it("init --no-start --force --no-verify flags toggle correctly", () => {
85
+ const { result } = parseCliArgs(["init", "--api-key", "k", "--no-start", "--force", "--no-verify"], "0.9.1");
86
+ expect(result.init?.noStart).toBe(true);
87
+ expect(result.init?.force).toBe(true);
88
+ expect(result.init?.noVerify).toBe(true);
89
+ });
90
+ it("init --name and --ingest-url and --config-path are captured", () => {
91
+ const { result } = parseCliArgs([
92
+ "init", "--api-key", "k", "--name", "web-01", "--ingest-url", "https://forge.example.com/api/v1/ingest", "--config-path", "/etc/x.yaml",
93
+ ], "0.9.1");
94
+ expect(result.init?.name).toBe("web-01");
95
+ expect(result.init?.ingestUrl).toBe("https://forge.example.com/api/v1/ingest");
96
+ expect(result.init?.configPath).toBe("/etc/x.yaml");
97
+ });
98
+ it("init --help returns help text instead of running init", () => {
99
+ const { result, output } = parseCliArgs(["init", "--help"], "0.9.1");
100
+ expect(result.mode).toBe("help");
101
+ expect(output).toContain("glassmkr-crucible init");
102
+ expect(output).toContain("--api-key");
103
+ expect(output).toContain("--no-start");
104
+ });
63
105
  });
64
106
  //# sourceMappingURL=cli.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli.test.js","sourceRoot":"","sources":["../../src/__tests__/cli.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.test.js","sourceRoot":"","sources":["../../src/__tests__/cli.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,187 @@
1
+ import { describe, it, expect, beforeEach } from "vitest";
2
+ import { runInit, isValidApiKey, buildCollectorYaml, buildSystemdUnit, SYSTEMD_UNIT_PATH } from "../init.js";
3
+ const VALID_NEW_KEY = "gmk_cru_live_abcdefghijklmnopqrstuvwx_a1b2";
4
+ const VALID_LEGACY_KEY = "col_abcdef0123456789abcdef0123456789ab";
5
+ function makeDeps(opts) {
6
+ const fs = { files: new Map(), dirs: new Set() };
7
+ for (const f of opts?.preExistingFiles ?? [])
8
+ fs.files.set(f, { data: "stale", mode: 0o600 });
9
+ const logs = [];
10
+ const warns = [];
11
+ const errors = [];
12
+ const systemctlCalls = [];
13
+ const deps = {
14
+ fs: {
15
+ existsSync: (p) => fs.files.has(p),
16
+ mkdirSync: (p) => { fs.dirs.add(p); },
17
+ writeFileSync: (p, data, o) => { fs.files.set(p, { data, mode: o?.mode ?? 0o644 }); },
18
+ chmodSync: (p, mode) => {
19
+ const f = fs.files.get(p);
20
+ if (f)
21
+ f.mode = mode;
22
+ },
23
+ },
24
+ exec: (cmd, args) => {
25
+ if (cmd === "command" && args[0] === "-v" && args[1] === "glassmkr-crucible") {
26
+ return { stdout: opts?.binPath === null ? "" : `${opts?.binPath ?? "/usr/local/bin/glassmkr-crucible"}\n`, status: 0 };
27
+ }
28
+ if (cmd === "which" && args[0] === "glassmkr-crucible") {
29
+ return { stdout: opts?.binPath === null ? "" : `${opts?.binPath ?? "/usr/local/bin/glassmkr-crucible"}\n`, status: 0 };
30
+ }
31
+ if (cmd === "systemctl") {
32
+ systemctlCalls.push(args);
33
+ return { stdout: "", status: opts?.systemctlExitCode ?? 0 };
34
+ }
35
+ return { stdout: "", status: 0 };
36
+ },
37
+ hostname: () => "test-host-01",
38
+ log: (m) => logs.push(m),
39
+ warn: (m) => warns.push(m),
40
+ error: (m) => errors.push(m),
41
+ fetch: async () => {
42
+ if (opts?.fetchThrows)
43
+ throw new Error("network down");
44
+ return { status: opts?.fetchStatus ?? 200 };
45
+ },
46
+ readStdin: async () => opts?.stdin ?? "",
47
+ };
48
+ return { deps, fs, logs, warns, errors, systemctlCalls };
49
+ }
50
+ describe("isValidApiKey", () => {
51
+ it("accepts the new gmk_cru_live_<...>_<4> format", () => {
52
+ expect(isValidApiKey(VALID_NEW_KEY)).toBe(true);
53
+ });
54
+ it("accepts the legacy col_<hex> format", () => {
55
+ expect(isValidApiKey(VALID_LEGACY_KEY)).toBe(true);
56
+ });
57
+ it("rejects forge_ session tokens", () => {
58
+ expect(isValidApiKey("forge_abc123")).toBe(false);
59
+ });
60
+ it("rejects random strings", () => {
61
+ expect(isValidApiKey("just-some-string")).toBe(false);
62
+ });
63
+ it("rejects empty / whitespace", () => {
64
+ expect(isValidApiKey("")).toBe(false);
65
+ expect(isValidApiKey(" ")).toBe(false);
66
+ expect(isValidApiKey("gmk_cru_live_abc def_1234")).toBe(false);
67
+ });
68
+ });
69
+ describe("buildCollectorYaml", () => {
70
+ it("emits a parseable YAML with name, url, key", () => {
71
+ const y = buildCollectorYaml("web-01", "https://forge.glassmkr.com/api/v1/ingest", VALID_NEW_KEY);
72
+ expect(y).toContain('server_name: "web-01"');
73
+ expect(y).toContain('url: "https://forge.glassmkr.com"');
74
+ expect(y).toContain(`api_key: "${VALID_NEW_KEY}"`);
75
+ });
76
+ it("strips /api/v1/ingest from the URL when present", () => {
77
+ const y = buildCollectorYaml("h", "https://forge.example.com/api/v1/ingest", VALID_NEW_KEY);
78
+ expect(y).toContain('url: "https://forge.example.com"');
79
+ expect(y).not.toContain("/api/v1/ingest");
80
+ });
81
+ it("escapes embedded double quotes in name", () => {
82
+ const y = buildCollectorYaml('we"ird', "https://x", VALID_NEW_KEY);
83
+ expect(y).toContain('server_name: "we\\"ird"');
84
+ });
85
+ });
86
+ describe("buildSystemdUnit", () => {
87
+ it("references the dynamic binary path with the config path", () => {
88
+ const u = buildSystemdUnit("/usr/local/bin/glassmkr-crucible", "/etc/glassmkr/collector.yaml");
89
+ expect(u).toContain("ExecStart=/usr/local/bin/glassmkr-crucible /etc/glassmkr/collector.yaml");
90
+ expect(u).toContain("Type=simple");
91
+ expect(u).toContain("Restart=always");
92
+ });
93
+ });
94
+ describe("runInit", () => {
95
+ let configPath;
96
+ beforeEach(() => { configPath = "/tmp/init-test-collector.yaml"; });
97
+ it("rejects malformed --api-key with exit code 2", async () => {
98
+ const { deps, errors } = makeDeps();
99
+ const code = await runInit({ apiKey: "nope", configPath, noVerify: true }, deps);
100
+ expect(code).toBe(2);
101
+ expect(errors[0]).toContain("invalid --api-key");
102
+ });
103
+ it("happy path: writes config (0600) + systemd unit (0644), enables service", async () => {
104
+ const { deps, fs, systemctlCalls } = makeDeps();
105
+ const code = await runInit({ apiKey: VALID_NEW_KEY, configPath, noVerify: true }, deps);
106
+ expect(code).toBe(0);
107
+ const yaml = fs.files.get(configPath);
108
+ expect(yaml?.mode).toBe(0o600);
109
+ expect(yaml?.data).toContain(VALID_NEW_KEY);
110
+ const unit = fs.files.get(SYSTEMD_UNIT_PATH);
111
+ expect(unit?.mode).toBe(0o644);
112
+ expect(unit?.data).toContain("ExecStart=/usr/local/bin/glassmkr-crucible /tmp/init-test-collector.yaml");
113
+ expect(systemctlCalls).toContainEqual(["daemon-reload"]);
114
+ expect(systemctlCalls).toContainEqual(["enable", "--now", "glassmkr-crucible"]);
115
+ });
116
+ it("--no-start: skips enable but still daemon-reloads", async () => {
117
+ const { deps, systemctlCalls } = makeDeps();
118
+ const code = await runInit({ apiKey: VALID_NEW_KEY, configPath, noVerify: true, noStart: true }, deps);
119
+ expect(code).toBe(0);
120
+ expect(systemctlCalls).toContainEqual(["daemon-reload"]);
121
+ expect(systemctlCalls.find((c) => c[0] === "enable")).toBeUndefined();
122
+ });
123
+ it("refuses to overwrite an existing config without --force", async () => {
124
+ const { deps, errors } = makeDeps({ preExistingFiles: [configPath] });
125
+ const code = await runInit({ apiKey: VALID_NEW_KEY, configPath, noVerify: true }, deps);
126
+ expect(code).toBe(4);
127
+ expect(errors[0]).toContain("config already exists");
128
+ });
129
+ it("--force overwrites an existing config", async () => {
130
+ const { deps, fs } = makeDeps({ preExistingFiles: [configPath] });
131
+ const code = await runInit({ apiKey: VALID_NEW_KEY, configPath, noVerify: true, force: true }, deps);
132
+ expect(code).toBe(0);
133
+ expect(fs.files.get(configPath)?.data).toContain(VALID_NEW_KEY);
134
+ });
135
+ it("reads --api-key from stdin when value is '-'", async () => {
136
+ const { deps, fs } = makeDeps({ stdin: VALID_LEGACY_KEY + "\n" });
137
+ const code = await runInit({ apiKey: "-", configPath, noVerify: true }, deps);
138
+ expect(code).toBe(0);
139
+ expect(fs.files.get(configPath)?.data).toContain(VALID_LEGACY_KEY);
140
+ });
141
+ it("aborts when binary not on PATH (exit code 7)", async () => {
142
+ const { deps, errors } = makeDeps({ binPath: null });
143
+ const code = await runInit({ apiKey: VALID_NEW_KEY, configPath, noVerify: true }, deps);
144
+ expect(code).toBe(7);
145
+ expect(errors[errors.length - 1]).toContain("could not locate the glassmkr-crucible binary");
146
+ });
147
+ it("connectivity probe: 401 from ingest endpoint -> exit code 3", async () => {
148
+ const { deps, errors } = makeDeps({ fetchStatus: 401 });
149
+ const code = await runInit({ apiKey: VALID_NEW_KEY, configPath }, deps);
150
+ expect(code).toBe(3);
151
+ expect(errors[0]).toContain("api key rejected");
152
+ });
153
+ it("connectivity probe: 5xx warns but continues", async () => {
154
+ const { deps, warns } = makeDeps({ fetchStatus: 502 });
155
+ const code = await runInit({ apiKey: VALID_NEW_KEY, configPath }, deps);
156
+ expect(code).toBe(0);
157
+ expect(warns.some((w) => w.includes("502"))).toBe(true);
158
+ });
159
+ it("connectivity probe: network error warns and continues", async () => {
160
+ const { deps, warns } = makeDeps({ fetchThrows: true });
161
+ const code = await runInit({ apiKey: VALID_NEW_KEY, configPath }, deps);
162
+ expect(code).toBe(0);
163
+ expect(warns.some((w) => w.includes("connectivity probe failed"))).toBe(true);
164
+ });
165
+ it("--name overrides hostname", async () => {
166
+ const { deps, fs } = makeDeps();
167
+ await runInit({ apiKey: VALID_NEW_KEY, name: "custom-name", configPath, noVerify: true }, deps);
168
+ expect(fs.files.get(configPath)?.data).toContain('server_name: "custom-name"');
169
+ });
170
+ it("falls back to hostname when --name not provided", async () => {
171
+ const { deps, fs } = makeDeps();
172
+ await runInit({ apiKey: VALID_NEW_KEY, configPath, noVerify: true }, deps);
173
+ expect(fs.files.get(configPath)?.data).toContain('server_name: "test-host-01"');
174
+ });
175
+ it("--ingest-url override is reflected in collector.yaml", async () => {
176
+ const { deps, fs } = makeDeps();
177
+ await runInit({ apiKey: VALID_NEW_KEY, ingestUrl: "https://forge.example.com/api/v1/ingest", configPath, noVerify: true }, deps);
178
+ expect(fs.files.get(configPath)?.data).toContain('url: "https://forge.example.com"');
179
+ });
180
+ it("systemctl enable failure surfaces as exit code 9", async () => {
181
+ const { deps, errors } = makeDeps({ systemctlExitCode: 1 });
182
+ const code = await runInit({ apiKey: VALID_NEW_KEY, configPath, noVerify: true }, deps);
183
+ expect(code).toBe(9);
184
+ expect(errors[errors.length - 1]).toContain("systemctl enable --now");
185
+ });
186
+ });
187
+ //# sourceMappingURL=init.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.test.js","sourceRoot":"","sources":["../../src/__tests__/init.test.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts CHANGED
@@ -1,9 +1,19 @@
1
- export type CliMode = "version" | "help" | "run" | "mark-reboot" | "reboot";
1
+ export type CliMode = "version" | "help" | "run" | "mark-reboot" | "reboot" | "init";
2
2
  export interface CliArgs {
3
3
  mode: CliMode;
4
4
  configPath: string;
5
5
  reason?: string;
6
6
  ttl?: string;
7
+ init?: InitFlags;
8
+ }
9
+ export interface InitFlags {
10
+ apiKey?: string;
11
+ name?: string;
12
+ ingestUrl?: string;
13
+ configPath?: string;
14
+ noStart: boolean;
15
+ force: boolean;
16
+ noVerify: boolean;
7
17
  }
8
18
  export declare const DEFAULT_CONFIG_PATH = "/etc/glassmkr/collector.yaml";
9
19
  export declare function parseCliArgs(argv: string[], version: string): {
@@ -11,3 +21,4 @@ export declare function parseCliArgs(argv: string[], version: string): {
11
21
  output: string | null;
12
22
  };
13
23
  export declare function helpText(version: string): string;
24
+ export declare function initHelp(version: string): string;
package/dist/cli.js CHANGED
@@ -5,6 +5,61 @@ export const DEFAULT_CONFIG_PATH = "/etc/glassmkr/collector.yaml";
5
5
  export function parseCliArgs(argv, version) {
6
6
  // argv is typically process.argv.slice(2)
7
7
  let configPath = DEFAULT_CONFIG_PATH;
8
+ // Subcommand dispatch: `init` takes its own flag set.
9
+ if (argv[0] === "init") {
10
+ const flags = { noStart: false, force: false, noVerify: false };
11
+ for (let i = 1; i < argv.length; i++) {
12
+ const a = argv[i];
13
+ if (a === "--help" || a === "-h") {
14
+ return { result: { mode: "help", configPath: "" }, output: initHelp(version) };
15
+ }
16
+ if (a === "--api-key") {
17
+ flags.apiKey = argv[++i];
18
+ continue;
19
+ }
20
+ if (a.startsWith("--api-key=")) {
21
+ flags.apiKey = a.slice("--api-key=".length);
22
+ continue;
23
+ }
24
+ if (a === "--name") {
25
+ flags.name = argv[++i];
26
+ continue;
27
+ }
28
+ if (a.startsWith("--name=")) {
29
+ flags.name = a.slice("--name=".length);
30
+ continue;
31
+ }
32
+ if (a === "--ingest-url") {
33
+ flags.ingestUrl = argv[++i];
34
+ continue;
35
+ }
36
+ if (a.startsWith("--ingest-url=")) {
37
+ flags.ingestUrl = a.slice("--ingest-url=".length);
38
+ continue;
39
+ }
40
+ if (a === "--config-path") {
41
+ flags.configPath = argv[++i];
42
+ continue;
43
+ }
44
+ if (a.startsWith("--config-path=")) {
45
+ flags.configPath = a.slice("--config-path=".length);
46
+ continue;
47
+ }
48
+ if (a === "--no-start") {
49
+ flags.noStart = true;
50
+ continue;
51
+ }
52
+ if (a === "--force") {
53
+ flags.force = true;
54
+ continue;
55
+ }
56
+ if (a === "--no-verify") {
57
+ flags.noVerify = true;
58
+ continue;
59
+ }
60
+ }
61
+ return { result: { mode: "init", configPath: "", init: flags }, output: null };
62
+ }
8
63
  // Subcommand dispatch: `mark-reboot` and `reboot` take their own flags
9
64
  // (--reason, --ttl) but re-use --help.
10
65
  if (argv[0] === "mark-reboot" || argv[0] === "reboot") {
@@ -70,6 +125,7 @@ export function helpText(version) {
70
125
  "",
71
126
  "Usage:",
72
127
  " glassmkr-crucible [options]",
128
+ " glassmkr-crucible init --api-key <K> [--name <N>] [--ingest-url <U>] [--no-start] [--force]",
73
129
  " glassmkr-crucible mark-reboot [--reason TEXT] [--ttl DURATION]",
74
130
  " glassmkr-crucible reboot [--reason TEXT] [--ttl DURATION]",
75
131
  "",
@@ -79,6 +135,9 @@ export function helpText(version) {
79
135
  ` -c, --config Path to config file (default: ${DEFAULT_CONFIG_PATH})`,
80
136
  "",
81
137
  "Subcommands:",
138
+ " init First-run setup: validate API key, write",
139
+ " collector.yaml + systemd unit, enable service.",
140
+ " See 'glassmkr-crucible init --help'.",
82
141
  " mark-reboot Write a planned-reboot marker so the next boot",
83
142
  " does not fire `server_rebooted_unexpectedly`.",
84
143
  " You run the reboot yourself afterwards.",
@@ -88,6 +147,38 @@ export function helpText(version) {
88
147
  "Docs: https://github.com/glassmkr/crucible",
89
148
  ].join("\n");
90
149
  }
150
+ export function initHelp(version) {
151
+ return [
152
+ `glassmkr-crucible init - first-run setup wizard`,
153
+ "",
154
+ "Usage:",
155
+ " glassmkr-crucible init --api-key <KEY> [options]",
156
+ " glassmkr-crucible init --api-key - [options] # read key from stdin",
157
+ "",
158
+ "Required:",
159
+ " --api-key <KEY> gmk_cru_live_<...>_<4> or col_<hex>. Use - to read from stdin.",
160
+ "",
161
+ "Options:",
162
+ " --name <NAME> Server name in the Forge dashboard. Defaults to the host's hostname.",
163
+ " --ingest-url <URL> Ingest endpoint (default: https://forge.glassmkr.com/api/v1/ingest).",
164
+ " --config-path <P> Where to write collector.yaml (default: /etc/glassmkr/collector.yaml).",
165
+ " --no-start Write config + unit, daemon-reload, but do not enable/start the service.",
166
+ " --force Overwrite an existing config file.",
167
+ " --no-verify Skip the connectivity probe against the ingest endpoint.",
168
+ " -h, --help Print this help and exit.",
169
+ "",
170
+ "What this does:",
171
+ " 1. Validates the api key format and (unless --no-verify) checks it against the ingest endpoint.",
172
+ " 2. Writes /etc/glassmkr/collector.yaml (mode 0600).",
173
+ " 3. Writes /etc/systemd/system/glassmkr-crucible.service (mode 0644) with",
174
+ " ExecStart pointing at the dynamically-detected binary path.",
175
+ " 4. Runs systemctl daemon-reload.",
176
+ " 5. Unless --no-start, runs systemctl enable --now glassmkr-crucible.",
177
+ "",
178
+ "Requires root for the filesystem and systemd writes (sudo).",
179
+ `v${version}`,
180
+ ].join("\n");
181
+ }
91
182
  function subcommandHelp(mode, version) {
92
183
  const action = mode === "reboot"
93
184
  ? "Write a planned-reboot marker and invoke `systemctl reboot`."
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}