src / commands.ts
src / commands.ts
// Commands for the user rather than the model: show the state of things, and accept, discard
// or undo parser rules. The MCP server's command line and the plugin's /simplesearch chat
// command both run them, so a rule change always needs a person.
import { KNOWN_ENGINES, VERSION, isEngine } from "./config";
import type { Ctx } from "./ops";
import { profileDir, profileInUse } from "./profile";
export const RULE_COMMANDS = ["approve", "reject", "rollback", "reset"] as const;
export function statusReport(ctx: Ctx, settingsFrom: string): string {
const cfg = ctx.cfg;
const lines = [`simpleSearch ${VERSION}`, `settings read from: ${settingsFrom}`, `data folder: ${cfg.dataDir}`];
lines.push(`browser: ${cfg.browserPath ?? "not found"}, profile "${cfg.profile}", port ${cfg.port}`);
const dir = profileDir(cfg.profile);
const open = dir ? profileInUse(dir) : null;
lines.push(
`profile folder: ${dir ?? "not found in profiles.ini"}${dir ? `, ${open === true ? "open in a running browser" : open === false ? "not open" : "open state unknown"}` : ""}`
);
lines.push(`rule updates: ${cfg.ruleUpdates === "auto" ? "applied automatically" : "held for approval"}`);
for (const p of cfg.problems) lines.push(`problem: ${p}`);
for (const engine of cfg.engines) {
const rules = ctx.rules.get(engine);
lines.push(`${engine}: ${rules.source} rules; ${ctx.health.describe(engine)}`);
const pending = ctx.rules.getPending(engine);
if (pending) {
lines.push(` proposed rules waiting since ${pending.proposedAt} (${pending.summary}):`);
lines.push(` ${JSON.stringify(pending.rules)}`);
}
}
return lines.join("\n");
}
// Runs approve, reject, rollback or reset for one engine. Null when the command is not one of these.
export function ruleCommand(ctx: Ctx, command: string, engine: string | undefined): string | null {
if (!(RULE_COMMANDS as readonly string[]).includes(command)) return null;
if (!engine || !isEngine(engine)) return `Name an engine: ${KNOWN_ENGINES.join(", ")}`;
const store = ctx.rules;
const message =
command === "approve" ? store.approve(engine) : command === "reject" ? store.reject(engine) : command === "rollback" ? store.rollback(engine) : store.reset(engine);
if (command === "reject") return message;
const { source, updatedAt, defaultsVersion, ...active } = store.get(engine);
return `${message}\nactive ${engine} rules: ${JSON.stringify(active)}`;
}
// Commands for the user rather than the model: show the state of things, and accept, discard
// or undo parser rules. The MCP server's command line and the plugin's /simplesearch chat
// command both run them, so a rule change always needs a person.
import { KNOWN_ENGINES, VERSION, isEngine } from "./config";
import type { Ctx } from "./ops";
import { profileDir, profileInUse } from "./profile";
export const RULE_COMMANDS = ["approve", "reject", "rollback", "reset"] as const;
export function statusReport(ctx: Ctx, settingsFrom: string): string {
const cfg = ctx.cfg;
const lines = [`simpleSearch ${VERSION}`, `settings read from: ${settingsFrom}`, `data folder: ${cfg.dataDir}`];
lines.push(`browser: ${cfg.browserPath ?? "not found"}, profile "${cfg.profile}", port ${cfg.port}`);
const dir = profileDir(cfg.profile);
const open = dir ? profileInUse(dir) : null;
lines.push(
`profile folder: ${dir ?? "not found in profiles.ini"}${dir ? `, ${open === true ? "open in a running browser" : open === false ? "not open" : "open state unknown"}` : ""}`
);
lines.push(`rule updates: ${cfg.ruleUpdates === "auto" ? "applied automatically" : "held for approval"}`);
for (const p of cfg.problems) lines.push(`problem: ${p}`);
for (const engine of cfg.engines) {
const rules = ctx.rules.get(engine);
lines.push(`${engine}: ${rules.source} rules; ${ctx.health.describe(engine)}`);
const pending = ctx.rules.getPending(engine);
if (pending) {
lines.push(` proposed rules waiting since ${pending.proposedAt} (${pending.summary}):`);
lines.push(` ${JSON.stringify(pending.rules)}`);
}
}
return lines.join("\n");
}
// Runs approve, reject, rollback or reset for one engine. Null when the command is not one of these.
export function ruleCommand(ctx: Ctx, command: string, engine: string | undefined): string | null {
if (!(RULE_COMMANDS as readonly string[]).includes(command)) return null;
if (!engine || !isEngine(engine)) return `Name an engine: ${KNOWN_ENGINES.join(", ")}`;
const store = ctx.rules;
const message =
command === "approve" ? store.approve(engine) : command === "reject" ? store.reject(engine) : command === "rollback" ? store.rollback(engine) : store.reset(engine);
if (command === "reject") return message;
const { source, updatedAt, defaultsVersion, ...active } = store.get(engine);
return `${message}\nactive ${engine} rules: ${JSON.stringify(active)}`;
}