Skip to content
Draft
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"backlog": "ai-driven-dev/framework#891",
"written_at": "2026-10-06T15:05:28Z",
"written_by": "aidd-dev:01-plan"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
My confidence level of correctness now: 95%

# Correctness (100%)
- The delivered change matches the agreed issue #891 contract: unsupported user-scope plugin selections retain the existing cause/remedies and exit 1 through the presentation error handler. `setup.ts:156-195` guards constructor validation without moving policy out of `SetupFlow`.
- Independent focused verification against commit `65d1917a`: 62 tests passed, including seven hermetic built-binary tests. Exact stderr assertions exclude stack traces and bundle dumps; supported user setup still leaves the project unchanged. Full suite and required repository gates are evidenced in the review report.
- The README distinguishes user registration, native activation, plugin file installation and project hooks. Support derives from present profiles; no global installer or configuration rewriting was introduced. Help enumerates supported tools from the existing predicate rather than duplicating policy.
- Edge cases considered: all/recommended/named plugin modes; empty or omitted AI selection; IDE selection; unsupported AI tools; project-scope behavior; supported user setup; missing native binaries. Broader setup construction errors also reach the same handler. Invalid parser inputs keep their existing handling.
- Trust answers are all yes: the implementation is appropriately small, consequential choices preserve existing policy, and the user's end-to-end refusal and discoverability needs are met. No issue-contract gap or delivery blocker found.

# Deal breakers
- None.

# Suggestions (enhancements only)
- Clarify the plan's “dependencies are not created” wording to identify the setup action. Existing `cli.ts:55-61` can construct dependencies in the unchanged startup update-check hook; command tests and hermetic e2e prove the intended command-local boundary. The caller has confirmed this scope and owns the wording correction. No code expansion is warranted for issue #891.
68 changes: 68 additions & 0 deletions aidd_docs/tasks/2026_10/2026_10_06_setup-validation/phase-1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
status: reviewed
---

# Instruction: Guard setup validation

## Architecture projection
```txt
cli/
src/presentation/commands/setup.ts modify: guard constructor and clarify help
tests/presentation/commands/setup-wiring.integration.test.ts modify: prove constructor failures render before dependency creation
tests/e2e/setup-scope-user.e2e.test.ts modify: prove clean refusal in the real binary
tests/golden/snapshots/help/surface.json modify: record the intended setup help change
README.md modify: document current scope support and restrictions
```
No source files are created or deleted. Domain validation and tool activation remain unchanged.

## User Journey
```mermaid
flowchart TD
A[Run setup with user scope] --> B{Supported options?}
B -->|No| C[Read validation message and remedies; exit 1]
B -->|Yes| D[Register shared source and supported tool; exit 0]
E[Read setup help and README] --> F[Discover scope limits before installation]
```

## Test Scope
```mermaid
journey
section Setup
Create isolated project and user directories => no real profile touched: 5: system
section Happy path
Run supported user-scope setup with plugins none => exit 0 and project unchanged: 5: cli
Read setup help => restrictions discoverable: 5: cli
section Edge case - unsupported plugin mode
User scope with all or recommended or named plugins => setup => message and remedies with exit 1 and no stack or bundle dump: 1: cli
section Edge case - other constructor validation
User scope with no AI tools or an IDE or an unsupported AI tool => setup => clean validation error before dependencies: 1: cli
section Teardown
Remove isolated directories => baseline restored: 5: system
```

## Wireframe
Not applicable: command-line validation only.

## Tasks to do
### 1) Reproduce and guard constructor errors
1. Add regression tests and demonstrate failure against the current command.
2. Move SetupFlow construction and dependent banner into the existing try block before dependency creation.
3. Preserve the existing error messages, exit status, domain policy, and supported setup behavior.

### 2) Explain shipped scope support
1. Extend the existing README scope documentation with support grounded in current profiles and registry.
2. Clarify setup help: explicit supported AI tools, no IDE tools, no plugin enabling at user scope; native activation depends on available host CLI.
3. Distinguish setup registration from plugin installation and avoid promising global configuration rewriting.
4. Regenerate the existing help golden snapshot and confirm only setup help changes.

### 3) Validate
1. Run relevant command, domain, and user-scope e2e tests, typecheck, architecture suite, and lint on changed files.
2. Reproduce the issue through the hermetic built-binary tests after other checks.
3. Report exact commands and results, including limitations.

## Test acceptance criteria
| Task | Acceptance criteria |
| --- | --- |
| 1 | Unsupported plugin modes print the existing cause and remedies, exit 1, and emit no exception name, stack frame, or minified bundle; the setup action does not create dependencies. Other constructor validation errors use the same boundary. |
| 2 | Help and README accurately explain current user-scope setup and plugin installation limitations from source; no installation capability is added. |
| 3 | Relevant tests, typecheck, architecture checks, and changed-file lint pass; built-binary reproduction runs with isolated user directories. |
36 changes: 36 additions & 0 deletions aidd_docs/tasks/2026_10/2026_10_06_setup-validation/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
objective: "Setup renders constructor validation failures as clean CLI errors and documents the current user-scope support limits."
status: reviewed
---

# Plan: Render setup validation errors

## Overview
| Field | Value |
| --- | --- |
| **Goal** | Refuse unsupported setup options with a useful message and exit 1, without a stack trace or bundle dump. |
| **Source** | https://github.com/ai-driven-dev/framework/issues/891 and its follow-up comment |

## Phases
| # | Phase | File |
| --- | --- | --- |
| 1 | Guard setup construction and explain user scope | [phase-1.md](./phase-1.md) |

## Resources
| Source | Verified |
| --- | --- |
| `cli/src/presentation/commands/setup.ts` | SetupFlow is constructed before the existing error boundary. |
| `cli/src/contexts/framework/domain/setup-flow.ts` | Constructor validation intentionally refuses plugins and other unsupported user-scope options. |
| `cli/src/presentation/error-handler.ts` | Existing handler prints the message and exits 1. |
| `cli/src/contexts/tools/domain/registry.ts` and profiles | User-scope setup requires native activation or a user install directory; plugin installation scope is a separate declaration. |
| `cli/tests/e2e/helpers.ts` | Built-binary runs isolate user directories and remove host tools from PATH. |
| `cli/aidd_docs/memory/architecture.md` and `testing.md` | Preserve context boundaries; regression evidence must exercise the built binary. |

## Decisions
| Decision | Why |
| --- | --- |
| Move construction into the existing presentation error boundary. | Covers all current and future constructor validation without duplicating domain rules. |
| Reuse README scope documentation and clarify setup help. | Make shipped restrictions discoverable without inventing broader global installation support. |
| Add focused command and built-binary regression coverage. | Domain tests alone cannot detect an escaped command exception. |
| Run typecheck, relevant tests, architecture checks, lint, and hermetic CLI journey. | Validate behavior and responsibility placement; no browser surface exists. |
| Preserve pre-existing `.gitignore` and `.hermes.md` changes outside task commits. | They are unrelated workspace changes. |
36 changes: 36 additions & 0 deletions aidd_docs/tasks/2026_10/2026_10_06_setup-validation/review.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Review: Render setup validation errors
- **Verdict**: approve
- **Diff**: `156f5432...65d1917a`
- **Axes run**: code, functional, relevancy
- **Date**: 2026_10_06
- **Findings**: 0 critical, 0 warning, 0 minor
- **Score**: 100% of acceptance criteria and baseline checklist fulfilled; no severity adjustment.

## Phases
### Phase 1 — Guard setup construction and explain user scope
- [x] Unsupported plugin modes retain the cause and remedies, exit 1, and emit no exception name, stack frame, or bundle dump; the setup action creates no dependencies. Other constructor validation uses the same boundary. — `cli/src/presentation/commands/setup.ts:156`, `cli/src/presentation/commands/setup.ts:194`, `cli/tests/presentation/commands/setup-wiring.integration.test.ts:261`, `cli/tests/e2e/setup-scope-user.e2e.test.ts:28`.
- [x] Help and README describe shipped user-scope setup and plugin installation limits from current profiles; no installation capability is added. — `cli/src/presentation/commands/setup.ts:122`, `cli/README.md:71`, `cli/src/contexts/tools/domain/registry.ts:172`, `cli/src/contexts/tools/domain/profiles/cursor/profile.ts:120`, `cli/src/contexts/tools/domain/profiles/claude/profile.ts:125`, `cli/src/contexts/tools/domain/profiles/codex/profile.ts:194`, `cli/src/contexts/tools/domain/profiles/copilot/profile.ts:302`; golden diff changes only setup help.
- [x] Relevant tests, typecheck, architecture checks and lint pass; built-binary reproduction isolates user directories and host binaries. — checker rerun: 62 passed across domain, command and user-scope e2e; `cli/tests/e2e/helpers.ts:66`, `cli/tests/e2e/helpers.ts:161`, `cli/tests/e2e/helpers.ts:196`, `cli/tests/e2e/global-setup.ts:30`; `/tmp/aidd-891-commit.log:55`, `/tmp/aidd-891-commit.log:727`, `/tmp/aidd-891-push.log:828`.

## Findings
| Sev | Kind | Phase | Location | Issue | Fix |
| --- | --- | --- | --- | --- | --- |
| - | - | - | - | None. | - |

## Verification
| Metric | Value |
| --- | --- |
| Verified | 100% (3/3 acceptance criteria) |
| Files checked | All eight changed files: `plan.md`, `phase-1.md`, `backlog-link.json`, `cli/README.md`, `cli/src/presentation/commands/setup.ts`, `cli/tests/e2e/setup-scope-user.e2e.test.ts`, `cli/tests/golden/snapshots/help/surface.json`, `cli/tests/presentation/commands/setup-wiring.integration.test.ts`; canonical domain flow, error handler, registry, profiles, machine-scope use case, activation flow, binary helpers, CLI startup and project rules also inspected. |
| Unchecked | none |
| Unplanned | none; task metadata links the issue and records the agreed plan. |
| No information duplication | Fulfilled: constructor policy remains solely in `SetupFlow`; error rendering reuses `ErrorHandler`; help derives supported tools from the same registry predicate; README is the single detailed support matrix. Exact error assertions and the required golden snapshot verify their respective public contracts. |
| No incoherence or contradiction | Fulfilled: source profiles support the documented matrix, missing-host warning, native scopes and Cursor project-hook caveat. `setup --help` golden change is isolated to setup. |
| No over-engineering | Fulfilled: one existing error boundary extended to cover construction, no new abstraction, installer, dependency or configuration writer. |
| No dead code or debug leftovers | Fulfilled: every added import is used; changed lines contain no debug logs, commented blocks or silent TODOs; knip green at `/tmp/aidd-891-push.log:836`. |
| Architecture and declared rules | Fulfilled: command layer catches and exits; domain invariant remains in its constructor; presentation reads public registry capability declarations; dependencies remain in runtime wiring. `cli/.claude/rules/00-architecture/0-error-handling.md:8`, `0-hexagonal.md:11`, `0-contexts.md:13`; 140 architecture assertions, lint, typecheck and type honesty green in commit log. |
| Independent focused command | `PATH=/opt/homebrew/Cellar/node/26.8.2/bin:$PATH pnpm --dir cli exec vitest run --project=unit --project=integration --project=e2e tests/presentation/commands/setup-wiring.integration.test.ts tests/contexts/framework/domain/setup-flow.unit.test.ts tests/e2e/setup-scope-user.e2e.test.ts` => 3 files passed, 62 tests passed (23 domain, 32 command, 7 e2e), exit 0. |
| Full-suite and repository evidence | Inspected `/tmp/aidd-891-full-test.log:853`: 529 files passed, 6805 tests passed, one opt-in Kilo test skipped; repeated full-suite result and knip green in push log. Commit log proves 549 repository tests passed, zero failed, plus documentation checks and CLI gates. Full suite not repeated without a new concern. |
| Diff hygiene | `git diff --check 156f5432..65d1917a` => exit 0, no output. HEAD independently verified as `65d1917a4b7f668ca5bd804fe05fc142a179099d`. |
| Acceptance wording ambiguity | The original phrase “dependencies are not created” is broader than its command-local evidence. Caller explicitly confirmed it means the setup action's `createDeps` call (`setup.ts:172`). Existing `cli.ts:55-61` preAction can initialize dependencies for update checking first; hermetic tests disable it with `AIDD_SKIP_UPDATE_CHECK=1`. This startup behavior is unchanged and outside issue #891; caller owns clarification of the plan wording. |
| Actual end-to-end need | Fulfilled: real binary refuses all, recommended and named plugin selections with exact one-line stderr and exit 1; supported user setup remains green and leaves the project untouched. Current constructor failures are rendered before the welcome banner and command dependency graph. No contract gap found. |
21 changes: 20 additions & 1 deletion cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ aidd update
```

The first command bootstraps the project: manifest, default marketplace, tool configs, plugins.
`--scope user` on `setup` registers the framework source and native activation machine-wide instead, and writes nothing under the project.
`--scope user` on `setup` registers the framework source and supported tools machine-wide instead, and writes nothing under the project. See the scope support below.

## Authentication

Expand Down Expand Up @@ -68,6 +68,25 @@ Run `aidd --help`, then a group's own `--help`, for flags this page does not rep

`setup`, `doctor`, `sync` and `clean` accept `--scope <project|user>`. Project scope is the default and acts on this project alone.

`setup --scope user` requires an explicit supported `--ai` list, no `--ide`, and `--plugins none` (or omit `--plugins` in a scripted run). It records the source and tools in the user registry without installing tool configuration files or enabling plugins. `--ai all` includes unsupported tools and is refused.

| Tool | `setup --scope user` | `plugin install` file scope |
| --- | --- | --- |
| `claude` | Registers the source; drives Claude's native CLI at user scope | `project` |
| `codex` | Registers the source; drives Codex's native CLI machine-wide | `project` |
| `copilot` | Registers the source; drives Copilot's native CLI machine-wide | `project` |
| `cursor` | Records the source and tool only; no native activation | `user`, under `~/.cursor/plugins/local/` |
| `opencode`, `kilo` | Unsupported; use project-scope setup | `project` |
| `vscode` (`--ide`) | Unsupported; use project-scope setup | Not an AI plugin target |

Native activation requires the corresponding `claude`, `codex`, or `copilot` executable on `PATH`. When it is missing, registration succeeds with a warning and activation remains unrun; install the host CLI, then run `aidd sync --scope user`.

```sh
aidd setup --scope user --ai claude,codex,copilot --plugins none --yes
```

Setup registration and plugin installation have separate scope rules. `aidd plugin install <name> --tool cursor --scope user` installs Cursor plugin files in its user directory, while plugin installation for the other AI tools uses project scope. Codex and Copilot's native enablement is machine-wide even though their plugin file scope is `project`. Cursor plugin installation can still write project hooks and the project manifest. User-scope setup does not rewrite global rules, agents, skills, commands, or MCP configuration.

### Framework

| Command | Does |
Expand Down
45 changes: 29 additions & 16 deletions cli/src/presentation/commands/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import type { Command } from "commander";
import { MarketplaceSourceMode } from "../../contexts/distribution/domain/marketplace-source-mode.js";
import { SetupUseCase } from "../../contexts/framework/application/setup-use-case.js";
import { SetupFlow } from "../../contexts/framework/domain/setup-flow.js";
import { assertToolIdsMatchCategory } from "../../contexts/tools/domain/registry.js";
import {
assertToolIdsMatchCategory,
getAllRegisteredTools,
supportsUserScopeActivation,
} from "../../contexts/tools/domain/registry.js";
import type { ToolId } from "../../kernel/tool.js";
import { AI_TOOL_IDS, IDE_TOOL_IDS } from "../../kernel/tool.js";
import { createDeps } from "../../runtime/wiring/framework.js";
Expand Down Expand Up @@ -113,7 +117,16 @@ export function registerSetupCommand(program: Command): void {
.option(
"--scope <scope>",
"project (default) installs into this project alone; user registers the shared " +
"framework source and native activation machine-wide, writing nothing under this project"
"framework source and supported tools machine-wide, writing nothing under this project; " +
"see user-scope requirements below"
)
.addHelpText(
"after",
() =>
"\nUser scope:\n" +
` Pass --ai ${[...getAllRegisteredTools().keys()].filter(supportsUserScopeActivation).sort().join(",")} (choose one or more), --plugins none, and no --ide.\n` +
" Native activation requires the corresponding host CLI on PATH.\n" +
" Tools without native activation are registered only; setup installs no plugins or tool configuration files."
)
.action(async (cmdOptions: SetupCmdOptions) => {
const { verbose, output, projectRoot } = parseGlobalOptions(program);
Expand All @@ -140,22 +153,22 @@ export function registerSetupCommand(program: Command): void {
);

const registerDefaultMarketplace = cmdOptions.defaultMarketplace !== false;
const flow = new SetupFlow({
projectRoot,
source,
aiTools: toolIds.aiTools,
ideTools: toolIds.ideTools,
pluginMode,
pluginNames,
interactive,
force: false,
registerDefaultMarketplace,
scope,
});
try {
const flow = new SetupFlow({
projectRoot,
source,
aiTools: toolIds.aiTools,
ideTools: toolIds.ideTools,
pluginMode,
pluginNames,
interactive,
force: false,
registerDefaultMarketplace,
scope,
});

if (interactive) printWelcomeBanner(output);
if (interactive) printWelcomeBanner(output);

try {
const deps = await createDeps(projectRoot, { verbose }, output);

const result = await new SetupUseCase(
Expand Down
Loading
Loading