mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
feat: add correct JSON schema for .roomodes configuration files (#11791)
Some checks failed
Code QA Roo Code / check-translations (push) Has been cancelled
Code QA Roo Code / knip (push) Has been cancelled
Code QA Roo Code / compile (push) Has been cancelled
Code QA Roo Code / platform-unit-test (ubuntu-latest) (push) Has been cancelled
Code QA Roo Code / platform-unit-test (windows-latest) (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Nightly Publish / publish-nightly (push) Has been cancelled
Deploy roocode.com / check-secrets (push) Has been cancelled
Deploy roocode.com / deploy (push) Has been cancelled
Some checks failed
Code QA Roo Code / check-translations (push) Has been cancelled
Code QA Roo Code / knip (push) Has been cancelled
Code QA Roo Code / compile (push) Has been cancelled
Code QA Roo Code / platform-unit-test (ubuntu-latest) (push) Has been cancelled
Code QA Roo Code / platform-unit-test (windows-latest) (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Nightly Publish / publish-nightly (push) Has been cancelled
Deploy roocode.com / check-secrets (push) Has been cancelled
Deploy roocode.com / deploy (push) Has been cancelled
Co-authored-by: Roo Code <roomote@roocode.com>
This commit is contained in:
parent
9cfaf38d8a
commit
7adbfec2a4
7 changed files with 690 additions and 2 deletions
|
|
@ -20,7 +20,8 @@
|
|||
"build": "tsup",
|
||||
"build:watch": "tsup --watch --outDir npm/dist --onSuccess 'echo ✅ Types rebuilt to npm/dist'",
|
||||
"npm:publish": "node scripts/publish-npm.cjs",
|
||||
"clean": "rimraf dist .turbo"
|
||||
"clean": "rimraf dist .turbo",
|
||||
"generate:schema": "tsx scripts/generate-roomodes-schema.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"ai-sdk-provider-poe": "2.0.18",
|
||||
|
|
@ -32,6 +33,8 @@
|
|||
"@types/node": "^24.1.0",
|
||||
"globals": "^16.3.0",
|
||||
"tsup": "^8.4.0",
|
||||
"vitest": "^3.2.3"
|
||||
"ajv": "^8.18.0",
|
||||
"vitest": "^3.2.3",
|
||||
"zod-to-json-schema": "^3.25.1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
25
packages/types/scripts/generate-roomodes-schema.ts
Normal file
25
packages/types/scripts/generate-roomodes-schema.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* Generates the JSON Schema for .roomodes configuration files from the Zod
|
||||
* schemas defined in packages/types/src/mode.ts.
|
||||
*
|
||||
* This ensures the schema stays in sync with the TypeScript types. Run via:
|
||||
* pnpm --filter @roo-code/types generate:schema
|
||||
*
|
||||
* The output is written to schemas/roomodes.json at the repository root.
|
||||
*/
|
||||
|
||||
import * as fs from "fs"
|
||||
import * as path from "path"
|
||||
import { fileURLToPath } from "url"
|
||||
|
||||
import { generateRoomodesJsonSchema } from "../src/roomodes-schema.js"
|
||||
|
||||
const jsonSchema = generateRoomodesJsonSchema()
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const repoRoot = path.resolve(__dirname, "../../..")
|
||||
const outPath = path.join(repoRoot, "schemas", "roomodes.json")
|
||||
fs.mkdirSync(path.dirname(outPath), { recursive: true })
|
||||
fs.writeFileSync(outPath, JSON.stringify(jsonSchema, null, "\t") + "\n", "utf-8")
|
||||
|
||||
console.log(`Generated ${path.relative(repoRoot, outPath)}`)
|
||||
26
packages/types/src/__tests__/roomodes-schema-sync.spec.ts
Normal file
26
packages/types/src/__tests__/roomodes-schema-sync.spec.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { describe, it, expect } from "vitest"
|
||||
import * as fs from "fs"
|
||||
import * as path from "path"
|
||||
import { fileURLToPath } from "url"
|
||||
|
||||
import { generateRoomodesJsonSchema } from "../roomodes-schema.js"
|
||||
|
||||
/**
|
||||
* This test verifies that the checked-in schemas/roomodes.json matches what
|
||||
* would be generated from the current Zod schemas. If this test fails, run:
|
||||
*
|
||||
* pnpm --filter @roo-code/types generate:schema
|
||||
*
|
||||
* to regenerate the schema file.
|
||||
*/
|
||||
describe("roomodes schema sync", () => {
|
||||
it("should match the dynamically generated schema from Zod types", () => {
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const schemaPath = path.resolve(__dirname, "../../../../schemas/roomodes.json")
|
||||
const checkedIn = JSON.parse(fs.readFileSync(schemaPath, "utf-8"))
|
||||
|
||||
const generated = generateRoomodesJsonSchema()
|
||||
|
||||
expect(checkedIn).toEqual(generated)
|
||||
})
|
||||
})
|
||||
438
packages/types/src/__tests__/roomodes-schema.spec.ts
Normal file
438
packages/types/src/__tests__/roomodes-schema.spec.ts
Normal file
|
|
@ -0,0 +1,438 @@
|
|||
/**
|
||||
* Validates the generated schemas/roomodes.json against sample configurations
|
||||
* using AJV. The schema itself is dynamically generated from the Zod types in
|
||||
* packages/types/src/mode.ts -- see packages/types/scripts/generate-roomodes-schema.ts.
|
||||
*
|
||||
* A separate drift-detection test (roomodes-schema-sync.spec.ts) ensures the
|
||||
* checked-in schema stays in sync with the Zod source of truth.
|
||||
*/
|
||||
import { describe, it, expect, beforeAll } from "vitest"
|
||||
import Ajv, { type ValidateFunction } from "ajv"
|
||||
import * as fs from "fs"
|
||||
import * as path from "path"
|
||||
import { fileURLToPath } from "url"
|
||||
|
||||
describe("roomodes JSON schema", () => {
|
||||
let schema: Record<string, unknown>
|
||||
let validate: ValidateFunction
|
||||
|
||||
beforeAll(() => {
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const schemaPath = path.resolve(__dirname, "../../../../schemas/roomodes.json")
|
||||
schema = JSON.parse(fs.readFileSync(schemaPath, "utf-8"))
|
||||
const ajv = new Ajv.default({ strict: false })
|
||||
validate = ajv.compile(schema)
|
||||
})
|
||||
|
||||
it("should be a valid JSON Schema", () => {
|
||||
expect(validate).toBeDefined()
|
||||
})
|
||||
|
||||
it("should accept a minimal valid .roomodes config", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "my-mode",
|
||||
name: "My Mode",
|
||||
roleDefinition: "You are a helpful assistant.",
|
||||
groups: ["read"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(validate.errors).toBeNull()
|
||||
expect(valid).toBe(true)
|
||||
})
|
||||
|
||||
it("should accept a mode with all optional properties", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "full-mode",
|
||||
name: "Full Mode",
|
||||
roleDefinition: "A complete mode definition.",
|
||||
whenToUse: "Use when you need everything.",
|
||||
description: "A mode with all properties.",
|
||||
customInstructions: "Follow these additional rules.",
|
||||
groups: ["read", "edit", "command", "mcp"],
|
||||
source: "project",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(validate.errors).toBeNull()
|
||||
expect(valid).toBe(true)
|
||||
})
|
||||
|
||||
it("should accept the built-in architect mode with tuple-style edit group", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "architect",
|
||||
name: "Architect",
|
||||
roleDefinition: "You are an experienced technical leader.",
|
||||
whenToUse: "Use this mode when you need to plan.",
|
||||
description: "Plan and design before implementation",
|
||||
groups: ["read", ["edit", { fileRegex: "\\.md$", description: "Markdown files only" }], "mcp"],
|
||||
source: "project",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(validate.errors).toBeNull()
|
||||
expect(valid).toBe(true)
|
||||
})
|
||||
|
||||
it("should accept a tuple group entry with only fileRegex", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "restricted",
|
||||
name: "Restricted",
|
||||
roleDefinition: "Limited editor.",
|
||||
groups: [["edit", { fileRegex: "\\.ts$" }]],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(validate.errors).toBeNull()
|
||||
expect(valid).toBe(true)
|
||||
})
|
||||
|
||||
it("should accept a tuple group entry with empty options", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "empty-opts",
|
||||
name: "Empty Options",
|
||||
roleDefinition: "Mode with empty group options.",
|
||||
groups: [["edit", {}]],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(validate.errors).toBeNull()
|
||||
expect(valid).toBe(true)
|
||||
})
|
||||
|
||||
it("should accept the modes tool group", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "orchestrator",
|
||||
name: "Orchestrator",
|
||||
roleDefinition: "You orchestrate other modes.",
|
||||
groups: ["read", "modes"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(validate.errors).toBeNull()
|
||||
expect(valid).toBe(true)
|
||||
})
|
||||
|
||||
it("should reject a config missing customModes", () => {
|
||||
const config = {}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(valid).toBe(false)
|
||||
})
|
||||
|
||||
it("should reject a mode missing required slug", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
name: "No Slug",
|
||||
roleDefinition: "Missing slug.",
|
||||
groups: ["read"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(valid).toBe(false)
|
||||
})
|
||||
|
||||
it("should reject a mode missing required groups", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "no-groups",
|
||||
name: "No Groups",
|
||||
roleDefinition: "Missing groups.",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(valid).toBe(false)
|
||||
})
|
||||
|
||||
it("should reject a slug with invalid characters", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "invalid slug!",
|
||||
name: "Bad Slug",
|
||||
roleDefinition: "Invalid slug characters.",
|
||||
groups: ["read"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(valid).toBe(false)
|
||||
})
|
||||
|
||||
it("should reject an invalid tool group name", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "bad-group",
|
||||
name: "Bad Group",
|
||||
roleDefinition: "Invalid group name.",
|
||||
groups: ["nonexistent"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(valid).toBe(false)
|
||||
})
|
||||
|
||||
it("should reject additional properties on CustomMode", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "extra-props",
|
||||
name: "Extra Props",
|
||||
roleDefinition: "Has extra properties.",
|
||||
groups: ["read"],
|
||||
unknownField: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(valid).toBe(false)
|
||||
})
|
||||
|
||||
it("should reject additional properties on GroupOptions", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "bad-opts",
|
||||
name: "Bad Options",
|
||||
roleDefinition: "Extra options properties.",
|
||||
groups: [["edit", { fileRegex: "\\.md$", unknownOpt: true }]],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(valid).toBe(false)
|
||||
})
|
||||
|
||||
it("should reject a tuple with more than 2 elements", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "big-tuple",
|
||||
name: "Big Tuple",
|
||||
roleDefinition: "Too many tuple elements.",
|
||||
groups: [["edit", { fileRegex: "\\.md$" }, "extra"]],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(valid).toBe(false)
|
||||
})
|
||||
|
||||
it("should reject an invalid source value", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "bad-source",
|
||||
name: "Bad Source",
|
||||
roleDefinition: "Invalid source.",
|
||||
groups: ["read"],
|
||||
source: "unknown",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(valid).toBe(false)
|
||||
})
|
||||
|
||||
it("should accept an empty customModes array", () => {
|
||||
const config = {
|
||||
customModes: [],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(validate.errors).toBeNull()
|
||||
expect(valid).toBe(true)
|
||||
})
|
||||
|
||||
it("should accept the browser tool group (deprecated but valid)", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "browser-mode",
|
||||
name: "Browser Mode",
|
||||
roleDefinition: "A mode that uses the browser tool group.",
|
||||
groups: ["read", "browser", "command"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(validate.errors).toBeNull()
|
||||
expect(valid).toBe(true)
|
||||
})
|
||||
|
||||
it("should accept a browser tuple group entry", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "browser-tuple",
|
||||
name: "Browser Tuple",
|
||||
roleDefinition: "A mode with browser tuple.",
|
||||
groups: [["browser", { fileRegex: "\\.html$", description: "HTML files only" }]],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(validate.errors).toBeNull()
|
||||
expect(valid).toBe(true)
|
||||
})
|
||||
|
||||
it("should accept a mode with rulesFiles", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "rules-mode",
|
||||
name: "Rules Mode",
|
||||
roleDefinition: "A mode with rules files.",
|
||||
groups: ["read"],
|
||||
rulesFiles: [
|
||||
{
|
||||
relativePath: "rule1.md",
|
||||
content: "# Rule 1\nFollow this rule.",
|
||||
},
|
||||
{
|
||||
relativePath: "subfolder/rule2.md",
|
||||
content: "# Rule 2\nFollow this other rule.",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(validate.errors).toBeNull()
|
||||
expect(valid).toBe(true)
|
||||
})
|
||||
|
||||
it("should accept a mode with empty rulesFiles array", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "empty-rules",
|
||||
name: "Empty Rules",
|
||||
roleDefinition: "A mode with empty rules files.",
|
||||
groups: ["read"],
|
||||
rulesFiles: [],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(validate.errors).toBeNull()
|
||||
expect(valid).toBe(true)
|
||||
})
|
||||
|
||||
it("should accept rulesFiles entries with only relativePath (content is optional)", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "path-only-rules",
|
||||
name: "Path Only Rules",
|
||||
roleDefinition: "A mode with rules files that only have relativePath.",
|
||||
groups: ["read"],
|
||||
rulesFiles: [{ relativePath: "rule1.md" }],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(validate.errors).toBeNull()
|
||||
expect(valid).toBe(true)
|
||||
})
|
||||
|
||||
it("should reject rulesFiles entries missing required relativePath", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "bad-rules",
|
||||
name: "Bad Rules",
|
||||
roleDefinition: "A mode with invalid rules files.",
|
||||
groups: ["read"],
|
||||
rulesFiles: [{ content: "some content" }],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(valid).toBe(false)
|
||||
})
|
||||
|
||||
it("should reject rulesFiles entries with extra properties", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "extra-rules",
|
||||
name: "Extra Rules",
|
||||
roleDefinition: "A mode with extra rule properties.",
|
||||
groups: ["read"],
|
||||
rulesFiles: [{ relativePath: "rule1.md", content: "content", extra: true }],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(valid).toBe(false)
|
||||
})
|
||||
|
||||
it("should accept multiple modes", () => {
|
||||
const config = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "mode-a",
|
||||
name: "Mode A",
|
||||
roleDefinition: "First mode.",
|
||||
groups: ["read"],
|
||||
},
|
||||
{
|
||||
slug: "mode-b",
|
||||
name: "Mode B",
|
||||
roleDefinition: "Second mode.",
|
||||
groups: ["read", "edit"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const valid = validate(config)
|
||||
expect(validate.errors).toBeNull()
|
||||
expect(valid).toBe(true)
|
||||
})
|
||||
})
|
||||
58
packages/types/src/roomodes-schema.ts
Normal file
58
packages/types/src/roomodes-schema.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* Builds the Zod schema for .roomodes configuration files and converts it
|
||||
* to JSON Schema (draft-07). This module is the single source of truth for
|
||||
* both the generator script (scripts/generate-roomodes-schema.ts) and the
|
||||
* drift-detection test.
|
||||
*/
|
||||
|
||||
import { z } from "zod"
|
||||
import { zodToJsonSchema } from "zod-to-json-schema"
|
||||
|
||||
import { toolGroups, deprecatedToolGroups } from "./tool.js"
|
||||
import { groupOptionsSchema, modeConfigSchema } from "./mode.js"
|
||||
|
||||
// Build a ToolGroup enum that includes deprecated groups so existing configs
|
||||
// still validate.
|
||||
const allToolGroups = [...toolGroups, ...deprecatedToolGroups] as [string, ...string[]]
|
||||
const allToolGroupsSchema = z.enum(allToolGroups)
|
||||
|
||||
// Build a GroupEntry schema that uses the extended tool group list.
|
||||
const groupEntrySchema = z.union([allToolGroupsSchema, z.tuple([allToolGroupsSchema, groupOptionsSchema])])
|
||||
|
||||
// Build the RuleFile schema (used during import/export but not part of the
|
||||
// core Zod types).
|
||||
const ruleFileSchema = z.object({
|
||||
relativePath: z.string(),
|
||||
content: z.string().optional(),
|
||||
})
|
||||
|
||||
// Build an extended ModeConfig schema that includes rulesFiles and uses the
|
||||
// extended groups (with deprecated entries).
|
||||
const exportedModeConfigSchema = modeConfigSchema.omit({ groups: true }).extend({
|
||||
groups: z.array(groupEntrySchema),
|
||||
rulesFiles: z.array(ruleFileSchema).optional(),
|
||||
})
|
||||
|
||||
// Build the top-level .roomodes schema.
|
||||
const roomodesZodSchema = z
|
||||
.object({
|
||||
customModes: z.array(exportedModeConfigSchema),
|
||||
})
|
||||
.strict()
|
||||
|
||||
/**
|
||||
* Generates the JSON Schema object for .roomodes configuration files.
|
||||
* Includes metadata fields ($id, title, description).
|
||||
*/
|
||||
export function generateRoomodesJsonSchema(): Record<string, unknown> {
|
||||
const jsonSchema = zodToJsonSchema(roomodesZodSchema, {
|
||||
$refStrategy: "none",
|
||||
target: "jsonSchema7",
|
||||
}) as Record<string, unknown>
|
||||
|
||||
jsonSchema["$id"] = "https://github.com/RooCodeInc/Roo-Code/blob/main/schemas/roomodes.json"
|
||||
jsonSchema["title"] = "Roo Code Custom Modes"
|
||||
jsonSchema["description"] = "Schema for .roomodes configuration files used by Roo Code to define custom modes."
|
||||
|
||||
return jsonSchema
|
||||
}
|
||||
42
pnpm-lock.yaml
generated
42
pnpm-lock.yaml
generated
|
|
@ -725,6 +725,9 @@ importers:
|
|||
'@types/node':
|
||||
specifier: ^24.1.0
|
||||
version: 24.2.1
|
||||
ajv:
|
||||
specifier: ^8.18.0
|
||||
version: 8.18.0
|
||||
globals:
|
||||
specifier: ^16.3.0
|
||||
version: 16.3.0
|
||||
|
|
@ -734,6 +737,9 @@ importers:
|
|||
vitest:
|
||||
specifier: ^3.2.3
|
||||
version: 3.2.4(@types/debug@4.1.12)(@types/node@24.2.1)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
|
||||
zod-to-json-schema:
|
||||
specifier: ^3.25.1
|
||||
version: 3.25.1(zod@3.25.76)
|
||||
|
||||
packages/vscode-shim:
|
||||
devDependencies:
|
||||
|
|
@ -4939,6 +4945,9 @@ packages:
|
|||
ajv@6.12.6:
|
||||
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
||||
|
||||
ajv@8.18.0:
|
||||
resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==}
|
||||
|
||||
ansi-colors@4.1.3:
|
||||
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
|
||||
engines: {node: '>=6'}
|
||||
|
|
@ -5174,6 +5183,7 @@ packages:
|
|||
basic-ftp@5.0.5:
|
||||
resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
deprecated: Security vulnerability fixed in 5.2.0, please upgrade
|
||||
|
||||
better-path-resolve@1.0.0:
|
||||
resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==}
|
||||
|
|
@ -6621,6 +6631,9 @@ packages:
|
|||
fast-shallow-equal@1.0.0:
|
||||
resolution: {integrity: sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==}
|
||||
|
||||
fast-uri@3.1.0:
|
||||
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
|
||||
|
||||
fast-xml-parser@5.2.3:
|
||||
resolution: {integrity: sha512-OdCYfRqfpuLUFonTNjvd30rCBZUneHpSQkCqfaeWQ9qrKcl6XlWeDBNVwGb+INAIxRshuN2jF+BE0L6gbBO2mw==}
|
||||
hasBin: true
|
||||
|
|
@ -7649,6 +7662,9 @@ packages:
|
|||
json-schema-traverse@0.4.1:
|
||||
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
|
||||
|
||||
json-schema-traverse@1.0.0:
|
||||
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
|
||||
|
||||
json-schema@0.4.0:
|
||||
resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
|
||||
|
||||
|
|
@ -9431,6 +9447,10 @@ packages:
|
|||
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
require-from-string@2.0.2:
|
||||
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
resize-observer-polyfill@1.5.1:
|
||||
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
|
||||
|
||||
|
|
@ -11064,6 +11084,11 @@ packages:
|
|||
peerDependencies:
|
||||
zod: 3.25.76
|
||||
|
||||
zod-to-json-schema@3.25.1:
|
||||
resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==}
|
||||
peerDependencies:
|
||||
zod: 3.25.76
|
||||
|
||||
zod-to-ts@1.2.0:
|
||||
resolution: {integrity: sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==}
|
||||
peerDependencies:
|
||||
|
|
@ -15248,6 +15273,13 @@ snapshots:
|
|||
json-schema-traverse: 0.4.1
|
||||
uri-js: 4.4.1
|
||||
|
||||
ajv@8.18.0:
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
fast-uri: 3.1.0
|
||||
json-schema-traverse: 1.0.0
|
||||
require-from-string: 2.0.2
|
||||
|
||||
ansi-colors@4.1.3: {}
|
||||
|
||||
ansi-escapes@7.0.0:
|
||||
|
|
@ -17090,6 +17122,8 @@ snapshots:
|
|||
|
||||
fast-shallow-equal@1.0.0: {}
|
||||
|
||||
fast-uri@3.1.0: {}
|
||||
|
||||
fast-xml-parser@5.2.3:
|
||||
dependencies:
|
||||
strnum: 2.1.1
|
||||
|
|
@ -18219,6 +18253,8 @@ snapshots:
|
|||
|
||||
json-schema-traverse@0.4.1: {}
|
||||
|
||||
json-schema-traverse@1.0.0: {}
|
||||
|
||||
json-schema@0.4.0: {}
|
||||
|
||||
json-stable-stringify-without-jsonify@1.0.1: {}
|
||||
|
|
@ -20432,6 +20468,8 @@ snapshots:
|
|||
|
||||
require-directory@2.1.1: {}
|
||||
|
||||
require-from-string@2.0.2: {}
|
||||
|
||||
resize-observer-polyfill@1.5.1: {}
|
||||
|
||||
resolve-from@4.0.0: {}
|
||||
|
|
@ -22377,6 +22415,10 @@ snapshots:
|
|||
dependencies:
|
||||
zod: 3.25.76
|
||||
|
||||
zod-to-json-schema@3.25.1(zod@3.25.76):
|
||||
dependencies:
|
||||
zod: 3.25.76
|
||||
|
||||
zod-to-ts@1.2.0(typescript@5.8.3)(zod@3.25.76):
|
||||
dependencies:
|
||||
typescript: 5.8.3
|
||||
|
|
|
|||
96
schemas/roomodes.json
Normal file
96
schemas/roomodes.json
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"customModes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"slug": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z0-9-]+$"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"roleDefinition": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"whenToUse": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"customInstructions": {
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"enum": ["global", "project"]
|
||||
},
|
||||
"groups": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["read", "edit", "command", "mcp", "modes", "browser"]
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"minItems": 2,
|
||||
"maxItems": 2,
|
||||
"items": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["read", "edit", "command", "mcp", "modes", "browser"]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fileRegex": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"rulesFiles": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"relativePath": {
|
||||
"type": "string"
|
||||
},
|
||||
"content": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["relativePath"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["slug", "name", "roleDefinition", "groups"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["customModes"],
|
||||
"additionalProperties": false,
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://github.com/RooCodeInc/Roo-Code/blob/main/schemas/roomodes.json",
|
||||
"title": "Roo Code Custom Modes",
|
||||
"description": "Schema for .roomodes configuration files used by Roo Code to define custom modes."
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue