ワンクリックで
infra-import-refactor
Refactor direct infrastructure imports into port interfaces with dependency injection
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Refactor direct infrastructure imports into port interfaces with dependency injection
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Show CI/CD pipeline status for current branch with job details and failure diagnostics
Cross-validate documentation and artifacts across the codebase for consistency, conflicts, and contradictions. Use when users ask to "cross-validate", "validate docs", "check documentation consistency", "audit documentation", or find conflicts/contradictions in docs. Supports automatic fixing with "validate and fix" argument. Runs parallel subagents for efficient validation across categories (domain-models, agent-system, tech-stack, architecture, cli-commands). Part of the ShipIT autonomous SDLC platform — https://github.com/jrmatherly/shipit
React Flow (@xyflow/react) for workflow visualization with custom nodes and edges. Use when building graph visualizations, creating custom workflow nodes, implementing edge labels, or controlling viewport. Triggers on ReactFlow, @xyflow/react, Handle, NodeProps, EdgeProps, useReactFlow, fitView.
Diagnose semantic-release and npm publish failures from the latest CI release job
Provides complete shadcn/ui component library patterns including installation, configuration, and implementation of accessible React components. Use when setting up shadcn/ui, installing components, building forms with React Hook Form and Zod, customizing themes with Tailwind CSS, or implementing UI patterns like buttons, dialogs, dropdowns, tables, and complex form layouts.
Use when ready to commit, push, and create a PR with CI verification. Triggers include "commit and pr", "push pr", "create pr", "ship it", or when implementation is complete and needs CI validation. Watches CI and auto-fixes failures. Part of the ShipIT autonomous SDLC platform — https://github.com/jrmatherly/shipit
| name | infra-import-refactor |
| description | Refactor direct infrastructure imports into port interfaces with dependency injection |
| user_invocable | true |
Guide the refactoring of direct infrastructure imports in application/presentation layers into proper port interfaces with tsyringe dependency injection.
check-layer-violations.sh hook flags an infrastructure importfrom.*infrastructure/ imports in application or presentation codeScan for direct infrastructure imports in forbidden layers:
# Application layer violations
grep -rn "from.*infrastructure/" packages/core/src/application/ | grep -v "import type" | grep -v "di/container"
# Presentation layer violations
grep -rn "from.*infrastructure/" src/presentation/ | grep -v "import type" | grep -v "di/container" | grep -v "server-container"
For each import, determine the category:
| Category | Description | Action |
|---|---|---|
| A: Needs new port | No existing interface covers this service | Create interface + adapter |
| B: Has port, not wired | Interface exists but consumer uses direct import | Switch to DI injection |
| C: Type-only | Only types are imported, no runtime dependency | Convert to import type |
Simplest fix. Change:
// BEFORE (violation)
import { SomeType } from '@/infrastructure/services/some-service';
// AFTER (clean)
import type { SomeType } from '@/infrastructure/services/some-service';
Type-only imports are allowed since they're erased at runtime and don't create a dependency.
If a port interface already exists in packages/core/src/application/ports/output/:
// BEFORE (violation)
import { GitService } from '@/infrastructure/services/git-service';
export class SomeUseCase {
private gitService = new GitService();
}
// AFTER (clean)
import type { IGitPrService } from '../ports/output/services/git-pr-service.interface';
@injectable()
export class SomeUseCase {
constructor(
@inject('IGitPrService') private readonly gitPrService: IGitPrService,
) {}
}
Create in packages/core/src/application/ports/output/services/ or repositories/:
// packages/core/src/application/ports/output/services/my-service.interface.ts
export interface IMyService {
doSomething(input: SomeInput): Promise<SomeOutput>;
}
Naming conventions:
kebab-case.interface.tsI prefix + PascalCase (e.g., IMyService)services/ for stateless operations, repositories/ for data persistence// packages/core/src/infrastructure/services/my-service.ts
import { injectable } from 'tsyringe';
import type { IMyService } from '@/application/ports/output/services/my-service.interface';
@injectable()
export class MyService implements IMyService {
async doSomething(input: SomeInput): Promise<SomeOutput> {
// existing implementation
}
}
Add to packages/core/src/infrastructure/di/container.ts:
container.register<IMyService>('IMyService', { useClass: MyService });
@injectable()
export class SomeUseCase {
constructor(
@inject('IMyService') private readonly myService: IMyService,
) {}
}
For each refactored consumer, update its test to inject a mock:
const mockMyService: IMyService = {
doSomething: vi.fn().mockResolvedValue(expectedOutput),
};
const useCase = new SomeUseCase(mockMyService);
Consider using /mock-factory if the interface is used in 3+ test files.
pnpm typecheck # Types resolve
pnpm test:unit # Tests pass with mocks
pnpm validate # Full validation
# Verify no violations remain
grep -rn "from.*infrastructure/" packages/core/src/application/ | grep -v "import type" | grep -v "di/container"
grep -rn "from.*infrastructure/" src/presentation/ | grep -v "import type" | grep -v "di/container" | grep -v "server-container"
Before — presentation layer directly imports infrastructure:
// src/presentation/cli/commands/init.ts
import { FileSystemService } from '@/infrastructure/services/file-system-service';
const fs = new FileSystemService();
const exists = await fs.directoryExists(path);
After — proper port interface with DI:
// 1. New interface
// packages/core/src/application/ports/output/services/file-system-service.interface.ts
export interface IFileSystemService {
directoryExists(path: string): Promise<boolean>;
readFile(path: string): Promise<string>;
writeFile(path: string, content: string): Promise<void>;
}
// 2. Infrastructure implements it
// packages/core/src/infrastructure/services/file-system-service.ts
@injectable()
export class FileSystemService implements IFileSystemService { ... }
// 3. DI registration
container.register<IFileSystemService>('IFileSystemService', { useClass: FileSystemService });
// 4. Use case wraps the operation
// packages/core/src/application/use-cases/check-directory.ts
@injectable()
export class CheckDirectoryUseCase {
constructor(
@inject('IFileSystemService') private readonly fs: IFileSystemService,
) {}
async execute(path: string): Promise<boolean> {
return this.fs.directoryExists(path);
}
}
// 5. Presentation uses the use case
// src/presentation/cli/commands/init.ts
const exists = await checkDirectoryUseCase.execute(path);