|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +`@codifycli/plugin-core` is a TypeScript library for building Codify plugins. Codify is an infrastructure-as-code tool |
| 8 | +that manages system resources (applications, CLI tools, settings) through a declarative JSON configuration. This library |
| 9 | +provides the core abstractions and runtime for implementing plugins that can create, modify, and destroy system |
| 10 | +resources. |
| 11 | + |
| 12 | +## Development Commands |
| 13 | + |
| 14 | +### Testing |
| 15 | + |
| 16 | +```bash |
| 17 | +# Run all tests with Vitest |
| 18 | +npm test |
| 19 | + |
| 20 | +# Note: `npm test` also runs TypeScript compilation as a posttest step |
| 21 | +``` |
| 22 | + |
| 23 | +### Building |
| 24 | + |
| 25 | +```bash |
| 26 | +# Compile TypeScript to dist/ |
| 27 | +npm run prepublishOnly |
| 28 | + |
| 29 | +# Or just compile directly |
| 30 | +npx tsc |
| 31 | +``` |
| 32 | + |
| 33 | +### Linting |
| 34 | + |
| 35 | +```bash |
| 36 | +# Lint with ESLint (oclif + oclif-typescript + prettier configs) |
| 37 | +npx eslint src/ |
| 38 | +``` |
| 39 | + |
| 40 | +### CLI Tool |
| 41 | + |
| 42 | +The package includes a `codify-build` CLI tool (in `bin/build.js`) used by plugin implementations to generate |
| 43 | +documentation and validate schemas. |
| 44 | + |
| 45 | +## Architecture |
| 46 | + |
| 47 | +### Core Concepts |
| 48 | + |
| 49 | +**Plugin System Architecture:** |
| 50 | + |
| 51 | +- **Plugin** (`src/plugin/plugin.ts`): Top-level container that manages multiple resource types and handles IPC |
| 52 | + communication with the Codify CLI via the MessageHandler |
| 53 | +- **Resource** (`src/resource/resource.ts`): Abstract base class representing a manageable system resource (e.g., |
| 54 | + homebrew, git config, applications). Each resource must implement: |
| 55 | + - `refresh()`: Query current system state |
| 56 | + - `create()`: Install/create the resource |
| 57 | + - `destroy()`: Uninstall/remove the resource |
| 58 | + - `modify()`: Update individual parameters (optional) |
| 59 | +- **Plan** (`src/plan/plan.ts`): Represents a set of changes to transform current state into desired state, similar to |
| 60 | + Terraform plans. Contains a ChangeSet with parameter-level operations (ADD/REMOVE/MODIFY/NO-OP) and resource-level |
| 61 | + operation (CREATE/DESTROY/MODIFY/RECREATE/NO-OP) |
| 62 | +- **ResourceController** (`src/resource/resource-controller.ts`): Orchestrates the full lifecycle: validation → |
| 63 | + planning → application. Handles both stateful mode (tracks state between runs) and stateless mode (declarative only) |
| 64 | + |
| 65 | +**Stateful vs Stateless Modes:** |
| 66 | + |
| 67 | +- **Stateless**: Plans computed by comparing desired config against current system state. Only manages parameters |
| 68 | + explicitly declared in config. |
| 69 | +- **Stateful**: Tracks previous state. Enables destroy operations and more granular change detection. Plans compare |
| 70 | + desired vs state, then match state to current system state. |
| 71 | + |
| 72 | +**Stateful Parameters** (`src/stateful-parameter/stateful-parameter.ts`): |
| 73 | + |
| 74 | +- Parameters that have their own lifecycle tied to the parent resource (e.g., homebrew formulas, nvm node versions) |
| 75 | +- Implement their own `refresh()`, `add()`, `modify()`, `remove()` methods |
| 76 | +- Can be array-based (`ArrayStatefulParameter`) for managing collections |
| 77 | + |
| 78 | +**PTY Abstraction** (`src/pty/`): |
| 79 | + |
| 80 | +- `BackgroundPty`: Executes commands asynchronously during refresh/plan operations. Multiple commands can run in |
| 81 | + parallel. Killed after planning completes. |
| 82 | +- `SequentialPty`: Executes commands synchronously during apply operations to ensure ordered execution and proper error |
| 83 | + handling |
| 84 | +- `getPty()`: Access current PTY from async local storage context |
| 85 | +- All shell execution goes through this abstraction for consistent output handling and root privilege escalation |
| 86 | + |
| 87 | +**IPC Communication** (`src/messages/`): |
| 88 | + |
| 89 | +- `MessageHandler`: Processes messages from Codify CLI (initialize, plan, apply, validate, import, match) |
| 90 | +- `MessageSender`: Sends responses and requests (e.g., sudo password prompts) back to CLI |
| 91 | +- Messages validated against schemas from `@codifycli/schemas` |
| 92 | + |
| 93 | +### Directory Structure |
| 94 | + |
| 95 | +``` |
| 96 | +src/ |
| 97 | +├── plugin/ - Plugin class and main entry point |
| 98 | +├── resource/ - Resource base class, settings, controller |
| 99 | +├── plan/ - Plan calculation and change set logic |
| 100 | +├── stateful-parameter/ - Stateful parameter abstractions |
| 101 | +├── pty/ - Pseudo-terminal abstraction for shell commands |
| 102 | +├── messages/ - IPC message handlers and senders |
| 103 | +├── utils/ - File utilities, path resolution, debug logging |
| 104 | +└── common/ - Shared errors and types |
| 105 | +``` |
| 106 | + |
| 107 | +### Key Files |
| 108 | + |
| 109 | +- `src/index.ts`: Main entry point with `runPlugin()` function |
| 110 | +- `src/plugin/plugin.ts`: Core plugin implementation (~290 lines) |
| 111 | +- `src/resource/resource.ts`: Abstract Resource class |
| 112 | +- `src/resource/resource-controller.ts`: Resource lifecycle orchestration |
| 113 | +- `src/resource/resource-settings.ts`: Configuration schema for resources (parameter settings, OS support, allow |
| 114 | + multiple, etc.) |
| 115 | +- `src/plan/plan.ts`: Plan calculation logic (~500 lines) |
| 116 | +- `src/plan/change-set.ts`: Parameter-level diff algorithm |
| 117 | +- `bin/build.js`: Documentation/schema builder for plugin implementations |
| 118 | + |
| 119 | +### Resource Settings |
| 120 | + |
| 121 | +Resources are configured via `ResourceSettings<T>` returned by `getSettings()`: |
| 122 | + |
| 123 | +- `id`: Unique type identifier |
| 124 | +- `schema`: JSON Schema or Zod schema for validation |
| 125 | +- `operatingSystems`: Supported OS platforms (darwin/linux/win32) |
| 126 | +- `linuxDistros`: Supported Linux distributions (optional) |
| 127 | +- `allowMultiple`: Whether multiple instances can coexist (requires `matcher` function) |
| 128 | +- `parameterSettings`: Per-parameter configuration (equals functions, transformations, stateful types, sensitivity) |
| 129 | +- `isSensitive`: Marks resource as sensitive (prevents auto-import, hides values) |
| 130 | +- `dependencies`: Resource IDs this resource depends on |
| 131 | +- `canDestroy`: Whether resource can be destroyed (default: true) |
| 132 | + |
| 133 | +## Implementation Notes |
| 134 | + |
| 135 | +### Testing |
| 136 | + |
| 137 | +- Uses Vitest with `pool: 'forks'` configuration for isolated test execution |
| 138 | +- Test files use `.test.ts` suffix and are excluded from compilation |
| 139 | +- TypeScript compilation runs as a posttest step to catch type errors |
| 140 | + |
| 141 | +### Module System |
| 142 | + |
| 143 | +- Uses ES modules (`"type": "module"` in package.json) |
| 144 | +- Module resolution: `Node16` with `.js` extensions in imports (even for `.ts` files) |
| 145 | +- Target: ES2022 |
| 146 | +- Requires Node.js >=22.0.0 |
| 147 | + |
| 148 | +### Parameter Matching and Filtering |
| 149 | + |
| 150 | +Array parameters support custom matching logic: |
| 151 | + |
| 152 | +- `isElementEqual`: Function to compare array elements |
| 153 | +- `filterInStatelessMode`: Controls how current state is filtered against desired state in stateless mode |
| 154 | +- Default behavior: filters current arrays to only include elements matching desired config (prevents spurious deletes) |
| 155 | + |
| 156 | +### Path Handling |
| 157 | + |
| 158 | +Utility functions in `src/utils/functions.ts`: |
| 159 | + |
| 160 | +- `tildify()`: Convert absolute paths to use `~` |
| 161 | +- `untildify()`: Expand `~` to home directory |
| 162 | +- `resolvePathWithVariables()`: Resolve paths with variables like `$CODIFY_*` |
| 163 | +- Path transformations are commonly used in `InputTransformation` for file/directory parameters |
| 164 | + |
| 165 | +### CI/CD |
| 166 | + |
| 167 | +GitHub Actions workflow (`.github/workflows/unit-test-ci.yaml`): |
| 168 | + |
| 169 | +- Runs on push to any branch |
| 170 | +- Tests on: `ubuntu-latest`, `macos-latest` |
| 171 | +- Node.js version: 22.x |
| 172 | +- Commands: `npm ci` → `npm run test` |
| 173 | + |
| 174 | +### Dependencies |
| 175 | + |
| 176 | +Key dependencies: |
| 177 | + |
| 178 | +- `@codifycli/schemas`: Shared schema definitions and types |
| 179 | +- `@homebridge/node-pty-prebuilt-multiarch`: PTY for shell command execution |
| 180 | +- `ajv`: JSON Schema validation |
| 181 | +- `zod`: Alternative schema validation (v4) |
| 182 | +- `clean-deep`: Remove null/undefined from objects |
| 183 | +- `lodash.isequal`: Deep equality checks |
0 commit comments