From 2b77d6cf63952444f396a15d5fb69c40ec2f4202 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 18 Aug 2026 07:48:49 +0000 Subject: [PATCH] =?UTF-8?q?Add=2010=20rig=20samples=20431=E2=80=93440=20(2?= =?UTF-8?q?026-08-18)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generated by daily rig evaluator: - 431: JSONL File Analyzer (reused) - 432: NPM Peer Dep Checker (reused) - 433: TypeScript Barrel Module Writer (reused) - 434: Git Remote Metadata Inspector (reused) - 435: OS Environment Variable Scanner (reused) - 436: Sequential Commit Pipeline (reused) - 437: TypeScript Tuple Pattern Extractor (new) - 438: TypeScript Interface Stub Writer (new) - 439: Git Grep Search Workflow (new) - 440: JSON Union Type Inferrer (new) All 10 passed typecheck. Three programs required fixes: - Task 6 (436): workflow body used (call, input) positional args → fixed to ({call}) destructuring + meta required - Task 7 (437): string array concat type error → added explicit string[] annotations - Task 9 (439): workflow body signature and missing meta → fixed Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- skills/rig/samples/431-jsonl-file-analyzer.md | 47 +++++++++++++++ .../rig/samples/432-npm-peer-dep-checker.md | 45 ++++++++++++++ .../samples/433-ts-barrel-module-writer.md | 40 +++++++++++++ skills/rig/samples/434-git-remote-metadata.md | 35 +++++++++++ skills/rig/samples/435-os-env-scanner.md | 50 ++++++++++++++++ .../samples/436-sequential-commit-pipeline.md | 60 +++++++++++++++++++ .../samples/437-ts-tuple-pattern-extractor.md | 48 +++++++++++++++ .../samples/438-ts-interface-stub-writer.md | 40 +++++++++++++ .../samples/439-git-grep-search-workflow.md | 47 +++++++++++++++ .../samples/440-json-union-type-inferrer.md | 50 ++++++++++++++++ 10 files changed, 462 insertions(+) create mode 100644 skills/rig/samples/431-jsonl-file-analyzer.md create mode 100644 skills/rig/samples/432-npm-peer-dep-checker.md create mode 100644 skills/rig/samples/433-ts-barrel-module-writer.md create mode 100644 skills/rig/samples/434-git-remote-metadata.md create mode 100644 skills/rig/samples/435-os-env-scanner.md create mode 100644 skills/rig/samples/436-sequential-commit-pipeline.md create mode 100644 skills/rig/samples/437-ts-tuple-pattern-extractor.md create mode 100644 skills/rig/samples/438-ts-interface-stub-writer.md create mode 100644 skills/rig/samples/439-git-grep-search-workflow.md create mode 100644 skills/rig/samples/440-json-union-type-inferrer.md diff --git a/skills/rig/samples/431-jsonl-file-analyzer.md b/skills/rig/samples/431-jsonl-file-analyzer.md new file mode 100644 index 0000000..d6edacf --- /dev/null +++ b/skills/rig/samples/431-jsonl-file-analyzer.md @@ -0,0 +1,47 @@ +# jsonl-file-analyzer - JSONL File Analyzer + +```rig +import { agent, p, s, defineTool, repair } from "rig"; + +const analyzeJsonLine = defineTool("analyzeJsonLine", { + description: "Parse a single JSONL line and return validity, keys, and value types.", + parameters: s.object({ + line: s.string, + }), + handler: async ({ line }) => { + try { + const obj = JSON.parse(line); + if (typeof obj !== "object" || obj === null || Array.isArray(obj)) { + return { valid: false, keys: [] as string[], valueTypes: {} as Record }; + } + const keys = Object.keys(obj); + const valueTypes: Record = {}; + for (const k of keys) { + const v = obj[k]; + valueTypes[k] = Array.isArray(v) ? "array" : typeof v; + } + return { valid: true, keys, valueTypes }; + } catch { + return { valid: false, keys: [] as string[], valueTypes: {} as Record }; + } + }, +}); + +// Agent role: analyze a JSONL file, report per-line validity, top keys, and schema consistency. +const jsonlFileAnalyzer = agent({ + model: "small", + input: s.object({ inputFile: s.path }), + output: s.object({ + totalLines: s.int, + validLines: s.int, + invalidLines: s.int, + topKeys: s.array(s.string), + schemaConsistent: s.boolean, + }), + instructions: p`Read the JSONL file at ${p.readInput("inputFile")} line by line. For each non-empty line call analyzeJsonLine. Count total, valid, and invalid lines. Identify the top 5 most frequent keys across all valid lines. Determine if all valid lines share the same key set (schemaConsistent). Return the declared output.`, + tools: [analyzeJsonLine], + addons: [repair()], +}); + +export default jsonlFileAnalyzer; +``` diff --git a/skills/rig/samples/432-npm-peer-dep-checker.md b/skills/rig/samples/432-npm-peer-dep-checker.md new file mode 100644 index 0000000..2c530d4 --- /dev/null +++ b/skills/rig/samples/432-npm-peer-dep-checker.md @@ -0,0 +1,45 @@ +# npm-peer-dep-checker - NPM Peer Dep Checker + +```rig +import { agent, p, s, defineTool, repair } from "rig"; + +const checkPeerConflict = defineTool("checkPeerConflict", { + description: "Classify a peer dependency as conflicting, warn, or ok.", + parameters: s.object({ + package: s.string, + required: s.string, + installed: s.optional(s.string), + }), + handler: async ({ installed, required }) => { + if (!installed) { + return { conflicting: true, reason: "Package not installed", severity: "error" as const }; + } + const [reqMajor] = required.replace(/[\^~>=<]/g, "").split("."); + const [instMajor] = installed.replace(/[\^~>=<]/g, "").split("."); + if (reqMajor !== instMajor) { + return { conflicting: true, reason: `Major version mismatch: required ${required}, installed ${installed}`, severity: "error" as const }; + } + return { conflicting: false, reason: "Compatible", severity: "ok" as const }; + }, +}); + +// Agent role: check npm peer dependency conflicts in the current project. +const npmPeerDepChecker = agent({ + model: "small", + output: s.object({ + conflicts: s.array(s.object({ + package: s.string, + reason: s.string, + severity: s.enum("error", "warning", "ok"), + })), + totalConflicts: s.int, + hasErrors: s.boolean, + hasPeerDeps: s.boolean, + }), + instructions: p`Review ${p.read("package.json")} and run ${p.bash("npm ls --json 2>&1 || true")} to identify peer dependency conflicts. For each peerDependency call checkPeerConflict with the package name, required version, and installed version. Return the list of conflicts, totalConflicts, hasErrors, and hasPeerDeps.`, + tools: [checkPeerConflict], + addons: [repair()], +}); + +export default npmPeerDepChecker; +``` diff --git a/skills/rig/samples/433-ts-barrel-module-writer.md b/skills/rig/samples/433-ts-barrel-module-writer.md new file mode 100644 index 0000000..cd37bea --- /dev/null +++ b/skills/rig/samples/433-ts-barrel-module-writer.md @@ -0,0 +1,40 @@ +# ts-barrel-module-writer - TypeScript Barrel Module Writer + +```rig +import { agent, p, s, defineTool, repair } from "rig"; + +const validateExportName = defineTool("validateExportName", { + description: "Validate that a name is a valid TypeScript identifier for export.", + parameters: s.object({ + name: s.string, + }), + handler: async ({ name }) => { + const valid = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name); + return { + valid, + reason: valid ? undefined : `"${name}" is not a valid TypeScript identifier`, + }; + }, +}); + +// Agent role: write a TypeScript barrel module file exporting named members. +const tsBarrelModuleWriter = agent({ + model: "small", + input: s.object({ + targetFile: s.path, + moduleName: s.string, + exports: s.array(s.string), + }), + output: s.object({ + outputFile: s.path, + exportsWritten: s.array(s.string), + moduleLines: s.int, + success: s.boolean, + }), + instructions: p`You are writing a TypeScript barrel module. For each name in input.exports, call validateExportName to verify it is a valid identifier. Then write a barrel module to ${p.writeOutput("outputFile", "targetFile")} that re-exports each valid name. The module should contain one export line per valid identifier: \`export { name } from "./name";\`. Return outputFile, exportsWritten (the valid exports written), moduleLines (total lines in the file), and success (true if at least one export was written).`, + tools: [validateExportName], + addons: [repair()], +}); + +export default tsBarrelModuleWriter; +``` diff --git a/skills/rig/samples/434-git-remote-metadata.md b/skills/rig/samples/434-git-remote-metadata.md new file mode 100644 index 0000000..37092a3 --- /dev/null +++ b/skills/rig/samples/434-git-remote-metadata.md @@ -0,0 +1,35 @@ +# git-remote-metadata - Git Remote Metadata Inspector + +```rig +import { agent, p, s, defineTool, steering } from "rig"; + +const classifyRemote = defineTool("classifyRemote", { + description: "Classify a git remote URL by hosting provider.", + parameters: s.object({ + name: s.string, + url: s.string, + }), + handler: async ({ url }) => { + if (/github\.com/i.test(url)) return { type: "github" as const }; + if (/gitlab\.com/i.test(url)) return { type: "gitlab" as const }; + if (/bitbucket\.org/i.test(url)) return { type: "bitbucket" as const }; + return { type: "other" as const }; + }, +}); + +// Agent role: inspect git remotes and report their URLs, types, and branch counts. +const gitRemoteMetadataInspector = agent({ + model: "small", + output: s.record(s.object({ + url: s.string, + type: s.enum("github", "gitlab", "bitbucket", "other"), + branchCount: s.int, + })), + instructions: p`List git remotes with ${p.bash("git remote -v")} then for each unique remote call classifyRemote with its name and fetch URL. Count remote branches with ${p.bash("git ls-remote --heads --quiet 2>/dev/null | wc -l")}. Return a record keyed by remote name containing url, type, and branchCount.`, + tools: [classifyRemote], + addons: [steering()], + maxTurns: 3, +}); + +export default gitRemoteMetadataInspector; +``` diff --git a/skills/rig/samples/435-os-env-scanner.md b/skills/rig/samples/435-os-env-scanner.md new file mode 100644 index 0000000..c4297c8 --- /dev/null +++ b/skills/rig/samples/435-os-env-scanner.md @@ -0,0 +1,50 @@ +# os-env-scanner - OS Environment Variable Scanner + +```rig +import { agent, p, s, defineTool, repair } from "rig"; + +const classifyEnvVar = defineTool("classifyEnvVar", { + description: "Classify an OS environment variable by category.", + parameters: s.object({ + name: s.string, + value: s.string, + }), + handler: async ({ name }) => { + if (/^(PATH|LD_LIBRARY_PATH|DYLD_LIBRARY_PATH|MANPATH|PKG_CONFIG_PATH)$/i.test(name)) { + return { category: "path" as const }; + } + if (/^(LANG|LANGUAGE|LC_\w+)$/i.test(name)) { + return { category: "locale" as const }; + } + if (/^(HOME|USER|LOGNAME|SHELL|USERNAME)$/i.test(name)) { + return { category: "home" as const }; + } + if (/^(EDITOR|VISUAL|PAGER|BROWSER)$/i.test(name)) { + return { category: "editor" as const }; + } + if (/^(CI|GITHUB_|JENKINS_|TRAVIS|CIRCLECI|GITLAB_CI|BUILD_|RUNNER_)/i.test(name)) { + return { category: "ci" as const }; + } + return { category: "custom" as const }; + }, +}); + +// Agent role: scan OS environment variables and categorize them. +const osEnvScanner = agent({ + model: "small", + 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, + }), + instructions: p`List all environment variables with ${p.bash("env")}. For each variable call classifyEnvVar with its name and value. Return a vars record keyed by variable name, plus totalVars, ciEnvCount (count of ci-category vars), and customCount (count of custom-category vars).`, + tools: [classifyEnvVar], + addons: [repair()], +}); + +export default osEnvScanner; +``` diff --git a/skills/rig/samples/436-sequential-commit-pipeline.md b/skills/rig/samples/436-sequential-commit-pipeline.md new file mode 100644 index 0000000..f729555 --- /dev/null +++ b/skills/rig/samples/436-sequential-commit-pipeline.md @@ -0,0 +1,60 @@ +# sequential-commit-pipeline - Sequential Commit Pipeline + +```rig +import { workflow, agent, p, s } from "rig"; + +// Agent role: collect recent git commits as structured data. +const commitCollector = agent({ + model: "small", + output: s.object({ + commits: s.array(s.object({ hash: s.string, message: s.string })), + }), + instructions: p`Run ${p.bash("git log --oneline -20")} and parse each line into hash and message. Return the commits array.`, +}); + +// Agent role: classify each commit by conventional commit type. +const commitClassifier = agent({ + model: "small", + input: s.object({ + commits: s.array(s.object({ hash: s.string, message: s.string })), + }), + output: s.object({ + classified: s.array(s.object({ + hash: s.string, + message: s.string, + type: s.enum("feat", "fix", "chore", "docs", "other"), + })), + }), + instructions: `Classify each commit by its conventional commit type prefix. feat → "feat", fix → "fix", chore/build/ci/refactor/test/style/perf → "chore", docs → "docs", everything else → "other". Return classified array.`, +}); + +// Agent role: aggregate classified commits into a summary record. +const commitAggregator = agent({ + model: "small", + input: s.object({ + classified: s.array(s.object({ + hash: s.string, + message: s.string, + type: s.enum("feat", "fix", "chore", "docs", "other"), + })), + }), + output: s.object({ + summary: s.record(s.int), + totalCommits: s.int, + topCategory: s.string, + }), + instructions: `Count the number of commits per type. Return summary as a record of type→count, totalCommits, and topCategory (the type with the highest count).`, +}); + +// Workflow role: pipeline git commits through collection, classification, and aggregation. +export default workflow({ + meta: { name: "sequential-commit-pipeline", description: "Collect, classify, and aggregate git commits in sequence." }, + body: async ({ call }) => { + const r1 = await call(commitCollector, "Collect recent commits."); + if (!r1) return null; + const r2 = await call(commitClassifier, { commits: r1.commits }); + if (!r2) return null; + return call(commitAggregator, r2); + }, +}); +``` diff --git a/skills/rig/samples/437-ts-tuple-pattern-extractor.md b/skills/rig/samples/437-ts-tuple-pattern-extractor.md new file mode 100644 index 0000000..fc2842c --- /dev/null +++ b/skills/rig/samples/437-ts-tuple-pattern-extractor.md @@ -0,0 +1,48 @@ +# ts-tuple-pattern-extractor - TypeScript Tuple Pattern Extractor + +```rig +import { agent, p, s, defineTool, repair } from "rig"; + +const extractTuplePatternsFromFile = defineTool("extractTuplePatternsFromFile", { + description: "Count tuple type patterns in a TypeScript file.", + parameters: s.object({ + filePath: s.string, + }), + handler: async ({ filePath }) => { + const { readFile } = await import("node:fs/promises"); + const content = await readFile(filePath, "utf8"); + const tuplePattern = /:\s*\[[\w\s,.|&?<>]+\]/g; + const readonlyPattern = /readonly\s*\[[\w\s,.|&?<>\.\.\.]+\]/g; + const spreadPattern = /\.\.\.\w+/g; + const tuples: string[] = content.match(tuplePattern) ?? []; + const readonlyTuples: string[] = content.match(readonlyPattern) ?? []; + const allTuples = tuples.concat(readonlyTuples); + const hasSpreads = allTuples.some((t) => spreadPattern.test(t)); + return { + tupleCount: allTuples.length, + hasSpreads, + readonlyCount: readonlyTuples.length, + }; + }, +}); + +// Agent role: scan TypeScript source files for tuple type patterns and report statistics. +const tsTuplePatternExtractor = agent({ + model: "small", + output: s.object({ + files: s.record(s.object({ + tupleCount: s.int, + hasSpreads: s.boolean, + readonlyCount: s.int, + })), + totalTuples: s.int, + totalFiles: s.int, + mostTupledFile: s.optional(s.string), + }), + instructions: p`Find TypeScript files with ${p.glob("src/**/*.ts")}. For each file call extractTuplePatternsFromFile. Return a files record keyed by path, totalTuples (sum of all tupleCount), totalFiles, and mostTupledFile (path with highest tupleCount, or omit if none found).`, + tools: [extractTuplePatternsFromFile], + addons: [repair()], +}); + +export default tsTuplePatternExtractor; +``` diff --git a/skills/rig/samples/438-ts-interface-stub-writer.md b/skills/rig/samples/438-ts-interface-stub-writer.md new file mode 100644 index 0000000..3bd2f2d --- /dev/null +++ b/skills/rig/samples/438-ts-interface-stub-writer.md @@ -0,0 +1,40 @@ +# ts-interface-stub-writer - TypeScript Interface Stub Writer + +```rig +import { agent, p, s, defineTool, repair } from "rig"; + +const validateMethodSignature = defineTool("validateMethodSignature", { + description: "Validate a TypeScript method signature string.", + parameters: s.object({ + signature: s.string, + }), + handler: async ({ signature }) => { + const valid = /^\s*\w+\s*\([^)]*\)\s*:\s*\S+\s*$/.test(signature); + return { + valid, + reason: valid ? undefined : `"${signature}" is not a valid TypeScript method signature (expected: name(args): ReturnType)`, + }; + }, +}); + +// Agent role: generate a TypeScript interface stub file from a name and method list. +const tsInterfaceStubWriter = agent({ + model: "small", + input: s.object({ + interfaceName: s.string, + methods: s.array(s.string), + outputFile: s.path, + }), + output: s.object({ + outputFile: s.path, + methodsWritten: s.array(s.string), + isValid: s.boolean, + linesEmitted: s.int, + }), + instructions: p`For each method signature in input.methods, call validateMethodSignature to check it is valid. Collect only the valid method signatures. Write a TypeScript interface file to ${p.writeOutput("outputFile", "outputFile")} with the format:\n\nexport interface InterfaceName {\n method1(args): ReturnType;\n ...\n}\n\nReturn outputFile, methodsWritten (the valid signatures included), isValid (true if all input methods were valid), and linesEmitted (total lines written).`, + tools: [validateMethodSignature], + addons: [repair()], +}); + +export default tsInterfaceStubWriter; +``` diff --git a/skills/rig/samples/439-git-grep-search-workflow.md b/skills/rig/samples/439-git-grep-search-workflow.md new file mode 100644 index 0000000..4bd8a64 --- /dev/null +++ b/skills/rig/samples/439-git-grep-search-workflow.md @@ -0,0 +1,47 @@ +# git-grep-search-workflow - Git Grep Search Workflow + +```rig +import { workflow, agent, p, s } from "rig"; + +// Agent role: search the git repository for lines matching a pattern. +const patternSearcher = agent({ + model: "small", + input: s.object({ pattern: s.string }), + output: s.object({ + matches: s.array(s.object({ file: s.string, line: s.int, content: s.string })), + totalMatches: s.int, + }), + instructions: p`Run ${p.bash('git grep -n "$1" -- "*.ts" 2>/dev/null || true')} where $1 is replaced by input.pattern. Parse each output line (format: file:lineNumber:content) into structured matches. Return matches array and totalMatches.`, +}); + +// Agent role: classify each code match as a comment, string literal, or code reference. +const matchClassifier = agent({ + model: "small", + input: s.object({ + matches: s.array(s.object({ file: s.string, line: s.int, content: s.string })), + }), + output: s.object({ + classified: s.array(s.object({ + file: s.string, + line: s.int, + content: s.string, + kind: s.enum("comment", "string", "code"), + })), + commentMatches: s.int, + codeMatches: s.int, + stringMatches: s.int, + }), + instructions: `For each match classify whether the pattern appears in: a comment (line contains // or is inside /* */), a string literal (surrounded by quotes), or code. Return classified array plus counts for each kind.`, +}); + +// Workflow role: run git grep for a pattern then classify each match by context. +export default workflow({ + meta: { name: "git-grep-search-workflow", description: "Search for a pattern in TypeScript source files and classify each match." }, + input: s.object({ pattern: s.string }), + body: async ({ call, input }) => { + const r1 = await call(patternSearcher, input); + if (!r1) return null; + return call(matchClassifier, { matches: r1.matches }); + }, +}); +``` diff --git a/skills/rig/samples/440-json-union-type-inferrer.md b/skills/rig/samples/440-json-union-type-inferrer.md new file mode 100644 index 0000000..07398ad --- /dev/null +++ b/skills/rig/samples/440-json-union-type-inferrer.md @@ -0,0 +1,50 @@ +# json-union-type-inferrer - JSON Union Type Inferrer + +```rig +import { agent, p, s, defineTool, repair } from "rig"; + +const inferFieldType = defineTool("inferFieldType", { + description: "Infer the TypeScript-compatible type of a field from its observed values.", + parameters: s.object({ + fieldName: s.string, + values: s.array(s.unknown), + }), + handler: async ({ values }) => { + const types = new Set(); + let nullable = false; + const uniqueValues = new Set(); + for (const v of values) { + if (v === null) { nullable = true; continue; } + uniqueValues.add(JSON.stringify(v)); + if (Array.isArray(v)) types.add("array"); + else types.add(typeof v === "object" ? "object" : typeof v); + } + const typeList = [...types]; + let inferredType: "string" | "number" | "boolean" | "null" | "array" | "object" | "mixed"; + if (typeList.length === 0) inferredType = "null"; + else if (typeList.length === 1) inferredType = typeList[0] as typeof inferredType; + else inferredType = "mixed"; + return { inferredType, nullable, uniqueValues: uniqueValues.size }; + }, +}); + +// Agent role: analyze a JSON file containing an array of objects and infer field types. +const jsonUnionTypeInferrer = agent({ + model: "small", + input: s.object({ jsonFile: s.string }), + output: s.object({ + fields: s.record(s.object({ + type: s.enum("string", "number", "boolean", "null", "array", "object", "mixed"), + nullable: s.boolean, + uniqueValues: s.int, + })), + totalFields: s.int, + mixedTypeCount: s.int, + }), + instructions: p`Read the JSON file at ${p.readInput("jsonFile")}. Parse it as an array of objects. For each field key, collect all its values across objects and call inferFieldType. Return a fields record keyed by field name, totalFields, and mixedTypeCount (number of fields with type "mixed").`, + tools: [inferFieldType], + addons: [repair()], +}); + +export default jsonUnionTypeInferrer; +```