mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Make index-signature access explicit
This commit is contained in:
parent
63086634df
commit
d77b7bf526
13 changed files with 63 additions and 60 deletions
|
|
@ -193,10 +193,7 @@ export class AppServerClient {
|
|||
}
|
||||
|
||||
setHookEnabled(hook: HookMetadata, enabled: boolean): Promise<ConfigWriteResponse> {
|
||||
const state: Record<string, JsonValue> = { enabled };
|
||||
if (hook.trustStatus === "trusted") {
|
||||
state.trusted_hash = hook.currentHash;
|
||||
}
|
||||
const state: Record<string, JsonValue> = hook.trustStatus === "trusted" ? { enabled, trusted_hash: hook.currentHash } : { enabled };
|
||||
return this.writeHookState(hook.key, state);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@ export function classifyAppServerLog(message: string): ClassifiedAppServerLog {
|
|||
const parsed = parseAppServerLog(normalized);
|
||||
if (!parsed) return null;
|
||||
|
||||
const level = logString(parsed.level).toUpperCase();
|
||||
const fields = parsed.fields && typeof parsed.fields === "object" ? (parsed.fields as Record<string, unknown>) : {};
|
||||
const text = stripAnsi(logString(fields.message, normalized));
|
||||
const target = logString(parsed.target);
|
||||
const level = logString(parsed["level"]).toUpperCase();
|
||||
const parsedFields = parsed["fields"];
|
||||
const fields = parsedFields && typeof parsedFields === "object" ? (parsedFields as Record<string, unknown>) : {};
|
||||
const text = stripAnsi(logString(fields["message"], normalized));
|
||||
const target = logString(parsed["target"]);
|
||||
if (target.includes("rmcp::transport::worker") && isMcpTokenRefreshLog(text)) return null;
|
||||
if (target.includes("codex_core::tools::router") && text.includes("apply_patch verification failed")) return null;
|
||||
if (level === "ERROR") return { kind: "error", text };
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ export class PanelSessionController {
|
|||
try {
|
||||
const response = await client.readAccountRateLimits();
|
||||
const rateLimitsByLimitId = response.rateLimitsByLimitId;
|
||||
const codexRateLimit = rateLimitsByLimitId && Object.hasOwn(rateLimitsByLimitId, "codex") ? rateLimitsByLimitId.codex : undefined;
|
||||
const codexRateLimit = rateLimitsByLimitId && Object.hasOwn(rateLimitsByLimitId, "codex") ? rateLimitsByLimitId["codex"] : undefined;
|
||||
this.host.state.rateLimit = codexRateLimit ?? response.rateLimits;
|
||||
} catch {
|
||||
this.host.state.rateLimit = null;
|
||||
|
|
|
|||
|
|
@ -43,8 +43,9 @@ export function configRecord(effectiveConfig: ConfigReadResponse | null): Record
|
|||
}
|
||||
|
||||
export function selectedProfileConfig(config: Record<string, unknown>): Record<string, unknown> {
|
||||
const profileName = typeof config.profile === "string" && config.profile.length > 0 ? config.profile : null;
|
||||
return profileName ? asRecord(asRecord(config.profiles)[profileName]) : {};
|
||||
const profile = config["profile"];
|
||||
const profileName = typeof profile === "string" && profile.length > 0 ? profile : null;
|
||||
return profileName ? asRecord(asRecord(config["profiles"])[profileName]) : {};
|
||||
}
|
||||
|
||||
export function resolvedConfigValue(config: Record<string, unknown>, key: string): unknown {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export interface EffectiveConfigSection {
|
|||
export function contextSummary(snapshot: RuntimeSnapshot): ContextSummary | null {
|
||||
const usage = snapshot.tokenUsage;
|
||||
const config = configRecord(snapshot.effectiveConfig);
|
||||
const contextWindow = usage?.modelContextWindow ?? toNumber(config.model_context_window);
|
||||
const contextWindow = usage?.modelContextWindow ?? toNumber(config["model_context_window"]);
|
||||
if (!usage) {
|
||||
if (!snapshot.activeThreadId) return null;
|
||||
if (!snapshot.displayItems.some((item) => item.turnId)) {
|
||||
|
|
@ -106,15 +106,15 @@ export function rateLimitSummary(snapshot: RuntimeSnapshot, nowMs = Date.now()):
|
|||
|
||||
export function effectiveConfigSections(snapshot: RuntimeSnapshot, vaultPath: string): EffectiveConfigSection[] {
|
||||
const config = configRecord(snapshot.effectiveConfig);
|
||||
const features = asRecord(config.features);
|
||||
const features = asRecord(config["features"]);
|
||||
const tools = asRecord(resolvedConfigValue(config, "tools"));
|
||||
const workspaceWrite = asRecord(config.sandbox_workspace_write);
|
||||
const workspaceWrite = asRecord(config["sandbox_workspace_write"]);
|
||||
return [
|
||||
{
|
||||
title: "Scope",
|
||||
rows: [
|
||||
{ key: "cwd", value: vaultPath },
|
||||
{ key: "profile", value: stringValue(config.profile, "(default)") },
|
||||
{ key: "profile", value: stringValue(config["profile"], "(default)") },
|
||||
{ key: "model provider", value: stringValue(resolvedConfigValue(config, "model_provider"), "(from default)") },
|
||||
],
|
||||
},
|
||||
|
|
@ -141,8 +141,8 @@ export function effectiveConfigSections(snapshot: RuntimeSnapshot, vaultPath: st
|
|||
{ key: "config service tier", value: configuredServiceTier(config) ?? "(not reported)" },
|
||||
{ key: "active service tier", value: activeRuntimeValueLabel(snapshot.activeServiceTier) },
|
||||
{ key: "fast mode", value: fastModeLabel(snapshot, config) },
|
||||
{ key: "context window", value: tokenLimitLabel(config.model_context_window) },
|
||||
{ key: "auto compact limit", value: tokenLimitLabel(config.model_auto_compact_token_limit) },
|
||||
{ key: "context window", value: tokenLimitLabel(config["model_context_window"]) },
|
||||
{ key: "auto compact limit", value: tokenLimitLabel(config["model_auto_compact_token_limit"]) },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
@ -156,19 +156,19 @@ export function effectiveConfigSections(snapshot: RuntimeSnapshot, vaultPath: st
|
|||
key: "active reviewer",
|
||||
value: activeRuntimeValueLabel(snapshot.activeApprovalsReviewer),
|
||||
},
|
||||
{ key: "sandbox", value: stringValue(config.sandbox_mode, "(from default)") },
|
||||
{ key: "workspace network", value: stringValue(workspaceWrite.network_access, "(from default)") },
|
||||
{ key: "writable roots", value: writableRootsLabel(workspaceWrite.writable_roots) },
|
||||
{ key: "sandbox", value: stringValue(config["sandbox_mode"], "(from default)") },
|
||||
{ key: "workspace network", value: stringValue(workspaceWrite["network_access"], "(from default)") },
|
||||
{ key: "writable roots", value: writableRootsLabel(workspaceWrite["writable_roots"]) },
|
||||
{ key: "web search", value: stringValue(resolvedConfigValue(config, "web_search"), "(from default)") },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Features",
|
||||
rows: [
|
||||
{ key: "hooks", value: stringValue(features.hooks, "(from default)") },
|
||||
{ key: "apply patch freeform", value: stringValue(features.apply_patch_freeform, "(from default)") },
|
||||
{ key: "tool web search", value: stringValue(tools.web_search, "(from default)") },
|
||||
{ key: "apps", value: enabledAppsLabel(config.apps) },
|
||||
{ key: "hooks", value: stringValue(features["hooks"], "(from default)") },
|
||||
{ key: "apply patch freeform", value: stringValue(features["apply_patch_freeform"], "(from default)") },
|
||||
{ key: "tool web search", value: stringValue(tools["web_search"], "(from default)") },
|
||||
{ key: "apps", value: enabledAppsLabel(config["apps"]) },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
@ -275,12 +275,12 @@ function writableRootsLabel(value: unknown): string {
|
|||
function enabledAppsLabel(value: unknown): string {
|
||||
const apps = asRecord(value);
|
||||
const enabled = Object.entries(apps)
|
||||
.filter(([key, app]) => key !== "_default" && asRecord(app).enabled === true)
|
||||
.filter(([key, app]) => key !== "_default" && asRecord(app)["enabled"] === true)
|
||||
.map(([key]) => key)
|
||||
.sort();
|
||||
if (enabled.length > 0) return enabled.join(", ");
|
||||
const defaultConfig = asRecord(apps._default);
|
||||
return stringValue(defaultConfig.enabled, "(from default)");
|
||||
const defaultConfig = asRecord(apps["_default"]);
|
||||
return stringValue(defaultConfig["enabled"], "(from default)");
|
||||
}
|
||||
|
||||
function asRecord(value: unknown): Record<string, unknown> {
|
||||
|
|
|
|||
|
|
@ -35,18 +35,21 @@ export const DEFAULT_SETTINGS: CodexPanelSettings = {
|
|||
export function normalizeSettings(data: unknown): CodexPanelSettings {
|
||||
const record = asRecord(data);
|
||||
return {
|
||||
codexPath: stringOrDefault(record.codexPath, DEFAULT_CODEX_PATH).trim() || DEFAULT_CODEX_PATH,
|
||||
threadNamingModel: threadNamingModelOrDefault(record.threadNamingModel),
|
||||
threadNamingEffort: reasoningEffortOrDefault(record.threadNamingEffort),
|
||||
rewriteSelectionModel: modelOrDefault(record.rewriteSelectionModel),
|
||||
rewriteSelectionEffort: reasoningEffortOrDefault(record.rewriteSelectionEffort),
|
||||
sendShortcut: sendShortcutOrDefault(record.sendShortcut),
|
||||
archiveExportEnabled: booleanOrDefault(record.archiveExportEnabled, DEFAULT_SETTINGS.archiveExportEnabled),
|
||||
archiveExportFolderTemplate: stringOrDefault(record.archiveExportFolderTemplate, DEFAULT_SETTINGS.archiveExportFolderTemplate).trim(),
|
||||
codexPath: stringOrDefault(record["codexPath"], DEFAULT_CODEX_PATH).trim() || DEFAULT_CODEX_PATH,
|
||||
threadNamingModel: threadNamingModelOrDefault(record["threadNamingModel"]),
|
||||
threadNamingEffort: reasoningEffortOrDefault(record["threadNamingEffort"]),
|
||||
rewriteSelectionModel: modelOrDefault(record["rewriteSelectionModel"]),
|
||||
rewriteSelectionEffort: reasoningEffortOrDefault(record["rewriteSelectionEffort"]),
|
||||
sendShortcut: sendShortcutOrDefault(record["sendShortcut"]),
|
||||
archiveExportEnabled: booleanOrDefault(record["archiveExportEnabled"], DEFAULT_SETTINGS.archiveExportEnabled),
|
||||
archiveExportFolderTemplate: stringOrDefault(
|
||||
record["archiveExportFolderTemplate"],
|
||||
DEFAULT_SETTINGS.archiveExportFolderTemplate,
|
||||
).trim(),
|
||||
archiveExportFilenameTemplate:
|
||||
stringOrDefault(record.archiveExportFilenameTemplate, DEFAULT_SETTINGS.archiveExportFilenameTemplate).trim() ||
|
||||
stringOrDefault(record["archiveExportFilenameTemplate"], DEFAULT_SETTINGS.archiveExportFilenameTemplate).trim() ||
|
||||
DEFAULT_SETTINGS.archiveExportFilenameTemplate,
|
||||
archiveExportTags: stringOrDefault(record.archiveExportTags, DEFAULT_SETTINGS.archiveExportTags).trim(),
|
||||
archiveExportTags: stringOrDefault(record["archiveExportTags"], DEFAULT_SETTINGS.archiveExportTags).trim(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -54,16 +57,16 @@ export function settingsMatchNormalizedData(data: unknown, settings: CodexPanelS
|
|||
const record = asRecord(data);
|
||||
return (
|
||||
Object.keys(record).length === 10 &&
|
||||
record.codexPath === settings.codexPath &&
|
||||
record.threadNamingModel === settings.threadNamingModel &&
|
||||
record.threadNamingEffort === settings.threadNamingEffort &&
|
||||
record.rewriteSelectionModel === settings.rewriteSelectionModel &&
|
||||
record.rewriteSelectionEffort === settings.rewriteSelectionEffort &&
|
||||
record.sendShortcut === settings.sendShortcut &&
|
||||
record.archiveExportEnabled === settings.archiveExportEnabled &&
|
||||
record.archiveExportFolderTemplate === settings.archiveExportFolderTemplate &&
|
||||
record.archiveExportFilenameTemplate === settings.archiveExportFilenameTemplate &&
|
||||
record.archiveExportTags === settings.archiveExportTags
|
||||
record["codexPath"] === settings.codexPath &&
|
||||
record["threadNamingModel"] === settings.threadNamingModel &&
|
||||
record["threadNamingEffort"] === settings.threadNamingEffort &&
|
||||
record["rewriteSelectionModel"] === settings.rewriteSelectionModel &&
|
||||
record["rewriteSelectionEffort"] === settings.rewriteSelectionEffort &&
|
||||
record["sendShortcut"] === settings.sendShortcut &&
|
||||
record["archiveExportEnabled"] === settings.archiveExportEnabled &&
|
||||
record["archiveExportFolderTemplate"] === settings.archiveExportFolderTemplate &&
|
||||
record["archiveExportFilenameTemplate"] === settings.archiveExportFilenameTemplate &&
|
||||
record["archiveExportTags"] === settings.archiveExportTags
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,8 +90,8 @@ export function syncComposerControls(
|
|||
sendButton.classList.toggle("is-interrupt", interruptMode);
|
||||
sendButton.classList.toggle("is-steer", canSteer);
|
||||
const mode = interruptMode ? "interrupt" : canSteer ? "steer" : "send";
|
||||
if (sendButton.dataset.codexMode !== mode) {
|
||||
sendButton.dataset.codexMode = mode;
|
||||
if (sendButton.dataset["codexMode"] !== mode) {
|
||||
sendButton.dataset["codexMode"] = mode;
|
||||
setButtonIcon(sendButton, interruptMode ? "square" : canSteer ? "corner-down-right" : "send");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ export function messageRenderBlocks(context: MessageStreamContext): MessageRende
|
|||
export function syncMessageRenderBlocks(parent: HTMLElement, blocks: MessageRenderBlock[], signatures: Map<string, string>): void {
|
||||
const existing = new Map<string, HTMLElement>();
|
||||
parent.querySelectorAll<HTMLElement>(":scope > [data-codex-panel-block-key]").forEach((element) => {
|
||||
const key = element.dataset.codexPanelBlockKey;
|
||||
const key = element.dataset["codexPanelBlockKey"];
|
||||
if (key) existing.set(key, element);
|
||||
});
|
||||
|
||||
|
|
@ -129,8 +129,8 @@ export function syncMessageRenderBlocks(parent: HTMLElement, blocks: MessageRend
|
|||
const currentWasNext = current === nextPosition;
|
||||
if (!element || signatures.get(block.key) !== block.signature) {
|
||||
element = block.render();
|
||||
element.dataset.codexPanelBlockKey = block.key;
|
||||
element.dataset.codexPanelBlockSignature = shortSignature(block.signature);
|
||||
element.dataset["codexPanelBlockKey"] = block.key;
|
||||
element.dataset["codexPanelBlockSignature"] = shortSignature(block.signature);
|
||||
signatures.set(block.key, block.signature);
|
||||
if (current) {
|
||||
current.replaceWith(element);
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ describe("AppServerClient", () => {
|
|||
input: [{ type: "text", text: "default", text_elements: [] }],
|
||||
},
|
||||
});
|
||||
expect((transport.sent[2] as { params?: Record<string, unknown> }).params?.collaborationMode).toBeUndefined();
|
||||
expect((transport.sent[2] as { params?: Record<string, unknown> }).params?.["collaborationMode"]).toBeUndefined();
|
||||
transport.emitLine({ id: 2, result: { turn: { id: "turn-default" } } });
|
||||
await defaultTurn;
|
||||
|
||||
|
|
@ -492,7 +492,7 @@ describe("AppServerClient", () => {
|
|||
method: "skills/list",
|
||||
params: { cwds: ["/vault"], forceReload: false },
|
||||
});
|
||||
expect((transport.sent[2] as { params?: Record<string, unknown> }).params?.perCwdExtraUserRoots).toBeUndefined();
|
||||
expect((transport.sent[2] as { params?: Record<string, unknown> }).params?.["perCwdExtraUserRoots"]).toBeUndefined();
|
||||
transport.emitLine({ id: 2, result: { data: [] } });
|
||||
await skills;
|
||||
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ class ToggleComponent {
|
|||
}
|
||||
|
||||
export function setIcon(element: HTMLElement, icon: string): void {
|
||||
element.dataset.icon = icon;
|
||||
element.dataset["icon"] = icon;
|
||||
}
|
||||
|
||||
function ensureElementHelpers(): void {
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ describe("runtime settings", () => {
|
|||
effectiveConfig: { config } as unknown as RuntimeSnapshot["effectiveConfig"],
|
||||
});
|
||||
|
||||
expect(config.approvals_reviewer).toBe("auto_review");
|
||||
expect(config["approvals_reviewer"]).toBe("auto_review");
|
||||
expect(autoReviewActive(snapshot, config)).toBe(false);
|
||||
});
|
||||
|
||||
|
|
@ -360,8 +360,8 @@ describe("runtime settings", () => {
|
|||
"active service tier": "(not reported)",
|
||||
"fast mode": "on",
|
||||
});
|
||||
expect(policyRows.approval).toBe("never");
|
||||
expect(policyRows.reviewer).toBe("auto_review");
|
||||
expect(policyRows["approval"]).toBe("never");
|
||||
expect(policyRows["reviewer"]).toBe("auto_review");
|
||||
expect(policyRows["auto-review"]).toBe("on");
|
||||
expect(policyRows["config reviewer"]).toBe("auto_review");
|
||||
expect(policyRows["active reviewer"]).toBe("(not reported)");
|
||||
|
|
|
|||
|
|
@ -2157,14 +2157,14 @@ describe("composer renderer decisions", () => {
|
|||
expect(sendButton?.getAttribute("aria-label")).toBe("Interrupt");
|
||||
expect(sendButton?.classList.contains("is-interrupt")).toBe(true);
|
||||
expect(sendButton?.classList.contains("is-steer")).toBe(false);
|
||||
expect(sendButton?.dataset.icon).toBe("square");
|
||||
expect(sendButton?.dataset["icon"]).toBe("square");
|
||||
|
||||
composer.value = "adjust course";
|
||||
syncComposerControls(parent, composer, true, true);
|
||||
expect(sendButton?.getAttribute("aria-label")).toBe("Steer");
|
||||
expect(sendButton?.classList.contains("is-interrupt")).toBe(false);
|
||||
expect(sendButton?.classList.contains("is-steer")).toBe(true);
|
||||
expect(sendButton?.dataset.icon).toBe("corner-down-right");
|
||||
expect(sendButton?.dataset["icon"]).toBe("corner-down-right");
|
||||
});
|
||||
|
||||
it("honors the smaller viewport branch of the composer max-height CSS", () => {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
"noImplicitOverride": true,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"isolatedModules": true,
|
||||
|
|
|
|||
Loading…
Reference in a new issue