# 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*