@lousy-agents/cli 1.0.2 → 1.0.5
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 +9 -7
- package/ui/copilot-with-react/.devcontainer/devcontainer.json +90 -0
- package/ui/copilot-with-react/.editorconfig +16 -0
- package/ui/copilot-with-react/.github/ISSUE_TEMPLATE/feature-to-spec.yml +54 -0
- package/ui/copilot-with-react/.github/copilot-instructions.md +281 -0
- package/ui/copilot-with-react/.github/instructions/pipeline.instructions.md +46 -0
- package/ui/copilot-with-react/.github/instructions/software-architecture.instructions.md +401 -0
- package/ui/copilot-with-react/.github/instructions/spec.instructions.md +411 -0
- package/ui/copilot-with-react/.github/instructions/test.instructions.md +119 -0
- package/ui/copilot-with-react/.github/specs/README.md +84 -0
- package/ui/copilot-with-react/.github/workflows/assign-copilot.yml +59 -0
- package/ui/copilot-with-react/.github/workflows/copilot-setup-steps.yml +37 -0
- package/ui/copilot-with-react/.nvmrc +1 -0
- package/ui/copilot-with-react/.vscode/extensions.json +15 -0
- package/ui/copilot-with-react/.vscode/launch.json +19 -0
- package/ui/copilot-with-react/.yamllint +18 -0
- package/ui/copilot-with-react/biome.json +31 -0
- package/ui/copilot-with-react/next.config.ts +16 -0
- package/ui/copilot-with-react/package.json +41 -0
- package/ui/copilot-with-react/tsconfig.json +28 -0
- package/ui/copilot-with-react/vitest.config.ts +17 -0
- package/ui/copilot-with-react/vitest.setup.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lousy-agents/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "CLI scaffolding tool that sets up projects with structure, instructions, and feedback loops for AI coding assistants",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -23,15 +23,17 @@
|
|
|
23
23
|
"vibe-coding"
|
|
24
24
|
],
|
|
25
25
|
"publishConfig": {
|
|
26
|
-
"access": "public"
|
|
26
|
+
"access": "public",
|
|
27
|
+
"provenance": true
|
|
27
28
|
},
|
|
28
29
|
"files": [
|
|
29
|
-
"dist"
|
|
30
|
+
"dist",
|
|
31
|
+
"ui"
|
|
30
32
|
],
|
|
31
33
|
"bin": {
|
|
32
|
-
"cli": "
|
|
33
|
-
"lousy-agents": "
|
|
34
|
-
"lousy-agents-mcp": "
|
|
34
|
+
"cli": "dist/index.js",
|
|
35
|
+
"lousy-agents": "dist/index.js",
|
|
36
|
+
"lousy-agents-mcp": "dist/mcp-server.js"
|
|
35
37
|
},
|
|
36
38
|
"scripts": {
|
|
37
39
|
"dev": "tsx src/index.ts",
|
|
@@ -54,7 +56,7 @@
|
|
|
54
56
|
"zod": "4.3.6"
|
|
55
57
|
},
|
|
56
58
|
"devDependencies": {
|
|
57
|
-
"@biomejs/biome": "2.3.
|
|
59
|
+
"@biomejs/biome": "2.3.13",
|
|
58
60
|
"@types/chance": "1.1.7",
|
|
59
61
|
"@types/node": "24.10.4",
|
|
60
62
|
"chance": "1.1.13",
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<%= it.projectName %>",
|
|
3
|
+
"image": "mcr.microsoft.com/devcontainers/javascript-node:24-bookworm",
|
|
4
|
+
"features": {
|
|
5
|
+
"ghcr.io/devcontainers/features/github-cli:1": {
|
|
6
|
+
"version": "2.83.2"
|
|
7
|
+
},
|
|
8
|
+
"ghcr.io/rocker-org/devcontainer-features/apt-packages:1": {
|
|
9
|
+
"packages": "libnss3, libnspr4, libatk1.0-0, libatk-bridge2.0-0, libcups2, libdrm2, libdbus-1-3, libatspi2.0-0, libxcomposite1, libxdamage1, libxfixes3, libxrandr2, libgbm1, libxkbcommon0, libasound2, yamllint, shellcheck",
|
|
10
|
+
"upgradePackages": true
|
|
11
|
+
},
|
|
12
|
+
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {
|
|
13
|
+
"version": "27.5.1"
|
|
14
|
+
},
|
|
15
|
+
"ghcr.io/devcontainers-extra/features/actionlint:1": {
|
|
16
|
+
"version": "1.7.9"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"forwardPorts": [3000],
|
|
20
|
+
"portsAttributes": {
|
|
21
|
+
"3000": {
|
|
22
|
+
"label": "Application",
|
|
23
|
+
"onAutoForward": "notify"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"postCreateCommand": "npm cache add @upstash/context7-mcp @modelcontextprotocol/server-sequential-thinking",
|
|
27
|
+
"waitFor": "postCreateCommand",
|
|
28
|
+
"remoteUser": "node",
|
|
29
|
+
"customizations": {
|
|
30
|
+
"vscode": {
|
|
31
|
+
"extensions": [
|
|
32
|
+
"biomejs.biome",
|
|
33
|
+
"dbaeumer.vscode-eslint",
|
|
34
|
+
"editorconfig.editorconfig",
|
|
35
|
+
"vitest.explorer",
|
|
36
|
+
"ms-vscode-remote.remote-containers",
|
|
37
|
+
"GitHub.codespaces",
|
|
38
|
+
"ms-vscode.makefile-tools",
|
|
39
|
+
"GitHub.Copilot",
|
|
40
|
+
"GitHub.Copilot-Chat",
|
|
41
|
+
"GitHub.github-vscode-theme",
|
|
42
|
+
"redhat.vscode-yaml"
|
|
43
|
+
],
|
|
44
|
+
"settings": {
|
|
45
|
+
"editor.formatOnSave": true,
|
|
46
|
+
"editor.defaultFormatter": "biomejs.biome",
|
|
47
|
+
"[json]": {
|
|
48
|
+
"editor.defaultFormatter": "biomejs.biome"
|
|
49
|
+
},
|
|
50
|
+
"[javascript]": {
|
|
51
|
+
"editor.defaultFormatter": "biomejs.biome"
|
|
52
|
+
},
|
|
53
|
+
"[typescript]": {
|
|
54
|
+
"editor.defaultFormatter": "biomejs.biome"
|
|
55
|
+
},
|
|
56
|
+
"[yaml]": {
|
|
57
|
+
"editor.defaultFormatter": "redhat.vscode-yaml",
|
|
58
|
+
"editor.tabSize": 2
|
|
59
|
+
},
|
|
60
|
+
"editor.codeActionsOnSave": {
|
|
61
|
+
"source.fixAll.eslint": "explicit"
|
|
62
|
+
},
|
|
63
|
+
"vitest.enable": true,
|
|
64
|
+
"vitest.commandLine": "vitest",
|
|
65
|
+
"github.copilot.chat.agent.model": "claude-sonnet-4.5",
|
|
66
|
+
"github.copilot.chat.ask.model": "claude-sonnet-4.5",
|
|
67
|
+
"yaml.schemas": {
|
|
68
|
+
"https://json.schemastore.org/github-workflow.json": ".github/workflows/*.yml"
|
|
69
|
+
},
|
|
70
|
+
"github.copilot.chat.mcp.enabled": true
|
|
71
|
+
},
|
|
72
|
+
"mcp": {
|
|
73
|
+
"servers": {
|
|
74
|
+
"context7": {
|
|
75
|
+
"type": "stdio",
|
|
76
|
+
"command": "npx",
|
|
77
|
+
"args": ["-y", "@upstash/context7-mcp"]
|
|
78
|
+
},
|
|
79
|
+
"sequential-thinking": {
|
|
80
|
+
"command": "npx",
|
|
81
|
+
"args": [
|
|
82
|
+
"-y",
|
|
83
|
+
"@modelcontextprotocol/server-sequential-thinking"
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset = utf-8
|
|
5
|
+
end_of_line = lf
|
|
6
|
+
indent_size = 4
|
|
7
|
+
indent_style = space
|
|
8
|
+
insert_final_newline = true
|
|
9
|
+
max_line_length = off
|
|
10
|
+
trim_trailing_whitespace = true
|
|
11
|
+
|
|
12
|
+
[{*.json}]
|
|
13
|
+
indent_size = 4
|
|
14
|
+
|
|
15
|
+
[{*.yaml,*.yml}]
|
|
16
|
+
indent_size = 2
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Copilot Feature To Spec
|
|
3
|
+
description: Create a spec for the Copilot coding agent.
|
|
4
|
+
title: "[Spec]: "
|
|
5
|
+
labels: ["copilot-ready", "enhancement"]
|
|
6
|
+
body:
|
|
7
|
+
- type: markdown
|
|
8
|
+
attributes:
|
|
9
|
+
value: |
|
|
10
|
+
## Copilot Specification
|
|
11
|
+
Please fill out the details below.
|
|
12
|
+
This structure is parsed by the Copilot Agent.
|
|
13
|
+
|
|
14
|
+
- type: textarea
|
|
15
|
+
id: context
|
|
16
|
+
attributes:
|
|
17
|
+
label: Context & Goal
|
|
18
|
+
description: What is the goal? What part of the codebase?
|
|
19
|
+
placeholder: |
|
|
20
|
+
We need to add a rate-limiting middleware to the API
|
|
21
|
+
gateway...
|
|
22
|
+
validations:
|
|
23
|
+
required: true
|
|
24
|
+
|
|
25
|
+
- type: textarea
|
|
26
|
+
id: acceptance-criteria
|
|
27
|
+
attributes:
|
|
28
|
+
label: Acceptance Criteria
|
|
29
|
+
description: How will we verify this is done?
|
|
30
|
+
placeholder: |
|
|
31
|
+
I run `node dist/index.js init`.
|
|
32
|
+
I see a .github directory with ...
|
|
33
|
+
validations:
|
|
34
|
+
required: true
|
|
35
|
+
|
|
36
|
+
# ---------------------------------------------------------
|
|
37
|
+
# This section triggers the GitHub Script integration
|
|
38
|
+
# ---------------------------------------------------------
|
|
39
|
+
- type: textarea
|
|
40
|
+
id: extra-instructions
|
|
41
|
+
attributes:
|
|
42
|
+
label: Extra Instructions
|
|
43
|
+
description: Specific prompt engineering for the agent. This will be posted as a comment to guide the bot.
|
|
44
|
+
value: |
|
|
45
|
+
1. Review .github/instructions/spec.instructions.md for more details and use this as your guide for the feature specification.
|
|
46
|
+
2. Ensure you review all other repository instructions before starting work to understand engineering requirements.
|
|
47
|
+
3. Create your final spec output in the .github/specs directory and ensure requirements are captured in the EARS format.
|
|
48
|
+
4. Create a data flow diagram and sequence diagram to illustrate the feature's operation.
|
|
49
|
+
5. Break down the feature into manageable tasks with clear descriptions.
|
|
50
|
+
6. As you complete each task in the spec, mark the checkboxes as complete in the spec file using [x] notation.
|
|
51
|
+
7. If you need to make assumptions, ask questions on the issue.
|
|
52
|
+
8. Use the diagrams to inform your implementation plan.
|
|
53
|
+
validations:
|
|
54
|
+
required: false
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Next.js TDD Application
|
|
6
|
+
|
|
7
|
+
A Next.js TypeScript application following Test-Driven Development, Clean Architecture, and strict validation workflows.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
Run `nvm use` before any npm command. During development, use file-scoped commands for faster feedback, and run the full validation suite (`npx biome check && npm test && npm run build`) before commits.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# ALWAYS run first
|
|
15
|
+
nvm use
|
|
16
|
+
|
|
17
|
+
# Core commands
|
|
18
|
+
npm install # Install deps (updates package-lock.json)
|
|
19
|
+
npm test # Run tests (vitest)
|
|
20
|
+
npm run build # Production build
|
|
21
|
+
npx biome check # Lint check
|
|
22
|
+
npx biome check --write # Auto-fix lint/format
|
|
23
|
+
|
|
24
|
+
# File-scoped (faster feedback)
|
|
25
|
+
npx biome check path/to/file.ts
|
|
26
|
+
npm test path/to/file.test.ts
|
|
27
|
+
|
|
28
|
+
# Validation suite (run before commits)
|
|
29
|
+
npx biome check && npm test && npm run build
|
|
30
|
+
|
|
31
|
+
# Other
|
|
32
|
+
npm audit # Security check
|
|
33
|
+
npm run lint:workflows # Validate GitHub Actions (actionlint)
|
|
34
|
+
npm run lint:yaml # Validate YAML (yamllint)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Workflow: TDD Required
|
|
38
|
+
|
|
39
|
+
Follow this exact sequence for ALL code changes. Work in small increments — make one change at a time and validate before proceeding.
|
|
40
|
+
|
|
41
|
+
1. **Research**: Search codebase for existing patterns, components, utilities. Use Context7 MCP tools for library/API documentation.
|
|
42
|
+
2. **Write failing test**: Create test describing desired behavior
|
|
43
|
+
3. **Verify failure**: Run `npm test` — confirm clear failure message
|
|
44
|
+
4. **Implement minimal code**: Write just enough to pass
|
|
45
|
+
5. **Verify pass**: Run `npm test` — confirm pass
|
|
46
|
+
6. **Refactor**: Clean up, remove duplication, keep tests green
|
|
47
|
+
7. **Validate**: `npx biome check && npm test && npm run build`
|
|
48
|
+
|
|
49
|
+
Task is NOT complete until all validation passes.
|
|
50
|
+
|
|
51
|
+
## Tech Stack
|
|
52
|
+
|
|
53
|
+
- **Framework**: Next.js (React) — follow Next.js conventions
|
|
54
|
+
- **Language**: TypeScript (strict mode)
|
|
55
|
+
- **Validation**: Zod for runtime validation of external data
|
|
56
|
+
- **Testing**: Vitest (never Jest), MSW for HTTP mocking, Chance.js for test fixtures
|
|
57
|
+
- **Linting**: Biome (never ESLint/Prettier separately)
|
|
58
|
+
- **Logging**: Pino with JSON format and child loggers
|
|
59
|
+
- **HTTP**: fetch API only
|
|
60
|
+
- **Architecture**: Clean Architecture principles
|
|
61
|
+
|
|
62
|
+
## Project Structure
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
.github/ GitHub Actions workflows
|
|
66
|
+
src/ Application source code
|
|
67
|
+
components/ React components
|
|
68
|
+
pages/ Next.js pages and routes
|
|
69
|
+
lib/ Utilities and helpers
|
|
70
|
+
tests/ Test files (mirror src/ structure)
|
|
71
|
+
scripts/ Build, deploy, and test scripts
|
|
72
|
+
.nvmrc Node.js version (latest LTS)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Code Style
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { z } from 'zod';
|
|
79
|
+
|
|
80
|
+
// Define schema for runtime validation
|
|
81
|
+
const UserSchema = z.object({
|
|
82
|
+
id: z.string(),
|
|
83
|
+
name: z.string(),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
type User = z.infer<typeof UserSchema>;
|
|
87
|
+
|
|
88
|
+
// ✅ Good - small, typed, single purpose, descriptive names, runtime validation
|
|
89
|
+
async function fetchUserById(userId: string): Promise<User> {
|
|
90
|
+
if (!userId) {
|
|
91
|
+
throw new Error('User ID required');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const response = await fetch(`/api/users/${userId}`);
|
|
95
|
+
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
throw new Error(`Failed to fetch user: ${response.status}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const data: unknown = await response.json();
|
|
101
|
+
return UserSchema.parse(data);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ❌ Bad - untyped, type assertion on external data, no validation, multiple responsibilities, impure (side effects: global state mutation)
|
|
105
|
+
async function doStuff(x) {
|
|
106
|
+
console.log('fetching');
|
|
107
|
+
globalState.loading = true;
|
|
108
|
+
const response = await fetch('/api/users/' + x);
|
|
109
|
+
return response.json() as User;
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Rules:**
|
|
114
|
+
- Always use TypeScript type hints
|
|
115
|
+
- Use descriptive names for variables, functions, and modules
|
|
116
|
+
- Functions must be small and have single responsibility
|
|
117
|
+
- Avoid god functions and classes — break into smaller, focused units
|
|
118
|
+
- Avoid repetitive code — extract reusable functions
|
|
119
|
+
- Extract functions when there are multiple code paths
|
|
120
|
+
- Favor immutability and pure functions
|
|
121
|
+
- Avoid temporal coupling
|
|
122
|
+
- Keep cyclomatic complexity low
|
|
123
|
+
- Remove all unused imports and variables
|
|
124
|
+
- Validate external data at runtime with Zod — never use type assertions (`as Type`) on API responses
|
|
125
|
+
- Always check `response.ok` when using fetch
|
|
126
|
+
- Run lint and tests after EVERY change
|
|
127
|
+
|
|
128
|
+
## Testing Standards
|
|
129
|
+
|
|
130
|
+
Tests are executable documentation. Use Arrange-Act-Assert pattern. Mock HTTP with MSW. Generate test fixtures with Chance.js.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import Chance from 'chance';
|
|
134
|
+
import { http, HttpResponse } from 'msw';
|
|
135
|
+
import { setupServer } from 'msw/node';
|
|
136
|
+
import { beforeAll, afterAll, afterEach, describe, it, expect } from 'vitest';
|
|
137
|
+
import { fetchUserById } from './user-service';
|
|
138
|
+
|
|
139
|
+
const chance = new Chance();
|
|
140
|
+
const server = setupServer();
|
|
141
|
+
|
|
142
|
+
beforeAll(() => server.listen());
|
|
143
|
+
afterEach(() => server.resetHandlers());
|
|
144
|
+
afterAll(() => server.close());
|
|
145
|
+
|
|
146
|
+
// ✅ Good - describes behavior, reads like documentation, uses generated fixtures
|
|
147
|
+
describe('User retrieval', () => {
|
|
148
|
+
describe('given a valid user ID', () => {
|
|
149
|
+
it('returns the user details from the API', async () => {
|
|
150
|
+
// Arrange
|
|
151
|
+
const userId = chance.guid();
|
|
152
|
+
const expectedUser = { id: userId, name: chance.name() };
|
|
153
|
+
server.use(
|
|
154
|
+
http.get(`/api/users/${userId}`, () => {
|
|
155
|
+
return HttpResponse.json(expectedUser);
|
|
156
|
+
})
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
// Act
|
|
160
|
+
const result = await fetchUserById(userId);
|
|
161
|
+
|
|
162
|
+
// Assert
|
|
163
|
+
expect(result).toEqual(expectedUser);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('given an empty user ID', () => {
|
|
168
|
+
it('rejects with a validation error', async () => {
|
|
169
|
+
// Arrange - no server setup needed, validation happens before fetch
|
|
170
|
+
|
|
171
|
+
// Act & Assert
|
|
172
|
+
await expect(fetchUserById('')).rejects.toThrow('User ID required');
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe('given a non-existent user ID', () => {
|
|
177
|
+
it('rejects with an error containing the status code', async () => {
|
|
178
|
+
// Arrange
|
|
179
|
+
const userId = chance.guid();
|
|
180
|
+
server.use(
|
|
181
|
+
http.get(`/api/users/${userId}`, () => {
|
|
182
|
+
return new HttpResponse(null, { status: 404 });
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
// Act & Assert
|
|
187
|
+
await expect(fetchUserById(userId)).rejects.toThrow(
|
|
188
|
+
'Failed to fetch user: 404'
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
describe('given an invalid response shape', () => {
|
|
194
|
+
it('rejects with a validation error', async () => {
|
|
195
|
+
// Arrange
|
|
196
|
+
const userId = chance.guid();
|
|
197
|
+
server.use(
|
|
198
|
+
http.get(`/api/users/${userId}`, () => {
|
|
199
|
+
return HttpResponse.json({ invalid: 'data' });
|
|
200
|
+
})
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
// Act & Assert
|
|
204
|
+
await expect(fetchUserById(userId)).rejects.toThrow();
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// ❌ Bad - implementation-focused, hardcoded values, duplicated test data
|
|
210
|
+
describe('fetchUserById', () => {
|
|
211
|
+
it('works', async () => {
|
|
212
|
+
const user = { id: '123', name: 'Alice' };
|
|
213
|
+
server.use(
|
|
214
|
+
http.get('/api/users/123', () => HttpResponse.json(user))
|
|
215
|
+
);
|
|
216
|
+
const result = await fetchUserById('123'); // duplicated '123' across arrange/act/assert
|
|
217
|
+
expect(result).toEqual(user);
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Rules:**
|
|
223
|
+
- Tests are executable documentation — describe behavior, not implementation
|
|
224
|
+
- Name `describe` blocks for features/scenarios, not function names
|
|
225
|
+
- Name `it` blocks as specifications that read as complete sentences
|
|
226
|
+
- Use nested `describe` blocks for "given/when" context
|
|
227
|
+
- Use Chance.js to generate test fixtures — avoid hardcoded test data
|
|
228
|
+
- Extract test data to constants — never duplicate values across arrange/act/assert
|
|
229
|
+
- Use Vitest (never Jest)
|
|
230
|
+
- Mock HTTP with MSW (never mock fetch directly)
|
|
231
|
+
- Follow Arrange-Act-Assert pattern
|
|
232
|
+
- Tests must be deterministic — same result every run
|
|
233
|
+
- Reset handlers between tests for isolation
|
|
234
|
+
- Avoid conditional logic in tests unless absolutely necessary
|
|
235
|
+
- Ensure all code paths have corresponding tests
|
|
236
|
+
- Test happy paths, unhappy paths, and edge cases
|
|
237
|
+
- Never modify tests to pass without understanding root cause
|
|
238
|
+
|
|
239
|
+
## Dependencies
|
|
240
|
+
|
|
241
|
+
- Use latest LTS Node.js — check with `nvm ls-remote --lts`, update `.nvmrc`
|
|
242
|
+
- Pin ALL dependencies to exact versions (no ^ or ~)
|
|
243
|
+
- Use explicit version numbers when adding new dependencies
|
|
244
|
+
- Search npm for latest stable version before adding
|
|
245
|
+
- Run `npm audit` after any dependency change
|
|
246
|
+
- Ensure `package-lock.json` is updated correctly
|
|
247
|
+
- Use Dependabot to keep dependencies current
|
|
248
|
+
|
|
249
|
+
## GitHub Actions
|
|
250
|
+
|
|
251
|
+
- Validation must be automated via GitHub Actions and runnable locally the same way
|
|
252
|
+
- Validate all workflows using actionlint
|
|
253
|
+
- Validate all YAML files using yamllint
|
|
254
|
+
- Pin all 3rd party Actions to specific version or commit SHA
|
|
255
|
+
- Keep all 3rd party Actions updated to latest version
|
|
256
|
+
|
|
257
|
+
## Boundaries
|
|
258
|
+
|
|
259
|
+
**✅ Always do:**
|
|
260
|
+
- Run `nvm use` before any npm command
|
|
261
|
+
- Write tests before implementation (TDD)
|
|
262
|
+
- Run lint and tests after every change
|
|
263
|
+
- Run full validation before commits
|
|
264
|
+
- Use existing patterns from codebase
|
|
265
|
+
- Work in small increments
|
|
266
|
+
- Use Context7 MCP tools for code generation and documentation
|
|
267
|
+
|
|
268
|
+
**⚠️ Ask first:**
|
|
269
|
+
- Adding new dependencies
|
|
270
|
+
- Changing project structure
|
|
271
|
+
- Modifying GitHub Actions workflows
|
|
272
|
+
- Database schema changes
|
|
273
|
+
|
|
274
|
+
**🚫 Never do:**
|
|
275
|
+
- Skip the TDD workflow
|
|
276
|
+
- Store secrets in code (use environment variables)
|
|
277
|
+
- Use Jest (use Vitest)
|
|
278
|
+
- Mock fetch directly (use MSW)
|
|
279
|
+
- Modify tests to pass without fixing root cause
|
|
280
|
+
- Add dependencies without explicit version numbers
|
|
281
|
+
- Use type assertions (`as Type`) on external/API data
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: ".github/workflows/*.{yml,yaml}"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Pipeline Instructions
|
|
6
|
+
|
|
7
|
+
## MANDATORY: After Modifying Workflows
|
|
8
|
+
|
|
9
|
+
Run these validation commands in order:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm run lint:workflows # Validate GitHub Actions workflows with actionlint
|
|
13
|
+
npm run lint:yaml # Validate YAML syntax with yamllint
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Workflow Structure Requirements
|
|
17
|
+
|
|
18
|
+
1. Every workflow MUST include test and lint jobs.
|
|
19
|
+
2. Reference Node.js version from `.nvmrc` using `actions/setup-node` with `node-version-file` input.
|
|
20
|
+
3. Use official setup actions: `actions/checkout`, `actions/setup-node`, `actions/cache`.
|
|
21
|
+
|
|
22
|
+
## Action Pinning Format
|
|
23
|
+
|
|
24
|
+
Pin ALL third-party actions to exact commit SHA with version comment:
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
# CORRECT format:
|
|
28
|
+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
|
29
|
+
|
|
30
|
+
# INCORRECT formats (do NOT use):
|
|
31
|
+
uses: actions/checkout@v4 # ❌ version tag only
|
|
32
|
+
uses: actions/checkout@v4.1.1 # ❌ version tag only
|
|
33
|
+
uses: actions/checkout@main # ❌ branch reference
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Before adding any action:
|
|
37
|
+
1. Check GitHub for the LATEST stable version
|
|
38
|
+
2. Find the full commit SHA for that version
|
|
39
|
+
3. Add both SHA and version comment
|
|
40
|
+
|
|
41
|
+
## Runner Requirements
|
|
42
|
+
|
|
43
|
+
| Workflow | Runner |
|
|
44
|
+
|----------|--------|
|
|
45
|
+
| Default (all workflows) | `ubuntu-latest` |
|
|
46
|
+
| `copilot-setup-steps.yml` | May use different runners as needed |
|