---
name: cli-app-sync
description: Detect and fix template drift between SmartStack.app (source of truth) and CLI templates
argument-hint: "[report|fix|check <file>]"
model: sonnet
allowed-tools: Read, Grep, Glob, Bash, Edit, Write
---

## Current state (auto-injected)
- CLI version: !`node -p "require('./package.json').version" 2>/dev/null || echo "unknown"`
- CLI branch: !`git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown"`
- App branch: !`git -C "D:/01 - projets/SmartStack.app/02-Develop" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown"`
- App last commit: !`git -C "D:/01 - projets/SmartStack.app/02-Develop" log --oneline -1 2>/dev/null || echo "unknown"`

<objective>
Detect drift between SmartStack.app (the platform / source of truth) and the CLI project templates used by `ss init`.

SmartStack.app defines the reference architecture. The CLI templates generate **client projects** that consume the platform via NuGet/npm. Some differences are **intentional by design** (see exclusions below). This skill identifies **unintentional drift** that should be corrected.

See [references/comparison-map.md](references/comparison-map.md) for the full file mapping and exclusion rules.
</objective>

<quick_start>
```bash
/cli-app-sync                # Full drift report (read-only)
/cli-app-sync report         # Same as above
/cli-app-sync fix            # Detect drift + apply fixes interactively
/cli-app-sync check Program  # Check a single file mapping
```
</quick_start>

<subcommands>

| Command | Description |
|---------|-------------|
| `/cli-app-sync` | Full drift report across all comparison points |
| `/cli-app-sync report` | Same as above (explicit) |
| `/cli-app-sync fix` | Detect drift and propose fixes interactively |
| `/cli-app-sync check <name>` | Check a single comparison point by name |

</subcommands>

<paths>

**Source of truth (SmartStack.app):**
```
APP_ROOT = D:/01 - projets/SmartStack.app/02-Develop
APP_API  = $APP_ROOT/src/SmartStack.Api
APP_WEB  = $APP_ROOT/web/smartstack-web
```

**CLI templates (to validate):**
```
CLI_ROOT      = D:/01 - projets/SmartStack.cli/02-Develop
CLI_TEMPLATES = $CLI_ROOT/templates/project
CLI_INIT      = $CLI_ROOT/src/commands/init.ts
```

</paths>

<workflow>

## Step 1: Resolve paths and verify access

```bash
APP_ROOT="D:/01 - projets/SmartStack.app/02-Develop"
CLI_ROOT="D:/01 - projets/SmartStack.cli/02-Develop"

# Verify both projects are accessible
[ -d "$APP_ROOT/src/SmartStack.Api" ] || { echo "ERROR: SmartStack.app not found at $APP_ROOT"; exit 1; }
[ -d "$CLI_ROOT/templates/project" ] || { echo "ERROR: CLI templates not found at $CLI_ROOT"; exit 1; }
```

## Step 2: Run comparison for each mapping

For each entry in the [comparison map](references/comparison-map.md):

1. **Read the reference file** from SmartStack.app
2. **Read the template file** from CLI (either `.template` file or inline content in `init.ts`)
3. **Compare** the relevant patterns/sections (not byte-for-byte — templates have `{{ProjectName}}` placeholders)
4. **Classify** the result: `OK`, `DRIFT`, or `INTENTIONAL`

### Comparison strategy by type

**Template files** (`templates/project/*.template`):
- Read both files
- Replace `{{ProjectName}}` with `SmartStack` in the template for comparison
- Compare structure, imports, method calls, middleware order

**Inline templates in `init.ts`**:
- Extract the template string from `init.ts` (look for the variable assignment)
- Compare key properties/patterns against the reference file
- Focus on: dependency versions, compiler options, proxy config, CSS directives

## Step 3: Generate report

```
================================================================================
              CLI ↔ APP TEMPLATE SYNC REPORT
================================================================================

SmartStack.app: {branch} @ {commit}
SmartStack.cli: v{version} @ {branch}
Date: {date}

COMPARISON POINTS: {total}
--------------------------------------------------------------------------------

  [OK]    Program.cs — Serilog, Kestrel, Swagger, AppInsights present
  [DRIFT] package.json — @types/node ^24.0.0 vs ^26.0.0 in app
  [DRIFT] vite.config.ts — bypass() present but missing ws reconnect
  [OK]    tsconfig.json — ES2022, verbatimModuleSyntax, erasableSyntaxOnly
  [OK]    index.css — @custom-variant dark present
  [OK]    DependencyInjection.Application — MediatR warning present
  [OK]    DependencyInjection.Infrastructure — SQL Server pattern matches
  [SKIP]  App.tsx — Intentionally different (client uses PageRegistry+DynamicRouter v3.7+)
  [SKIP]  ExtensionsDbContext — Intentionally simplified

--------------------------------------------------------------------------------
SUMMARY: {ok} OK | {drift} DRIFT | {skip} SKIPPED
================================================================================
```

## Step 4: Handle drifts (fix mode)

If running `/cli-app-sync fix` and drifts are detected:

```yaml
AskUserQuestion:
  header: "Fix drifts"
  question: "Drifts detected. How do you want to proceed?"
  options:
    - label: "Fix all (Recommended)"
      description: "Apply all fixes automatically"
    - label: "Fix interactively"
      description: "Review and approve each fix individually"
    - label: "Report only"
      description: "Show details without fixing"
  multiSelect: false
```

For each drift in fix mode:
1. Show the diff (what changed in app vs what the template has)
2. Propose the fix
3. Apply using Edit tool (for `.template` files) or inline edit (for `init.ts`)

## Step 5: Post-fix verification

After applying fixes:
```bash
cd "$CLI_ROOT" && npm run build 2>&1
```

If build succeeds, display summary of changes.

</workflow>

<intentional_differences>

These differences are **by design** and should always be marked `[SKIP]`:

| File/Pattern | Reason |
|---|---|
| `App.tsx` — routing pattern (`PageRegistry`+`DynamicRouter` v3.7+) | Client projects use their own routing entry point, not platform routing |
| `ExtensionsDbContext` | Intentionally simplified vs `CoreDbContext` — different architectural role |
| `api.ts` | Re-exports SmartStack client — wrapper pattern is correct |
| `DependencyInjection.Infrastructure.cs` | SQL Server connection pattern identical by design |
| Skills/Agents/Hooks | Installed globally via `ss install`, not by `ss init` |
| SmartStack.app-only skills | `bugfix-issue`, `feature-test`, `sonar`, `version-bump` are platform-specific |
| `appsettings.json` | Client projects have a simplified config (no core service settings) |

</intentional_differences>

<comparison_categories>

### Backend comparisons

| ID | App reference | CLI template | Key patterns to check |
|---|---|---|---|
| `program-cs` | `src/SmartStack.Api/Program.cs` | `templates/project/Program.cs.template` | Serilog bootstrap, Kestrel HTTP/1.1, appsettings.Local.json, UseSmartStackSerilog, AppInsights, UseSmartStackSwagger, try/catch/finally |
| `di-app` | *(no direct equivalent)* | `templates/project/DependencyInjection.Application.cs.template` | MediatR warning comment, no double-registration |
| `di-infra` | `src/SmartStack.Infrastructure/DependencyInjection.cs` | `templates/project/DependencyInjection.Infrastructure.cs.template` | SQL Server connection pattern, AddDbContext |
| `appsettings` | `src/SmartStack.Api/appsettings.json` | `templates/project/appsettings.json.template` | Serilog config section, ConnectionStrings pattern, Logging sinks |

### Frontend comparisons

| ID | App reference | CLI template (in `init.ts`) | Key patterns to check |
|---|---|---|---|
| `package-json` | `web/smartstack-web/package.json` | `init.ts` → `packageJson` variable | Dependency versions (`@types/node`, `typescript`, `eslint-plugin-react-refresh`), testing stack (`vitest`, `@testing-library/*`), scripts (`test`, `test:watch`, `test:coverage`) |
| `vite-config` | `web/smartstack-web/vite.config.ts` | `init.ts` → `viteConfig` variable | Proxy bypass() function, plugin list, resolve aliases |
| `tsconfig` | `web/smartstack-web/tsconfig.json` or `tsconfig.app.json` | `init.ts` → `tsConfig` variable | `target`, `lib`, `verbatimModuleSyntax`, `erasableSyntaxOnly`, no `isolatedModules` |
| `index-css` | `web/smartstack-web/src/index.css` | `init.ts` → `indexCss` variable | `@import "tailwindcss"`, `@source` directive, `@custom-variant dark` |

</comparison_categories>

<extraction_patterns>

### Extracting inline templates from `init.ts`

Templates in `init.ts` are assigned as template literals or objects. Use these patterns to locate them:

```
package.json  → search for: "const packageJson = {"
vite.config   → search for: "const viteConfig = \`"
tsconfig      → search for: "const tsConfig = {"
index.css     → search for: "const indexCss = \`"
```

### Comparing versions

For `package.json` dependencies, compare:
- Major version range: `^22.0.0` vs `^24.0.0` → DRIFT if major differs by > 1
- Tilde vs caret: `~5.9.0` vs `^5.7.0` → DRIFT if strategy differs
- Missing packages: present in app but absent in template → DRIFT
- Extra packages in template are OK (client-specific needs)

### Comparing TypeScript config

Compare key compiler options:
- `target` and `lib` → must match
- `verbatimModuleSyntax` → must be present (replaces deprecated `isolatedModules`)
- `erasableSyntaxOnly` → must be present
- Other options → informational only

</extraction_patterns>

<output_format>

### Per-comparison detail (verbose)

```
--- program-cs ---
Reference: SmartStack.app/src/SmartStack.Api/Program.cs
Template:  templates/project/Program.cs.template

Checks:
  [OK] Serilog bootstrap logger (Log.Logger = new LoggerConfiguration...)
  [OK] try/catch/finally pattern
  [OK] ConfigureKestrel HTTP/1.1
  [OK] appsettings.Local.json loading
  [OK] UseSmartStackSerilog()
  [OK] Application Insights conditional
  [OK] UseSmartStackSwagger()
  [OK] Log.Information start/success messages

Status: OK
```

### Drift detail

```
--- package-json ---
Reference: SmartStack.app/web/smartstack-web/package.json
Template:  init.ts → packageJson

Drifts:
  [DRIFT] @types/node: template=^24.0.0, app=^26.0.0
  [DRIFT] Missing devDependency: @testing-library/dom

Status: DRIFT (2 issues)
```

</output_format>

<success_criteria>
- All comparison points from the map are checked
- Intentional differences are correctly identified as SKIP
- Drift detection catches: missing patterns, outdated versions, removed options
- Fix mode correctly updates template files and init.ts inline templates
- Build passes after fixes are applied
- Report is clear, actionable, and easy to scan
</success_criteria>
