@lousy-agents/cli 1.1.0 → 2.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 +11 -12
- package/api/copilot-with-fastify/.devcontainer/devcontainer.json +90 -0
- package/api/copilot-with-fastify/.editorconfig +16 -0
- package/api/copilot-with-fastify/.github/ISSUE_TEMPLATE/feature-to-spec.yml +55 -0
- package/api/copilot-with-fastify/.github/copilot-instructions.md +387 -0
- package/api/copilot-with-fastify/.github/instructions/pipeline.instructions.md +149 -0
- package/api/copilot-with-fastify/.github/instructions/software-architecture.instructions.md +430 -0
- package/api/copilot-with-fastify/.github/instructions/spec.instructions.md +411 -0
- package/api/copilot-with-fastify/.github/instructions/test.instructions.md +268 -0
- package/api/copilot-with-fastify/.github/specs/README.md +84 -0
- package/api/copilot-with-fastify/.github/workflows/assign-copilot.yml +59 -0
- package/api/copilot-with-fastify/.github/workflows/ci.yml +88 -0
- package/api/copilot-with-fastify/.nvmrc +1 -0
- package/api/copilot-with-fastify/.vscode/extensions.json +14 -0
- package/api/copilot-with-fastify/.vscode/launch.json +30 -0
- package/api/copilot-with-fastify/.vscode/mcp.json +19 -0
- package/api/copilot-with-fastify/.yamllint +18 -0
- package/api/copilot-with-fastify/biome.json +31 -0
- package/api/copilot-with-fastify/package.json +37 -0
- package/api/copilot-with-fastify/tsconfig.json +34 -0
- package/api/copilot-with-fastify/vitest.config.ts +21 -0
- package/api/copilot-with-fastify/vitest.integration.config.ts +18 -0
- package/api/copilot-with-fastify/vitest.setup.ts +5 -0
- package/dist/commands/init.d.ts +2 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +39 -45
- package/dist/commands/init.js.map +1 -1
- package/dist/lib/config.d.ts +6 -5
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +186 -6
- package/dist/lib/config.js.map +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Specifications Directory
|
|
2
|
+
|
|
3
|
+
This directory contains feature specifications created through the spec-driven development workflow.
|
|
4
|
+
|
|
5
|
+
## Workflow Overview
|
|
6
|
+
|
|
7
|
+
1. **Create a Spec Issue** — Use the "Copilot Feature To Spec" issue template to define your feature
|
|
8
|
+
2. **Auto-Assignment** — Issues with the `copilot-ready` label automatically trigger Copilot assignment
|
|
9
|
+
3. **Spec Creation** — Copilot creates a structured specification in this directory
|
|
10
|
+
4. **Implementation** — Follow the tasks in the spec to implement the feature
|
|
11
|
+
|
|
12
|
+
## Spec File Structure
|
|
13
|
+
|
|
14
|
+
Each spec follows this structure:
|
|
15
|
+
|
|
16
|
+
```markdown
|
|
17
|
+
# Feature: <name>
|
|
18
|
+
|
|
19
|
+
## Problem Statement
|
|
20
|
+
<2-3 sentences describing the problem>
|
|
21
|
+
|
|
22
|
+
## Personas
|
|
23
|
+
| Persona | Impact | Notes |
|
|
24
|
+
|---------|--------|-------|
|
|
25
|
+
|
|
26
|
+
## Value Assessment
|
|
27
|
+
- **Primary value**: <type> — <explanation>
|
|
28
|
+
|
|
29
|
+
## User Stories
|
|
30
|
+
|
|
31
|
+
### Story 1: <Title>
|
|
32
|
+
As a **<persona>**,
|
|
33
|
+
I want **<capability>**,
|
|
34
|
+
so that I can **<outcome>**.
|
|
35
|
+
|
|
36
|
+
#### Acceptance Criteria
|
|
37
|
+
- When <trigger>, the <system> shall <response>
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Design
|
|
42
|
+
|
|
43
|
+
### Components Affected
|
|
44
|
+
### Dependencies
|
|
45
|
+
### Open Questions
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Tasks
|
|
50
|
+
|
|
51
|
+
### Task 1: <Title>
|
|
52
|
+
**Objective**: ...
|
|
53
|
+
**Verification**: ...
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## EARS Syntax for Acceptance Criteria
|
|
57
|
+
|
|
58
|
+
Use EARS (Easy Approach to Requirements Syntax) patterns:
|
|
59
|
+
|
|
60
|
+
| Pattern | Template | Use When |
|
|
61
|
+
|---------|----------|----------|
|
|
62
|
+
| Ubiquitous | The `<system>` shall `<response>` | Always true |
|
|
63
|
+
| Event-driven | When `<trigger>`, the `<system>` shall `<response>` | Responding to event |
|
|
64
|
+
| State-driven | While `<state>`, the `<system>` shall `<response>` | During a condition |
|
|
65
|
+
| Optional | Where `<feature>` is enabled, the `<system>` shall `<response>` | Configurable capability |
|
|
66
|
+
| Unwanted | If `<condition>`, then the `<system>` shall `<response>` | Error handling |
|
|
67
|
+
| Complex | While `<state>`, when `<trigger>`, the `<system>` shall `<response>` | Combining conditions |
|
|
68
|
+
|
|
69
|
+
### Examples
|
|
70
|
+
|
|
71
|
+
```markdown
|
|
72
|
+
- The API shall validate all input parameters
|
|
73
|
+
- When a user submits a form, the system shall display a success message
|
|
74
|
+
- While the server is under high load, the system shall queue requests
|
|
75
|
+
- Where manual approval is configured, the system shall pause deployment until approved
|
|
76
|
+
- If the request body is malformed, then the system shall return a 400 error
|
|
77
|
+
- While branch protection is enabled, when a push is attempted, the system shall reject unauthorized changes
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Related Files
|
|
81
|
+
|
|
82
|
+
- `.github/ISSUE_TEMPLATE/feature-to-spec.yml` — Issue template for creating specs
|
|
83
|
+
- `.github/workflows/assign-copilot.yml` — Workflow for auto-assigning Copilot
|
|
84
|
+
- `.github/instructions/spec.instructions.md` — Detailed instructions for spec writing
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Auto-Assign Copilot on Spec Issues
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
issues:
|
|
6
|
+
types: [opened, edited]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
issues: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
assign-agent:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- name: Assign and Instruct Copilot
|
|
16
|
+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
|
17
|
+
with:
|
|
18
|
+
script: |
|
|
19
|
+
const issue = context.payload.issue;
|
|
20
|
+
|
|
21
|
+
// Check if issue has the copilot-ready label
|
|
22
|
+
const hasCopilotLabel = issue.labels.some(label => label.name === 'copilot-ready');
|
|
23
|
+
|
|
24
|
+
if (!hasCopilotLabel) {
|
|
25
|
+
console.log("Issue does not have 'copilot-ready' label. Skipping.");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const body = issue.body || "";
|
|
30
|
+
const pattern = /### Extra Instructions\s+([\s\S]*?)(?=\n###|$)/;
|
|
31
|
+
const match = body.match(pattern);
|
|
32
|
+
|
|
33
|
+
// Always mention @copilot to trigger assignment and provide context
|
|
34
|
+
let comment = "@copilot";
|
|
35
|
+
|
|
36
|
+
if (match && match[1].trim().length > 0) {
|
|
37
|
+
let instructions = match[1].trim();
|
|
38
|
+
|
|
39
|
+
// Basic sanitization: limit length to prevent overly long comments
|
|
40
|
+
const MAX_LENGTH = 2000;
|
|
41
|
+
if (instructions.length > MAX_LENGTH) {
|
|
42
|
+
instructions = instructions.slice(0, MAX_LENGTH) + "\n\n[Instructions truncated]";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
comment = `@copilot ${instructions}`;
|
|
46
|
+
console.log("Found extra instructions, mentioning Copilot with instructions.");
|
|
47
|
+
} else {
|
|
48
|
+
comment = "@copilot Please work on this issue according to the specification provided.";
|
|
49
|
+
console.log("No extra instructions found, mentioning Copilot with default message.");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
await github.rest.issues.createComment({
|
|
53
|
+
owner: context.repo.owner,
|
|
54
|
+
repo: context.repo.repo,
|
|
55
|
+
issue_number: issue.number,
|
|
56
|
+
body: comment
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
console.log("Successfully mentioned Copilot in issue comment.");
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: CI
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
pull_request:
|
|
8
|
+
branches: [main]
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
lint:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- name: Checkout
|
|
18
|
+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
19
|
+
|
|
20
|
+
- name: Setup Node.js
|
|
21
|
+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
22
|
+
with:
|
|
23
|
+
node-version-file: '.nvmrc'
|
|
24
|
+
cache: 'npm'
|
|
25
|
+
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: npm ci
|
|
28
|
+
|
|
29
|
+
- name: Lint
|
|
30
|
+
run: npx biome check
|
|
31
|
+
|
|
32
|
+
unit-tests:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- name: Checkout
|
|
36
|
+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
37
|
+
|
|
38
|
+
- name: Setup Node.js
|
|
39
|
+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
40
|
+
with:
|
|
41
|
+
node-version-file: '.nvmrc'
|
|
42
|
+
cache: 'npm'
|
|
43
|
+
|
|
44
|
+
- name: Install dependencies
|
|
45
|
+
run: npm ci
|
|
46
|
+
|
|
47
|
+
- name: Run unit tests
|
|
48
|
+
run: npm test
|
|
49
|
+
|
|
50
|
+
integration-tests:
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
steps:
|
|
53
|
+
- name: Checkout
|
|
54
|
+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
55
|
+
|
|
56
|
+
- name: Setup Node.js
|
|
57
|
+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
58
|
+
with:
|
|
59
|
+
node-version-file: '.nvmrc'
|
|
60
|
+
cache: 'npm'
|
|
61
|
+
|
|
62
|
+
- name: Install dependencies
|
|
63
|
+
run: npm ci
|
|
64
|
+
|
|
65
|
+
- name: Run integration tests
|
|
66
|
+
run: npm run test:integration
|
|
67
|
+
env:
|
|
68
|
+
# Testcontainers will pull and manage PostgreSQL container
|
|
69
|
+
TESTCONTAINERS_RYUK_DISABLED: false
|
|
70
|
+
|
|
71
|
+
build:
|
|
72
|
+
runs-on: ubuntu-latest
|
|
73
|
+
needs: [lint, unit-tests, integration-tests]
|
|
74
|
+
steps:
|
|
75
|
+
- name: Checkout
|
|
76
|
+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
77
|
+
|
|
78
|
+
- name: Setup Node.js
|
|
79
|
+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
80
|
+
with:
|
|
81
|
+
node-version-file: '.nvmrc'
|
|
82
|
+
cache: 'npm'
|
|
83
|
+
|
|
84
|
+
- name: Install dependencies
|
|
85
|
+
run: npm ci
|
|
86
|
+
|
|
87
|
+
- name: Build
|
|
88
|
+
run: npm run build
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
v24.12.0
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"recommendations": [
|
|
3
|
+
"biomejs.biome",
|
|
4
|
+
"editorconfig.editorconfig",
|
|
5
|
+
"vitest.explorer",
|
|
6
|
+
"ms-vscode-remote.remote-containers",
|
|
7
|
+
"GitHub.codespaces",
|
|
8
|
+
"GitHub.Copilot",
|
|
9
|
+
"GitHub.Copilot-Chat",
|
|
10
|
+
"GitHub.github-vscode-theme",
|
|
11
|
+
"redhat.vscode-yaml",
|
|
12
|
+
"ms-azuretools.vscode-docker"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.2.0",
|
|
3
|
+
"configurations": [
|
|
4
|
+
{
|
|
5
|
+
"name": "Start API Locally",
|
|
6
|
+
"type": "node",
|
|
7
|
+
"request": "launch",
|
|
8
|
+
"runtimeExecutable": "npm",
|
|
9
|
+
"runtimeArgs": ["run", "dev"],
|
|
10
|
+
"console": "integratedTerminal",
|
|
11
|
+
"cwd": "${workspaceFolder}",
|
|
12
|
+
"serverReadyAction": {
|
|
13
|
+
"pattern": "Server listening on port ([0-9]+)",
|
|
14
|
+
"uriFormat": "http://localhost:%s/health",
|
|
15
|
+
"action": "openExternally"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "Debug Current Test File",
|
|
20
|
+
"type": "node",
|
|
21
|
+
"request": "launch",
|
|
22
|
+
"autoAttachChildProcesses": true,
|
|
23
|
+
"skipFiles": ["<node_internals>/**", "**/node_modules/**"],
|
|
24
|
+
"program": "${workspaceFolder}/node_modules/vitest/vitest.mjs",
|
|
25
|
+
"args": ["run", "${relativeFile}"],
|
|
26
|
+
"smartStep": true,
|
|
27
|
+
"console": "integratedTerminal"
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"servers": {
|
|
3
|
+
"context7": {
|
|
4
|
+
"type": "stdio",
|
|
5
|
+
"command": "npx",
|
|
6
|
+
"args": ["-y", "@upstash/context7-mcp"]
|
|
7
|
+
},
|
|
8
|
+
"sequential-thinking": {
|
|
9
|
+
"type": "stdio",
|
|
10
|
+
"command": "npx",
|
|
11
|
+
"args": ["-y", "@modelcontextprotocol/server-sequential-thinking"]
|
|
12
|
+
},
|
|
13
|
+
"lousy-agents": {
|
|
14
|
+
"type": "stdio",
|
|
15
|
+
"command": "npx",
|
|
16
|
+
"args": ["-y", "@lousy-agents/cli", "mcp"]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
extends: default
|
|
2
|
+
|
|
3
|
+
ignore: |
|
|
4
|
+
node_modules/
|
|
5
|
+
dist/
|
|
6
|
+
|
|
7
|
+
rules:
|
|
8
|
+
indentation:
|
|
9
|
+
spaces: 2
|
|
10
|
+
indent-sequences: true
|
|
11
|
+
line-length:
|
|
12
|
+
max: 120
|
|
13
|
+
level: warning
|
|
14
|
+
|
|
15
|
+
document-start: disable
|
|
16
|
+
truthy: disable
|
|
17
|
+
comments:
|
|
18
|
+
min-spaces-from-content: 1
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"root": false,
|
|
3
|
+
"$schema": "https://biomejs.dev/schemas/2.3.11/schema.json",
|
|
4
|
+
"vcs": {
|
|
5
|
+
"enabled": true,
|
|
6
|
+
"clientKind": "git",
|
|
7
|
+
"useIgnoreFile": true
|
|
8
|
+
},
|
|
9
|
+
"files": {
|
|
10
|
+
"ignoreUnknown": false
|
|
11
|
+
},
|
|
12
|
+
"formatter": {
|
|
13
|
+
"enabled": true,
|
|
14
|
+
"indentStyle": "space",
|
|
15
|
+
"indentWidth": 4
|
|
16
|
+
},
|
|
17
|
+
"linter": {
|
|
18
|
+
"enabled": true,
|
|
19
|
+
"rules": {
|
|
20
|
+
"recommended": true,
|
|
21
|
+
"style": {
|
|
22
|
+
"useConsistentCurlyBraces": "error"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"javascript": {
|
|
27
|
+
"formatter": {
|
|
28
|
+
"quoteStyle": "double"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<%= it.projectName %>",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "tsx watch src/index.ts",
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"start": "node dist/index.js",
|
|
10
|
+
"test": "vitest run",
|
|
11
|
+
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
12
|
+
"lint": "biome check .",
|
|
13
|
+
"lint:fix": "biome check --write .",
|
|
14
|
+
"lint:workflows": "actionlint",
|
|
15
|
+
"lint:yaml": "yamllint .",
|
|
16
|
+
"db:migrate": "tsx src/db/migrate.ts"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@fastify/cors": "11.0.1",
|
|
20
|
+
"@fastify/sensible": "6.0.3",
|
|
21
|
+
"fastify": "5.4.0",
|
|
22
|
+
"kysely": "0.28.2",
|
|
23
|
+
"pino": "9.6.0",
|
|
24
|
+
"postgres": "3.4.7",
|
|
25
|
+
"zod": "3.25.56"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@biomejs/biome": "2.3.8",
|
|
29
|
+
"@testcontainers/postgresql": "10.25.0",
|
|
30
|
+
"@types/node": "22.16.4",
|
|
31
|
+
"chance": "1.1.12",
|
|
32
|
+
"testcontainers": "10.25.0",
|
|
33
|
+
"tsx": "4.20.3",
|
|
34
|
+
"typescript": "5.8.3",
|
|
35
|
+
"vitest": "4.0.15"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["ES2022"],
|
|
5
|
+
"module": "NodeNext",
|
|
6
|
+
"moduleResolution": "NodeNext",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"outDir": "./dist",
|
|
12
|
+
"rootDir": "./src",
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true,
|
|
16
|
+
"resolveJsonModule": true,
|
|
17
|
+
"noEmit": false,
|
|
18
|
+
"isolatedModules": true,
|
|
19
|
+
"noUnusedLocals": true,
|
|
20
|
+
"noUnusedParameters": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true,
|
|
22
|
+
"exactOptionalPropertyTypes": true,
|
|
23
|
+
"noImplicitReturns": true,
|
|
24
|
+
"noUncheckedIndexedAccess": true
|
|
25
|
+
},
|
|
26
|
+
"include": ["src/**/*.ts"],
|
|
27
|
+
"exclude": [
|
|
28
|
+
"node_modules",
|
|
29
|
+
"dist",
|
|
30
|
+
"**/*.test.ts",
|
|
31
|
+
"**/*.spec.ts",
|
|
32
|
+
"**/*.integration.ts"
|
|
33
|
+
]
|
|
34
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { defineConfig } from "vitest/config";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
environment: "node",
|
|
7
|
+
setupFiles: ["./vitest.setup.ts"],
|
|
8
|
+
include: ["src/**/*.test.ts"],
|
|
9
|
+
exclude: ["**/*.integration.ts"],
|
|
10
|
+
coverage: {
|
|
11
|
+
provider: "v8",
|
|
12
|
+
reporter: ["text", "json", "html"],
|
|
13
|
+
exclude: [
|
|
14
|
+
"node_modules/",
|
|
15
|
+
"dist/",
|
|
16
|
+
"**/*.test.ts",
|
|
17
|
+
"**/*.integration.ts",
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineConfig } from "vitest/config";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
environment: "node",
|
|
7
|
+
setupFiles: ["./vitest.setup.ts"],
|
|
8
|
+
include: ["src/**/*.integration.ts"],
|
|
9
|
+
testTimeout: 60000,
|
|
10
|
+
hookTimeout: 60000,
|
|
11
|
+
pool: "forks",
|
|
12
|
+
poolOptions: {
|
|
13
|
+
forks: {
|
|
14
|
+
singleFork: true,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
});
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export declare const PROJECT_TYPE_OPTIONS: ("
|
|
1
|
+
export declare const PROJECT_TYPE_OPTIONS: ("api" | "cli" | "webapp" | "graphql")[];
|
|
2
|
+
export declare const SUPPORTED_PROJECT_TYPES: readonly ["webapp", "api"];
|
|
2
3
|
export declare const initCommand: import("citty").CommandDef<{
|
|
3
4
|
kind: {
|
|
4
5
|
type: "string";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,oBAAoB,
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,oBAAoB,0CAA4B,CAAC;AAC9D,eAAO,MAAM,uBAAuB,4BAA6B,CAAC;AAoGlE,eAAO,MAAM,WAAW;;;;;;;;;EAyEtB,CAAC"}
|
package/dist/commands/init.js
CHANGED
|
@@ -4,8 +4,9 @@ import { z } from "zod";
|
|
|
4
4
|
import { getProjectStructure } from "../lib/config.js";
|
|
5
5
|
import { createFilesystemStructure, } from "../lib/filesystem-structure.js";
|
|
6
6
|
import { getProjectNameError, isValidProjectName, } from "../lib/project-name-validation.js";
|
|
7
|
-
const ProjectTypeSchema = z.enum(["
|
|
7
|
+
const ProjectTypeSchema = z.enum(["cli", "webapp", "api", "graphql"]);
|
|
8
8
|
export const PROJECT_TYPE_OPTIONS = ProjectTypeSchema.options;
|
|
9
|
+
export const SUPPORTED_PROJECT_TYPES = ["webapp", "api"];
|
|
9
10
|
const initArgs = {
|
|
10
11
|
kind: {
|
|
11
12
|
type: "string",
|
|
@@ -19,29 +20,28 @@ const initArgs = {
|
|
|
19
20
|
function formatErrorMessage(error) {
|
|
20
21
|
return error instanceof Error ? error.message : String(error);
|
|
21
22
|
}
|
|
22
|
-
async function
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
async function getValidatedProjectName(promptFn, existingName, projectTypeLabel, placeholder) {
|
|
24
|
+
const rawProjectName = existingName
|
|
25
|
+
? existingName
|
|
26
|
+
: await promptFn("What is your project name?", {
|
|
27
|
+
type: "text",
|
|
28
|
+
placeholder,
|
|
29
|
+
});
|
|
30
|
+
const projectName = typeof rawProjectName === "string" ? rawProjectName.trim() : "";
|
|
31
|
+
if (!projectName) {
|
|
32
|
+
consola.error(`Project name is required for ${projectTypeLabel} projects`);
|
|
33
|
+
throw new Error("Project name is required");
|
|
31
34
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
if (!isValidProjectName(projectName)) {
|
|
36
|
+
const errorMessage = getProjectNameError(projectName) || "Invalid npm package name";
|
|
37
|
+
consola.error(`Invalid project name: "${projectName}". ${errorMessage}`);
|
|
38
|
+
throw new Error(`Invalid project name. ${errorMessage}`);
|
|
35
39
|
}
|
|
40
|
+
return { projectName };
|
|
36
41
|
}
|
|
37
42
|
async function createWebappScaffolding(targetDir, templateContext) {
|
|
38
43
|
try {
|
|
39
|
-
// Load the webapp structure from configuration
|
|
40
44
|
const webappStructure = await getProjectStructure("webapp");
|
|
41
|
-
if (!webappStructure) {
|
|
42
|
-
consola.warn("No webapp project structure defined in configuration");
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
45
|
await createFilesystemStructure(webappStructure, targetDir, templateContext);
|
|
46
46
|
}
|
|
47
47
|
catch (error) {
|
|
@@ -49,6 +49,16 @@ async function createWebappScaffolding(targetDir, templateContext) {
|
|
|
49
49
|
throw error;
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
+
async function createRestApiScaffolding(targetDir, templateContext) {
|
|
53
|
+
try {
|
|
54
|
+
const restApiStructure = await getProjectStructure("api");
|
|
55
|
+
await createFilesystemStructure(restApiStructure, targetDir, templateContext);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
consola.error(`Failed to create REST API scaffolding: ${formatErrorMessage(error)}`);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
52
62
|
export const initCommand = defineCommand({
|
|
53
63
|
meta: {
|
|
54
64
|
name: "init",
|
|
@@ -56,22 +66,18 @@ export const initCommand = defineCommand({
|
|
|
56
66
|
},
|
|
57
67
|
args: initArgs,
|
|
58
68
|
run: async (context) => {
|
|
59
|
-
// Support dependency injection for testing via context.data
|
|
60
|
-
// Runtime checks for type safety
|
|
61
69
|
const targetDir = typeof context.data?.targetDir === "string"
|
|
62
70
|
? context.data.targetDir
|
|
63
71
|
: process.cwd();
|
|
64
72
|
const promptFn = typeof context.data?.prompt === "function"
|
|
65
73
|
? context.data.prompt
|
|
66
74
|
: consola.prompt.bind(consola);
|
|
67
|
-
// Use CLI argument if provided, otherwise prompt
|
|
68
75
|
const rawProjectType = context.args.kind
|
|
69
76
|
? context.args.kind
|
|
70
77
|
: await promptFn("What type of project are you initializing?", {
|
|
71
78
|
type: "select",
|
|
72
|
-
options:
|
|
79
|
+
options: SUPPORTED_PROJECT_TYPES,
|
|
73
80
|
});
|
|
74
|
-
// Validate the user input at runtime
|
|
75
81
|
const parseResult = ProjectTypeSchema.safeParse(rawProjectType);
|
|
76
82
|
if (!parseResult.success) {
|
|
77
83
|
const validOptions = PROJECT_TYPE_OPTIONS.join(", ");
|
|
@@ -80,35 +86,23 @@ export const initCommand = defineCommand({
|
|
|
80
86
|
}
|
|
81
87
|
const projectType = parseResult.data;
|
|
82
88
|
consola.success(`Selected project type: ${projectType}`);
|
|
83
|
-
if (projectType === "
|
|
84
|
-
|
|
85
|
-
consola.info("CLI project scaffolding complete. Check the .github directory for instructions.");
|
|
89
|
+
if (projectType === "cli") {
|
|
90
|
+
throw new Error('Project type "cli" is not yet supported. Supported types: webapp, api');
|
|
86
91
|
}
|
|
87
92
|
else if (projectType === "webapp") {
|
|
88
|
-
|
|
89
|
-
const rawProjectName = context.args.name
|
|
90
|
-
? context.args.name
|
|
91
|
-
: await promptFn("What is your project name?", {
|
|
92
|
-
type: "text",
|
|
93
|
-
placeholder: "my-webapp",
|
|
94
|
-
});
|
|
95
|
-
const projectName = typeof rawProjectName === "string" ? rawProjectName.trim() : "";
|
|
96
|
-
if (!projectName) {
|
|
97
|
-
consola.error("Project name is required for webapp projects");
|
|
98
|
-
throw new Error("Project name is required");
|
|
99
|
-
}
|
|
100
|
-
if (!isValidProjectName(projectName)) {
|
|
101
|
-
const errorMessage = getProjectNameError(projectName) ||
|
|
102
|
-
"Invalid npm package name";
|
|
103
|
-
consola.error(`Invalid project name: "${projectName}". ${errorMessage}`);
|
|
104
|
-
throw new Error(`Invalid project name. ${errorMessage}`);
|
|
105
|
-
}
|
|
93
|
+
const { projectName } = await getValidatedProjectName(promptFn, context.args.name, "webapp", "my-webapp");
|
|
106
94
|
const templateContext = { projectName };
|
|
107
95
|
await createWebappScaffolding(targetDir, templateContext);
|
|
108
96
|
consola.info("Webapp project scaffolding complete. Run 'npm install' to install dependencies.");
|
|
109
97
|
}
|
|
98
|
+
else if (projectType === "api") {
|
|
99
|
+
const { projectName } = await getValidatedProjectName(promptFn, context.args.name, "REST API", "my-rest-api");
|
|
100
|
+
const templateContext = { projectName };
|
|
101
|
+
await createRestApiScaffolding(targetDir, templateContext);
|
|
102
|
+
consola.info("REST API project scaffolding complete. Run 'npm install' to install dependencies.");
|
|
103
|
+
}
|
|
110
104
|
else {
|
|
111
|
-
|
|
105
|
+
throw new Error('Project type "graphql" is not yet supported. Supported types: webapp, api');
|
|
112
106
|
}
|
|
113
107
|
},
|
|
114
108
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EACH,yBAAyB,GAE5B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACH,mBAAmB,EACnB,kBAAkB,GACrB,MAAM,mCAAmC,CAAC;AAE3C,MAAM,iBAAiB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|