Project pending requests into domain models

This commit is contained in:
murashit 2026-06-21 15:55:02 +09:00
parent 380587e2be
commit 2e9d74167d
23 changed files with 363 additions and 245 deletions

View file

@ -1,159 +1,42 @@
import type { RequestId } from "../../generated/app-server/RequestId";
import type { ServerRequest } from "../../generated/app-server/ServerRequest";
type SimpleApprovalDecision = "accept" | "acceptForSession" | "decline" | "cancel";
type AppServerCommandApprovalDecision =
| SimpleApprovalDecision
| { acceptWithExecpolicyAmendment: unknown }
| { applyNetworkPolicyAmendment: { network_policy_amendment: { action: "allow" | "deny"; [key: string]: unknown } } };
type AppServerApprovalAction = "accept" | "accept-session" | "decline" | "cancel" | AppServerCommandApprovalDecisionAction;
interface AppServerCommandApprovalDecisionAction {
kind: "command-decision";
decision: AppServerCommandApprovalDecision;
}
import type {
ApprovalAction,
CommandApprovalDecision,
McpElicitationAction,
McpElicitationContentValue,
PendingApproval,
PendingMcpElicitation,
PendingMcpElicitationField,
PendingMcpElicitationOption,
PendingUserInput,
} from "../../domain/pending-requests/model";
type AppServerRequestByMethod<Method extends ServerRequest["method"]> = Extract<ServerRequest, { method: Method }>;
type AppServerRequestParams<Method extends ServerRequest["method"]> = AppServerRequestByMethod<Method>["params"];
type AppServerCommandApprovalParams = AppServerRequestParams<"item/commandExecution/requestApproval">;
type AppServerFileChangeApprovalParams = Omit<AppServerRequestParams<"item/fileChange/requestApproval">, "reason" | "grantRoot"> & {
reason: string | null;
grantRoot: string | null;
};
type AppServerPermissionsApprovalParams = AppServerRequestParams<"item/permissions/requestApproval">;
export type AppServerApproval =
| {
requestId: RequestId;
method: "item/commandExecution/requestApproval";
params: AppServerCommandApprovalParams;
}
| {
requestId: RequestId;
method: "item/fileChange/requestApproval";
params: AppServerFileChangeApprovalParams;
}
| {
requestId: RequestId;
method: "item/permissions/requestApproval";
params: AppServerPermissionsApprovalParams;
};
interface AppServerGrantedPermissionProfile {
network?: unknown;
fileSystem?: unknown;
}
type AppServerApprovalResponseSource =
| { method: "item/commandExecution/requestApproval" }
| { method: "item/fileChange/requestApproval" }
| { method: "item/permissions/requestApproval"; params: { permissions: { network?: unknown; fileSystem?: unknown } } };
export type AppServerApprovalResponse =
| { decision: AppServerCommandApprovalDecision }
| { decision: SimpleApprovalDecision }
| { decision: CommandApprovalDecision }
| { scope: "session" | "turn"; permissions: AppServerGrantedPermissionProfile };
type AppServerUserInputParams = AppServerRequestParams<"item/tool/requestUserInput">;
export interface AppServerUserInput {
requestId: RequestId;
method: "item/tool/requestUserInput";
params: AppServerUserInputParams;
}
export interface AppServerUserInputResponse {
answers: Record<string, { answers: string[] }>;
}
type AppServerMcpElicitationAction = "accept" | "decline" | "cancel";
type AppServerMcpElicitationContentValue = string | number | boolean | readonly string[] | null;
type AppServerMcpElicitationRequest = AppServerRequestByMethod<"mcpServer/elicitation/request">;
type AppServerMcpElicitationFormParams = Extract<AppServerMcpElicitationRequest["params"], { mode: "form" }>;
type AppServerMcpElicitationPrimitiveSchema = NonNullable<AppServerMcpElicitationFormParams["requestedSchema"]["properties"][string]>;
interface AppServerMcpElicitationOption {
value: string;
label: string;
}
interface AppServerMcpElicitationFieldBase {
id: string;
title: string;
description: string | null;
required: boolean;
}
type AppServerMcpElicitationField =
| (AppServerMcpElicitationFieldBase & {
type: "string";
format: string | null;
minLength: number | null;
maxLength: number | null;
defaultValue: string;
})
| (AppServerMcpElicitationFieldBase & {
type: "number" | "integer";
minimum: number | null;
maximum: number | null;
defaultValue: number | null;
})
| (AppServerMcpElicitationFieldBase & {
type: "boolean";
defaultValue: boolean;
})
| (AppServerMcpElicitationFieldBase & {
type: "single-select";
options: readonly AppServerMcpElicitationOption[];
defaultValue: string;
})
| (AppServerMcpElicitationFieldBase & {
type: "multi-select";
options: readonly AppServerMcpElicitationOption[];
minItems: number | null;
maxItems: number | null;
defaultValue: readonly string[];
});
interface AppServerMcpElicitationNormalizedFormParams {
threadId: string;
turnId: string | null;
serverName: string;
mode: "form";
message: string;
meta: unknown;
fields: readonly AppServerMcpElicitationField[];
}
interface AppServerMcpElicitationNormalizedUrlParams {
threadId: string;
turnId: string | null;
serverName: string;
mode: "url";
message: string;
meta: unknown;
url: string;
elicitationId: string;
}
export interface AppServerMcpElicitation {
requestId: RequestId;
method: "mcpServer/elicitation/request";
params: AppServerMcpElicitationNormalizedFormParams | AppServerMcpElicitationNormalizedUrlParams;
}
export interface AppServerMcpElicitationResponse {
action: AppServerMcpElicitationAction;
action: McpElicitationAction;
content: unknown;
_meta: unknown;
}
export function appServerApprovalRequest(request: ServerRequest): AppServerApproval | null {
export function appServerApprovalRequest(request: ServerRequest): PendingApproval | null {
switch (request.method) {
case "item/commandExecution/requestApproval":
return {
@ -182,13 +65,10 @@ export function appServerApprovalRequest(request: ServerRequest): AppServerAppro
}
}
export function appServerApprovalResponse(
approval: AppServerApprovalResponseSource,
action: AppServerApprovalAction,
): AppServerApprovalResponse {
export function appServerApprovalResponse(approval: PendingApproval, action: ApprovalAction): AppServerApprovalResponse {
if (approval.method === "item/commandExecution/requestApproval") {
return {
decision: isAppServerCommandDecisionAction(action) ? action.decision : commandDecision(action),
decision: isCommandDecisionAction(action) ? action.decision : commandDecision(action),
};
}
@ -204,7 +84,7 @@ export function appServerApprovalResponse(
};
}
export function appServerUserInputRequest(request: ServerRequest): AppServerUserInput | null {
export function appServerUserInputRequest(request: ServerRequest): PendingUserInput | null {
if (request.method !== "item/tool/requestUserInput") return null;
return {
requestId: request.id,
@ -229,7 +109,7 @@ export function appServerUserInputResponse(
};
}
export function appServerMcpElicitationRequest(request: ServerRequest): AppServerMcpElicitation | null {
export function appServerMcpElicitationRequest(request: ServerRequest): PendingMcpElicitation | null {
if (request.method !== "mcpServer/elicitation/request") return null;
const params = request.params;
if (params.mode === "url") {
@ -264,8 +144,8 @@ export function appServerMcpElicitationRequest(request: ServerRequest): AppServe
}
export function appServerMcpElicitationResponse(
action: AppServerMcpElicitationAction,
content: Record<string, AppServerMcpElicitationContentValue> | null,
action: McpElicitationAction,
content: Record<string, McpElicitationContentValue> | null,
): AppServerMcpElicitationResponse {
return {
action,
@ -274,18 +154,18 @@ export function appServerMcpElicitationResponse(
};
}
function isAppServerCommandDecisionAction(action: AppServerApprovalAction): action is AppServerCommandApprovalDecisionAction {
function isCommandDecisionAction(action: ApprovalAction): action is Extract<ApprovalAction, { kind: "command-decision" }> {
return typeof action === "object";
}
function commandDecision(action: AppServerApprovalAction): AppServerCommandApprovalDecision {
function commandDecision(action: ApprovalAction): CommandApprovalDecision {
if (action === "accept") return "accept";
if (action === "accept-session") return "acceptForSession";
if (action === "cancel") return "cancel";
return "decline";
}
function fileChangeDecision(action: AppServerApprovalAction): SimpleApprovalDecision {
function fileChangeDecision(action: ApprovalAction): CommandApprovalDecision {
if (action === "accept") return "accept";
if (action === "accept-session") return "acceptForSession";
if (action === "cancel") return "cancel";
@ -302,7 +182,7 @@ function grantedPermissions(requested: { network?: unknown; fileSystem?: unknown
function mcpElicitationFieldsFromSchema(
properties: Record<string, AppServerMcpElicitationPrimitiveSchema | undefined>,
required: ReadonlySet<string>,
): AppServerMcpElicitationField[] {
): PendingMcpElicitationField[] {
return Object.entries(properties).flatMap(([id, schema]) => {
if (!schema) return [];
return [mcpElicitationFieldFromSchema(id, schema, required.has(id))];
@ -313,7 +193,7 @@ function mcpElicitationFieldFromSchema(
id: string,
schema: AppServerMcpElicitationPrimitiveSchema,
required: boolean,
): AppServerMcpElicitationField {
): PendingMcpElicitationField {
const base = {
id,
title: schema.title ?? id,
@ -362,7 +242,7 @@ function mcpElicitationFieldFromSchema(
};
}
function singleSelectOptions(schema: Extract<AppServerMcpElicitationPrimitiveSchema, { type: "string" }>): AppServerMcpElicitationOption[] {
function singleSelectOptions(schema: Extract<AppServerMcpElicitationPrimitiveSchema, { type: "string" }>): PendingMcpElicitationOption[] {
if ("oneOf" in schema) return schema.oneOf.map((option) => ({ value: option.const, label: option.title }));
if ("enum" in schema) {
const enumNames = "enumNames" in schema ? schema.enumNames : undefined;
@ -372,7 +252,7 @@ function singleSelectOptions(schema: Extract<AppServerMcpElicitationPrimitiveSch
return [];
}
function multiSelectOptions(schema: Extract<AppServerMcpElicitationPrimitiveSchema, { type: "array" }>): AppServerMcpElicitationOption[] {
function multiSelectOptions(schema: Extract<AppServerMcpElicitationPrimitiveSchema, { type: "array" }>): PendingMcpElicitationOption[] {
if ("anyOf" in schema.items) return schema.items.anyOf.map((option) => ({ value: option.const, label: option.title }));
return schema.items.enum.map((value) => ({ value, label: value }));
}
@ -382,16 +262,16 @@ function bigintToNumberOrNull(value: bigint | number | undefined): number | null
return typeof value === "number" && Number.isFinite(value) ? value : null;
}
function toJsonContent(content: Record<string, AppServerMcpElicitationContentValue> | null): unknown {
function toJsonContent(content: Record<string, McpElicitationContentValue> | null): unknown {
if (!content) return null;
return Object.fromEntries(Object.entries(content).map(([key, value]) => [key, toJsonValue(value)]));
}
function toJsonValue(value: AppServerMcpElicitationContentValue): unknown {
function toJsonValue(value: McpElicitationContentValue): unknown {
if (isReadonlyStringArray(value)) return [...value];
return value;
}
function isReadonlyStringArray(value: AppServerMcpElicitationContentValue): value is readonly string[] {
function isReadonlyStringArray(value: McpElicitationContentValue): value is readonly string[] {
return Array.isArray(value);
}

View file

@ -0,0 +1,308 @@
export type PendingRequestId = string | number;
type SimpleApprovalDecision = "accept" | "acceptForSession" | "decline" | "cancel";
export type CommandApprovalDecision =
| SimpleApprovalDecision
| { acceptWithExecpolicyAmendment: unknown }
| { applyNetworkPolicyAmendment: { network_policy_amendment: { action: "allow" | "deny"; [key: string]: unknown } } };
interface CommandApprovalParams {
threadId: string;
turnId: string;
itemId: string;
startedAtMs: number;
approvalId?: string | null;
reason?: string | null;
networkApprovalContext?: unknown;
command?: string | null;
cwd?: string | null;
commandActions?: unknown[] | null;
additionalPermissions?: unknown;
proposedExecpolicyAmendment?: unknown;
proposedNetworkPolicyAmendments?: unknown[] | null;
availableDecisions?: CommandApprovalDecision[] | null;
}
interface FileChangeApprovalParams {
threadId: string;
turnId: string;
itemId: string;
startedAtMs: number;
reason: string | null;
grantRoot: string | null;
}
interface PermissionProfile {
network?: { enabled?: boolean | null } | null;
fileSystem?: {
entries?: readonly { path: unknown; access?: unknown }[] | null;
read?: unknown;
write?: unknown;
globScanMaxDepth?: unknown;
} | null;
}
interface PermissionsApprovalParams {
threadId: string;
turnId: string;
itemId: string;
startedAtMs: number;
reason: string | null;
cwd: string;
environmentId: string | null;
permissions: PermissionProfile;
}
export type ApprovalAction = "accept" | "accept-session" | "decline" | "cancel" | CommandApprovalDecisionAction;
interface CommandApprovalDecisionAction {
kind: "command-decision";
decision: CommandApprovalDecision;
}
export type PendingApproval =
| {
requestId: PendingRequestId;
method: "item/commandExecution/requestApproval";
params: CommandApprovalParams;
}
| {
requestId: PendingRequestId;
method: "item/fileChange/requestApproval";
params: FileChangeApprovalParams;
}
| {
requestId: PendingRequestId;
method: "item/permissions/requestApproval";
params: PermissionsApprovalParams;
};
interface PendingUserInputOption {
label: string;
description: string;
}
export interface PendingUserInputQuestion {
id: string;
header: string;
question: string;
isOther: boolean;
isSecret: boolean;
options: PendingUserInputOption[] | null;
}
interface PendingUserInputParams {
threadId: string;
turnId: string;
itemId: string;
questions: PendingUserInputQuestion[];
autoResolutionMs: number | null;
}
export interface PendingUserInput {
requestId: PendingRequestId;
method: "item/tool/requestUserInput";
params: PendingUserInputParams;
}
export type McpElicitationAction = "accept" | "decline" | "cancel";
export type McpElicitationContentValue = string | number | boolean | readonly string[] | null;
export interface PendingMcpElicitationOption {
value: string;
label: string;
}
interface PendingMcpElicitationFieldBase {
id: string;
title: string;
description: string | null;
required: boolean;
}
export type PendingMcpElicitationField =
| (PendingMcpElicitationFieldBase & {
type: "string";
format: string | null;
minLength: number | null;
maxLength: number | null;
defaultValue: string;
})
| (PendingMcpElicitationFieldBase & {
type: "number" | "integer";
minimum: number | null;
maximum: number | null;
defaultValue: number | null;
})
| (PendingMcpElicitationFieldBase & {
type: "boolean";
defaultValue: boolean;
})
| (PendingMcpElicitationFieldBase & {
type: "single-select";
options: readonly PendingMcpElicitationOption[];
defaultValue: string;
})
| (PendingMcpElicitationFieldBase & {
type: "multi-select";
options: readonly PendingMcpElicitationOption[];
minItems: number | null;
maxItems: number | null;
defaultValue: readonly string[];
});
interface PendingMcpElicitationFormParams {
threadId: string;
turnId: string | null;
serverName: string;
mode: "form";
message: string;
meta: unknown;
fields: readonly PendingMcpElicitationField[];
}
interface PendingMcpElicitationUrlParams {
threadId: string;
turnId: string | null;
serverName: string;
mode: "url";
message: string;
meta: unknown;
url: string;
elicitationId: string;
}
export interface PendingMcpElicitation {
requestId: PendingRequestId;
method: "mcpServer/elicitation/request";
params: PendingMcpElicitationFormParams | PendingMcpElicitationUrlParams;
}
export function approvalActionKind(action: ApprovalAction): "accept" | "accept-session" | "decline" | "cancel" {
if (!isCommandDecisionAction(action)) return action;
const decision = action.decision;
if (typeof decision === "string") return simpleApprovalActionKind(decision);
if ("acceptWithExecpolicyAmendment" in decision) return "accept-session";
if ("applyNetworkPolicyAmendment" in decision) {
return decision.applyNetworkPolicyAmendment.network_policy_amendment.action === "allow" ? "accept-session" : "decline";
}
return "decline";
}
function simpleApprovalActionKind(decision: string): "accept" | "accept-session" | "decline" | "cancel" {
if (decision === "accept") return "accept";
if (decision === "acceptForSession") return "accept-session";
if (decision === "cancel") return "cancel";
return "decline";
}
function isCommandDecisionAction(action: ApprovalAction): action is CommandApprovalDecisionAction {
return typeof action === "object";
}
export function questionDefaultAnswer(question: PendingUserInputQuestion): string {
return question.options?.[0]?.label ?? "";
}
export function userInputDraftKey(requestId: PendingRequestId, questionId: string): string {
return pendingRequestDerivedKey(requestId, questionId);
}
export function userInputOtherDraftKey(requestId: PendingRequestId, questionId: string): string {
return pendingRequestDerivedKey(requestId, `${questionId}:other`);
}
export function mcpElicitationDraftKey(requestId: PendingRequestId, fieldId: string): string {
return pendingRequestDerivedKey(requestId, `mcp:${fieldId}`);
}
export function approvalDetailsDisclosureId(requestId: PendingRequestId): string {
return pendingRequestDerivedKey(requestId, "details");
}
export function pendingRequestDerivedKeyPrefix(requestId: PendingRequestId): string {
return `${String(requestId)}:`;
}
function pendingRequestDerivedKey(requestId: PendingRequestId, suffix: string): string {
return `${pendingRequestDerivedKeyPrefix(requestId)}${suffix}`;
}
export function answersForPendingUserInput(input: PendingUserInput, drafts: ReadonlyMap<string, string>): Record<string, string> {
return Object.fromEntries(
input.params.questions.map((question) => [
question.id,
drafts.get(userInputDraftKey(input.requestId, question.id)) ?? questionDefaultAnswer(question),
]),
);
}
export function contentForPendingMcpElicitation(
elicitation: PendingMcpElicitation,
drafts: ReadonlyMap<string, string>,
): Record<string, McpElicitationContentValue> | null {
if (elicitation.params.mode !== "form") return null;
return Object.fromEntries(
elicitation.params.fields.map((field) => [
field.id,
mcpElicitationFieldValue(field, drafts.get(mcpElicitationDraftKey(elicitation.requestId, field.id))),
]),
);
}
export function mcpElicitationFieldDefaultDraft(field: PendingMcpElicitationField): string {
switch (field.type) {
case "boolean":
return field.defaultValue ? "true" : "false";
case "multi-select":
return JSON.stringify(field.defaultValue);
case "number":
case "integer":
return field.defaultValue === null ? "" : String(field.defaultValue);
default:
return field.defaultValue;
}
}
function mcpElicitationFieldValue(field: PendingMcpElicitationField, draftValue: string | undefined): McpElicitationContentValue {
const draft = draftValue ?? mcpElicitationFieldDefaultDraft(field);
switch (field.type) {
case "boolean":
return draft === "true";
case "number":
case "integer":
return numericMcpElicitationFieldValue(field, draft);
case "multi-select":
return multiSelectMcpElicitationFieldValue(field, draft);
default:
return draft;
}
}
function numericMcpElicitationFieldValue(
field: Extract<PendingMcpElicitationField, { type: "number" | "integer" }>,
draft: string,
): number | null {
if (draft.trim() === "") return null;
const parsed = field.type === "integer" ? Number.parseInt(draft, 10) : Number(draft);
if (Number.isFinite(parsed)) return parsed;
return field.defaultValue;
}
function multiSelectMcpElicitationFieldValue(
field: Extract<PendingMcpElicitationField, { type: "multi-select" }>,
draft: string,
): readonly string[] {
try {
const parsed = JSON.parse(draft) as unknown;
if (Array.isArray(parsed)) {
const allowed = new Set(field.options.map((option) => option.value));
return parsed.filter((value): value is string => typeof value === "string" && allowed.has(value));
}
} catch {
// Fall through to schema default when a stale draft cannot be parsed.
}
return field.defaultValue;
}

View file

@ -16,7 +16,7 @@ import {
type PendingMcpElicitation,
type PendingRequestId,
type PendingUserInput,
} from "../../domain/pending-requests/model";
} from "../../../../domain/pending-requests/model";
import { approvalResponse } from "../requests/approval";
import { mcpElicitationResponse } from "../requests/mcp-elicitation";
import { userInputResponse } from "../requests/user-input";

View file

@ -1,5 +1,5 @@
import type { ServerNotification, ServerRequest } from "../../../../app-server/connection/rpc-messages";
import type { PendingApproval, PendingMcpElicitation, PendingUserInput } from "../../domain/pending-requests/model";
import type { PendingApproval, PendingMcpElicitation, PendingUserInput } from "../../../../domain/pending-requests/model";
import { toPendingApproval } from "../requests/approval";
import { toPendingMcpElicitation } from "../requests/mcp-elicitation";
import { toPendingUserInput } from "../requests/user-input";

View file

@ -2,54 +2,12 @@ import type { ServerRequest } from "../../../../app-server/connection/rpc-messag
import {
appServerApprovalRequest,
appServerApprovalResponse,
type AppServerApproval,
type AppServerApprovalResponse,
} from "../../../../app-server/protocol/server-requests";
import type { ApprovalAction, PendingApproval } from "../../domain/pending-requests/model";
import type { ApprovalAction, PendingApproval } from "../../../../domain/pending-requests/model";
export function toPendingApproval(request: ServerRequest): PendingApproval | null {
const approval = appServerApprovalRequest(request);
if (!approval) return null;
switch (approval.method) {
case "item/commandExecution/requestApproval":
return pendingApproval(approval);
case "item/fileChange/requestApproval":
return pendingApproval(approval);
case "item/permissions/requestApproval":
return pendingApproval(approval);
}
}
function pendingApproval(
request: Extract<AppServerApproval, { method: "item/commandExecution/requestApproval" }>,
): Extract<PendingApproval, { method: "item/commandExecution/requestApproval" }>;
function pendingApproval(
request: Extract<AppServerApproval, { method: "item/fileChange/requestApproval" }>,
): Extract<PendingApproval, { method: "item/fileChange/requestApproval" }>;
function pendingApproval(
request: Extract<AppServerApproval, { method: "item/permissions/requestApproval" }>,
): Extract<PendingApproval, { method: "item/permissions/requestApproval" }>;
function pendingApproval(request: AppServerApproval): PendingApproval {
switch (request.method) {
case "item/commandExecution/requestApproval":
return {
requestId: request.requestId,
method: request.method,
params: request.params,
};
case "item/fileChange/requestApproval":
return {
requestId: request.requestId,
method: request.method,
params: request.params,
};
case "item/permissions/requestApproval":
return {
requestId: request.requestId,
method: request.method,
params: request.params,
};
}
return appServerApprovalRequest(request);
}
export function approvalResponse(approval: PendingApproval, action: ApprovalAction): AppServerApprovalResponse {

View file

@ -4,28 +4,10 @@ import {
appServerMcpElicitationResponse,
type AppServerMcpElicitationResponse,
} from "../../../../app-server/protocol/server-requests";
import type { McpElicitationAction, McpElicitationContentValue, PendingMcpElicitation } from "../../domain/pending-requests/model";
import type { McpElicitationAction, McpElicitationContentValue, PendingMcpElicitation } from "../../../../domain/pending-requests/model";
export function toPendingMcpElicitation(request: ServerRequest): PendingMcpElicitation | null {
const elicitation = appServerMcpElicitationRequest(request);
if (!elicitation) return null;
if (elicitation.params.mode === "url") {
return {
requestId: elicitation.requestId,
method: elicitation.method,
params: {
...elicitation.params,
},
};
}
return {
requestId: elicitation.requestId,
method: elicitation.method,
params: {
...elicitation.params,
fields: elicitation.params.fields,
},
};
return appServerMcpElicitationRequest(request);
}
export function mcpElicitationResponse(

View file

@ -4,16 +4,10 @@ import {
appServerUserInputResponse,
type AppServerUserInputResponse,
} from "../../../../app-server/protocol/server-requests";
import type { PendingUserInput } from "../../domain/pending-requests/model";
import type { PendingUserInput } from "../../../../domain/pending-requests/model";
export function toPendingUserInput(request: ServerRequest): PendingUserInput | null {
const userInputRequest = appServerUserInputRequest(request);
if (!userInputRequest) return null;
return {
requestId: userInputRequest.requestId,
method: userInputRequest.method,
params: userInputRequest.params,
};
return appServerUserInputRequest(request);
}
export function userInputResponse(input: PendingUserInput, answers: Record<string, string>): AppServerUserInputResponse {

View file

@ -5,9 +5,9 @@ import type {
PendingMcpElicitation,
PendingRequestId,
PendingUserInput,
} from "../../domain/pending-requests/model";
} from "../../../../domain/pending-requests/model";
export type { PendingRequestId } from "../../domain/pending-requests/model";
export type { PendingRequestId } from "../../../../domain/pending-requests/model";
export interface PendingRequestBlockState {
approvals: readonly PendingApproval[];

View file

@ -8,7 +8,7 @@ import {
type PendingApproval,
type PendingMcpElicitation,
type PendingUserInput,
} from "../../domain/pending-requests/model";
} from "../../../../domain/pending-requests/model";
import type { PendingRequestBlockActions, PendingRequestBlockState, PendingRequestId } from "./block";
import type { ChatState } from "../state/root-reducer";

View file

@ -6,7 +6,7 @@ import {
type PendingMcpElicitation,
type PendingRequestId,
type PendingUserInput,
} from "../../domain/pending-requests/model";
} from "../../../../domain/pending-requests/model";
export interface ChatRequestState {
readonly approvals: readonly PendingApproval[];

View file

@ -1,7 +1,7 @@
import { jsonPreview } from "../../../../utils";
import { pathRelativeToRoot } from "../message-stream/format/path-labels";
import { permissionRows, type MessageStreamPermissionProfile } from "../message-stream/format/permission-rows";
import type { PendingApproval } from "./model";
import type { PendingApproval } from "../../../../domain/pending-requests/model";
interface ApprovalSummaryParts {
reason: string | null;

View file

@ -6,7 +6,7 @@ import {
type PendingApproval,
type PendingMcpElicitation,
type PendingUserInput,
} from "./model";
} from "../../../../domain/pending-requests/model";
import { approvalDetails, approvalResultSummary, approvalTitle } from "./approval";
import type { MessageStreamItem, MessageStreamUserInputQuestionResult } from "../message-stream/items";
import { definedProp } from "../../../../utils";

View file

@ -1,4 +1,4 @@
import type { PendingApproval, PendingMcpElicitation, PendingUserInput } from "./model";
import type { PendingApproval, PendingMcpElicitation, PendingUserInput } from "../../../../domain/pending-requests/model";
export function pendingRequestsSignature(
approvals: readonly PendingApproval[],

View file

@ -3,7 +3,7 @@ import {
type ApprovalAction,
type CommandApprovalDecision,
type PendingApproval,
} from "../../domain/pending-requests/model";
} from "../../../../domain/pending-requests/model";
export interface ApprovalActionOption {
id: string;

View file

@ -1,4 +1,4 @@
import type { PendingApproval, PendingMcpElicitation, PendingUserInput } from "../../domain/pending-requests/model";
import type { PendingApproval, PendingMcpElicitation, PendingUserInput } from "../../../../domain/pending-requests/model";
import {
pendingApprovalViewModel,
pendingMcpElicitationViewModel,

View file

@ -11,7 +11,7 @@ import {
questionDefaultAnswer,
userInputDraftKey,
userInputOtherDraftKey,
} from "../../domain/pending-requests/model";
} from "../../../../domain/pending-requests/model";
type PendingRequestId = DomainPendingRequestId;

View file

@ -1,6 +1,6 @@
import type { ComponentChild as UiNode } from "preact";
import type { ApprovalAction, McpElicitationAction, PendingRequestId } from "../../domain/pending-requests/model";
import type { ApprovalAction, McpElicitationAction, PendingRequestId } from "../../../../domain/pending-requests/model";
import type { PendingRequestBlockSnapshot } from "../../presentation/pending-requests/snapshot";
import type { MessageStreamForkTarget } from "../../presentation/message-stream/text-view";
import type { PlanImplementationTarget } from "../../domain/message-stream/selectors";

View file

@ -1,7 +1,7 @@
import type { ComponentChild as UiNode } from "preact";
import { useEffect, useLayoutEffect, useRef, useState } from "preact/hooks";
import { approvalDetailsDisclosureId } from "../../domain/pending-requests/model";
import { approvalDetailsDisclosureId } from "../../../../domain/pending-requests/model";
import {
type PendingApprovalViewModel,
type PendingMcpElicitationFieldViewModel,

View file

@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
import { approvalResponse, toPendingApproval } from "../../../../../src/features/chat/app-server/requests/approval";
import { approvalDetails, approvalSummary, approvalTitle } from "../../../../../src/features/chat/domain/pending-requests/approval";
import type { CommandApprovalDecision } from "../../../../../src/features/chat/domain/pending-requests/model";
import type { CommandApprovalDecision } from "../../../../../src/domain/pending-requests/model";
import { approvalActionOptions } from "../../../../../src/features/chat/presentation/pending-requests/approval-view";
import type { ServerRequest } from "../../../../../src/app-server/connection/rpc-messages";

View file

@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
import type { ServerRequest } from "../../../../../src/app-server/connection/rpc-messages";
import { toPendingMcpElicitation, mcpElicitationResponse } from "../../../../../src/features/chat/app-server/requests/mcp-elicitation";
import { contentForPendingMcpElicitation, mcpElicitationDraftKey } from "../../../../../src/features/chat/domain/pending-requests/model";
import { contentForPendingMcpElicitation, mcpElicitationDraftKey } from "../../../../../src/domain/pending-requests/model";
function expectPresent<T>(value: T | null | undefined): T {
if (value === null || value === undefined) throw new Error("Expected value to be present");

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { answersForPendingUserInput, questionDefaultAnswer } from "../../../../../src/features/chat/domain/pending-requests/model";
import { answersForPendingUserInput, questionDefaultAnswer } from "../../../../../src/domain/pending-requests/model";
import { toPendingUserInput, userInputResponse } from "../../../../../src/features/chat/app-server/requests/user-input";
import {
pendingRequestFocusSignature,

View file

@ -7,11 +7,7 @@ import {
pendingApprovalViewModel,
pendingMcpElicitationViewModel,
} from "../../../../../src/features/chat/presentation/pending-requests/view-model";
import type {
PendingApproval,
PendingMcpElicitation,
PendingUserInput,
} from "../../../../../src/features/chat/domain/pending-requests/model";
import type { PendingApproval, PendingMcpElicitation, PendingUserInput } from "../../../../../src/domain/pending-requests/model";
import type { PendingRequestBlockContext } from "../../../../../src/features/chat/ui/message-stream/context";
import type { MessageStreamItem } from "../../../../../src/features/chat/domain/message-stream/items";
import { changeInputValue } from "../../../../support/dom";

View file

@ -2,7 +2,7 @@ import { vi } from "vitest";
import type { ComponentChild as UiNode } from "preact";
import { act } from "preact/test-utils";
import type { PendingApproval, PendingUserInput } from "../../../../../src/features/chat/domain/pending-requests/model";
import type { PendingApproval, PendingUserInput } from "../../../../../src/domain/pending-requests/model";
import { pendingRequestBlockSnapshotFromState } from "../../../../../src/features/chat/presentation/pending-requests/snapshot";
import { pendingRequestBlockNode } from "../../../../../src/features/chat/ui/message-stream/pending-request-block";
import { messageStreamBlocks as rawMessageStreamBlocks } from "../../../../../src/features/chat/ui/message-stream/stream-blocks";