@boopkit/cli 0.1.0 → 0.1.1
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/package.json +3 -2
- package/src/templates/kernel/.github/copilot-instructions.md +3 -0
- package/src/templates/kernel/.gitignore.hbs +7 -0
- package/src/templates/kernel/AGENTS.md.hbs +28 -0
- package/src/templates/kernel/CLAUDE.md.hbs +3 -0
- package/src/templates/kernel/Procfile.hbs +1 -0
- package/src/templates/kernel/README.md.hbs +17 -0
- package/src/templates/kernel/package.json.hbs +16 -0
- package/src/templates/kernel/reference/boop-guide.ref.md +160 -0
- package/src/templates/kernel/specs/README.md +12 -0
- package/src/templates/kernel/src/app.ts.hbs +23 -0
- package/src/templates/kernel/src/lib/.gitkeep +0 -0
- package/src/templates/kernel/src/server.ts.hbs +3 -0
- package/src/templates/kernel/tsconfig.json.hbs +16 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boopkit/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "CLI tool to scaffold new projects from boop profiles and capabilities",
|
|
5
5
|
"main": "dist/cli.js",
|
|
6
6
|
"workspaces": [
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
13
|
"dist/",
|
|
14
|
-
"profiles/"
|
|
14
|
+
"profiles/",
|
|
15
|
+
"src/templates/"
|
|
15
16
|
],
|
|
16
17
|
"publishConfig": {
|
|
17
18
|
"access": "public"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# {{projectName}}
|
|
2
|
+
|
|
3
|
+
This is a **boop**-managed project. Use boop commands — don't reinvent what boop already provides.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. Run `boop status` to see what needs configuration
|
|
8
|
+
2. Follow the setup hints to configure your environment
|
|
9
|
+
3. Run `npm run dev` to start the development server
|
|
10
|
+
|
|
11
|
+
## How to work in this project
|
|
12
|
+
|
|
13
|
+
1. **Check skills first.** Before coding, reviewing, testing, or designing, check [skills/index.md](skills/index.md) for a matching skill and follow its process. Do not rely on general knowledge when a project skill exists.
|
|
14
|
+
2. **Use boop for capabilities.** To add features like database, auth, or other infrastructure, run `boop add <capability>` — don't install or wire things manually. Run `boop caps` to see what's available.
|
|
15
|
+
3. **Check project status.** Run `boop status` to see what's configured and what needs attention.
|
|
16
|
+
4. **Run `boop --help`** for the full command list.
|
|
17
|
+
|
|
18
|
+
## Boop extension model
|
|
19
|
+
|
|
20
|
+
Read [reference/boop-guide.ref.md](reference/boop-guide.ref.md) to understand how this project's services, controllers, and styles are structured — service tiers, factory patterns, the adoption curve (use → compose → adopt), and CSS extension.
|
|
21
|
+
|
|
22
|
+
## Project layout
|
|
23
|
+
- `src/` — source code
|
|
24
|
+
- `skills/` — process skills for agents (read `skills/index.md`)
|
|
25
|
+
- `reference/` — architecture and coding standards ("what exists now")
|
|
26
|
+
- `specs/` — design docs and specifications ("future state")
|
|
27
|
+
- `tests/` — `npm test` (Jest)
|
|
28
|
+
- `.boop/` — project manifest (managed by boop)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
web: npm start
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# {{projectName}}
|
|
2
|
+
|
|
3
|
+
A project scaffolded with [boop](https://github.com/boop).
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm run dev
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Scripts
|
|
13
|
+
|
|
14
|
+
- `npm start` — Start the application
|
|
15
|
+
- `npm run dev` — Start in development mode
|
|
16
|
+
- `npm run build` — Build the project
|
|
17
|
+
- `npm test` — Run tests
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": "{{nodeVersion}}"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"start": "{{scripts.start}}",
|
|
10
|
+
"dev": "{{scripts.dev}}",
|
|
11
|
+
"build": "{{scripts.build}}",
|
|
12
|
+
"test": "{{scripts.test}}"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {},
|
|
15
|
+
"devDependencies": {}
|
|
16
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Busy Agent's Guide to Boop
|
|
2
|
+
|
|
3
|
+
Quick orientation for AI agents working in a boop-generated project. Read this before modifying service code, controller logic, or styles.
|
|
4
|
+
|
|
5
|
+
**Deep dive**: If this project has `reference/application-services.ref.md`, it covers service tiers, factory internals, and controller patterns in full detail.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## How Boop Projects Work
|
|
10
|
+
|
|
11
|
+
Boop projects are built from **capabilities** — each one adds skills, npm packages, scaffolded files, or all three. The developer owns scaffolded files from day one. Packages (`@boopkit/*`) are managed dependencies that can be updated via npm — or adopted into the project when the developer outgrows them.
|
|
12
|
+
|
|
13
|
+
Key commands:
|
|
14
|
+
- `boop caps` — list available capabilities
|
|
15
|
+
- `boop add <capability>` — add a capability to the project
|
|
16
|
+
- `boop adopt <capability>` — copy package source into the project and take ownership
|
|
17
|
+
- `boop status` — check project configuration and what needs attention
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Service Tiers
|
|
22
|
+
|
|
23
|
+
Application logic is organized into four tiers. Dependency flows downward only.
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
Developer code ← project-owned, fully custom
|
|
27
|
+
→ Business services ← multi-step orchestration (e.g. postNotice)
|
|
28
|
+
→ Data services ← typed CRUD + lifecycle events (e.g. createNoticeService)
|
|
29
|
+
→ Entity primitives ← createEntityService, createPropertyService (@boopkit/cap-services)
|
|
30
|
+
→ Primitives ← middleware, DB helpers, validators
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
| Tier | In package? | npm updatable? | Typical relationship |
|
|
34
|
+
|------|-------------|----------------|---------------------|
|
|
35
|
+
| Primitives | Yes | Yes | Stable utilities — rarely replaced |
|
|
36
|
+
| Data services | Yes | Yes | Long-lived composable building blocks |
|
|
37
|
+
| Business services | Yes | Yes | Use until you outgrow, then adopt |
|
|
38
|
+
| Developer code | No | N/A | Fully owned from the start |
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Factory Pattern
|
|
43
|
+
|
|
44
|
+
Boop services export **factory functions** that return a bag of typed methods — not classes, not singletons.
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
const noticeService = createNoticeService<MyNoticeInfo>(store);
|
|
48
|
+
const { create, findById, list } = noticeService; // destructuring is safe
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Generic type params** let you extend the base entity shape. Set the type once at factory creation; type safety flows to every returned method:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
interface MyNoticeInfo extends BaseNoticeInfo {
|
|
55
|
+
priority: 'low' | 'medium' | 'high';
|
|
56
|
+
tags: string[];
|
|
57
|
+
}
|
|
58
|
+
const noticeService = createNoticeService<MyNoticeInfo>(store);
|
|
59
|
+
// All methods are now typed with MyNoticeInfo
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Lifecycle events** are optional callbacks passed to the factory. When provided, they fire on mutations. When omitted, they're no-ops:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
const noticeService = createNoticeService<MyNoticeInfo>(store, {
|
|
66
|
+
onCreated: async (notice) => { /* publish, log, index, etc. */ },
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## The Adoption Curve: Use → Compose → Adopt
|
|
73
|
+
|
|
74
|
+
Every boop service supports three levels of engagement. Move between them as needs evolve.
|
|
75
|
+
|
|
76
|
+
### 1. Use the box
|
|
77
|
+
Call the high-level method. Accept the defaults.
|
|
78
|
+
```typescript
|
|
79
|
+
const notice = await noticeBoardService.postNotice(input);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2. Compose the steps
|
|
83
|
+
Business services expose their sub-operations as public methods. Orchestrate them yourself, inserting custom logic between steps:
|
|
84
|
+
```typescript
|
|
85
|
+
noticeBoardService.validateContent(input);
|
|
86
|
+
const notice = await noticeBoardService.createNotice(input);
|
|
87
|
+
await myCustomApprovalWorkflow(notice); // your step
|
|
88
|
+
await noticeBoardService.notifySubscribers(notice);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**How to find decomposed operations**: Look at the convenience method's implementation — it calls the individual steps in sequence. Each step is a public method on the same service. JSDoc on each method explains what it does.
|
|
92
|
+
|
|
93
|
+
### 3. Adopt
|
|
94
|
+
Copy the package source into the project and own it:
|
|
95
|
+
```bash
|
|
96
|
+
boop adopt noticeboard
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
This copies `@boopkit/cap-noticeboard` source into `src/adopted/cap-noticeboard/`, rewrites all imports, removes the package dependency, and updates the manifest. From here, the developer maintains the code directly.
|
|
100
|
+
|
|
101
|
+
> **"Adopt" not "eject."** Adoption implies natural maturation — taking ownership of code that served you well.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Controller Handlers
|
|
106
|
+
|
|
107
|
+
Packages export **individual route handlers** as named functions, plus an optional **router factory**:
|
|
108
|
+
|
|
109
|
+
**Use the box** — mount the whole router:
|
|
110
|
+
```typescript
|
|
111
|
+
app.use('/noticeboard', createNoticeBoardRouter({ noticeBoardService }));
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Compose the steps** — pick individual handlers, add custom middleware:
|
|
115
|
+
```typescript
|
|
116
|
+
const handlers = createNoticeBoardHandlers({ noticeBoardService });
|
|
117
|
+
app.get('/noticeboard', handlers.listNotices);
|
|
118
|
+
app.post('/noticeboard', rateLimit(5), handlers.postNotice);
|
|
119
|
+
app.delete('/noticeboard/:id', requireAdmin, handlers.deleteNotice);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## CSS Extension
|
|
125
|
+
|
|
126
|
+
The project's `styles/styles.css` imports from packages in a layered cascade:
|
|
127
|
+
|
|
128
|
+
```css
|
|
129
|
+
@import "tailwindcss"; /* 1. Framework */
|
|
130
|
+
@import "@boopkit/cap-web/styles/theme.css"; /* 2. Design tokens */
|
|
131
|
+
@import "@boopkit/cap-web/styles/base.css"; /* 3. Base styles */
|
|
132
|
+
@import "@boopkit/cap-noticeboard/styles/..."; /* 4. Capability styles */
|
|
133
|
+
|
|
134
|
+
@theme { --color-brand-600: #059669; } /* 5. Project overrides */
|
|
135
|
+
.btn-primary { @apply shadow-lg; } /* 6. Component overrides */
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Design tokens** (`@theme`) generate Tailwind utilities automatically. Override a token → everything downstream updates.
|
|
139
|
+
|
|
140
|
+
**Package CSS is npm-updatable.** Boop ships new components that pick up the project's brand colors via tokens. Developers override any class by redeclaring it later in the file — CSS cascade handles precedence.
|
|
141
|
+
|
|
142
|
+
**The same adoption curve applies**: use the imports → override specific classes → drop the import and own the styles.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Project Structure at a Glance
|
|
147
|
+
|
|
148
|
+
| Directory | Owned by | Purpose |
|
|
149
|
+
|-----------|----------|---------|
|
|
150
|
+
| `src/services/` | Developer | Service wiring files (bridge factories to ServiceMap) |
|
|
151
|
+
| `src/routes/` | Developer | Route mounting (thin glue over handler sets) |
|
|
152
|
+
| `src/controllers/` | Developer | Project-specific controllers |
|
|
153
|
+
| `src/adopted/` | Developer | Adopted package source (created by `boop adopt`) |
|
|
154
|
+
| `styles/` | Developer | Project CSS (imports from packages + overrides) |
|
|
155
|
+
| `styles/adopted/` | Developer | Adopted package styles |
|
|
156
|
+
| `views/` | Developer | Handlebars templates (layouts, pages, partials) |
|
|
157
|
+
| `node_modules/@boopkit/*` | Package | Managed dependencies (updatable via npm) |
|
|
158
|
+
| `skills/` | Scaffolded | Agent skills (process guidance) |
|
|
159
|
+
| `reference/` | Scaffolded | Architecture docs |
|
|
160
|
+
| `.boop/config.json` | Boop | Project manifest (capabilities, adopted packages) |
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Specs
|
|
2
|
+
|
|
3
|
+
Design documents and specifications for planned features and changes. Specs describe the **future state** — what we intend to build — in contrast to `reference/` which documents the **current state**.
|
|
4
|
+
|
|
5
|
+
## Workflow
|
|
6
|
+
|
|
7
|
+
1. Write a spec for a new feature or significant change
|
|
8
|
+
2. Review and approve the spec
|
|
9
|
+
3. Create implementation tasks (in beads) from the approved spec
|
|
10
|
+
4. After shipping, update `reference/` docs to reflect the new reality
|
|
11
|
+
|
|
12
|
+
Specs remain as a record of design intent even after implementation.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// @boopkit:env
|
|
2
|
+
import express from 'express';
|
|
3
|
+
{{{hookImports}}}
|
|
4
|
+
|
|
5
|
+
const app = express();
|
|
6
|
+
const PORT = process.env.PORT || {{port}};
|
|
7
|
+
app.locals.projectName = '{{projectName}}';
|
|
8
|
+
|
|
9
|
+
app.use(express.json());
|
|
10
|
+
app.use(express.urlencoded({ extended: true }));
|
|
11
|
+
{{{hookPreRoutes}}}
|
|
12
|
+
|
|
13
|
+
{{{hookPostRoutes}}}
|
|
14
|
+
|
|
15
|
+
export async function boot() {
|
|
16
|
+
{{{hookInit}}}
|
|
17
|
+
|
|
18
|
+
app.listen(PORT, () => {
|
|
19
|
+
console.log(`{{projectName}} listening on port ${PORT}`);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default app;
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"outDir": "dist",
|
|
6
|
+
"rootDir": "src",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"declaration": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*"],
|
|
15
|
+
"exclude": ["node_modules", "dist"]
|
|
16
|
+
}
|