Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: CI

on:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Type check
run: pnpm run typecheck

- name: Lint
run: pnpm run lint

- name: Test
run: pnpm run test

- name: Build
run: pnpm run build

commitlint:
name: Lint Commits
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Validate PR commits
run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose
43 changes: 43 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Release

on:
push:
branches:
- master

permissions:
contents: write
issues: write
pull-requests: write

jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build
run: pnpm run build

- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release
1 change: 1 addition & 0 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npx --no -- commitlint --edit $1
22 changes: 22 additions & 0 deletions .releaserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"branches": ["master"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
[
"@semantic-release/changelog",
{
"changelogFile": "CHANGELOG.md"
}
],
"@semantic-release/npm",
[
"@semantic-release/git",
{
"assets": ["package.json", "CHANGELOG.md"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
],
"@semantic-release/github"
]
}
160 changes: 136 additions & 24 deletions AGENT.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,166 @@
# AI Agent Instructions

This file contains instructions for the AI when working on this repository.
This file contains instructions for AI agents working on this repository.

## Project Overview

[Describe your project, its purpose, and key technologies used]
**contui** is a Terminal UI for managing containers on macOS using the native `container` CLI. Built with Ink (React for CLI) and TypeScript, it provides vim-style keyboard navigation for container, image, network, and volume management.

### Key Technologies
- **Ink v5** - React-based terminal UI framework
- **TypeScript** - Strict type checking enabled
- **Jest** - Testing framework with ESM support
- **ESLint** - Flat config format (eslint.config.js)
- **pnpm** - Package manager

## Code Patterns

### Architecture
[Document your architecture - e.g., MVC, Clean Architecture, etc.]

The application follows a **component-based architecture** with separation of concerns:

1. **Components** (`src/components/`): React components for UI rendering
2. **Hooks** (`src/hooks/`): Custom hooks for state and behavior
3. **Services** (`src/services/`): External integrations (container CLI wrapper)
4. **Types** (`src/types/`): Shared TypeScript interfaces

### Naming Conventions
[Document naming conventions for files, functions, variables, etc.]

- **Files**: `kebab-case.ts` for utilities, `PascalCase.tsx` for React components
- **Components**: PascalCase (e.g., `ContainersView`, `StatusBar`)
- **Hooks**: camelCase with `use` prefix (e.g., `useKeyboard`, `useContainerData`)
- **Types**: PascalCase (e.g., `Container`, `ContainerStatus`)
- **Functions**: camelCase (e.g., `handleAction`, `getItemCount`)

### Component Structure
[If applicable, describe component/module structure]

```typescript
// Standard component pattern
import React from "react";
import { Box, Text } from "ink";
import type { SomeType } from "../types/index.js";

interface Props {
data: SomeType;
selectedIndex: number;
}

export function ComponentName({ data, selectedIndex }: Props): React.ReactElement {
// Component logic
return <Box>...</Box>;
}
```

### Important Patterns

1. **ESM Imports**: Always use `.js` extension for local imports
```typescript
import { Container } from "../types/index.js"; // Correct
import { Container } from "../types/index"; // Wrong
```

2. **Keyboard Handling**: Centralized in `useKeyboard` hook - add new keybindings there

3. **CLI Commands**: All container operations go through `src/services/container-cli.ts`

4. **State Management**: Uses React's built-in `useState` and `useCallback`

5. **Selection Highlighting**: Uses Ink's inverse text (`<Text inverse>`) for selection

## Testing Requirements

### Unit Tests
- All new functions should have corresponding unit tests
- Use [your testing framework] for unit tests
- Aim for [X]% coverage on new code

### Integration Tests
[Document when and how to write integration tests]
- All new service functions should have corresponding unit tests
- Use Jest with ESM support (`NODE_OPTIONS='--experimental-vm-modules'`)
- Tests located in `src/__tests__/`
- Aim for coverage on critical paths (CLI parsing, data transformation)

### Test Patterns
```typescript
import { describe, it, expect, jest } from "@jest/globals";

describe("ModuleName", () => {
it("should do something specific", () => {
// Arrange
// Act
// Assert
});
});
```

### Running Tests
```bash
pnpm test # Run all tests
pnpm test:watch # Watch mode
pnpm test:coverage # Coverage report
```

## Commit Conventions

Follow conventional commits format:
- `feat:` New feature
- `fix:` Bug fix
Follow [Conventional Commits](https://www.conventionalcommits.org/):

- `feat:` New feature (triggers minor version bump)
- `fix:` Bug fix (triggers patch version bump)
- `refactor:` Code improvement without behavior change
- `test:` Testing additions
- `test:` Test additions
- `chore:` Maintenance/dependencies
- `docs:` Documentation
- `perf:` Performance improvement
- `ci:` CI changes
- `build:` Build system changes

All AI commits should include the Co-Authored-By trailer as specified in the task prompt.
Breaking changes: Add `!` after type (e.g., `feat!:`) or include `BREAKING CHANGE:` in footer.

## Important Files
AI commits must include:
```
Co-Authored-By: Claude <noreply@anthropic.com>
```

[List key files the AI should understand before making changes]
## Important Files

- `src/index.ts` - Main entry point
- `src/config/` - Configuration files
- [Add more key files]
| File | Purpose |
|------|---------|
| `src/index.tsx` | Entry point with health check |
| `src/components/App.tsx` | Main app component, state management |
| `src/services/container-cli.ts` | Container CLI wrapper (critical) |
| `src/hooks/useKeyboard.ts` | Keyboard handler (add shortcuts here) |
| `src/hooks/useContainerData.ts` | Data fetching logic |
| `src/types/index.ts` | All TypeScript interfaces |

## Constraints

- [List any constraints or limitations]
- [E.g., "Do not modify files in /vendor"]
- [E.g., "Always use async/await over callbacks"]
- **Do not use npm or yarn** - This project uses pnpm
- **Always use async/await** - No callbacks for async operations
- **No Docker dependency** - Uses macOS native `container` CLI only
- **Preserve vim-style navigation** - j/k, h/l patterns are intentional
- **ESM only** - Project uses `"type": "module"`
- **Do not modify** `.github/workflows/` without explicit request
- **Keep Ink v5 compatibility** - Don't introduce v4 patterns

## Validation Before Commits

Always run before committing:
```bash
pnpm run typecheck
pnpm run lint
pnpm test
```

## Common Tasks

### Adding a New Keyboard Shortcut
1. Edit `src/hooks/useKeyboard.ts`
2. Add the key handler in the `handleInput` function
3. Update `src/components/HelpOverlay.tsx` to document it
4. Update README.md keyboard shortcuts table

### Adding a New Container Operation
1. Add method to `src/services/container-cli.ts`
2. Add corresponding test in `src/__tests__/container-cli.test.ts`
3. Wire up in `src/components/App.tsx` via `handleAction`

### Adding a New Tab/View
1. Add type to `Tab` union in `src/types/index.ts`
2. Create component in `src/components/`
3. Add to tab switching in `useKeyboard.ts`
4. Add rendering case in `App.tsx`
Loading