gemmein 0.0.2 → 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gemmein Limited
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ NOTE: this license covers the launcher ("shim") only. The Gemmein engine
24
+ artifact it downloads is separately licensed under proprietary terms
25
+ presented at download time — see ARTIFACT-LICENSE.md in the distribution
26
+ repository.
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ // gemmein — thin launcher. Downloads the Gemmein local engine once,
3
+ // verifies it against hashes baked into this package, caches it, runs it.
4
+ // Everything real happens in the engine, locally, offline.
5
+
6
+ import { ENGINE_VERSION, ENGINE_FILES, DOWNLOAD_BASE } from "../lib/versions.mjs";
7
+ import { engineCached, fetchEngine, runEngine } from "../lib/engine.mjs";
8
+
9
+ const args = process.argv.slice(2);
10
+
11
+ try {
12
+ if (!engineCached(ENGINE_VERSION, ENGINE_FILES)) {
13
+ console.log(`Fetching the Gemmein engine (v${ENGINE_VERSION}, one time — everything runs locally after this)…`);
14
+ await fetchEngine(ENGINE_VERSION, ENGINE_FILES, DOWNLOAD_BASE);
15
+ console.log("Verified and cached. You're set — this never needs the network again.\n");
16
+ }
17
+ runEngine(ENGINE_VERSION, args);
18
+ } catch (error) {
19
+ console.error(`\n${error.message}\n`);
20
+ process.exit(1);
21
+ }
package/lib/engine.mjs ADDED
@@ -0,0 +1,74 @@
1
+ // Fetch-verify-cache-run. Small on purpose: this file is the entire trust
2
+ // surface of what executes on a user's machine, and it's shipped as
3
+ // readable source so anyone can audit it.
4
+ //
5
+ // OFFLINE-LAW: the network is touched ONLY when the pinned engine version
6
+ // isn't cached yet. Once cached, everything — including every future
7
+ // `gemmein dev` — runs fully offline.
8
+
9
+ import { createHash } from "node:crypto";
10
+ import { mkdirSync, readFileSync, writeFileSync, renameSync, existsSync, chmodSync } from "node:fs";
11
+ import { homedir } from "node:os";
12
+ import { join } from "node:path";
13
+ import { spawn } from "node:child_process";
14
+
15
+ export function engineDir(version, base = join(homedir(), ".gemmein", "engine")) {
16
+ return join(base, version);
17
+ }
18
+
19
+ function sha256(buffer) {
20
+ return createHash("sha256").update(buffer).digest("hex");
21
+ }
22
+
23
+ /** True when every pinned file exists in the cache with the pinned hash. */
24
+ export function engineCached(version, files, base) {
25
+ const dir = engineDir(version, base);
26
+ return Object.entries(files).every(([name, hash]) => {
27
+ try { return sha256(readFileSync(join(dir, name))) === hash; } catch { return false; }
28
+ });
29
+ }
30
+
31
+ /**
32
+ * Download the pinned engine and verify BEFORE it lands in the cache.
33
+ * A hash mismatch aborts everything — nothing unverified is ever written
34
+ * to its final location, so nothing unverified can ever run.
35
+ */
36
+ export async function fetchEngine(version, files, downloadBase, base) {
37
+ if (Object.values(files).some((h) => !/^[a-f0-9]{64}$/.test(h))) {
38
+ throw new Error(
39
+ "this shim build has no released engine pinned — update the gemmein package (npm i -g gemmein@latest)"
40
+ );
41
+ }
42
+ const dir = engineDir(version, base);
43
+ mkdirSync(dir, { recursive: true });
44
+ for (const [name, expected] of Object.entries(files)) {
45
+ const url = `${downloadBase}/${version}/${name}`;
46
+ const res = await fetch(url);
47
+ if (!res.ok) throw new Error(`couldn't download the Gemmein engine (${res.status} for ${name}) — check your connection and try again`);
48
+ const bytes = Buffer.from(await res.arrayBuffer());
49
+ const actual = sha256(bytes);
50
+ if (actual !== expected) {
51
+ throw new Error(
52
+ `SECURITY: ${name} from the download server does not match the hash pinned in this npm package ` +
53
+ `(expected ${expected.slice(0, 12)}…, got ${actual.slice(0, 12)}…). Refusing to run it. ` +
54
+ `This should never happen — please report it: hello@gemmein.com`
55
+ );
56
+ }
57
+ const tmp = join(dir, `${name}.tmp`);
58
+ writeFileSync(tmp, bytes);
59
+ renameSync(tmp, join(dir, name));
60
+ }
61
+ chmodSync(join(dir, "gemmein.js"), 0o755);
62
+ }
63
+
64
+ /** Hand over to the cached engine, argv passed through, cwd preserved. */
65
+ export function runEngine(version, args, base) {
66
+ const entry = join(engineDir(version, base), "gemmein.js");
67
+ if (!existsSync(entry)) throw new Error("engine missing after verification — report this: hello@gemmein.com");
68
+ const child = spawn(process.execPath, [entry, ...args], { stdio: "inherit" });
69
+ child.on("exit", (code, signal) => {
70
+ if (signal) process.kill(process.pid, signal);
71
+ process.exit(code ?? 0);
72
+ });
73
+ return child;
74
+ }
@@ -0,0 +1,21 @@
1
+ // THE COMPILE-TIME CONSTANTS (CARVE-BOUNDARY hash law).
2
+ //
3
+ // These hashes are baked into the published npm package and are the ONLY
4
+ // thing the downloaded engine is verified against. They are never fetched
5
+ // at runtime and never served from the CDN — the hash travels through npm,
6
+ // the artifact travels through downloads.gemmein.com, and compromising one
7
+ // channel is useless without the other.
8
+ //
9
+ // Updated ONLY by the promotion ritual (PROMOTION.md). The TBD placeholder
10
+ // fails closed: the shim refuses to download anything until a real release
11
+ // has been promoted.
12
+
13
+ export const ENGINE_VERSION = "0.1.0";
14
+
15
+ /** file name -> hex sha256 */
16
+ export const ENGINE_FILES = {
17
+ "gemmein.js": "6dc0ad751f0f2023039d58f1f44a80824ec4b44d67bca57b44c097729a65936f",
18
+ "llms.txt": "1aa0989dd1624e93014122a451e22043659caa02e32a5b096da90d2b1cff6217",
19
+ };
20
+
21
+ export const DOWNLOAD_BASE = "https://downloads.gemmein.com/engine";
package/package.json CHANGED
@@ -1,8 +1,37 @@
1
1
  {
2
2
  "name": "gemmein",
3
- "version": "0.0.2",
4
- "description": "Gemmein \u2014 the secure backend for AI-built apps. For the SDK, install @gemmein/sdk. This name is reserved for the future Gemmein CLI.",
3
+ "version": "0.1.0",
4
+ "description": "gemmein \u2014 declare your business boundaries, prove them locally, ship. Thin launcher: downloads the Gemmein local engine, verifies it, runs it. What you read here is what runs.",
5
5
  "license": "MIT",
6
+ "type": "module",
7
+ "bin": {
8
+ "gemmein": "./bin/gemmein.mjs"
9
+ },
10
+ "files": [
11
+ "bin",
12
+ "lib"
13
+ ],
14
+ "engines": {
15
+ "node": ">=18"
16
+ },
17
+ "scripts": {
18
+ "test": "node --test test/*.test.mjs"
19
+ },
20
+ "keywords": [
21
+ "backend",
22
+ "auth",
23
+ "storage",
24
+ "payments",
25
+ "local-first",
26
+ "ai",
27
+ "vibe-coding"
28
+ ],
29
+ "homepage": "https://gemmein.com",
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
6
33
  "author": "Gemmein Limited",
7
- "homepage": "https://gemmein.com"
34
+ "bugs": {
35
+ "email": "hello@gemmein.com"
36
+ }
8
37
  }
package/README.md DELETED
@@ -1,11 +0,0 @@
1
- # gemmein
2
-
3
- You probably want the SDK:
4
-
5
- ```
6
- npm i @gemmein/sdk
7
- ```
8
-
9
- This package name is reserved for the future Gemmein CLI.
10
-
11
- Docs: https://docs.gemmein.com · Site: https://gemmein.com