refactor: eliminate remaining 15 any warnings and ratchet rule to error
- TaskCard: four catch((err: any) => err.message) promise handlers in
archive/unarchive/delete/move → catch((err) => getErrorMessage(err)).
- InlineCreateCard + QuickEntryBox: .catch((err: any)) model-load handlers
→ getErrorMessage(err) with existing @fusion/core import.
- TerminalModal: drop (navigator as any).maxTouchPoints — modern lib.dom
types already expose the property.
- serve.ts: remove unused any annotation on OpenRouter model mapper; the
array element type is already inferred from json.data.
- pi.js, runtime-resolution.ts, dashboard.ts, serve.ts, dev-server-port-
detect.ts, devserver-manager.ts: drop now-stale eslint-disable comments
that the cleanup made redundant.
Fix a prompt-builder regression surfaced by agent's `any` cleanup: toolCall
with a raw string `arguments` field must be preserved verbatim (JSON-quoted)
rather than coerced to `{}`; restores a previously-passing test.
Then promote @typescript-eslint/no-explicit-any from warn → error. Future
new anys must either come with a one-line disable + justification or use a
real type. Workspace is now lint-clean (0 problems).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -866,8 +866,6 @@ export async function runDashboard(port: number, opts: { paused?: boolean; dev?:
|
||||
//
|
||||
// Create the skills adapter using the same DefaultPackageManager instance
|
||||
// that was set up earlier for extension resolution.
|
||||
//
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
const skillsAdapter = packageManager
|
||||
? createSkillsAdapter({
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- dashboard's resolve() uses a looser onMissing signature than pi's DefaultPackageManager
|
||||
|
||||
@@ -524,7 +524,7 @@ export async function runServe(
|
||||
};
|
||||
}>;
|
||||
};
|
||||
const orModels = (json.data || []).map((m: any) => {
|
||||
const orModels = (json.data || []).map((m) => {
|
||||
const id = (m.id || "").toLowerCase();
|
||||
const name = (m.name || "").toLowerCase();
|
||||
const reasoning =
|
||||
@@ -615,8 +615,6 @@ export async function runServe(
|
||||
//
|
||||
// Create the skills adapter using the same DefaultPackageManager instance
|
||||
// that was set up earlier for extension resolution.
|
||||
//
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
const skillsAdapter = packageManager
|
||||
? createSkillsAdapter({
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- dashboard's resolve() uses a looser onMissing signature than pi's DefaultPackageManager
|
||||
|
||||
@@ -189,9 +189,9 @@ export function InlineCreateCard({
|
||||
setFavoriteModels(response.favoriteModels);
|
||||
}
|
||||
})
|
||||
.catch((err: any) => {
|
||||
.catch((err) => {
|
||||
if (!cancelled) {
|
||||
setModelsError(err?.message || "Failed to load models");
|
||||
setModelsError(getErrorMessage(err) || "Failed to load models");
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
|
||||
@@ -175,9 +175,9 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err: any) => {
|
||||
.catch((err) => {
|
||||
if (!cancelled) {
|
||||
setModelsError(err?.message || "Failed to load models");
|
||||
setModelsError(getErrorMessage(err) || "Failed to load models");
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
|
||||
@@ -702,8 +702,8 @@ function TaskCardComponent({
|
||||
|
||||
void onArchiveTask(task.id).then(() => {
|
||||
addToast(`Archived ${task.id}`, "success");
|
||||
}).catch((err: any) => {
|
||||
addToast(`Failed to archive ${task.id}: ${err.message}`, "error");
|
||||
}).catch((err) => {
|
||||
addToast(`Failed to archive ${task.id}: ${getErrorMessage(err)}`, "error");
|
||||
});
|
||||
}, [addToast, onArchiveTask, task.id]);
|
||||
|
||||
@@ -713,8 +713,8 @@ function TaskCardComponent({
|
||||
|
||||
void onUnarchiveTask(task.id).then(() => {
|
||||
addToast(`Unarchived ${task.id}`, "success");
|
||||
}).catch((err: any) => {
|
||||
addToast(`Failed to unarchive ${task.id}: ${err.message}`, "error");
|
||||
}).catch((err) => {
|
||||
addToast(`Failed to unarchive ${task.id}: ${getErrorMessage(err)}`, "error");
|
||||
});
|
||||
}, [addToast, onUnarchiveTask, task.id]);
|
||||
|
||||
@@ -725,8 +725,8 @@ function TaskCardComponent({
|
||||
if (window.confirm(`Delete ${task.id}?`)) {
|
||||
void onDeleteTask(task.id).then(() => {
|
||||
addToast(`Deleted ${task.id}`, "success");
|
||||
}).catch((err: any) => {
|
||||
addToast(`Failed to delete ${task.id}: ${err.message}`, "error");
|
||||
}).catch((err) => {
|
||||
addToast(`Failed to delete ${task.id}: ${getErrorMessage(err)}`, "error");
|
||||
});
|
||||
}
|
||||
}, [addToast, onDeleteTask, task.id]);
|
||||
@@ -760,8 +760,8 @@ function TaskCardComponent({
|
||||
|
||||
void onMoveTask(task.id, column).then(() => {
|
||||
addToast(`Moved ${task.id} to ${COLUMN_LABELS[column]}`, "success");
|
||||
}).catch((err: any) => {
|
||||
addToast(`Failed to move ${task.id}: ${err.message}`, "error");
|
||||
}).catch((err) => {
|
||||
addToast(`Failed to move ${task.id}: ${getErrorMessage(err)}`, "error");
|
||||
});
|
||||
}, [addToast, onMoveTask, task.id]);
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ export async function retryDynamicImport<T>(
|
||||
function isMobileDevice(): boolean {
|
||||
if (typeof window === "undefined") return false;
|
||||
const hasTouchScreen =
|
||||
"ontouchstart" in window || (navigator as any).maxTouchPoints > 0;
|
||||
"ontouchstart" in window || navigator.maxTouchPoints > 0;
|
||||
const isNarrow = window.innerWidth <= 768;
|
||||
return hasTouchScreen && isNarrow;
|
||||
}
|
||||
|
||||
@@ -235,7 +235,6 @@ export async function probeFallbackPorts(host = DEFAULT_PROBE_HOST, timeoutMs =
|
||||
}
|
||||
|
||||
// Probe sequentially so first responsive common port wins deterministically.
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const isOpen = await probePort(safeHost, port, safeTimeout);
|
||||
if (isOpen) {
|
||||
return {
|
||||
|
||||
@@ -312,7 +312,6 @@ export class DevServerManager extends EventEmitter<DevServerManagerEvents> {
|
||||
|
||||
private async findFirstReachablePort(ports: number[]): Promise<number | null> {
|
||||
for (const port of ports) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const reachable = await probePort(port);
|
||||
if (reachable) {
|
||||
return port;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
* Uses Fusion auth for writes and legacy pi auth as a read-only fallback.
|
||||
* Provides factory functions for creating triage and executor agent sessions.
|
||||
*/
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { exec } from "node:child_process";
|
||||
import { promisify } from "node:util";
|
||||
|
||||
@@ -78,7 +78,6 @@ export class DefaultPiRuntime implements AgentRuntime {
|
||||
readonly name = "Default PI Runtime";
|
||||
|
||||
// Synchronous cached describeModel function
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private static describeModelFn: ((session: AgentSession) => string) | null = null;
|
||||
|
||||
/**
|
||||
@@ -223,7 +222,6 @@ function wrapPluginRuntime(
|
||||
describeModel: (session: AgentSession) => {
|
||||
const adapter = instance as Record<string, unknown>;
|
||||
if (typeof adapter.describeModel === "function") {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return (adapter.describeModel as (s: AgentSession) => string)(session);
|
||||
}
|
||||
// Fallback to default pi describeModel - use cached sync function
|
||||
|
||||
@@ -438,19 +438,30 @@ function contentToText(content: string | unknown[]): string {
|
||||
if (block.type === "thinking") return ""; // Skip thinking — internal reasoning, not conversation
|
||||
if (block.type === "toolCall") {
|
||||
const name = typeof block.name === "string" ? block.name : "";
|
||||
const args = block.arguments && typeof block.arguments === "object"
|
||||
? (block.arguments as Record<string, unknown>)
|
||||
: undefined;
|
||||
const rawArgs = block.arguments;
|
||||
// A toolCall may carry either parsed args (object) or the raw unparsed
|
||||
// string that pi produced — preserve the raw string verbatim so callers
|
||||
// can see what the model actually sent.
|
||||
const argsObject =
|
||||
rawArgs && typeof rawArgs === "object" ? (rawArgs as Record<string, unknown>) : undefined;
|
||||
const isCustom = isCustomToolName(name);
|
||||
if (isCustom) {
|
||||
// Custom tools: don't reference the MCP tool name — Claude might try to re-call it.
|
||||
// Just note what was done. The result follows as a TOOL RESULT message.
|
||||
const argsStr = args ? JSON.stringify(args) : "{}";
|
||||
const argsStr = argsObject
|
||||
? JSON.stringify(argsObject)
|
||||
: typeof rawArgs === "string"
|
||||
? JSON.stringify(rawArgs)
|
||||
: "{}";
|
||||
return `[Used ${name} tool with args: ${argsStr}]`;
|
||||
}
|
||||
const claudeName = mapPiToolNameToClaude(name);
|
||||
const claudeArgs = args ? translatePiArgsToClaude(name, args) : undefined;
|
||||
const argsStr = claudeArgs ? JSON.stringify(claudeArgs) : "{}";
|
||||
const claudeArgs = argsObject ? translatePiArgsToClaude(name, argsObject) : undefined;
|
||||
const argsStr = claudeArgs
|
||||
? JSON.stringify(claudeArgs)
|
||||
: typeof rawArgs === "string"
|
||||
? JSON.stringify(rawArgs)
|
||||
: "{}";
|
||||
return `Historical tool call (non-executable): ${claudeName} args=${argsStr}`;
|
||||
}
|
||||
// Unknown block types are represented as a placeholder
|
||||
|
||||
Reference in New Issue
Block a user