Files
rtu_v5/.planning/codebase/CONVENTIONS.md
2026-03-12 00:56:57 +08:00

5.5 KiB

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:

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:

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:

/**
 * 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:

/**
 * 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:

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

output({ success: true, data: result });

Error output: Uses centralized error() function from oc-core.cjs

error('current_oc_profile not set in oc_config.json', 'MISSING_CURRENT_PROFILE');

From bin/gsd-oc-lib/oc-core.cjs:

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:

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

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

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:

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:

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