diff --git a/skills/rig/samples/371-json-fixture-anonymizer.md b/skills/rig/samples/371-json-fixture-anonymizer.md new file mode 100644 index 0000000..8946968 --- /dev/null +++ b/skills/rig/samples/371-json-fixture-anonymizer.md @@ -0,0 +1,35 @@ +# 371 - Json Fixture Anonymizer + +```rig +import { agent, p, s, defineTool, repair } from "rig"; + +const anonymizeValue = defineTool("anonymizeValue", { + description: "Anonymize a field value based on the field name.", + parameters: s.object({ fieldName: s.string, value: s.string }), + handler({ fieldName, value }) { + const lower = fieldName.toLowerCase(); + if (lower.includes("email")) return "redacted@example.com" as const; + if (lower.includes("name")) return "John Doe" as const; + if (lower.includes("phone")) return "XXX-XXXX" as const; + if (lower.includes("id")) return String(Math.abs(value.split("").reduce((a: number, c: string) => a + c.charCodeAt(0), 0))); + return "REDACTED" as const; + }, +}); + +// Agent role: Read a JSON fixture file, anonymize specified fields, and write sanitized output. +const jsonFixtureAnonymizer = agent({ + model: "small", + input: s.object({ inputFile: s.path, outputFile: s.path, fieldsToAnonymize: s.array(s.string) }), + instructions: p`Read ${p.readInput("inputFile")}, anonymize the fields listed in fieldsToAnonymize using the anonymizeValue tool, then write the sanitized JSON to ${p.writeInput("outputFile", "anonymizedContent")}.`, + output: s.object({ + fieldsAnonymized: s.int, + totalRecords: s.int, + outputPath: s.path, + anonymizedFields: s.array(s.string), + }), + tools: [anonymizeValue], + addons: [repair()], +}); + +export default jsonFixtureAnonymizer; +``` diff --git a/skills/rig/samples/372-csv-to-markdown-table.md b/skills/rig/samples/372-csv-to-markdown-table.md new file mode 100644 index 0000000..d35aeb9 --- /dev/null +++ b/skills/rig/samples/372-csv-to-markdown-table.md @@ -0,0 +1,30 @@ +# 372 - Csv To Markdown Table + +```rig +import { agent, p, s, defineTool, repair } from "rig"; + +const parseCSVRow = defineTool("parseCSVRow", { + description: "Parse a single CSV row into an array of trimmed string values.", + parameters: s.object({ row: s.string }), + handler({ row }) { + return row.split(",").map((cell: string) => cell.trim()); + }, +}); + +// Agent role: Convert a CSV file to a Markdown table and write it to the output file. +const csvToMarkdownTable = agent({ + model: "small", + input: s.object({ csvFile: s.path, outputFile: s.path, includeStats: s.boolean }), + instructions: p`Read ${p.readInput("csvFile")}, parse each row using parseCSVRow, format as a Markdown table, and write to ${p.writeInput("outputFile", "markdownContent")}. If includeStats is true, append row and column statistics.`, + output: s.object({ + rowCount: s.int, + columnCount: s.int, + outputFile: s.path, + headers: s.array(s.string), + }), + tools: [parseCSVRow], + addons: [repair()], +}); + +export default csvToMarkdownTable; +``` diff --git a/skills/rig/samples/373-toml-config-section-analyzer.md b/skills/rig/samples/373-toml-config-section-analyzer.md new file mode 100644 index 0000000..22b7bfc --- /dev/null +++ b/skills/rig/samples/373-toml-config-section-analyzer.md @@ -0,0 +1,29 @@ +# 373 - Toml Config Section Analyzer + +```rig +import { agent, p, s, defineTool, repair } from "rig"; +import { readFile } from "node:fs/promises"; + +const analyzeTomlFile = defineTool("analyzeTomlFile", { + description: "Read a TOML file and extract its top-level section headers and key count.", + parameters: s.object({ filePath: s.path }), + async handler({ filePath }) { + const content = await readFile(filePath, "utf8"); + const sections = [...content.matchAll(/^\[(\w+)\]/gm)].map((m: RegExpMatchArray) => m[1]); + const keyCount = content.split("\n").filter((l: string) => /^\w+\s*=/.test(l)).length; + const hasRequired = sections.includes("dependencies") || sections.includes("package"); + return { sections, keyCount, hasRequired }; + }, +}); + +// Agent role: Discover all TOML files and analyze their section structure. +const tomlConfigAnalyzer = agent({ + model: "small", + instructions: p`Analyze TOML files found at ${p.glob("**/*.toml")} using the analyzeTomlFile tool. Return results keyed by file path.`, + output: s.record(s.object({ sections: s.array(s.string), keyCount: s.int, hasRequired: s.boolean })), + tools: [analyzeTomlFile], + addons: [repair()], +}); + +export default tomlConfigAnalyzer; +``` diff --git a/skills/rig/samples/374-git-checkpoint-summarizer.md b/skills/rig/samples/374-git-checkpoint-summarizer.md new file mode 100644 index 0000000..1ed2fb5 --- /dev/null +++ b/skills/rig/samples/374-git-checkpoint-summarizer.md @@ -0,0 +1,35 @@ +# 374 - Git Checkpoint Summarizer + +```rig +import { agent, p, s, defineTool, repair } from "rig"; + +const classifyCheckpoint = defineTool("classifyCheckpoint", { + description: "Classify a git checkpoint string as stash, commit, tag, or branch.", + parameters: s.object({ ref: s.string }), + handler({ ref }) { + if (ref.startsWith("stash@")) return "stash" as const; + if (/^v?\d+\.\d+/.test(ref)) return "tag" as const; + if (/^[0-9a-f]{7,40}/.test(ref.split(" ")[0])) return "commit" as const; + return "branch" as const; + }, +}); + +// Agent role: Summarize git stash and commit checkpoints in the repository. +const gitCheckpointSummarizer = agent({ + model: "small", + instructions: p`Review git checkpoints: +Stash list: ${p.bash("git stash list")} +Recent commits: ${p.bash("git log --oneline -10")} + +Use classifyCheckpoint to classify each entry and return a summary.`, + output: s.object({ + checkpoints: s.array(s.object({ ref: s.string, type: s.enum("stash", "commit", "tag", "branch"), message: s.string })), + latestCheckpoint: s.optional(s.string), + totalCount: s.int, + }), + tools: [classifyCheckpoint], + addons: [repair()], +}); + +export default gitCheckpointSummarizer; +``` diff --git a/skills/rig/samples/375-ts-literal-union-extractor.md b/skills/rig/samples/375-ts-literal-union-extractor.md new file mode 100644 index 0000000..2db18a6 --- /dev/null +++ b/skills/rig/samples/375-ts-literal-union-extractor.md @@ -0,0 +1,33 @@ +# 375 - Ts Literal Union Extractor + +```rig +import { agent, p, s, defineTool, steering } from "rig"; +import { readFile } from "node:fs/promises"; + +const extractLiteralUnions = defineTool("extractLiteralUnions", { + description: "Extract TypeScript string literal type unions from a source file.", + parameters: s.object({ filePath: s.path }), + async handler({ filePath }) { + const content = await readFile(filePath, "utf8"); + const results: Record = {}; + const regex = /type\s+(\w+)\s*=\s*((?:'[^']*'|"[^"]*")\s*(?:\|\s*(?:'[^']*'|"[^"]*")\s*)*)/g; + for (const match of content.matchAll(regex)) { + const name = match[1]; + const members = [...match[2].matchAll(/['"]([^'"]+)['"]/g)].map((m: RegExpMatchArray) => m[1]); + results[name] = { members, memberCount: members.length, isStringLiteral: true }; + } + return results; + }, +}); + +// Agent role: Scan TypeScript files to find and catalog all string literal type union definitions. +const tsLiteralUnionExtractor = agent({ + model: "small", + instructions: p`Find TypeScript files: ${p.bash("find . -name '*.ts' -not -path '*/node_modules/*' | head -30")}. Use extractLiteralUnions on each file to collect all string literal type unions.`, + output: s.record(s.object({ members: s.array(s.string), memberCount: s.int, isStringLiteral: s.boolean })), + tools: [extractLiteralUnions], + addons: [steering()], +}); + +export default tsLiteralUnionExtractor; +``` diff --git a/skills/rig/samples/376-markdown-heading-validator.md b/skills/rig/samples/376-markdown-heading-validator.md new file mode 100644 index 0000000..58f1779 --- /dev/null +++ b/skills/rig/samples/376-markdown-heading-validator.md @@ -0,0 +1,44 @@ +# 376 - Markdown Heading Validator + +```rig +import { agent, p, s, defineTool, repair } from "rig"; +import { readFile } from "node:fs/promises"; + +const validateHeadings = defineTool("validateHeadings", { + description: "Validate Markdown heading structure in a file — check for skipped levels and multiple H1s.", + parameters: s.object({ filePath: s.path }), + async handler({ filePath }) { + const content = await readFile(filePath, "utf8"); + const headings = [...content.matchAll(/^(#{1,6})\s+(.+)$/gm)].map((m: RegExpMatchArray) => ({ + level: m[1].length, + text: m[2].trim(), + })); + const issues: string[] = []; + const h1Count = headings.filter((h: { level: number; text: string }) => h.level === 1).length; + if (h1Count > 1) issues.push(`Multiple H1 headings found (${h1Count})`); + for (let i = 1; i < headings.length; i++) { + if (headings[i].level > headings[i - 1].level + 1) { + issues.push(`Heading level skipped: H${headings[i - 1].level} → H${headings[i].level}`); + } + } + const maxDepth = headings.reduce((max: number, h: { level: number; text: string }) => Math.max(max, h.level), 0); + return { headings, maxDepth, isValid: issues.length === 0, issues }; + }, +}); + +// Agent role: Validate the heading structure of all Markdown files in the workspace. +const markdownHeadingValidator = agent({ + model: "small", + instructions: p`Validate Markdown heading structure for files found at ${p.glob("**/*.md")}. Use validateHeadings on each file and return results keyed by file path.`, + output: s.record(s.object({ + headings: s.array(s.object({ level: s.int, text: s.string })), + maxDepth: s.int, + isValid: s.boolean, + issues: s.array(s.string), + })), + tools: [validateHeadings], + addons: [repair()], +}); + +export default markdownHeadingValidator; +``` diff --git a/skills/rig/samples/377-ts-barrel-module-writer.md b/skills/rig/samples/377-ts-barrel-module-writer.md new file mode 100644 index 0000000..a4a6200 --- /dev/null +++ b/skills/rig/samples/377-ts-barrel-module-writer.md @@ -0,0 +1,30 @@ +# 377 - Ts Barrel Module Writer + +```rig +import { agent, p, s, defineTool, repair } from "rig"; + +const validateExportName = defineTool("validateExportName", { + description: "Validate that a string is a valid JavaScript identifier for export.", + parameters: s.object({ name: s.string }), + handler({ name }) { + return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name); + }, +}); + +// Agent role: Generate a TypeScript barrel module that re-exports the given symbols and write it to the target file. +const tsBarrelModuleWriter = agent({ + model: "small", + input: s.object({ targetFile: s.path, moduleName: s.string, exports: s.array(s.string) }), + instructions: p`Given the input targetFile, moduleName, and exports array, validate each export name using validateExportName, generate barrel export lines, and write the module to ${p.writeInput("targetFile", "moduleContent")}.`, + output: s.object({ + outputFile: s.path, + exportsWritten: s.array(s.string), + moduleLines: s.int, + success: s.boolean, + }), + tools: [validateExportName], + addons: [repair()], +}); + +export default tsBarrelModuleWriter; +``` diff --git a/skills/rig/samples/378-git-remote-metadata-inspector.md b/skills/rig/samples/378-git-remote-metadata-inspector.md new file mode 100644 index 0000000..7ca5bc7 --- /dev/null +++ b/skills/rig/samples/378-git-remote-metadata-inspector.md @@ -0,0 +1,35 @@ +# 378 - Git Remote Metadata Inspector + +```rig +import { agent, p, s, defineTool, steering } from "rig"; + +const classifyRemote = defineTool("classifyRemote", { + description: "Classify a git remote URL into its hosting provider.", + parameters: s.object({ url: s.string }), + handler({ url }) { + if (url.includes("github.com")) return "github" as const; + if (url.includes("gitlab.com")) return "gitlab" as const; + if (url.includes("bitbucket.org")) return "bitbucket" as const; + return "other" as const; + }, +}); + +// Agent role: Inspect git remote metadata and classify each remote by provider. +const gitRemoteMetadataInspector = agent({ + model: "small", + instructions: p`Inspect git remotes: +Remotes: ${p.bash("git remote -v")} +Branch count: ${p.bash("git ls-remote --heads origin 2>/dev/null | wc -l")} + +Use classifyRemote for each remote URL and return results keyed by remote name.`, + output: s.record(s.object({ + url: s.string, + type: s.enum("github", "gitlab", "bitbucket", "other"), + branchCount: s.int, + })), + tools: [classifyRemote], + addons: [steering()], +}); + +export default gitRemoteMetadataInspector; +``` diff --git a/skills/rig/samples/379-os-env-variable-scanner.md b/skills/rig/samples/379-os-env-variable-scanner.md new file mode 100644 index 0000000..2e8cf77 --- /dev/null +++ b/skills/rig/samples/379-os-env-variable-scanner.md @@ -0,0 +1,34 @@ +# 379 - Os Env Variable Scanner + +```rig +import { agent, p, s, defineTool, repair } from "rig"; + +const classifyEnvVar = defineTool("classifyEnvVar", { + description: "Classify an environment variable by its name and value into a category.", + parameters: s.object({ name: s.string, value: s.string }), + handler({ name }) { + if (name === "PATH" || name.endsWith("_PATH") || name.endsWith("_HOME")) return "path" as const; + if (name.startsWith("LANG") || name.startsWith("LC_")) return "locale" as const; + if (name === "HOME" || name === "USER" || name === "USERNAME" || name === "LOGNAME") return "home" as const; + if (name === "EDITOR" || name === "VISUAL" || name === "PAGER") return "editor" as const; + if (name === "CI" || name.startsWith("GITHUB_") || name.startsWith("RUNNER_") || name.startsWith("ACTIONS_")) return "ci" as const; + return "custom" as const; + }, +}); + +// Agent role: Scan all OS environment variables and categorize them by type. +const osEnvVariableScanner = agent({ + model: "small", + instructions: p`Scan environment variables: ${p.bash("env")}. Use classifyEnvVar on each variable and return a summary.`, + output: s.object({ + vars: s.record(s.object({ value: s.string, category: s.enum("path", "locale", "home", "editor", "ci", "custom") })), + totalVars: s.int, + ciEnvCount: s.int, + customCount: s.int, + }), + tools: [classifyEnvVar], + addons: [repair()], +}); + +export default osEnvVariableScanner; +``` diff --git a/skills/rig/samples/380-sequential-commit-classifier-workflow.md b/skills/rig/samples/380-sequential-commit-classifier-workflow.md new file mode 100644 index 0000000..b46e25e --- /dev/null +++ b/skills/rig/samples/380-sequential-commit-classifier-workflow.md @@ -0,0 +1,49 @@ +# 380 - Sequential Commit Classifier Workflow + +```rig +import { agent, workflow, p, s } from "rig"; + +// Agent role: Collect recent git commits from the repository. +const commitCollector = agent({ + model: "small", + instructions: p`Collect recent commits: ${p.bash("git log --oneline -10")}. Return each as hash and message.`, + output: s.object({ + commits: s.array(s.object({ hash: s.string, message: s.string })), + }), +}); + +// Agent role: Classify each commit message into a conventional commit category. +const commitClassifier = agent({ + model: "small", + input: s.object({ commits: s.array(s.object({ hash: s.string, message: s.string })) }), + instructions: p`Classify each commit in the input. Return the hash and category for each.`, + output: s.array(s.object({ hash: s.string, category: s.enum("feat", "fix", "chore", "docs", "other") })), +}); + +// Agent role: Aggregate classified commits into a summary report. +const commitAggregator = agent({ + model: "small", + input: s.array(s.object({ hash: s.string, category: s.enum("feat", "fix", "chore", "docs", "other") })), + instructions: p`Count how many commits fall into each category and identify the top category.`, + output: s.object({ + summary: s.record(s.int), + totalCommits: s.int, + topCategory: s.string, + }), +}); + +// Workflow role: Pipeline three agents to collect, classify, and aggregate recent git commits. +export default workflow({ + meta: { name: "sequential-commit-classifier", description: "Collect, classify, and aggregate recent git commits.", phases: ["Collect", "Classify", "Aggregate"] }, + body: async ({ call, phase }) => { + phase("Collect"); + const step1 = await call(commitCollector, "Collect recent commits."); + if (!step1) return null; + phase("Classify"); + const step2 = await call(commitClassifier, { commits: step1.commits }); + if (!step2) return null; + phase("Aggregate"); + return call(commitAggregator, step2); + }, +}); +```