mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
style: Improve code formatting and add comments for clarity across multiple files
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
import { CodeAgent, CodeAgentType, getCodeAgentDisplayName } from "./CodeAgentInterface";
|
||||
import {
|
||||
CodeAgent,
|
||||
CodeAgentType,
|
||||
getCodeAgentDisplayName,
|
||||
} from "./CodeAgentInterface";
|
||||
import OpenCodeAgent from "./OpenCodeAgent";
|
||||
import logger from "Common/Server/Utils/Logger";
|
||||
|
||||
@@ -15,11 +19,13 @@ export default class CodeAgentFactory {
|
||||
case CodeAgentType.OpenCode:
|
||||
return new OpenCodeAgent();
|
||||
|
||||
// Future agents can be added here:
|
||||
// case CodeAgentType.Goose:
|
||||
// return new GooseAgent();
|
||||
// case CodeAgentType.ClaudeCode:
|
||||
// return new ClaudeCodeAgent();
|
||||
/*
|
||||
* Future agents can be added here:
|
||||
* case CodeAgentType.Goose:
|
||||
* return new GooseAgent();
|
||||
* case CodeAgentType.ClaudeCode:
|
||||
* return new ClaudeCodeAgent();
|
||||
*/
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown code agent type: ${type}`);
|
||||
@@ -68,8 +74,10 @@ export default class CodeAgentFactory {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create agent with fallback
|
||||
// Tries to create the specified type, falls back to first available
|
||||
/*
|
||||
* Create agent with fallback
|
||||
* Tries to create the specified type, falls back to first available
|
||||
*/
|
||||
public static async createAgentWithFallback(
|
||||
preferredType?: CodeAgentType,
|
||||
): Promise<CodeAgent> {
|
||||
|
||||
@@ -40,17 +40,16 @@ export type CodeAgentProgressCallback = (
|
||||
event: CodeAgentProgressEvent,
|
||||
) => void | Promise<void>;
|
||||
|
||||
// Abstract interface for code agents
|
||||
// This allows us to support multiple agents (OpenCode, Goose, Claude Code, etc.)
|
||||
/*
|
||||
* Abstract interface for code agents
|
||||
* This allows us to support multiple agents (OpenCode, Goose, Claude Code, etc.)
|
||||
*/
|
||||
export interface CodeAgent {
|
||||
// Name of the agent (e.g., "OpenCode", "Goose", "ClaudeCode")
|
||||
readonly name: string;
|
||||
|
||||
// Initialize the agent with LLM configuration
|
||||
initialize(
|
||||
config: CodeAgentLLMConfig,
|
||||
logger?: TaskLogger,
|
||||
): Promise<void>;
|
||||
initialize(config: CodeAgentLLMConfig, logger?: TaskLogger): Promise<void>;
|
||||
|
||||
// Execute a task and return the result
|
||||
executeTask(task: CodeAgentTask): Promise<CodeAgentResult>;
|
||||
@@ -71,10 +70,12 @@ export interface CodeAgent {
|
||||
// Enum for supported code agent types
|
||||
export enum CodeAgentType {
|
||||
OpenCode = "OpenCode",
|
||||
// Future agents:
|
||||
// Goose = "Goose",
|
||||
// ClaudeCode = "ClaudeCode",
|
||||
// Aider = "Aider",
|
||||
/*
|
||||
* Future agents:
|
||||
* Goose = "Goose",
|
||||
* ClaudeCode = "ClaudeCode",
|
||||
* Aider = "Aider",
|
||||
*/
|
||||
}
|
||||
|
||||
// Helper function to get display name for agent type
|
||||
|
||||
@@ -51,12 +51,15 @@ export default class OpenCodeAgent implements CodeAgent {
|
||||
|
||||
public async executeTask(task: CodeAgentTask): Promise<CodeAgentResult> {
|
||||
if (!this.config) {
|
||||
return this.createErrorResult("Agent not initialized. Call initialize() first.");
|
||||
return this.createErrorResult(
|
||||
"Agent not initialized. Call initialize() first.",
|
||||
);
|
||||
}
|
||||
|
||||
this.aborted = false;
|
||||
const logs: Array<string> = [];
|
||||
const timeoutMs: number = task.timeoutMs || OpenCodeAgent.DEFAULT_TIMEOUT_MS;
|
||||
const timeoutMs: number =
|
||||
task.timeoutMs || OpenCodeAgent.DEFAULT_TIMEOUT_MS;
|
||||
|
||||
try {
|
||||
await this.log(`Executing task in directory: ${task.workingDirectory}`);
|
||||
@@ -83,7 +86,9 @@ export default class OpenCodeAgent implements CodeAgent {
|
||||
},
|
||||
);
|
||||
|
||||
logs.push(`Output: ${output.substring(0, 1000)}${output.length > 1000 ? "..." : ""}`);
|
||||
logs.push(
|
||||
`Output: ${output.substring(0, 1000)}${output.length > 1000 ? "..." : ""}`,
|
||||
);
|
||||
|
||||
if (this.aborted) {
|
||||
return this.createErrorResult("Task was aborted", logs);
|
||||
@@ -94,7 +99,9 @@ export default class OpenCodeAgent implements CodeAgent {
|
||||
task.workingDirectory,
|
||||
);
|
||||
|
||||
await this.log(`OpenCode completed. ${modifiedFiles.length} files modified.`);
|
||||
await this.log(
|
||||
`OpenCode completed. ${modifiedFiles.length} files modified.`,
|
||||
);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
@@ -308,7 +315,13 @@ export default class OpenCodeAgent implements CodeAgent {
|
||||
|
||||
const args: Array<string> = ["run", prompt];
|
||||
|
||||
logger.debug(`Running: opencode ${args.map((a: string) => a.includes(" ") ? `"${a.substring(0, 50)}..."` : a).join(" ")}`);
|
||||
logger.debug(
|
||||
`Running: opencode ${args
|
||||
.map((a: string) => {
|
||||
return a.includes(" ") ? `"${a.substring(0, 50)}..."` : a;
|
||||
})
|
||||
.join(" ")}`,
|
||||
);
|
||||
|
||||
const child: ChildProcess = spawn("opencode", args, {
|
||||
cwd: workingDirectory,
|
||||
@@ -325,7 +338,11 @@ export default class OpenCodeAgent implements CodeAgent {
|
||||
const timeout: ReturnType<typeof setTimeout> = setTimeout(() => {
|
||||
if (child.pid) {
|
||||
child.kill("SIGTERM");
|
||||
reject(new Error(`OpenCode execution timed out after ${timeoutMs / 1000} seconds`));
|
||||
reject(
|
||||
new Error(
|
||||
`OpenCode execution timed out after ${timeoutMs / 1000} seconds`,
|
||||
),
|
||||
);
|
||||
}
|
||||
}, timeoutMs);
|
||||
|
||||
@@ -340,9 +357,11 @@ export default class OpenCodeAgent implements CodeAgent {
|
||||
|
||||
// Stream to task logger for server-side logging
|
||||
if (this.taskLogger) {
|
||||
this.taskLogger.info(`[OpenCode] ${trimmedText}`).catch((err: Error) => {
|
||||
logger.error(`Failed to log OpenCode output: ${err.message}`);
|
||||
});
|
||||
this.taskLogger
|
||||
.info(`[OpenCode] ${trimmedText}`)
|
||||
.catch((err: Error) => {
|
||||
logger.error(`Failed to log OpenCode output: ${err.message}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,9 +383,11 @@ export default class OpenCodeAgent implements CodeAgent {
|
||||
|
||||
// Stream to task logger for server-side logging
|
||||
if (this.taskLogger) {
|
||||
this.taskLogger.warning(`[OpenCode stderr] ${trimmedText}`).catch((err: Error) => {
|
||||
logger.error(`Failed to log OpenCode stderr: ${err.message}`);
|
||||
});
|
||||
this.taskLogger
|
||||
.warning(`[OpenCode stderr] ${trimmedText}`)
|
||||
.catch((err: Error) => {
|
||||
logger.error(`Failed to log OpenCode stderr: ${err.message}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,9 @@ const executeTask: ExecuteTaskFunction = async (
|
||||
|
||||
try {
|
||||
// Log handler starting
|
||||
await taskLogger.info(`Starting ${handler.name} for task type: ${taskType}`);
|
||||
await taskLogger.info(
|
||||
`Starting ${handler.name} for task type: ${taskType}`,
|
||||
);
|
||||
|
||||
// Validate metadata if the handler supports it
|
||||
if (handler.validateMetadata && !handler.validateMetadata(metadata)) {
|
||||
@@ -106,9 +108,11 @@ const executeTask: ExecuteTaskFunction = async (
|
||||
// Flush all pending logs
|
||||
await taskLogger.flush();
|
||||
|
||||
// If the task was not successful and we want to report it as an error
|
||||
// Note: Based on user requirements, "no fix found" should be Completed, not Error
|
||||
// Only throw if there was an actual error (not just "no action taken")
|
||||
/*
|
||||
* If the task was not successful and we want to report it as an error
|
||||
* Note: Based on user requirements, "no fix found" should be Completed, not Error
|
||||
* Only throw if there was an actual error (not just "no action taken")
|
||||
*/
|
||||
if (!result.success && result.data?.["isError"]) {
|
||||
throw new Error(result.message);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ import RepositoryManager, {
|
||||
RepositoryConfig,
|
||||
CloneResult,
|
||||
} from "../Utils/RepositoryManager";
|
||||
import PullRequestCreator, { PullRequestResult } from "../Utils/PullRequestCreator";
|
||||
import PullRequestCreator, {
|
||||
PullRequestResult,
|
||||
} from "../Utils/PullRequestCreator";
|
||||
import WorkspaceManager, { WorkspaceInfo } from "../Utils/WorkspaceManager";
|
||||
import {
|
||||
CodeAgentFactory,
|
||||
@@ -48,7 +50,10 @@ export default class FixExceptionTaskHandler extends BaseTaskHandler<FixExceptio
|
||||
): Promise<TaskResult> {
|
||||
const metadata: FixExceptionMetadata = context.metadata;
|
||||
|
||||
await this.log(context, `Starting Fix Exception task for exception: ${metadata.exceptionId} (taskId: ${context.taskId.toString()})`);
|
||||
await this.log(
|
||||
context,
|
||||
`Starting Fix Exception task for exception: ${metadata.exceptionId} (taskId: ${context.taskId.toString()})`,
|
||||
);
|
||||
|
||||
let workspace: WorkspaceInfo | null = null;
|
||||
|
||||
@@ -114,7 +119,9 @@ export default class FixExceptionTaskHandler extends BaseTaskHandler<FixExceptio
|
||||
);
|
||||
|
||||
// Step 4: Create workspace for the task
|
||||
workspace = await WorkspaceManager.createWorkspace(context.taskId.toString());
|
||||
workspace = await WorkspaceManager.createWorkspace(
|
||||
context.taskId.toString(),
|
||||
);
|
||||
await this.log(context, `Created workspace: ${workspace.workspacePath}`);
|
||||
|
||||
// Step 5: Process each repository
|
||||
@@ -222,9 +229,8 @@ export default class FixExceptionTaskHandler extends BaseTaskHandler<FixExceptio
|
||||
`Getting access token for ${repo.organizationName}/${repo.repositoryName}...`,
|
||||
);
|
||||
|
||||
const tokenData: RepositoryToken = await context.backendAPI.getRepositoryToken(
|
||||
repo.id,
|
||||
);
|
||||
const tokenData: RepositoryToken =
|
||||
await context.backendAPI.getRepositoryToken(repo.id);
|
||||
|
||||
// Clone the repository
|
||||
await this.log(
|
||||
@@ -239,7 +245,9 @@ export default class FixExceptionTaskHandler extends BaseTaskHandler<FixExceptio
|
||||
repositoryUrl: tokenData.repositoryUrl,
|
||||
};
|
||||
|
||||
const repoManager: RepositoryManager = new RepositoryManager(context.logger);
|
||||
const repoManager: RepositoryManager = new RepositoryManager(
|
||||
context.logger,
|
||||
);
|
||||
const cloneResult: CloneResult = await repoManager.cloneRepository(
|
||||
repoConfig,
|
||||
workspace.workspacePath,
|
||||
@@ -258,7 +266,9 @@ export default class FixExceptionTaskHandler extends BaseTaskHandler<FixExceptio
|
||||
|
||||
// Initialize code agent
|
||||
await this.log(context, "Initializing code agent...");
|
||||
const agent: CodeAgent = CodeAgentFactory.createAgent(CodeAgentType.OpenCode);
|
||||
const agent: CodeAgent = CodeAgentFactory.createAgent(
|
||||
CodeAgentType.OpenCode,
|
||||
);
|
||||
const agentConfig: CodeAgentLLMConfig = {
|
||||
llmType: llmConfig.llmType,
|
||||
};
|
||||
@@ -321,11 +331,17 @@ export default class FixExceptionTaskHandler extends BaseTaskHandler<FixExceptio
|
||||
|
||||
// Push the branch
|
||||
await this.log(context, `Pushing branch ${branchName}...`);
|
||||
await repoManager.pushBranch(cloneResult.repositoryPath, branchName, repoConfig);
|
||||
await repoManager.pushBranch(
|
||||
cloneResult.repositoryPath,
|
||||
branchName,
|
||||
repoConfig,
|
||||
);
|
||||
|
||||
// Create pull request
|
||||
await this.log(context, "Creating pull request...");
|
||||
const prCreator: PullRequestCreator = new PullRequestCreator(context.logger);
|
||||
const prCreator: PullRequestCreator = new PullRequestCreator(
|
||||
context.logger,
|
||||
);
|
||||
|
||||
const prTitle: string = PullRequestCreator.generatePRTitle(
|
||||
exceptionDetails.exception.message,
|
||||
|
||||
@@ -2,8 +2,10 @@ import { TaskHandler } from "./TaskHandlerInterface";
|
||||
import AIAgentTaskType from "Common/Types/AI/AIAgentTaskType";
|
||||
import logger from "Common/Server/Utils/Logger";
|
||||
|
||||
// Registry for task handlers
|
||||
// Allows dynamic registration and lookup of handlers by task type
|
||||
/*
|
||||
* Registry for task handlers
|
||||
* Allows dynamic registration and lookup of handlers by task type
|
||||
*/
|
||||
export default class TaskHandlerRegistry {
|
||||
private static instance: TaskHandlerRegistry | null = null;
|
||||
private handlers: Map<AIAgentTaskType, TaskHandler> = new Map();
|
||||
|
||||
@@ -139,7 +139,9 @@ export default class BackendAPI {
|
||||
|
||||
// Get LLM configuration for a project
|
||||
public async getLLMConfig(projectId: string): Promise<LLMConfig> {
|
||||
const url: URL = URL.fromURL(this.baseUrl).addRoute("/api/ai-agent-data/get-llm-config");
|
||||
const url: URL = URL.fromURL(this.baseUrl).addRoute(
|
||||
"/api/ai-agent-data/get-llm-config",
|
||||
);
|
||||
|
||||
const response = await API.post({
|
||||
url,
|
||||
|
||||
@@ -30,7 +30,9 @@ export default class RepositoryManager {
|
||||
config: RepositoryConfig,
|
||||
workDir: string,
|
||||
): Promise<CloneResult> {
|
||||
await this.log(`Cloning repository ${config.organizationName}/${config.repositoryName}...`);
|
||||
await this.log(
|
||||
`Cloning repository ${config.organizationName}/${config.repositoryName}...`,
|
||||
);
|
||||
|
||||
// Build the authenticated URL
|
||||
const authUrl: string = this.buildAuthenticatedUrl(config);
|
||||
@@ -112,11 +114,7 @@ export default class RepositoryManager {
|
||||
): Promise<void> {
|
||||
try {
|
||||
// Check if branch exists locally
|
||||
await this.runGitCommand(repoPath, [
|
||||
"rev-parse",
|
||||
"--verify",
|
||||
branchName,
|
||||
]);
|
||||
await this.runGitCommand(repoPath, ["rev-parse", "--verify", branchName]);
|
||||
await this.checkoutBranch(repoPath, branchName);
|
||||
} catch (error) {
|
||||
// Branch doesn't exist, create it
|
||||
@@ -169,10 +167,7 @@ export default class RepositoryManager {
|
||||
}
|
||||
|
||||
// Commit changes
|
||||
public async commitChanges(
|
||||
repoPath: string,
|
||||
message: string,
|
||||
): Promise<void> {
|
||||
public async commitChanges(repoPath: string, message: string): Promise<void> {
|
||||
await this.log(`Committing changes: ${message.substring(0, 50)}...`);
|
||||
|
||||
await Execute.executeCommandFile({
|
||||
@@ -196,15 +191,15 @@ export default class RepositoryManager {
|
||||
const authUrl: string = this.buildAuthenticatedUrl(config);
|
||||
|
||||
// Update the remote URL
|
||||
await this.runGitCommand(repoPath, ["remote", "set-url", "origin", authUrl]);
|
||||
await this.runGitCommand(repoPath, [
|
||||
"remote",
|
||||
"set-url",
|
||||
"origin",
|
||||
authUrl,
|
||||
]);
|
||||
|
||||
// Push with tracking
|
||||
await this.runGitCommand(repoPath, [
|
||||
"push",
|
||||
"-u",
|
||||
"origin",
|
||||
branchName,
|
||||
]);
|
||||
await this.runGitCommand(repoPath, ["push", "-u", "origin", branchName]);
|
||||
|
||||
await this.log(`Branch ${branchName} pushed to remote`);
|
||||
}
|
||||
|
||||
@@ -174,8 +174,10 @@ export default class WorkspaceManager {
|
||||
|
||||
const workspacePath: string = path.join(this.BASE_TEMP_DIR, entry.name);
|
||||
|
||||
// Try to extract timestamp from directory name
|
||||
// Format: task-{taskId}-{timestamp}-{uniqueId}
|
||||
/*
|
||||
* Try to extract timestamp from directory name
|
||||
* Format: task-{taskId}-{timestamp}-{uniqueId}
|
||||
*/
|
||||
const match: RegExpMatchArray | null = entry.name.match(
|
||||
/task-[^-]+-(\d+)-[^-]+/,
|
||||
);
|
||||
@@ -203,7 +205,9 @@ export default class WorkspaceManager {
|
||||
public static async initialize(): Promise<void> {
|
||||
try {
|
||||
await LocalFile.makeDirectory(this.BASE_TEMP_DIR);
|
||||
logger.debug(`Workspace base directory initialized: ${this.BASE_TEMP_DIR}`);
|
||||
logger.debug(
|
||||
`Workspace base directory initialized: ${this.BASE_TEMP_DIR}`,
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error("Error initializing workspace manager:");
|
||||
logger.error(error);
|
||||
|
||||
@@ -543,7 +543,7 @@ export default class AIAgentTask extends BaseModel {
|
||||
@Column({
|
||||
type: ColumnType.Number,
|
||||
nullable: false,
|
||||
default: 1
|
||||
default: 1,
|
||||
})
|
||||
public taskNumber?: number = undefined;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,8 @@ export default class AIAgentDataAPI {
|
||||
const projectId: ObjectID = new ObjectID(data["projectId"] as string);
|
||||
|
||||
// Check if this is a Project AI Agent (has a projectId)
|
||||
const isProjectAIAgent: boolean = aiAgent.projectId !== null && aiAgent.projectId !== undefined;
|
||||
const isProjectAIAgent: boolean =
|
||||
aiAgent.projectId !== null && aiAgent.projectId !== undefined;
|
||||
|
||||
// Get LLM provider for the project
|
||||
const llmProvider: LlmProvider | null =
|
||||
@@ -97,8 +98,10 @@ export default class AIAgentDataAPI {
|
||||
);
|
||||
}
|
||||
|
||||
// Security check: Project AI Agents cannot access Global LLM Providers
|
||||
// Only Global AI Agents (projectId is null) can access Global LLM Providers
|
||||
/*
|
||||
* Security check: Project AI Agents cannot access Global LLM Providers
|
||||
* Only Global AI Agents (projectId is null) can access Global LLM Providers
|
||||
*/
|
||||
const isGlobalLLMProvider: boolean = llmProvider.isGlobalLlm === true;
|
||||
|
||||
if (isProjectAIAgent && isGlobalLLMProvider) {
|
||||
@@ -281,11 +284,12 @@ export default class AIAgentDataAPI {
|
||||
// Extract service catalog IDs
|
||||
const serviceCatalogIds: Array<ObjectID> =
|
||||
serviceCatalogTelemetryServices
|
||||
.filter((s: ServiceCatalogTelemetryService) => s.serviceCatalogId)
|
||||
.map(
|
||||
(s: ServiceCatalogTelemetryService) =>
|
||||
s.serviceCatalogId as ObjectID,
|
||||
);
|
||||
.filter((s: ServiceCatalogTelemetryService) => {
|
||||
return s.serviceCatalogId;
|
||||
})
|
||||
.map((s: ServiceCatalogTelemetryService) => {
|
||||
return s.serviceCatalogId as ObjectID;
|
||||
});
|
||||
|
||||
// Step 2: Find CodeRepositories linked to these ServiceCatalogs
|
||||
const repositories: Array<{
|
||||
@@ -338,7 +342,9 @@ export default class AIAgentDataAPI {
|
||||
mainBranchName: string;
|
||||
servicePathInRepository: string | null;
|
||||
gitHubAppInstallationId: string | null;
|
||||
}) => r.id === scr.codeRepository?._id?.toString(),
|
||||
}) => {
|
||||
return r.id === scr.codeRepository?._id?.toString();
|
||||
},
|
||||
);
|
||||
if (!existingRepo) {
|
||||
repositories.push({
|
||||
@@ -346,11 +352,9 @@ export default class AIAgentDataAPI {
|
||||
name: scr.codeRepository.name || "",
|
||||
repositoryHostedAt:
|
||||
scr.codeRepository.repositoryHostedAt || "",
|
||||
organizationName:
|
||||
scr.codeRepository.organizationName || "",
|
||||
organizationName: scr.codeRepository.organizationName || "",
|
||||
repositoryName: scr.codeRepository.repositoryName || "",
|
||||
mainBranchName:
|
||||
scr.codeRepository.mainBranchName || "main",
|
||||
mainBranchName: scr.codeRepository.mainBranchName || "main",
|
||||
servicePathInRepository:
|
||||
scr.servicePathInRepository || null,
|
||||
gitHubAppInstallationId:
|
||||
|
||||
@@ -1,20 +1,35 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1767009661768 implements MigrationInterface {
|
||||
public name = 'MigrationName1767009661768'
|
||||
public name = "MigrationName1767009661768";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "AIAgentTask" ADD "taskNumber" integer NOT NULL DEFAULT '1'`);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_5294ce8ea35d411bc972803e8b" ON "AIAgentTask" ("taskNumber") `);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_5294ce8ea35d411bc972803e8b"`);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`);
|
||||
await queryRunner.query(`ALTER TABLE "AIAgentTask" DROP COLUMN "taskNumber"`);
|
||||
}
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AIAgentTask" ADD "taskNumber" integer NOT NULL DEFAULT '1'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_5294ce8ea35d411bc972803e8b" ON "AIAgentTask" ("taskNumber") `,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_5294ce8ea35d411bc972803e8b"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AIAgentTask" DROP COLUMN "taskNumber"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,5 +429,5 @@ export default [
|
||||
AddAIAgentIsDefault1766918848434,
|
||||
MigrationName1766923324521,
|
||||
AddGitHubAppInstallationIdToProject1766958924188,
|
||||
MigrationName1767009661768
|
||||
MigrationName1767009661768,
|
||||
];
|
||||
|
||||
@@ -63,10 +63,7 @@ const HeaderIconDropdownButton: FunctionComponent<ComponentProps> = (
|
||||
/>
|
||||
)}
|
||||
{props.icon && (
|
||||
<Icon
|
||||
className="h-5 w-5 text-gray-500"
|
||||
icon={props.icon}
|
||||
/>
|
||||
<Icon className="h-5 w-5 text-gray-500" icon={props.icon} />
|
||||
)}
|
||||
</button>
|
||||
{props.title && (
|
||||
|
||||
@@ -188,9 +188,11 @@ describe("ExceptionUtil", () => {
|
||||
|
||||
test("handles null/undefined gracefully", () => {
|
||||
// @ts-expect-error - testing edge case
|
||||
const normalizedNull: string = ExceptionUtil.normalizeForFingerprint(null);
|
||||
const normalizedNull: string =
|
||||
ExceptionUtil.normalizeForFingerprint(null);
|
||||
// @ts-expect-error - testing edge case
|
||||
const normalizedUndefined: string = ExceptionUtil.normalizeForFingerprint(undefined);
|
||||
const normalizedUndefined: string =
|
||||
ExceptionUtil.normalizeForFingerprint(undefined);
|
||||
|
||||
expect(normalizedNull).toBe("");
|
||||
expect(normalizedUndefined).toBe("");
|
||||
|
||||
Reference in New Issue
Block a user