Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 97x 56x 41x 8x 8x 8x 8x 8x 8x 8x 8x 8x 112x 112x 110x 2x 110x 112x 95x 97x 1x | import { z } from 'zod';
import { RuntimeNameSchema, type RuntimeName } from '../sdk/runtimes/types.js';
import { SeverityThresholdSchema, ConfidenceThresholdSchema } from '../types/index.js';
// Tool names that can be allowed/denied
export const ToolNameSchema = z.enum([
'Read',
'Write',
'Edit',
'Bash',
'Glob',
'Grep',
'WebFetch',
'WebSearch',
]);
export type ToolName = z.infer<typeof ToolNameSchema>;
// Tool configuration for skills
export const ToolConfigSchema = z.object({
allowed: z.array(ToolNameSchema).optional(),
denied: z.array(ToolNameSchema).optional(),
});
export type ToolConfig = z.infer<typeof ToolConfigSchema>;
// Skill definition
export const SkillDefinitionSchema = z.object({
name: z.string().min(1),
description: z.string(),
prompt: z.string(),
tools: ToolConfigSchema.optional(),
/** Directory where the skill was loaded from, for resolving resources (scripts/, references/, assets/) */
rootDir: z.string().optional(),
});
export type SkillDefinition = z.infer<typeof SkillDefinitionSchema>;
// Schedule-specific configuration
export const ScheduleConfigSchema = z.object({
/** Title for the tracking issue (default: "Warden: {skillName}") */
issueTitle: z.string().optional(),
/** Create PR with fixes when suggestedFix is available */
createFixPR: z.boolean().default(false),
/** Branch prefix for fix PRs (default: "warden-fix") */
fixBranchPrefix: z.string().default('warden-fix'),
});
export type ScheduleConfig = z.infer<typeof ScheduleConfigSchema>;
// Trigger type: where the trigger runs
export const TriggerTypeSchema = z.enum(['pull_request', 'local', 'schedule']);
export type TriggerType = z.infer<typeof TriggerTypeSchema>;
export { RuntimeNameSchema };
export type { RuntimeName };
export const AgentRuntimeConfigSchema = z.object({
/** Model for repo-aware skill execution. Overrides legacy defaults.model. */
model: z.string().optional(),
/** Maximum agentic turns for repo-aware skill execution. Overrides legacy defaults.maxTurns. */
maxTurns: z.number().int().positive().optional(),
}).strict();
export type AgentRuntimeConfig = z.infer<typeof AgentRuntimeConfigSchema>;
export const AuxiliaryRuntimeConfigSchema = z.object({
/** Model for auxiliary structured model calls. Uses runtime default if omitted. */
model: z.string().optional(),
/** Max retries for auxiliary structured model calls. Overrides legacy auxiliaryMaxRetries. */
maxRetries: z.number().int().positive().optional(),
}).strict();
export type AuxiliaryRuntimeConfig = z.infer<typeof AuxiliaryRuntimeConfigSchema>;
export const SynthesisRuntimeConfigSchema = z.object({
/** Model for post-analysis synthesis/consolidation. Falls back to auxiliary.model if omitted. */
model: z.string().optional(),
}).strict();
export type SynthesisRuntimeConfig = z.infer<typeof SynthesisRuntimeConfigSchema>;
export const VerificationConfigSchema = z.object({
/** Verify candidate findings in a second read-only pass. Defaults to true. */
enabled: z.boolean().optional(),
}).strict();
export type VerificationConfig = z.infer<typeof VerificationConfigSchema>;
// Skill trigger definition (nested under [[skills.triggers]])
export const SkillTriggerSchema = z.object({
/** Trigger type: pull_request (GitHub), local (CLI), or schedule (cron) */
type: TriggerTypeSchema,
/** Actions to trigger on (only for pull_request type) */
actions: z.array(z.string()).min(1).optional(),
// Per-trigger overrides (flattened output fields)
failOn: SeverityThresholdSchema.optional(),
reportOn: SeverityThresholdSchema.optional(),
maxFindings: z.number().int().positive().optional(),
reportOnSuccess: z.boolean().optional(),
/** Use REQUEST_CHANGES review event when findings exceed failOn */
requestChanges: z.boolean().optional(),
/** Fail the check run when findings exceed failOn */
failCheck: z.boolean().optional(),
model: z.string().optional(),
maxTurns: z.number().int().positive().optional(),
/** Minimum confidence level for findings. Findings below this are filtered from output. */
minConfidence: ConfidenceThresholdSchema.optional(),
/** Schedule-specific configuration. Only used when type is 'schedule'. */
schedule: ScheduleConfigSchema.optional(),
}).refine(
(data) => {
// actions is required for pull_request type
if (data.type === 'pull_request') {
return data.actions !== undefined && data.actions.length > 0;
}
return true;
},
{
message: "actions is required for pull_request triggers",
path: ["actions"],
}
);
export type SkillTrigger = z.infer<typeof SkillTriggerSchema>;
// Skill configuration (top-level [[skills]])
export const SkillConfigSchema = z.object({
name: z.string().min(1),
/** Path patterns to include */
paths: z.array(z.string()).optional(),
/** Path patterns to exclude */
ignorePaths: z.array(z.string()).optional(),
/** Remote repository reference for the skill (e.g., "owner/repo" or "owner/repo@sha") */
remote: z.string().optional(),
// Flattened output fields (skill-level defaults)
failOn: SeverityThresholdSchema.optional(),
reportOn: SeverityThresholdSchema.optional(),
maxFindings: z.number().int().positive().optional(),
reportOnSuccess: z.boolean().optional(),
/** Use REQUEST_CHANGES review event when findings exceed failOn */
requestChanges: z.boolean().optional(),
/** Fail the check run when findings exceed failOn */
failCheck: z.boolean().optional(),
/** Model to use for this skill (e.g., 'openai/gpt-5.5'). Uses SDK default if not specified. */
model: z.string().optional(),
/** Maximum agentic turns (API round-trips) per hunk analysis. Overrides defaults.maxTurns. */
maxTurns: z.number().int().positive().optional(),
/** Minimum confidence level for findings. Findings below this are filtered from output. */
minConfidence: ConfidenceThresholdSchema.optional(),
/** Triggers defining when/where this skill runs. Omit to run everywhere (wildcard). */
triggers: z.array(SkillTriggerSchema).optional(),
});
export type SkillConfig = z.infer<typeof SkillConfigSchema>;
// Runner configuration
export const RunnerConfigSchema = z.object({
/** Max concurrent file analyses across all skills (default: 4) */
concurrency: z.number().int().positive().optional(),
});
export type RunnerConfig = z.infer<typeof RunnerConfigSchema>;
// File pattern for chunking configuration
export const FilePatternSchema = z.object({
/** Glob pattern to match files (e.g., "**\/pnpm-lock.yaml") */
pattern: z.string(),
/** How to handle matching files: 'per-hunk' (default), 'whole-file', or 'skip' */
mode: z.enum(['per-hunk', 'whole-file', 'skip']).default('skip'),
});
export type FilePattern = z.infer<typeof FilePatternSchema>;
// Coalescing configuration for merging nearby hunks
export const CoalesceConfigSchema = z.object({
/** Enable hunk coalescing (default: true) */
enabled: z.boolean().default(true),
/** Max lines gap between hunks to merge (default: 30) */
maxGapLines: z.number().int().nonnegative().default(30),
/** Target max size per chunk in characters (default: 8000) */
maxChunkSize: z.number().int().positive().default(8000),
});
export type CoalesceConfig = z.infer<typeof CoalesceConfigSchema>;
// Chunking configuration for controlling how files are processed
export const ChunkingConfigSchema = z.object({
/** Patterns to control file processing mode */
filePatterns: z.array(FilePatternSchema).optional(),
/** Coalescing options for merging nearby hunks */
coalesce: CoalesceConfigSchema.optional(),
/** Max number of "other files" to list in hunk prompts for PR context. 0 disables the section entirely. Default: 50 */
maxContextFiles: z.number().int().nonnegative().default(50),
});
export type ChunkingConfig = z.infer<typeof ChunkingConfigSchema>;
// Default configuration that skills inherit from
export const DefaultsSchema = z.object({
/** Fail the build when findings meet this severity */
failOn: SeverityThresholdSchema.optional(),
/** Only report findings at or above this severity */
reportOn: SeverityThresholdSchema.optional(),
maxFindings: z.number().int().positive().optional(),
/** Report even when there are no findings (default: false) */
reportOnSuccess: z.boolean().optional(),
/** Use REQUEST_CHANGES review event when findings exceed failOn. Default: false */
requestChanges: z.boolean().optional(),
/** Fail the check run when findings exceed failOn. Default: false */
failCheck: z.boolean().optional(),
/** Default model for all skills (e.g., 'openai/gpt-5.5') */
model: z.string().optional(),
/** Maximum agentic turns (API round-trips) per hunk analysis. Default: 50 */
maxTurns: z.number().int().positive().optional(),
/** Runtime backend for all model-backed execution. Default: pi */
runtime: RuntimeNameSchema.optional(),
/** Model defaults for repo-aware skill execution. */
agent: AgentRuntimeConfigSchema.optional(),
/** Model defaults for auxiliary structured model calls. */
auxiliary: AuxiliaryRuntimeConfigSchema.optional(),
/** Model defaults for post-analysis synthesis/consolidation. */
synthesis: SynthesisRuntimeConfigSchema.optional(),
/** Candidate finding verification. Enabled by default; set enabled=false to opt out. */
verification: VerificationConfigSchema.optional(),
/** Minimum confidence level for findings. Findings below this are filtered from output. Default: medium */
minConfidence: ConfidenceThresholdSchema.optional(),
/** Path patterns to exclude from all skills */
ignorePaths: z.array(z.string()).optional(),
/** Default branch for the repository (e.g., 'main', 'master', 'develop'). Auto-detected if not specified. */
defaultBranch: z.string().optional(),
/** Chunking configuration for controlling how files are processed */
chunking: ChunkingConfigSchema.optional(),
/** Delay in milliseconds between batch starts when processing files in parallel. Default: 0 */
batchDelayMs: z.number().int().nonnegative().optional(),
/** Max retries for auxiliary structured model calls (extraction repair, merging, dedup, fix evaluation). Default: 5 */
auxiliaryMaxRetries: z.number().int().positive().optional(),
});
export type Defaults = z.infer<typeof DefaultsSchema>;
// Log cleanup mode
export const LogCleanupModeSchema = z.enum(['ask', 'auto', 'never']);
export type LogCleanupMode = z.infer<typeof LogCleanupModeSchema>;
// Logs configuration
export const LogsConfigSchema = z.object({
/** How to handle expired log files: 'ask' (default, prompt in TTY), 'auto' (silently delete), 'never' (keep all) */
cleanup: LogCleanupModeSchema.default('ask'),
/** Number of days to retain log files before considering them expired. Default: 30 */
retentionDays: z.number().int().positive().default(30),
});
export type LogsConfig = z.infer<typeof LogsConfigSchema>;
// Main warden.toml configuration
export const WardenConfigSchema = z
.object({
version: z.literal(1),
defaults: DefaultsSchema.optional(),
skills: z.array(SkillConfigSchema).default([]),
runner: RunnerConfigSchema.optional(),
logs: LogsConfigSchema.optional(),
})
.superRefine((config, ctx) => {
const names = config.skills.map((s) => s.name);
const duplicates = names.filter((name, i) => names.indexOf(name) !== i);
if (duplicates.length > 0) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Duplicate skill names: ${[...new Set(duplicates)].join(', ')}`,
path: ['skills'],
});
}
// Validate schedule skills have paths
for (const [i, skill] of config.skills.entries()) {
if (skill.triggers) {
for (const trigger of skill.triggers) {
if (trigger.type === 'schedule' && (!skill.paths || skill.paths.length === 0)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "paths is required for skills with schedule triggers",
path: ['skills', i, 'paths'],
});
}
}
}
}
});
export type WardenConfig = z.infer<typeof WardenConfigSchema>;
|