Skip to content

Commit f84a95f

Browse files
feat: Version 1.0.0 (#55)
* feat: Added login method * feat: Added connect integration with codify-dashboard * feat: switched to hono server and added cors support * feat: switched to express * chore: refactored apply flow to use express * Added login helper and trying out parser abstraction * Added ability to load, apply and plan cloud files * Moved login init to base command. Fixes * Added new codify file resolution logic. WIP default document endpoint fetch * Added path as an arg to apply and plan * Added path as an arg to validate * Fixed import logic to support cloud files * Fixed login bugs. - Resolve promise when logged in - Fixed login manager bug Added useful log message for connect * Fixed codify apply via connect to supply tmpFile path. Added helpful log messages. Fixed header name error for websocket validation. Reduced size of token * Switched to socketIO * Switched back to websockets instead of socket io * Prevent multiple pty instances from being created * Improved the command handler to support more variations * Fixed build bugs. Moved uuid to dependency. Fixed entry points that were messed up. Improved error handling for documents endpoint * Improved session ending logic. * Added missing import flag * Changed connect commands to use rootCommand that way it updates with the current project and doesn't rely on global codify. Added error if port is already in use. * Refactored how commands are handled. Allows for greater flexibility. * Added import handler * Added concept of clientId. Added import writer * Re-worked login to get email, userId, claims directly from token. Switched to ES256 self signed tokens. Added codify edit command * Removed extraneous logs. Added message for codify edit * Added install beta script. Fixed urls to point to dashboard.codifycli.com. Fixed logins if another process is already using the port. Fixed logins not saving credentials if .codify folder doesn't exist. * Fixed login behavior for connect and edit. Added log out command * Add new refresh command * Changed the parameterless import to mimic init (auto import everything) * Added refresh method to connect and fixed bugs * Fixed API calls to parse error messages as non-json * Fixed bugs: - Check for login expiration was in milliseconds (should be seconds) - The proper node binary was not used by connect handlers - Lack of refresh command name + Deploy script * Added --updateExisting flag for import command. Made refresh orchestrator empty and reliant on the import orchestrator. Refactored save file type to an individual function * Fixed file modification calculator handling of an empty file '[]'. Added tests for auto-import * Fixed file modification calculator handling of an empty file '[]'. Added tests for auto-import * fix: Fixed bugs with refresh and import * feat: Added support for Codify remote files * fix: Bug fix for files that don't currently exist. Import confirmation prompt * fix: Bug fix for MacOS oclif installer bug. It doesn't clear the oclif update plugin directory so older versions are still usable after re-installing * feat: Added auto complete, additional version flags, additional help flags and set the default command to edit * fix: Added init command * Added new finish event to unify sending the remote result back to the dashboard * Added the useful ability to kill the previous codify connect so you don't have to go find it * fix: Moved kill port to dependencies * feat: Added connection start time and connection termination * feat: Refactored the initialization process to return a resource definition. We can put info in here in the future if needed. Right now return if a resource has any sensitive parameters * feat: Added sensitive parameter filtering to import and init. Added sensitive parameter hiding to displaying plans * feat: Added improvements to import and init saving of results * feat: Improved init experience (always new project for init) * feat: Fixed build issues and improved help * fix: Fixed existing tests * feat: Added CLI logins without the browser * feat: Added test for connect + improvements and fixes * feat: Added test for connect commands (apply, plan, import, etc) + improvements and fixes * feat: Added additional tests for edit, login and refresh * feat: Add readme and license * feat: Upgrade to node 22 * fix: Test and type fixes * fix: Temp disable socket-server tests * fix: Enable one of the disabled tests * kevin/fix-tests (#50) * fix: Enabled another test * fix: Update test name * fix: Enable more tests * fix: Enabled all tests * fix: Mock the pty call * Added some logs * Move server close above expect * Fix terminal problems * Attempt to make tests less flaky * Add log * Added sequential * Added sequential * Disable parallelism * Add wait between tests * Disable threading * Skip connect tests altogether * Fix: Bug fixes for help, and init using dev-dependency. Added extra cors header removing the need for PNA notification * feat: Added new spawn code using node-pty. Root and stdin are both supported now * feat: Removed the spinner powered by log messages (caused pointer issues previously) since it's no longer needed. Fix sudo util missing problems * feat: Added codify test command that can spawn a tart vm to test codify configs * feat: Improved the display for test. Added linux support on a macOS host. * feat: Added support for validating by OS and distro. Added improved install script that works on linux * feat: Allow beta plugins to be auto-magically be added when codify version is beta * feat: Reverted commenting out xz * feat: Added os filtering for codify init command * feat: Updated github urls and description * feat: Force arch to be arm64. Added linux to uplaod script. * fix: Fixed sudo, reporters, os filtering, and others (mainly linux related) * fix: Connect commands not working on other shells * fix: Fixed running sudo commands on linux and commands with quotes * chore: switch to public npm @codifycli/ink-form package * fix: Fixed environment variables not carried over to sudo. Fixed bash only sudo command. * fix: Fixed warnings on linux install. Bumped oclif version. * feat: Updated ink. Switched to dots instead of half circles. Move sleep before displaying message. * fix: Fixed weird memory problem with using spinner and status message from @inkjs/ui * feat: Improved coloring for progress display * fix: Fixed tests * chore: commit package-lock.json * fix: Linux tests and build errors * feat: Allow CI builds to run on both macOS and linux * feat: Improved test command and added file syncing (#56) * WIP: fixed the test command and added a promptSecret to collect the user's password initially * fix: Selectively sync either /usr/local/lib/codify or ~/.local/share/codify * Undo un-needed changes * feat: Added a block for non-mac os systems * feat: Added test to list of remote commands * chore: Updated packages. Switched to @codifycli/schemas * chore: Updated package-lock.json * feat: removed login requirement for connect command * fix: Remove github token code in github actions * chore: Update to @codifycli/plugin-core and update version of @codifycli/schemas * feat: Updated README * chore: new package-lock.json * feat: Add CLAUDE.md and updated the README.md * fix: Fix bugs with the test command * chore: update version to 1.0.0
1 parent 50459b2 commit f84a95f

File tree

130 files changed

+15533
-8368
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+15533
-8368
lines changed

.eslintrc.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
"unicorn/no-array-for-each": "off",
1919
"unicorn/prefer-object-from-entries": "off",
2020
"unicorn/prefer-type-error": "off",
21+
"unicorn/no-static-only-class": "off",
22+
"@typescript-eslint/no-duplicate-enum-values": "off",
2123
"quotes": [
2224
"error",
2325
"single"

.github/workflows/run-unit-tests.yaml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,18 @@ on: ['push']
77

88
jobs:
99
build-and-test:
10-
runs-on: ubuntu-latest
10+
runs-on: ${{ matrix.os }}
11+
12+
strategy:
13+
matrix:
14+
os: [ubuntu-latest, macos-latest]
1115

1216
steps:
1317
- uses: actions/checkout@v4
14-
- run: echo -e "\n//npm.pkg.github.com/:_authToken=${{ secrets.PACKAGES_PAT_GITHUB }}" >> ./.npmrc
15-
- name: Use Node.js 20
18+
- name: Use Node.js 22
1619
uses: actions/setup-node@v4
1720
with:
18-
node-version: '20.x'
21+
node-version: '22.x'
1922
cache: 'npm'
2023
- run: npm ci
21-
- run: npm test
24+
- run: npm run test

.npmrc

Lines changed: 0 additions & 1 deletion
This file was deleted.

CLAUDE.md

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
Codify is a configuration-as-code CLI tool that brings Infrastructure-as-Code principles to local development environments. It allows developers to declaratively define their development setup (packages, tools, system settings) in configuration files and apply them in a reproducible way. Think "Terraform for your local machine."
8+
9+
## Development Commands
10+
11+
### Building
12+
```bash
13+
npm run build # Build TypeScript to dist/
14+
npm run lint # Type-check with tsc
15+
```
16+
17+
### Testing
18+
```bash
19+
npm test # Run all tests with Vitest
20+
npm test -- path/to/test # Run specific test file
21+
npm run posttest # Runs lint after tests
22+
```
23+
24+
### Running Locally
25+
```bash
26+
./bin/dev.js <command> # Run CLI in development mode
27+
./bin/dev.js apply # Example: run apply command
28+
```
29+
30+
### Test Command (VM Testing)
31+
The `test` command spins up a Tart VM to test Codify configs in isolation:
32+
```bash
33+
./bin/dev.js test --vm-os darwin # Test on macOS VM
34+
./bin/dev.js test --vm-os linux # Test on Linux VM
35+
```
36+
37+
## High-Level Architecture
38+
39+
### Core Architectural Patterns
40+
41+
1. **Command-Orchestrator Pattern**: Commands (`src/commands/`) are thin oclif wrappers. Orchestrators (`src/orchestrators/`) contain all business logic and workflow coordination. This separation enables reusability.
42+
43+
2. **Multi-Process Plugin System**: The most unique architectural decision is running plugins as separate Node.js child processes communicating via IPC:
44+
- **Why**: Isolation (crashes don't crash CLI), security (parent controls sudo), flexibility
45+
- **Plugin Process** (`src/plugins/plugin-process.ts`): Spawns plugins using `fork()`
46+
- **IPC Protocol** (`src/plugins/plugin-message.ts`): Type-safe message passing
47+
- **Security**: Plugins run isolated; parent process controls all sudo operations
48+
- When plugins need sudo, they send `COMMAND_REQUEST` events back to parent
49+
50+
3. **Event-Driven Architecture**: Central event bus (`src/events/context.ts`) using EventEmitter:
51+
- Tracks process/subprocess lifecycle (PLAN, APPLY, INITIALIZE_PLUGINS, etc.)
52+
- Enables plugin-to-CLI communication (sudo prompts, login credentials, etc.)
53+
- Powers progress tracking for UI
54+
55+
4. **Reporter Pattern**: Abstract `Reporter` interface with multiple implementations selected via `--output` flag:
56+
- `DefaultReporter`: Rich Ink-based TUI with React components
57+
- `PlainReporter`: Simple text output
58+
- `JsonReporter`: Machine-readable JSON
59+
- `DebugReporter`: Verbose logging
60+
- `StubReporter`: No-op for testing
61+
62+
5. **Resource Lifecycle State Machine**:
63+
```
64+
Parse Config → Validate → Resolve Dependencies → Plan → Apply
65+
```
66+
- **ResourceConfig**: Desired state from config file
67+
- **Plan**: Computed difference between desired and current state
68+
- **ResourcePlan**: Per-resource operations (CREATE, UPDATE, DELETE, NOOP)
69+
- **Project**: Container with dependency graph
70+
71+
6. **Dependency Resolution**:
72+
- Explicit: `dependsOn` field in config
73+
- Implicit: Extracted from parameter references (e.g., `${other-resource.param}`)
74+
- Plugin-level: Plugins declare type dependencies (e.g., xcode-tools on macOS)
75+
- Topological sort ensures correct evaluation order (`src/utils/dependency-graph-resolver.ts`)
76+
77+
### Key Directory Structure
78+
79+
- **`/src/orchestrators/`**: Business logic layer - each file implements one CLI command's workflow
80+
- `plan.ts`: Parse → Validate → Resolve deps → Generate plan
81+
- `apply.ts`: Execute plan after user confirmation
82+
- `import.ts`: Import existing resources into config
83+
- `test.ts`: VM-based testing with live config sync via file watcher
84+
85+
- **`/src/plugins/`**: Plugin infrastructure
86+
- `plugin-manager.ts`: Registry routing operations to plugins
87+
- `plugin-process.ts`: Child process lifecycle and IPC
88+
- `plugin.ts`: High-level plugin API
89+
90+
- **`/src/entities/`**: Domain models with rich behavior
91+
- `Project`: Container with dependency resolution
92+
- `ResourceConfig`: Mutable config with dependency tracking
93+
- `Plan`: Immutable plan with sorting/filtering
94+
95+
- **`/src/parser/`**: Multi-format config parsing (JSON, JSONC, JSON5, YAML)
96+
- All parsers maintain source maps for error messages
97+
- Cloud parser fetches from Dashboard API via UUID
98+
99+
- **`/src/ui/`**: User interface layer
100+
- `/reporters/`: Output strategy implementations
101+
- `/components/`: React components for Ink TUI
102+
- `/store/`: Jotai state management for UI
103+
104+
- **`/src/connect/`**: Dashboard integration
105+
- WebSocket server for persistent connection
106+
- OAuth flow handling
107+
- JWT credential management
108+
109+
- **`/src/generators/`**: Config file writers
110+
- Computes diffs for updating existing configs
111+
- Writes to local files or cloud (via Dashboard API)
112+
113+
### Important Data Flows
114+
115+
**Apply Command Flow:**
116+
```
117+
ApplyOrchestrator.run()
118+
→ PlanOrchestrator.run()
119+
→ PluginInitOrchestrator.run()
120+
→ Parse configs → Project
121+
→ PluginManager.initialize() → ResourceDefinitions
122+
→ Project.resolveDependencies()
123+
→ PluginManager.plan() → Plan
124+
→ Reporter.promptConfirmation()
125+
→ PluginManager.apply()
126+
→ For each resource (topologically sorted):
127+
→ Plugin.apply() [IPC to child process]
128+
```
129+
130+
**Plugin Communication Flow:**
131+
```
132+
Parent Process Plugin Process
133+
|-- initialize() -------->|
134+
|<-- resourceDefinitions -|
135+
|-- plan(resource) ------>|
136+
| [Plugin needs sudo]
137+
|<-- COMMAND_REQUEST -----|
138+
|-- prompt user |
139+
|-- COMMAND_GRANTED ----->|
140+
|<-- PlanResponse --------|
141+
```
142+
143+
### Key Architectural Decisions
144+
145+
1. **Single file Projects**: Projects only currently support one file
146+
2. **Cloud-First**: UUIDs are valid "file paths" - enables seamless local/cloud switching
147+
3. **XCode Tools Injection**: On macOS, `xcode-tools` automatically prepended (most resources depend on it)
148+
4. **Test VM Strategy**: Uses Tart VMs with bind mounts (not copying) + file watcher for live config editing
149+
5. **OS Filtering**: Resources specify `os: ["Darwin", "Linux"]` for conditional inclusion
150+
6. **Secure Mode**: `--secure` flag forces sudo prompt for every command (no password caching)
151+
152+
### Common Implementation Patterns
153+
154+
1. **Plugin Resolution**: Local plugins use file paths (`.ts`/`.js`), network plugins use semver versions
155+
2. **Source Maps**: Preserved through entire parse → validate → plan flow for accurate error messages
156+
3. **Event Timing**: Events fire synchronously; use `ctx.once()` carefully to avoid race conditions
157+
4. **Process Cleanup**: Plugins must be killed on exit via `registerKillListeners`
158+
5. **Reporter Lifecycle**: Call `reporter.hide()` before synchronous output to prevent UI corruption
159+
160+
### Testing Patterns
161+
162+
- **Ink Component Tests**: Must polyfill `console.Console` for test environment:
163+
```typescript
164+
import { Console } from 'node:console';
165+
if (!console.Console) {
166+
console.Console = Console;
167+
}
168+
```
169+
- **Plugin Tests**: Use `StubReporter` to avoid UI initialization
170+
- **VM Tests**: `test` command uses Tart VMs with bind mounts for integration testing
171+
172+
## Build & Distribution
173+
174+
- **Framework**: oclif CLI framework with manifest generation
175+
- **Module System**: ES modules with NodeNext resolution
176+
- **Packaging**: `oclif pack tarballs` for multi-platform binaries
177+
- **Updates**: Self-updating via S3 (`@oclif/plugin-update`)
178+
- **Code Signing**: macOS notarization via `scripts/notarize.sh`
179+
180+
## Common Gotchas
181+
182+
1. **Import Paths**: Use `.js` extensions in imports even though files are `.ts` (ES module resolution)
183+
2. **Schema Validation**: Config changes require updating schemas in `@codifycli/schemas` package
184+
3. **Plugin IPC**: Plugins cannot directly read stdin (security isolation)
185+
4. **Sudo Caching**: Password cached in memory during session unless `--secure` flag used
186+
5. **File Watcher**: Use `persistent: false` option to prevent hanging processes
187+
6. **Linting**: ESLint enforces single quotes, specific import ordering, and strict type safety

0 commit comments

Comments
 (0)