Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 39 additions & 21 deletions .agents/rules/cli-commands.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,54 @@ description: CLI command patterns and development
The main CLI is defined in [bin/koapp.js](mdc:bin/koapp.js) and provides:

- `koapp init <app-name>` - Initialize new project
- `koapp gen` - Generate code/components
- `koapp http` - HTTP-related utilities
- `koapp http [dir]` - Serve a static directory over HTTP
- `koapp skills -i <cursor|claude>` - Install the bundled AI skills into a project

## Command Structure

Commands are implemented in the `commands/` directory:
Commands are implemented in the `commands/` directory and auto-loaded by
`@axiosleo/cli-tool` through the `commands_dir` option:

- [commands/init.js](mdc:commands/init.js) - Project initialization
- [commands/gen.js](mdc:commands/gen.js) - Code generation
- [commands/http.js](mdc:commands/http.js) - HTTP utilities
- [commands/http.js](mdc:commands/http.js) - Static HTTP server
- [commands/skills.js](mdc:commands/skills.js) - AI skills installer

Shared, testable helpers live in `src/cli/` (e.g. [src/cli/pnpm.js](mdc:src/cli/pnpm.js)
for Corepack / pnpm detection, [src/cli/pkg.js](mdc:src/cli/pkg.js) for
package-manager detection). Keep command files thin and put logic there.

## Project Initialization

The init command creates new projects using templates from `assets/tmpl/`:
The init command asks which template to generate (or takes `-t`):

```bash
npx @axiosleo/koapp init <app-name> -d <optional-dir>
npx @axiosleo/koapp init <app-name> [-d <optional-dir>] [-t simple-ts|simple-js|monorepo]
```

This generates:
| Template | Source | Result |
| --- | --- | --- |
| `simple-ts` (default) | `assets/simple/ts/` | One TypeScript HTTP service and sample routes. No database. |
| `simple-js` | `assets/simple/js/` | The same service in CommonJS. No compile step. |
| `monorepo` | `assets/monorepo/` | pnpm workspace: `apps/services` (admin Session auth, `/openapi` Bearer Api-Key, SQLite), `packages/commands`, `bin/<app-name>.js` |

Every template also receives `.agents/skills/` copied from `assets/skills/`.
After writing files, init probes for pnpm (offering to install the pinned
version) and then offers to run `pnpm install` and `pnpm dev`.

- TypeScript service structure
- Database configuration
- Docker compose setup
- Package.json with dependencies
- Basic application structure
Template selection and file rendering live in [src/cli/scaffold.js](mdc:src/cli/scaffold.js)
so they can be tested without a prompt.

## Template System

Templates use `.tmpl` extension and are processed during project generation:
Templates use the `.tmpl` extension and are processed during project generation:

- `assets/tmpl/services/` - Service templates
- `assets/tmpl/database/` - Database setup
- `assets/tmpl/docker-compose.yml.tmpl` - Docker configuration
- `assets/tmpl/package.json.tmpl` - Package configuration
- `assets/simple/{ts,js}/**/*.tmpl` and `assets/monorepo/**/*.tmpl` - rendered
with `_render_with_file`, which replaces `${name}` with the app name; the
`.tmpl` suffix is stripped on output
- `assets/monorepo/bin/monoapp.js.tmpl` - renamed to `bin/<app-name>.js`
(monorepo template only)
- `assets/skills/` - copied verbatim into `<app>/.agents/skills/`
(`_sync` reback must stay off, or the copy writes back into this package)

## Command Development

Expand All @@ -53,15 +66,20 @@ When creating new CLI commands:
1. Create command file in `commands/` directory
2. Extend base Command class from `@axiosleo/cli-tool`
3. Implement `exec(args, options)` method
4. Register command in main CLI file
4. No manual registration is needed - every file under `commands/` is picked up
via `commands_dir` in `bin/koapp.js`

## Usage Examples

```bash
# Initialize new project
# Initialize new project (prompts for a template; default is simple-ts)
npx @axiosleo/koapp init my-app

# Initialize in specific directory
# Skip the prompt
npx @axiosleo/koapp init my-app -t simple-js
npx @axiosleo/koapp init my-app -t monorepo

# Initialize in a specific directory
npx @axiosleo/koapp init my-app -d ./projects

# Show help
Expand Down
5 changes: 3 additions & 2 deletions .agents/rules/development-workflow.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ Available in [package.json](mdc:package.json):
- Use clear, descriptive file names
- Follow existing patterns for consistency

### Templates (`assets/tmpl/`)
### Templates (`assets/monorepo/`, `assets/skills/`)

- Template files use `.tmpl` extension
- Template files use `.tmpl` extension; `${name}` is replaced with the app name during `koapp init`
- `assets/skills/` is copied verbatim into generated projects (`.agents/skills/`)
- Maintain template structure for project scaffolding
- Update templates when adding new features

Expand Down
4 changes: 2 additions & 2 deletions .agents/rules/socket-application.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const router = new Router("/", { /* ... */ });

const app = new SocketApplication({
routers: [router],
port: 8081,
port: 8801,
ping: {
open: true,
interval: 1000 * 10,
Expand Down Expand Up @@ -55,7 +55,7 @@ const router = new Router("/", { /* ... */ });

const app = new WebSocketApplication({
routers: [router],
port: 8081,
port: 8801,
ping: {
open: false,
interval: 1000 * 3,
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,16 @@ npm install @axiosleo/koapp

## Initialization

`koapp init` asks which project to generate. Pressing enter selects the simple TypeScript service. Pass `-t` to skip the prompt.

| Template | Flag | What you get |
| --- | --- | --- |
| Simple TypeScript app (default) | `-t simple-ts` | One koapp HTTP service and sample routes. No database. |
| Simple JavaScript app | `-t simple-js` | The same service in CommonJS, with no compile step. |
| Full monorepo | `-t monorepo` | pnpm workspace: admin Session API, Api-Keys, and SQLite. |

```bash
npx @axiosleo/koapp init <app-name> -d <optional-dir>
npx @axiosleo/koapp init <app-name> [-d <dir>] [-t simple-ts|simple-js|monorepo]

# Show help information
# npx @axiosleo/koapp init -h
Expand Down
6 changes: 3 additions & 3 deletions assets/monorepo/README.en.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ pnpm install
cp .env.example .env
# Edit .env and set at least ADMIN_PASSWORD

# Start the API in dev mode (default 0.0.0.0:8082)
# Start the API in dev mode (default 0.0.0.0:8801)
pnpm --filter ${name}-services run dev
```

Verify the service:

```bash
curl http://127.0.0.1:8082/api/health
curl http://127.0.0.1:8801/api/health
```

## Directory layout
Expand Down Expand Up @@ -159,7 +159,7 @@ Copy [`.env.example`](.env.example) to the monorepo root `.env` and adjust as ne

| Variable | Default | Description |
| --- | --- | --- |
| `API_PORT` | `8082` | HTTP listen port |
| `API_PORT` | `8801` | HTTP listen port |
| `APP_SECRET` | `${name}-dev-secret-change-me` | Application secret (config) |
| `SQLITE_PATH` | `./data/${name}.db` | Metadata DB path (relative to monorepo root, or the binary directory) |
| `ADMIN_USERNAME` | `admin` | Admin username |
Expand Down
6 changes: 3 additions & 3 deletions assets/monorepo/README.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ pnpm install
cp .env.example .env
# 编辑 .env,至少设置 ADMIN_PASSWORD

# 启动开发服务(默认 0.0.0.0:8082)
# 启动开发服务(默认 0.0.0.0:8801)
pnpm --filter ${name}-services run dev
```

验证服务:

```bash
curl http://127.0.0.1:8082/api/health
curl http://127.0.0.1:8801/api/health
```

## 目录结构
Expand Down Expand Up @@ -159,7 +159,7 @@ CLI 会读取仓库根目录 `.env`(如 `SQLITE_PATH`),与 API 进程共

| 变量 | 默认值 | 说明 |
| --- | --- | --- |
| `API_PORT` | `8082` | HTTP 监听端口 |
| `API_PORT` | `8801` | HTTP 监听端口 |
| `APP_SECRET` | `${name}-dev-secret-change-me` | 应用密钥(配置项) |
| `SQLITE_PATH` | `./data/${name}.db` | 元数据库路径(相对路径锚定到仓库根,或二进制同目录) |
| `ADMIN_USERNAME` | `admin` | 管理员用户名 |
Expand Down
5 changes: 5 additions & 0 deletions assets/simple/js/.env.example.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# HTTP listen port
# API_PORT=8801

# prod enables production mode (debug off). Anything else is local/dev.
# DEPLOY_ENV=local
6 changes: 6 additions & 0 deletions assets/simple/js/.gitignore.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/
dist/
.env
*.log
.DS_Store
coverage/
3 changes: 3 additions & 0 deletions assets/simple/js/.npmrc.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
registry=https://registry.npmmirror.com
shamefully-hoist=false
strict-peer-dependencies=false
1 change: 1 addition & 0 deletions assets/simple/js/.nvmrc.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24.8.0
9 changes: 9 additions & 0 deletions assets/simple/js/AGENTS.md.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# ${name}

简易 koapp HTTP 服务(JavaScript / CommonJS,pnpm,Node >= 20)。无数据库,无需编译。

- 入口:`src/bootstrap.js`,应用类 `src/app.js`,配置 `src/config.js`
- 路由:`src/routes/index.js` 挂载 `src/routes/example.router.js`
- 默认端口 `8801`(`API_PORT`)
- `pnpm dev` 或 `pnpm start`
- koapp API 见 `.agents/skills/koapp*`
62 changes: 62 additions & 0 deletions assets/simple/js/README.md.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# ${name}

基于 [@axiosleo/koapp](https://github.com/AxiosLeo/node-koapp) 的简易 HTTP 接口服务(JavaScript / CommonJS)。只包含示例路由,不包含数据库,无需编译。

## 环境要求

- Node.js `>= 20`
- pnpm `>= 10`

## 快速开始

```bash
pnpm install
cp .env.example .env # 可选
pnpm dev # http://127.0.0.1:8801
```

直接启动:

```bash
pnpm start
```

## 目录

```
src/
bootstrap.js # 进程入口
app.js # KoaApplication
config.js # 读取 .env
routes/index.js # 根路由:请求日志、404 兜底
routes/example.router.js
```

## 示例路由

| 方法 | 路径 | 说明 |
| --- | --- | --- |
| `GET` | `/` | `success('hello, world!')` |
| `GET` | `/health` | `{ status: 'ok' }` |
| `GET`/`POST` | `/multi` | 多方法,回显 method |
| `GET` | `/a/{:a}/b/{:b}` | 路径参数 |
| `ANY` | `/any` | 任意方法,回显 params / query / body |
| `ANY` | `/error` | 抛错,框架转为 500 |
| `ANY` | `/failed` | `failed()`,HTTP 403 |
| `ANY` | `/result` | `result()` 自定义 header |
| `GET` | `/result/obj` | `result()` 返回对象 |
| `ANY` | `/success` | `success()` |
| `ANY` | `/html` | `text/html` |
| `ANY` | `/model` | `Model` 序列化 |
| `ANY` | `/model/error` | `Model` 校验失败 |
| `ANY` | `/validate/{:param1}/{:param2}` | params / query / body 校验 |
| `ANY` | `/sse` | Server-Sent Events |

未匹配的路径返回 404。

## 环境变量

| 变量 | 默认值 | 说明 |
| --- | --- | --- |
| `API_PORT` | `8801` | 监听端口 |
| `DEPLOY_ENV` | `local` | `prod` 时关闭 debug |
47 changes: 47 additions & 0 deletions assets/simple/js/eslint.config.mjs.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import js from '@eslint/js';
import globals from 'globals';

export default [
js.configs.recommended,
{
languageOptions: {
globals: {
...globals.node
},
ecmaVersion: 2020,
sourceType: 'commonjs'
},
rules: {
indent: [2, 2, { SwitchCase: 1 }],
quotes: [2, 'single'],
'linebreak-style': [2, 'unix'],
semi: [2, 'always'],
curly: 2,
eqeqeq: 2,
'no-eval': 2,
'guard-for-in': 2,
'no-caller': 2,
'no-else-return': 2,
'no-eq-null': 2,
'no-extend-native': 2,
'no-extra-bind': 2,
'no-floating-decimal': 2,
'no-implied-eval': 2,
'no-labels': 2,
'no-with': 2,
'no-loop-func': 2,
'no-redeclare': [2, { builtinGlobals: true }],
'no-delete-var': 2,
'no-shadow-restricted-names': 2,
'no-undef-init': 2,
'no-use-before-define': 2,
'no-unused-vars': [2, { args: 'none' }],
'no-undefined': 2,
'no-undef': 2,
'global-require': 0,
'no-console': 2,
'key-spacing': [2, { beforeColon: false, afterColon: true }],
'eol-last': [2, 'always']
}
}
];
5 changes: 5 additions & 0 deletions assets/simple/js/nodemon.json.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"watch": ["src"],
"exec": "node src/bootstrap.js",
"ext": "js"
}
28 changes: 28 additions & 0 deletions assets/simple/js/package.json.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "${name}",
"version": "0.0.1",
"private": true,
"description": "Simple koapp HTTP service",
"main": "src/bootstrap.js",
"packageManager": "pnpm@10.33.4",
"engines": {
"node": ">=20",
"pnpm": ">=10"
},
"scripts": {
"dev": "nodemon",
"start": "node src/bootstrap.js",
"lint": "eslint src/"
},
"dependencies": {
"@axiosleo/cli-tool": "^1.6.4",
"@axiosleo/koapp": "^1.3.3",
"dotenv": "^16.4.5"
},
"devDependencies": {
"@eslint/js": "^9.17.0",
"eslint": "^9.17.0",
"globals": "^15.14.0",
"nodemon": "^3.1.0"
}
}
24 changes: 24 additions & 0 deletions assets/simple/js/src/app.js.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';

const { KoaApplication } = require('@axiosleo/koapp');
const config = require('./config');
const routers = require('./routes');

class App extends KoaApplication {
constructor() {
const debugMode = config.envs.deploy !== 'prod';
super({
app_id: '${name}',
listen_host: '0.0.0.0',
debug: debugMode,
port: config.envs.port,
routers,
body_parser: {
enableTypes: ['json', 'form', 'text'],
encode: 'utf-8'
}
});
}
}

module.exports = App;
Loading
Loading