feat: expand intelligent investigation workspace
Generic Container CI/CD / test-build-publish (push) Successful in 1m52s
Frontend CI/CD / build-test-publish-and-deploy (push) Successful in 1m52s

This commit is contained in:
2026-10-30 17:30:19 +08:00
parent ddd03dbff6
commit c0e4231b83
223 changed files with 13155 additions and 5304 deletions
+81 -15
View File
@@ -7,13 +7,21 @@ import {
} from ".";
type ExecuteAction = (request: FrontendActionRequest, signal: AbortSignal) => Promise<unknown>;
type SubmitResult = (sessionId: string, actionId: string, result: FrontendActionResult) => Promise<void>;
type SubmitResult = (
sessionId: string,
actionId: string,
result: FrontendActionResult
) => Promise<void>;
const ERROR_CODE_PATTERN = /^[A-Z][A-Z0-9_]+$/;
export class FrontendActionExecutor {
private readonly controllers = new Map<string, AbortController>();
private queue: Promise<void> = Promise.resolve();
constructor(private readonly execute: ExecuteAction, private readonly submit: SubmitResult) {}
constructor(
private readonly execute: ExecuteAction,
private readonly submit: SubmitResult
) {}
async handle(value: unknown, activeSessionId: string | null): Promise<void> {
const request = parseFrontendActionRequest(value);
@@ -24,32 +32,90 @@ export class FrontendActionExecutor {
return;
}
if (this.controllers.has(request.actionId)) return;
const result = await this.executeOnce(request);
storeActionResult(request.sessionId, result);
await this.submit(request.sessionId, request.actionId, result);
const controller = new AbortController();
this.controllers.set(request.actionId, controller);
const pending = this.queue.then(async () => {
const result = await this.executeOnce(request, controller);
storeActionResult(request.sessionId, result);
await this.submit(request.sessionId, request.actionId, result);
});
this.queue = pending.catch(() => undefined);
return pending;
}
cancelAll(): void {
for (const controller of this.controllers.values()) controller.abort();
this.controllers.clear();
this.queue = Promise.resolve();
}
private async executeOnce(request: FrontendActionRequest): Promise<FrontendActionResult> {
if (Date.now() >= request.expiresAt) return this.failure(request, "expired", "ACTION_EXPIRED", "frontend action expired before execution");
const controller = new AbortController();
this.controllers.set(request.actionId, controller);
private async executeOnce(
request: FrontendActionRequest,
controller: AbortController
): Promise<FrontendActionResult> {
const remaining = request.expiresAt - Date.now();
const timer =
remaining > 0
? setTimeout(
() => controller.abort(new DOMException("Action expired", "TimeoutError")),
remaining
)
: undefined;
try {
return { version: "frontend-action-result@1", actionId: request.actionId, status: "succeeded", output: await this.execute(request, controller.signal), completedAt: Date.now() };
controller.signal.throwIfAborted();
if (remaining <= 0)
return this.failure(
request,
"expired",
"ACTION_EXPIRED",
"frontend action expired before execution"
);
const output = await this.execute(request, controller.signal);
controller.signal.throwIfAborted();
return {
version: "frontend-action-result@2",
actionId: request.actionId,
status: "succeeded",
output,
completedAt: Date.now()
};
} catch (error) {
const expired =
controller.signal.reason instanceof DOMException &&
controller.signal.reason.name === "TimeoutError";
const message = error instanceof Error ? error.message : "frontend action failed";
const code = controller.signal.aborted ? "ACTION_CANCELLED" : ERROR_CODE_PATTERN.test(message) ? message : "ACTION_FAILED";
return this.failure(request, controller.signal.aborted ? "cancelled" : "failed", code, message);
const code = expired
? "ACTION_EXPIRED"
: controller.signal.aborted
? "ACTION_CANCELLED"
: ERROR_CODE_PATTERN.test(message)
? message
: "ACTION_FAILED";
return this.failure(
request,
expired ? "expired" : controller.signal.aborted ? "cancelled" : "failed",
code,
message
);
} finally {
this.controllers.delete(request.actionId);
clearTimeout(timer);
if (this.controllers.get(request.actionId) === controller)
this.controllers.delete(request.actionId);
}
}
private failure(request: FrontendActionRequest, status: "failed" | "cancelled" | "expired", code: string, message: string): FrontendActionResult {
return { version: "frontend-action-result@1", actionId: request.actionId, status, error: { code, message }, completedAt: Date.now() };
private failure(
request: FrontendActionRequest,
status: "failed" | "cancelled" | "expired",
code: string,
message: string
): FrontendActionResult {
return {
version: "frontend-action-result@2",
actionId: request.actionId,
status,
error: { code, message },
completedAt: Date.now()
};
}
}