Metadata-Version: 2.4
Name: dev-code
Version: 0.2.0
Summary: Project · editor · container — simplified
Project-URL: Homepage, https://dacrystal.github.io/dev-code/
Project-URL: Source Code, https://github.com/dacrystal/dev-code
Project-URL: Issues, https://github.com/dacrystal/dev-code/issues
Author-email: Nasser Alansari <dacrystal@users.noreply.github.com>
License-File: LICENSE
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.10
Requires-Dist: click>=8.0
Description-Content-Type: text/markdown

# dev-code

```text
     _                                _
    | |                              | |
  __| | _____   ________ ___ ___   __| | ___
 / _` |/ _ \ \ / /______/ __/ _ \ / _` |/ _ \
| (_| |  __/\ V /      | (_| (_) | (_| |  __/
 \__,_|\___| \_/        \___\___/ \__,_|\___|
  project · editor · container — simplified
```

[![GitHub](https://img.shields.io/badge/github-dacrystal%2Fdev--code-blue?logo=github)](https://github.com/dacrystal/dev-code)
[![Coverage](https://codecov.io/gh/dacrystal/dev-code/branch/main/graph/badge.svg)](https://codecov.io/gh/dacrystal/dev-code)
[![PyPI version](https://img.shields.io/pypi/v/dev-code)](https://pypi.org/project/dev-code/)
[![Python 3.10+](https://img.shields.io/pypi/pyversions/dev-code)](https://pypi.org/project/dev-code/)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

Reusable Dev Containers for any project — without modifying the repository.

---

![](https://raw.githubusercontent.com/dacrystal/dev-code/main/assets/demo.png "Demo gif")

`devcode` is a CLI that opens any project in VS Code Dev Containers using reusable, local templates.

Define your environment once and reuse it across projects.

---

## Why devcode?

Typical Dev Container workflows involve:

* Copying `.devcontainer/` directories between projects
* Recreating environments repeatedly
* Committing configuration to repositories you do not control

`devcode` separates environment configuration from project code:

* Templates are stored locally
* Projects remain unchanged
* Containers are launched with a single command

---

## Quick Start

```bash
# Install
pip install dev-code

# Open a project (auto-detects template from container history, or uses default)
devcode open ~/projects/my-app

# Open with an explicit template
devcode open ~/projects/my-app dev-code

# Reopen projects later
devcode ps -a -i
```

---

## Requirements

* VS Code with the Dev Containers extension
* Docker

---

## Core Concepts

### Templates

Templates are reusable devcontainer configurations stored locally.

Default location:

```
~/.local/share/dev-code/templates/
```

Override search paths via `settings.json` (see [Configuration](#configuration)).

---

## Command Reference

### Global Flags

```bash
-v, --verbose   Enable debug output
```

---

### devcode open

```bash
devcode open <path> [template] [options]
```

Open a project in VS Code using a devcontainer template.

#### Arguments

* `<path>` — Project directory (must exist)

* `[template]` *(optional)*

  * Template name, or
  * Path to a `devcontainer.json`, or
  * Path to a directory containing it

  Paths must start with `./`, `../`, `/`, or `~/`.

  If both a template name and a local directory match, the template takes precedence and a warning is shown.

  **If omitted**, devcode auto-detects the template in this order:
  1. Most recently running container for this project path (uses its stored config)
  2. Most recently stopped container for this project path
  3. `default_template` from `settings.json` (error if not set)

#### Options

| Option                      | Default                 | Description                                                |
| --------------------------- | ----------------------- | ---------------------------------------------------------- |
| `--dry-run`                 | —                       | Print resolved configuration and actions without executing |
| `--container-folder <path>` | `/workspaces/<project>` | Container mount path                                       |
| `--timeout <seconds>`       | `300`                   | Time to wait for container startup                         |

---

### devcode new

```bash
devcode new <name> [base]
```

Create a new template.

| Argument | Default    | Description           |
| -------- | ---------- | --------------------- |
| `[base]` | `dev-code` | Template to copy from |

Options:

```bash
--edit
```

Open the template in VS Code after creation.

---

### devcode edit

```bash
devcode edit [template]
```

* With a name: opens that template
* Without arguments: opens the templates directory

---

### devcode list

```bash
devcode list [--long]
```

| Option   | Description                             |
| -------- | --------------------------------------- |
| `--long` | Show full paths and grouped directories |

---

### devcode ps

```bash
devcode ps [-a] [-i]
```

| Flag | Description                |
| ---- | -------------------------- |
| `-a` | Include stopped containers |
| `-i` | Interactive reopen mode    |

Interactive mode prompts:

```
Open [1-N]:
```

Selecting a number reopens the project in VS Code.

---

### devcode completion

```bash
devcode completion bash
devcode completion zsh
```

Enable in shell:

```bash
eval "$(devcode completion bash)"
```

---

## Typical Workflow

```bash
devcode new python-dev
devcode edit python-dev
devcode open ~/projects/my-app python-dev
```

---

## Configuration

devcode reads `settings.json` from:

```
~/.config/dev-code/settings.json
```

Override the config directory:

```bash
DEVCODE_CONF_DIR=/custom/path devcode open ~/projects/my-app
```

The file is created automatically with defaults on first run.

### settings.json

```json
{
  "template_sources": ["~/.local/share/dev-code/templates"],
  "default_template": "dev-code"
}
```

| Key | Description |
| --- | --- |
| `template_sources` | Ordered list of template directories. First is the write target; rest are read-only. |
| `default_template` | Template used when `devcode open` is called without a template argument and no container history is found. Error if unset. |

---

## Template System

### Default Location

```
~/.local/share/dev-code/templates/
```

Configure additional paths via `template_sources` in `settings.json`.

---

## File Injection (cp)

Inject files from the host into the container at startup.

### Example

```json
{
  "customizations": {
    "dev-code": {
      "cp": [
        {
          "source": "${localEnv:HOME}/.config/myapp",
          "target": "/home/vscode/.config/myapp"
        }
      ]
    }
  }
}
```

---

### Fields

| Field         | Required | Description                            |
| ------------- | -------- | -------------------------------------- |
| `source`      | Yes      | Host path                              |
| `target`      | Yes      | Container path                         |
| `override`    | No       | Skip if target exists (default: false) |
| `owner`       | No       | Requires `group`                       |
| `group`       | No       | Requires `owner`                       |
| `permissions` | No       | chmod applied recursively              |

---

### Source Behavior

* Supports `${localEnv:VAR}`
* Supports relative paths from `.devcontainer/`
* Missing environment variables cause the entry to be skipped

---

### Copy Directory Contents

Use `/.` suffix:

```json
{
  "source": "${localEnv:HOME}/.config/myapp/.",
  "target": "/home/vscode/.config/myapp/"
}
```

Copies directory contents instead of the directory itself.

---

### Behavior Rules

* `target/` copies into the directory
* Without trailing `/` copies as a file or directory
* `override=false` skips existing files
* Ownership and permissions are applied after copying

---

## Project Switching

```bash
devcode ps -a -i
```

Lists containers and allows reopening projects interactively.

---

## Advanced Options

* Multiple template directories
* Template inheritance
* Verbose debugging (`-v`)
* Dry runs (`--dry-run`)
* Custom container paths

---

## Internal Flow

1. Validate project path (must exist)
2. Resolve template (explicit → container history → settings default)
3. Launch VS Code Dev Container
4. Apply file injection rules

---

## License

MIT
