mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Finalize strict ESLint fixes
This commit is contained in:
parent
f172610277
commit
2918451eaf
9 changed files with 145 additions and 106 deletions
|
|
@ -201,13 +201,7 @@ export class PanelController {
|
|||
} else if (method === "hook/completed") {
|
||||
this.upsertHookRun(params.run, params.turnId, params.run.status);
|
||||
} else if (method === "item/mcpToolCall/progress") {
|
||||
this.state.displayItems = appendToolOutput(
|
||||
this.state.displayItems,
|
||||
params.itemId,
|
||||
params.turnId,
|
||||
params.message,
|
||||
"mcp progress",
|
||||
);
|
||||
this.state.displayItems = appendToolOutput(this.state.displayItems, params.itemId, params.turnId, params.message, "mcp progress");
|
||||
} else if (method === "item/autoApprovalReview/started" || method === "item/autoApprovalReview/completed") {
|
||||
const reviewItem = createAutoReviewResultItem(params);
|
||||
this.state.displayItems = upsertDisplayItem(removeUnstructuredAutoReviewWarnings(this.state.displayItems), reviewItem);
|
||||
|
|
@ -427,6 +421,7 @@ export class PanelController {
|
|||
this.state.activeReasoningEffort = settings.effort;
|
||||
this.state.activeCollaborationMode = settings.collaborationMode.mode;
|
||||
this.state.requestedCollaborationMode = settings.collaborationMode.mode;
|
||||
const nullableSettings: ThreadSettingsWithNullableReviewer = settings;
|
||||
const serviceTierOverride = this.state.activeServiceTierOverride || this.state.requestedServiceTier !== null;
|
||||
const approvalsReviewerOverride = this.state.activeApprovalsReviewerOverride || this.state.requestedApprovalsReviewer !== null;
|
||||
this.state.activeServiceTier = settings.serviceTier ?? (serviceTierOverride ? this.state.activeServiceTier : null);
|
||||
|
|
@ -437,6 +432,11 @@ export class PanelController {
|
|||
}
|
||||
}
|
||||
|
||||
type ThreadSettings = Extract<ServerNotification, { method: "thread/settings/updated" }>["params"]["threadSettings"];
|
||||
type ThreadSettingsWithNullableReviewer = Omit<ThreadSettings, "approvalsReviewer"> & {
|
||||
approvalsReviewer: ThreadSettings["approvalsReviewer"] | null;
|
||||
};
|
||||
|
||||
function removeUnstructuredAutoReviewWarnings(items: DisplayItem[]): DisplayItem[] {
|
||||
return items.filter((item) => !isUnstructuredAutoReviewWarning(item));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,9 +105,12 @@ export async function generateThreadTitleWithCodex(
|
|||
|
||||
let client!: AppServerClient;
|
||||
client = new AppServerClient(codexPath, cwd, {
|
||||
onNotification: (notification) => { handleNamingNotification(notification); },
|
||||
onServerRequest: (request) =>
|
||||
{ client.rejectServerRequest(request.id, -32601, "Thread title generation does not handle server requests."); },
|
||||
onNotification: (notification) => {
|
||||
handleNamingNotification(notification);
|
||||
},
|
||||
onServerRequest: (request) => {
|
||||
client.rejectServerRequest(request.id, -32601, "Thread title generation does not handle server requests.");
|
||||
},
|
||||
onLog: () => undefined,
|
||||
onExit: () => {
|
||||
if (completed) return;
|
||||
|
|
|
|||
|
|
@ -930,6 +930,7 @@ export class CodexPanelView extends ItemView {
|
|||
this.render();
|
||||
|
||||
await this.ensureConnected();
|
||||
if (!threadId) return;
|
||||
try {
|
||||
await this.resumeThread(threadId);
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -212,8 +212,12 @@ function renderHookRow(list: HTMLElement, hook: HookMetadata, state: HookSection
|
|||
});
|
||||
}
|
||||
|
||||
function firstNonEmptyString(...values: string[]): string {
|
||||
return values.find((value) => value.length > 0) ?? values.at(-1) ?? "";
|
||||
function firstNonEmptyString(...values: (string | null | undefined)[]): string {
|
||||
return (
|
||||
values.find((value): value is string => typeof value === "string" && value.length > 0) ??
|
||||
values.find((value): value is string => typeof value === "string") ??
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
function formatThreadDate(timestamp: number): string {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,12 @@ export interface MessageStreamContext {
|
|||
renderPendingRequests?: () => HTMLElement | null;
|
||||
}
|
||||
|
||||
type RenderableMessageItem = Extract<DisplayItem, { kind: "message" | "system" | "userInputResult" }>;
|
||||
|
||||
function isRenderableMessageItem(item: DisplayItem): item is RenderableMessageItem {
|
||||
return item.kind === "message" || item.kind === "system" || item.kind === "userInputResult";
|
||||
}
|
||||
|
||||
export function messageRenderBlocks(context: MessageStreamContext): MessageRenderBlock[] {
|
||||
const blocks: MessageRenderBlock[] = [];
|
||||
|
||||
|
|
@ -212,6 +218,9 @@ function renderDisplayItem(parent: HTMLElement, item: DisplayItem, context: Mess
|
|||
renderToolResult(parent, item, context);
|
||||
return;
|
||||
}
|
||||
if (!isRenderableMessageItem(item)) {
|
||||
return;
|
||||
}
|
||||
const messageEl = parent.createDiv({ cls: messageClass(item) });
|
||||
applyExecutionStateClass(messageEl, executionState(item));
|
||||
const role = messageEl.createDiv({ cls: "codex-panel__message-role" });
|
||||
|
|
|
|||
|
|
@ -107,12 +107,16 @@ export function toolbarSignature(model: ToolbarViewModel): string {
|
|||
openPanel: model.openPanel,
|
||||
threads: model.threads.map(
|
||||
(thread) =>
|
||||
`${thread.threadId}:${thread.title}:${String(thread.selected)}:${String(thread.disabled)}:${String(thread.canArchive)}:${thread.rename?.draft ?? ""}:${
|
||||
String(thread.rename?.generating ?? false)
|
||||
}`,
|
||||
`${thread.threadId}:${thread.title}:${String(thread.selected)}:${String(thread.disabled)}:${String(thread.canArchive)}:${thread.rename?.draft ?? ""}:${String(
|
||||
thread.rename?.generating ?? false,
|
||||
)}`,
|
||||
),
|
||||
modelChoices: model.modelChoices.map(
|
||||
(choice) => `${choice.label}:${String(choice.selected)}:${String(choice.disabled)}:${choice.meta ?? ""}`,
|
||||
),
|
||||
effortChoices: model.effortChoices.map(
|
||||
(choice) => `${choice.label}:${String(choice.selected)}:${String(choice.disabled)}:${choice.meta ?? ""}`,
|
||||
),
|
||||
modelChoices: model.modelChoices.map((choice) => `${choice.label}:${String(choice.selected)}:${String(choice.disabled)}:${choice.meta ?? ""}`),
|
||||
effortChoices: model.effortChoices.map((choice) => `${choice.label}:${String(choice.selected)}:${String(choice.disabled)}:${choice.meta ?? ""}`),
|
||||
connectLabel: model.connectLabel,
|
||||
diagnostics: model.diagnostics.map((section) => ({
|
||||
title: section.title,
|
||||
|
|
|
|||
|
|
@ -95,47 +95,53 @@ describe("approval model", () => {
|
|||
});
|
||||
|
||||
it("shows approval reasons first in pending request summaries", () => {
|
||||
const command = expectPresent(toPendingApproval({
|
||||
id: 20,
|
||||
method: "item/commandExecution/requestApproval",
|
||||
params: {
|
||||
command: "npm run build",
|
||||
cwd: "/tmp/project",
|
||||
threadId: "thread",
|
||||
turnId: "turn",
|
||||
itemId: "command",
|
||||
startedAtMs: 1,
|
||||
reason: "Needs unsandboxed access",
|
||||
commandActions: [],
|
||||
proposedExecpolicyAmendment: null,
|
||||
proposedNetworkPolicyAmendments: [],
|
||||
},
|
||||
}));
|
||||
const fileChange = expectPresent(toPendingApproval({
|
||||
id: 21,
|
||||
method: "item/fileChange/requestApproval",
|
||||
params: {
|
||||
threadId: "thread",
|
||||
turnId: "turn",
|
||||
itemId: "file",
|
||||
startedAtMs: 1,
|
||||
reason: "Write outside workspace",
|
||||
grantRoot: "/tmp/project",
|
||||
},
|
||||
}));
|
||||
const permissions = expectPresent(toPendingApproval({
|
||||
id: 22,
|
||||
method: "item/permissions/requestApproval",
|
||||
params: {
|
||||
cwd: "/tmp/project",
|
||||
threadId: "thread",
|
||||
turnId: "turn",
|
||||
itemId: "permissions",
|
||||
startedAtMs: 1,
|
||||
reason: "Need network",
|
||||
permissions: { network: { enabled: true }, fileSystem: null },
|
||||
},
|
||||
}));
|
||||
const command = expectPresent(
|
||||
toPendingApproval({
|
||||
id: 20,
|
||||
method: "item/commandExecution/requestApproval",
|
||||
params: {
|
||||
command: "npm run build",
|
||||
cwd: "/tmp/project",
|
||||
threadId: "thread",
|
||||
turnId: "turn",
|
||||
itemId: "command",
|
||||
startedAtMs: 1,
|
||||
reason: "Needs unsandboxed access",
|
||||
commandActions: [],
|
||||
proposedExecpolicyAmendment: null,
|
||||
proposedNetworkPolicyAmendments: [],
|
||||
},
|
||||
}),
|
||||
);
|
||||
const fileChange = expectPresent(
|
||||
toPendingApproval({
|
||||
id: 21,
|
||||
method: "item/fileChange/requestApproval",
|
||||
params: {
|
||||
threadId: "thread",
|
||||
turnId: "turn",
|
||||
itemId: "file",
|
||||
startedAtMs: 1,
|
||||
reason: "Write outside workspace",
|
||||
grantRoot: "/tmp/project",
|
||||
},
|
||||
}),
|
||||
);
|
||||
const permissions = expectPresent(
|
||||
toPendingApproval({
|
||||
id: 22,
|
||||
method: "item/permissions/requestApproval",
|
||||
params: {
|
||||
cwd: "/tmp/project",
|
||||
threadId: "thread",
|
||||
turnId: "turn",
|
||||
itemId: "permissions",
|
||||
startedAtMs: 1,
|
||||
reason: "Need network",
|
||||
permissions: { network: { enabled: true }, fileSystem: null },
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(approvalSummary(command)).toBe("Needs unsandboxed access\nnpm run build");
|
||||
expect(approvalSummary(fileChange)).toBe("Write outside workspace\ngrant root: /tmp/project");
|
||||
|
|
@ -143,19 +149,21 @@ describe("approval model", () => {
|
|||
});
|
||||
|
||||
it("keeps approval details semantic and omits raw payloads", () => {
|
||||
const approval = expectPresent(toPendingApproval({
|
||||
id: 23,
|
||||
method: "item/permissions/requestApproval",
|
||||
params: {
|
||||
cwd: "/tmp/project",
|
||||
threadId: "thread",
|
||||
turnId: "turn",
|
||||
itemId: "permissions",
|
||||
startedAtMs: 1,
|
||||
reason: "Need network",
|
||||
permissions: { network: { enabled: true }, fileSystem: null },
|
||||
},
|
||||
}));
|
||||
const approval = expectPresent(
|
||||
toPendingApproval({
|
||||
id: 23,
|
||||
method: "item/permissions/requestApproval",
|
||||
params: {
|
||||
cwd: "/tmp/project",
|
||||
threadId: "thread",
|
||||
turnId: "turn",
|
||||
itemId: "permissions",
|
||||
startedAtMs: 1,
|
||||
reason: "Need network",
|
||||
permissions: { network: { enabled: true }, fileSystem: null },
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(approvalDetails(approval)).toEqual([
|
||||
{ key: "reason", value: "Need network" },
|
||||
|
|
@ -165,22 +173,24 @@ describe("approval model", () => {
|
|||
});
|
||||
|
||||
it("omits empty approval detail rows", () => {
|
||||
const approval = expectPresent(toPendingApproval({
|
||||
id: 24,
|
||||
method: "item/commandExecution/requestApproval",
|
||||
params: {
|
||||
command: "npm test",
|
||||
cwd: "/tmp/project",
|
||||
threadId: "thread",
|
||||
turnId: "turn",
|
||||
itemId: "command",
|
||||
startedAtMs: 1,
|
||||
reason: null,
|
||||
commandActions: [],
|
||||
proposedExecpolicyAmendment: null,
|
||||
proposedNetworkPolicyAmendments: [],
|
||||
},
|
||||
}));
|
||||
const approval = expectPresent(
|
||||
toPendingApproval({
|
||||
id: 24,
|
||||
method: "item/commandExecution/requestApproval",
|
||||
params: {
|
||||
command: "npm test",
|
||||
cwd: "/tmp/project",
|
||||
threadId: "thread",
|
||||
turnId: "turn",
|
||||
itemId: "command",
|
||||
startedAtMs: 1,
|
||||
reason: null,
|
||||
commandActions: [],
|
||||
proposedExecpolicyAmendment: null,
|
||||
proposedNetworkPolicyAmendments: [],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(approvalDetails(approval)).toEqual([
|
||||
{ key: "command", value: "npm test" },
|
||||
|
|
|
|||
|
|
@ -310,6 +310,12 @@ function ensureElementHelpers(): void {
|
|||
};
|
||||
}
|
||||
|
||||
function nodeConstructor(): typeof Node {
|
||||
const defaultView = document.defaultView;
|
||||
if (defaultView === null) throw new Error("Expected document.defaultView to install Obsidian DOM helpers.");
|
||||
return (globalThis as typeof globalThis & { Node?: typeof Node }).Node ?? defaultView.Node;
|
||||
}
|
||||
|
||||
function applyOptions(element: HTMLElement, options: ElementOptions): void {
|
||||
if (Array.isArray(options.cls)) {
|
||||
element.classList.add(...options.cls.filter(Boolean));
|
||||
|
|
|
|||
|
|
@ -40,25 +40,27 @@ describe("user input model", () => {
|
|||
});
|
||||
|
||||
it("signs pending request content and drafts deterministically", () => {
|
||||
const input = expectPresent(toPendingUserInput({
|
||||
id: 7,
|
||||
method: "item/tool/requestUserInput",
|
||||
params: {
|
||||
threadId: "thread",
|
||||
turnId: "turn",
|
||||
itemId: "item",
|
||||
questions: [
|
||||
{
|
||||
id: "direction",
|
||||
header: "Direction",
|
||||
question: "Which way?",
|
||||
isOther: true,
|
||||
isSecret: false,
|
||||
options: [{ label: "Recommended", description: "Use the default path" }],
|
||||
},
|
||||
],
|
||||
},
|
||||
}));
|
||||
const input = expectPresent(
|
||||
toPendingUserInput({
|
||||
id: 7,
|
||||
method: "item/tool/requestUserInput",
|
||||
params: {
|
||||
threadId: "thread",
|
||||
turnId: "turn",
|
||||
itemId: "item",
|
||||
questions: [
|
||||
{
|
||||
id: "direction",
|
||||
header: "Direction",
|
||||
question: "Which way?",
|
||||
isOther: true,
|
||||
isSecret: false,
|
||||
options: [{ label: "Recommended", description: "Use the default path" }],
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
const drafts = new Map([
|
||||
["z", "last"],
|
||||
["a", "first"],
|
||||
|
|
|
|||
Loading…
Reference in a new issue