Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 12 additions & 41 deletions skills/rig/samples/318-ts-barrel-re-exporter.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,21 @@
```rig
import { agent, p, s, defineTool, repair } from "rig";
import { readFile } from "node:fs/promises";

// Agent role: generate a barrel index.ts that re-exports all exported symbols from TypeScript files in a directory.
// Agent role: generate a barrel file for exported symbols in skills/rig/engines.
const tsBarrelReExporter = agent({
model: "small",
input: s.object({
sourceDir: s.path,
outputFile: s.path,
}),
instructions: p`You are a TypeScript barrel re-exporter.

Find TypeScript source files to barrel (excluding index files):
${p.bash("find . -name '*.ts' -not -name 'index.ts' -not -name '*.test.ts' -not -name '*.d.ts' -not -path '*/node_modules/*' | head -50")}

For each TypeScript file in the source directory, call extractExportedSymbols to discover exported names.
Then write the barrel file to ${p.writeInput("outputFile", "barrelContent")}.
Return the declared output.`,
tools: [
defineTool("extractExportedSymbols", {
description: "Read a TypeScript file and extract all top-level exported symbol names",
parameters: s.object({ filePath: s.path }),
async handler({ filePath }) {
const content = await readFile(filePath, "utf8");
const symbols: string[] = [];
const exportRegex = /^export\s+(?:(?:default\s+)?(?:function|class|const|let|var|type|interface|enum)\s+(\w+)|(\{[^}]+\}))/gm;
for (const match of content.matchAll(exportRegex)) {
if (match[1]) {
symbols.push(match[1]);
} else if (match[2]) {
const named = match[2].replace(/[{}]/g, "").split(",").map((s: string) => s.trim().split(/\s+as\s+/)[0].trim()).filter(Boolean);
symbols.push(...named);
}
}
return { filePath, symbols };
},
}),
],
output: s.object({
exports: s.array(s.string),
outputFile: s.path,
totalExports: s.int,
filesScanned: s.int,
}),
instructions: p`Generate a TypeScript barrel for skills/rig/engines from ${p.bash("find skills/rig/engines -name '*.ts' -not -name 'index.ts' -not -name '*.d.ts' | head -20")}. Use extractExportedSymbols for each file, set outputFile to /tmp/rig-barrel.ts, write barrelContent to ${p.writeOutput("barrelContent", "/tmp/rig-barrel.ts")}, and return the declared output.`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] The instructions are now a single dense line, sacrificing the readability that made the original multi-line template literal easy to scan.

💡 Suggested refactor

Split the template literal across lines:

instructions: p`Generate a TypeScript barrel for skills/rig/engines
from ${p.bash("find skills/rig/engines -name '*.ts' -not -name 'index.ts' -not -name '*.d.ts' | head -20")}.
Use extractExportedSymbols for each file, set outputFile to /tmp/rig-barrel.ts,
write barrelContent to ${p.writeOutput("barrelContent", "/tmp/rig-barrel.ts")},
and return the declared output.`,

This matches the style of other samples and keeps each prompt step scannable at a glance.

tools: [defineTool("extractExportedSymbols", {
description: "Read a TypeScript file and extract top-level exported symbol names",
parameters: s.object({ filePath: s.path }),
async handler({ filePath }) {
const content = await readFile(filePath, "utf8");
const symbols = [...content.matchAll(/^export\s+(?:(?:default\s+)?(?:function|class|const|let|var|type|interface|enum)\s+(\w+)|(\{[^}]+\}))/gm)].flatMap((match) => match[1] ? [match[1]] : match[2]!.replace(/[{}]/g, "").split(",").map((name) => name.trim().split(/\s+as\s+/)[0].trim()).filter(Boolean));
return { filePath, symbols };
},
})],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] The tool definition and output schema are now one-liners, which keeps file size down but harms readability in a sample whose purpose is to teach. Samples are documentation first.

💡 Suggested refactor

Expand the output schema and tool definition to multi-line form, consistent with every other sample in the directory:

  output: s.object({
    barrelContent: s.string,
    exports: s.array(s.string),
    outputFile: s.path,
    totalExports: s.int,
    filesScanned: s.int,
  }),

Similarly, break the tool handler body out of the one-liner .flatMap chain for legibility.

output: s.object({ barrelContent: s.string, exports: s.array(s.string), outputFile: s.path, totalExports: s.int, filesScanned: s.int }),
addons: [repair()],
});

export default tsBarrelReExporter;
```