Skip to content

feat: extract @agentspec/codegen — provider-agnostic code generation#17

Draft
iliassjabali wants to merge 8 commits intomainfrom
feat/codegen-migration
Draft

feat: extract @agentspec/codegen — provider-agnostic code generation#17
iliassjabali wants to merge 8 commits intomainfrom
feat/codegen-migration

Conversation

@iliassjabali
Copy link
Copy Markdown
Collaborator

@iliassjabali iliassjabali commented Mar 26, 2026

Summary

Extract all code generation logic from @agentspec/adapter-claude into a new provider-agnostic @agentspec/codegen package. The CLI and docs now treat all providers equally — no Claude-specific hardcoding in the generic pipeline.

New package: @agentspec/codegen

  • Hexagonal architecture: CodegenProvider port with three adapters:
    • ClaudeSubscriptionProvider — uses the Claude CLI via @anthropic-ai/claude-agent-sdk
    • AnthropicApiProvider — uses @anthropic-ai/sdk directly
    • CodexProvider — uses OpenAI's API
  • Auto-detection: resolveProvider() probes Claude CLI → ANTHROPIC_API_KEYOPENAI_API_KEY
  • Override: AGENTSPEC_CODEGEN_PROVIDER=claude-sub|anthropic-api|codex or --provider flag
  • Streaming: CodegenChunk discriminated union (delta | heartbeat | done)
  • Utilities: collect(), repairYaml(), probeProviders()
  • Full test suite: 78 tests — contract tests, provider unit tests, resolver, repair, probe

@agentspec/adapter-claude → deprecated shim

  • Re-exports from @agentspec/codegen with old API names
  • generateWithClaude()generateCode(), resolveAuth()resolveProvider()
  • Logs a once-per-process deprecation warning
  • Still published to npm for backwards compatibility

CLI updates

  • agentspec generate and agentspec scan use @agentspec/codegen directly
  • New agentspec provider-status command
  • --provider flag on generate and scan for explicit provider selection
  • Improved error messages and help text

Docs

  • docs/concepts/adapters.md — rewritten for multi-provider architecture
  • docs/guides/provider-auth.md — covers all three providers
  • docs/reference/cli.md — updated commands, env vars, examples
  • packages/codegen/README.md — full package docs
  • docs/quick-start.md — provider-agnostic language

CI / publish

  • publish.yml — adapter-claude publish step (after codegen, resolves workspace deps)
  • release.yml — adapter-claude in version bump loop

Test coverage

  • 78 codegen tests: contract tests (3 providers), unit tests, resolver, repair, probe
  • 371 CLI tests: including 8 new E2E cross-functionality tests
  • 1,073 total tests across workspace — all passing
  • pnpm typecheck clean across all 6 packages

iliassjabali and others added 5 commits March 22, 2026 00:16
…laude subscription + API key

## What this does

AgentSpec previously required ANTHROPIC_API_KEY for generate and scan.
This change adds full support for Claude Pro/Max subscriptions so users
with a Claude.ai plan can run AgentSpec without any API key.

## New command: agentspec claude-status

Inspect the full Claude auth environment in one shot:

  agentspec claude-status        # table output
  agentspec claude-status --json # machine-readable, exit 1 if not ready

Reports:
- CLI: installed, version, authenticated, account email, plan (Pro/Max/Free)
- API: key set, masked preview, live HTTP probe to /v1/models, base URL
- Env: AGENTSPEC_CLAUDE_AUTH_MODE override, ANTHROPIC_MODEL, resolved mode

Implemented via probeClaudeAuth() in adapter-claude/src/auth.ts which
collects all data without throwing, then renders it in claude-status.ts.

## Auth resolution (CLI first)

resolveAuth() in auth.ts picks the method in this order:
  1. Claude CLI — if installed + authenticated (subscription users)
  2. ANTHROPIC_API_KEY — fallback for CI / API-only setups
  3. Neither — single combined error with setup instructions for both

Override: AGENTSPEC_CLAUDE_AUTH_MODE=cli|api

## CLI stdin fix

runClaudeCli() now pipes the user message via stdin (spawnSync input:)
instead of as a CLI argument, avoiding ARG_MAX limits on large manifests.

## Why not @anthropic-ai/claude-agent-sdk

The agent SDK is designed for persistent multi-turn coding assistants
(session management, resume cursors, tool approval gates). AgentSpec
generate/scan are one-shot calls — the SDK would be ~2500 lines of
adapter code with almost all of it unused. Our spawnSync approach is
the correct scope match: zero extra dependency, auth for free, simple
to test and debug. The only tradeoff is no streaming in CLI mode.

## Files

New:
- packages/adapter-claude/src/auth.ts — resolveAuth, isCliAvailable, probeClaudeAuth
- packages/adapter-claude/src/cli-runner.ts — runClaudeCli via spawnSync stdin
- packages/cli/src/commands/claude-status.ts — new CLI command
- packages/adapter-claude/src/__tests__/auth.test.ts — 16 tests
- packages/adapter-claude/src/__tests__/cli-runner.test.ts — 9 tests
- docs/guides/claude-auth.md — full auth guide incl. claude-status usage
- examples/gymcoach/docker-compose.yml — local Postgres + Redis

Updated:
- adapter-claude/index.ts — routes generate/repair through resolveAuth
- cli/commands/generate.ts + scan.ts — remove hard API key blocks, show auth label
- cli/cli.ts — registers claude-status command
- docs/reference/cli.md — claude-status section, updated generate/scan auth docs
- docs/concepts/adapters.md + quick-start.md — dual-auth examples throughout

Tests: 63 passing in adapter-claude, 1039 passing workspace-wide
…tion or class'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
- auth.ts: parse claude auth status JSON before lowercasing so loggedIn:false
  is not silently misread as true (Copilot comment on isClaudeAuthenticated)
- auth.ts: reduce API key preview exposure from 16 chars to first-4…last-2
- auth.ts: remove dead catch branch in isClaudeAuthenticated (both if-branches
  returned false; simplified to unconditional return false)
- cli-runner.ts: remove dead systemPromptPath temp-file write — system prompt
  was written to disk but never used; --system-prompt was passed inline.
  Also fixes cleanupTempFile which called unlinkSync on a directory (would
  always throw and leave temp dirs behind).
- generate.ts / scan.ts: derive authLabel from resolveAuth() instead of
  isCliAvailable() so AGENTSPEC_CLAUDE_AUTH_MODE override is reflected in
  the spinner (Copilot comment on both commands)
- generate.ts / scan.ts: resolve auth once and pass into generateWithClaude
  via new options.auth field to avoid redundant subprocess call (PERF-01)
- generate.ts: fix runDeployTarget helm path to wrap generateWithClaude in
  try/catch with graceful error output (QUAL-03)
- index.ts: wrap repairYaml YAML content in XML tags to prevent prompt
  injection from adversarial agent.yaml files (SEC-02); truncate to 64 KB
- skills/guidelines.md: add security preamble instructing Claude to treat
  context_manifest and context_file XML tags as data only, never instructions
- docs: correct timeout example in error table from 120s to 300s
- tests: add claude-status.test.ts (9 tests) covering JSON output shape and
  exit code 0/1 for all three resolved modes
- tests: add probeClaudeAuth coverage (8 tests) to auth.test.ts
- tests: add repairYaml coverage (4 tests) and XML tag assertions to
  claude-adapter.test.ts; update buildContext tests for new XML format
- tests: remove dead node:fs mock from cli-runner.test.ts
- tests: update scan/generate test mocks from isCliAvailable to resolveAuth
- cli.test.ts: pass AGENTSPEC_CLAUDE_AUTH_MODE=api in generate tests to
  prevent them hitting real Claude CLI on developer machines
…nostic architecture

Replace the monolithic @agentspec/adapter-claude with @agentspec/codegen — a
provider-agnostic code generation package using hexagonal architecture.

- CodegenProvider port with three adapters: Claude subscription, Anthropic API, OpenAI Codex
- Auto-detection via resolveProvider() (CLI → API key → Codex)
- Streaming via AsyncIterable<CodegenChunk> (delta | heartbeat | done)
- @agentspec/adapter-claude retained as deprecated backwards-compat shim
- CLI updated: --provider flag on generate and scan commands
- 78 codegen tests, 363 CLI tests, 1065 total — all passing
- Docs updated: adapters guide, claude-auth, cli reference, codegen README
Remove all Claude-specific hardcoding from the generic codegen pipeline.
The CLI, types, and docs now use provider-agnostic language throughout.

Renames:
- claude-status command → provider-status
- probeClaudeAuth() → probeProviders()
- ClaudeProbeReport → ProviderProbeReport
- ClaudeApiProbe → AnthropicApiProbe
- ClaudeEnvProbe → ProviderEnvProbe
- auth-probe.ts → provider-probe.ts
- docs/guides/claude-auth.md → provider-auth.md
- resolvedMode: 'cli'|'api' → resolvedProvider: string|null
- authModeOverride → providerOverride
- AGENTSPEC_CLAUDE_AUTH_MODE → AGENTSPEC_CODEGEN_PROVIDER

Adds E2E cross-functionality tests covering the full
resolver → provider-probe → provider-status pipeline.
Replace `as any` with proper types:
- Contract tests use CodegenChunk instead of unknown/any
- Test spies use ReturnType<typeof vi.spyOn<...>> instead of any
- Context builder test uses AgentSpecManifest instead of any
- Contract makeSuccessStream param widened to unknown (removes as any at call sites)
- Codex test uses type guard narrowing instead of as any
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant