mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-02 20:43:36 +00:00
refactor: consolidate shared packages and eliminate code duplication
- Update 26+ files to import secureFs from @automaker/platform - Create shared type files: github.ts, worktree.ts, claude.ts in libs/types - Create exec-utils.ts for cross-platform shell execution - Delete redundant wrapper files: secure-fs.ts, stream-processor.ts, enhancement-prompts.ts - Update GitHub routes to use createLogError pattern - Add isENOENT helper to routes/common.ts - Fix test imports to use @automaker/prompts and @automaker/platform 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Enhancement Prompts - Re-exported from @automaker/prompts
|
||||
*
|
||||
* This file now re-exports enhancement prompts from the shared @automaker/prompts package
|
||||
* to maintain backward compatibility with existing imports in the server codebase.
|
||||
*/
|
||||
|
||||
export {
|
||||
IMPROVE_SYSTEM_PROMPT,
|
||||
TECHNICAL_SYSTEM_PROMPT,
|
||||
SIMPLIFY_SYSTEM_PROMPT,
|
||||
ACCEPTANCE_SYSTEM_PROMPT,
|
||||
IMPROVE_EXAMPLES,
|
||||
TECHNICAL_EXAMPLES,
|
||||
SIMPLIFY_EXAMPLES,
|
||||
ACCEPTANCE_EXAMPLES,
|
||||
getEnhancementPrompt,
|
||||
getSystemPrompt,
|
||||
getExamples,
|
||||
buildUserPrompt,
|
||||
isValidEnhancementMode,
|
||||
getAvailableEnhancementModes,
|
||||
} from '@automaker/prompts';
|
||||
|
||||
export type { EnhancementMode, EnhancementExample } from '@automaker/prompts';
|
||||
69
apps/server/src/lib/exec-utils.ts
Normal file
69
apps/server/src/lib/exec-utils.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Shell execution utilities
|
||||
*
|
||||
* Provides cross-platform shell execution with extended PATH
|
||||
* to find tools like git and gh in Electron environments.
|
||||
*/
|
||||
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
|
||||
/**
|
||||
* Promisified exec for async/await usage
|
||||
*/
|
||||
export const execAsync = promisify(exec);
|
||||
|
||||
/**
|
||||
* Path separator for the current platform
|
||||
*/
|
||||
const pathSeparator = process.platform === 'win32' ? ';' : ':';
|
||||
|
||||
/**
|
||||
* Additional paths to search for executables.
|
||||
* Electron apps don't inherit the user's shell PATH, so we need to add
|
||||
* common tool installation locations.
|
||||
*/
|
||||
const additionalPaths: string[] = [];
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
// Windows paths for Git and other tools
|
||||
if (process.env.LOCALAPPDATA) {
|
||||
additionalPaths.push(`${process.env.LOCALAPPDATA}\\Programs\\Git\\cmd`);
|
||||
}
|
||||
if (process.env.PROGRAMFILES) {
|
||||
additionalPaths.push(`${process.env.PROGRAMFILES}\\Git\\cmd`);
|
||||
}
|
||||
if (process.env['ProgramFiles(x86)']) {
|
||||
additionalPaths.push(`${process.env['ProgramFiles(x86)']}\\Git\\cmd`);
|
||||
}
|
||||
} else {
|
||||
// Unix/Mac paths
|
||||
additionalPaths.push(
|
||||
'/opt/homebrew/bin', // Homebrew on Apple Silicon
|
||||
'/usr/local/bin', // Homebrew on Intel Mac, common Linux location
|
||||
'/home/linuxbrew/.linuxbrew/bin', // Linuxbrew
|
||||
`${process.env.HOME}/.local/bin` // pipx, other user installs
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extended PATH that includes common tool installation locations.
|
||||
*/
|
||||
export const extendedPath = [process.env.PATH, ...additionalPaths.filter(Boolean)]
|
||||
.filter(Boolean)
|
||||
.join(pathSeparator);
|
||||
|
||||
/**
|
||||
* Environment variables with extended PATH for executing shell commands.
|
||||
*/
|
||||
export const execEnv = {
|
||||
...process.env,
|
||||
PATH: extendedPath,
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if an error is ENOENT (file/path not found or spawn failed)
|
||||
*/
|
||||
export function isENOENT(error: unknown): boolean {
|
||||
return error !== null && typeof error === 'object' && 'code' in error && error.code === 'ENOENT';
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Re-export secure file system utilities from @automaker/platform
|
||||
* This file exists for backward compatibility with existing imports
|
||||
*/
|
||||
|
||||
import { secureFs } from '@automaker/platform';
|
||||
|
||||
export const {
|
||||
access,
|
||||
readFile,
|
||||
writeFile,
|
||||
mkdir,
|
||||
readdir,
|
||||
stat,
|
||||
rm,
|
||||
unlink,
|
||||
copyFile,
|
||||
appendFile,
|
||||
rename,
|
||||
lstat,
|
||||
joinPath,
|
||||
resolvePath,
|
||||
} = secureFs;
|
||||
@@ -1,190 +0,0 @@
|
||||
/**
|
||||
* Stream Processor - Unified stream handling for provider messages
|
||||
*
|
||||
* Eliminates duplication of the stream processing pattern that was
|
||||
* repeated 4x in auto-mode-service.ts (main execution, revision,
|
||||
* task execution, continuation).
|
||||
*/
|
||||
|
||||
import type { ProviderMessage, ContentBlock } from '@automaker/types';
|
||||
|
||||
/**
|
||||
* Callbacks for handling different stream events
|
||||
*/
|
||||
export interface StreamHandlers {
|
||||
/** Called for each text block in the stream */
|
||||
onText?: (text: string) => void | Promise<void>;
|
||||
/** Called for each tool use in the stream */
|
||||
onToolUse?: (name: string, input: unknown) => void | Promise<void>;
|
||||
/** Called when an error occurs in the stream */
|
||||
onError?: (error: string) => void | Promise<void>;
|
||||
/** Called when the stream completes successfully */
|
||||
onComplete?: (result: string) => void | Promise<void>;
|
||||
/** Called for thinking blocks (if present) */
|
||||
onThinking?: (thinking: string) => void | Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Result from processing a stream
|
||||
*/
|
||||
export interface StreamResult {
|
||||
/** All accumulated text from the stream */
|
||||
text: string;
|
||||
/** Whether the stream completed successfully */
|
||||
success: boolean;
|
||||
/** Error message if stream failed */
|
||||
error?: string;
|
||||
/** Final result message if stream completed */
|
||||
result?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a provider message stream with unified handling
|
||||
*
|
||||
* This eliminates the repeated pattern of:
|
||||
* ```
|
||||
* for await (const msg of stream) {
|
||||
* if (msg.type === 'assistant' && msg.message?.content) {
|
||||
* for (const block of msg.message.content) {
|
||||
* if (block.type === 'text') { ... }
|
||||
* else if (block.type === 'tool_use') { ... }
|
||||
* }
|
||||
* } else if (msg.type === 'error') { ... }
|
||||
* else if (msg.type === 'result') { ... }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param stream - The async generator from provider.executeQuery()
|
||||
* @param handlers - Callbacks for different event types
|
||||
* @returns Accumulated result with text and status
|
||||
*/
|
||||
export async function processStream(
|
||||
stream: AsyncGenerator<ProviderMessage>,
|
||||
handlers: StreamHandlers
|
||||
): Promise<StreamResult> {
|
||||
let accumulatedText = '';
|
||||
let success = true;
|
||||
let errorMessage: string | undefined;
|
||||
let resultMessage: string | undefined;
|
||||
|
||||
try {
|
||||
for await (const msg of stream) {
|
||||
if (msg.type === 'assistant' && msg.message?.content) {
|
||||
for (const block of msg.message.content) {
|
||||
await processContentBlock(block, handlers, (text) => {
|
||||
accumulatedText += text;
|
||||
});
|
||||
}
|
||||
} else if (msg.type === 'error') {
|
||||
success = false;
|
||||
errorMessage = msg.error || 'Unknown error';
|
||||
if (handlers.onError) {
|
||||
await handlers.onError(errorMessage);
|
||||
}
|
||||
throw new Error(errorMessage);
|
||||
} else if (msg.type === 'result' && msg.subtype === 'success') {
|
||||
resultMessage = msg.result || '';
|
||||
if (handlers.onComplete) {
|
||||
await handlers.onComplete(resultMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (!errorMessage) {
|
||||
success = false;
|
||||
errorMessage = error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
return {
|
||||
text: accumulatedText,
|
||||
success,
|
||||
error: errorMessage,
|
||||
result: resultMessage,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a single content block
|
||||
*/
|
||||
async function processContentBlock(
|
||||
block: ContentBlock,
|
||||
handlers: StreamHandlers,
|
||||
appendText: (text: string) => void
|
||||
): Promise<void> {
|
||||
switch (block.type) {
|
||||
case 'text':
|
||||
if (block.text) {
|
||||
appendText(block.text);
|
||||
if (handlers.onText) {
|
||||
await handlers.onText(block.text);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'tool_use':
|
||||
if (block.name && handlers.onToolUse) {
|
||||
await handlers.onToolUse(block.name, block.input);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'thinking':
|
||||
if (block.thinking && handlers.onThinking) {
|
||||
await handlers.onThinking(block.thinking);
|
||||
}
|
||||
break;
|
||||
|
||||
// tool_result blocks are handled internally by the SDK
|
||||
case 'tool_result':
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a simple stream processor that just collects text
|
||||
*
|
||||
* Useful for cases where you just need the final text output
|
||||
* without any side effects during streaming.
|
||||
*/
|
||||
export async function collectStreamText(stream: AsyncGenerator<ProviderMessage>): Promise<string> {
|
||||
const result = await processStream(stream, {});
|
||||
return result.text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process stream with progress callback
|
||||
*
|
||||
* Simplified interface for the common case of just wanting
|
||||
* text updates during streaming.
|
||||
*/
|
||||
export async function processStreamWithProgress(
|
||||
stream: AsyncGenerator<ProviderMessage>,
|
||||
onProgress: (text: string) => void
|
||||
): Promise<StreamResult> {
|
||||
return processStream(stream, {
|
||||
onText: onProgress,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a stream result contains a specific marker
|
||||
*
|
||||
* Useful for detecting spec generation markers like [SPEC_GENERATED]
|
||||
*/
|
||||
export function hasMarker(result: StreamResult, marker: string): boolean {
|
||||
return result.text.includes(marker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract content before a marker
|
||||
*
|
||||
* Useful for extracting spec content before [SPEC_GENERATED] marker
|
||||
*/
|
||||
export function extractBeforeMarker(text: string, marker: string): string | null {
|
||||
const index = text.indexOf(marker);
|
||||
if (index === -1) {
|
||||
return null;
|
||||
}
|
||||
return text.substring(0, index).trim();
|
||||
}
|
||||
@@ -3,26 +3,16 @@
|
||||
* Stores worktree-specific data in .automaker/worktrees/:branch/worktree.json
|
||||
*/
|
||||
|
||||
import * as secureFs from './secure-fs.js';
|
||||
import { secureFs } from '@automaker/platform';
|
||||
import * as path from 'path';
|
||||
import type { WorktreePRInfo, WorktreeMetadata } from '@automaker/types';
|
||||
|
||||
// Re-export types for convenience
|
||||
export type { WorktreePRInfo, WorktreeMetadata } from '@automaker/types';
|
||||
|
||||
/** Maximum length for sanitized branch names in filesystem paths */
|
||||
const MAX_SANITIZED_BRANCH_PATH_LENGTH = 200;
|
||||
|
||||
export interface WorktreePRInfo {
|
||||
number: number;
|
||||
url: string;
|
||||
title: string;
|
||||
state: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface WorktreeMetadata {
|
||||
branch: string;
|
||||
createdAt: string;
|
||||
pr?: WorktreePRInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize branch name for cross-platform filesystem safety
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@ import type {
|
||||
SimpleQueryResult,
|
||||
StreamingQueryOptions,
|
||||
StreamingQueryResult,
|
||||
PromptContentBlock,
|
||||
} from './types.js';
|
||||
|
||||
export class ClaudeProvider extends BaseProvider {
|
||||
@@ -335,7 +336,7 @@ export class ClaudeProvider extends BaseProvider {
|
||||
/**
|
||||
* Create a multi-part prompt generator for content blocks
|
||||
*/
|
||||
private createPromptGenerator(content: Array<{ type: string; text?: string; source?: object }>) {
|
||||
private createPromptGenerator(content: PromptContentBlock[]) {
|
||||
// Return an async generator that yields SDK user messages
|
||||
// The SDK expects this format for multi-part prompts
|
||||
return (async function* () {
|
||||
|
||||
@@ -4,12 +4,11 @@
|
||||
* Uses ClaudeProvider.executeStreamingQuery() for SDK interaction.
|
||||
*/
|
||||
|
||||
import * as secureFs from '../../lib/secure-fs.js';
|
||||
import type { EventEmitter } from '../../lib/events.js';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { ProviderFactory } from '../../providers/provider-factory.js';
|
||||
import { parseAndCreateFeatures } from './parse-and-create-features.js';
|
||||
import { getAppSpecPath } from '@automaker/platform';
|
||||
import { getAppSpecPath, secureFs } from '@automaker/platform';
|
||||
|
||||
const logger = createLogger('SpecRegeneration');
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
* Uses ClaudeProvider.executeStreamingQuery() for SDK interaction.
|
||||
*/
|
||||
|
||||
import * as secureFs from '../../lib/secure-fs.js';
|
||||
import type { EventEmitter } from '../../lib/events.js';
|
||||
import {
|
||||
specOutputSchema,
|
||||
@@ -15,7 +14,7 @@ import {
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { ProviderFactory } from '../../providers/provider-factory.js';
|
||||
import { generateFeaturesFromSpec } from './generate-features-from-spec.js';
|
||||
import { ensureAutomakerDir, getAppSpecPath } from '@automaker/platform';
|
||||
import { ensureAutomakerDir, getAppSpecPath, secureFs } from '@automaker/platform';
|
||||
|
||||
const logger = createLogger('SpecRegeneration');
|
||||
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
import * as secureFs from '../../lib/secure-fs.js';
|
||||
import type { EventEmitter } from '../../lib/events.js';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { getFeaturesDir } from '@automaker/platform';
|
||||
import { getFeaturesDir, secureFs } from '@automaker/platform';
|
||||
|
||||
const logger = createLogger('SpecRegeneration');
|
||||
|
||||
|
||||
@@ -1,35 +1,6 @@
|
||||
/**
|
||||
* Claude Usage types for CLI-based usage tracking
|
||||
* Re-exported from @automaker/types for convenience
|
||||
*/
|
||||
|
||||
export type ClaudeUsage = {
|
||||
sessionTokensUsed: number;
|
||||
sessionLimit: number;
|
||||
sessionPercentage: number;
|
||||
sessionResetTime: string; // ISO date string
|
||||
sessionResetText: string; // Raw text like "Resets 10:59am (Asia/Dubai)"
|
||||
|
||||
weeklyTokensUsed: number;
|
||||
weeklyLimit: number;
|
||||
weeklyPercentage: number;
|
||||
weeklyResetTime: string; // ISO date string
|
||||
weeklyResetText: string; // Raw text like "Resets Dec 22 at 7:59pm (Asia/Dubai)"
|
||||
|
||||
sonnetWeeklyTokensUsed: number;
|
||||
sonnetWeeklyPercentage: number;
|
||||
sonnetResetText: string; // Raw text like "Resets Dec 27 at 9:59am (Asia/Dubai)"
|
||||
|
||||
costUsed: number | null;
|
||||
costLimit: number | null;
|
||||
costCurrency: string | null;
|
||||
|
||||
lastUpdated: string; // ISO date string
|
||||
userTimezone: string;
|
||||
};
|
||||
|
||||
export type ClaudeStatus = {
|
||||
indicator: {
|
||||
color: 'green' | 'yellow' | 'orange' | 'red' | 'gray';
|
||||
};
|
||||
description: string;
|
||||
};
|
||||
export type { ClaudeUsage, ClaudeStatus } from '@automaker/types';
|
||||
|
||||
@@ -18,14 +18,13 @@ export {
|
||||
getGitRepositoryDiffs,
|
||||
} from '@automaker/git-utils';
|
||||
|
||||
type Logger = ReturnType<typeof createLogger>;
|
||||
// Re-export error utilities from shared package
|
||||
export { getErrorMessage } from '@automaker/utils';
|
||||
|
||||
/**
|
||||
* Get error message from error object
|
||||
*/
|
||||
export function getErrorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : 'Unknown error';
|
||||
}
|
||||
// Re-export exec utilities
|
||||
export { execAsync, execEnv, isENOENT } from '../lib/exec-utils.js';
|
||||
|
||||
type Logger = ReturnType<typeof createLogger>;
|
||||
|
||||
/**
|
||||
* Create a logError function for a specific logger
|
||||
|
||||
@@ -11,9 +11,8 @@
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { PathNotAllowedError } from '@automaker/platform';
|
||||
import { PathNotAllowedError, secureFs } from '@automaker/platform';
|
||||
import { ProviderFactory } from '../../../providers/provider-factory.js';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import * as path from 'path';
|
||||
|
||||
const logger = createLogger('DescribeFile');
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
buildUserPrompt,
|
||||
isValidEnhancementMode,
|
||||
type EnhancementMode,
|
||||
} from '../../../lib/enhancement-prompts.js';
|
||||
} from '@automaker/prompts';
|
||||
|
||||
const logger = createLogger('EnhancePrompt');
|
||||
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs, getAllowedRootDirectory, PathNotAllowedError } from '@automaker/platform';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import { getAllowedRootDirectory, PathNotAllowedError } from '@automaker/platform';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createBrowseHandler() {
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs, getBoardDir } from '@automaker/platform';
|
||||
import path from 'path';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
import { getBoardDir } from '@automaker/platform';
|
||||
|
||||
export function createDeleteBoardBackgroundHandler() {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { PathNotAllowedError } from '@automaker/platform';
|
||||
import { secureFs, PathNotAllowedError } from '@automaker/platform';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createDeleteHandler() {
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { PathNotAllowedError } from '@automaker/platform';
|
||||
import { secureFs, PathNotAllowedError } from '@automaker/platform';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createExistsHandler() {
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs, PathNotAllowedError } from '@automaker/platform';
|
||||
import path from 'path';
|
||||
import { PathNotAllowedError } from '@automaker/platform';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createImageHandler() {
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs, PathNotAllowedError } from '@automaker/platform';
|
||||
import path from 'path';
|
||||
import { PathNotAllowedError } from '@automaker/platform';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createMkdirHandler() {
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { PathNotAllowedError } from '@automaker/platform';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
import { secureFs, PathNotAllowedError } from '@automaker/platform';
|
||||
import { getErrorMessage, logError, isENOENT } from '../common.js';
|
||||
|
||||
// Optional files that are expected to not exist in new projects
|
||||
// Don't log ENOENT errors for these to reduce noise
|
||||
@@ -15,10 +14,6 @@ function isOptionalFile(filePath: string): boolean {
|
||||
return OPTIONAL_FILES.some((optionalFile) => filePath.endsWith(optionalFile));
|
||||
}
|
||||
|
||||
function isENOENT(error: unknown): boolean {
|
||||
return error !== null && typeof error === 'object' && 'code' in error && error.code === 'ENOENT';
|
||||
}
|
||||
|
||||
export function createReadHandler() {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { PathNotAllowedError } from '@automaker/platform';
|
||||
import { secureFs, PathNotAllowedError } from '@automaker/platform';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createReaddirHandler() {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs } from '@automaker/platform';
|
||||
import path from 'path';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs, getBoardDir } from '@automaker/platform';
|
||||
import path from 'path';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
import { getBoardDir } from '@automaker/platform';
|
||||
|
||||
export function createSaveBoardBackgroundHandler() {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs, getImagesDir } from '@automaker/platform';
|
||||
import path from 'path';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
import { getImagesDir } from '@automaker/platform';
|
||||
|
||||
export function createSaveImageHandler() {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { PathNotAllowedError } from '@automaker/platform';
|
||||
import { secureFs, PathNotAllowedError } from '@automaker/platform';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createStatHandler() {
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs, isPathAllowed } from '@automaker/platform';
|
||||
import path from 'path';
|
||||
import { isPathAllowed } from '@automaker/platform';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createValidatePathHandler() {
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs, PathNotAllowedError } from '@automaker/platform';
|
||||
import path from 'path';
|
||||
import { PathNotAllowedError } from '@automaker/platform';
|
||||
import { mkdirSafe } from '@automaker/utils';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
|
||||
@@ -3,14 +3,11 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { GitHubRemoteStatus } from '@automaker/types';
|
||||
import { execAsync, execEnv, getErrorMessage, logError } from './common.js';
|
||||
|
||||
export interface GitHubRemoteStatus {
|
||||
hasGitHubRemote: boolean;
|
||||
remoteUrl: string | null;
|
||||
owner: string | null;
|
||||
repo: string | null;
|
||||
}
|
||||
// Re-export type for convenience
|
||||
export type { GitHubRemoteStatus } from '@automaker/types';
|
||||
|
||||
export async function checkGitHubRemote(projectPath: string): Promise<GitHubRemoteStatus> {
|
||||
const status: GitHubRemoteStatus = {
|
||||
|
||||
@@ -2,34 +2,16 @@
|
||||
* Common utilities for GitHub routes
|
||||
*/
|
||||
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { createLogError, getErrorMessage } from '../../common.js';
|
||||
import { execAsync, execEnv } from '../../../lib/exec-utils.js';
|
||||
|
||||
export const execAsync = promisify(exec);
|
||||
const logger = createLogger('GitHub');
|
||||
|
||||
// Extended PATH to include common tool installation locations
|
||||
export const extendedPath = [
|
||||
process.env.PATH,
|
||||
'/opt/homebrew/bin',
|
||||
'/usr/local/bin',
|
||||
'/home/linuxbrew/.linuxbrew/bin',
|
||||
`${process.env.HOME}/.local/bin`,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(':');
|
||||
// Re-export exec utilities for convenience
|
||||
export { execAsync, execEnv } from '../../../lib/exec-utils.js';
|
||||
|
||||
export const execEnv = {
|
||||
...process.env,
|
||||
PATH: extendedPath,
|
||||
};
|
||||
// Re-export error utilities
|
||||
export { getErrorMessage } from '../../common.js';
|
||||
|
||||
export function getErrorMessage(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
return error.message;
|
||||
}
|
||||
return String(error);
|
||||
}
|
||||
|
||||
export function logError(error: unknown, context: string): void {
|
||||
console.error(`[GitHub] ${context}:`, error);
|
||||
}
|
||||
export const logError = createLogError(logger);
|
||||
|
||||
@@ -3,35 +3,12 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { GitHubIssue, ListIssuesResult } from '@automaker/types';
|
||||
import { execAsync, execEnv, getErrorMessage, logError } from './common.js';
|
||||
import { checkGitHubRemote } from './check-github-remote.js';
|
||||
|
||||
export interface GitHubLabel {
|
||||
name: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
export interface GitHubAuthor {
|
||||
login: string;
|
||||
}
|
||||
|
||||
export interface GitHubIssue {
|
||||
number: number;
|
||||
title: string;
|
||||
state: string;
|
||||
author: GitHubAuthor;
|
||||
createdAt: string;
|
||||
labels: GitHubLabel[];
|
||||
url: string;
|
||||
body: string;
|
||||
}
|
||||
|
||||
export interface ListIssuesResult {
|
||||
success: boolean;
|
||||
openIssues?: GitHubIssue[];
|
||||
closedIssues?: GitHubIssue[];
|
||||
error?: string;
|
||||
}
|
||||
// Re-export types for convenience
|
||||
export type { GitHubLabel, GitHubAuthor, GitHubIssue, ListIssuesResult } from '@automaker/types';
|
||||
|
||||
export function createListIssuesHandler() {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
|
||||
@@ -3,39 +3,12 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { GitHubPR, ListPRsResult } from '@automaker/types';
|
||||
import { execAsync, execEnv, getErrorMessage, logError } from './common.js';
|
||||
import { checkGitHubRemote } from './check-github-remote.js';
|
||||
|
||||
export interface GitHubLabel {
|
||||
name: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
export interface GitHubAuthor {
|
||||
login: string;
|
||||
}
|
||||
|
||||
export interface GitHubPR {
|
||||
number: number;
|
||||
title: string;
|
||||
state: string;
|
||||
author: GitHubAuthor;
|
||||
createdAt: string;
|
||||
labels: GitHubLabel[];
|
||||
url: string;
|
||||
isDraft: boolean;
|
||||
headRefName: string;
|
||||
reviewDecision: string | null;
|
||||
mergeable: string;
|
||||
body: string;
|
||||
}
|
||||
|
||||
export interface ListPRsResult {
|
||||
success: boolean;
|
||||
openPRs?: GitHubPR[];
|
||||
mergedPRs?: GitHubPR[];
|
||||
error?: string;
|
||||
}
|
||||
// Re-export types for convenience
|
||||
export type { GitHubLabel, GitHubAuthor, GitHubPR, ListPRsResult } from '@automaker/types';
|
||||
|
||||
export function createListPRsHandler() {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
import type { Request, Response } from 'express';
|
||||
import { spawn } from 'child_process';
|
||||
import path from 'path';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { PathNotAllowedError } from '@automaker/platform';
|
||||
import { secureFs, PathNotAllowedError } from '@automaker/platform';
|
||||
import { logger, getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createCloneHandler() {
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs, getAllowedRootDirectory, getDataDirectory } from '@automaker/platform';
|
||||
import path from 'path';
|
||||
import { getAllowedRootDirectory, getDataDirectory } from '@automaker/platform';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createConfigHandler() {
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs, getAllowedRootDirectory } from '@automaker/platform';
|
||||
import path from 'path';
|
||||
import { getAllowedRootDirectory } from '@automaker/platform';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createDirectoriesHandler() {
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
*/
|
||||
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import path from 'path';
|
||||
import { getErrorMessage as getErrorMessageShared, createLogError } from '../common.js';
|
||||
import { execAsync, execEnv, isENOENT } from '../../lib/exec-utils.js';
|
||||
import { FeatureLoader } from '../../services/feature-loader.js';
|
||||
|
||||
const logger = createLogger('Worktree');
|
||||
export const execAsync = promisify(exec);
|
||||
const featureLoader = new FeatureLoader();
|
||||
|
||||
// Re-export exec utilities for convenience
|
||||
export { execAsync, execEnv, isENOENT } from '../../lib/exec-utils.js';
|
||||
|
||||
// ============================================================================
|
||||
// Constants
|
||||
// ============================================================================
|
||||
@@ -20,48 +20,6 @@ const featureLoader = new FeatureLoader();
|
||||
/** Maximum allowed length for git branch names */
|
||||
export const MAX_BRANCH_NAME_LENGTH = 250;
|
||||
|
||||
// ============================================================================
|
||||
// Extended PATH configuration for Electron apps
|
||||
// ============================================================================
|
||||
|
||||
const pathSeparator = process.platform === 'win32' ? ';' : ':';
|
||||
const additionalPaths: string[] = [];
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
// Windows paths
|
||||
if (process.env.LOCALAPPDATA) {
|
||||
additionalPaths.push(`${process.env.LOCALAPPDATA}\\Programs\\Git\\cmd`);
|
||||
}
|
||||
if (process.env.PROGRAMFILES) {
|
||||
additionalPaths.push(`${process.env.PROGRAMFILES}\\Git\\cmd`);
|
||||
}
|
||||
if (process.env['ProgramFiles(x86)']) {
|
||||
additionalPaths.push(`${process.env['ProgramFiles(x86)']}\\Git\\cmd`);
|
||||
}
|
||||
} else {
|
||||
// Unix/Mac paths
|
||||
additionalPaths.push(
|
||||
'/opt/homebrew/bin', // Homebrew on Apple Silicon
|
||||
'/usr/local/bin', // Homebrew on Intel Mac, common Linux location
|
||||
'/home/linuxbrew/.linuxbrew/bin', // Linuxbrew
|
||||
`${process.env.HOME}/.local/bin` // pipx, other user installs
|
||||
);
|
||||
}
|
||||
|
||||
const extendedPath = [process.env.PATH, ...additionalPaths.filter(Boolean)]
|
||||
.filter(Boolean)
|
||||
.join(pathSeparator);
|
||||
|
||||
/**
|
||||
* Environment variables with extended PATH for executing shell commands.
|
||||
* Electron apps don't inherit the user's shell PATH, so we need to add
|
||||
* common tool installation locations.
|
||||
*/
|
||||
export const execEnv = {
|
||||
...process.env,
|
||||
PATH: extendedPath,
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Validation utilities
|
||||
// ============================================================================
|
||||
@@ -111,14 +69,6 @@ export async function isGitRepo(repoPath: string): Promise<boolean> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an error is ENOENT (file/path not found or spawn failed)
|
||||
* These are expected in test environments with mock paths
|
||||
*/
|
||||
export function isENOENT(error: unknown): boolean {
|
||||
return error !== null && typeof error === 'object' && 'code' in error && error.code === 'ENOENT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a path is a mock/test path that doesn't exist
|
||||
*/
|
||||
|
||||
@@ -5,15 +5,12 @@
|
||||
* can switch between branches even after worktrees are removed.
|
||||
*/
|
||||
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs, getBranchTrackingPath, ensureAutomakerDir } from '@automaker/platform';
|
||||
import type { TrackedBranch } from '@automaker/types';
|
||||
import path from 'path';
|
||||
import { getBranchTrackingPath, ensureAutomakerDir } from '@automaker/platform';
|
||||
|
||||
export interface TrackedBranch {
|
||||
name: string;
|
||||
createdAt: string;
|
||||
lastActivatedAt?: string;
|
||||
}
|
||||
// Re-export type for convenience
|
||||
export type { TrackedBranch } from '@automaker/types';
|
||||
|
||||
interface BranchTrackingData {
|
||||
branches: TrackedBranch[];
|
||||
|
||||
@@ -11,7 +11,7 @@ import type { Request, Response } from 'express';
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import path from 'path';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs } from '@automaker/platform';
|
||||
import {
|
||||
isGitRepo,
|
||||
getErrorMessage,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import path from 'path';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs } from '@automaker/platform';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
import { getGitRepositoryDiffs } from '../../common.js';
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { Request, Response } from 'express';
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import path from 'path';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs } from '@automaker/platform';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
import { generateSyntheticDiffForNewFile } from '../../common.js';
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { Request, Response } from 'express';
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import path from 'path';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs } from '@automaker/platform';
|
||||
import { getErrorMessage, logError, normalizePath } from '../common.js';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import type { Request, Response } from 'express';
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs } from '@automaker/platform';
|
||||
import { join } from 'path';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import type { Request, Response } from 'express';
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs } from '@automaker/platform';
|
||||
import { isGitRepo } from '@automaker/git-utils';
|
||||
import { getErrorMessage, logError, normalizePath } from '../common.js';
|
||||
import { readAllWorktreeMetadata, type WorktreePRInfo } from '../../../lib/worktree-metadata.js';
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { PRComment, PRInfo } from '@automaker/types';
|
||||
import {
|
||||
getErrorMessage,
|
||||
logError,
|
||||
@@ -12,26 +13,8 @@ import {
|
||||
isGhCliAvailable,
|
||||
} from '../common.js';
|
||||
|
||||
export interface PRComment {
|
||||
id: number;
|
||||
author: string;
|
||||
body: string;
|
||||
path?: string;
|
||||
line?: number;
|
||||
createdAt: string;
|
||||
isReviewComment: boolean;
|
||||
}
|
||||
|
||||
export interface PRInfo {
|
||||
number: number;
|
||||
title: string;
|
||||
url: string;
|
||||
state: string;
|
||||
author: string;
|
||||
body: string;
|
||||
comments: PRComment[];
|
||||
reviewComments: PRComment[];
|
||||
}
|
||||
// Re-export types for convenience
|
||||
export type { PRComment, PRInfo } from '@automaker/types';
|
||||
|
||||
export function createPRInfoHandler() {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { Request, Response } from 'express';
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import path from 'path';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import { secureFs } from '@automaker/platform';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
import * as secureFs from '../lib/secure-fs.js';
|
||||
import type { EventEmitter } from '../lib/events.js';
|
||||
import type { ExecuteOptions } from '@automaker/types';
|
||||
import {
|
||||
@@ -15,7 +14,7 @@ import {
|
||||
} from '@automaker/utils';
|
||||
import { ProviderFactory } from '../providers/provider-factory.js';
|
||||
import { createChatOptions, validateWorkingDirectory } from '../lib/sdk-options.js';
|
||||
import { PathNotAllowedError } from '@automaker/platform';
|
||||
import { PathNotAllowedError, secureFs } from '@automaker/platform';
|
||||
|
||||
interface Message {
|
||||
id: string;
|
||||
|
||||
@@ -20,9 +20,11 @@ import {
|
||||
loadContextFiles,
|
||||
createLogger,
|
||||
sleep,
|
||||
processStream,
|
||||
extractBeforeMarker,
|
||||
} from '@automaker/utils';
|
||||
import { secureFs, getFeatureDir } from '@automaker/platform';
|
||||
import { resolveModelString, DEFAULT_MODELS } from '@automaker/model-resolver';
|
||||
import { getFeatureDir } from '@automaker/platform';
|
||||
import {
|
||||
getPlanningPromptPrefix,
|
||||
parseTasksFromSpec,
|
||||
@@ -31,10 +33,8 @@ import {
|
||||
buildContinuationPrompt,
|
||||
} from '@automaker/prompts';
|
||||
import path from 'path';
|
||||
import * as secureFs from '../lib/secure-fs.js';
|
||||
import type { EventEmitter } from '../lib/events.js';
|
||||
import { createAutoModeOptions, validateWorkingDirectory } from '../lib/sdk-options.js';
|
||||
import { processStream, extractBeforeMarker } from '../lib/stream-processor.js';
|
||||
import { FeatureLoader } from './feature-loader.js';
|
||||
|
||||
import {
|
||||
|
||||
@@ -13,8 +13,7 @@ import {
|
||||
shortHash,
|
||||
} from '@automaker/git-utils';
|
||||
import { extractTitleFromDescription } from '@automaker/prompts';
|
||||
import { getFeatureDir } from '@automaker/platform';
|
||||
import * as secureFs from '../../lib/secure-fs.js';
|
||||
import { getFeatureDir, secureFs } from '@automaker/platform';
|
||||
import path from 'path';
|
||||
import type { EventEmitter } from '../../lib/events.js';
|
||||
import type { Feature } from '@automaker/types';
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Used to persist agent output to agent-output.md in the feature directory.
|
||||
*/
|
||||
|
||||
import * as secureFs from '../../lib/secure-fs.js';
|
||||
import { secureFs } from '@automaker/platform';
|
||||
import path from 'path';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
|
||||
|
||||
@@ -6,13 +6,11 @@
|
||||
*/
|
||||
|
||||
import type { ExecuteOptions } from '@automaker/types';
|
||||
import { createLogger, classifyError } from '@automaker/utils';
|
||||
import { createLogger, classifyError, processStream } from '@automaker/utils';
|
||||
import { resolveModelString, DEFAULT_MODELS } from '@automaker/model-resolver';
|
||||
import { getAutomakerDir } from '@automaker/platform';
|
||||
import { getAutomakerDir, secureFs } from '@automaker/platform';
|
||||
import { ProviderFactory } from '../../providers/provider-factory.js';
|
||||
import { validateWorkingDirectory } from '../../lib/sdk-options.js';
|
||||
import { processStream } from '../../lib/stream-processor.js';
|
||||
import * as secureFs from '../../lib/secure-fs.js';
|
||||
import path from 'path';
|
||||
import type { EventEmitter } from '../../lib/events.js';
|
||||
|
||||
|
||||
@@ -9,8 +9,7 @@ import type { ExecuteOptions, ParsedTask } from '@automaker/types';
|
||||
import type { EventEmitter } from '../../lib/events.js';
|
||||
import type { BaseProvider } from '../../providers/base-provider.js';
|
||||
import { buildTaskPrompt } from '@automaker/prompts';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { processStream } from '../../lib/stream-processor.js';
|
||||
import { createLogger, processStream } from '@automaker/utils';
|
||||
import type { TaskExecutionContext, TaskProgress } from './types.js';
|
||||
|
||||
const logger = createLogger('TaskExecutor');
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
import { spawn, execSync, type ChildProcess } from 'child_process';
|
||||
import * as secureFs from '../lib/secure-fs.js';
|
||||
import { secureFs } from '@automaker/platform';
|
||||
import path from 'path';
|
||||
import net from 'net';
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ import path from 'path';
|
||||
import type { Feature, PlanSpec, FeatureStatus } from '@automaker/types';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { resolveDependencies, areDependenciesSatisfied } from '@automaker/dependency-resolver';
|
||||
import * as secureFs from '../lib/secure-fs.js';
|
||||
import {
|
||||
getFeaturesDir,
|
||||
getFeatureDir,
|
||||
getFeatureImagesDir,
|
||||
ensureAutomakerDir,
|
||||
secureFs,
|
||||
} from '@automaker/platform';
|
||||
|
||||
const logger = createLogger('FeatureLoader');
|
||||
|
||||
@@ -8,14 +8,13 @@
|
||||
*/
|
||||
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import * as secureFs from '../lib/secure-fs.js';
|
||||
|
||||
import {
|
||||
getGlobalSettingsPath,
|
||||
getCredentialsPath,
|
||||
getProjectSettingsPath,
|
||||
ensureDataDir,
|
||||
ensureAutomakerDir,
|
||||
secureFs,
|
||||
} from '@automaker/platform';
|
||||
import type {
|
||||
GlobalSettings,
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
SIMPLIFY_EXAMPLES,
|
||||
ACCEPTANCE_EXAMPLES,
|
||||
type EnhancementMode,
|
||||
} from '@/lib/enhancement-prompts.js';
|
||||
} from '@automaker/prompts';
|
||||
|
||||
describe('enhancement-prompts.ts', () => {
|
||||
describe('System Prompt Constants', () => {
|
||||
|
||||
@@ -10,10 +10,16 @@ vi.mock('child_process', () => ({
|
||||
execSync: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock secure-fs
|
||||
vi.mock('@/lib/secure-fs.js', () => ({
|
||||
access: vi.fn(),
|
||||
}));
|
||||
// Mock secure-fs from @automaker/platform
|
||||
vi.mock('@automaker/platform', async () => {
|
||||
const actual = await vi.importActual('@automaker/platform');
|
||||
return {
|
||||
...actual,
|
||||
secureFs: {
|
||||
access: vi.fn(),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// Mock net
|
||||
vi.mock('net', () => ({
|
||||
@@ -24,7 +30,7 @@ vi.mock('net', () => ({
|
||||
}));
|
||||
|
||||
import { spawn, execSync } from 'child_process';
|
||||
import * as secureFs from '@/lib/secure-fs.js';
|
||||
import { secureFs } from '@automaker/platform';
|
||||
import net from 'net';
|
||||
|
||||
describe('dev-server-service.ts', () => {
|
||||
|
||||
Reference in New Issue
Block a user