diff --git a/packages/pi-fff/README.md b/packages/pi-fff/README.md index 6456d55b8..e38cf6522 100644 --- a/packages/pi-fff/README.md +++ b/packages/pi-fff/README.md @@ -136,6 +136,7 @@ For persistent global configuration, create `pi-fff.json` in pi's agent director ```json { + "$schema": "https://raw.githubusercontent.com/dmtrKovalenko/fff/main/packages/pi-fff/pi-fff.schema.json", "mode": "override", "frecencyDbPath": "/path/to/frecency", "historyDbPath": "/path/to/history", @@ -148,6 +149,7 @@ All fields are optional: | Field | Type | Default | |---|---|---| +| `$schema` | non-empty string | none | | `mode` | `tools-and-ui`, `tools-only`, or `override` | `tools-and-ui` | | `frecencyDbPath` | non-empty string | See [Data](#data) | | `historyDbPath` | non-empty string | See [Data](#data) | diff --git a/packages/pi-fff/package.json b/packages/pi-fff/package.json index 922ea609e..4d8a7ea59 100644 --- a/packages/pi-fff/package.json +++ b/packages/pi-fff/package.json @@ -30,7 +30,8 @@ ] }, "files": [ - "src" + "src", + "pi-fff.schema.json" ], "publishConfig": { "access": "public" diff --git a/packages/pi-fff/pi-fff.schema.json b/packages/pi-fff/pi-fff.schema.json new file mode 100644 index 000000000..8a619ca03 --- /dev/null +++ b/packages/pi-fff/pi-fff.schema.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/dmtrKovalenko/fff/main/packages/pi-fff/pi-fff.schema.json", + "title": "pi-fff configuration", + "description": "Global startup configuration for the pi-fff extension.", + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "type": "string", + "minLength": 1, + "description": "Schema URL used by editors for validation and completion." + }, + "mode": { + "type": "string", + "enum": ["tools-and-ui", "tools-only", "override"], + "default": "tools-and-ui", + "description": "Controls which FFF tools and autocomplete integrations are enabled." + }, + "frecencyDbPath": { + "type": "string", + "minLength": 1, + "description": "Path to the frecency database." + }, + "historyDbPath": { + "type": "string", + "minLength": 1, + "description": "Path to the query history database." + }, + "enableFsRootScanning": { + "type": "boolean", + "default": false, + "description": "Allows indexing when pi is launched from the filesystem root." + }, + "enableHomeDirScanning": { + "type": "boolean", + "default": true, + "description": "Allows indexing when pi is launched from the home directory." + } + } +} diff --git a/packages/pi-fff/src/config.ts b/packages/pi-fff/src/config.ts index 0af98bd3e..a463f97d5 100644 --- a/packages/pi-fff/src/config.ts +++ b/packages/pi-fff/src/config.ts @@ -8,6 +8,7 @@ export const VALID_MODES = ["tools-and-ui", "tools-only", "override"] as const; export type FffMode = (typeof VALID_MODES)[number]; export interface FffConfig { + $schema?: string; mode?: FffMode; frecencyDbPath?: string; historyDbPath?: string; @@ -16,6 +17,7 @@ export interface FffConfig { } const CONFIG_KEYS = new Set([ + "$schema", "mode", "frecencyDbPath", "historyDbPath", @@ -57,6 +59,7 @@ export function loadConfig(agentDir = piDataDir()): FffConfig { throw invalidConfig(configPath, `"mode" must be one of ${VALID_MODES.join(", ")}`); } + validateString(configPath, parsed, "$schema"); validateString(configPath, parsed, "frecencyDbPath"); validateString(configPath, parsed, "historyDbPath"); validateBoolean(configPath, parsed, "enableFsRootScanning"); @@ -80,7 +83,7 @@ function isRecord(value: unknown): value is Record { function validateString( configPath: string, config: Record, - key: "frecencyDbPath" | "historyDbPath", + key: "$schema" | "frecencyDbPath" | "historyDbPath", ): void { const value = config[key]; if (value !== undefined && (typeof value !== "string" || value.length === 0)) { diff --git a/packages/pi-fff/test/config.test.ts b/packages/pi-fff/test/config.test.ts index 60f1c57e0..053aba1df 100644 --- a/packages/pi-fff/test/config.test.ts +++ b/packages/pi-fff/test/config.test.ts @@ -24,6 +24,8 @@ describe("loadConfig", () => { test("loads every supported option", () => { const config = { + $schema: + "https://raw.githubusercontent.com/dmtrKovalenko/fff/main/packages/pi-fff/pi-fff.schema.json", mode: "override" as const, frecencyDbPath: "/data/frecency", historyDbPath: "/data/history", @@ -57,6 +59,8 @@ describe("loadConfig", () => { test("rejects invalid option values", () => { const cases: [Record, string][] = [ + [{ $schema: false }, '"$schema" must be a non-empty string'], + [{ $schema: "" }, '"$schema" must be a non-empty string'], [{ mode: "replace" }, '"mode" must be one of'], [{ frecencyDbPath: "" }, '"frecencyDbPath" must be a non-empty string'], [{ historyDbPath: false }, '"historyDbPath" must be a non-empty string'],