diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 481b8d0..f6348d4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -38,7 +38,7 @@ pulse/ │ │ │ ├── executors.ts 保命 executors(确定性本地命令) │ │ │ └── index.ts │ │ └── executors/ ← 业务 executors(agent 可扩展) -│ │ ├── coding-agent.ts Coding Agent Executor +│ │ ├── cursor-agent.ts Cursor Agent Executor │ │ └── index.ts │ │ │ └── upulse/src/ ← CLI 工具(@uncaged/upulse) diff --git a/packages/pulse/src/executors/coding-agent.test.ts b/packages/pulse/src/executors/cursor-agent.test.ts similarity index 90% rename from packages/pulse/src/executors/coding-agent.test.ts rename to packages/pulse/src/executors/cursor-agent.test.ts index cc6e2e0..397a4da 100644 --- a/packages/pulse/src/executors/coding-agent.test.ts +++ b/packages/pulse/src/executors/cursor-agent.test.ts @@ -1,5 +1,5 @@ /** - * Tests for coding-agent executor. + * Tests for cursor-agent executor. * * Uses stub binaries to avoid actually spawning Cursor Agent. * Verifies prompt file content, error handling, and result structure. @@ -16,7 +16,7 @@ import { } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; -import { type CodingEffect, createCodingExecutor } from './coding-agent.js'; +import { type CursorEffect, createCursorExecutor } from './cursor-agent.js'; const TEST_TMP = join(tmpdir(), `pulse-coding-test-${process.pid}`); const STUB_DIR = join(TEST_TMP, 'stubs'); @@ -38,7 +38,7 @@ function makeStub(name: string, script: string): string { return path; } -function makeEffect(overrides?: Partial): CodingEffect { +function makeEffect(overrides?: Partial): CursorEffect { return { type: 'coding-task', prompt: 'Fix the broken test in store.test.ts', @@ -48,9 +48,9 @@ function makeEffect(overrides?: Partial): CodingEffect { }; } -describe('createCodingExecutor', () => { +describe('createCursorExecutor', () => { test('returns a function', () => { - const exec = createCodingExecutor({ tmpDir: TEST_TMP }); + const exec = createCursorExecutor({ tmpDir: TEST_TMP }); expect(typeof exec).toBe('function'); }); @@ -76,20 +76,20 @@ describe('createCodingExecutor', () => { test('rejects unexpected effect type', async () => { const agentStub = makeStub('agent-type-check', 'exit 0'); - const exec = createCodingExecutor({ + const exec = createCursorExecutor({ tmpDir: TEST_TMP, apiKey: 'test-key', agentBin: agentStub, }); - const badEffect = { ...makeEffect(), type: 'other-task' } as CodingEffect; + const badEffect = { ...makeEffect(), type: 'other-task' } as CursorEffect; expect(exec(badEffect)).rejects.toThrow('Unexpected effect type'); }); }); -describe('CodingEffect structure', () => { +describe('CursorEffect structure', () => { test('required fields', () => { - const effect: CodingEffect = { + const effect: CursorEffect = { type: 'coding-task', prompt: 'do something', scenario: 'debug', @@ -103,7 +103,7 @@ describe('CodingEffect structure', () => { }); test('optional timeoutMs', () => { - const effect: CodingEffect = { + const effect: CursorEffect = { type: 'coding-task', prompt: 'do something', scenario: 'ci-fix', @@ -145,7 +145,7 @@ describe('prompt assembly', () => { // Stub reads the prompt file path (last positional arg) and cats it const catLastArg = 'cat "$' + '{@: -1}"'; const agentStub = makeStub(`agent-${scenario}`, catLastArg); - const exec = createCodingExecutor({ + const exec = createCursorExecutor({ tmpDir: TEST_TMP, apiKey: 'test-api-key', agentBin: agentStub, @@ -162,7 +162,7 @@ describe('prompt assembly', () => { describe('temp file cleanup', () => { test('prompt file is deleted after execution', async () => { const agentStub = makeStub('agent-cleanup', 'exit 0'); - const exec = createCodingExecutor({ + const exec = createCursorExecutor({ tmpDir: TEST_TMP, apiKey: 'test-key', agentBin: agentStub, @@ -179,7 +179,7 @@ describe('temp file cleanup', () => { test('prompt file is deleted even on failure', async () => { const agentStub = makeStub('agent-cleanup-fail', 'exit 1'); - const exec = createCodingExecutor({ + const exec = createCursorExecutor({ tmpDir: TEST_TMP, apiKey: 'test-key', agentBin: agentStub, @@ -197,7 +197,7 @@ describe('temp file cleanup', () => { describe('error handling', () => { test('missing apiKey and failed apiKeyCommand throws', async () => { - const exec = createCodingExecutor({ + const exec = createCursorExecutor({ tmpDir: TEST_TMP, apiKeyCommand: '/nonexistent/path/to/binary', agentBin: '/bin/echo', @@ -211,7 +211,7 @@ describe('error handling', () => { test('agent exit code 1 returns success=false', async () => { const failStub = makeStub('agent-fail', 'exit 1'); - const exec = createCodingExecutor({ + const exec = createCursorExecutor({ tmpDir: TEST_TMP, apiKey: 'test-key', agentBin: failStub, @@ -225,7 +225,7 @@ describe('error handling', () => { test('agent exit code 0 returns success=true', async () => { const okStub = makeStub('agent-ok', 'echo "task done"; exit 0'); - const exec = createCodingExecutor({ + const exec = createCursorExecutor({ tmpDir: TEST_TMP, apiKey: 'test-key', agentBin: okStub, @@ -244,7 +244,7 @@ describe('API key caching', () => { test('apiKey is resolved once and cached', async () => { const keyStub = makeStub('key-counter', `echo "cached-key-$(date +%s%N)"`); const agentStub = makeStub('agent-cache', 'exit 0'); - const exec = createCodingExecutor({ + const exec = createCursorExecutor({ tmpDir: TEST_TMP, apiKeyCommand: keyStub, agentBin: agentStub, @@ -259,7 +259,7 @@ describe('API key caching', () => { test('direct apiKey skips command resolution', async () => { const agentStub = makeStub('agent-direct', 'exit 0'); - const exec = createCodingExecutor({ + const exec = createCursorExecutor({ tmpDir: TEST_TMP, apiKey: 'direct-key', apiKeyCommand: '/nonexistent/should-not-be-called', diff --git a/packages/pulse/src/executors/coding-agent.ts b/packages/pulse/src/executors/cursor-agent.ts similarity index 95% rename from packages/pulse/src/executors/coding-agent.ts rename to packages/pulse/src/executors/cursor-agent.ts index 32f9f40..670cc2b 100644 --- a/packages/pulse/src/executors/coding-agent.ts +++ b/packages/pulse/src/executors/cursor-agent.ts @@ -1,8 +1,8 @@ /** - * executors/coding-agent.ts — Coding Agent Executor + * executors/cursor-agent.ts — Cursor Agent Executor * * Spawns a Cursor Agent CLI process to execute coding tasks. - * The executor is intentionally thin: it only translates a CodingEffect + * The executor is intentionally thin: it only translates a CursorEffect * into a CLI invocation. All intelligence (clone, branch, test, PR) * lives in the coding agent driven by repo conventions and scenario prompts. * @@ -22,7 +22,7 @@ export type CodingScenario = | 'ci-fix' | 'refactor'; -export interface CodingEffect { +export interface CursorEffect { type: 'coding-task'; /** Task description assembled by the triggering Rule. */ prompt: string; @@ -96,10 +96,10 @@ const SCENARIO_PREAMBLES: Record = { /** * Create a coding agent executor with the given options. * - * Returns an async function that accepts a CodingEffect and spawns + * Returns an async function that accepts a CursorEffect and spawns * the Cursor Agent CLI to execute the task. */ -export function createCodingExecutor(opts: CodingExecutorOptions = {}) { +export function createCursorExecutor(opts: CodingExecutorOptions = {}) { const { agentBin = `${process.env.HOME}/.local/bin/agent`, apiKey: directApiKey, @@ -111,7 +111,7 @@ export function createCodingExecutor(opts: CodingExecutorOptions = {}) { let cachedApiKey: string | undefined = directApiKey; return async function executeCodingTask( - effect: CodingEffect, + effect: CursorEffect, ): Promise { if (effect.type !== 'coding-task') { throw new Error(`Unexpected effect type: ${effect.type}`); diff --git a/packages/pulse/src/executors/index.ts b/packages/pulse/src/executors/index.ts index 4181295..c5ff6ae 100644 --- a/packages/pulse/src/executors/index.ts +++ b/packages/pulse/src/executors/index.ts @@ -1,7 +1,7 @@ export { - type CodingEffect, type CodingExecutorOptions, type CodingResult, type CodingScenario, - createCodingExecutor, -} from './coding-agent.js'; + type CursorEffect, + createCursorExecutor, +} from './cursor-agent.js';