@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 +51 -0
- package/dist/index.js +176 -0
- package/package.json +32 -0
- package/templates/east/.nvmrc +1 -0
- package/templates/east/README.md +18 -0
- package/templates/east/eslint.config.js +15 -0
- package/templates/east/gitignore +3 -0
- package/templates/east/package.json +28 -0
- package/templates/east/src/index.spec.ts +15 -0
- package/templates/east/src/index.ts +7 -0
- package/templates/east/tsconfig.json +24 -0
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,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,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
|
+
}
|