@eclipse-lyra/create-app 0.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/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # @eclipse-lyra/create-app
2
+
3
+ Scaffold a new Eclipse Lyra app with a single command.
4
+
5
+ ## Testing locally
6
+
7
+ From the Eclipse Lyra monorepo root, run the CLI with Node (no publish needed):
8
+
9
+ ```bash
10
+ node packages/create-app/index.js my-app
11
+ # or non-interactive:
12
+ node packages/create-app/index.js my-app --yes
13
+ ```
14
+
15
+ Or use `npx` with the package path:
16
+
17
+ ```bash
18
+ npx file:./packages/create-app my-app --yes
19
+ ```
20
+
21
+ Then `cd my-app && npm run dev` to run the scaffolded app.
22
+
23
+ ## Usage (published package)
24
+
25
+ ```bash
26
+ npm create @eclipse-lyra/app
27
+ ```
28
+
29
+ With a project name (directory):
30
+
31
+ ```bash
32
+ npm create @eclipse-lyra/app my-app
33
+ ```
34
+
35
+ To skip prompts when a project name is provided:
36
+
37
+ ```bash
38
+ npm create @eclipse-lyra/app my-app -- --yes
39
+ ```
40
+
41
+ ## Next steps
42
+
43
+ After scaffolding:
44
+
45
+ ```bash
46
+ cd my-app
47
+ npm run dev
48
+ ```
49
+
50
+ From the created project root, `npm run dev` runs the app (Vite). Use `npm run build` and `npm run preview` to build and preview.
51
+
52
+ ## What you get
53
+
54
+ - A **monorepo** with two workspace packages:
55
+ - **`packages/app`** – the Lyra app (Vite, core + extensions from npm).
56
+ - **`packages/example-extension`** – a minimal example extension you can copy or extend.
57
+ - The app registers a **logo contribution** on the left main toolbar (slot `start`) with the text `my!app`; you can change it in `packages/app/src/main.ts`.
58
+ - The example extension is loaded by the app and adds an "Example" view in the left side panel.
59
+
60
+ ## Example extension
61
+
62
+ The template includes an example extension in **`packages/example-extension`** to show how to build your own extensions without publishing a separate npm package.
63
+
64
+ - **`src/index.ts`** – Registers the extension with `extensionRegistry.registerExtension()` (id, name, description, loader, icon). Same pattern as published extensions like `@eclipse-lyra/extension-howto-system` and `@eclipse-lyra/extension-utils`.
65
+ - **`src/example-extension-loader.ts`** – Loaded when the extension is activated. Registers a **TabContribution** to `SIDEBAR_MAIN` (the left side panel), so the "Example" tab appears alongside the workspace file browser.
66
+ - **`tsconfig.json`** – TypeScript config for the extension (IDE and type-checking).
67
+ - **`vite.config.ts`** – Vite lib build; run `npm run build -w example-extension` to output `dist/` when you want to publish the extension.
68
+
69
+ You can edit `packages/example-extension` in place, add more views or contributions, or copy it to start a new extension. The app depends on it via `"example-extension": "*"` in `packages/app/package.json` (npm links the workspace package). The app compiles the extension from source in dev; use the extension’s build script if you publish it as a separate package.
package/index.js ADDED
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { cpSync, mkdirSync, readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs';
4
+ import { dirname, join, resolve, basename } from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import { spawnSync } from 'child_process';
7
+
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ const TEMPLATE_DIR = join(__dirname, 'template');
10
+
11
+ function parseArgs() {
12
+ const args = process.argv.slice(2).filter((a) => !a.startsWith('--'));
13
+ const projectDir = args[0] || 'my-lyra-app';
14
+ const yes = process.argv.includes('--yes') || process.argv.includes('-y');
15
+ return { projectDir, yes };
16
+ }
17
+
18
+ function main() {
19
+ const { projectDir, yes } = parseArgs();
20
+ const targetDir = resolve(process.cwd(), projectDir);
21
+ const appName = basename(targetDir);
22
+
23
+ if (existsSync(targetDir)) {
24
+ console.error(`Error: Directory "${projectDir}" already exists.`);
25
+ process.exit(1);
26
+ }
27
+
28
+ if (!existsSync(TEMPLATE_DIR)) {
29
+ console.error('Error: Template directory not found. Reinstall @eclipse-lyra/create-app.');
30
+ process.exit(1);
31
+ }
32
+
33
+ console.log(`Creating app in ${targetDir}...`);
34
+ mkdirSync(targetDir, { recursive: true });
35
+ cpSync(TEMPLATE_DIR, targetDir, { recursive: true });
36
+ const appDescription = `${appName} – Application built with Eclipse Lyra.`;
37
+
38
+ const rootPkgPath = join(targetDir, 'package.json');
39
+ const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf8'));
40
+ rootPkg.name = appName;
41
+ rootPkg.scripts.dev = `npm run dev -w ${appName}`;
42
+ rootPkg.scripts.build = `npm run build -w ${appName}`;
43
+ rootPkg.scripts.preview = `npm run preview -w ${appName}`;
44
+ writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2) + '\n');
45
+
46
+ const appPkgPath = join(targetDir, 'packages', 'app', 'package.json');
47
+ const appPkg = JSON.parse(readFileSync(appPkgPath, 'utf8'));
48
+ appPkg.name = appName;
49
+ appPkg.description = appDescription;
50
+ writeFileSync(appPkgPath, JSON.stringify(appPkg, null, 2) + '\n');
51
+
52
+ const mainTsPath = join(targetDir, 'packages', 'app', 'src', 'main.ts');
53
+ let mainTs = readFileSync(mainTsPath, 'utf8');
54
+ mainTs = mainTs.replace(/\{\{APP_NAME\}\}/g, appName);
55
+ writeFileSync(mainTsPath, mainTs);
56
+
57
+ const readmePath = join(targetDir, 'README.md');
58
+ let readme = readFileSync(readmePath, 'utf8');
59
+ readme = readme.replace(/\{\{APP_NAME\}\}/g, appName);
60
+ writeFileSync(readmePath, readme);
61
+
62
+ const gitignoreSrc = join(targetDir, '_gitignore');
63
+ if (existsSync(gitignoreSrc)) {
64
+ writeFileSync(join(targetDir, '.gitignore'), readFileSync(gitignoreSrc, 'utf8'));
65
+ unlinkSync(gitignoreSrc);
66
+ }
67
+
68
+ console.log('Installing dependencies...');
69
+ const install = spawnSync('npm', ['install'], { cwd: targetDir, stdio: 'inherit', shell: true });
70
+ if (install.status !== 0) {
71
+ process.exit(install.status ?? 1);
72
+ }
73
+
74
+ console.log('\nDone! Next steps:\n');
75
+ console.log(` cd ${projectDir}`);
76
+ console.log(' npm run dev\n');
77
+ }
78
+
79
+ main();
package/package.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@eclipse-lyra/create-app",
3
+ "version": "0.0.0",
4
+ "description": "Scaffold a new Eclipse Lyra app (monorepo with app + example extension)",
5
+ "type": "module",
6
+ "bin": "index.js",
7
+ "files": [
8
+ "index.js",
9
+ "template"
10
+ ],
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/eclipse-lyra/core"
14
+ },
15
+ "license": "EPL-2.0"
16
+ }
@@ -0,0 +1,22 @@
1
+ # {{APP_NAME}}
2
+
3
+ Application built with [Eclipse Lyra](https://github.com/eclipse-lyra/core).
4
+
5
+ ## Getting started
6
+
7
+ ```bash
8
+ npm run dev
9
+ ```
10
+
11
+ Then open the URL shown in the terminal (e.g. https://localhost:5173/).
12
+
13
+ ## Scripts
14
+
15
+ - **dev** – Start the development server
16
+ - **build** – Build for production
17
+ - **preview** – Preview the production build locally
18
+
19
+ ## Structure
20
+
21
+ - **packages/app** – The Lyra app (entry point, extensions, UI)
22
+ - **packages/example-extension** – Example extension; use it as a reference to add your own
@@ -0,0 +1,4 @@
1
+ node_modules
2
+ dist
3
+ *.local
4
+ .DS_Store
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "{{APP_NAME}}",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "workspaces": ["packages/*"],
6
+ "scripts": {
7
+ "dev": "npm run dev -w {{APP_NAME}}",
8
+ "build": "npm run build -w {{APP_NAME}}",
9
+ "preview": "npm run preview -w {{APP_NAME}}"
10
+ }
11
+ }
@@ -0,0 +1,16 @@
1
+ declare module 'vite-plugin-mkcert' {
2
+ import type { Plugin } from 'vite';
3
+ const plugin: () => Plugin;
4
+ export default plugin;
5
+ }
6
+
7
+ declare module 'vite-plugin-cross-origin-isolation' {
8
+ import type { Plugin } from 'vite';
9
+ const plugin: () => Plugin;
10
+ export default plugin;
11
+ }
12
+
13
+ declare module '@eclipse-lyra/core/vite-plugin-resolve-deps' {
14
+ import type { Plugin } from 'vite';
15
+ export function resolveDepVersionsPlugin(options?: { includeDevDependencies?: boolean }): Plugin;
16
+ }
@@ -0,0 +1,11 @@
1
+ <!doctype html>
2
+ <html lang="en" class="wa-dark">
3
+ <head>
4
+ <meta charset="UTF-8"/>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
+ <title>Loading...</title>
7
+ <script type="module" src="/src/main.ts"></script>
8
+ </head>
9
+ <body>
10
+ </body>
11
+ </html>
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "{{APP_NAME}}",
3
+ "version": "0.0.0",
4
+ "description": "{{APP_DESCRIPTION}}",
5
+ "type": "module",
6
+ "private": true,
7
+ "scripts": {
8
+ "dev": "vite",
9
+ "build": "vite build",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "@eclipse-lyra/core": "^0.x",
14
+ "@eclipse-lyra/extension-ai-system": "^0.x",
15
+ "@eclipse-lyra/extension-command-palette": "^0.x",
16
+ "@eclipse-lyra/extension-md-editor": "^0.x",
17
+ "@eclipse-lyra/extension-media-viewer": "^0.x",
18
+ "@eclipse-lyra/extension-memory-usage": "^0.x",
19
+ "@eclipse-lyra/extension-monaco-editor": "^0.x",
20
+ "@eclipse-lyra/extension-notebook": "^0.x",
21
+ "@eclipse-lyra/extension-python-runtime": "^0.x",
22
+ "@eclipse-lyra/extension-settings-tree": "^0.x",
23
+ "@eclipse-lyra/extension-utils": "^0.x",
24
+ "example-extension": "*",
25
+ "pace-js": "^1.2.4"
26
+ },
27
+ "devDependencies": {
28
+ "typescript": "^5.9.3",
29
+ "vite": "^7.1.12",
30
+ "vite-plugin-cross-origin-isolation": "^0.1.6",
31
+ "vite-plugin-mkcert": "^1.17.9"
32
+ },
33
+ "marketplace": {
34
+ "catalogUrls": [
35
+ "https://raw.githubusercontent.com/kispace-io/appspace-marketplace/main/catalogs/extensions.json",
36
+ "https://raw.githubusercontent.com/kispace-io/appspace-marketplace/main/catalogs/apps.json"
37
+ ]
38
+ }
39
+ }
@@ -0,0 +1,12 @@
1
+ <svg width="140" height="32" viewBox="0 0 140 40" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
2
+ <g transform="translate(4, 4)">
3
+ <rect x="16" y="6" width="8" height="8" rx="1.5" fill="#0d6efd"/>
4
+ <g transform="rotate(-12, 20, 20)">
5
+ <rect x="17" y="15" width="6" height="6" rx="1" fill="#e9ecef" stroke="#6b7280" stroke-width="0.5"/>
6
+ <rect x="9" y="17" width="6" height="6" rx="1" fill="#e9ecef" stroke="#6b7280" stroke-width="0.5"/>
7
+ <rect x="17" y="25" width="6" height="6" rx="1" fill="#e9ecef" stroke="#6b7280" stroke-width="0.5"/>
8
+ <rect x="25" y="17" width="6" height="6" rx="1" fill="#e9ecef" stroke="#6b7280" stroke-width="0.5"/>
9
+ </g>
10
+ </g>
11
+ <text x="45" y="23" font-family="system-ui, sans-serif" font-size="14" font-weight="600" fill="#0d6efd">Eclipse Lyra</text>
12
+ </svg>
@@ -0,0 +1,42 @@
1
+ import Pace from 'pace-js';
2
+ import 'pace-js/themes/blue/pace-theme-minimal.css';
3
+
4
+ Pace.start();
5
+
6
+ import '@eclipse-lyra/extension-md-editor';
7
+ import '@eclipse-lyra/extension-media-viewer';
8
+ import '@eclipse-lyra/extension-memory-usage';
9
+ import '@eclipse-lyra/extension-monaco-editor';
10
+ import '@eclipse-lyra/extension-settings-tree';
11
+ import '@eclipse-lyra/extension-utils';
12
+ import '@eclipse-lyra/extension-ai-system';
13
+ import '@eclipse-lyra/extension-command-palette';
14
+ import '@eclipse-lyra/extension-notebook';
15
+ import '@eclipse-lyra/extension-python-runtime';
16
+
17
+ import 'example-extension';
18
+
19
+ import { appLoaderService, contributionRegistry, type HTMLContribution, TOOLBAR_MAIN } from '@eclipse-lyra/core';
20
+
21
+ contributionRegistry.registerContribution(TOOLBAR_MAIN, {
22
+ label: 'Brand',
23
+ slot: 'start',
24
+ component: '<span style="margin-right: 1rem;">{{APP_NAME}}</span>',
25
+ } as HTMLContribution);
26
+
27
+ appLoaderService.registerApp(
28
+ {
29
+ extensions: [
30
+ '@eclipse-lyra/extension-utils',
31
+ '@eclipse-lyra/extension-command-palette',
32
+ '@eclipse-lyra/extension-md-editor',
33
+ '@eclipse-lyra/extension-monaco-editor',
34
+ '@eclipse-lyra/extension-media-viewer',
35
+ '@eclipse-lyra/extension-settings-tree',
36
+ '@eclipse-lyra/extension-memory-usage',
37
+ '@eclipse-lyra/extension-ai-system',
38
+ 'example-extension',
39
+ ],
40
+ },
41
+ { autoStart: true, hostConfig: true }
42
+ );
@@ -0,0 +1,8 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ declare const __RESOLVED_PACKAGE_INFO__: { name: string; version: string; dependencies: Record<string, string> } | undefined;
4
+
5
+ declare module "pace-js" {
6
+ const Pace: { start: (options?: unknown) => void };
7
+ export default Pace;
8
+ }
@@ -0,0 +1,37 @@
1
+ import { defineConfig } from 'vite';
2
+ import mkcert from 'vite-plugin-mkcert';
3
+ import crossOriginIsolation from 'vite-plugin-cross-origin-isolation';
4
+ import { resolveDepVersionsPlugin } from '@eclipse-lyra/core/vite-plugin-resolve-deps';
5
+ import path from 'path';
6
+ import { fileURLToPath } from 'url';
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+
10
+ export default defineConfig({
11
+ root: __dirname,
12
+ base: process.env.VITE_BASE_PATH || '/',
13
+ resolve: {},
14
+ optimizeDeps: {
15
+ include: ['@eclipse-lyra/core'],
16
+ },
17
+ plugins: [resolveDepVersionsPlugin(), mkcert(), crossOriginIsolation()],
18
+ esbuild: {
19
+ tsconfigRaw: {
20
+ compilerOptions: {
21
+ experimentalDecorators: true,
22
+ useDefineForClassFields: false,
23
+ },
24
+ },
25
+ },
26
+ worker: {
27
+ format: 'es',
28
+ },
29
+ build: {
30
+ outDir: path.resolve(__dirname, 'dist'),
31
+ rollupOptions: {
32
+ input: {
33
+ main: path.resolve(__dirname, 'index.html'),
34
+ },
35
+ },
36
+ },
37
+ });
@@ -0,0 +1,18 @@
1
+ # example-extension
2
+
3
+ Example Eclipse Lyra extension that adds a view to the **left side panel** – the same tab bar as **Workspace** (file browser). You get an "Example" tab next to the workspace; use it as a reference to build your own extensions.
4
+
5
+ ## What it does
6
+
7
+ - Registers an extension with the Lyra extension registry.
8
+ - Contributes a tab to `SIDEBAR_MAIN` (the left sidebar). The "Example" view appears in the same folder as the Workspace / file browser tab; switch between them via the sidebar icons.
9
+ - The tab content is a minimal HTML snippet; you can replace it with your own UI.
10
+
11
+ ## Files
12
+
13
+ - **src/index.ts** – Registers the extension (`extensionRegistry.registerExtension`) and points to the loader.
14
+ - **src/example-extension-loader.ts** – Loaded when the extension starts. Registers a `TabContribution` to `SIDEBAR_MAIN` with name, label, icon, and component.
15
+
16
+ ## Extending
17
+
18
+ Copy this package or add new contributions in the loader (e.g. more tabs, or contributions to other slots like `TOOLBAR_MAIN_RIGHT`). See [@eclipse-lyra/core](https://github.com/eclipse-lyra/core) and published extensions (e.g. `@eclipse-lyra/extension-utils`) for more patterns.
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "example-extension",
3
+ "version": "0.0.0",
4
+ "type": "module",
5
+ "main": "./src/index.ts",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./src/index.ts",
9
+ "import": "./src/index.ts"
10
+ }
11
+ },
12
+ "dependencies": {
13
+ "@eclipse-lyra/core": "^0.x"
14
+ },
15
+ "devDependencies": {
16
+ "typescript": "^5.9.3",
17
+ "vite": "^7.1.12"
18
+ },
19
+ "scripts": {
20
+ "build": "vite build"
21
+ }
22
+ }
@@ -0,0 +1,19 @@
1
+ import { html } from '@eclipse-lyra/core/externals/lit';
2
+ import { contributionRegistry, SIDEBAR_MAIN } from '@eclipse-lyra/core';
3
+ import type { TabContribution } from '@eclipse-lyra/core';
4
+
5
+ contributionRegistry.registerContribution(SIDEBAR_MAIN, {
6
+ name: 'example-view',
7
+ label: 'Example',
8
+ icon: 'puzzle-piece',
9
+ closable: true,
10
+ toolbar: false,
11
+ component: (_id: string) => html`
12
+ <div style="padding: var(--wa-space-l);">
13
+ <h2>Example extension</h2>
14
+ <p>This view is contributed by the <code>example-extension</code> package to the left side panel.</p>
15
+ </div>
16
+ `,
17
+ } as TabContribution);
18
+
19
+ export default function exampleExtensionLoader() {}
@@ -0,0 +1,9 @@
1
+ import { extensionRegistry } from '@eclipse-lyra/core';
2
+
3
+ extensionRegistry.registerExtension({
4
+ id: 'example-extension',
5
+ name: 'Example',
6
+ description: 'Example extension showing how to add a view to the left side panel',
7
+ loader: () => import('./example-extension-loader'),
8
+ icon: 'puzzle-piece',
9
+ });
@@ -0,0 +1,12 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "skipLibCheck": true,
8
+ "experimentalDecorators": true,
9
+ "useDefineForClassFields": false
10
+ },
11
+ "include": ["src/**/*"]
12
+ }
@@ -0,0 +1,18 @@
1
+ import { defineConfig } from 'vite';
2
+ import path from 'path';
3
+ import { dirname } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const isExternal = (id: string): boolean =>
8
+ !id.startsWith('./') && !id.startsWith('../') && !(path.isAbsolute(id) && id.includes('/src/'));
9
+
10
+ export default defineConfig({
11
+ build: {
12
+ lib: { entry: path.resolve(__dirname, 'src/index.ts'), formats: ['es'], fileName: 'index' },
13
+ rollupOptions: { external: isExternal, output: { format: 'es' } },
14
+ outDir: 'dist',
15
+ sourcemap: true,
16
+ minify: false,
17
+ },
18
+ });