---
name: erp-kit-update-advisor
description: Advise whether the consumer repo should update `@tailor-platform/erp-kit` and present the concrete migration impact, including a list of files in the repo that the breaking changes touch. Use when the user asks "should I update erp-kit?", before planning an update, or as a periodic dependency review. This skill is about a forward-looking action recommendation, not a backward-looking score (use erp-kit-score for the latter).
metadata:
  erp-kit-version: "0.38.0"
---

# erp-kit Update Advisor

Compare the consumer's installed `@tailor-platform/erp-kit` against the latest published version, classify the changelog between them, locate the files in the repo that the breaking changes touch, and emit a recommendation.

This skill is intentionally **forward-looking** — its output is "should you update now, what changes if you do, and which files do you have to edit?" — separate from `erp-kit-score`, which evaluates the repo's current state.

## Version Check

Run `npx erp-kit internal measure versions` from the repo root. If `status` is `"violations"`, relay the findings (each states its own fix) and stop; otherwise proceed.

## When to Use

- User asks "should I update erp-kit?" or "is there a new version?"
- Before planning an update, to surface what will change
- Periodic dependency review

## Workflow

```
SETUP → RESOLVE LATEST → CLASSIFY CHANGELOG → IDENTIFY AFFECTED FILES → RECOMMEND
```

## Step 1: Setup

Define shared context:

- `REPO_ROOT`: argument or current working directory. Must contain a `package.json` and a `node_modules/@tailor-platform/erp-kit/` directory.
- `INSTALLED_VERSION`: read from `node_modules/@tailor-platform/erp-kit/package.json` `version` field
- `DECLARED_VERSION`: read from the repo's `package.json` `dependencies` or `devDependencies` `@tailor-platform/erp-kit` value

If `@tailor-platform/erp-kit` is not a dependency, stop with: "erp-kit is not installed in this repo."

## Step 2: Resolve latest version

Run:

```bash
npm view @tailor-platform/erp-kit version
```

Capture as `LATEST_VERSION`. If unreachable, note that and proceed with what is known.

Compute the gap from `INSTALLED_VERSION` to `LATEST_VERSION` as `majorGap` / `minorGap` / `patchGap`.

Also detect any mismatch between `INSTALLED_VERSION` and the version declared in `package.json` (e.g. declared `^0.24.0` but installed `0.20.0` because of a stale lockfile). Surface this as a separate observation.

## Step 3: Fetch and classify the latest changelog

Fetch the latest `CHANGELOG.md` from npm:

```bash
curl -sL $(npm view @tailor-platform/erp-kit@latest dist.tarball) | tar -xzO package/CHANGELOG.md
```

This streams the latest published tarball and extracts only `CHANGELOG.md` to stdout — no temp file, no third-party CDN.

Why not `node_modules/.../CHANGELOG.md`: the locally installed copy stops at `INSTALLED_VERSION`. The entries advisor needs to classify (between installed and latest) are by definition not in the local copy.

Prerequisites: Unix-like environment with `npm`, `curl`, `tar`; outbound HTTPS to the npm registry. If the fetch fails (network, registry unreachable, empty output), report the failure and stop — advisor cannot proceed without the latest changelog.

Identify entries between `INSTALLED_VERSION` (exclusive) and `LATEST_VERSION` (inclusive). Group each into:

- **material** — pattern changes, BREAKING markers, removed APIs, security fixes
- **cosmetic** — refactors, doc updates, internal cleanups
- **unrelated** — touches modules / surface areas the consumer does not use

When uncertain, treat as material. The cost of "I told you it was safe to update and it wasn't" is higher than the cost of "I told you to look closer and it was fine."

For each material entry, capture:

- the version it landed in
- a one-line summary
- whether it has a migration note (search the body for "migration", "update", "upgrade", "removed", "renamed", "breaking" — both verbs appear in real-world changelogs)
- the **search hints** for Step 4 (e.g. identifier names that were removed/renamed, packages whose imports changed, scaffold paths that moved). Read the changelog body carefully — these are the patterns the agent will grep for next.

## Step 4: Identify affected files

For each **material** change identified in Step 3, do a focused scan of the repo and list the files that will need attention. This is the part that catches "old code written against an old scaffold pattern" without needing a scaffold version stamp.

### Procedure per material change

1. Derive search terms from the changelog body and the search hints captured above. Examples:
   - Renamed API `transferOrder` → `moveStock`: grep for `transferOrder` across `apps/**/*.ts`, `modules/**/*.ts`
   - New pattern requirement `createContext()`: grep for `mutation` resolvers that pass `context` directly without wrapping
   - Removed import `from "@tailor-platform/erp-kit/legacy"`: grep for the legacy import path
   - `lib/` content rule changed: list non-types files under `modules/*/lib/`
2. Run `rg` / `grep` against `REPO_ROOT`, scoped to plausible paths (resolvers, modules, frontend, depending on the change).
3. For each hit, record `{ path, line?, snippet?, reason }`. Capture enough context that the user can act without re-running the search.
4. If a change's search hints don't point to anything concrete (e.g. internal refactor with no surface impact), record an empty `affectedFiles: []` so the output remains explicit.

### Heuristic guardrails

- Prefer narrower scopes (e.g. `apps/*/backend/src/resolver`) over `**/*`. Wider scans inflate noise.
- Skip `.test.ts` / `.stories.tsx` unless the change is testing-specific.
- If a search would touch more than ~30 files, summarise rather than list each one (`"matches in 42 files under modules/sales/, sample: …"`).
- The goal is **actionable hits**, not exhaustive enumeration.

### Limits

This step is best-effort:

- Changelog entries without enough detail can't be searched effectively → mark them `affectedFiles: "needs-manual-review"` and explain why.
- Subtle pattern changes (e.g. "AppShell adoption is now strongly recommended") are hard to grep — surface as a general advisory rather than file list.
- The agent should be honest in the output about which material changes have a confident file list vs. which are unresolved.

## Step 5: Recommend

Based on the gap, changelog, and affected files, emit one of three recommendations:

| Recommendation | When |
| -------------- | ---- |
| **update now** | gap is small (patch / minor), no material changes, OR a security fix is in scope |
| **update soon (review first)** | gap has material changes; user should fix the listed affected files before / after updating |
| **wait / no rush** | gap is only cosmetic / unrelated, no security issue, repo's current state is stable |

For each recommendation, include:

- the suggested target version (usually `LATEST_VERSION`, but may suggest an intermediate version if a single hop minimises risk)
- the concrete commands (e.g. `pnpm update @tailor-platform/erp-kit && pnpm erp-kit update`)
- per material change: the migration note **and** the affected file list from Step 4
- a closing **best-effort note** reminding the user that the affected-file list cannot catch dynamic imports, aliased references, type-only usages, or pattern shifts without unique identifiers. This note must always be included whenever an affected-file list is shown, never omitted.

## Output

Emit a markdown advisory:

```markdown
# erp-kit Update Advisory

Installed: v0.22.0 · Latest: v0.25.0 · Gap: +3 minor

## Recommendation: **update soon (review first)**

The 3-minor gap includes 2 material changes that touch 4 files in this repo.

## Material changes

### v0.24.0 — `createContext()` is now required in mutation resolvers

Migration: wrap each `context` argument with `createContext(context)`.

**Affected files (2):**

- `apps/my-shop/backend/src/resolver/createOrder.ts:12` — `body: async (context) => {` passes context directly
- `apps/my-shop/backend/src/resolver/updateOrder.ts:8` — same pattern

### v0.25.0 — `transferOrder` command renamed to `moveStock`

Migration: rename call sites.

**Affected files (2):**

- `apps/my-shop/backend/src/resolver/transferStock.ts:15` — calls `commands.transferOrder(...)`
- `modules/promotion/command/relocateStock.ts:22` — imports `transferOrder` from `@tailor-platform/erp-kit/module`

## Cosmetic / unrelated

5 changesets touch tooling / docs only — no consumer action required.

## How to update

\`\`\`bash
pnpm update @tailor-platform/erp-kit
pnpm erp-kit update
\`\`\`

After updating, run `erp-kit-score` to check the repo against the new version's philosophy.

> **Note:** The affected-files list is best-effort and may be incomplete. Dynamic imports, aliased references, type-only usages, and pattern-level shifts that lack a unique identifier cannot be detected by grep. Treat the list as a starting point — read each migration note and verify your codebase manually for changes outside this list.
```

If a JSON sidecar is requested (or the skill is invoked programmatically), also emit:

```json
{
  "installedVersion": "0.22.0",
  "latestVersion": "0.25.0",
  "lockfileDrift": false,
  "recommendation": "update-soon-review",
  "materialChanges": [
    {
      "version": "0.24.0",
      "summary": "createContext() is now required in mutation resolvers",
      "hasMigrationNote": true,
      "affectedFiles": [
        { "path": "apps/my-shop/backend/src/resolver/createOrder.ts", "line": 12, "snippet": "body: async (context) => {", "reason": "passes context directly" },
        { "path": "apps/my-shop/backend/src/resolver/updateOrder.ts", "line": 8, "snippet": "body: async (context) => {", "reason": "same pattern" }
      ]
    },
    {
      "version": "0.25.0",
      "summary": "transferOrder command renamed to moveStock",
      "hasMigrationNote": true,
      "affectedFiles": [
        { "path": "apps/my-shop/backend/src/resolver/transferStock.ts", "line": 15, "reason": "calls commands.transferOrder(...)" },
        { "path": "modules/promotion/command/relocateStock.ts", "line": 22, "reason": "imports transferOrder" }
      ]
    }
  ],
  "cosmeticChangeCount": 5
}
```
