diff --git a/AGENTS.md b/AGENTS.md new file mode 120000 index 0000000..681311e --- /dev/null +++ b/AGENTS.md @@ -0,0 +1 @@ +CLAUDE.md \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..5c2be0a --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,64 @@ +# CLAUDE.md + +Plasma Compose — Launchr CLI plugin for dependency composition. Fetches packages from Git/HTTP sources, merges them with local files into `.compose/build/` using configurable conflict resolution strategies. + +## Commands +```bash +make deps # install go dependencies +make test # run tests (go test ./...) +make lint # golangci-lint v2.5.0 +make build # build binary +make all # deps + test + build +``` +`DEBUG=1` enables debug symbols. Requires Go 1.24.0+, CGO disabled. + +## File Layout +| File | Role | +|------|------| +| `plugin.go` | Launchr plugin, registers actions: `compose`, `compose:add`, `compose:update`, `compose:delete` | +| `compose/compose.go` | Orchestrator: working dirs, cleanup, signal handling. Key type: `Composer` | +| `compose/downloadManager.go` | Downloads packages (Git/HTTP), recursive dependency resolution. Key type: `DownloadManager` | +| `compose/git.go` | Git clone/fetch with keyring auth. Uses `go-git` with `EnableDotGitCommonDir: true` for worktree support | +| `compose/http.go` | HTTP download + extraction (`.tar.gz`, `.zip` only) | +| `compose/builder.go` | Filesystem merge with topsort ordering + merge strategies. Key type: `Builder` | +| `compose/yaml.go` | Config parsing. Key types: `YamlCompose`, `Package`, `Dependency`, `Source`, `Strategy` | +| `compose/forms.go` | Interactive TUI forms for add/update/delete actions | +| `action.*.yaml` | Action definitions with CLI options | + +## Critical Behaviors +- **Strategy path matching**: Uses `strings.HasPrefix` (prefix matching), NOT glob patterns. Trailing separator auto-appended. +- **Conflict default**: Local files win. Strategies override this per-path. +- **Layer order**: Local files first, then packages in topological sort order (dependencies before dependents). +- **First strategy wins**: Per file, first matching strategy determines action. +- **`remove-extra-local-files`**: Only strategy targeting local walk; others target package walk. +- **Git worktrees**: Supported via `PlainOpenWithOptions` with `EnableDotGitCommonDir: true`. +- **Excluded from build**: `.compose/` dir, `plasma-compose.yaml`, `.git` from packages (local `.git` preserved). +- **Auth cascade**: no-auth → keyring (global base URL) → keyring (exact URL) → manual prompt. + +## Merge Strategies +| Strategy | Target | Effect | +|----------|--------|--------| +| `overwrite-local-file` | Package files | Package replaces local at matching paths | +| `remove-extra-local-files` | Local files | Skip local files matching paths (not added to build) | +| `ignore-extra-package-files` | Package files | Skip package files at matching paths | +| `filter-package-files` | Package files | Only include package files matching paths | + +## Config Format +```yaml +name: project-name +dependencies: + - name: package-name + source: + type: git # git (default) or http + url: https://github.com/user/repo.git + ref: branch-or-tag # omit for default branch (target="latest") + strategy: + - name: overwrite-local-file + path: ["config/", "templates/"] +``` + +## Working Directories +- `.compose/packages///` — downloaded package contents +- `.compose/build/` — final composed output (cleaned each run) +- `--clean` flag removes entire `.compose/` before run +- `--skip-not-versioned` filters to git-tracked files only (works with worktrees) diff --git a/GEMINI.md b/GEMINI.md new file mode 120000 index 0000000..681311e --- /dev/null +++ b/GEMINI.md @@ -0,0 +1 @@ +CLAUDE.md \ No newline at end of file diff --git a/plasmactl-compose.md b/plasmactl-compose.md new file mode 100644 index 0000000..8361237 --- /dev/null +++ b/plasmactl-compose.md @@ -0,0 +1,110 @@ +# Plasma Compose Reference + +Plasma Compose is a Launchr CLI plugin that composes a filesystem from multiple package sources. It reads `plasma-compose.yaml`, fetches dependencies (Git/HTTP), resolves them via topological sort, merges files with configurable strategies, and outputs to `.compose/build/`. + +## Configuration +```yaml +name: project-name +dependencies: + - name: package-name + source: + type: git # "git" (default) or "http" + url: https://github.com/user/repo.git + ref: main # branch or tag; omit for default branch + strategy: + - name: overwrite-local-file + path: ["config/", "templates/"] +``` +**Git sources**: Clone by `ref` (tries tag first, then branch). Omitting `ref` clones the default branch (target=`latest`). +**HTTP sources**: Download and extract `.tar.gz` or `.zip` archives. `ref` is ignored. + +## CLI Actions + +**`compose`** — Full composition (fetch + build). +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--working-dir, -w` | string | `.compose/packages` | Package download directory | +| `--skip-not-versioned, -s` | bool | false | Only include git-tracked files from source | +| `--conflicts-verbosity` | bool | false | Log conflict resolutions | +| `--clean` | bool | false | Remove `.compose/` before start | +| `--interactive` | bool | true | Allow interactive credential prompts | + +**`compose:add`** — Add package to `plasma-compose.yaml`. +**`compose:update`** — Update package (or all interactively if `--package` omitted). +**`compose:delete`** — Remove packages (`--packages` comma-separated). +Add/update options: `--package`, `--type` (git/http), `--url`, `--ref`, `--strategy` (array), `--strategy-path` (array, pipe-separated paths). Add also has `--allow-create`. + +## Composition Pipeline +1. **Parse** `plasma-compose.yaml` → `YamlCompose` (name + dependencies) +2. **Download** each dependency to `.compose/packages///` + - Recursively process nested `plasma-compose.yaml` in packages + - Git: check local vs remote ref, skip if up to date + - HTTP: skip if directory exists +3. **Clean** `.compose/build/` +4. **Walk local files** → entries tree (excludes `.compose/`, `plasma-compose.yaml`) + - With `--skip-not-versioned`: only git-tracked files (works with worktrees) + - `remove-extra-local-files` strategy applied here (matching paths skipped) +5. **Apply packages** in topological order (dependencies before dependents) + - `.git` entries from packages are skipped + - Per file: first matching strategy wins; default = local wins +6. **Copy** entries tree to `.compose/build/` preserving permissions and symlinks + +## Merge Strategies +Strategy paths use **prefix matching** (`strings.HasPrefix`), not globs. Trailing separator is auto-appended. +| Strategy | Applied to | Behavior | +|----------|-----------|----------| +| `overwrite-local-file` | Package walk | Package file replaces local at matching paths | +| `remove-extra-local-files` | Local walk | Local files at matching paths excluded from build | +| `ignore-extra-package-files` | Package walk | Package files at matching paths silently skipped | +| `filter-package-files` | Package walk | Only package files at matching paths are included | + +Per package, multiple strategies can be defined. First match wins, then processing stops for that file. If no strategy matches, default behavior applies (local files win on conflict). + +## Authentication +Three modes tried in order for both Git and HTTP: +1. **None** — public access +2. **Keyring** — credentials from system keyring (first by base URL, then exact URL) +3. **Manual** — interactive prompt (requires `--interactive`) + +Fails cascade to the next mode automatically. + +## Directory Layout +``` +project-root/ +├── plasma-compose.yaml +└── .compose/ + ├── packages/// # downloaded packages + └── build/ # composed output +``` +`--clean` removes entire `.compose/`. Build dir is always cleaned before each run. + +## Example +```yaml +name: enterprise-app +dependencies: + - name: core-platform + source: + type: git + url: https://github.com/corp/platform.git + ref: v3.0.0 + - name: auth-module + source: + type: git + url: https://github.com/corp/auth.git + ref: v1.5.2 + strategy: + - name: overwrite-local-file + path: ["middleware/"] + - name: monitoring + source: + type: http + url: https://releases.corp.com/monitoring-v2.1.0.tar.gz + strategy: + - name: filter-package-files + path: ["agents/", "config/monitoring/"] +``` +**Result** (applied in order): +1. Local project files (base layer) +2. `core-platform` — all files merged, local wins on conflicts +3. `auth-module` — files under `middleware/` overwrite local versions +4. `monitoring` — only `agents/` and `config/monitoring/` included