config: warn on unknown toolSets typo instead of dropping silently

unknownToolSetNames() + startup notice (stderr headless, NoticeBus
interactive) flags gti vs git typos at boot, not as that set off.
This commit is contained in:
asepharyana
2026-09-09 13:28:24 +07:00
parent dcede3c10a
commit 5028ea6973
4 changed files with 24 additions and 3 deletions
+9 -1
View File
@@ -4,7 +4,7 @@ import React from 'react';
import type { LanguageModel, ModelMessage } from 'ai';
import { resolveAgent, VARIANTS, isThinkingLevel, type AgentVariant } from './agents';
import { loadExternalPlugins, loadExternalTools } from './autoload';
import { configPath, loadConfig, missingKeyMessage, resolveModel, writeConfigFile, type Config } from './config';
import { configPath, loadConfig, missingKeyMessage, readConfigFile, resolveModel, unknownToolSetNames, writeConfigFile, type Config } from './config';
import type { FallbackEvent } from './fallback';
import { farewell } from './farewell';
import { readStdin, runHeadless } from './headless';
@@ -107,6 +107,8 @@ if (modelFlag) process.env['SHIRO_MODEL'] = modelFlag;
if (baseUrlFlag) process.env['SHIRO_BASE_URL'] = baseUrlFlag;
let cfg = await loadConfig();
const rawToolSets = (await readConfigFile()).toolSets as unknown;
const unknownToolSets = unknownToolSetNames(rawToolSets);
const yolo = has('--yolo');
const headless = flag('-p', '--print') !== undefined;
@@ -121,6 +123,12 @@ const notices = createNoticeBus();
const subagents = createSubagentBus();
const askBridge = createAskBridge();
if (unknownToolSets.length > 0) {
const msg = `unknown toolSets ignored: ${unknownToolSets.join(', ')} — valid: core, edit-plus, nav, extra, git, net`;
if (headless) process.stderr.write(`shiro: ${msg}\n`);
else notices.emit(msg);
}
function reportFallback(e: FallbackEvent): void {
const line = `endpoint fallback: ${e.from} rejected the request, retrying on ${e.to}\n ${e.reason}`;
if (headless) process.stderr.write(`shiro: ${line}\n`);
+5
View File
@@ -82,6 +82,11 @@ export async function writeConfigFile(patch: Partial<Config>): Promise<string> {
}
/** File config, then env overrides. Env wins so `SHIRO_MODEL=x shiro` works. */
export function unknownToolSetNames(raw: unknown): string[] {
if (!Array.isArray(raw)) return [];
return (raw as unknown[]).filter((v): v is string => typeof v === 'string' && !isToolSetName(v));
}
export async function loadConfig(): Promise<Config> {
const file = await readConfigFile();