mirror of
https://github.com/KeygraphHQ/shannon.git
synced 2026-05-19 23:44:46 +02:00
fix: resolve all biome warnings and formatting issues
- Remove unnecessary non-null assertions where values are guaranteed - Replace array index access with .at() for safer element retrieval - Use local variables to avoid repeated process.env lookups - Replace any types with unknown in functional utilities - Use nullish coalescing for TOTP hash byte access - Auto-format security patches to match biome config
This commit is contained in:
@@ -219,9 +219,9 @@ async function setupRouter(): Promise<ShannonConfig> {
|
||||
|
||||
const router: ShannonConfig['router'] = { default: defaultModel };
|
||||
if (routerProvider === 'openai') {
|
||||
router!.openai_key = apiKey;
|
||||
router.openai_key = apiKey;
|
||||
} else {
|
||||
router!.openrouter_key = apiKey;
|
||||
router.openrouter_key = apiKey;
|
||||
}
|
||||
|
||||
return { router };
|
||||
|
||||
@@ -65,11 +65,8 @@ export function start(args: StartArgs): void {
|
||||
const containerName = `shannon-worker-${suffix}`;
|
||||
|
||||
// 8. Generate workspace name if not provided
|
||||
let workspace = args.workspace;
|
||||
if (!workspace) {
|
||||
const hostname = new URL(args.url).hostname.replace(/[^a-zA-Z0-9-]/g, '-');
|
||||
workspace = `${hostname}_shannon-${Date.now()}`;
|
||||
}
|
||||
const workspace =
|
||||
args.workspace ?? `${new URL(args.url).hostname.replace(/[^a-zA-Z0-9-]/g, '-')}_shannon-${Date.now()}`;
|
||||
|
||||
// 9. Resolve credentials
|
||||
const credentialsDir = getCredentialsDir();
|
||||
@@ -142,7 +139,7 @@ export function start(args: StartArgs): void {
|
||||
|
||||
// Clear waiting line and show info
|
||||
process.stdout.write('\r\x1b[K');
|
||||
printInfo(args, useRouter, workspace!, workflowId, repo.hostPath, workspacesDir);
|
||||
printInfo(args, useRouter, workspace, workflowId, repo.hostPath, workspacesDir);
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
|
||||
@@ -88,7 +88,10 @@ function buildMcpServers(
|
||||
// NOTE: Explicit allowlist — the Playwright MCP subprocess must not inherit
|
||||
// secrets (API keys, AWS tokens) from the parent process.
|
||||
const MCP_ENV_ALLOWLIST = [
|
||||
'PATH', 'HOME', 'NODE_PATH', 'DISPLAY',
|
||||
'PATH',
|
||||
'HOME',
|
||||
'NODE_PATH',
|
||||
'DISPLAY',
|
||||
'PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH',
|
||||
] as const;
|
||||
|
||||
@@ -98,8 +101,9 @@ function buildMcpServers(
|
||||
};
|
||||
|
||||
for (const key of MCP_ENV_ALLOWLIST) {
|
||||
if (process.env[key]) {
|
||||
envVars[key] = process.env[key]!;
|
||||
const val = process.env[key];
|
||||
if (val) {
|
||||
envVars[key] = val;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,8 +256,9 @@ export async function runClaudePrompt(
|
||||
'ANTHROPIC_LARGE_MODEL',
|
||||
];
|
||||
for (const name of passthroughVars) {
|
||||
if (process.env[name]) {
|
||||
sdkEnv[name] = process.env[name]!;
|
||||
const val = process.env[name];
|
||||
if (val) {
|
||||
sdkEnv[name] = val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,14 +89,14 @@ function summarizeTodoUpdate(input: ToolCallInput | undefined): string | null {
|
||||
const inProgress = todos.filter((t) => t.status === 'in_progress');
|
||||
|
||||
// Show recently completed tasks
|
||||
if (completed.length > 0) {
|
||||
const recent = completed[completed.length - 1]!;
|
||||
const recent = completed.at(-1);
|
||||
if (recent) {
|
||||
return `✅ ${recent.content}`;
|
||||
}
|
||||
|
||||
// Show current in-progress task
|
||||
if (inProgress.length > 0) {
|
||||
const current = inProgress[0]!;
|
||||
const current = inProgress.at(0);
|
||||
if (current) {
|
||||
return `🔄 ${current.content}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -336,6 +336,7 @@ export class MetricsTracker {
|
||||
|
||||
// Calculate metrics per phase
|
||||
const phaseMetrics: Record<string, PhaseMetrics> = {};
|
||||
// biome-ignore lint/style/noNonNullAssertion: called from recalculateAggregations which guards this.data
|
||||
const totalDuration = this.data!.metrics.total_duration_ms;
|
||||
|
||||
for (const [phaseName, agentList] of Object.entries(phases)) {
|
||||
|
||||
@@ -37,7 +37,7 @@ async function buildLoginInstructions(authentication: Authentication, logger: Ac
|
||||
const getSection = (content: string, sectionName: string): string => {
|
||||
const regex = new RegExp(`<!-- BEGIN:${sectionName} -->([\\s\\S]*?)<!-- END:${sectionName} -->`, 'g');
|
||||
const match = regex.exec(content);
|
||||
return match ? match[1]!.trim() : '';
|
||||
return match?.[1]?.trim() ?? '';
|
||||
};
|
||||
|
||||
// 2. Extract sections based on login type
|
||||
@@ -101,14 +101,13 @@ async function processIncludes(content: string, baseDir: string): Promise<string
|
||||
|
||||
const replacements: IncludeReplacement[] = await Promise.all(
|
||||
Array.from(content.matchAll(includeRegex)).map(async (match) => {
|
||||
const includePath = path.resolve(baseDir, match[1]!);
|
||||
const rawPath = match[1] ?? '';
|
||||
const includePath = path.resolve(baseDir, rawPath);
|
||||
if (!includePath.startsWith(resolvedBase + path.sep) && includePath !== resolvedBase) {
|
||||
throw new PentestError(
|
||||
`Path traversal detected in @include(): ${match[1]}`,
|
||||
'prompt',
|
||||
false,
|
||||
{ includePath, baseDir: resolvedBase },
|
||||
);
|
||||
throw new PentestError(`Path traversal detected in @include(): ${rawPath}`, 'prompt', false, {
|
||||
includePath,
|
||||
baseDir: resolvedBase,
|
||||
});
|
||||
}
|
||||
const sharedContent = await fs.readFile(includePath, 'utf8');
|
||||
return {
|
||||
|
||||
@@ -243,7 +243,7 @@ const validateQueueContent = async (
|
||||
|
||||
return Object.freeze({
|
||||
...pathsWithExistence,
|
||||
queueData: queueValidation.data!,
|
||||
queueData: queueValidation.data as QueueData,
|
||||
});
|
||||
} catch (readError) {
|
||||
return {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* Generic functional composition patterns for async operations.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// biome-ignore lint/suspicious/noExplicitAny: pipeline functions need flexible typing for composition
|
||||
type PipelineFunction = (x: any) => any | Promise<any>;
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,13 +48,14 @@ function generateHOTP(secret: string, counter: number, digits: number = 6): stri
|
||||
hmac.update(counterBuffer);
|
||||
const hash = hmac.digest();
|
||||
|
||||
// Dynamic truncation
|
||||
const offset = hash[hash.length - 1]! & 0x0f;
|
||||
// Dynamic truncation (SHA-1 always produces 20 bytes)
|
||||
const lastByte = hash[hash.length - 1] ?? 0;
|
||||
const offset = lastByte & 0x0f;
|
||||
const code =
|
||||
((hash[offset]! & 0x7f) << 24) |
|
||||
((hash[offset + 1]! & 0xff) << 16) |
|
||||
((hash[offset + 2]! & 0xff) << 8) |
|
||||
(hash[offset + 3]! & 0xff);
|
||||
(((hash[offset] ?? 0) & 0x7f) << 24) |
|
||||
(((hash[offset + 1] ?? 0) & 0xff) << 16) |
|
||||
(((hash[offset + 2] ?? 0) & 0xff) << 8) |
|
||||
((hash[offset + 3] ?? 0) & 0xff);
|
||||
|
||||
// Generate digits
|
||||
const otp = (code % 10 ** digits).toString().padStart(digits, '0');
|
||||
|
||||
Reference in New Issue
Block a user