@kmlckj/licos-ai-cli 1.0.21 → 1.0.22

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.
@@ -5,7 +5,7 @@
5
5
  "scripts": {
6
6
  "build": "bash ./scripts/build.sh",
7
7
  "dev": "bash ./scripts/dev.sh",
8
- "ensure:deps": "node -e \"const fs=require('fs'); const bins=['node_modules/.bin/vite','node_modules/.bin/tsx','node_modules/.bin/tsup','node_modules/.bin/eslint','node_modules/.bin/tsc']; process.exit(bins.every((p)=>fs.existsSync(p)||fs.existsSync(p+'.cmd'))?0:1)\" || pnpm install --registry=https://registry.npmmirror.com --prefer-frozen-lockfile --prefer-offline --reporter=append-only || pnpm install --registry=https://registry.npmjs.org --no-frozen-lockfile --reporter=append-only",
8
+ "ensure:deps": "node -e \"const fs=require('fs'); const bins=['node_modules/.bin/vite','node_modules/.bin/tsx','node_modules/.bin/tsup','node_modules/.bin/eslint','node_modules/.bin/tsc']; process.exit(bins.every((p)=>fs.existsSync(p)||fs.existsSync(p+'.cmd'))?0:1)\" || pnpm install --registry=https://registry.npmmirror.com --prefer-frozen-lockfile --prefer-offline --reporter=append-only || pnpm install --registry=https://registry.npmjs.org --no-frozen-lockfile --reporter=append-only",
9
9
  "prebuild": "pnpm run ensure:deps",
10
10
  "predev": "pnpm run ensure:deps",
11
11
  "preinstall": "node -e \"const ua=process.env.npm_config_user_agent||''; if(!ua.includes('pnpm')){console.error('Use pnpm to install dependencies.'); process.exit(1)}\"",
@@ -1,70 +1,70 @@
1
- // ABOUTME: Express server with Vite integration
2
- // ABOUTME: Handles API routes and serves frontend in dev/prod modes
3
-
4
- import { createServer, type Server } from 'http';
5
- import express from 'express';
6
- import router from './routes/index';
7
- import { setupVite } from './vite';
8
-
9
- function isProdProjectEnv(value?: string): boolean {
10
- const normalized = value?.trim().toLowerCase();
11
- return normalized === 'prod' || normalized === 'production' || normalized === 'release';
12
- }
13
-
14
- const isDev = !isProdProjectEnv(process.env.LICOS_PROJECT_ENV);
15
- const port = parseInt(process.env.PORT || '<%= port %>', 10);
16
- const hostname = process.env.HOSTNAME || 'localhost';
17
- const app = express();
18
- // 使用 http.createServer 包装 Express app,以便支持 WebSocket 等协议升级
19
- const server = createServer(app);
20
-
21
- async function startServer(): Promise<Server> {
22
- // 请求日志(仅开发环境)
23
- if (isDev) {
24
- app.use((req, res, next) => {
25
- const start = Date.now();
26
- res.on('finish', () => {
27
- const ms = Date.now() - start;
28
- console.log(`${req.method} ${req.url} - ${ms}ms`);
29
- });
30
- next();
31
- });
32
- }
33
-
34
- // 添加请求体解析
35
- app.use(express.json());
36
- app.use(express.urlencoded({ extended: true }));
37
-
38
- // 注册 API 路由
39
- app.use(router);
40
-
41
- // 集成 Vite(开发模式)或静态文件服务(生产模式)
42
- await setupVite(app, server);
43
-
44
- // 全局错误处理
45
- app.use((err: Error, _req: express.Request, res: express.Response, _next: express.NextFunction) => {
46
- console.error('Server error:', err);
47
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
48
- const status = 'status' in err ? (err as any).status || 500 : 500;
49
- res.status(status).json({
50
- error: err.message || 'Internal server error',
51
- });
52
- });
53
-
54
- server.once('error', err => {
55
- console.error('Server error:', err);
56
- process.exit(1);
57
- });
58
-
59
- server.listen(port, () => {
60
- console.log(`\n✨ Server running at http://${hostname}:${port}`);
61
- console.log(`📝 Environment: ${isDev ? 'development' : 'production'}\n`);
62
- });
63
-
64
- return server;
65
- }
66
-
67
- startServer().catch(err => {
68
- console.error('Failed to start server:', err);
69
- process.exit(1);
70
- });
1
+ // ABOUTME: Express server with Vite integration
2
+ // ABOUTME: Handles API routes and serves frontend in dev/prod modes
3
+
4
+ import { createServer, type Server } from 'http';
5
+ import express from 'express';
6
+ import router from './routes/index';
7
+ import { setupVite } from './vite';
8
+
9
+ function isProdProjectEnv(value?: string): boolean {
10
+ const normalized = value?.trim().toLowerCase();
11
+ return normalized === 'prod' || normalized === 'production' || normalized === 'release';
12
+ }
13
+
14
+ const isDev = !isProdProjectEnv(process.env.LICOS_PROJECT_ENV);
15
+ const port = parseInt(process.env.PORT || '<%= port %>', 10);
16
+ const hostname = process.env.HOSTNAME || 'localhost';
17
+ const app = express();
18
+ // 使用 http.createServer 包装 Express app,以便支持 WebSocket 等协议升级
19
+ const server = createServer(app);
20
+
21
+ async function startServer(): Promise<Server> {
22
+ // 请求日志(仅开发环境)
23
+ if (isDev) {
24
+ app.use((req, res, next) => {
25
+ const start = Date.now();
26
+ res.on('finish', () => {
27
+ const ms = Date.now() - start;
28
+ console.log(`${req.method} ${req.url} - ${ms}ms`);
29
+ });
30
+ next();
31
+ });
32
+ }
33
+
34
+ // 添加请求体解析
35
+ app.use(express.json());
36
+ app.use(express.urlencoded({ extended: true }));
37
+
38
+ // 注册 API 路由
39
+ app.use(router);
40
+
41
+ // 集成 Vite(开发模式)或静态文件服务(生产模式)
42
+ await setupVite(app, server);
43
+
44
+ // 全局错误处理
45
+ app.use((err: Error, _req: express.Request, res: express.Response, _next: express.NextFunction) => {
46
+ console.error('Server error:', err);
47
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
48
+ const status = 'status' in err ? (err as any).status || 500 : 500;
49
+ res.status(status).json({
50
+ error: err.message || 'Internal server error',
51
+ });
52
+ });
53
+
54
+ server.once('error', err => {
55
+ console.error('Server error:', err);
56
+ process.exit(1);
57
+ });
58
+
59
+ server.listen(port, () => {
60
+ console.log(`\n✨ Server running at http://${hostname}:${port}`);
61
+ console.log(`📝 Environment: ${isDev ? 'development' : 'production'}\n`);
62
+ });
63
+
64
+ return server;
65
+ }
66
+
67
+ startServer().catch(err => {
68
+ console.error('Failed to start server:', err);
69
+ process.exit(1);
70
+ });
@@ -1,93 +1,93 @@
1
- // ABOUTME: Vite integration for Express server
2
- // ABOUTME: Handles dev middleware and production static file serving
3
-
4
- import type { Server } from 'http';
5
- import type { Application, Request, Response } from 'express';
6
- import express from 'express';
7
- import path from 'path';
8
- import fs from 'fs';
9
-
10
- function isProdProjectEnv(value?: string): boolean {
11
- const normalized = value?.trim().toLowerCase();
12
- return normalized === 'prod' || normalized === 'production' || normalized === 'release';
13
- }
14
-
15
- const isDev = !isProdProjectEnv(process.env.LICOS_PROJECT_ENV);
16
-
17
- function mountProjectAssets(app: Application) {
18
- const assetsPath = path.resolve(process.cwd(), 'assets');
19
- if (fs.existsSync(assetsPath)) {
20
- app.use('/assets', express.static(assetsPath));
21
- }
22
- }
23
-
24
- /**
25
- * 集成 Vite 开发服务器(中间件模式)
26
- */
27
- export async function setupViteMiddleware(app: Application, httpServer: Server) {
28
- const [{ createServer: createViteServer }, { default: viteConfig }] = await Promise.all([
29
- import('vite'),
30
- import('../vite.config'),
31
- ]);
32
-
33
- const vite = await createViteServer({
34
- ...viteConfig,
35
- server: {
36
- ...viteConfig.server,
37
- hmr:
38
- viteConfig.server?.hmr === false
39
- ? false
40
- : {
41
- ...(typeof viteConfig.server?.hmr === 'object' ? viteConfig.server.hmr : {}),
42
- server: httpServer,
43
- },
44
- middlewareMode: true,
45
- },
46
- appType: 'spa',
47
- });
48
-
49
- mountProjectAssets(app);
50
-
51
- // 使用 Vite middleware
52
- app.use(vite.middlewares);
53
-
54
- console.log('🚀 Vite dev server initialized');
55
- }
56
-
57
- /**
58
- * 设置生产环境静态文件服务
59
- */
60
- export function setupStaticServer(app: Application) {
61
- const distPath = path.resolve(process.cwd(), 'dist');
62
-
63
- if (!fs.existsSync(distPath)) {
64
- console.error('❌ dist folder not found. Please run "pnpm build" first.');
65
- process.exit(1);
66
- }
67
-
68
- // 1. 服务项目根 assets/ 和构建产物静态文件(如果存在对应文件则直接返回)
69
- mountProjectAssets(app);
70
- app.use(express.static(distPath));
71
-
72
- // 2. SPA fallback - 所有未处理的请求返回 index.html
73
- // 到达这里的请求说明:
74
- // - 不是 API 请求(已被前面注册的路由处理)
75
- // - 不是静态文件(express.static 未找到对应文件)
76
- // - 需要返回 index.html 让前端路由处理
77
- app.use((_req: Request, res: Response) => {
78
- res.sendFile(path.join(distPath, 'index.html'));
79
- });
80
-
81
- console.log('📦 Serving static files from dist/');
82
- }
83
-
84
- /**
85
- * 根据环境设置 Vite
86
- */
87
- export async function setupVite(app: Application, httpServer: Server) {
88
- if (isDev) {
89
- await setupViteMiddleware(app, httpServer);
90
- } else {
91
- setupStaticServer(app);
92
- }
93
- }
1
+ // ABOUTME: Vite integration for Express server
2
+ // ABOUTME: Handles dev middleware and production static file serving
3
+
4
+ import type { Server } from 'http';
5
+ import type { Application, Request, Response } from 'express';
6
+ import express from 'express';
7
+ import path from 'path';
8
+ import fs from 'fs';
9
+
10
+ function isProdProjectEnv(value?: string): boolean {
11
+ const normalized = value?.trim().toLowerCase();
12
+ return normalized === 'prod' || normalized === 'production' || normalized === 'release';
13
+ }
14
+
15
+ const isDev = !isProdProjectEnv(process.env.LICOS_PROJECT_ENV);
16
+
17
+ function mountProjectAssets(app: Application) {
18
+ const assetsPath = path.resolve(process.cwd(), 'assets');
19
+ if (fs.existsSync(assetsPath)) {
20
+ app.use('/assets', express.static(assetsPath));
21
+ }
22
+ }
23
+
24
+ /**
25
+ * 集成 Vite 开发服务器(中间件模式)
26
+ */
27
+ export async function setupViteMiddleware(app: Application, httpServer: Server) {
28
+ const [{ createServer: createViteServer }, { default: viteConfig }] = await Promise.all([
29
+ import('vite'),
30
+ import('../vite.config'),
31
+ ]);
32
+
33
+ const vite = await createViteServer({
34
+ ...viteConfig,
35
+ server: {
36
+ ...viteConfig.server,
37
+ hmr:
38
+ viteConfig.server?.hmr === false
39
+ ? false
40
+ : {
41
+ ...(typeof viteConfig.server?.hmr === 'object' ? viteConfig.server.hmr : {}),
42
+ server: httpServer,
43
+ },
44
+ middlewareMode: true,
45
+ },
46
+ appType: 'spa',
47
+ });
48
+
49
+ mountProjectAssets(app);
50
+
51
+ // 使用 Vite middleware
52
+ app.use(vite.middlewares);
53
+
54
+ console.log('🚀 Vite dev server initialized');
55
+ }
56
+
57
+ /**
58
+ * 设置生产环境静态文件服务
59
+ */
60
+ export function setupStaticServer(app: Application) {
61
+ const distPath = path.resolve(process.cwd(), 'dist');
62
+
63
+ if (!fs.existsSync(distPath)) {
64
+ console.error('❌ dist folder not found. Please run "pnpm build" first.');
65
+ process.exit(1);
66
+ }
67
+
68
+ // 1. 服务项目根 assets/ 和构建产物静态文件(如果存在对应文件则直接返回)
69
+ mountProjectAssets(app);
70
+ app.use(express.static(distPath));
71
+
72
+ // 2. SPA fallback - 所有未处理的请求返回 index.html
73
+ // 到达这里的请求说明:
74
+ // - 不是 API 请求(已被前面注册的路由处理)
75
+ // - 不是静态文件(express.static 未找到对应文件)
76
+ // - 需要返回 index.html 让前端路由处理
77
+ app.use((_req: Request, res: Response) => {
78
+ res.sendFile(path.join(distPath, 'index.html'));
79
+ });
80
+
81
+ console.log('📦 Serving static files from dist/');
82
+ }
83
+
84
+ /**
85
+ * 根据环境设置 Vite
86
+ */
87
+ export async function setupVite(app: Application, httpServer: Server) {
88
+ if (isDev) {
89
+ await setupViteMiddleware(app, httpServer);
90
+ } else {
91
+ setupStaticServer(app);
92
+ }
93
+ }
@@ -1,130 +1,130 @@
1
-
2
- import { spawn } from 'child_process';
3
- import { resolve, join, basename, dirname } from 'path';
4
- import { appendFileSync, openSync, closeSync, mkdirSync } from 'fs';
5
- import { fileURLToPath } from 'url';
6
-
7
- const __filename = fileURLToPath(import.meta.url);
8
- const __dirname = dirname(__filename);
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
- export const paramsSchema = {
19
- type: 'object',
20
- properties: {
21
- appName: {
22
- type: 'string',
23
- minLength: 1,
24
- pattern: '^[a-z0-9-]+$',
25
- description:
26
- 'Application name (lowercase, alphanumeric and hyphens only)',
27
- },
28
- port: {
29
- type: 'number',
30
- default: 5000,
31
- minimum: 1024,
32
- maximum: 65535,
33
- description: 'Development server port',
34
- },
35
- hmrPort: {
36
- type: 'number',
37
- default: 6000,
38
- minimum: 1024,
39
- maximum: 65535,
40
- description: 'Development HMR server port',
41
- },
42
- },
43
- required: [],
44
- additionalProperties: false,
45
- };
46
-
47
- const description = `Vite(简单项目):\`licos init \${LICOS_PROJECT_PATH} --template vite\`
48
- - 适用:轻量级 SPA、纯前端交互、仪表盘等轻量级项目。`;
49
-
50
- const config = {
51
- description: description,
52
- paramsSchema,
53
-
54
- defaultParams: {
55
- port: 5000,
56
- hmrPort: 6000,
57
- appName: 'projects',
58
- },
59
-
60
- onBeforeRender: async context => {
61
- console.log(
62
- `Creating Vanilla TypeScript + Vite project: ${context.appName}`,
63
- );
64
- return context;
65
- },
66
-
67
- onAfterRender: async (_context, outputPath) => {
68
- console.log(`\nProject created at: ${outputPath}`);
69
- console.log('\nConfiguration:');
70
- console.log(' - Framework: vite');
71
- console.log(' - TypeScript: enabled');
72
- console.log(' - App Router: enabled');
73
- console.log(` - Port: ${_context.port}`);
74
- },
75
-
76
- onComplete: async (_context, outputPath) => {
77
- if (process.env.NODE_ENV === 'test') {
78
- console.log('⊘ Skipping dependency install in test environment');
79
- return;
80
- }
81
- if (_context.options?.skipInstall) {
82
- console.log('⊘ Skipping dependency install because --skip-install was provided');
83
- return;
84
- }
85
-
86
- const cmd = 'bash';
87
- const args = [
88
- '-lc',
89
- 'pnpm install --registry=https://registry.npmmirror.com --prefer-frozen-lockfile --prefer-offline --reporter=append-only || pnpm install --registry=https://registry.npmjs.org --no-frozen-lockfile --reporter=append-only',
90
- ];
91
- console.log(
92
- `\nTriggering: ${cmd} ${args.join(' ')} (running in background)`,
93
- );
94
-
95
- try {
96
- const projectRoot = resolve(outputPath);
97
-
98
- const logDir = process.env.LICOS_LOG_DIR || resolve(__dirname, '../.log');
99
- mkdirSync(logDir, { recursive: true });
100
-
101
- const projectName = basename(projectRoot);
102
- const logFile = join(logDir, `${projectName}-init.log`);
103
-
104
- const timestamp = new Date().toISOString();
105
- appendFileSync(
106
- logFile,
107
- `\n=== [${timestamp}] ${cmd} ${args.join(' ')} ===\n`,
108
- );
109
-
110
- const logFd = openSync(logFile, 'a');
111
-
112
- const child = spawn(cmd, args, {
113
- cwd: projectRoot,
114
- detached: true,
115
- stdio: ['ignore', logFd, logFd],
116
- });
117
-
118
- child.unref();
119
- closeSync(logFd);
120
-
121
- console.log('✓ pnpm install triggered (running in background)');
122
- console.log(` Log file: ${logFile}`);
123
- } catch (error) {
124
- console.error('✗ Failed to trigger pnpm install:', error);
125
- console.log(' You can manually run: pnpm install --registry=https://registry.npmmirror.com || pnpm install --registry=https://registry.npmjs.org --no-frozen-lockfile');
126
- }
127
- },
128
- };
129
-
130
- export default config;
1
+
2
+ import { spawn } from 'child_process';
3
+ import { resolve, join, basename, dirname } from 'path';
4
+ import { appendFileSync, openSync, closeSync, mkdirSync } from 'fs';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+ export const paramsSchema = {
19
+ type: 'object',
20
+ properties: {
21
+ appName: {
22
+ type: 'string',
23
+ minLength: 1,
24
+ pattern: '^[a-z0-9-]+$',
25
+ description:
26
+ 'Application name (lowercase, alphanumeric and hyphens only)',
27
+ },
28
+ port: {
29
+ type: 'number',
30
+ default: 5000,
31
+ minimum: 1024,
32
+ maximum: 65535,
33
+ description: 'Development server port',
34
+ },
35
+ hmrPort: {
36
+ type: 'number',
37
+ default: 6000,
38
+ minimum: 1024,
39
+ maximum: 65535,
40
+ description: 'Development HMR server port',
41
+ },
42
+ },
43
+ required: [],
44
+ additionalProperties: false,
45
+ };
46
+
47
+ const description = `Vite(简单项目):\`licos init \${LICOS_PROJECT_PATH} --template vite\`
48
+ - 适用:轻量级 SPA、纯前端交互、仪表盘等轻量级项目。`;
49
+
50
+ const config = {
51
+ description: description,
52
+ paramsSchema,
53
+
54
+ defaultParams: {
55
+ port: 5000,
56
+ hmrPort: 6000,
57
+ appName: 'projects',
58
+ },
59
+
60
+ onBeforeRender: async context => {
61
+ console.log(
62
+ `Creating Vanilla TypeScript + Vite project: ${context.appName}`,
63
+ );
64
+ return context;
65
+ },
66
+
67
+ onAfterRender: async (_context, outputPath) => {
68
+ console.log(`\nProject created at: ${outputPath}`);
69
+ console.log('\nConfiguration:');
70
+ console.log(' - Framework: vite');
71
+ console.log(' - TypeScript: enabled');
72
+ console.log(' - App Router: enabled');
73
+ console.log(` - Port: ${_context.port}`);
74
+ },
75
+
76
+ onComplete: async (_context, outputPath) => {
77
+ if (process.env.NODE_ENV === 'test') {
78
+ console.log('⊘ Skipping dependency install in test environment');
79
+ return;
80
+ }
81
+ if (_context.options?.skipInstall) {
82
+ console.log('⊘ Skipping dependency install because --skip-install was provided');
83
+ return;
84
+ }
85
+
86
+ const cmd = 'bash';
87
+ const args = [
88
+ '-lc',
89
+ 'pnpm install --registry=https://registry.npmmirror.com --prefer-frozen-lockfile --prefer-offline --reporter=append-only || pnpm install --registry=https://registry.npmjs.org --no-frozen-lockfile --reporter=append-only',
90
+ ];
91
+ console.log(
92
+ `\nTriggering: ${cmd} ${args.join(' ')} (running in background)`,
93
+ );
94
+
95
+ try {
96
+ const projectRoot = resolve(outputPath);
97
+
98
+ const logDir = process.env.LICOS_LOG_DIR || resolve(__dirname, '../.log');
99
+ mkdirSync(logDir, { recursive: true });
100
+
101
+ const projectName = basename(projectRoot);
102
+ const logFile = join(logDir, `${projectName}-init.log`);
103
+
104
+ const timestamp = new Date().toISOString();
105
+ appendFileSync(
106
+ logFile,
107
+ `\n=== [${timestamp}] ${cmd} ${args.join(' ')} ===\n`,
108
+ );
109
+
110
+ const logFd = openSync(logFile, 'a');
111
+
112
+ const child = spawn(cmd, args, {
113
+ cwd: projectRoot,
114
+ detached: true,
115
+ stdio: ['ignore', logFd, logFd],
116
+ });
117
+
118
+ child.unref();
119
+ closeSync(logFd);
120
+
121
+ console.log('✓ pnpm install triggered (running in background)');
122
+ console.log(` Log file: ${logFile}`);
123
+ } catch (error) {
124
+ console.error('✗ Failed to trigger pnpm install:', error);
125
+ console.log(' You can manually run: pnpm install --registry=https://registry.npmmirror.com || pnpm install --registry=https://registry.npmjs.org --no-frozen-lockfile');
126
+ }
127
+ },
128
+ };
129
+
130
+ export default config;
package/lib/cli.js CHANGED
@@ -2109,7 +2109,7 @@ const EventBuilder = {
2109
2109
  };
2110
2110
 
2111
2111
  var name = "@kmlckj/licos-ai-cli";
2112
- var version = "1.0.21";
2112
+ var version = "1.0.22";
2113
2113
  var description = "LICOS AI coding workspace CLI - project template engine and dev tools";
2114
2114
  var license = "MIT";
2115
2115
  var author = "kmlckj";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kmlckj/licos-ai-cli",
3
- "version": "1.0.21",
3
+ "version": "1.0.22",
4
4
  "description": "LICOS AI coding workspace CLI - project template engine and dev tools",
5
5
  "license": "MIT",
6
6
  "author": "kmlckj",