mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Tighten app-server boundary contracts
This commit is contained in:
parent
2364664c2e
commit
859ccb2ac1
9 changed files with 33 additions and 32 deletions
|
|
@ -72,6 +72,7 @@
|
|||
"**/src/**/*.{ts,tsx}",
|
||||
"!**/src/app-server/connection/**",
|
||||
"!**/src/app-server/protocol/server-requests.ts",
|
||||
"!**/src/app-server/protocol/thread.ts",
|
||||
"!**/src/app-server/protocol/turn.ts"
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
import type { Thread, ThreadProvenance } from "../../domain/threads/model";
|
||||
import type { Thread as GeneratedThread } from "../../generated/app-server/v2/Thread";
|
||||
|
||||
export interface ThreadRecord {
|
||||
id: string;
|
||||
preview: string;
|
||||
name: string | null;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
recencyAt?: number | null;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
type RequiredThreadRecordFields = "id" | "preview" | "name" | "createdAt" | "updatedAt";
|
||||
|
||||
export type ThreadRecord = Pick<GeneratedThread, RequiredThreadRecordFields> &
|
||||
Partial<Omit<GeneratedThread, RequiredThreadRecordFields | "source" | "status" | "turns">> & {
|
||||
/** Kept unknown at the protocol edge so a newer SessionSource variant degrades to `other` instead of breaking thread lists. */
|
||||
source?: unknown;
|
||||
status?: unknown;
|
||||
turns?: readonly GeneratedThread["turns"][number][];
|
||||
};
|
||||
|
||||
export function threadFromThreadRecord(thread: ThreadRecord, options: { archived?: boolean } = {}): Thread {
|
||||
const hasRecencyAt = Object.hasOwn(thread, "recencyAt");
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import type { ThreadTokenUsage, TokenUsageBreakdown } from "../../domain/runtime
|
|||
const ROLLOUT_TOKEN_USAGE_READ_TIMEOUT_MS = 2_000;
|
||||
const ROLLOUT_TOKEN_USAGE_MAX_BASE64_BYTES = 12 * 1024 * 1024;
|
||||
|
||||
export type RolloutReadFileBase64 = (path: string, options: { timeoutMs: number }) => Promise<string>;
|
||||
export type RolloutReadFileBase64 = (path: string, options: { timeoutMs: number }) => Promise<string | null>;
|
||||
|
||||
export async function recoverRolloutTokenUsage(
|
||||
path: string | null,
|
||||
|
|
@ -11,12 +11,13 @@ export async function recoverRolloutTokenUsage(
|
|||
): Promise<ThreadTokenUsage | null> {
|
||||
if (!path || !isAbsolutePath(path)) return null;
|
||||
|
||||
let dataBase64: string;
|
||||
let dataBase64: string | null;
|
||||
try {
|
||||
dataBase64 = await readFileBase64(path, { timeoutMs: ROLLOUT_TOKEN_USAGE_READ_TIMEOUT_MS });
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
if (dataBase64 === null) return null;
|
||||
if (dataBase64.length > ROLLOUT_TOKEN_USAGE_MAX_BASE64_BYTES) return null;
|
||||
|
||||
const text = decodeBase64Text(dataBase64);
|
||||
|
|
|
|||
|
|
@ -25,10 +25,6 @@ import type { AppServerRequestClient } from "./request-client";
|
|||
const THREAD_LIST_PAGE_LIMIT = 100;
|
||||
|
||||
export type ThreadTurnSortDirection = "asc" | "desc";
|
||||
export type TurnTranscriptSummaryClient = AppServerRequestClient;
|
||||
export type ThreadForkClient = AppServerRequestClient;
|
||||
export type ThreadRollbackClient = AppServerRequestClient;
|
||||
export type ThreadCompactionClient = AppServerRequestClient;
|
||||
|
||||
interface TurnTranscriptSummaryPage {
|
||||
summaries: TurnTranscriptSummary[];
|
||||
|
|
@ -165,7 +161,7 @@ export async function readThreadForArchiveExport(client: AppServerRequestClient,
|
|||
}
|
||||
|
||||
export async function readCompletedTurnTranscriptSummariesPage(
|
||||
client: TurnTranscriptSummaryClient,
|
||||
client: AppServerRequestClient,
|
||||
threadId: string,
|
||||
cursor: string | null,
|
||||
limit: number,
|
||||
|
|
@ -179,7 +175,7 @@ export async function readCompletedTurnTranscriptSummariesPage(
|
|||
}
|
||||
|
||||
export async function readReferencedThreadTurnTranscriptSummaries(
|
||||
client: TurnTranscriptSummaryClient,
|
||||
client: AppServerRequestClient,
|
||||
threadId: string,
|
||||
limit = REFERENCED_THREAD_TURN_LIMIT,
|
||||
): Promise<TurnTranscriptSummary[]> {
|
||||
|
|
@ -208,13 +204,13 @@ function threadRollbackSnapshotFromAppServerResponse(response: ThreadRollbackRes
|
|||
};
|
||||
}
|
||||
|
||||
export async function rollbackThread(client: ThreadRollbackClient, threadId: string, numTurns?: number): Promise<ThreadRollbackSnapshot> {
|
||||
export async function rollbackThread(client: AppServerRequestClient, threadId: string, numTurns?: number): Promise<ThreadRollbackSnapshot> {
|
||||
const response = await client.request("thread/rollback", { threadId, numTurns: numTurns ?? 1 });
|
||||
return threadRollbackSnapshotFromAppServerResponse(response);
|
||||
}
|
||||
|
||||
export async function forkThread(
|
||||
client: ThreadForkClient,
|
||||
client: AppServerRequestClient,
|
||||
threadId: string,
|
||||
cwd: string,
|
||||
lastTurnId: string | null = null,
|
||||
|
|
@ -234,7 +230,7 @@ export interface EphemeralThreadForkSnapshot {
|
|||
}
|
||||
|
||||
export async function forkEphemeralThread(
|
||||
client: ThreadForkClient,
|
||||
client: AppServerRequestClient,
|
||||
sourceThreadId: string,
|
||||
cwd: string,
|
||||
): Promise<EphemeralThreadForkSnapshot> {
|
||||
|
|
@ -252,7 +248,7 @@ export async function forkEphemeralThread(
|
|||
};
|
||||
}
|
||||
|
||||
export async function compactThread(client: ThreadCompactionClient, threadId: string): Promise<void> {
|
||||
export async function compactThread(client: AppServerRequestClient, threadId: string): Promise<void> {
|
||||
await client.request("thread/compact/start", { threadId });
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,8 +38,11 @@ export interface RuntimePermissionState {
|
|||
}
|
||||
|
||||
export interface RuntimePermissionKnownState {
|
||||
/** True when the active-thread layer is authoritative, including an authoritative null meaning the detail was not reported. */
|
||||
readonly approvalPolicyKnown: boolean;
|
||||
/** True prevents fallback to a different config profile's sandbox; null still displays as not reported. */
|
||||
readonly sandboxPolicyKnown: boolean;
|
||||
/** True when the active profile identity, including an authoritative null, supersedes config fallback. */
|
||||
readonly permissionProfileKnown: boolean;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ interface ChatThreadReferenceResolverOptions {
|
|||
export interface ChatAppServerGateway extends ChatSessionTransports, ChatMetadataTransports {
|
||||
clientAccess: AppServerClientAccess;
|
||||
connectionAvailable(): boolean;
|
||||
readFileBase64(path: string, options?: { timeoutMs?: number }): Promise<string>;
|
||||
readFileBase64(path: string, options?: { timeoutMs?: number }): Promise<string | null>;
|
||||
threadReferences(options: ChatThreadReferenceResolverOptions): ThreadReferenceResolver;
|
||||
}
|
||||
|
||||
|
|
@ -70,9 +70,9 @@ async function readCurrentClientFileBase64(
|
|||
host: ChatAppServerGatewayHost,
|
||||
path: string,
|
||||
options: { timeoutMs?: number } = {},
|
||||
): Promise<string> {
|
||||
): Promise<string | null> {
|
||||
const client = host.currentClient();
|
||||
if (!client) return "";
|
||||
if (!client) return null;
|
||||
const response = await client.request("fs/readFile", { path }, options);
|
||||
return host.currentClient() === client ? response.dataBase64 : "";
|
||||
return host.currentClient() === client ? response.dataBase64 : null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { readReferencedThreadTurnTranscriptSummaries, type TurnTranscriptSummaryClient } from "../../../app-server/services/threads";
|
||||
import type { AppServerRequestClient } from "../../../app-server/services/request-client";
|
||||
import { readReferencedThreadTurnTranscriptSummaries } from "../../../app-server/services/threads";
|
||||
import { type CodexInput, codexTextInputWithAttachments } from "../../../domain/chat/input";
|
||||
import { shortThreadId } from "../../../domain/threads/id";
|
||||
import type { Thread } from "../../../domain/threads/model";
|
||||
|
|
@ -7,7 +8,7 @@ import type { ComposerInputSnapshot } from "../application/composer/input-snapsh
|
|||
import type { ThreadReferenceInput } from "../application/turns/slash-command-execution";
|
||||
|
||||
interface ThreadReferenceResolverHost {
|
||||
currentClient(): TurnTranscriptSummaryClient | null;
|
||||
currentClient(): AppServerRequestClient | null;
|
||||
prepareInput(text: string, snapshot: ComposerInputSnapshot): { text: string; input: CodexInput };
|
||||
addSystemMessage(text: string): void;
|
||||
setStatus(status: string): void;
|
||||
|
|
|
|||
|
|
@ -45,9 +45,6 @@ interface ChatAppServerTransportHost extends ConnectedChatAppServerClientHost {
|
|||
vaultPath: string;
|
||||
}
|
||||
|
||||
type ChatThreadHistoryClient = AppServerRequestClient;
|
||||
type ChatThreadResumeClient = AppServerRequestClient;
|
||||
|
||||
interface AppServerThreadTurnsPage {
|
||||
readonly data: ThreadTurnsPage["turns"];
|
||||
readonly nextCursor: string | null;
|
||||
|
|
@ -244,7 +241,7 @@ async function withCurrentChatAppServerClient<T>(
|
|||
}
|
||||
|
||||
async function readChatThreadHistoryPage(
|
||||
client: ChatThreadHistoryClient,
|
||||
client: AppServerRequestClient,
|
||||
threadId: string,
|
||||
cursor: string | null,
|
||||
limit = 20,
|
||||
|
|
@ -260,7 +257,7 @@ function chatThreadHistoryPageFromTurnsPage(page: ThreadTurnsPage): ThreadHistor
|
|||
};
|
||||
}
|
||||
|
||||
async function resumeChatThread(client: ChatThreadResumeClient, threadId: string, cwd: string): Promise<ThreadResumeSnapshot> {
|
||||
async function resumeChatThread(client: AppServerRequestClient, threadId: string, cwd: string): Promise<ThreadResumeSnapshot> {
|
||||
const response = await resumeThread(client, threadId, cwd);
|
||||
return {
|
||||
activation: threadActivationSnapshotFromAppServerResponse(response),
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ describe("Biome Grit plugin wiring", () => {
|
|||
"**/src/**/*.{ts,tsx}",
|
||||
"!**/src/app-server/connection/**",
|
||||
"!**/src/app-server/protocol/server-requests.ts",
|
||||
"!**/src/app-server/protocol/thread.ts",
|
||||
"!**/src/app-server/protocol/turn.ts",
|
||||
]);
|
||||
expect(projectPluginIncludes("no-restricted-css-policy.grit")).toEqual(["**/src/styles/**/*.css"]);
|
||||
|
|
|
|||
Loading…
Reference in a new issue