openplanr 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/agent-factory.d.ts +1 -1
- package/dist/agents/agent-factory.d.ts.map +1 -1
- package/dist/agents/claude-agent.d.ts +8 -3
- package/dist/agents/claude-agent.d.ts.map +1 -1
- package/dist/agents/claude-agent.js +154 -19
- package/dist/agents/claude-agent.js.map +1 -1
- package/dist/agents/codex-agent.d.ts +7 -3
- package/dist/agents/codex-agent.d.ts.map +1 -1
- package/dist/agents/codex-agent.js +96 -19
- package/dist/agents/codex-agent.js.map +1 -1
- package/dist/agents/cursor-agent.d.ts +3 -2
- package/dist/agents/cursor-agent.d.ts.map +1 -1
- package/dist/agents/cursor-agent.js +21 -12
- package/dist/agents/cursor-agent.js.map +1 -1
- package/dist/agents/implementation-bridge.d.ts +9 -0
- package/dist/agents/implementation-bridge.d.ts.map +1 -1
- package/dist/agents/implementation-bridge.js +116 -31
- package/dist/agents/implementation-bridge.js.map +1 -1
- package/dist/agents/index.d.ts +4 -3
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +3 -2
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/progress.d.ts +62 -0
- package/dist/agents/progress.d.ts.map +1 -0
- package/dist/agents/progress.js +155 -0
- package/dist/agents/progress.js.map +1 -0
- package/dist/agents/prompt-composer.js +2 -2
- package/dist/agents/prompt-composer.js.map +1 -1
- package/dist/agents/task-parser.js +1 -1
- package/dist/agents/task-parser.js.map +1 -1
- package/dist/agents/types.d.ts +2 -0
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/agents/utils.d.ts +4 -0
- package/dist/agents/utils.d.ts.map +1 -1
- package/dist/agents/utils.js +23 -0
- package/dist/agents/utils.js.map +1 -1
- package/dist/ai/codebase/context-builder.d.ts.map +1 -1
- package/dist/ai/codebase/context-builder.js +3 -3
- package/dist/ai/codebase/context-builder.js.map +1 -1
- package/dist/ai/codebase/file-reader.d.ts.map +1 -1
- package/dist/ai/codebase/file-reader.js +39 -10
- package/dist/ai/codebase/file-reader.js.map +1 -1
- package/dist/ai/codebase/index.d.ts +2 -2
- package/dist/ai/codebase/index.d.ts.map +1 -1
- package/dist/ai/codebase/index.js +2 -2
- package/dist/ai/codebase/index.js.map +1 -1
- package/dist/ai/codebase/stack-detector.d.ts.map +1 -1
- package/dist/ai/codebase/stack-detector.js +42 -19
- package/dist/ai/codebase/stack-detector.js.map +1 -1
- package/dist/ai/codebase/tree-generator.d.ts.map +1 -1
- package/dist/ai/codebase/tree-generator.js +3 -7
- package/dist/ai/codebase/tree-generator.js.map +1 -1
- package/dist/ai/errors.d.ts.map +1 -1
- package/dist/ai/errors.js.map +1 -1
- package/dist/ai/index.d.ts +2 -2
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +1 -1
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/prompts/prompt-builder.d.ts +1 -0
- package/dist/ai/prompts/prompt-builder.d.ts.map +1 -1
- package/dist/ai/prompts/prompt-builder.js +11 -1
- package/dist/ai/prompts/prompt-builder.js.map +1 -1
- package/dist/ai/prompts/system-prompts.d.ts +1 -0
- package/dist/ai/prompts/system-prompts.d.ts.map +1 -1
- package/dist/ai/prompts/system-prompts.js +24 -0
- package/dist/ai/prompts/system-prompts.js.map +1 -1
- package/dist/ai/provider-factory.d.ts.map +1 -1
- package/dist/ai/provider-factory.js.map +1 -1
- package/dist/ai/providers/anthropic-provider.d.ts +1 -1
- package/dist/ai/providers/anthropic-provider.d.ts.map +1 -1
- package/dist/ai/providers/anthropic-provider.js +2 -3
- package/dist/ai/providers/anthropic-provider.js.map +1 -1
- package/dist/ai/providers/openai-provider.d.ts +1 -1
- package/dist/ai/providers/openai-provider.d.ts.map +1 -1
- package/dist/ai/providers/openai-provider.js +1 -1
- package/dist/ai/providers/openai-provider.js.map +1 -1
- package/dist/ai/schemas/ai-response-schemas.d.ts +16 -0
- package/dist/ai/schemas/ai-response-schemas.d.ts.map +1 -1
- package/dist/ai/schemas/ai-response-schemas.js +13 -1
- package/dist/ai/schemas/ai-response-schemas.js.map +1 -1
- package/dist/cli/commands/checklist.d.ts +1 -1
- package/dist/cli/commands/checklist.d.ts.map +1 -1
- package/dist/cli/commands/checklist.js +2 -2
- package/dist/cli/commands/checklist.js.map +1 -1
- package/dist/cli/commands/config.d.ts +1 -1
- package/dist/cli/commands/config.d.ts.map +1 -1
- package/dist/cli/commands/config.js +4 -4
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/epic.d.ts +1 -1
- package/dist/cli/commands/epic.d.ts.map +1 -1
- package/dist/cli/commands/epic.js +10 -8
- package/dist/cli/commands/epic.js.map +1 -1
- package/dist/cli/commands/feature.d.ts +1 -1
- package/dist/cli/commands/feature.d.ts.map +1 -1
- package/dist/cli/commands/feature.js +8 -6
- package/dist/cli/commands/feature.js.map +1 -1
- package/dist/cli/commands/init.d.ts +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +7 -4
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/plan.d.ts +1 -1
- package/dist/cli/commands/plan.d.ts.map +1 -1
- package/dist/cli/commands/plan.js +23 -12
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/quick.d.ts +13 -0
- package/dist/cli/commands/quick.d.ts.map +1 -0
- package/dist/cli/commands/quick.js +332 -0
- package/dist/cli/commands/quick.js.map +1 -0
- package/dist/cli/commands/refine.d.ts +1 -1
- package/dist/cli/commands/refine.d.ts.map +1 -1
- package/dist/cli/commands/refine.js +10 -10
- package/dist/cli/commands/refine.js.map +1 -1
- package/dist/cli/commands/rules.d.ts +1 -1
- package/dist/cli/commands/rules.d.ts.map +1 -1
- package/dist/cli/commands/rules.js +3 -3
- package/dist/cli/commands/rules.js.map +1 -1
- package/dist/cli/commands/status.d.ts +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +36 -6
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/story.d.ts +1 -1
- package/dist/cli/commands/story.d.ts.map +1 -1
- package/dist/cli/commands/story.js +10 -8
- package/dist/cli/commands/story.js.map +1 -1
- package/dist/cli/commands/sync.d.ts +1 -1
- package/dist/cli/commands/sync.d.ts.map +1 -1
- package/dist/cli/commands/sync.js +3 -3
- package/dist/cli/commands/sync.js.map +1 -1
- package/dist/cli/commands/task.d.ts +1 -1
- package/dist/cli/commands/task.d.ts.map +1 -1
- package/dist/cli/commands/task.js +62 -9
- package/dist/cli/commands/task.js.map +1 -1
- package/dist/cli/index.js +9 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/generators/base-generator.d.ts +1 -1
- package/dist/generators/base-generator.d.ts.map +1 -1
- package/dist/generators/base-generator.js.map +1 -1
- package/dist/generators/claude-generator.d.ts +2 -2
- package/dist/generators/claude-generator.d.ts.map +1 -1
- package/dist/generators/claude-generator.js +3 -3
- package/dist/generators/claude-generator.js.map +1 -1
- package/dist/generators/codex-generator.d.ts +2 -2
- package/dist/generators/codex-generator.d.ts.map +1 -1
- package/dist/generators/codex-generator.js +2 -2
- package/dist/generators/codex-generator.js.map +1 -1
- package/dist/generators/cursor-generator.d.ts +1 -1
- package/dist/generators/cursor-generator.d.ts.map +1 -1
- package/dist/generators/cursor-generator.js +1 -1
- package/dist/generators/cursor-generator.js.map +1 -1
- package/dist/generators/generator-factory.d.ts +1 -1
- package/dist/generators/generator-factory.d.ts.map +1 -1
- package/dist/generators/generator-factory.js +1 -1
- package/dist/generators/generator-factory.js.map +1 -1
- package/dist/models/schema.d.ts +1 -0
- package/dist/models/schema.d.ts.map +1 -1
- package/dist/models/schema.js +1 -0
- package/dist/models/schema.js.map +1 -1
- package/dist/models/types.d.ts +3 -2
- package/dist/models/types.d.ts.map +1 -1
- package/dist/services/ai-service.d.ts +1 -1
- package/dist/services/ai-service.d.ts.map +1 -1
- package/dist/services/ai-service.js +3 -5
- package/dist/services/ai-service.js.map +1 -1
- package/dist/services/artifact-gathering.d.ts.map +1 -1
- package/dist/services/artifact-gathering.js +3 -3
- package/dist/services/artifact-gathering.js.map +1 -1
- package/dist/services/artifact-service.d.ts +1 -1
- package/dist/services/artifact-service.d.ts.map +1 -1
- package/dist/services/artifact-service.js +5 -3
- package/dist/services/artifact-service.js.map +1 -1
- package/dist/services/checklist-service.d.ts.map +1 -1
- package/dist/services/checklist-service.js.map +1 -1
- package/dist/services/config-service.d.ts.map +1 -1
- package/dist/services/config-service.js +3 -2
- package/dist/services/config-service.js.map +1 -1
- package/dist/services/credential-backends.d.ts.map +1 -1
- package/dist/services/credential-backends.js +3 -3
- package/dist/services/credential-backends.js.map +1 -1
- package/dist/services/credentials-service.d.ts.map +1 -1
- package/dist/services/credentials-service.js +1 -1
- package/dist/services/credentials-service.js.map +1 -1
- package/dist/services/id-service.d.ts.map +1 -1
- package/dist/services/id-service.js.map +1 -1
- package/dist/services/prompt-service.js +1 -1
- package/dist/services/prompt-service.js.map +1 -1
- package/dist/services/template-service.js +1 -1
- package/dist/services/template-service.js.map +1 -1
- package/dist/templates/quick/quick-task.md.hbs +29 -0
- package/dist/utils/constants.d.ts +2 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +2 -0
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/error-context.d.ts +23 -0
- package/dist/utils/error-context.d.ts.map +1 -0
- package/dist/utils/error-context.js +94 -0
- package/dist/utils/error-context.js.map +1 -0
- package/dist/utils/fs.d.ts.map +1 -1
- package/dist/utils/fs.js +7 -3
- package/dist/utils/fs.js.map +1 -1
- package/dist/utils/logger.js +2 -2
- package/dist/utils/logger.js.map +1 -1
- package/package.json +6 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Factory for creating coding agent instances.
|
|
3
3
|
*/
|
|
4
|
-
import type { CodingAgent } from './types.js';
|
|
5
4
|
import type { CodingAgentName } from '../models/types.js';
|
|
5
|
+
import type { CodingAgent } from './types.js';
|
|
6
6
|
export declare function createAgent(name: CodingAgentName): Promise<CodingAgent>;
|
|
7
7
|
//# sourceMappingURL=agent-factory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-factory.d.ts","sourceRoot":"","sources":["../../src/agents/agent-factory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"agent-factory.d.ts","sourceRoot":"","sources":["../../src/agents/agent-factory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,wBAAsB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC,CAiB7E"}
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Claude Code CLI agent adapter.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
4
|
+
* Spawns `claude --print` with stream-json output, showing real-time
|
|
5
|
+
* progress via the shared progress spinner. Includes automatic retry
|
|
6
|
+
* for transient API errors.
|
|
6
7
|
*/
|
|
7
|
-
import type {
|
|
8
|
+
import type { AgentOptions, AgentResult, CodingAgent } from './types.js';
|
|
8
9
|
export declare class ClaudeAgent implements CodingAgent {
|
|
9
10
|
readonly name = "claude";
|
|
10
11
|
isAvailable(): Promise<boolean>;
|
|
11
12
|
execute(prompt: string, options: AgentOptions): Promise<AgentResult>;
|
|
13
|
+
private spawnClaude;
|
|
14
|
+
private buildArgs;
|
|
15
|
+
private attachListeners;
|
|
16
|
+
private printSummary;
|
|
12
17
|
}
|
|
13
18
|
//# sourceMappingURL=claude-agent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-agent.d.ts","sourceRoot":"","sources":["../../src/agents/claude-agent.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"claude-agent.d.ts","sourceRoot":"","sources":["../../src/agents/claude-agent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAsCzE,qBAAa,WAAY,YAAW,WAAW;IAC7C,QAAQ,CAAC,IAAI,YAAY;IAEnB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAI/B,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IAiC1E,OAAO,CAAC,WAAW;IAyCnB,OAAO,CAAC,SAAS;IAmBjB,OAAO,CAAC,eAAe;IA2CvB,OAAO,CAAC,YAAY;CA0BrB"}
|
|
@@ -1,48 +1,183 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Claude Code CLI agent adapter.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
4
|
+
* Spawns `claude --print` with stream-json output, showing real-time
|
|
5
|
+
* progress via the shared progress spinner. Includes automatic retry
|
|
6
|
+
* for transient API errors.
|
|
6
7
|
*/
|
|
7
8
|
import { spawn } from 'node:child_process';
|
|
8
|
-
import {
|
|
9
|
+
import { createReadStream } from 'node:fs';
|
|
10
|
+
import { unlink, writeFile } from 'node:fs/promises';
|
|
11
|
+
import { tmpdir } from 'node:os';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import chalk from 'chalk';
|
|
14
|
+
import { createProgressSpinner, describeActivity } from './progress.js';
|
|
15
|
+
import { isRetryableError, MAX_RETRIES, RETRY_DELAY_MS, sleep, which } from './utils.js';
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Constants
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
/**
|
|
20
|
+
* Default tool set — we use all standard tools. Claude Code already
|
|
21
|
+
* enforces CWD sandboxing and default permission checks. The safety
|
|
22
|
+
* prompt below handles project-scoped constraints.
|
|
23
|
+
*/
|
|
24
|
+
const ALLOWED_TOOLS = ['Bash', 'Edit', 'Write', 'Read', 'Glob', 'Grep'];
|
|
25
|
+
const SAFETY_PROMPT = [
|
|
26
|
+
'IMPORTANT SAFETY RULES:',
|
|
27
|
+
'1. NEVER run system-wide destructive commands: docker system prune, docker volume prune, docker image prune -a, or similar commands that affect resources beyond this project.',
|
|
28
|
+
'2. For docker cleanup, ONLY use project-scoped commands: docker compose down, docker compose rm.',
|
|
29
|
+
'3. NEVER run sudo or any privilege escalation.',
|
|
30
|
+
'4. NEVER run rm -rf on directories you did not create in this session.',
|
|
31
|
+
'5. When unsure if a command is destructive, explain what you would run and ask the user to execute it manually.',
|
|
32
|
+
].join('\n');
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Helpers
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
/** Write prompt to a temp file to avoid ARG_MAX / backpressure issues */
|
|
37
|
+
async function writeTempPrompt(prompt) {
|
|
38
|
+
const tmpFile = path.join(tmpdir(), `planr-prompt-${Date.now()}.txt`);
|
|
39
|
+
await writeFile(tmpFile, prompt, 'utf-8');
|
|
40
|
+
return tmpFile;
|
|
41
|
+
}
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
// Agent
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
9
45
|
export class ClaudeAgent {
|
|
10
46
|
name = 'claude';
|
|
11
47
|
async isAvailable() {
|
|
12
48
|
return (await which('claude')) !== null;
|
|
13
49
|
}
|
|
14
50
|
async execute(prompt, options) {
|
|
51
|
+
const tmpFile = await writeTempPrompt(prompt);
|
|
52
|
+
try {
|
|
53
|
+
let lastExitCode = 1;
|
|
54
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
55
|
+
if (attempt > 0) {
|
|
56
|
+
const delaySec = (RETRY_DELAY_MS * attempt) / 1000;
|
|
57
|
+
process.stderr.write(`\n⟳ Retrying (attempt ${attempt + 1}/${MAX_RETRIES + 1}) in ${delaySec}s...\n`);
|
|
58
|
+
await sleep(RETRY_DELAY_MS * attempt);
|
|
59
|
+
}
|
|
60
|
+
const result = await this.spawnClaude(tmpFile, options);
|
|
61
|
+
lastExitCode = result.exitCode;
|
|
62
|
+
if (result.exitCode === 0)
|
|
63
|
+
return result;
|
|
64
|
+
if (result.stderr && isRetryableError(result.stderr))
|
|
65
|
+
continue;
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
return { output: '', exitCode: lastExitCode };
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
await unlink(tmpFile).catch(() => { });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// -------------------------------------------------------------------------
|
|
75
|
+
// Private
|
|
76
|
+
// -------------------------------------------------------------------------
|
|
77
|
+
spawnClaude(tmpFile, options) {
|
|
15
78
|
return new Promise((resolve, reject) => {
|
|
16
|
-
const args =
|
|
79
|
+
const args = this.buildArgs(options);
|
|
17
80
|
const child = spawn('claude', args, {
|
|
18
81
|
cwd: options.cwd,
|
|
19
82
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
20
83
|
env: { ...process.env },
|
|
21
84
|
});
|
|
22
|
-
const
|
|
23
|
-
child.
|
|
24
|
-
|
|
25
|
-
chunks.push(text);
|
|
26
|
-
if (options.stream) {
|
|
27
|
-
process.stdout.write(text);
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
child.stderr.on('data', (data) => {
|
|
31
|
-
const text = data.toString();
|
|
32
|
-
if (options.stream) {
|
|
33
|
-
process.stderr.write(text);
|
|
34
|
-
}
|
|
35
|
-
});
|
|
85
|
+
const fileStream = createReadStream(tmpFile, 'utf-8');
|
|
86
|
+
fileStream.pipe(child.stdin);
|
|
87
|
+
const { spinner, stderrChunks, resultRef, statsRef } = this.attachListeners(child);
|
|
36
88
|
child.on('error', (err) => {
|
|
89
|
+
spinner.stop();
|
|
37
90
|
reject(new Error(`Failed to launch claude CLI: ${err.message}`));
|
|
38
91
|
});
|
|
39
92
|
child.on('close', (code) => {
|
|
93
|
+
spinner.stop();
|
|
94
|
+
this.printSummary(resultRef.text, statsRef, stderrChunks, code);
|
|
95
|
+
// Combine stderr and stdout for retry detection — Claude sometimes
|
|
96
|
+
// emits API errors (e.g. "tool use concurrency") via stdout stream
|
|
97
|
+
const stderr = stderrChunks.join('');
|
|
98
|
+
const combinedOutput = `${stderr}\n${resultRef.text}`;
|
|
40
99
|
resolve({
|
|
41
|
-
output:
|
|
100
|
+
output: resultRef.text,
|
|
42
101
|
exitCode: code ?? 1,
|
|
102
|
+
stderr: combinedOutput,
|
|
43
103
|
});
|
|
44
104
|
});
|
|
45
105
|
});
|
|
46
106
|
}
|
|
107
|
+
buildArgs(options) {
|
|
108
|
+
const args = [
|
|
109
|
+
'--print',
|
|
110
|
+
'--verbose',
|
|
111
|
+
'--output-format',
|
|
112
|
+
'stream-json',
|
|
113
|
+
'--allowedTools',
|
|
114
|
+
...ALLOWED_TOOLS,
|
|
115
|
+
'--append-system-prompt',
|
|
116
|
+
SAFETY_PROMPT,
|
|
117
|
+
];
|
|
118
|
+
if (options.continueSession) {
|
|
119
|
+
args.push('--continue');
|
|
120
|
+
}
|
|
121
|
+
return args;
|
|
122
|
+
}
|
|
123
|
+
attachListeners(child) {
|
|
124
|
+
const spinner = createProgressSpinner();
|
|
125
|
+
const stderrChunks = [];
|
|
126
|
+
const resultRef = { text: '' };
|
|
127
|
+
const statsRef = { filesCreated: 0, filesEdited: 0 };
|
|
128
|
+
let jsonBuffer = '';
|
|
129
|
+
child.stdout?.on('data', (data) => {
|
|
130
|
+
jsonBuffer += data.toString();
|
|
131
|
+
const lines = jsonBuffer.split('\n');
|
|
132
|
+
jsonBuffer = lines.pop() || '';
|
|
133
|
+
for (const line of lines) {
|
|
134
|
+
const trimmed = line.trim();
|
|
135
|
+
if (!trimmed)
|
|
136
|
+
continue;
|
|
137
|
+
try {
|
|
138
|
+
const event = JSON.parse(trimmed);
|
|
139
|
+
const activity = describeActivity(event);
|
|
140
|
+
if (activity) {
|
|
141
|
+
spinner.setActivity(activity);
|
|
142
|
+
if (activity.startsWith('Creating '))
|
|
143
|
+
statsRef.filesCreated++;
|
|
144
|
+
if (activity.startsWith('Editing '))
|
|
145
|
+
statsRef.filesEdited++;
|
|
146
|
+
process.stderr.write(`\r\x1b[K${chalk.green('✓')} ${chalk.dim(activity)}\n`);
|
|
147
|
+
}
|
|
148
|
+
if (event.type === 'result') {
|
|
149
|
+
resultRef.text = event.result || '';
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// Incomplete JSON line — skip
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
child.stderr?.on('data', (data) => {
|
|
158
|
+
stderrChunks.push(data.toString());
|
|
159
|
+
});
|
|
160
|
+
return { spinner, stderrChunks, resultRef, statsRef };
|
|
161
|
+
}
|
|
162
|
+
printSummary(resultText, stats, stderrChunks, exitCode) {
|
|
163
|
+
if (resultText) {
|
|
164
|
+
console.log(resultText);
|
|
165
|
+
}
|
|
166
|
+
const parts = [];
|
|
167
|
+
if (stats.filesCreated > 0) {
|
|
168
|
+
parts.push(`${stats.filesCreated} file${stats.filesCreated > 1 ? 's' : ''} created`);
|
|
169
|
+
}
|
|
170
|
+
if (stats.filesEdited > 0) {
|
|
171
|
+
parts.push(`${stats.filesEdited} file${stats.filesEdited > 1 ? 's' : ''} edited`);
|
|
172
|
+
}
|
|
173
|
+
if (parts.length > 0) {
|
|
174
|
+
console.log(chalk.dim(`\n📊 ${parts.join(', ')}`));
|
|
175
|
+
}
|
|
176
|
+
if (exitCode !== 0) {
|
|
177
|
+
const stderr = stderrChunks.join('');
|
|
178
|
+
if (stderr)
|
|
179
|
+
process.stderr.write(stderr);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
47
182
|
}
|
|
48
183
|
//# sourceMappingURL=claude-agent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-agent.js","sourceRoot":"","sources":["../../src/agents/claude-agent.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"claude-agent.js","sourceRoot":"","sources":["../../src/agents/claude-agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* OpenAI Codex CLI agent adapter.
|
|
3
3
|
*
|
|
4
|
-
* Invokes
|
|
5
|
-
*
|
|
4
|
+
* Invokes `codex exec --full-auto --json` for non-interactive mode with
|
|
5
|
+
* write access. Parses JSONL events for real-time progress display.
|
|
6
|
+
* Includes retry logic for transient errors.
|
|
6
7
|
*/
|
|
7
|
-
import type {
|
|
8
|
+
import type { AgentOptions, AgentResult, CodingAgent } from './types.js';
|
|
8
9
|
export declare class CodexAgent implements CodingAgent {
|
|
9
10
|
readonly name = "codex";
|
|
10
11
|
isAvailable(): Promise<boolean>;
|
|
11
12
|
execute(prompt: string, options: AgentOptions): Promise<AgentResult>;
|
|
13
|
+
private spawnCodex;
|
|
14
|
+
private buildArgs;
|
|
15
|
+
private attachListeners;
|
|
12
16
|
}
|
|
13
17
|
//# sourceMappingURL=codex-agent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-agent.d.ts","sourceRoot":"","sources":["../../src/agents/codex-agent.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"codex-agent.d.ts","sourceRoot":"","sources":["../../src/agents/codex-agent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGzE,qBAAa,UAAW,YAAW,WAAW;IAC5C,QAAQ,CAAC,IAAI,WAAW;IAElB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAI/B,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IA8B1E,OAAO,CAAC,UAAU;IA6ClB,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,eAAe;CA4CxB"}
|
|
@@ -1,47 +1,124 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* OpenAI Codex CLI agent adapter.
|
|
3
3
|
*
|
|
4
|
-
* Invokes
|
|
5
|
-
*
|
|
4
|
+
* Invokes `codex exec --full-auto --json` for non-interactive mode with
|
|
5
|
+
* write access. Parses JSONL events for real-time progress display.
|
|
6
|
+
* Includes retry logic for transient errors.
|
|
6
7
|
*/
|
|
7
8
|
import { spawn } from 'node:child_process';
|
|
8
|
-
import {
|
|
9
|
+
import { createReadStream } from 'node:fs';
|
|
10
|
+
import { unlink, writeFile } from 'node:fs/promises';
|
|
11
|
+
import { tmpdir } from 'node:os';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import chalk from 'chalk';
|
|
14
|
+
import { createProgressSpinner, describeCodexActivity } from './progress.js';
|
|
15
|
+
import { isRetryableError, MAX_RETRIES, RETRY_DELAY_MS, sleep, which } from './utils.js';
|
|
9
16
|
export class CodexAgent {
|
|
10
17
|
name = 'codex';
|
|
11
18
|
async isAvailable() {
|
|
12
19
|
return (await which('codex')) !== null;
|
|
13
20
|
}
|
|
14
21
|
async execute(prompt, options) {
|
|
22
|
+
const tmpFile = path.join(tmpdir(), `planr-prompt-${Date.now()}.txt`);
|
|
23
|
+
await writeFile(tmpFile, prompt, 'utf-8');
|
|
24
|
+
try {
|
|
25
|
+
let lastExitCode = 1;
|
|
26
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
27
|
+
if (attempt > 0) {
|
|
28
|
+
const delaySec = (RETRY_DELAY_MS * attempt) / 1000;
|
|
29
|
+
process.stderr.write(`\n⟳ Retrying (attempt ${attempt + 1}/${MAX_RETRIES + 1}) in ${delaySec}s...\n`);
|
|
30
|
+
await sleep(RETRY_DELAY_MS * attempt);
|
|
31
|
+
}
|
|
32
|
+
const result = await this.spawnCodex(tmpFile, options);
|
|
33
|
+
lastExitCode = result.exitCode;
|
|
34
|
+
if (result.exitCode === 0)
|
|
35
|
+
return result;
|
|
36
|
+
if (result.stderr && isRetryableError(result.stderr))
|
|
37
|
+
continue;
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
return { output: '', exitCode: lastExitCode };
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
await unlink(tmpFile).catch(() => { });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
spawnCodex(tmpFile, options) {
|
|
15
47
|
return new Promise((resolve, reject) => {
|
|
16
|
-
const
|
|
48
|
+
const args = this.buildArgs(options);
|
|
49
|
+
const child = spawn('codex', args, {
|
|
17
50
|
cwd: options.cwd,
|
|
18
51
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
19
52
|
env: { ...process.env },
|
|
20
53
|
});
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (options.stream) {
|
|
26
|
-
process.stdout.write(text);
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
child.stderr.on('data', (data) => {
|
|
30
|
-
const text = data.toString();
|
|
31
|
-
if (options.stream) {
|
|
32
|
-
process.stderr.write(text);
|
|
33
|
-
}
|
|
34
|
-
});
|
|
54
|
+
// Stream the temp file into stdin
|
|
55
|
+
const fileStream = createReadStream(tmpFile, 'utf-8');
|
|
56
|
+
fileStream.pipe(child.stdin);
|
|
57
|
+
const { spinner, stderrChunks, resultRef } = this.attachListeners(child);
|
|
35
58
|
child.on('error', (err) => {
|
|
59
|
+
spinner.stop();
|
|
36
60
|
reject(new Error(`Failed to launch codex CLI: ${err.message}`));
|
|
37
61
|
});
|
|
38
62
|
child.on('close', (code) => {
|
|
63
|
+
spinner.stop();
|
|
64
|
+
if (resultRef.text) {
|
|
65
|
+
console.log(resultRef.text);
|
|
66
|
+
}
|
|
67
|
+
if (code !== 0) {
|
|
68
|
+
const stderr = stderrChunks.join('');
|
|
69
|
+
if (stderr)
|
|
70
|
+
process.stderr.write(stderr);
|
|
71
|
+
}
|
|
39
72
|
resolve({
|
|
40
|
-
output:
|
|
73
|
+
output: resultRef.text,
|
|
41
74
|
exitCode: code ?? 1,
|
|
75
|
+
stderr: stderrChunks.join(''),
|
|
42
76
|
});
|
|
43
77
|
});
|
|
44
78
|
});
|
|
45
79
|
}
|
|
80
|
+
buildArgs(options) {
|
|
81
|
+
if (options.continueSession) {
|
|
82
|
+
return ['exec', 'resume', '--last'];
|
|
83
|
+
}
|
|
84
|
+
return ['exec', '--full-auto', '--json'];
|
|
85
|
+
}
|
|
86
|
+
attachListeners(child) {
|
|
87
|
+
const spinner = createProgressSpinner();
|
|
88
|
+
const stderrChunks = [];
|
|
89
|
+
const resultRef = { text: '' };
|
|
90
|
+
let jsonBuffer = '';
|
|
91
|
+
child.stdout?.on('data', (data) => {
|
|
92
|
+
jsonBuffer += data.toString();
|
|
93
|
+
const lines = jsonBuffer.split('\n');
|
|
94
|
+
jsonBuffer = lines.pop() || '';
|
|
95
|
+
for (const line of lines) {
|
|
96
|
+
const trimmed = line.trim();
|
|
97
|
+
if (!trimmed)
|
|
98
|
+
continue;
|
|
99
|
+
try {
|
|
100
|
+
const event = JSON.parse(trimmed);
|
|
101
|
+
const activity = describeCodexActivity(event);
|
|
102
|
+
if (activity) {
|
|
103
|
+
spinner.setActivity(activity);
|
|
104
|
+
process.stderr.write(`\r\x1b[K${chalk.green('✓')} ${chalk.dim(activity)}\n`);
|
|
105
|
+
}
|
|
106
|
+
// Capture the last agent message as the result text
|
|
107
|
+
if (event.type === 'item.completed' &&
|
|
108
|
+
event.item?.type === 'agent_message' &&
|
|
109
|
+
event.item.text) {
|
|
110
|
+
resultRef.text = event.item.text;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Incomplete JSON line — skip
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
child.stderr?.on('data', (data) => {
|
|
119
|
+
stderrChunks.push(data.toString());
|
|
120
|
+
});
|
|
121
|
+
return { spinner, stderrChunks, resultRef };
|
|
122
|
+
}
|
|
46
123
|
}
|
|
47
124
|
//# sourceMappingURL=codex-agent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-agent.js","sourceRoot":"","sources":["../../src/agents/codex-agent.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"codex-agent.js","sourceRoot":"","sources":["../../src/agents/codex-agent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAmB,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAE9F,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEzF,MAAM,OAAO,UAAU;IACZ,IAAI,GAAG,OAAO,CAAC;IAExB,KAAK,CAAC,WAAW;QACf,OAAO,CAAC,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,OAAqB;QACjD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,gBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACtE,MAAM,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAE1C,IAAI,CAAC;YACH,IAAI,YAAY,GAAG,CAAC,CAAC;YAErB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;gBACxD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;oBAChB,MAAM,QAAQ,GAAG,CAAC,cAAc,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC;oBACnD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,yBAAyB,OAAO,GAAG,CAAC,IAAI,WAAW,GAAG,CAAC,QAAQ,QAAQ,QAAQ,CAChF,CAAC;oBACF,MAAM,KAAK,CAAC,cAAc,GAAG,OAAO,CAAC,CAAC;gBACxC,CAAC;gBAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBACvD,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC;gBAE/B,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC;oBAAE,OAAO,MAAM,CAAC;gBACzC,IAAI,MAAM,CAAC,MAAM,IAAI,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC;oBAAE,SAAS;gBAC/D,OAAO,MAAM,CAAC;YAChB,CAAC;YAED,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;QAChD,CAAC;gBAAS,CAAC;YACT,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAEO,UAAU,CAChB,OAAe,EACf,OAAqB;QAErB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAErC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;gBACjC,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;gBAC/B,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;aACxB,CAAC,CAAC;YAEH,kCAAkC;YAClC,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACtD,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAE7B,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;YAEzE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACxB,OAAO,CAAC,IAAI,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAClE,CAAC,CAAC,CAAC;YAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBACzB,OAAO,CAAC,IAAI,EAAE,CAAC;gBAEf,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC;oBACnB,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;gBAC9B,CAAC;gBAED,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBACf,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACrC,IAAI,MAAM;wBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAC3C,CAAC;gBAED,OAAO,CAAC;oBACN,MAAM,EAAE,SAAS,CAAC,IAAI;oBACtB,QAAQ,EAAE,IAAI,IAAI,CAAC;oBACnB,MAAM,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;iBAC9B,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,SAAS,CAAC,OAAqB;QACrC,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;YAC5B,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACtC,CAAC;QAED,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAEO,eAAe,CAAC,KAA+B;QACrD,MAAM,OAAO,GAAG,qBAAqB,EAAE,CAAC;QACxC,MAAM,YAAY,GAAa,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;QAC/B,IAAI,UAAU,GAAG,EAAE,CAAC;QAEpB,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YACxC,UAAU,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrC,UAAU,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;YAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC5B,IAAI,CAAC,OAAO;oBAAE,SAAS;gBAEvB,IAAI,CAAC;oBACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAe,CAAC;oBAEhD,MAAM,QAAQ,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;oBAC9C,IAAI,QAAQ,EAAE,CAAC;wBACb,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;wBAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;oBAC/E,CAAC;oBAED,oDAAoD;oBACpD,IACE,KAAK,CAAC,IAAI,KAAK,gBAAgB;wBAC/B,KAAK,CAAC,IAAI,EAAE,IAAI,KAAK,eAAe;wBACpC,KAAK,CAAC,IAAI,CAAC,IAAI,EACf,CAAC;wBACD,SAAS,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;oBACnC,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,8BAA8B;gBAChC,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YACxC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;IAC9C,CAAC;CACF"}
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Cursor agent adapter.
|
|
3
3
|
*
|
|
4
4
|
* Since Cursor is GUI-based, this agent writes the implementation
|
|
5
|
-
* prompt to a file that Cursor can read from its
|
|
5
|
+
* prompt to a file that Cursor can read from its Composer panel.
|
|
6
|
+
* For follow-up/fix prompts, it appends to the same file.
|
|
6
7
|
*/
|
|
7
|
-
import type {
|
|
8
|
+
import type { AgentOptions, AgentResult, CodingAgent } from './types.js';
|
|
8
9
|
export declare class CursorAgent implements CodingAgent {
|
|
9
10
|
readonly name = "cursor";
|
|
10
11
|
isAvailable(): Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor-agent.d.ts","sourceRoot":"","sources":["../../src/agents/cursor-agent.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"cursor-agent.d.ts","sourceRoot":"","sources":["../../src/agents/cursor-agent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzE,qBAAa,WAAY,YAAW,WAAW;IAC7C,QAAQ,CAAC,IAAI,YAAY;IAEnB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAO/B,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;CAqC3E"}
|
|
@@ -2,38 +2,47 @@
|
|
|
2
2
|
* Cursor agent adapter.
|
|
3
3
|
*
|
|
4
4
|
* Since Cursor is GUI-based, this agent writes the implementation
|
|
5
|
-
* prompt to a file that Cursor can read from its
|
|
5
|
+
* prompt to a file that Cursor can read from its Composer panel.
|
|
6
|
+
* For follow-up/fix prompts, it appends to the same file.
|
|
6
7
|
*/
|
|
7
|
-
import path from 'node:path';
|
|
8
8
|
import { access } from 'node:fs/promises';
|
|
9
|
-
import
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { ensureDir, writeFile } from '../utils/fs.js';
|
|
11
|
+
import { logger } from '../utils/logger.js';
|
|
10
12
|
export class CursorAgent {
|
|
11
13
|
name = 'cursor';
|
|
12
14
|
async isAvailable() {
|
|
13
15
|
// Cursor is available if the project has a .cursor directory
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
return access(path.join(process.cwd(), '.cursor'))
|
|
17
|
+
.then(() => true)
|
|
18
|
+
.catch(() => false);
|
|
16
19
|
}
|
|
17
20
|
async execute(prompt, options) {
|
|
18
21
|
const promptDir = path.join(options.cwd, '.cursor', 'prompts');
|
|
19
22
|
await ensureDir(promptDir);
|
|
20
|
-
// Extract task ID from prompt for filename
|
|
23
|
+
// Extract task ID from prompt for a meaningful filename
|
|
21
24
|
const taskMatch = prompt.match(/TASK-\d{3}/);
|
|
22
25
|
const filename = taskMatch ? `${taskMatch[0]}.md` : `implement-${Date.now()}.md`;
|
|
23
26
|
const filePath = path.join(promptDir, filename);
|
|
24
|
-
|
|
27
|
+
const header = options.continueSession ? '<!-- Follow-up / Fix prompt -->\n\n' : '';
|
|
28
|
+
await writeFile(filePath, header + prompt);
|
|
29
|
+
const action = options.continueSession ? 'Fix' : 'Implementation';
|
|
25
30
|
const output = [
|
|
26
|
-
|
|
31
|
+
`${action} prompt saved to: ${filePath}`,
|
|
27
32
|
'',
|
|
28
|
-
'To
|
|
33
|
+
'To use in Cursor:',
|
|
29
34
|
' 1. Open Cursor in this project',
|
|
30
|
-
' 2. Open
|
|
31
|
-
|
|
32
|
-
' 4. Or paste the prompt directly into
|
|
35
|
+
' 2. Open Composer (Cmd+I / Ctrl+I)',
|
|
36
|
+
` 3. Reference the file: @${path.relative(options.cwd, filePath)}`,
|
|
37
|
+
' 4. Or copy-paste the prompt directly into Composer',
|
|
33
38
|
].join('\n');
|
|
34
39
|
if (options.stream) {
|
|
35
40
|
console.log(output);
|
|
36
41
|
}
|
|
42
|
+
if (options.continueSession) {
|
|
43
|
+
logger.dim('Note: Cursor does not support session continuation.');
|
|
44
|
+
logger.dim('The fix prompt has been saved as a new file — paste it into your existing Composer thread.');
|
|
45
|
+
}
|
|
37
46
|
return { output, exitCode: 0 };
|
|
38
47
|
}
|
|
39
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor-agent.js","sourceRoot":"","sources":["../../src/agents/cursor-agent.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"cursor-agent.js","sourceRoot":"","sources":["../../src/agents/cursor-agent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAG5C,MAAM,OAAO,WAAW;IACb,IAAI,GAAG,QAAQ,CAAC;IAEzB,KAAK,CAAC,WAAW;QACf,6DAA6D;QAC7D,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;aAC/C,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;aAChB,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,OAAqB;QACjD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAC/D,MAAM,SAAS,CAAC,SAAS,CAAC,CAAC;QAE3B,wDAAwD;QACxD,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC;QACjF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAEhD,MAAM,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,qCAAqC,CAAC,CAAC,CAAC,EAAE,CAAC;QAEpF,MAAM,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;QAE3C,MAAM,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC;QAClE,MAAM,MAAM,GAAG;YACb,GAAG,MAAM,qBAAqB,QAAQ,EAAE;YACxC,EAAE;YACF,mBAAmB;YACnB,kCAAkC;YAClC,qCAAqC;YACrC,6BAA6B,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE;YACnE,sDAAsD;SACvD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtB,CAAC;QAED,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;YAC5B,MAAM,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;YAClE,MAAM,CAAC,GAAG,CACR,4FAA4F,CAC7F,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACjC,CAAC;CACF"}
|
|
@@ -18,4 +18,13 @@ export interface ImplementOptions {
|
|
|
18
18
|
markDone?: boolean;
|
|
19
19
|
}
|
|
20
20
|
export declare function executeImplementation(projectDir: string, config: OpenPlanrConfig, taskId: string, opts: ImplementOptions): Promise<void>;
|
|
21
|
+
export interface FollowUpOptions {
|
|
22
|
+
agent?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Send a follow-up message to the coding agent, continuing the
|
|
26
|
+
* previous session. This is the feedback loop for fixing issues
|
|
27
|
+
* found after implementation.
|
|
28
|
+
*/
|
|
29
|
+
export declare function executeFollowUp(projectDir: string, config: OpenPlanrConfig, message: string, opts: FollowUpOptions): Promise<void>;
|
|
21
30
|
//# sourceMappingURL=implementation-bridge.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"implementation-bridge.d.ts","sourceRoot":"","sources":["../../src/agents/implementation-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"implementation-bridge.d.ts","sourceRoot":"","sources":["../../src/agents/implementation-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAmB,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAiB3E,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CA2Kf;AAoCD,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,IAAI,CAAC,CAsCf"}
|