mirror of
https://github.com/jparkerweb/plan2code.git
synced 2026-09-18 00:32:23 -07:00
Pin LF line endings and renormalize the working tree
scripts/validate-char-count.js measures characters on disk, so a CRLF checkout added ~1 char per line and pushed the 11k-budget prompt files over the limit depending on how the repo was cloned. Pins eol=lf, marks binaries, and renormalizes the files that had CRLF. AI Assisted
This commit is contained in:
@@ -1,82 +1,82 @@
|
||||
import type { Agent, AgentConfig, AgentExecutionOptions, AgentExecutionResult } from './types.js';
|
||||
import { executeCommand } from '../utils/process.js';
|
||||
import { writeFileSync, unlinkSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { tmpdir } from 'os';
|
||||
|
||||
const claudeCodeConfig: AgentConfig = {
|
||||
name: 'claude-code',
|
||||
displayName: 'Claude Code',
|
||||
command: 'claude',
|
||||
models: [
|
||||
{ value: 'default', label: 'Default (use Claude config)' },
|
||||
],
|
||||
defaultModel: 'default',
|
||||
flags: {
|
||||
prompt: '--print',
|
||||
model: '--model',
|
||||
skipPermissions: '--dangerously-skip-permissions',
|
||||
},
|
||||
};
|
||||
|
||||
class ClaudeCodeAgent implements Agent {
|
||||
readonly config = claudeCodeConfig;
|
||||
|
||||
async execute(options: AgentExecutionOptions): Promise<AgentExecutionResult> {
|
||||
// Write prompt to temp file - more reliable than stdin on Windows
|
||||
const tempFile = join(tmpdir(), `plan2code-prompt-${Date.now()}.txt`);
|
||||
writeFileSync(tempFile, options.prompt, 'utf-8');
|
||||
|
||||
try {
|
||||
// Build args: flags first, then read prompt from temp file via shell
|
||||
const args: string[] = [
|
||||
this.config.flags.prompt, // --print for non-interactive mode
|
||||
this.config.flags.skipPermissions,
|
||||
];
|
||||
|
||||
// Only add --model if not using default
|
||||
if (options.model && options.model !== 'default') {
|
||||
args.push(this.config.flags.model, options.model);
|
||||
}
|
||||
|
||||
// Use stdin from the temp file
|
||||
const result = await executeCommand({
|
||||
command: this.config.command,
|
||||
args,
|
||||
cwd: options.cwd,
|
||||
timeout: options.timeout,
|
||||
signal: options.signal,
|
||||
stdinFile: tempFile,
|
||||
});
|
||||
|
||||
return {
|
||||
stdout: result.stdout,
|
||||
stderr: result.stderr,
|
||||
exitCode: result.exitCode,
|
||||
timedOut: result.timedOut,
|
||||
cancelled: result.cancelled,
|
||||
duration: result.duration,
|
||||
};
|
||||
} finally {
|
||||
// Clean up temp file
|
||||
try {
|
||||
unlinkSync(tempFile);
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async isAvailable(): Promise<boolean> {
|
||||
// Run claude --version to verify it's actually installed and working
|
||||
const result = await executeCommand({
|
||||
command: this.config.command,
|
||||
args: ['--version'],
|
||||
cwd: process.cwd(),
|
||||
timeout: 5000,
|
||||
});
|
||||
return result.exitCode === 0;
|
||||
}
|
||||
}
|
||||
|
||||
export const claudeCodeAgent = new ClaudeCodeAgent();
|
||||
import type { Agent, AgentConfig, AgentExecutionOptions, AgentExecutionResult } from './types.js';
|
||||
import { executeCommand } from '../utils/process.js';
|
||||
import { writeFileSync, unlinkSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { tmpdir } from 'os';
|
||||
|
||||
const claudeCodeConfig: AgentConfig = {
|
||||
name: 'claude-code',
|
||||
displayName: 'Claude Code',
|
||||
command: 'claude',
|
||||
models: [
|
||||
{ value: 'default', label: 'Default (use Claude config)' },
|
||||
],
|
||||
defaultModel: 'default',
|
||||
flags: {
|
||||
prompt: '--print',
|
||||
model: '--model',
|
||||
skipPermissions: '--dangerously-skip-permissions',
|
||||
},
|
||||
};
|
||||
|
||||
class ClaudeCodeAgent implements Agent {
|
||||
readonly config = claudeCodeConfig;
|
||||
|
||||
async execute(options: AgentExecutionOptions): Promise<AgentExecutionResult> {
|
||||
// Write prompt to temp file - more reliable than stdin on Windows
|
||||
const tempFile = join(tmpdir(), `plan2code-prompt-${Date.now()}.txt`);
|
||||
writeFileSync(tempFile, options.prompt, 'utf-8');
|
||||
|
||||
try {
|
||||
// Build args: flags first, then read prompt from temp file via shell
|
||||
const args: string[] = [
|
||||
this.config.flags.prompt, // --print for non-interactive mode
|
||||
this.config.flags.skipPermissions,
|
||||
];
|
||||
|
||||
// Only add --model if not using default
|
||||
if (options.model && options.model !== 'default') {
|
||||
args.push(this.config.flags.model, options.model);
|
||||
}
|
||||
|
||||
// Use stdin from the temp file
|
||||
const result = await executeCommand({
|
||||
command: this.config.command,
|
||||
args,
|
||||
cwd: options.cwd,
|
||||
timeout: options.timeout,
|
||||
signal: options.signal,
|
||||
stdinFile: tempFile,
|
||||
});
|
||||
|
||||
return {
|
||||
stdout: result.stdout,
|
||||
stderr: result.stderr,
|
||||
exitCode: result.exitCode,
|
||||
timedOut: result.timedOut,
|
||||
cancelled: result.cancelled,
|
||||
duration: result.duration,
|
||||
};
|
||||
} finally {
|
||||
// Clean up temp file
|
||||
try {
|
||||
unlinkSync(tempFile);
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async isAvailable(): Promise<boolean> {
|
||||
// Run claude --version to verify it's actually installed and working
|
||||
const result = await executeCommand({
|
||||
command: this.config.command,
|
||||
args: ['--version'],
|
||||
cwd: process.cwd(),
|
||||
timeout: 5000,
|
||||
});
|
||||
return result.exitCode === 0;
|
||||
}
|
||||
}
|
||||
|
||||
export const claudeCodeAgent = new ClaudeCodeAgent();
|
||||
|
||||
@@ -1,70 +1,70 @@
|
||||
import type { Agent, AgentConfig, AgentExecutionOptions, AgentExecutionResult } from './types.js';
|
||||
import { executeCommand } from '../utils/process.js';
|
||||
|
||||
const copilotCliConfig: AgentConfig = {
|
||||
name: 'copilot-cli',
|
||||
displayName: 'GitHub Copilot CLI',
|
||||
command: 'copilot',
|
||||
models: [
|
||||
{ value: 'claude-sonnet-4', label: 'Claude Sonnet 4 (Default)' },
|
||||
{ value: 'claude-sonnet-4.5', label: 'Claude Sonnet 4.5' },
|
||||
{ value: 'claude-opus-4.5', label: 'Claude Opus 4.5' },
|
||||
{ value: 'gpt-5', label: 'GPT-5' },
|
||||
{ value: 'gpt-5-mini', label: 'GPT-5 Mini' },
|
||||
{ value: 'gemini-3-pro-preview', label: 'Gemini 3 Pro' },
|
||||
],
|
||||
defaultModel: 'claude-sonnet-4',
|
||||
flags: {
|
||||
prompt: '-p',
|
||||
model: '--model',
|
||||
skipPermissions: '--allow-all-tools',
|
||||
silent: '-s',
|
||||
},
|
||||
};
|
||||
|
||||
class CopilotCliAgent implements Agent {
|
||||
readonly config = copilotCliConfig;
|
||||
|
||||
async execute(options: AgentExecutionOptions): Promise<AgentExecutionResult> {
|
||||
// Use stdin for prompt to handle multi-line text properly
|
||||
const args: string[] = [];
|
||||
|
||||
// Only add --model if not using default
|
||||
if (options.model && options.model !== 'default') {
|
||||
args.push(this.config.flags.model, options.model);
|
||||
}
|
||||
|
||||
args.push(this.config.flags.skipPermissions, this.config.flags.silent!);
|
||||
|
||||
const result = await executeCommand({
|
||||
command: this.config.command,
|
||||
args,
|
||||
cwd: options.cwd,
|
||||
timeout: options.timeout,
|
||||
signal: options.signal,
|
||||
stdin: options.prompt,
|
||||
});
|
||||
|
||||
return {
|
||||
stdout: result.stdout,
|
||||
stderr: result.stderr,
|
||||
exitCode: result.exitCode,
|
||||
timedOut: result.timedOut,
|
||||
cancelled: result.cancelled,
|
||||
duration: result.duration,
|
||||
};
|
||||
}
|
||||
|
||||
async isAvailable(): Promise<boolean> {
|
||||
// Run copilot --version to verify it's installed
|
||||
const result = await executeCommand({
|
||||
command: this.config.command,
|
||||
args: ['--version'],
|
||||
cwd: process.cwd(),
|
||||
timeout: 5000,
|
||||
});
|
||||
return result.exitCode === 0;
|
||||
}
|
||||
}
|
||||
|
||||
export const copilotCliAgent = new CopilotCliAgent();
|
||||
import type { Agent, AgentConfig, AgentExecutionOptions, AgentExecutionResult } from './types.js';
|
||||
import { executeCommand } from '../utils/process.js';
|
||||
|
||||
const copilotCliConfig: AgentConfig = {
|
||||
name: 'copilot-cli',
|
||||
displayName: 'GitHub Copilot CLI',
|
||||
command: 'copilot',
|
||||
models: [
|
||||
{ value: 'claude-sonnet-4', label: 'Claude Sonnet 4 (Default)' },
|
||||
{ value: 'claude-sonnet-4.5', label: 'Claude Sonnet 4.5' },
|
||||
{ value: 'claude-opus-4.5', label: 'Claude Opus 4.5' },
|
||||
{ value: 'gpt-5', label: 'GPT-5' },
|
||||
{ value: 'gpt-5-mini', label: 'GPT-5 Mini' },
|
||||
{ value: 'gemini-3-pro-preview', label: 'Gemini 3 Pro' },
|
||||
],
|
||||
defaultModel: 'claude-sonnet-4',
|
||||
flags: {
|
||||
prompt: '-p',
|
||||
model: '--model',
|
||||
skipPermissions: '--allow-all-tools',
|
||||
silent: '-s',
|
||||
},
|
||||
};
|
||||
|
||||
class CopilotCliAgent implements Agent {
|
||||
readonly config = copilotCliConfig;
|
||||
|
||||
async execute(options: AgentExecutionOptions): Promise<AgentExecutionResult> {
|
||||
// Use stdin for prompt to handle multi-line text properly
|
||||
const args: string[] = [];
|
||||
|
||||
// Only add --model if not using default
|
||||
if (options.model && options.model !== 'default') {
|
||||
args.push(this.config.flags.model, options.model);
|
||||
}
|
||||
|
||||
args.push(this.config.flags.skipPermissions, this.config.flags.silent!);
|
||||
|
||||
const result = await executeCommand({
|
||||
command: this.config.command,
|
||||
args,
|
||||
cwd: options.cwd,
|
||||
timeout: options.timeout,
|
||||
signal: options.signal,
|
||||
stdin: options.prompt,
|
||||
});
|
||||
|
||||
return {
|
||||
stdout: result.stdout,
|
||||
stderr: result.stderr,
|
||||
exitCode: result.exitCode,
|
||||
timedOut: result.timedOut,
|
||||
cancelled: result.cancelled,
|
||||
duration: result.duration,
|
||||
};
|
||||
}
|
||||
|
||||
async isAvailable(): Promise<boolean> {
|
||||
// Run copilot --version to verify it's installed
|
||||
const result = await executeCommand({
|
||||
command: this.config.command,
|
||||
args: ['--version'],
|
||||
cwd: process.cwd(),
|
||||
timeout: 5000,
|
||||
});
|
||||
return result.exitCode === 0;
|
||||
}
|
||||
}
|
||||
|
||||
export const copilotCliAgent = new CopilotCliAgent();
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import type { Agent } from './types.js';
|
||||
|
||||
class AgentRegistry {
|
||||
private agents: Map<string, Agent> = new Map();
|
||||
|
||||
register(agent: Agent): void {
|
||||
this.agents.set(agent.config.name, agent);
|
||||
}
|
||||
|
||||
get(name: string): Agent | undefined {
|
||||
return this.agents.get(name);
|
||||
}
|
||||
|
||||
getAll(): Agent[] {
|
||||
return Array.from(this.agents.values());
|
||||
}
|
||||
|
||||
getAvailable(): Promise<Agent[]> {
|
||||
return Promise.all(
|
||||
this.getAll().map(async (agent) => ({
|
||||
agent,
|
||||
available: await agent.isAvailable(),
|
||||
}))
|
||||
).then((results) =>
|
||||
results.filter((r) => r.available).map((r) => r.agent)
|
||||
);
|
||||
}
|
||||
|
||||
getNames(): string[] {
|
||||
return Array.from(this.agents.keys());
|
||||
}
|
||||
}
|
||||
|
||||
export const agentRegistry = new AgentRegistry();
|
||||
import type { Agent } from './types.js';
|
||||
|
||||
class AgentRegistry {
|
||||
private agents: Map<string, Agent> = new Map();
|
||||
|
||||
register(agent: Agent): void {
|
||||
this.agents.set(agent.config.name, agent);
|
||||
}
|
||||
|
||||
get(name: string): Agent | undefined {
|
||||
return this.agents.get(name);
|
||||
}
|
||||
|
||||
getAll(): Agent[] {
|
||||
return Array.from(this.agents.values());
|
||||
}
|
||||
|
||||
getAvailable(): Promise<Agent[]> {
|
||||
return Promise.all(
|
||||
this.getAll().map(async (agent) => ({
|
||||
agent,
|
||||
available: await agent.isAvailable(),
|
||||
}))
|
||||
).then((results) =>
|
||||
results.filter((r) => r.available).map((r) => r.agent)
|
||||
);
|
||||
}
|
||||
|
||||
getNames(): string[] {
|
||||
return Array.from(this.agents.keys());
|
||||
}
|
||||
}
|
||||
|
||||
export const agentRegistry = new AgentRegistry();
|
||||
|
||||
Reference in New Issue
Block a user