mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 06:12:03 +00:00
feat(server): Add readOnly mode to Cursor provider for read-only operations
Adds a readOnly option to ExecuteOptions that controls whether the Cursor CLI runs with --force flag (allows edits) or without (suggest-only). Read-only routes now pass readOnly: true: - generate-spec.ts, generate-features-from-spec.ts (we write files ourselves) - validate-issue.ts, generate-suggestions.ts (analysis only) - describe-file.ts, describe-image.ts (description only) - generate-plan.ts, enhance.ts (text generation only) Routes that implement features (auto-mode-service, agent-service) keep the default (readOnly: false) to allow file modifications. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -140,12 +140,18 @@ export class CursorProvider extends CliProvider {
|
||||
// shell escaping issues when content contains $(), backticks, etc.
|
||||
const cliArgs: string[] = [
|
||||
'-p', // Print mode (non-interactive)
|
||||
'--force', // Allow file modifications
|
||||
'--output-format',
|
||||
'stream-json',
|
||||
'--stream-partial-output', // Real-time streaming
|
||||
];
|
||||
|
||||
// Only add --force if NOT in read-only mode
|
||||
// Without --force, Cursor CLI suggests changes but doesn't apply them
|
||||
// With --force, Cursor CLI can actually edit files
|
||||
if (!options.readOnly) {
|
||||
cliArgs.push('--force');
|
||||
}
|
||||
|
||||
// Add model if not auto
|
||||
if (model !== 'auto') {
|
||||
cliArgs.push('--model', model);
|
||||
|
||||
@@ -34,6 +34,12 @@ export interface ExecuteOptions {
|
||||
conversationHistory?: ConversationMessage[]; // Previous messages for context
|
||||
sdkSessionId?: string; // Claude SDK session ID for resuming conversations
|
||||
settingSources?: Array<'user' | 'project' | 'local'>; // Claude filesystem settings to load
|
||||
/**
|
||||
* If true, the provider should run in read-only mode (no file modifications).
|
||||
* For Cursor CLI, this omits the --force flag, making it suggest-only.
|
||||
* Default: false (allows edits)
|
||||
*/
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -132,6 +132,7 @@ IMPORTANT: Do not ask for clarification. The specification is provided above. Ge
|
||||
maxTurns: 250,
|
||||
allowedTools: ['Read', 'Glob', 'Grep'],
|
||||
abortController,
|
||||
readOnly: true, // Feature generation only reads code, doesn't write
|
||||
})) {
|
||||
messageCount++;
|
||||
|
||||
|
||||
@@ -132,6 +132,7 @@ ${JSON.stringify(specOutputSchema, null, 2)}`;
|
||||
maxTurns: 250,
|
||||
allowedTools: ['Read', 'Glob', 'Grep'],
|
||||
abortController,
|
||||
readOnly: true, // Spec generation only reads code, we write the spec ourselves
|
||||
})) {
|
||||
messageCount++;
|
||||
|
||||
|
||||
@@ -183,6 +183,7 @@ Please analyze the current backlog and the user's request, then provide a JSON p
|
||||
allowedTools: [], // No tools needed for this
|
||||
abortController,
|
||||
settingSources: autoLoadClaudeMd ? ['user', 'project'] : undefined,
|
||||
readOnly: true, // Plan generation only generates text, doesn't write files
|
||||
});
|
||||
|
||||
let responseText = '';
|
||||
|
||||
@@ -207,6 +207,7 @@ File: ${fileName}${truncated ? ' (truncated)' : ''}`;
|
||||
cwd,
|
||||
maxTurns: 1,
|
||||
allowedTools: [],
|
||||
readOnly: true, // File description only reads, doesn't write
|
||||
})) {
|
||||
if (msg.type === 'assistant' && msg.message?.content) {
|
||||
for (const block of msg.message.content) {
|
||||
|
||||
@@ -371,6 +371,7 @@ export function createDescribeImageHandler(
|
||||
cwd,
|
||||
maxTurns: 1,
|
||||
allowedTools: ['Read'], // Allow Read tool so Cursor can read the image if needed
|
||||
readOnly: true, // Image description only reads, doesn't write
|
||||
})) {
|
||||
if (msg.type === 'assistant' && msg.message?.content) {
|
||||
for (const block of msg.message.content) {
|
||||
|
||||
@@ -97,6 +97,7 @@ async function executeWithCursor(prompt: string, model: string): Promise<string>
|
||||
prompt,
|
||||
model,
|
||||
cwd: process.cwd(), // Enhancement doesn't need a specific working directory
|
||||
readOnly: true, // Prompt enhancement only generates text, doesn't write files
|
||||
})) {
|
||||
if (msg.type === 'assistant' && msg.message?.content) {
|
||||
for (const block of msg.message.content) {
|
||||
|
||||
@@ -111,6 +111,7 @@ ${prompt}`;
|
||||
prompt: cursorPrompt,
|
||||
model,
|
||||
cwd: projectPath,
|
||||
readOnly: true, // Issue validation only reads code, doesn't write
|
||||
})) {
|
||||
if (msg.type === 'assistant' && msg.message?.content) {
|
||||
for (const block of msg.message.content) {
|
||||
|
||||
@@ -202,6 +202,7 @@ ${JSON.stringify(suggestionsSchema, null, 2)}`;
|
||||
maxTurns: 250,
|
||||
allowedTools: ['Read', 'Glob', 'Grep'],
|
||||
abortController,
|
||||
readOnly: true, // Suggestions only reads code, doesn't write
|
||||
})) {
|
||||
if (msg.type === 'assistant' && msg.message?.content) {
|
||||
for (const block of msg.message.content) {
|
||||
|
||||
Reference in New Issue
Block a user