@elaraai/create-east 1.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.
package/LICENSE.md ADDED
@@ -0,0 +1,51 @@
1
+ Copyright (c) 2025 Elara AI Pty Ltd
2
+
3
+ # East Workspace — Multi-License Repository
4
+
5
+ This repository contains multiple components released under different
6
+ licenses. Each component directory under `libs/` that contains its own
7
+ `LICENSE.md` is governed **exclusively** by that file, which takes
8
+ precedence over this one. This file licenses everything not otherwise
9
+ covered, and summarizes the per-component split.
10
+
11
+ ## License by component
12
+
13
+ - **Dual AGPL-3.0 / Commercial** — `east`, `east-node`, `east-ui`, and the
14
+ e3 SDK (`@elaraai/e3`, `@elaraai/e3-types`).
15
+ - **Business Source License 1.1** — `east-c`, `east-py` (runtime, std, io,
16
+ cli), and the e3 server stack (`@elaraai/e3-core`, `@elaraai/e3-cli`,
17
+ `@elaraai/e3-api-client`, `@elaraai/e3-api-server`, `@elaraai/e3-api-tests`).
18
+ - **Hybrid (TypeScript AGPL-3.0 / Python BSL 1.1)** — `east-py-datascience`.
19
+
20
+ For the full terms of any component, see its `libs/<name>/LICENSE.md` and
21
+ the per-package `LICENSE.md`.
22
+
23
+ ## Repository-level files
24
+
25
+ All files that are **not** part of a component carrying its own
26
+ `LICENSE.md` — including the build tooling, `scripts/`, `docs/`,
27
+ `.github/`, the `Makefile`, and top-level configuration — are licensed
28
+ under the GNU Affero General Public License v3.0 or later
29
+ (AGPL-3.0-or-later).
30
+
31
+ Full text: https://www.gnu.org/licenses/agpl-3.0.html
32
+
33
+ ## Commercial licensing
34
+
35
+ To use any dual-licensed component without the source-disclosure
36
+ requirements of AGPL-3.0, or to discuss licensing for Business Source
37
+ License components, contact Elara AI Pty Ltd at support@elara.ai.
38
+
39
+ ## Contributions
40
+
41
+ By submitting a contribution you agree to license it under the license(s)
42
+ applicable to the component you are contributing to. See
43
+ [CONTRIBUTING.md](CONTRIBUTING.md) and [CLA.md](CLA.md).
44
+
45
+ ## Governing Law
46
+
47
+ This file is governed by the laws of New South Wales, Australia.
48
+
49
+ ---
50
+
51
+ *Elara AI Pty Ltd*
package/dist/index.js ADDED
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env node
2
+
3
+ // ../scaffold-core/dist/scaffold.js
4
+ import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
5
+ import { join, relative } from "node:path";
6
+ import { spawnSync } from "node:child_process";
7
+
8
+ // ../scaffold-core/dist/names.js
9
+ import { basename } from "node:path";
10
+ function deriveNames(rawName, cwd) {
11
+ const source = rawName === "." ? basename(cwd) : rawName;
12
+ const projectName = source.trim().toLowerCase().replace(/[\s_]+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
13
+ if (projectName === "") {
14
+ throw new Error(`Could not derive a valid project name from "${rawName}"`);
15
+ }
16
+ const displayName = projectName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
17
+ const workspaceName = projectName.replace(/-/g, "_");
18
+ return { projectName, displayName, workspaceName };
19
+ }
20
+
21
+ // ../scaffold-core/dist/scaffold.js
22
+ var TEXT_REPLACE_EXT = /* @__PURE__ */ new Set([
23
+ ".ts",
24
+ ".tsx",
25
+ ".js",
26
+ ".mjs",
27
+ ".json",
28
+ ".toml",
29
+ ".md",
30
+ ".txt",
31
+ ".yml",
32
+ ".yaml",
33
+ ".py",
34
+ ".nvmrc",
35
+ ".python-version",
36
+ ""
37
+ ]);
38
+ var DOTFILE_RENAMES = {
39
+ gitignore: ".gitignore",
40
+ npmrc: ".npmrc"
41
+ };
42
+ function substituteTokens(content, names) {
43
+ return content.replaceAll("__PROJECT_NAME__", names.projectName).replaceAll("__DISPLAY_NAME__", names.displayName).replaceAll("__WORKSPACE_NAME__", names.workspaceName);
44
+ }
45
+ function transformPackageJson(raw, names, version) {
46
+ const pkg = JSON.parse(raw);
47
+ pkg.name = `@elaraai/${names.projectName}`;
48
+ pkg.description = names.displayName;
49
+ pkg.version = "0.0.1";
50
+ delete pkg.private;
51
+ const pin = `^${version}`;
52
+ for (const field of ["dependencies", "devDependencies", "peerDependencies"]) {
53
+ const deps = pkg[field];
54
+ if (!deps)
55
+ continue;
56
+ for (const [name, spec] of Object.entries(deps)) {
57
+ if (spec.startsWith("workspace:"))
58
+ deps[name] = pin;
59
+ }
60
+ }
61
+ return `${JSON.stringify(pkg, null, 2)}
62
+ `;
63
+ }
64
+ function walk(dir) {
65
+ const out = [];
66
+ for (const entry of readdirSync(dir)) {
67
+ const full = join(dir, entry);
68
+ if (statSync(full).isDirectory())
69
+ out.push(...walk(full));
70
+ else
71
+ out.push(full);
72
+ }
73
+ return out;
74
+ }
75
+ function extOf(path) {
76
+ const base = path.slice(path.lastIndexOf("/") + 1);
77
+ const dot = base.lastIndexOf(".");
78
+ return dot <= 0 ? "" : base.slice(dot);
79
+ }
80
+ function scaffold(options) {
81
+ const { kind, name, templateDir, version } = options;
82
+ const cwd = options.cwd ?? process.cwd();
83
+ const log = options.log ?? ((m) => console.log(m));
84
+ if (!existsSync(templateDir)) {
85
+ throw new Error(`Template directory not found: ${templateDir}`);
86
+ }
87
+ const names = deriveNames(name, cwd);
88
+ const inPlace = name === ".";
89
+ const projectDir = inPlace ? cwd : join(cwd, names.projectName);
90
+ if (!inPlace && existsSync(projectDir)) {
91
+ throw new Error(`Directory already exists: ${projectDir}`);
92
+ }
93
+ mkdirSync(projectDir, { recursive: true });
94
+ for (const srcPath of walk(templateDir)) {
95
+ const rel = relative(templateDir, srcPath);
96
+ const segments = rel.split(/[/\\]/);
97
+ const last = segments[segments.length - 1];
98
+ segments[segments.length - 1] = DOTFILE_RENAMES[last] ?? last;
99
+ const destRel = segments.join("/");
100
+ const destPath = join(projectDir, destRel);
101
+ mkdirSync(join(destPath, ".."), { recursive: true });
102
+ const baseName = segments[segments.length - 1];
103
+ if (baseName === "package.json") {
104
+ const manifest = transformPackageJson(readFileSync(srcPath, "utf8"), names, version);
105
+ writeFileSync(destPath, substituteTokens(manifest, names));
106
+ } else if (TEXT_REPLACE_EXT.has(extOf(srcPath)) || baseName.startsWith(".")) {
107
+ writeFileSync(destPath, substituteTokens(readFileSync(srcPath, "utf8"), names));
108
+ } else {
109
+ writeFileSync(destPath, readFileSync(srcPath));
110
+ }
111
+ }
112
+ log(`Created ${names.projectName} (${kind}) at ${projectDir}`);
113
+ if (options.install) {
114
+ runInstall(kind, projectDir, log);
115
+ }
116
+ return { ...names, projectDir, inPlace };
117
+ }
118
+ function hasCommand(cmd) {
119
+ const probe = process.platform === "win32" ? "where" : "which";
120
+ return spawnSync(probe, [cmd], { stdio: "ignore" }).status === 0;
121
+ }
122
+ function runInstall(kind, projectDir, log) {
123
+ log("Installing Node dependencies (npm install)...");
124
+ const npm = spawnSync("npm", ["install"], { cwd: projectDir, stdio: "inherit", shell: process.platform === "win32" });
125
+ if (npm.status !== 0) {
126
+ log("npm install failed \u2014 fix the issue and re-run `npm install`.");
127
+ return;
128
+ }
129
+ if (kind === "e3") {
130
+ if (hasCommand("uv")) {
131
+ log("Installing Python dependencies (uv sync)...");
132
+ const uv = spawnSync("uv", ["sync"], { cwd: projectDir, stdio: "inherit", shell: process.platform === "win32" });
133
+ if (uv.status !== 0)
134
+ log("uv sync failed \u2014 fix the issue and re-run `uv sync`.");
135
+ } else {
136
+ log("uv not found \u2014 install it (https://docs.astral.sh/uv/) then run `uv sync` to set up Python.");
137
+ }
138
+ }
139
+ }
140
+
141
+ // ../scaffold-core/dist/cli.js
142
+ import { readFileSync as readFileSync2 } from "node:fs";
143
+ import { dirname, join as join2 } from "node:path";
144
+ import { fileURLToPath } from "node:url";
145
+ function runCreateCli(kind, moduleUrl) {
146
+ const pkgRoot = join2(dirname(fileURLToPath(moduleUrl)), "..");
147
+ const args = process.argv.slice(2);
148
+ if (args.includes("--help") || args.includes("-h")) {
149
+ console.log(`Usage: npm create @elaraai/${kind} <project-name> [-- --install|--no-install]`);
150
+ console.log(` create-${kind} <project-name|.> [--install|--no-install]`);
151
+ return;
152
+ }
153
+ const version = JSON.parse(readFileSync2(join2(pkgRoot, "package.json"), "utf8")).version;
154
+ const templateDir = join2(pkgRoot, "templates", kind);
155
+ const name = args.find((a) => !a.startsWith("-")) ?? ".";
156
+ const install = args.includes("--install") ? true : args.includes("--no-install") ? false : Boolean(process.stdout.isTTY);
157
+ try {
158
+ const result = scaffold({ kind, name, templateDir, version, install });
159
+ printNextSteps(kind, result.projectName, result.inPlace, install);
160
+ } catch (err) {
161
+ console.error(`error: ${err instanceof Error ? err.message : String(err)}`);
162
+ process.exit(1);
163
+ }
164
+ }
165
+ function printNextSteps(kind, projectName, inPlace, installed) {
166
+ console.log("");
167
+ console.log("Next steps:");
168
+ if (!inPlace)
169
+ console.log(` cd ${projectName}`);
170
+ if (!installed)
171
+ console.log(kind === "e3" ? " npm run setup" : " npm install");
172
+ console.log(kind === "e3" ? " npm run start" : " npm run test");
173
+ }
174
+
175
+ // src/index.ts
176
+ runCreateCli("east", import.meta.url);
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@elaraai/create-east",
3
+ "version": "1.0.0",
4
+ "description": "Scaffold a new East project (AGPL-3.0, Node-only): npm create @elaraai/east",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-east": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "templates"
12
+ ],
13
+ "license": "AGPL-3.0-or-later",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/elaraai/east-workspace.git",
17
+ "directory": "libs/create/packages/create-east"
18
+ },
19
+ "engines": {
20
+ "node": ">=22"
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "^22",
24
+ "esbuild": "^0.24",
25
+ "typescript": "^5",
26
+ "@elaraai/scaffold-core": "1.0.0"
27
+ },
28
+ "scripts": {
29
+ "build": "node build.mjs",
30
+ "test": "node --test \"dist/**/*.spec.js\""
31
+ }
32
+ }
@@ -0,0 +1 @@
1
+ 22
@@ -0,0 +1,18 @@
1
+ # __DISPLAY_NAME__
2
+
3
+ East project (AGPL-3.0), Node-only.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ npm install
9
+ ```
10
+
11
+ ## Commands
12
+
13
+ ```bash
14
+ npm run build # compile TypeScript
15
+ npm run test # build and run tests
16
+ npm run lint # lint sources
17
+ npm run clean # remove build output and dependencies
18
+ ```
@@ -0,0 +1,15 @@
1
+ import tseslint from "@typescript-eslint/eslint-plugin";
2
+ import tsparser from "@typescript-eslint/parser";
3
+
4
+ export default [
5
+ { ignores: ["dist/", "node_modules/"] },
6
+ {
7
+ files: ["src/**/*.ts"],
8
+ languageOptions: {
9
+ parser: tsparser,
10
+ parserOptions: { ecmaVersion: "latest", sourceType: "module" },
11
+ },
12
+ plugins: { "@typescript-eslint": tseslint },
13
+ rules: {},
14
+ },
15
+ ];
@@ -0,0 +1,3 @@
1
+ node_modules/
2
+ dist/
3
+ *.tsbuildinfo
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@elaraai/template-east",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "description": "__DISPLAY_NAME__",
6
+ "type": "module",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "test": "npm run build && node --enable-source-maps --test \"dist/**/*.spec.js\"",
10
+ "test:only": "node --enable-source-maps --test \"dist/**/*.spec.js\"",
11
+ "lint": "eslint .",
12
+ "clean": "rimraf dist node_modules *.tsbuildinfo"
13
+ },
14
+ "dependencies": {
15
+ "@elaraai/east": "workspace:*",
16
+ "@elaraai/east-node-std": "workspace:*",
17
+ "@elaraai/east-node-io": "workspace:*"
18
+ },
19
+ "devDependencies": {
20
+ "@types/node": "^22",
21
+ "typescript": "^5",
22
+ "eslint": "^9",
23
+ "@typescript-eslint/eslint-plugin": "^8",
24
+ "@typescript-eslint/parser": "^8",
25
+ "rimraf": "^6"
26
+ },
27
+ "engines": { "node": ">=22" }
28
+ }
@@ -0,0 +1,15 @@
1
+ import { East } from "@elaraai/east";
2
+ import { describeEast, Assert } from "@elaraai/east-node-std";
3
+ import { greet } from "./index.js";
4
+
5
+ describeEast("__DISPLAY_NAME__", (test) => {
6
+ test("greet returns greeting message", ($) => {
7
+ const result = $.let(greet("World"));
8
+ $(Assert.equal(result, East.value("Hello, World!")));
9
+ });
10
+
11
+ test("greet with custom name", ($) => {
12
+ const result = $.let(greet("East"));
13
+ $(Assert.equal(result, East.value("Hello, East!")));
14
+ });
15
+ });
@@ -0,0 +1,7 @@
1
+ import { East, StringType } from "@elaraai/east";
2
+
3
+ export const greet = East.function(
4
+ [StringType],
5
+ StringType,
6
+ ($, name) => East.str`Hello, ${name}!`,
7
+ );
@@ -0,0 +1,24 @@
1
+ {
2
+ "exclude": ["dist"],
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "module": "nodenext",
6
+ "target": "esnext",
7
+ "lib": ["esnext", "es2024"],
8
+ "types": ["node"],
9
+ "sourceMap": true,
10
+ "declaration": true,
11
+ "declarationMap": true,
12
+ "noUncheckedIndexedAccess": true,
13
+ "exactOptionalPropertyTypes": true,
14
+ "strict": true,
15
+ "jsx": "react-jsx",
16
+ "verbatimModuleSyntax": true,
17
+ "isolatedModules": true,
18
+ "noUncheckedSideEffectImports": true,
19
+ "moduleDetection": "force",
20
+ "skipLibCheck": true,
21
+ "noErrorTruncation": true,
22
+ "incremental": true
23
+ }
24
+ }