Skip to content
Open
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
372 changes: 282 additions & 90 deletions bun.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions openspec/changes/add-abapify-pilot/.openspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-04-28
71 changes: 71 additions & 0 deletions openspec/changes/add-abapify-pilot/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
## Context

The repo already has a fully-featured `@abapify/adt-mcp` MCP server that exposes all ADT operations as MCP tools (`atc_run`, `cts_list_transports`, `list_package_objects`, etc.). Mastra AI provides a first-class `MCPClient` integration that lets an `Agent` call those tools natively. The goal is to compose these two pieces into a standalone `@abapify/adt-pilot` package without duplicating any ADT logic.

## Goals / Non-Goals

**Goals:**

- New Nx publishable library `packages/adt-pilot` (`@abapify/adt-pilot`)
- Mastra `Harness` with a single agent mode: **review**
- `codeReviewWorkflow`: a `createWorkflow` workflow with two input paths:
- **Package mode** (`mode: 'package'`, `packageName: string`) — calls `list_package_objects` then `atc_run` per object
- **Transport mode** (`mode: 'transport'`, `transportNumber: string`) — calls `cts_get_transport` to resolve objects then `atc_run` per object
- Structured output: `CodeReviewReport` (`{ mode, target, findings[], summary }`).
- 100% Vitest test coverage via `@abapify/adt-fixtures` mock server.

**Non-Goals:**

- UI / TUI frontend (Harness is wired but no terminal renderer shipped in this change)
- LLM-generated natural-language summaries (the agent returns structured JSON findings; an LLM layer can be added later)
- Modifying any existing package

## Decisions

### 1. Package as a separate Nx library, not a sample

**Decision**: `packages/adt-pilot` (publishable `@abapify/adt-pilot`).
**Rationale**: Makes the agent installable as a dependency, keeps it tested in CI like the rest of the monorepo, and follows the same package structure as `adt-mcp`.
**Alternative considered**: Add inside `samples/` — rejected because samples are not covered by the main CI test matrix and cannot be depended upon.

### 2. Mastra MCP wiring via `MCPClient` in-process

**Decision**: Use `@mastra/mcp`'s `MCPClient` with `InMemoryTransport` to connect to an in-process `@abapify/adt-mcp` server in tests; use `StdioServerParameters` to spawn the real binary in production.
**Rationale**: Avoids network overhead in tests; matches the pattern used by other Mastra-based agents. In production the pilot receives `baseUrl/username/password` as workflow input and passes them as tool arguments — no session state needed.
**Alternative considered**: Call ADT client directly without MCP — rejected because it would duplicate the tool layer and break the `adt-mcp ↔ adt-cli` parity invariant.

### 3. Workflow over pure Agent for code review

**Decision**: `codeReviewWorkflow` is a `createWorkflow` chain of typed steps rather than a freeform agent loop.
**Rationale**: Deterministic output schema, easier to test step-by-step, no LLM required for the core logic. The `Harness` wraps the workflow so an LLM can be plugged in later.
**Steps**:

1. `resolveObjects` — call `list_package_objects` or `cts_get_transport` to get the list of objects
2. `runAtcChecks` — call `atc_run` for each object (sequential or parallel configurable)
3. `buildReport` — aggregate findings into `CodeReviewReport`

### 4. `@mastra/mcp` for tool binding

**Decision**: Add `@mastra/mcp` as a direct dependency (not `@mastra/core` alone) because `MCPClient` lives there.
**Rationale**: Keeps the dependency surface minimal; `@mastra/core` is a peer dep of `@mastra/mcp`.

### 5. No LLM key required for tests

**Decision**: Workflow steps execute deterministically (no LLM calls); tests use the fixture mock server. The Harness agent mode is configured with a placeholder model string and is not exercised in unit/integration tests.
**Rationale**: Keeps CI independent of external API keys.

## Risks / Trade-offs

- **`@mastra/core` API churn** — Mastra is on v1 with frequent releases. The workflow/step API used here (`createWorkflow`, `createStep`) is the stable "v-next" surface. Pin to a minor version range.
→ Mitigation: snapshot the version in `package.json` as `"^1.28.0"`.

- **Large transitive dependency graph** — `@mastra/core` pulls in `hono`, `ai`, `ajv`, etc.
→ Mitigation: `adt-pilot` is a standalone package; it does not affect the bundle of `adt-cli` or `adt-mcp`.

## Migration Plan

No migration required — new package only. Deploy by publishing `@abapify/adt-pilot` independently.

## Open Questions

- Should `codeReviewWorkflow` run ATC checks in parallel per object? Default: sequential (safe); a `parallel` flag can be added later.
31 changes: 31 additions & 0 deletions openspec/changes/add-abapify-pilot/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## Why

AI-driven code review is a high-value workflow for SAP ABAP developers. By combining Mastra AI's agent framework with the existing `@abapify/adt-mcp` MCP server, we can ship a first-class agent — **abapify Pilot** — that runs ATC-based code review on an entire package hierarchy or a transport request without requiring any additional ADT integration code.

## What Changes

- New package `packages/adt-pilot` containing a Mastra `Harness`-based agent called **abapify Pilot**.
- The agent supports a **Code Review** workflow with two input modes:
- **Package mode** — given an ABAP package name, recursively reviews all objects including sub-packages.
- **Transport mode** — given a transport request number, reviews all objects included in that transport.
- The agent uses `@abapify/adt-mcp` tools (via Mastra `MCPClient`) as its only ADT integration layer.
- Full Vitest test suite with 100% coverage using `@abapify/adt-fixtures` payloads (mock ADT server pattern).

## Capabilities

### New Capabilities

- `abapify-pilot-agent`: Mastra `Harness` + `Agent` setup for abapify Pilot, with connection config and MCP tool wiring.
- `code-review-workflow`: `createWorkflow` that accepts either `{ mode: 'package', packageName }` or `{ mode: 'transport', transportNumber }` as input and produces a structured code review report.

### Modified Capabilities

<!-- none -->

## Impact

- **New package**: `packages/adt-pilot` (publishable, `@abapify/adt-pilot`)
- **Dependencies added**: `@mastra/core` (peer dep on `ai` SDK), `@abapify/adt-mcp`, `zod`
- **Dev dependencies**: `@abapify/adt-fixtures` (test fixtures), `vitest`
- **No breaking changes** to existing packages
- **Nx graph**: `adt-pilot` depends on `adt-mcp` and `adt-fixtures` (test only)
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
## ADDED Requirements

### Requirement: Package exports Harness and agent

The `@abapify/adt-pilot` package SHALL export a `createAbapifyPilot(config)` factory that returns a configured Mastra `Harness` instance with the **review** mode wired to the `codeReviewWorkflow`.

Comment on lines +5 to +6
#### Scenario: Factory returns Harness

- **WHEN** `createAbapifyPilot({ mcpServerParams, model })` is called
- **THEN** it returns a `Harness` instance with at least one mode whose `id` is `"review"`

#### Scenario: Harness mode agent is configured

- **WHEN** the returned Harness is initialised
- **THEN** the `review` mode agent has the MCP tools from `@abapify/adt-mcp` available

### Requirement: Package exports workflow

The `@abapify/adt-pilot` package SHALL export `codeReviewWorkflow` so it can be used outside the Harness context.

#### Scenario: Direct workflow import

- **WHEN** `import { codeReviewWorkflow } from '@abapify/adt-pilot'` is used
- **THEN** `codeReviewWorkflow` is a Mastra `Workflow` instance with `inputSchema` and `outputSchema`

### Requirement: Connection config passed as workflow input

The workflow and agent SHALL NOT store SAP connection credentials in package-level state. Credentials (`baseUrl`, `username`, `password`, `client?`) SHALL be passed as part of every workflow run's input.

#### Scenario: Credentials forwarded to MCP tools

- **WHEN** the workflow is executed with `{ baseUrl, username, password, mode, ... }`
- **THEN** all MCP tool calls include those credentials as arguments

### Requirement: Package is a publishable Nx library

The package SHALL be located at `packages/adt-pilot`, use the name `@abapify/adt-pilot`, and follow the same tsdown build + Vitest test setup used by other packages in the monorepo.

#### Scenario: Build succeeds

- **WHEN** `bunx nx build adt-pilot` is run
- **THEN** the build exits 0 and `packages/adt-pilot/dist/` is populated with `.mjs` and `.d.mts` files

Comment on lines +39 to +43
#### Scenario: Tests pass

- **WHEN** `bunx nx test adt-pilot` is run
- **THEN** all tests pass and coverage reaches 100% of statements/branches
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
## ADDED Requirements

### Requirement: Workflow accepts package mode input

The `codeReviewWorkflow` SHALL accept `{ mode: 'package', packageName: string, baseUrl: string, username: string, password: string, client?: string }` as input and produce a `CodeReviewReport`.

#### Scenario: Package mode resolves objects

- **WHEN** the workflow is executed with `mode: 'package'` and a valid `packageName`
- **THEN** the `resolveObjects` step calls the `list_package_objects` MCP tool with that package name
- **THEN** the step result contains an array of ABAP object URIs from that package and its sub-packages

#### Scenario: Package mode runs ATC on resolved objects

- **WHEN** `resolveObjects` returns a non-empty object list
- **THEN** the `runAtcChecks` step calls `atc_run` for each object URI
- **THEN** the `buildReport` step aggregates all findings into a `CodeReviewReport`

#### Scenario: Empty package produces empty report

- **WHEN** `list_package_objects` returns zero objects
- **THEN** the workflow completes successfully with `findings: []` and `summary.totalFindings: 0`

### Requirement: Workflow accepts transport mode input

The `codeReviewWorkflow` SHALL accept `{ mode: 'transport', transportNumber: string, baseUrl: string, username: string, password: string, client?: string }` as input and produce a `CodeReviewReport`.

#### Scenario: Transport mode resolves objects

- **WHEN** the workflow is executed with `mode: 'transport'` and a valid `transportNumber`
- **THEN** the `resolveObjects` step calls the `cts_get_transport` MCP tool with that transport number
- **THEN** the step result contains the list of ABAP object URIs from that transport

Comment on lines +30 to +33
#### Scenario: Transport mode runs ATC on resolved objects

- **WHEN** `resolveObjects` returns a non-empty object list
- **THEN** the `runAtcChecks` step calls `atc_run` for each resolved object URI
- **THEN** the `buildReport` step aggregates all findings into a `CodeReviewReport`

### Requirement: CodeReviewReport output schema

The workflow output SHALL conform to `CodeReviewReport`:

```typescript
{
mode: 'package' | 'transport';
target: string; // packageName or transportNumber
objects: string[]; // resolved object URIs
findings: AtcFinding[]; // all ATC findings across objects
summary: {
totalObjects: number;
totalFindings: number;
bySeverity: Record<string, number>;
};
}
```

#### Scenario: Report structure is correct

- **WHEN** the workflow completes
- **THEN** the output matches the `CodeReviewReport` schema
- **THEN** `summary.totalObjects` equals the number of objects resolved
- **THEN** `summary.totalFindings` equals the total number of findings across all objects

### Requirement: Workflow is three steps

The `codeReviewWorkflow` SHALL consist of exactly three named steps executed in sequence:

1. `resolveObjects`
2. `runAtcChecks`
3. `buildReport`

#### Scenario: Step chain is deterministic

- **WHEN** the workflow is committed (`.commit()`)
- **THEN** the execution order is always resolveObjects → runAtcChecks → buildReport

### Requirement: Workflow handles MCP tool errors gracefully

If an MCP tool call fails for an individual object, the workflow SHALL continue processing remaining objects and include an error entry in `findings` for the failed object.

#### Scenario: Partial ATC failure

- **WHEN** `atc_run` fails for one object but succeeds for others
- **THEN** the failed object produces a finding with `priority: 'error'` and a `description` containing the error message
- **THEN** the workflow does not throw; it returns a completed `CodeReviewReport`
59 changes: 59 additions & 0 deletions openspec/changes/add-abapify-pilot/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
## 1. Scaffold `packages/adt-pilot`

- [ ] 1.1 Create `packages/adt-pilot/` directory with `package.json` (`@abapify/adt-pilot`, version `0.3.6`, ESM, `exports: { ".": "./dist/index.mjs" }`)
- [ ] 1.2 Add `tsconfig.json` and `tsdown.config.ts` mirroring `packages/adt-mcp`
- [ ] 1.3 Add `project.json` for Nx with `build`, `test`, `lint`, `typecheck` targets
- [ ] 1.4 Add `vitest.config.ts` using the workspace preset
- [ ] 1.5 Create `src/index.ts` (empty barrel — fills in later tasks)

## 2. Add dependencies

- [ ] 2.1 Add `@mastra/core`, `@mastra/mcp` as runtime dependencies in `packages/adt-pilot/package.json`
- [ ] 2.2 Add `@abapify/adt-mcp` as a runtime dependency
- [ ] 2.3 Add `zod` as a runtime dependency
- [ ] 2.4 Add `@abapify/adt-fixtures` as a dev dependency
- [ ] 2.5 Run `bun install` to update the lockfile

## 3. Implement types (`src/types.ts`)

- [ ] 3.1 Define `ConnectionParams` (`baseUrl`, `username`, `password`, `client?`)
- [ ] 3.2 Define `AtcFinding` (`objectUri`, `priority`, `description`, `category?`, `checkName?`, `location?`)
- [ ] 3.3 Define `CodeReviewReport` (`mode`, `target`, `objects`, `findings`, `summary`)
- [ ] 3.4 Export all types from `src/index.ts`

## 4. Implement `codeReviewWorkflow` (`src/workflow.ts`)

- [ ] 4.1 Create `resolveObjects` step: accepts `{ mode, packageName?, transportNumber?, ...conn }`, calls `list_package_objects` or `cts_get_transport` via MCP client, returns `{ objects: string[] }`
- [ ] 4.2 Create `runAtcChecks` step: accepts `{ objects, ...conn }`, calls `atc_run` per object, returns `{ rawResults: AtcRunResult[] }`
- [ ] 4.3 Create `buildReport` step: accepts `{ mode, target, objects, rawResults }`, maps to `CodeReviewReport`
- [ ] 4.4 Wire steps with `createWorkflow(...).then(resolveObjects).then(runAtcChecks).then(buildReport).commit()`
- [ ] 4.5 Export `codeReviewWorkflow` from `src/index.ts`
- [ ] 4.6 Define and export Zod schemas for input and output

## 5. Implement MCP client factory (`src/mcp-client.ts`)

- [ ] 5.1 Create `createMcpToolSet(serverParams)` function using `@mastra/mcp`'s `MCPClient` that returns the tool set from the `@abapify/adt-mcp` server
- [ ] 5.2 Export `createMcpToolSet` from `src/index.ts`

## 6. Implement Harness agent (`src/agent.ts` + `src/harness.ts`)

- [ ] 6.1 Create `reviewAgent`: Mastra `Agent` with `id: 'review'`, instructions describing code review purpose, and MCP tools
- [ ] 6.2 Create `createAbapifyPilot(config)` factory returning a `Harness` with mode `{ id: 'review', default: true, agent: reviewAgent }`
- [ ] 6.3 Export `createAbapifyPilot` from `src/index.ts`

## 7. Write tests (`tests/`)

- [ ] 7.1 Create `tests/workflow.test.ts`: package mode happy path using `@abapify/adt-fixtures` mock server
- [ ] 7.2 Create `tests/workflow.test.ts` (continued): transport mode happy path
- [ ] 7.3 Create `tests/workflow.test.ts` (continued): empty package → empty report
- [ ] 7.4 Create `tests/workflow.test.ts` (continued): partial ATC failure → report with error finding
- [ ] 7.5 Create `tests/types.test.ts`: Zod schema validation for `CodeReviewReport`
- [ ] 7.6 Create `tests/mcp-client.test.ts`: mock MCPClient connect/disconnect lifecycle

## 8. Verify & finalize

- [ ] 8.1 Run `bunx nx build adt-pilot` — confirm build succeeds
- [ ] 8.2 Run `bunx nx test adt-pilot` — confirm all tests pass
- [ ] 8.3 Run `bunx nx lint adt-pilot` — confirm no lint errors
- [ ] 8.4 Run `bunx nx typecheck adt-pilot` — confirm no type errors
- [ ] 8.5 Run `bunx nx format:write` — format all changed files
47 changes: 47 additions & 0 deletions packages/adt-pilot/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "@abapify/adt-pilot",
"version": "0.3.6",
"description": "abapify Pilot — Mastra AI agent for ABAP code review via ADT MCP",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"type": "module",
"exports": {
".": "./dist/index.mjs",
"./package.json": "./package.json"
},
"files": [
"dist",
"README.md"
],
Comment on lines +9 to +17
"keywords": [
"sap",
"adt",
"abap",
"mastra",
"ai",
"agent",
"code-review",
"atc"
],
"dependencies": {
"@mastra/core": "^1.28.0",
"@modelcontextprotocol/sdk": "^1.27.0",
"zod": "^3.24.0"
},
"devDependencies": {
"@abapify/adt-client": "0.3.6",
"@abapify/adt-fixtures": "0.3.6",
"@abapify/adt-mcp": "0.3.6"
},
Comment on lines +28 to +37
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Local deps not workspace:* 📘 Rule violation ✧ Quality

packages/adt-pilot/package.json declares local workspace packages with a plain version (0.3.6)
instead of a workspace:* protocol. This violates the monorepo dependency versioning requirement
and can break workspace resolution consistency.
Agent Prompt
## Issue description
Local monorepo dependencies are declared with plain versions instead of the required `workspace:` protocol.

## Issue Context
`@abapify/adt-fixtures` and `@abapify/adt-mcp` are local packages in this repo; the compliance rule requires `workspace:*` (or `workspace:^`/`workspace:~`) for such dependencies.

## Fix Focus Areas
- packages/adt-pilot/package.json[34-37]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
"repository": {
"type": "git",
"url": "git+https://github.com/abapify/adt-cli.git",
"directory": "packages/adt-pilot"
},
"homepage": "https://github.com/abapify/adt-cli/tree/main/packages/adt-pilot#readme",
"bugs": {
"url": "https://github.com/abapify/adt-cli/issues"
}
}
30 changes: 30 additions & 0 deletions packages/adt-pilot/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "adt-pilot",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/adt-pilot/src",
"projectType": "library",
"release": {
"version": {
"manifestRootsToUpdate": ["{projectRoot}"]
}
},
"tags": ["scope:adt", "type:agent"],
"targets": {
"typecheck": {
"executor": "nx:run-commands",
"dependsOn": [],
"inputs": [
"{projectRoot}/src/**/*",
"{projectRoot}/tsconfig.json",
"{projectRoot}/tsconfig.lib.json",
"{workspaceRoot}/tsconfig.base.json"
],
"outputs": ["{workspaceRoot}/dist/out-tsc/packages/adt-pilot/**"],
"cache": true,
"options": {
"cwd": "packages/adt-pilot",
"command": "tsc -p tsconfig.lib.json --noEmit"
}
}
}
}
Loading
Loading