ezi 0.0.2 → 2.0.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.
Files changed (4) hide show
  1. package/README.md +51 -48
  2. package/dist/index.js +223 -0
  3. package/package.json +32 -6
  4. package/app.js +0 -1
package/README.md CHANGED
@@ -1,48 +1,51 @@
1
- <div align="center">
2
- <h1>ezi</h1>
3
- <p>A smooth, minimal framework for infusing JavaScript with dynamic behavior.</p>
4
- </div>
5
-
6
- ## Hi there 👋
7
-
8
- ### Welcome to the sleek and minimal framework that brings dynamic behavior to JavaScript! ✨
9
-
10
- ---
11
-
12
- # Features
13
-
14
- - Smooth Integration: Easy-to-use framework for adding dynamic functionality to
15
- your JavaScript projects.
16
- - Minimalistic Design: Focus on what matters with a clean and simple setup.
17
- - Dynamic State Management: Manage and update your state with ease.
18
- - Explore more and start building with DeshiJS today! 🚀
19
-
20
- ---
21
-
22
- ```html
23
- <div id="root"></div>
24
-
25
- <template>
26
- <button @click="incrementCounter()">
27
- { count } {count <= 1 ? 'time' : 'times' }
28
- </button>
29
- </template>
30
-
31
- <script type="module">
32
- import ezi from "//unpkg.com/ezi";
33
- ezi.init();
34
-
35
- useSignal({
36
- count: 0,
37
- incrementCounter: function () {
38
- this.count++;
39
- },
40
- });
41
-
42
- useEffect(() => {
43
- console.log("component mounted!");
44
- });
45
- </script>
46
- ```
47
-
48
- author: [Nazmul Hossain](https://www.facebook.com/codervai)
1
+ # ezi — `npx ezi` launcher for ezicode
2
+
3
+ Zero-dependency TypeScript CLI. It detects OS/arch, downloads the matching
4
+ native `ezicode` binary from GitHub Releases on first run, caches it, and
5
+ launches the editor detached. No `npm install` required by users.
6
+
7
+ ## Mono-repo layout
8
+
9
+ ```
10
+ ezicode/ # Rust workspace (cargo members: app)
11
+ ├── app/ # native editor (ezicode binary)
12
+ ├── ezi-cli/ # npm launcher (this folder, NOT a cargo member)
13
+ ```
14
+
15
+ Cargo ignores `ezi-cli/` (`members = ["app"]` in root `Cargo.toml:2`), npm
16
+ ignores the Rust side. One repo, two package managers.
17
+
18
+ ## Develop
19
+
20
+ ```bash
21
+ cd ezi-cli
22
+ npm install
23
+ npm run build # tsc -> dist/index.js
24
+ node ./dist/index.js --help
25
+ EZI_VERBOSE=1 node ./dist/index.js . # downloads real binary, opens editor
26
+ ```
27
+
28
+ ## Publish
29
+
30
+ ```bash
31
+ cd ezi-cli
32
+ npm run build
33
+ npm publish # package `ezi`, bin `ezi` -> dist/index.js
34
+ ```
35
+
36
+ Users then run:
37
+
38
+ ```bash
39
+ npx -y ezi . # first run downloads ~30-60MB binary to cache, opens editor
40
+ ezi . # after npm i -g ezi
41
+ ```
42
+
43
+ Keep `VERSION` in `src/index.ts`, `version` in `package.json`, and `version`
44
+ in `app/Cargo.toml` in sync — the launcher builds its download URL as
45
+ `.../releases/download/v<VERSION>/ezicode-<target>.*`.
46
+
47
+ ## Cache
48
+
49
+ - Linux/macOS: `~/.cache/ezi/v<version>/` (or `$XDG_CACHE_HOME`)
50
+ - Windows: `%LOCALAPPDATA%/ezi/cache/v<version>/`
51
+ - Override: `EZI_CACHE`, `EZI_VERSION`, `EZI_REPO`
package/dist/index.js ADDED
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * ezi — zero-install launcher for the ezicode native editor.
5
+ *
6
+ * Usage:
7
+ * npx ezi [file|dir] [args...] open editor (downloads binary on first run)
8
+ * npx ezi --help show help
9
+ * npx ezi --version launcher + editor version
10
+ *
11
+ * Env overrides:
12
+ * EZI_VERSION GitHub tag version without `v` (default: package version)
13
+ * EZI_REPO `owner/repo` (default: olovalabs/ezicode)
14
+ * EZI_CACHE cache dir override
15
+ *
16
+ * Design: zero npm dependencies (node builtins only) so the published
17
+ * package stays ~5KB. Platform binaries come from GitHub Releases:
18
+ * linux x64 -> ezicode-x86_64-unknown-linux-gnu.tar.gz
19
+ * mac arm64 -> ezicode-aarch64-apple-darwin.tar.gz
20
+ * win x64 -> ezicode-x86_64-pc-windows-msvc.exe (standalone, no unzip)
21
+ */
22
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ var desc = Object.getOwnPropertyDescriptor(m, k);
25
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
26
+ desc = { enumerable: true, get: function() { return m[k]; } };
27
+ }
28
+ Object.defineProperty(o, k2, desc);
29
+ }) : (function(o, m, k, k2) {
30
+ if (k2 === undefined) k2 = k;
31
+ o[k2] = m[k];
32
+ }));
33
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
34
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
35
+ }) : function(o, v) {
36
+ o["default"] = v;
37
+ });
38
+ var __importStar = (this && this.__importStar) || (function () {
39
+ var ownKeys = function(o) {
40
+ ownKeys = Object.getOwnPropertyNames || function (o) {
41
+ var ar = [];
42
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
43
+ return ar;
44
+ };
45
+ return ownKeys(o);
46
+ };
47
+ return function (mod) {
48
+ if (mod && mod.__esModule) return mod;
49
+ var result = {};
50
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
51
+ __setModuleDefault(result, mod);
52
+ return result;
53
+ };
54
+ })();
55
+ Object.defineProperty(exports, "__esModule", { value: true });
56
+ const fs = __importStar(require("node:fs"));
57
+ const https = __importStar(require("node:https"));
58
+ const os = __importStar(require("node:os"));
59
+ const path = __importStar(require("node:path"));
60
+ const node_child_process_1 = require("node:child_process");
61
+ const LAUNCHER_VERSION = "2.0.0"; // npm package version
62
+ const EDITOR_VERSION = "0.1.2"; // keep in sync with app/Cargo.toml (default download)
63
+ const REPO = process.env.EZI_REPO || "olovalabs/ezicode";
64
+ const TAG = `v${process.env.EZI_VERSION || EDITOR_VERSION}`;
65
+ function resolveTarget() {
66
+ const platform = process.platform;
67
+ const arch = process.arch;
68
+ if (platform === "linux" && arch === "x64") {
69
+ const t = "x86_64-unknown-linux-gnu";
70
+ return { kind: "targz", asset: `ezicode-${t}.tar.gz`, binRel: `ezicode-${t}/ezicode` };
71
+ }
72
+ if (platform === "darwin" && arch === "arm64") {
73
+ const t = "aarch64-apple-darwin";
74
+ return { kind: "targz", asset: `ezicode-${t}.tar.gz`, binRel: `ezicode-${t}/ezicode` };
75
+ }
76
+ if (platform === "win32" && arch === "x64") {
77
+ // Standalone exe on the release — no zip extraction needed.
78
+ return { kind: "exe", asset: "ezicode-x86_64-pc-windows-msvc.exe" };
79
+ }
80
+ throw new Error(`ezi: unsupported platform ${platform}/${arch}. ` +
81
+ `Prebuilt binaries exist for linux-x64, darwin-arm64, win32-x64 only. ` +
82
+ `Build from source: https://github.com/${REPO}`);
83
+ }
84
+ function cacheDir() {
85
+ if (process.env.EZI_CACHE)
86
+ return process.env.EZI_CACHE;
87
+ if (process.platform === "win32") {
88
+ const base = process.env.LOCALAPPDATA || path.join(os.homedir(), "AppData", "Local");
89
+ return path.join(base, "ezi", "cache", TAG);
90
+ }
91
+ const xdg = process.env.XDG_CACHE_HOME || path.join(os.homedir(), ".cache");
92
+ return path.join(xdg, "ezi", TAG);
93
+ }
94
+ function download(url, dest, redirects = 5) {
95
+ return new Promise((resolve, reject) => {
96
+ const req = https.get(url, { headers: { "User-Agent": "ezi-launcher" } }, (res) => {
97
+ const status = res.statusCode || 0;
98
+ if (status >= 300 && status < 400 && res.headers.location) {
99
+ if (redirects === 0) {
100
+ reject(new Error(`ezi: too many redirects downloading ${url}`));
101
+ return;
102
+ }
103
+ res.resume();
104
+ download(res.headers.location, dest, redirects - 1).then(resolve, reject);
105
+ return;
106
+ }
107
+ if (status !== 200) {
108
+ res.resume();
109
+ reject(new Error(`ezi: download failed (${status}) for ${url}`));
110
+ return;
111
+ }
112
+ const out = fs.createWriteStream(dest);
113
+ res.pipe(out);
114
+ out.on("finish", () => out.close(() => resolve()));
115
+ out.on("error", (err) => {
116
+ fs.rmSync(dest, { force: true });
117
+ reject(err);
118
+ });
119
+ });
120
+ req.on("error", reject);
121
+ });
122
+ }
123
+ function extractTargz(archive, destDir) {
124
+ return new Promise((resolve, reject) => {
125
+ // System tar exists on linux + macOS runners and images. Zero-dep by design.
126
+ (0, node_child_process_1.execFile)("tar", ["-xzf", archive, "-C", destDir], (err, _stdout, stderr) => {
127
+ if (err) {
128
+ reject(new Error(`ezi: failed to extract ${archive}: ${stderr || err.message}`));
129
+ return;
130
+ }
131
+ resolve();
132
+ });
133
+ });
134
+ }
135
+ async function ensureBinary(verbose) {
136
+ const target = resolveTarget();
137
+ const dir = cacheDir();
138
+ fs.mkdirSync(dir, { recursive: true });
139
+ if (target.kind === "exe") {
140
+ const bin = path.join(dir, "ezicode.exe");
141
+ if (fs.existsSync(bin))
142
+ return bin;
143
+ const url = `https://github.com/${REPO}/releases/download/${TAG}/${target.asset}`;
144
+ const tmp = bin + ".download";
145
+ if (verbose)
146
+ console.log(`ezi: downloading ${url}`);
147
+ await download(url, tmp);
148
+ fs.renameSync(tmp, bin);
149
+ return bin;
150
+ }
151
+ const bin = path.join(dir, target.binRel);
152
+ if (fs.existsSync(bin)) {
153
+ fs.chmodSync(bin, 0o755);
154
+ return bin;
155
+ }
156
+ const url = `https://github.com/${REPO}/releases/download/${TAG}/${target.asset}`;
157
+ const archive = path.join(dir, target.asset);
158
+ if (!fs.existsSync(archive)) {
159
+ if (verbose)
160
+ console.log(`ezi: downloading ${url}`);
161
+ await download(url, archive);
162
+ }
163
+ if (verbose)
164
+ console.log(`ezi: extracting ${target.asset}`);
165
+ await extractTargz(archive, dir);
166
+ if (!fs.existsSync(bin))
167
+ throw new Error(`ezi: binary not found after extract: ${bin}`);
168
+ fs.chmodSync(bin, 0o755);
169
+ return bin;
170
+ }
171
+ function printHelp() {
172
+ console.log(`ezi ${LAUNCHER_VERSION} — launcher for ezicode (https://github.com/${REPO})
173
+
174
+ Usage:
175
+ ezi [file|dir] [editor-args...] open in ezicode (downloads binary first run)
176
+ ezi --help this help
177
+ ezi --version launcher version
178
+ ezi --where print cached binary path
179
+ ezi --clean remove cached binaries
180
+
181
+ Env:
182
+ EZI_VERSION release version (default ${EDITOR_VERSION})
183
+ EZI_REPO owner/repo (default ${REPO})
184
+ EZI_CACHE cache dir override
185
+ `);
186
+ }
187
+ async function main() {
188
+ const args = process.argv.slice(2);
189
+ const verbose = args.includes("--verbose") || !!process.env.EZI_VERBOSE;
190
+ const passthrough = args.filter((a) => a !== "--verbose");
191
+ if (passthrough.includes("--help") || passthrough.includes("-h")) {
192
+ printHelp();
193
+ return;
194
+ }
195
+ if (passthrough.includes("--version") || passthrough.includes("-V")) {
196
+ console.log(`ezi ${LAUNCHER_VERSION} (editor ${TAG} @ ${REPO})`);
197
+ return;
198
+ }
199
+ if (passthrough.includes("--clean")) {
200
+ fs.rmSync(cacheDir(), { recursive: true, force: true });
201
+ console.log("ezi: cache cleared");
202
+ return;
203
+ }
204
+ const bin = await ensureBinary(verbose);
205
+ if (passthrough.includes("--where")) {
206
+ console.log(bin);
207
+ return;
208
+ }
209
+ // Launch detached so `npx ezi` returns immediately while the GUI stays open.
210
+ // stdio ignored: the editor owns its own window, not the terminal.
211
+ const child = (0, node_child_process_1.spawn)(bin, passthrough, {
212
+ detached: true,
213
+ stdio: "ignore",
214
+ windowsHide: true,
215
+ });
216
+ child.unref();
217
+ if (verbose)
218
+ console.log(`ezi: launched ${bin}`);
219
+ }
220
+ main().catch((err) => {
221
+ console.error(err instanceof Error ? err.message : String(err));
222
+ process.exit(1);
223
+ });
package/package.json CHANGED
@@ -1,6 +1,32 @@
1
- {
2
- "name": "ezi",
3
- "main": "app.js",
4
- "version": "0.0.2",
5
- "author": "Nazmul Hossain"
6
- }
1
+ {
2
+ "name": "ezi",
3
+ "version": "2.0.0",
4
+ "description": "Launch ezicode editor with npx — zero-install native binary launcher",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/olovalabs/ezicode.git",
9
+ "directory": "ezi-cli"
10
+ },
11
+ "homepage": "https://github.com/olovalabs/ezicode",
12
+ "keywords": ["ezicode", "ezi", "editor", "ide", "cli", "launcher"],
13
+ "engines": {
14
+ "node": ">=18"
15
+ },
16
+ "bin": {
17
+ "ezi": "./dist/index.js"
18
+ },
19
+ "files": ["dist/"],
20
+ "scripts": {
21
+ "build": "tsc",
22
+ "dev": "tsc --watch",
23
+ "start": "node ./dist/index.js",
24
+ "prepublishOnly": "npm run build",
25
+ "typecheck": "tsc --noEmit"
26
+ },
27
+ "dependencies": {},
28
+ "devDependencies": {
29
+ "@types/node": "^22.7.0",
30
+ "typescript": "^5.6.0"
31
+ }
32
+ }
package/app.js DELETED
@@ -1 +0,0 @@
1
- console.log("Hello world");