Skip to content

Commit fbf2600

Browse files
committed
Update AGENTS.md
1 parent b67405a commit fbf2600

1 file changed

Lines changed: 92 additions & 120 deletions

File tree

AGENTS.md

Lines changed: 92 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,189 +1,161 @@
11
# Agent Guidelines for @uscreen.de/dev-service
22

3-
This document provides guidelines for AI coding agents working on this repository.
3+
Guidelines for AI coding agents working on this repository.
44

55
## Project Overview
66

7-
A CLI tool for managing Docker services in local development environments. This is an ESM (ECMAScript modules) Node.js project that uses docker-compose to orchestrate development services.
7+
A CLI tool for managing Docker services in local development environments. ESM-only Node.js project using docker-compose to orchestrate services like Redis, Mongo, Nginx, etc.
88

99
## Build, Lint & Test Commands
1010

11-
### Testing
1211
```bash
13-
# Run all tests (sequential execution required)
14-
pnpm test
15-
16-
# Run tests with coverage (HTML + text report)
17-
pnpm run test:cov
12+
# Install dependencies (pnpm required, enforced by preinstall hook)
13+
pnpm install
1814

19-
# Run tests with coverage for CI (lcov + text report)
20-
pnpm run test:ci
15+
# Run all tests (must be sequential due to Docker conflicts)
16+
pnpm test
2117

2218
# Run a single test file
2319
node --test test/cli-install.test.js
2420

25-
# Run specific test with pattern
21+
# Run specific test by name pattern
2622
node --test --test-name-pattern="pattern" test/cli.test.js
27-
```
2823

29-
### Linting
30-
```bash
31-
# Lint check (uses @uscreen.de/eslint-config-prettystandard-node)
32-
pnpm exec eslint .
24+
# Tests with coverage
25+
pnpm run test:cov # HTML + text report
26+
pnpm run test:ci # lcov + text (CI)
3327

34-
# Lint and auto-fix
28+
# Lint (uses @antfu/eslint-config with flat config)
29+
pnpm exec eslint .
3530
pnpm exec eslint . --fix
36-
```
3731

38-
### Installation
39-
```bash
40-
# Install dependencies (pnpm is required)
41-
pnpm install
42-
```
43-
44-
### Make commands
45-
```bash
46-
make test # Run tests
47-
make test.coverage # Run tests with coverage
32+
# Make shortcuts
33+
make test # Run tests
34+
make test.coverage # Run tests with coverage
4835
```
4936

5037
## Code Style Guidelines
5138

5239
### Module System
53-
- **ESM only**: Use `import`/`export`, not `require()`
54-
- Use `'use strict'` at the top of files for consistency
55-
- Use `import.meta.url` for current file path
56-
- To require JSON files, use `createRequire` from `module`
40+
- **ESM only**: Use `import`/`export`, never `require()`
41+
- Use `node:` prefix for built-in modules: `import path from 'node:path'`
42+
- Always include `.js` extension in relative imports: `import { x } from './utils.js'`
43+
- Use `import.meta.url` for file path derivation
44+
- For JSON imports, use `createRequire` from `node:module`
5745

58-
### Import Style
46+
### Import Order
5947
```javascript
60-
// Standard library imports first
61-
import path from 'path'
48+
// 1. Node built-ins (with node: prefix)
49+
import { execSync } from 'node:child_process'
50+
import path from 'node:path'
51+
import { fileURLToPath } from 'node:url'
52+
// 2. Third-party packages
53+
import chalk from 'chalk'
6254
import fs from 'fs-extra'
63-
import { fileURLToPath } from 'url'
64-
65-
// Third-party imports
6655
import YAML from 'yaml'
67-
import chalk from 'chalk'
68-
import { Command } from 'commander'
69-
70-
// Local imports last
56+
// 3. Local imports
57+
import { COMPOSE_DIR, TEMPLATES_DIR } from './constants.js'
7158
import { docker, escape } from '../src/utils.js'
72-
import { COMPOSE_DIR } from './constants.js'
7359
```
7460

75-
### File Extensions
76-
- Always include `.js` extension in relative imports: `import { x } from './utils.js'`
77-
- Never omit extensions in ESM imports
78-
7961
### Formatting
80-
- **Indentation**: 2 spaces (no tabs, except in Makefiles)
81-
- **Quotes**: Single quotes for strings
82-
- **Semicolons**: Not required but used inconsistently - follow existing pattern in file
83-
- **Line endings**: LF (Unix style)
62+
- **Indentation**: 2 spaces (tabs only in Makefiles)
63+
- **Quotes**: Single quotes
64+
- **Semicolons**: None (consistently omitted across the entire codebase)
65+
- **Trailing commas**: None (enforced by `style/comma-dangle: ['error', 'never']`)
66+
- **Line endings**: LF
8467
- **Final newline**: Required
8568
- **Trailing whitespace**: Not allowed
86-
- **Max line length**: No strict limit, but be reasonable
8769

8870
### Naming Conventions
89-
- **Files**: kebab-case (e.g., `cli-install.js`, `cli-start.test.js`)
90-
- **Functions**: camelCase (e.g., `readPackageJson`, `checkComposeDir`)
91-
- **Constants**: SCREAMING_SNAKE_CASE (e.g., `COMPOSE_DIR`, `TEMPLATES_DIR`)
92-
- **Variables**: camelCase (e.g., `projectname`, `composePath`)
93-
- **Exported functions**: Use `export const functionName =` or `export const functionName = async`
71+
- **Files**: kebab-case (`cli-install.js`, `cli-start.test.js`)
72+
- **Functions/variables**: camelCase (`readPackageJson`, `composePath`)
73+
- **Constants**: SCREAMING_SNAKE_CASE (`COMPOSE_DIR`, `TEMPLATES_DIR`)
74+
- **Exports**: `export const functionName =` pattern
9475

9576
### Function Patterns
96-
```javascript
97-
// Arrow functions for simple utilities
98-
export const escape = (name) =>
99-
name.replace(/^[^a-zA-Z0-9]*/, '').replace(/[^a-zA-Z0-9-]/g, '-')
77+
- **Arrow functions only** -- the codebase never uses the `function` keyword
78+
- Top-level arrow functions are allowed (`antfu/top-level-function: off`)
10079

101-
// Named functions for complex logic
102-
const fillTemplate = (template, data, removeSections, keepSections) => {
103-
// implementation
104-
}
80+
```javascript
81+
export const escape = name =>
82+
name.replace(/^[^a-z0-9]*/i, '').replace(/[^a-z0-9-]/gi, '-')
10583

106-
// Async arrow functions
10784
export const install = async (opts) => {
10885
// implementation
10986
}
11087
```
11188

112-
### Error Handling
113-
```javascript
114-
// Throw errors with descriptive messages
115-
if (invalid.length > 0) {
116-
throw Error('Invalid custom services:\n...')
117-
}
89+
### Curly Braces
90+
Rule: `'curly': ['error', 'multi-line', 'consistent']` -- `else` goes on a new line after `}`:
11891

119-
// Catch and handle gracefully when appropriate
120-
try {
121-
packageJson = readPackageSync({ cwd: root })
122-
} catch (e) {}
92+
```javascript
93+
if (service) return result
12394

124-
// Use error utility for CLI output
125-
export const error = (e) => {
126-
console.error(chalk.red(`ERROR: ${e.message}\n`))
127-
process.exit(e.code || 1)
95+
if (service) {
96+
await compose('up', '-d', service)
97+
}
98+
else {
99+
await compose('up', '-d')
128100
}
129101
```
130102

131-
### Console Output
132-
- Use `chalk` for colored output in CLI
133-
- Error messages: `chalk.red('ERROR: ...')`
134-
- Warning messages: `chalk.yellow('WARNING: ...')`
135-
- Info messages: plain `console.log()`
136-
- Always include newline after messages
103+
### Error Handling
104+
- CLI-facing errors use `error()` from `src/utils.js` which prints with `chalk.red()` and calls `process.exit()`
105+
- In `bin/` files: `try { await action(options) } catch (e) { error(e) }`
106+
- Empty catch for non-critical: `try { ... } catch {}`
107+
- Warnings: `chalk.yellow()`, Info: plain `console.log()`
108+
- Always append `\n` after error/warning messages
137109

138-
### Async/Await
139-
- Prefer async/await over promise chains
140-
- Use `Promise.all()` for parallel operations
141-
- Handle rejections appropriately
110+
## Testing
142111

143-
### Testing with Node Test Runner
112+
Uses the **native Node.js test runner** (`node:test`) with `node:assert/strict`. Tests must run sequentially (`--test-concurrency=1`) because they share Docker resources.
144113
```javascript
145-
import { test } from 'node:test'
146114
import assert from 'node:assert/strict'
147-
import { cli } from './helpers.js'
148-
149-
test('$ cli', async (t) => {
150-
const result = await cli([])
151-
assert.equal(result.code, 1, 'Should fail')
152-
assert.equal(result.stdout, '', 'Should output nothing to stdout')
115+
import { afterEach, describe, test } from 'node:test'
116+
import { clearArena, cli, prepareArena } from './helpers.js'
117+
118+
describe('$ cli install', () => {
119+
afterEach(async () => {
120+
await clearArena()
121+
})
122+
123+
test('Within a folder with no package.json', async () => {
124+
const result = await cli(['install'], '/tmp')
125+
assert.equal(result.code, 1, 'Should fail')
126+
assert.ok(result.stderr.includes('ERROR'), 'Should output error')
127+
})
153128
})
154129
```
155130

156-
### Test Patterns
157-
- Use native Node.js test runner (node:test)
158-
- Tests must run sequentially (`--test-concurrency=1`)
159-
- Use strict assertions (`node:assert/strict`)
160-
- Test files: `*.test.js` in `test/` directory
161-
- Helper functions in `test/helpers.js`
162-
- Setup/teardown using `prepareArena()` and `clearArena()`
163-
- Disable color output in tests: `process.env.FORCE_COLOR = 0`
131+
- Test files: `test/*.test.js`
132+
- Helpers in `test/helpers.js` (`prepareArena`, `clearArena`, `cli`, `compose`, `loadYaml`)
133+
- Arena pattern: tests use `test/_arena/` as a temporary project directory
134+
- Color disabled in tests: `process.env.FORCE_COLOR = 0`
135+
- Every assertion includes a descriptive message string
136+
- Test names describe the scenario: `'If services are defined in .compose subfolder'`
164137

165138
## Project Structure
166139

167140
```
168-
.
169141
├── bin/ # CLI entry points (cli.js, cli-install.js, etc.)
170142
├── src/ # Source code
171-
│ ├── install.js # Service installation logic
172-
│ ├── utils.js # Shared utilities
173143
│ ├── check.js # Port availability checks
174-
│ └── constants.js # Constants
175-
├── templates/ # Service templates (YAML configs)
144+
│ ├── constants.js # Path constants, version
145+
│ ├── install.js # Service installation logic
146+
│ └── utils.js # Shared utilities (docker, compose, escape, error)
147+
├── templates/ # Docker-compose service templates (YAML)
176148
├── test/ # Tests
177-
│ ├── helpers.js # Test utilities
178-
│ └── *.test.js # Test files
179-
└── package.json # Package manifest
149+
│ ├── helpers.js # Test infrastructure (arena, cli runner, compose)
150+
│ └── *.test.js # Test files (18 files)
151+
└── eslint.config.js # ESLint flat config (@antfu/eslint-config)
180152
```
181153

182154
## Important Notes
183155

184-
- **Node version**: Requires Node.js >= 20
185-
- **Package manager**: pnpm only (enforced by preinstall hook)
186-
- **Docker dependencies**: Requires `docker` and `docker-compose` in PATH
187-
- **Tests**: Must run sequentially due to Docker resource conflicts
188-
- **No TypeScript**: Plain JavaScript with JSDoc if needed
189-
- **Shebang**: Use `#!/usr/bin/env node` for CLI executables
156+
- **Node.js**: >= 20 required (`.nvmrc` targets 24)
157+
- **Package manager**: pnpm only (enforced)
158+
- **Docker**: Requires `docker` and `docker-compose` in PATH
159+
- **No TypeScript**: Plain JavaScript only
160+
- **Shebang**: `#!/usr/bin/env node` for CLI executables in `bin/`
161+
- **CI**: Tests run on Node 20, 22, 24 via GitHub Actions

0 commit comments

Comments
 (0)