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
5 changes: 3 additions & 2 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,12 @@ testsprite agent install claude # install the skill for Claude Code
testsprite agent install codex # install into AGENTS.md for Codex (managed-section)
testsprite agent install cursor # .cursor/rules/testsprite-verify.mdc
testsprite agent install cline # .clinerules/testsprite-verify.md
testsprite agent install kiro # .kiro/skills/testsprite-verify/SKILL.md
testsprite agent install antigravity # .agents/skills/testsprite-verify/SKILL.md
testsprite agent list # list all 5 targets with status + mode + path
testsprite agent list # list all 6 targets with status + mode + path
```

Supported targets: `claude` (GA), `codex` (experimental), `cursor` (experimental), `cline` (experimental), `antigravity` (experimental).
Supported targets: `claude` (GA), `codex` (experimental), `cursor` (experimental), `cline` (experimental), `kiro` (experimental), `antigravity` (experimental).

The `codex` target uses **managed-section mode** — it writes only a sentinel-delimited section inside your existing `AGENTS.md`, so your project instructions are never clobbered. Re-running without `--force` replaces the section in-place; user content outside the sentinels is always preserved.

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ npm install -g @testsprite/testsprite-cli
testsprite setup
```

`testsprite setup` prompts for your [API key](https://www.testsprite.com), verifies it, and installs the verification-loop skill for your coding agent (`claude`, `cursor`, `cline`, `antigravity`, `codex`, etc.) — one command, so your agent is wired to verify its own work. Non-interactive (CI / onboarding scripts):
`testsprite setup` prompts for your [API key](https://www.testsprite.com), verifies it, and installs the verification-loop skill for your coding agent (`claude`, `cursor`, `cline`, `kiro`, `antigravity`, `codex`, etc.) — one command, so your agent is wired to verify its own work. Non-interactive (CI / onboarding scripts):

```bash
TESTSPRITE_API_KEY=sk-... testsprite setup --from-env --yes --agent claude
Expand Down Expand Up @@ -110,7 +110,7 @@ Prefer to configure each step by hand (or learn the surface offline with `--dry-
| | `test rerun` | Cheap replay of one/many tests (FE verbatim; BE with deps); `--all --project <id>` reruns all tests |
| | `test wait` | Block on a `runId` until terminal |
| | `test artifact get` | Download the failure bundle for a specific `runId` |
| **Agent** | `agent install` / `agent list` | Add or list coding-agent targets (pure-local): `claude`, `codex`, `cursor`, `cline`, `antigravity` |
| **Agent** | `agent install` / `agent list` | Add or list coding-agent targets (pure-local): `claude`, `codex`, `cursor`, `cline`, `kiro`, `antigravity` |

> The earlier command names — `init`, `auth configure`, `auth whoami`, `auth logout` — still work as hidden, deprecated aliases (each prints a one-line notice pointing at the new name), so existing scripts keep running. `auth configure` now runs the full `setup` (it also installs the skill).

Expand Down
41 changes: 37 additions & 4 deletions src/lib/agent-targets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,20 +60,21 @@ testsprite test artifact get <run-id> --out ./out/
// ---------------------------------------------------------------------------

describe('TARGETS', () => {
it('has all five required keys', () => {
it('has all six required keys', () => {
const keys = Object.keys(TARGETS).sort();
expect(keys).toEqual(['antigravity', 'claude', 'cline', 'codex', 'cursor']);
expect(keys).toEqual(['antigravity', 'claude', 'cline', 'codex', 'cursor', 'kiro']);
});

it('claude is GA', () => {
expect(TARGETS.claude.status).toBe('ga');
});

it('cursor, cline, antigravity, and codex are experimental', () => {
it('cursor, cline, antigravity, codex, and kiro are experimental', () => {
expect(TARGETS.cursor.status).toBe('experimental');
expect(TARGETS.cline.status).toBe('experimental');
expect(TARGETS.antigravity.status).toBe('experimental');
expect(TARGETS.codex.status).toBe('experimental');
expect(TARGETS.kiro.status).toBe('experimental');
});

it('each target has a non-empty POSIX path', () => {
Expand All @@ -88,6 +89,7 @@ describe('TARGETS', () => {
expect(TARGETS.antigravity.mode).toBe('own-file');
expect(TARGETS.cursor.mode).toBe('own-file');
expect(TARGETS.cline.mode).toBe('own-file');
expect(TARGETS.kiro.mode).toBe('own-file');
});

it('codex target has mode managed-section', () => {
Expand Down Expand Up @@ -255,16 +257,47 @@ describe('renderForTarget("cline")', () => {
});
});

describe('renderForTarget("kiro")', () => {
const result = renderForTarget('kiro', STUB_BODY);

it('returns the correct path', () => {
expect(result.path).toBe('.kiro/skills/testsprite-verify/SKILL.md');
});

it('frontmatter contains name: testsprite-verify', () => {
expect(result.content).toContain('name: testsprite-verify');
});

it('frontmatter contains description:', () => {
expect(result.content).toContain(`description: ${SKILL_DESCRIPTION}`);
});

it('content ends with a trailing newline', () => {
expect(result.content.endsWith('\n')).toBe(true);
});

it('produces the same content as claude (same wrapSkill)', () => {
const claude = renderForTarget('claude', STUB_BODY);
expect(result.content).toBe(claude.content);
});

it('differs only in landing path from claude', () => {
const claude = renderForTarget('claude', STUB_BODY);
expect(result.path).not.toBe(claude.path);
});
});

// ---------------------------------------------------------------------------
// Content integrity — load-bearing command strings must survive any body trim
// ---------------------------------------------------------------------------

describe('content integrity — own-file targets', () => {
const ownFileTargets: Array<'claude' | 'cursor' | 'cline' | 'antigravity'> = [
const ownFileTargets: Array<'claude' | 'cursor' | 'cline' | 'antigravity' | 'kiro'> = [
'claude',
'cursor',
'cline',
'antigravity',
'kiro',
];

// Use the real body for these checks, since we're guarding against trimming.
Expand Down
8 changes: 7 additions & 1 deletion src/lib/agent-targets.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { readFileSync } from 'node:fs';

export type AgentTarget = 'claude' | 'cursor' | 'cline' | 'antigravity' | 'codex';
export type AgentTarget = 'claude' | 'cursor' | 'cline' | 'antigravity' | 'codex' | 'kiro';

export interface TargetSpec {
status: 'ga' | 'experimental';
Expand Down Expand Up @@ -58,6 +58,12 @@ export const TARGETS: Record<AgentTarget, TargetSpec> = {
mode: 'own-file',
wrap: body => body,
},
kiro: {
status: 'experimental',
path: '.kiro/skills/testsprite-verify/SKILL.md',
mode: 'own-file',
wrap: wrapSkill,
},
/**
* codex target — managed-section mode.
*
Expand Down