first commit
This commit is contained in:
239
.planning/codebase/CONVENTIONS.md
Normal file
239
.planning/codebase/CONVENTIONS.md
Normal file
@@ -0,0 +1,239 @@
|
||||
# Coding Conventions
|
||||
|
||||
**Analysis Date:** 2026-03-12
|
||||
|
||||
## Language
|
||||
|
||||
**Primary:** JavaScript (Node.js)
|
||||
- All source files use CommonJS (`.cjs` extension)
|
||||
- ESM imports used in test files with `.test.cjs` extension
|
||||
|
||||
## File Naming
|
||||
|
||||
**Pattern:** kebab-case
|
||||
- Commands: `allow-read-config.cjs`, `get-profile.cjs`, `set-profile.cjs`
|
||||
- Libraries: `oc-core.cjs`, `oc-config.cjs`, `oc-models.cjs`
|
||||
- Tests: `get-profile.test.cjs`, `allow-read-config.test.cjs`
|
||||
|
||||
**Directories:**
|
||||
- Commands: `bin/gsd-oc-commands/`
|
||||
- Libraries: `bin/gsd-oc-lib/` or `bin/lib/`
|
||||
- Tests: `bin/test/`
|
||||
|
||||
## Code Style
|
||||
|
||||
### Formatting
|
||||
|
||||
**No explicit formatter configured.** Code uses:
|
||||
- 2-space indentation
|
||||
- Consistent brace placement
|
||||
- Max line length ~100 characters
|
||||
|
||||
**Example from `bin/gsd-oc-commands/get-profile.cjs`:**
|
||||
```javascript
|
||||
function getProfile(cwd, args) {
|
||||
const verbose = args.includes('--verbose');
|
||||
const raw = args.includes('--raw');
|
||||
const log = verbose ? (...args) => console.error('[get-profile]', ...args) : () => {};
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Linting
|
||||
|
||||
**No ESLint or Prettier configuration detected.**
|
||||
|
||||
## Import Organization
|
||||
|
||||
**Order in source files:**
|
||||
1. Node.js built-ins (`fs`, `path`, `os`)
|
||||
2. Local modules relative paths
|
||||
|
||||
**Example from `bin/gsd-oc-commands/allow-read-config.cjs`:**
|
||||
```javascript
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const { output, error, createBackup } = require('../gsd-oc-lib/oc-core.cjs');
|
||||
```
|
||||
|
||||
## Function Design
|
||||
|
||||
### Naming
|
||||
|
||||
- Commands: lowercase with hyphens (e.g., `getProfile`, `allowReadConfig`)
|
||||
- Helper functions: camelCase
|
||||
- Error code constants: UPPER_SNAKE_CASE
|
||||
|
||||
### Documentation
|
||||
|
||||
**Every file includes a JSDoc-style header:**
|
||||
```javascript
|
||||
/**
|
||||
* get-profile.cjs — Retrieve profile definitions from oc_config.json
|
||||
*
|
||||
* Command module that exports getProfile(cwd, args) function with two operation modes:
|
||||
* 1. No parameters: Returns current profile definition
|
||||
* 2. Profile name parameter: Returns specified profile definition
|
||||
*
|
||||
* Output format: JSON envelope {success: true, data: {...}}
|
||||
* Flags: --raw (output raw JSON without envelope), --verbose (output diagnostics to stderr)
|
||||
*
|
||||
* Usage: node get-profile.cjs [profile-name] [--raw] [--verbose]
|
||||
*/
|
||||
```
|
||||
|
||||
**Function JSDoc:**
|
||||
```javascript
|
||||
/**
|
||||
* Main command function
|
||||
*
|
||||
* @param {string} cwd - Current working directory
|
||||
* @param {string[]} args - Command line arguments
|
||||
*/
|
||||
function getProfile(cwd, args) {
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Error Codes
|
||||
|
||||
**Pattern:** Constant object with error codes, used with custom error function
|
||||
|
||||
From `bin/gsd-oc-lib/oc-profile-config.cjs`:
|
||||
```javascript
|
||||
const ERROR_CODES = {
|
||||
CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',
|
||||
INVALID_JSON: 'INVALID_JSON',
|
||||
PROFILE_NOT_FOUND: 'PROFILE_NOT_FOUND',
|
||||
INVALID_MODELS: 'INVALID_MODELS',
|
||||
INCOMPLETE_PROFILE: 'INCOMPLETE_PROFILE',
|
||||
WRITE_FAILED: 'WRITE_FAILED',
|
||||
APPLY_FAILED: 'APPLY_FAILED',
|
||||
ROLLBACK_FAILED: 'ROLLBACK_FAILED'
|
||||
};
|
||||
```
|
||||
|
||||
### Output Pattern
|
||||
|
||||
**Success output:** JSON envelope with `success: true` and `data`
|
||||
```javascript
|
||||
output({ success: true, data: result });
|
||||
```
|
||||
|
||||
**Error output:** Uses centralized `error()` function from `oc-core.cjs`
|
||||
```javascript
|
||||
error('current_oc_profile not set in oc_config.json', 'MISSING_CURRENT_PROFILE');
|
||||
```
|
||||
|
||||
From `bin/gsd-oc-lib/oc-core.cjs`:
|
||||
```javascript
|
||||
function error(message, code = 'UNKNOWN_ERROR') {
|
||||
const errorEnvelope = {
|
||||
success: false,
|
||||
error: {
|
||||
code,
|
||||
message
|
||||
}
|
||||
};
|
||||
console.error(JSON.stringify(errorEnvelope, null, 2));
|
||||
process.exit(1);
|
||||
}
|
||||
```
|
||||
|
||||
## Return Patterns
|
||||
|
||||
### Result Objects
|
||||
|
||||
**Pattern:** Return object with `success: boolean` and either `data` or `error`
|
||||
|
||||
From `bin/gsd-oc-lib/oc-profile-config.cjs`:
|
||||
```javascript
|
||||
function loadOcProfileConfig(cwd) {
|
||||
try {
|
||||
const configPath = path.join(cwd, '.planning', 'oc_config.json');
|
||||
if (!fs.existsSync(configPath)) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: ERROR_CODES.CONFIG_NOT_FOUND,
|
||||
message: `.planning/oc_config.json not found at ${configPath}`
|
||||
}
|
||||
};
|
||||
}
|
||||
return { success: true, config, configPath };
|
||||
} catch (err) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Module Design
|
||||
|
||||
### Exports
|
||||
|
||||
**Pattern:** Single function export via `module.exports`
|
||||
```javascript
|
||||
module.exports = getProfile;
|
||||
```
|
||||
|
||||
### Command Module Structure
|
||||
|
||||
1. JSDoc header with description
|
||||
2. Require statements
|
||||
3. Error code constants
|
||||
4. Helper functions
|
||||
5. Main command function
|
||||
6. `module.exports`
|
||||
|
||||
## CLI Patterns
|
||||
|
||||
### Flag Handling
|
||||
|
||||
**Pattern:** Simple array filtering
|
||||
```javascript
|
||||
const verbose = args.includes('--verbose');
|
||||
const raw = args.includes('--raw');
|
||||
const profileArgs = args.filter(arg => !arg.startsWith('--'));
|
||||
```
|
||||
|
||||
### Output Functions
|
||||
|
||||
From `bin/gsd-oc-lib/oc-core.cjs`:
|
||||
```javascript
|
||||
function output(result, raw = false, rawValue = null) {
|
||||
let outputStr;
|
||||
if (raw && rawValue !== null) {
|
||||
outputStr = rawValue;
|
||||
} else {
|
||||
outputStr = JSON.stringify(result, null, 2);
|
||||
}
|
||||
// Large payload handling (>50KB)
|
||||
if (outputStr.length > 50 * 1024) {
|
||||
const tempFile = path.join(require('os').tmpdir(), `gsd-oc-${Date.now()}.json`);
|
||||
fs.writeFileSync(tempFile, outputStr, 'utf8');
|
||||
console.log(`@file:${tempFile}`);
|
||||
} else {
|
||||
console.log(outputStr);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Logging
|
||||
|
||||
### Verbose Logging Pattern
|
||||
|
||||
**Conditional logging based on flag:**
|
||||
```javascript
|
||||
const log = verbose ? (...args) => console.error('[get-profile]', ...args) : () => {};
|
||||
log('Loading oc_config.json');
|
||||
log(`Config loaded from ${configPath}`);
|
||||
```
|
||||
|
||||
## Testing Conventions
|
||||
|
||||
Tests co-located in `bin/test/` directory with `.test.cjs` suffix.
|
||||
|
||||
---
|
||||
|
||||
*Convention analysis: 2026-03-12*
|
||||
Reference in New Issue
Block a user