# install

Scaffold the canonical Flutter consumer project structure and install the fast-CLI wrapper in a single step. Running `install` produces `bin/dispatcher.dart`, the two generated barrels, and `bin/dowel`, then injects `dowel` into `pubspec.yaml` so every future `plugin:install` and `make:command` invocation resolves cleanly.

- [Prerequisites](#prerequisites)
- [Basic Usage](#basic-usage)
- [Synopsis](#synopsis)
- [What It Writes](#what-it-writes)
- [Pubspec Injection](#pubspec-injection)
- [Idempotency](#idempotency)
- [Fast-CLI Auto-Chain](#fast-cli-auto-chain)
- [Examples](#examples)
- [Related Documentation](#related-documentation)

---

## Prerequisites

Add `dowel` to the project before invoking `install`. The package needs to resolve from `pubspec.yaml` so the substrate CLI is discoverable via `dart run`:

```bash
dart pub add dowel
```

Equivalent manual edit, then `dart pub get`:

```yaml
dependencies:
  dowel: ^0.0.21
```

`install` itself re-injects the dep at scaffold time (path-dep when `.dart_tool/package_config.json` resolves `dowel` to a relative `rootUri`, otherwise `dowel: any`), so the pub-add step is idempotent with the scaffold's own pubspec writes.

---

## Basic Usage

```bash
dart run dowel install
```

Run once in a new Flutter project root. The command reads the project name from `pubspec.yaml`, writes the four artefacts listed below, and prints a summary. After this completes, use the consumer wrapper alias:

```bash
dart run dowel <cmd>
```

or, after the fast-CLI build finishes:

```bash
./bin/dowel <cmd>
```

---

## Synopsis

Full signature as declared in `lib/src/commands/install_command.dart`:

```
install
  {--force : Overwrite files even when they already exist}
```

| Flag | Effect |
|:---|:---|
| `--force` | Overwrite `bin/dispatcher.dart`, the two generated barrels, and `bin/dowel` even when they are already present. Does not re-inject already-present pubspec entries. |

---

## What It Writes

`install` produces four artefacts in this order:

### 1. `bin/dispatcher.dart`

A generated CLI entry point that wires the consumer's own commands and plugin providers into the dowel runtime. The file is written from the `dispatcher.dart.stub` template with `{{ name }}` substituted to the `pubspec.yaml` project name. Header comment: `GENERATED by 'install' command; DO NOT EDIT. Regenerate via 'make:command' or 'plugins:refresh'.`

Structure:
- imports `package:<name>/app/commands/_index.g.dart as consumer_commands`
- imports `package:<name>/app/_plugins.g.dart as plugins`
- defines `_ConsumerCommandsProvider extends DowelServiceProvider` registering the consumer barrel
- `main(List<String> args)` calls `runDowel(args, baseProviders: [_ConsumerCommandsProvider(), ...plugins.autoDiscoveredProviders()], delegateToConsumer: false, collectMcpTools: args.isNotEmpty && args.first == 'mcp:serve')`

The `collectMcpTools` parameter is conditionally enabled only when the command is `mcp:serve`, so plugin providers' MCP tools register for the server without overhead on non-MCP CLI invocations.

### 2. `lib/app/_plugins.g.dart`

The plugins codegen barrel. Written as an empty-but-valid barrel on first install. `plugin:install` and `plugins:refresh` regenerate this file when plugins are added or removed. Never edit by hand: the source of truth is `.dowel/plugins.json`.

### 3. `lib/app/commands/_index.g.dart`

The commands codegen barrel. Written as an empty-but-valid barrel on first install. `make:command` and `commands:refresh` regenerate this file as new command files appear under `lib/app/commands/`. Never edit by hand.

### 4. `bin/dowel` (via Fast-CLI Auto-Chain)

A POSIX shell wrapper written by the `make:fast-cli` sub-command, which `install` calls in-process at the end of the scaffold phase. See [Fast-CLI Auto-Chain](#fast-cli-auto-chain) for details.

---

## Pubspec Injection

`install` injects a `dowel` dependency into `pubspec.yaml` after writing the four artefacts. Two injection modes:

**Path-dep mode (monorepo)**

When `.dart_tool/package_config.json` lists `dowel` with a *relative* `rootUri` (sibling-package monorepo workflow), `install` resolves the path against the consumer root and writes a `path:` dependency:

```yaml
dependencies:
  dowel:
    path: ../dowel
```

A `file://` absolute URI or any other absolute `rootUri` (the shape pub-cache produces) skips this branch and falls through to pub.dev mode.

**Pub.dev mode**

When no local relative-rootUri entry resolves, `install` injects the unconstrained version form so the next `dart pub get` (or `flutter pub get`) pulls the published package:

```yaml
dependencies:
  dowel: any
```

Run `dart pub get` (or `flutter pub get`) after `install` completes to resolve to a concrete version. Tighten the constraint by hand (e.g. `^0.0.21`) once the consumer has chosen a baseline.

The injection is idempotent: if `pubspec.yaml` already contains a `dowel:` key under `dependencies:`, neither form is written again (regardless of `--force`).

---

## Idempotency

Re-running `install` without `--force` is a no-op when the artefacts already exist. Each file goes through a `_shouldWrite(path, force)` guard: if the file exists and `force` is false, the write is skipped and a `[skip]` line is printed for that artefact. The pubspec injection is always idempotent (key presence check, independent of `--force`).

Pass `--force` to overwrite all four artefacts unconditionally. Useful after renaming the project or updating the stub template to a newer version:

```bash
dart run dowel install --force
```

`--force` is forwarded to the `make:fast-cli` auto-chain as well, so `bin/dowel` is rewritten and the AOT binary is recompiled from scratch.

---

## Fast-CLI Auto-Chain

At the end of `scaffoldInto`, `install` calls `MakeFastCliCommand.scaffoldInto(root, force, ctx)` in-process. This produces `bin/dowel`, compiles the AOT binary under `.dowel/cli-bundle/`, and patches `.gitignore`. The call happens only after all scaffold writes and pubspec injection succeed, so a partial failure in the scaffold phase does not leave a compiled binary that references a missing dispatcher.

The fast-CLI step is not separately gated: if `dart build cli` fails (e.g. the Dart SDK is too old to support it, the toolchain is missing, or the build itself errors), `make:fast-cli` returns a non-zero exit code and `install` propagates that failure. The scaffold artefacts written before the failure remain on disk so the project is still usable via `dart run dowel <cmd>` (the slower fallback). Re-running `install --force` after fixing the underlying issue recompiles `bin/dowel` and the AOT cache.

See [make:fast-cli](https://anilcancakir.com/dowel/docs/v0.0/commands/make-fast-cli.md) for the full performance profile, cache-hit behaviour, and POSIX-only caveat.

---

## Examples

### 1. Fresh install in a new Flutter project

```bash
flutter create my_app
cd my_app
dart pub add dowel
dart run dowel install
```

Output:
```
  write   bin/dispatcher.dart
  write   lib/app/_plugins.g.dart
  write   lib/app/commands/_index.g.dart
  inject  pubspec.yaml (dowel: any)
  write   bin/dowel (Building dowel CLI, one-time ~8s...)
Done. Run './bin/dowel status' to verify.
```

### 2. Force-overwrite after project rename

```bash
dart run dowel install --force
```

Regenerates `bin/dispatcher.dart` with the updated project name and recompiles `bin/dowel`.

### 3. Native-asset hooks note

`install` uses `dart build cli` (via the `make:fast-cli` auto-chain) to compile `bin/dispatcher.dart` into an AOT binary. This requires Dart 3.5 or later because transitive dependencies may declare `hook/build.dart` build hooks. On earlier SDKs, `bin/dowel` is not written but the rest of the scaffold completes normally. Use `dart run dowel <cmd>` as the fallback invocation form on those environments.

### 4. Monorepo path-dep install

In a monorepo where `dowel` lives at `../dowel`, run `flutter pub get` once to populate `.dart_tool/package_config.json`, then:

```bash
dart run dowel install
```

The path-dep form is detected automatically and written to `pubspec.yaml`. No flag needed.

---

## Related Documentation

- [make:command](https://anilcancakir.com/dowel/docs/v0.0/commands/index.md): scaffold a single `DowelCommand` subclass under `lib/app/commands/` and regenerate `_index.g.dart`.
- [plugin:install](https://anilcancakir.com/dowel/docs/v0.0/commands/plugin-install.md): register a third-party plugin after `flutter pub add`; requires the `lib/app/_plugins.g.dart` barrel that `install` writes.
- [make:fast-cli](https://anilcancakir.com/dowel/docs/v0.0/commands/make-fast-cli.md): the sub-command auto-chained by `install`; run it standalone to rebuild `bin/dowel` without touching the scaffold artefacts.
- [Getting Started: Installation](https://anilcancakir.com/dowel/docs/v0.0/getting-started/installation.md): step-by-step walkthrough from `dart pub add` to first `./bin/dowel status` for both vanilla Flutter and magic-stack projects.
