mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-18 22:33:08 +00:00
refactor: Improve all git operations, add stash support, add improved pull request flow, add worktree file copy options, address code review comments, add cherry pick options
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
import type { Feature } from '@automaker/types';
|
||||
import { createLogger, classifyError } from '@automaker/utils';
|
||||
import { areDependenciesSatisfied } from '@automaker/dependency-resolver';
|
||||
import type { TypedEventBus } from './typed-event-bus.js';
|
||||
import type { ConcurrencyManager } from './concurrency-manager.js';
|
||||
import type { SettingsService } from './settings-service.js';
|
||||
@@ -64,6 +65,7 @@ export type ClearExecutionStateFn = (
|
||||
) => Promise<void>;
|
||||
export type ResetStuckFeaturesFn = (projectPath: string) => Promise<void>;
|
||||
export type IsFeatureFinishedFn = (feature: Feature) => boolean;
|
||||
export type LoadAllFeaturesFn = (projectPath: string) => Promise<Feature[]>;
|
||||
|
||||
export class AutoLoopCoordinator {
|
||||
private autoLoopsByProject = new Map<string, ProjectAutoLoopState>();
|
||||
@@ -78,7 +80,8 @@ export class AutoLoopCoordinator {
|
||||
private clearExecutionStateFn: ClearExecutionStateFn,
|
||||
private resetStuckFeaturesFn: ResetStuckFeaturesFn,
|
||||
private isFeatureFinishedFn: IsFeatureFinishedFn,
|
||||
private isFeatureRunningFn: (featureId: string) => boolean
|
||||
private isFeatureRunningFn: (featureId: string) => boolean,
|
||||
private loadAllFeaturesFn?: LoadAllFeaturesFn
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -178,9 +181,31 @@ export class AutoLoopCoordinator {
|
||||
await this.sleep(10000, projectState.abortController.signal);
|
||||
continue;
|
||||
}
|
||||
const nextFeature = pendingFeatures.find(
|
||||
(f) => !this.isFeatureRunningFn(f.id) && !this.isFeatureFinishedFn(f)
|
||||
|
||||
// Load all features for dependency checking (if callback provided)
|
||||
const allFeatures = this.loadAllFeaturesFn
|
||||
? await this.loadAllFeaturesFn(projectPath)
|
||||
: pendingFeatures;
|
||||
|
||||
// Filter to eligible features: not running, not finished, and dependencies satisfied
|
||||
const eligibleFeatures = pendingFeatures.filter(
|
||||
(f) =>
|
||||
!this.isFeatureRunningFn(f.id) &&
|
||||
!this.isFeatureFinishedFn(f) &&
|
||||
areDependenciesSatisfied(f, allFeatures)
|
||||
);
|
||||
|
||||
// Sort eligible features by priority (lower number = higher priority, default 2)
|
||||
eligibleFeatures.sort((a, b) => (a.priority ?? 2) - (b.priority ?? 2));
|
||||
|
||||
const nextFeature = eligibleFeatures[0] ?? null;
|
||||
|
||||
if (nextFeature) {
|
||||
logger.info(
|
||||
`Auto-loop selected feature "${nextFeature.title || nextFeature.id}" ` +
|
||||
`(priority=${nextFeature.priority ?? 2}) from ${eligibleFeatures.length} eligible features`
|
||||
);
|
||||
}
|
||||
if (nextFeature) {
|
||||
projectState.hasEmittedIdleEvent = false;
|
||||
this.executeFeatureFn(
|
||||
|
||||
@@ -324,7 +324,8 @@ export class AutoModeServiceFacade {
|
||||
feature.status === 'completed' ||
|
||||
feature.status === 'verified' ||
|
||||
feature.status === 'waiting_approval',
|
||||
(featureId) => concurrencyManager.isRunning(featureId)
|
||||
(featureId) => concurrencyManager.isRunning(featureId),
|
||||
async (pPath) => featureLoader.getAll(pPath)
|
||||
);
|
||||
|
||||
// ExecutionService - runAgentFn calls AgentExecutor.execute
|
||||
|
||||
@@ -729,6 +729,7 @@ export class SettingsService {
|
||||
anthropic: { configured: boolean; masked: string };
|
||||
google: { configured: boolean; masked: string };
|
||||
openai: { configured: boolean; masked: string };
|
||||
zai: { configured: boolean; masked: string };
|
||||
}> {
|
||||
const credentials = await this.getCredentials();
|
||||
|
||||
@@ -750,6 +751,10 @@ export class SettingsService {
|
||||
configured: !!credentials.apiKeys.openai,
|
||||
masked: maskKey(credentials.apiKeys.openai),
|
||||
},
|
||||
zai: {
|
||||
configured: !!credentials.apiKeys.zai,
|
||||
masked: maskKey(credentials.apiKeys.zai),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -171,7 +171,11 @@ export class ZaiUsageService {
|
||||
*/
|
||||
getApiHost(): string {
|
||||
// Priority: 1. Instance host, 2. Z_AI_API_HOST env, 3. Default
|
||||
return process.env.Z_AI_API_HOST ? `https://${process.env.Z_AI_API_HOST}` : this.apiHost;
|
||||
if (process.env.Z_AI_API_HOST) {
|
||||
const envHost = process.env.Z_AI_API_HOST.trim();
|
||||
return envHost.startsWith('http') ? envHost : `https://${envHost}`;
|
||||
}
|
||||
return this.apiHost;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,8 +246,7 @@ export class ZaiUsageService {
|
||||
}
|
||||
|
||||
const quotaUrl =
|
||||
process.env.Z_AI_QUOTA_URL ||
|
||||
`${process.env.Z_AI_API_HOST ? `https://${process.env.Z_AI_API_HOST}` : 'https://api.z.ai'}/api/monitor/usage/quota/limit`;
|
||||
process.env.Z_AI_QUOTA_URL || `${this.getApiHost()}/api/monitor/usage/quota/limit`;
|
||||
|
||||
logger.info(`[verify] Testing API key against: ${quotaUrl}`);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user