@microsoft/agentrc 2.0.1-1 → 2.0.1-3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -18
- package/dist/index.js +307 -131
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __bannerCreateRequire } from "node:module";
|
|
3
|
+
const require = __bannerCreateRequire(import.meta.url);
|
|
2
4
|
var __create = Object.create;
|
|
3
5
|
var __defProp = Object.defineProperty;
|
|
4
6
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -5357,7 +5359,8 @@ var PACKAGE_MANAGERS = [
|
|
|
5357
5359
|
{ file: "pnpm-lock.yaml", name: "pnpm" },
|
|
5358
5360
|
{ file: "yarn.lock", name: "yarn" },
|
|
5359
5361
|
{ file: "package-lock.json", name: "npm" },
|
|
5360
|
-
{ file: "bun.lockb", name: "bun" }
|
|
5362
|
+
{ file: "bun.lockb", name: "bun" },
|
|
5363
|
+
{ file: "packages.lock.json", name: "nuget" }
|
|
5361
5364
|
];
|
|
5362
5365
|
async function analyzeRepo(repoPath) {
|
|
5363
5366
|
const files = await safeReadDir(repoPath);
|
|
@@ -5379,9 +5382,11 @@ async function analyzeRepo(repoPath) {
|
|
|
5379
5382
|
const hasRequirements = files.includes("requirements.txt");
|
|
5380
5383
|
const hasGoMod = files.includes("go.mod");
|
|
5381
5384
|
const hasCargo = files.includes("Cargo.toml");
|
|
5382
|
-
const
|
|
5383
|
-
(f) => f.endsWith(".csproj") || f.endsWith(".sln") || f.endsWith(".slnx")
|
|
5385
|
+
const hasDotnet = files.some(
|
|
5386
|
+
(f) => f.endsWith(".csproj") || f.endsWith(".fsproj") || f.endsWith(".sln") || f.endsWith(".slnx") || f === "global.json" || f === "Directory.Build.props"
|
|
5384
5387
|
);
|
|
5388
|
+
const hasCsproj = hasDotnet && files.some((f) => f.endsWith(".csproj"));
|
|
5389
|
+
const hasFsproj = files.some((f) => f.endsWith(".fsproj"));
|
|
5385
5390
|
const hasPomXml = files.includes("pom.xml");
|
|
5386
5391
|
const hasBuildGradle = files.includes("build.gradle") || files.includes("build.gradle.kts");
|
|
5387
5392
|
const hasGemfile = files.includes("Gemfile");
|
|
@@ -5396,7 +5401,8 @@ async function analyzeRepo(repoPath) {
|
|
|
5396
5401
|
if (hasPyProject || hasRequirements) analysis.languages.push("Python");
|
|
5397
5402
|
if (hasGoMod) analysis.languages.push("Go");
|
|
5398
5403
|
if (hasCargo) analysis.languages.push("Rust");
|
|
5399
|
-
if (hasCsproj) analysis.languages.push("C#");
|
|
5404
|
+
if (hasCsproj || hasDotnet && !hasFsproj) analysis.languages.push("C#");
|
|
5405
|
+
if (hasFsproj) analysis.languages.push("F#");
|
|
5400
5406
|
if (hasPomXml || hasBuildGradle) analysis.languages.push("Java");
|
|
5401
5407
|
if (hasGemfile) analysis.languages.push("Ruby");
|
|
5402
5408
|
if (hasComposerJson) analysis.languages.push("PHP");
|
|
@@ -5412,6 +5418,10 @@ async function analyzeRepo(repoPath) {
|
|
|
5412
5418
|
});
|
|
5413
5419
|
analysis.frameworks.push(...detectFrameworks(deps, files));
|
|
5414
5420
|
}
|
|
5421
|
+
if (hasDotnet) {
|
|
5422
|
+
const dotnetFrameworks = await detectDotnetFrameworks(repoPath);
|
|
5423
|
+
analysis.frameworks.push(...dotnetFrameworks);
|
|
5424
|
+
}
|
|
5415
5425
|
const workspace = await detectWorkspace(repoPath, files, rootPackageJson);
|
|
5416
5426
|
if (workspace) {
|
|
5417
5427
|
analysis.workspaceType = workspace.type;
|
|
@@ -5472,6 +5482,44 @@ function detectFrameworks(deps, files) {
|
|
|
5472
5482
|
if (deps.includes("fastify")) frameworks.push("Fastify");
|
|
5473
5483
|
return frameworks;
|
|
5474
5484
|
}
|
|
5485
|
+
async function detectDotnetFrameworks(repoPath) {
|
|
5486
|
+
const projectFiles = await fg("**/*.{csproj,fsproj}", {
|
|
5487
|
+
cwd: repoPath,
|
|
5488
|
+
onlyFiles: true,
|
|
5489
|
+
ignore: ["**/node_modules/**", "**/bin/**", "**/obj/**"]
|
|
5490
|
+
});
|
|
5491
|
+
const frameworks = [];
|
|
5492
|
+
for (const projFile of projectFiles) {
|
|
5493
|
+
try {
|
|
5494
|
+
const content = await fs2.readFile(path2.join(repoPath, projFile), "utf8");
|
|
5495
|
+
frameworks.push(...parseDotnetProject(content));
|
|
5496
|
+
} catch {
|
|
5497
|
+
}
|
|
5498
|
+
}
|
|
5499
|
+
return frameworks;
|
|
5500
|
+
}
|
|
5501
|
+
function parseDotnetProject(content) {
|
|
5502
|
+
const frameworks = [];
|
|
5503
|
+
const hasPackage = (pkg) => content.includes(`Include="${pkg}"`);
|
|
5504
|
+
if (content.includes('Sdk="Microsoft.NET.Sdk.Web"')) frameworks.push("ASP.NET Core");
|
|
5505
|
+
if (content.includes('Sdk="Microsoft.NET.Sdk.BlazorWebAssembly"'))
|
|
5506
|
+
frameworks.push("Blazor WebAssembly");
|
|
5507
|
+
if (hasPackage("Microsoft.AspNetCore") || hasPackage("Microsoft.AspNetCore.App"))
|
|
5508
|
+
frameworks.push("ASP.NET Core");
|
|
5509
|
+
if (hasPackage("Microsoft.AspNetCore.Components")) frameworks.push("Blazor");
|
|
5510
|
+
if (hasPackage("Microsoft.EntityFrameworkCore")) frameworks.push("Entity Framework");
|
|
5511
|
+
if (hasPackage("Microsoft.Maui.Controls")) frameworks.push(".NET MAUI");
|
|
5512
|
+
if (hasPackage("Xamarin.Forms") || hasPackage("Xamarin.Essentials")) frameworks.push("Xamarin");
|
|
5513
|
+
if (content.includes("<UseWPF>true</UseWPF>")) frameworks.push("WPF");
|
|
5514
|
+
if (content.includes("<UseWindowsForms>true</UseWindowsForms>")) frameworks.push("Windows Forms");
|
|
5515
|
+
if (hasPackage("xunit") || hasPackage("xunit.core")) frameworks.push("xUnit");
|
|
5516
|
+
if (hasPackage("NUnit") || hasPackage("nunit.framework")) frameworks.push("NUnit");
|
|
5517
|
+
if (hasPackage("MSTest.TestFramework")) frameworks.push("MSTest");
|
|
5518
|
+
if (frameworks.length === 0 && content.includes("<OutputType>Exe</OutputType>") && content.includes('Sdk="Microsoft.NET.Sdk"')) {
|
|
5519
|
+
frameworks.push("Console");
|
|
5520
|
+
}
|
|
5521
|
+
return frameworks;
|
|
5522
|
+
}
|
|
5475
5523
|
async function safeReadFile(filePath) {
|
|
5476
5524
|
try {
|
|
5477
5525
|
return await fs2.readFile(filePath, "utf8");
|
|
@@ -6631,9 +6679,9 @@ import path9 from "path";
|
|
|
6631
6679
|
// packages/core/src/utils/pr.ts
|
|
6632
6680
|
function buildInstructionsPrBody() {
|
|
6633
6681
|
return [
|
|
6634
|
-
"## \u{1F916}
|
|
6682
|
+
"## \u{1F916} Instructions Added",
|
|
6635
6683
|
"",
|
|
6636
|
-
"This PR adds a `.github/copilot-instructions.md` file to help
|
|
6684
|
+
"This PR adds a `.github/copilot-instructions.md` file to help AI coding assistants understand this codebase better.",
|
|
6637
6685
|
"",
|
|
6638
6686
|
"### What's Included",
|
|
6639
6687
|
"",
|
|
@@ -6645,7 +6693,7 @@ function buildInstructionsPrBody() {
|
|
|
6645
6693
|
"",
|
|
6646
6694
|
"### Benefits",
|
|
6647
6695
|
"",
|
|
6648
|
-
"With these instructions,
|
|
6696
|
+
"With these instructions, AI coding assistants will:",
|
|
6649
6697
|
"- Generate more contextually-aware code suggestions",
|
|
6650
6698
|
"- Follow project-specific patterns and conventions",
|
|
6651
6699
|
"- Understand the codebase structure",
|
|
@@ -6664,7 +6712,7 @@ function buildFullPrBody() {
|
|
|
6664
6712
|
"",
|
|
6665
6713
|
"| File | Purpose |",
|
|
6666
6714
|
"|------|---------|",
|
|
6667
|
-
"| `.github/copilot-instructions.md` | Custom instructions for
|
|
6715
|
+
"| `.github/copilot-instructions.md` | Custom instructions for AI coding assistants |",
|
|
6668
6716
|
"| `.vscode/settings.json` | VS Code settings for optimal AI assistance |",
|
|
6669
6717
|
"| `.vscode/mcp.json` | Model Context Protocol server configuration |",
|
|
6670
6718
|
"",
|
|
@@ -6678,7 +6726,7 @@ function buildFullPrBody() {
|
|
|
6678
6726
|
"",
|
|
6679
6727
|
"### Benefits",
|
|
6680
6728
|
"",
|
|
6681
|
-
"With these configurations,
|
|
6729
|
+
"With these configurations, AI coding assistants will:",
|
|
6682
6730
|
"- Generate more contextually-aware code suggestions",
|
|
6683
6731
|
"- Follow project-specific patterns and conventions",
|
|
6684
6732
|
"- Understand the codebase structure",
|
|
@@ -6688,7 +6736,7 @@ function buildFullPrBody() {
|
|
|
6688
6736
|
"",
|
|
6689
6737
|
"1. Merge this PR",
|
|
6690
6738
|
"2. Open the project in VS Code",
|
|
6691
|
-
"3. Start
|
|
6739
|
+
"3. Start using AI assistants \u2014 they now understand your project!",
|
|
6692
6740
|
"",
|
|
6693
6741
|
"---",
|
|
6694
6742
|
"*Generated by [AgentRC](https://github.com/microsoft/agentrc) - Prime your repos for AI*"
|
|
@@ -7163,7 +7211,9 @@ function normalizeError(error) {
|
|
|
7163
7211
|
}
|
|
7164
7212
|
function shouldFallbackToExternalServer(error) {
|
|
7165
7213
|
const message = normalizeError(error).message.toLowerCase();
|
|
7166
|
-
return message.includes("unknown option '--headless'") || message.includes("unknown option '--no-auto-update'") ||
|
|
7214
|
+
return message.includes("unknown option '--headless'") || message.includes("unknown option '--no-auto-update'") || // SDK's internal CLI resolution couldn't find the binary
|
|
7215
|
+
message.includes("copilot cli not found") || // Node's spawn() can't execute .bat/.cmd directly on Windows
|
|
7216
|
+
message.includes("spawn einval");
|
|
7167
7217
|
}
|
|
7168
7218
|
async function startExternalServer(cliConfig) {
|
|
7169
7219
|
const [cmd, args2] = buildExecArgs(cliConfig, ["--headless", "--log-level", "debug"]);
|
|
@@ -7281,8 +7331,11 @@ async function createCopilotClient(cliConfig) {
|
|
|
7281
7331
|
const desc = cliConfig.cliArgs ? `${cliConfig.cliPath} ${cliConfig.cliArgs.join(" ")}` : cliConfig.cliPath;
|
|
7282
7332
|
logCopilotDebug(`creating SDK client with cliPath=${desc} useStdio=false`);
|
|
7283
7333
|
const isNpx = /\bnpx(?:\.cmd)?$/iu.test(cliConfig.cliPath);
|
|
7284
|
-
|
|
7285
|
-
|
|
7334
|
+
const isBatShim = process.platform === "win32" && /\.(?:bat|cmd)$/iu.test(cliConfig.cliPath);
|
|
7335
|
+
if (isNpx || isBatShim) {
|
|
7336
|
+
logCopilotDebug(
|
|
7337
|
+
`${isNpx ? "npx wrapper" : ".bat/.cmd shim"} detected; using external server mode directly`
|
|
7338
|
+
);
|
|
7286
7339
|
const external = await startExternalServer(cliConfig);
|
|
7287
7340
|
const client = new sdk.CopilotClient({ cliUrl: external.cliUrl });
|
|
7288
7341
|
try {
|
|
@@ -7532,7 +7585,7 @@ async function generateCopilotInstructions(options) {
|
|
|
7532
7585
|
|
|
7533
7586
|
Fan out multiple Explore subagents to map out the codebase in parallel:
|
|
7534
7587
|
1. Check for existing instruction files: glob for **/{.github/copilot-instructions.md,AGENT.md,CLAUDE.md,.cursorrules,README.md}
|
|
7535
|
-
2. Identify the tech stack: look at package.json, tsconfig.json, pyproject.toml, Cargo.toml, go.mod, *.csproj, *.sln, build.gradle, pom.xml, etc.
|
|
7588
|
+
2. Identify the tech stack: look at package.json, tsconfig.json, pyproject.toml, Cargo.toml, go.mod, *.csproj, *.fsproj, *.sln, global.json, build.gradle, pom.xml, etc.
|
|
7536
7589
|
3. Understand the structure: list key directories
|
|
7537
7590
|
4. Detect monorepo structures: check for workspace configs (npm/pnpm/yarn workspaces, Cargo.toml [workspace], go.work, .sln solution files, settings.gradle include directives, pom.xml modules)
|
|
7538
7591
|
|
|
@@ -7578,7 +7631,7 @@ async function generateAreaInstructions(options) {
|
|
|
7578
7631
|
const applyToStr = applyToPatterns.join(", ");
|
|
7579
7632
|
progress(`Creating session for area "${area.name}"...`);
|
|
7580
7633
|
const preferredModel = options.model ?? DEFAULT_MODEL;
|
|
7581
|
-
const areaSystemContent = hasExistingInstructions ? `You are an expert codebase analyst. Your task is to generate a concise .instructions.md file for a specific area of a codebase. This file will be used as
|
|
7634
|
+
const areaSystemContent = hasExistingInstructions ? `You are an expert codebase analyst. Your task is to generate a concise .instructions.md file for a specific area of a codebase. This file will be used as an area instruction in VS Code, automatically applied when working on files matching certain patterns. This file should complement, not duplicate, existing instruction files. Use the Explore subagents and read-only tools to explore the codebase. When done, call the emit_file_content tool with the final markdown.` : `You are an expert codebase analyst. Your task is to generate a concise .instructions.md file for a specific area of a codebase. This file will be used as an area instruction in VS Code, automatically applied when working on files matching certain patterns. Use the Explore subagents and read-only tools to explore the codebase. When done, call the emit_file_content tool with the final markdown.`;
|
|
7582
7635
|
const { tool: emitTool, getContent } = await createEmitTool();
|
|
7583
7636
|
const session = await client.createSession({
|
|
7584
7637
|
model: preferredModel,
|
|
@@ -7611,7 +7664,7 @@ async function generateAreaInstructions(options) {
|
|
|
7611
7664
|
sessionError = getSessionError(errorMsg);
|
|
7612
7665
|
}
|
|
7613
7666
|
});
|
|
7614
|
-
const prompt = `Analyze the "${area.name}" area of this codebase and generate
|
|
7667
|
+
const prompt = `Analyze the "${area.name}" area of this codebase and generate an area instruction file.
|
|
7615
7668
|
|
|
7616
7669
|
This area covers files matching: ${applyToStr}
|
|
7617
7670
|
${area.description ? `Description: ${area.description}` : ""}
|
|
@@ -8733,7 +8786,7 @@ function getLevelName(level) {
|
|
|
8733
8786
|
function getLevelDescription(level) {
|
|
8734
8787
|
const descriptions = {
|
|
8735
8788
|
1: "Repo builds, tests run, and basic tooling (linter, lockfile) is in place. AI agents can clone and get started.",
|
|
8736
|
-
2: "README, CONTRIBUTING guide, and custom
|
|
8789
|
+
2: "README, CONTRIBUTING guide, and custom instructions exist. Agents understand project context and conventions.",
|
|
8737
8790
|
3: "CI/CD, security policies, CODEOWNERS, and observability are configured. Agents operate within well-defined guardrails.",
|
|
8738
8791
|
4: "MCP servers, custom agents, and AI skills are set up. Agents have deep integration with project-specific tools and workflows.",
|
|
8739
8792
|
5: "Full AI-native development: agents can independently plan, implement, test, and ship changes with minimal human oversight."
|
|
@@ -9198,7 +9251,7 @@ function buildCriteria() {
|
|
|
9198
9251
|
},
|
|
9199
9252
|
{
|
|
9200
9253
|
id: "custom-instructions",
|
|
9201
|
-
title: "Custom
|
|
9254
|
+
title: "Custom instructions or agent guidance",
|
|
9202
9255
|
pillar: "ai-tooling",
|
|
9203
9256
|
level: 1,
|
|
9204
9257
|
scope: "repo",
|
|
@@ -9209,7 +9262,7 @@ function buildCriteria() {
|
|
|
9209
9262
|
if (rootFound.length === 0) {
|
|
9210
9263
|
return {
|
|
9211
9264
|
status: "fail",
|
|
9212
|
-
reason: "Missing custom
|
|
9265
|
+
reason: "Missing custom instructions (e.g. copilot-instructions.md, CLAUDE.md, AGENTS.md, .cursorrules).",
|
|
9213
9266
|
evidence: [
|
|
9214
9267
|
"copilot-instructions.md",
|
|
9215
9268
|
"CLAUDE.md",
|
|
@@ -9225,13 +9278,13 @@ function buildCriteria() {
|
|
|
9225
9278
|
if (fileBasedInstructions.length === 0) {
|
|
9226
9279
|
return {
|
|
9227
9280
|
status: "pass",
|
|
9228
|
-
reason: `Root instructions found, but no
|
|
9281
|
+
reason: `Root instructions found, but no area instructions for ${areas.length} detected areas. Run \`agentrc instructions --areas\` to generate.`,
|
|
9229
9282
|
evidence: [...rootFound, ...areas.map((a) => `${a.name}: missing .instructions.md`)]
|
|
9230
9283
|
};
|
|
9231
9284
|
}
|
|
9232
9285
|
return {
|
|
9233
9286
|
status: "pass",
|
|
9234
|
-
reason: `Root + ${fileBasedInstructions.length}
|
|
9287
|
+
reason: `Root + ${fileBasedInstructions.length} area instruction(s) found.`,
|
|
9235
9288
|
evidence: [...rootFound, ...fileBasedInstructions]
|
|
9236
9289
|
};
|
|
9237
9290
|
}
|
|
@@ -9856,7 +9909,7 @@ async function processRepo(params) {
|
|
|
9856
9909
|
);
|
|
9857
9910
|
}
|
|
9858
9911
|
progress?.update(`${label}: Committing...`);
|
|
9859
|
-
await commitAll(repoPath, "chore: add
|
|
9912
|
+
await commitAll(repoPath, "chore: add instructions via AgentRC");
|
|
9860
9913
|
progress?.update(`${label}: Pushing...`);
|
|
9861
9914
|
await pushBranch(repoPath, branch, token, provider);
|
|
9862
9915
|
progress?.update(`${label}: Creating PR...`);
|
|
@@ -9892,7 +9945,7 @@ async function processGitHubRepo(options) {
|
|
|
9892
9945
|
token,
|
|
9893
9946
|
owner: repo.owner,
|
|
9894
9947
|
repo: repo.name,
|
|
9895
|
-
title: "\u{1F916} Add
|
|
9948
|
+
title: "\u{1F916} Add instructions via AgentRC",
|
|
9896
9949
|
body: buildInstructionsPrBody(),
|
|
9897
9950
|
head: branchName,
|
|
9898
9951
|
base: repo.defaultBranch
|
|
@@ -9924,7 +9977,7 @@ async function processAzureRepo(options) {
|
|
|
9924
9977
|
project: repo.project,
|
|
9925
9978
|
repoId: repo.id,
|
|
9926
9979
|
repoName: repo.name,
|
|
9927
|
-
title: "\u{1F916} Add
|
|
9980
|
+
title: "\u{1F916} Add instructions via AgentRC",
|
|
9928
9981
|
body: buildInstructionsPrBody(),
|
|
9929
9982
|
sourceBranch: branchName,
|
|
9930
9983
|
targetBranch: repo.defaultBranch
|
|
@@ -11039,11 +11092,7 @@ import path10 from "path";
|
|
|
11039
11092
|
|
|
11040
11093
|
// packages/core/src/services/visualReport.ts
|
|
11041
11094
|
function generateVisualReport(options) {
|
|
11042
|
-
const {
|
|
11043
|
-
reports,
|
|
11044
|
-
title = "AI Readiness Report",
|
|
11045
|
-
generatedAt = (/* @__PURE__ */ new Date()).toISOString()
|
|
11046
|
-
} = options;
|
|
11095
|
+
const { reports, title = "Readiness Report", generatedAt = (/* @__PURE__ */ new Date()).toISOString() } = options;
|
|
11047
11096
|
const successfulReports = reports.filter((r) => !r.error);
|
|
11048
11097
|
const failedReports = reports.filter((r) => r.error);
|
|
11049
11098
|
const totalRepos = reports.length;
|
|
@@ -11612,7 +11661,7 @@ function generateVisualReport(options) {
|
|
|
11612
11661
|
` : ""}
|
|
11613
11662
|
|
|
11614
11663
|
<div class="footer">
|
|
11615
|
-
<p>Generated with <a href="https://github.com/microsoft/agentrc">AgentRC</a> ·
|
|
11664
|
+
<p>Generated with <a href="https://github.com/microsoft/agentrc">AgentRC</a> · Readiness Tool</p>
|
|
11616
11665
|
</div>
|
|
11617
11666
|
</div>
|
|
11618
11667
|
<script>
|
|
@@ -12099,7 +12148,7 @@ function BatchReadinessTui({ token, outputPath, policies }) {
|
|
|
12099
12148
|
},
|
|
12100
12149
|
error: r.error
|
|
12101
12150
|
})),
|
|
12102
|
-
title: "Batch
|
|
12151
|
+
title: "Batch Readiness Report",
|
|
12103
12152
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12104
12153
|
});
|
|
12105
12154
|
const finalOutputPath = outputPath ?? path10.join(process.cwd(), "batch-readiness-report.html");
|
|
@@ -13471,6 +13520,7 @@ async function instructionsCommand(options) {
|
|
|
13471
13520
|
return;
|
|
13472
13521
|
}
|
|
13473
13522
|
try {
|
|
13523
|
+
const dryRunFiles = [];
|
|
13474
13524
|
if (!options.areasOnly && !options.area) {
|
|
13475
13525
|
if (strategy === "nested") {
|
|
13476
13526
|
try {
|
|
@@ -13482,25 +13532,57 @@ async function instructionsCommand(options) {
|
|
|
13482
13532
|
detailDir,
|
|
13483
13533
|
claudeMd
|
|
13484
13534
|
});
|
|
13485
|
-
|
|
13486
|
-
|
|
13487
|
-
|
|
13488
|
-
|
|
13489
|
-
|
|
13490
|
-
|
|
13491
|
-
|
|
13535
|
+
if (options.dryRun) {
|
|
13536
|
+
const dryFiles = [
|
|
13537
|
+
{ path: nestedResult.hub.relativePath, content: nestedResult.hub.content },
|
|
13538
|
+
...nestedResult.details.map((d) => ({ path: d.relativePath, content: d.content })),
|
|
13539
|
+
...nestedResult.claudeMd ? [
|
|
13540
|
+
{
|
|
13541
|
+
path: nestedResult.claudeMd.relativePath,
|
|
13542
|
+
content: nestedResult.claudeMd.content
|
|
13543
|
+
}
|
|
13544
|
+
] : []
|
|
13545
|
+
];
|
|
13546
|
+
for (const file of dryFiles) {
|
|
13547
|
+
const relPath = path14.relative(process.cwd(), path14.join(repoPath, file.path));
|
|
13548
|
+
if (shouldLog(options)) {
|
|
13549
|
+
progress.update(
|
|
13550
|
+
`[dry-run] Would write ${relPath} (${Buffer.byteLength(file.content, "utf8")} bytes)`
|
|
13551
|
+
);
|
|
13552
|
+
}
|
|
13553
|
+
}
|
|
13554
|
+
if (options.json) {
|
|
13555
|
+
dryRunFiles.push(
|
|
13556
|
+
...dryFiles.map((f) => ({
|
|
13557
|
+
path: f.path,
|
|
13558
|
+
bytes: Buffer.byteLength(f.content, "utf8")
|
|
13559
|
+
}))
|
|
13560
|
+
);
|
|
13561
|
+
}
|
|
13562
|
+
for (const warning of nestedResult.warnings) {
|
|
13563
|
+
if (shouldLog(options)) progress.update(`Warning: ${warning}`);
|
|
13564
|
+
}
|
|
13565
|
+
} else {
|
|
13566
|
+
const actions = await writeNestedInstructions(repoPath, nestedResult, options.force);
|
|
13567
|
+
for (const action of actions) {
|
|
13568
|
+
const relPath = path14.relative(process.cwd(), action.path);
|
|
13569
|
+
if (action.action === "wrote") {
|
|
13570
|
+
if (shouldLog(options)) progress.succeed(`Wrote ${relPath}`);
|
|
13571
|
+
} else if (shouldLog(options)) {
|
|
13572
|
+
progress.update(`Skipped ${relPath} (${skipReason(action.action)})`);
|
|
13573
|
+
}
|
|
13574
|
+
}
|
|
13575
|
+
for (const warning of nestedResult.warnings) {
|
|
13576
|
+
if (shouldLog(options)) progress.update(`Warning: ${warning}`);
|
|
13577
|
+
}
|
|
13578
|
+
if (options.json) {
|
|
13579
|
+
const result = {
|
|
13580
|
+
ok: true,
|
|
13581
|
+
status: "success",
|
|
13582
|
+
data: { files: actions }
|
|
13583
|
+
};
|
|
13584
|
+
outputResult(result, true);
|
|
13492
13585
|
}
|
|
13493
|
-
}
|
|
13494
|
-
for (const warning of nestedResult.warnings) {
|
|
13495
|
-
if (shouldLog(options)) progress.update(`Warning: ${warning}`);
|
|
13496
|
-
}
|
|
13497
|
-
if (options.json) {
|
|
13498
|
-
const result = {
|
|
13499
|
-
ok: true,
|
|
13500
|
-
status: "success",
|
|
13501
|
-
data: { files: actions }
|
|
13502
|
-
};
|
|
13503
|
-
outputResult(result, true);
|
|
13504
13586
|
}
|
|
13505
13587
|
} catch (error) {
|
|
13506
13588
|
const msg = "Failed to generate nested instructions. " + (error instanceof Error ? error.message : String(error));
|
|
@@ -13525,36 +13607,48 @@ async function instructionsCommand(options) {
|
|
|
13525
13607
|
return;
|
|
13526
13608
|
}
|
|
13527
13609
|
if (content) {
|
|
13528
|
-
|
|
13529
|
-
|
|
13530
|
-
outputPath
|
|
13531
|
-
content,
|
|
13532
|
-
|
|
13533
|
-
|
|
13534
|
-
|
|
13535
|
-
const relPath = path14.relative(process.cwd(), outputPath);
|
|
13536
|
-
const why = reason === "symlink" ? "path is a symlink" : "file exists (use --force)";
|
|
13610
|
+
if (options.dryRun) {
|
|
13611
|
+
const relPath = path14.relative(repoPath, outputPath);
|
|
13612
|
+
const displayPath = path14.relative(process.cwd(), outputPath);
|
|
13613
|
+
const byteCount = Buffer.byteLength(content, "utf8");
|
|
13614
|
+
if (shouldLog(options)) {
|
|
13615
|
+
progress.update(`[dry-run] Would write ${displayPath} (${byteCount} bytes)`);
|
|
13616
|
+
}
|
|
13537
13617
|
if (options.json) {
|
|
13538
|
-
|
|
13539
|
-
ok: true,
|
|
13540
|
-
status: "noop",
|
|
13541
|
-
data: { outputPath, skipped: true, reason: why }
|
|
13542
|
-
};
|
|
13543
|
-
outputResult(result, true);
|
|
13544
|
-
} else if (shouldLog(options)) {
|
|
13545
|
-
progress.update(`Skipped ${relPath}: ${why}`);
|
|
13618
|
+
dryRunFiles.push({ path: relPath, bytes: byteCount });
|
|
13546
13619
|
}
|
|
13547
13620
|
} else {
|
|
13548
|
-
|
|
13549
|
-
|
|
13550
|
-
|
|
13551
|
-
|
|
13552
|
-
|
|
13553
|
-
|
|
13554
|
-
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
|
|
13621
|
+
await ensureDir(path14.dirname(outputPath));
|
|
13622
|
+
const { wrote, reason } = await safeWriteFile(
|
|
13623
|
+
outputPath,
|
|
13624
|
+
content,
|
|
13625
|
+
Boolean(options.force)
|
|
13626
|
+
);
|
|
13627
|
+
if (!wrote) {
|
|
13628
|
+
const relPath = path14.relative(process.cwd(), outputPath);
|
|
13629
|
+
const why = reason === "symlink" ? "path is a symlink" : "file exists (use --force)";
|
|
13630
|
+
if (options.json) {
|
|
13631
|
+
const result = {
|
|
13632
|
+
ok: true,
|
|
13633
|
+
status: "noop",
|
|
13634
|
+
data: { outputPath, skipped: true, reason: why }
|
|
13635
|
+
};
|
|
13636
|
+
outputResult(result, true);
|
|
13637
|
+
} else if (shouldLog(options)) {
|
|
13638
|
+
progress.update(`Skipped ${relPath}: ${why}`);
|
|
13639
|
+
}
|
|
13640
|
+
} else {
|
|
13641
|
+
const byteCount = Buffer.byteLength(content, "utf8");
|
|
13642
|
+
if (options.json) {
|
|
13643
|
+
const result = {
|
|
13644
|
+
ok: true,
|
|
13645
|
+
status: "success",
|
|
13646
|
+
data: { outputPath, model: options.model ?? "default", byteCount }
|
|
13647
|
+
};
|
|
13648
|
+
outputResult(result, true);
|
|
13649
|
+
} else if (shouldLog(options)) {
|
|
13650
|
+
progress.succeed(`Updated ${path14.relative(process.cwd(), outputPath)}`);
|
|
13651
|
+
}
|
|
13558
13652
|
}
|
|
13559
13653
|
}
|
|
13560
13654
|
}
|
|
@@ -13588,7 +13682,7 @@ async function instructionsCommand(options) {
|
|
|
13588
13682
|
return;
|
|
13589
13683
|
}
|
|
13590
13684
|
if (shouldLog(options)) {
|
|
13591
|
-
progress.update(`Generating
|
|
13685
|
+
progress.update(`Generating instructions for ${targetAreas.length} area(s)...`);
|
|
13592
13686
|
}
|
|
13593
13687
|
for (const area of targetAreas) {
|
|
13594
13688
|
try {
|
|
@@ -13608,17 +13702,46 @@ async function instructionsCommand(options) {
|
|
|
13608
13702
|
detailDir,
|
|
13609
13703
|
claudeMd
|
|
13610
13704
|
});
|
|
13611
|
-
|
|
13612
|
-
|
|
13613
|
-
|
|
13614
|
-
|
|
13615
|
-
|
|
13616
|
-
|
|
13617
|
-
|
|
13705
|
+
if (options.dryRun) {
|
|
13706
|
+
const dryFiles = [
|
|
13707
|
+
{ path: nestedResult.hub.relativePath, content: nestedResult.hub.content },
|
|
13708
|
+
...nestedResult.details.map((d) => ({ path: d.relativePath, content: d.content })),
|
|
13709
|
+
...nestedResult.claudeMd ? [
|
|
13710
|
+
{
|
|
13711
|
+
path: nestedResult.claudeMd.relativePath,
|
|
13712
|
+
content: nestedResult.claudeMd.content
|
|
13713
|
+
}
|
|
13714
|
+
] : []
|
|
13715
|
+
];
|
|
13716
|
+
for (const file of dryFiles) {
|
|
13717
|
+
const relPath = path14.relative(process.cwd(), path14.join(repoPath, file.path));
|
|
13718
|
+
if (shouldLog(options)) {
|
|
13719
|
+
progress.update(
|
|
13720
|
+
`[dry-run] Would write ${relPath} (${Buffer.byteLength(file.content, "utf8")} bytes)`
|
|
13721
|
+
);
|
|
13722
|
+
}
|
|
13723
|
+
}
|
|
13724
|
+
if (options.json) {
|
|
13725
|
+
dryRunFiles.push(
|
|
13726
|
+
...dryFiles.map((f) => ({
|
|
13727
|
+
path: f.path,
|
|
13728
|
+
bytes: Buffer.byteLength(f.content, "utf8")
|
|
13729
|
+
}))
|
|
13730
|
+
);
|
|
13731
|
+
}
|
|
13732
|
+
} else {
|
|
13733
|
+
const actions = await writeNestedInstructions(repoPath, nestedResult, options.force);
|
|
13734
|
+
for (const action of actions) {
|
|
13735
|
+
const relPath = path14.relative(process.cwd(), action.path);
|
|
13736
|
+
if (action.action === "wrote") {
|
|
13737
|
+
if (shouldLog(options)) progress.succeed(`Wrote ${relPath}`);
|
|
13738
|
+
} else if (shouldLog(options)) {
|
|
13739
|
+
progress.update(`Skipped ${relPath} (${skipReason(action.action)})`);
|
|
13740
|
+
}
|
|
13741
|
+
}
|
|
13742
|
+
for (const warning of nestedResult.warnings) {
|
|
13743
|
+
if (shouldLog(options)) progress.update(`Warning: ${warning}`);
|
|
13618
13744
|
}
|
|
13619
|
-
}
|
|
13620
|
-
for (const warning of nestedResult.warnings) {
|
|
13621
|
-
if (shouldLog(options)) progress.update(`Warning: ${warning}`);
|
|
13622
13745
|
}
|
|
13623
13746
|
} else {
|
|
13624
13747
|
const body = await generateAreaInstructions({
|
|
@@ -13633,21 +13756,37 @@ async function instructionsCommand(options) {
|
|
|
13633
13756
|
}
|
|
13634
13757
|
continue;
|
|
13635
13758
|
}
|
|
13636
|
-
|
|
13637
|
-
if (result.status === "skipped") {
|
|
13759
|
+
if (options.dryRun) {
|
|
13638
13760
|
if (shouldLog(options)) {
|
|
13639
|
-
progress.update(
|
|
13761
|
+
progress.update(
|
|
13762
|
+
`[dry-run] Would write area "${area.name}" (${Buffer.byteLength(body, "utf8")} bytes)`
|
|
13763
|
+
);
|
|
13764
|
+
}
|
|
13765
|
+
if (options.json) {
|
|
13766
|
+
dryRunFiles.push({
|
|
13767
|
+
path: path14.relative(repoPath, areaInstructionPath(repoPath, area)),
|
|
13768
|
+
bytes: Buffer.byteLength(body, "utf8")
|
|
13769
|
+
});
|
|
13770
|
+
}
|
|
13771
|
+
} else {
|
|
13772
|
+
const result = await writeAreaInstruction(repoPath, area, body, options.force);
|
|
13773
|
+
if (result.status === "skipped") {
|
|
13774
|
+
if (shouldLog(options)) {
|
|
13775
|
+
progress.update(
|
|
13776
|
+
`Skipped "${area.name}" \u2014 file exists (use --force to overwrite).`
|
|
13777
|
+
);
|
|
13778
|
+
}
|
|
13779
|
+
continue;
|
|
13780
|
+
}
|
|
13781
|
+
if (result.status === "symlink") {
|
|
13782
|
+
if (shouldLog(options)) {
|
|
13783
|
+
progress.update(`Skipped "${area.name}" \u2014 path is a symlink.`);
|
|
13784
|
+
}
|
|
13785
|
+
continue;
|
|
13640
13786
|
}
|
|
13641
|
-
continue;
|
|
13642
|
-
}
|
|
13643
|
-
if (result.status === "symlink") {
|
|
13644
13787
|
if (shouldLog(options)) {
|
|
13645
|
-
progress.
|
|
13788
|
+
progress.succeed(`Wrote ${path14.relative(process.cwd(), result.filePath)}`);
|
|
13646
13789
|
}
|
|
13647
|
-
continue;
|
|
13648
|
-
}
|
|
13649
|
-
if (shouldLog(options)) {
|
|
13650
|
-
progress.succeed(`Wrote ${path14.relative(process.cwd(), result.filePath)}`);
|
|
13651
13790
|
}
|
|
13652
13791
|
}
|
|
13653
13792
|
} catch (error) {
|
|
@@ -13659,6 +13798,12 @@ async function instructionsCommand(options) {
|
|
|
13659
13798
|
}
|
|
13660
13799
|
}
|
|
13661
13800
|
}
|
|
13801
|
+
if (options.dryRun && options.json) {
|
|
13802
|
+
outputResult(
|
|
13803
|
+
{ ok: true, status: "noop", data: { dryRun: true, files: dryRunFiles } },
|
|
13804
|
+
true
|
|
13805
|
+
);
|
|
13806
|
+
}
|
|
13662
13807
|
if (!wantAreas && shouldLog(options) && !options.json) {
|
|
13663
13808
|
process.stderr.write("\nNext steps:\n");
|
|
13664
13809
|
process.stderr.write(" agentrc eval --init Scaffold evaluation test cases\n");
|
|
@@ -13677,6 +13822,18 @@ async function instructionsCommand(options) {
|
|
|
13677
13822
|
async function generateCommand(type, repoPathArg, options) {
|
|
13678
13823
|
const repoPath = path15.resolve(repoPathArg ?? process.cwd());
|
|
13679
13824
|
if (type === "instructions" || type === "agents") {
|
|
13825
|
+
if (!options.quiet) {
|
|
13826
|
+
process.stderr.write(
|
|
13827
|
+
`\u26A0 \`generate ${type}\` is deprecated \u2014 use \`agentrc instructions\` directly.
|
|
13828
|
+
`
|
|
13829
|
+
);
|
|
13830
|
+
}
|
|
13831
|
+
if (options.perApp && !options.quiet) {
|
|
13832
|
+
process.stderr.write(
|
|
13833
|
+
`\u26A0 --per-app is deprecated \u2014 use \`agentrc instructions --areas\` instead.
|
|
13834
|
+
`
|
|
13835
|
+
);
|
|
13836
|
+
}
|
|
13680
13837
|
const output = type === "agents" ? path15.join(repoPath, "AGENTS.md") : void 0;
|
|
13681
13838
|
await instructionsCommand({
|
|
13682
13839
|
repo: repoPath,
|
|
@@ -13949,7 +14106,7 @@ async function initCommand(repoPathArg, options) {
|
|
|
13949
14106
|
`);
|
|
13950
14107
|
}
|
|
13951
14108
|
process.stderr.write("\nNext steps:\n");
|
|
13952
|
-
process.stderr.write(" agentrc readiness
|
|
14109
|
+
process.stderr.write(" agentrc readiness Run readiness report across 9 pillars\n");
|
|
13953
14110
|
if (analysis.areas && analysis.areas.length > 0) {
|
|
13954
14111
|
process.stderr.write(" agentrc instructions --areas Generate per-area instructions\n");
|
|
13955
14112
|
}
|
|
@@ -14201,7 +14358,7 @@ async function readinessCommand(repoPathArg, options) {
|
|
|
14201
14358
|
if (options.visual || outputExt === ".html") {
|
|
14202
14359
|
const html = generateVisualReport({
|
|
14203
14360
|
reports: [{ repo: repoName, report }],
|
|
14204
|
-
title: `
|
|
14361
|
+
title: `Readiness Report: ${repoName}`,
|
|
14205
14362
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
14206
14363
|
});
|
|
14207
14364
|
const outputPath = options.output ? resolvedOutputPath : path18.join(repoPath, "readiness-report.html");
|
|
@@ -14301,7 +14458,7 @@ ${label}`));
|
|
|
14301
14458
|
}
|
|
14302
14459
|
}
|
|
14303
14460
|
if (report.extras.length) {
|
|
14304
|
-
log(chalk3.bold("\
|
|
14461
|
+
log(chalk3.bold("\nReadiness extras"));
|
|
14305
14462
|
for (const extra of report.extras) {
|
|
14306
14463
|
const icon = extra.status === "pass" ? chalk3.green("\u2714") : chalk3.red("\u2716");
|
|
14307
14464
|
log(`${icon} ${extra.title}`);
|
|
@@ -14366,7 +14523,7 @@ function printAreaBreakdown(areaReports) {
|
|
|
14366
14523
|
}
|
|
14367
14524
|
function formatReadinessMarkdown(report, repoName) {
|
|
14368
14525
|
const lines = [];
|
|
14369
|
-
lines.push(`#
|
|
14526
|
+
lines.push(`# Readiness Report: ${repoName}`);
|
|
14370
14527
|
lines.push("");
|
|
14371
14528
|
lines.push(`**Level ${report.achievedLevel}** \u2014 ${levelName(report.achievedLevel)}`);
|
|
14372
14529
|
lines.push("");
|
|
@@ -14399,7 +14556,7 @@ function formatReadinessMarkdown(report, repoName) {
|
|
|
14399
14556
|
lines.push("");
|
|
14400
14557
|
}
|
|
14401
14558
|
if (report.extras.length > 0) {
|
|
14402
|
-
lines.push("##
|
|
14559
|
+
lines.push("## Readiness Extras");
|
|
14403
14560
|
lines.push("");
|
|
14404
14561
|
for (const extra of report.extras) {
|
|
14405
14562
|
const icon = extra.status === "pass" ? "\u2705" : "\u274C";
|
|
@@ -14554,7 +14711,7 @@ function AgentRCTui({ repoPath, skipAnimation = false }) {
|
|
|
14554
14711
|
const [areaCursor, setAreaCursor] = useState5(0);
|
|
14555
14712
|
const repoLabel = useMemo(() => path19.basename(repoPath), [repoPath]);
|
|
14556
14713
|
const repoFull = useMemo(() => repoPath, [repoPath]);
|
|
14557
|
-
const isLoading = status === "generating" || status === "bootstrapping" || status === "evaluating" || status === "generating-areas";
|
|
14714
|
+
const isLoading = status === "generating" || status === "bootstrapping" || status === "evaluating" || status === "generating-areas" || status === "readiness-running";
|
|
14558
14715
|
const isMenu = status === "model-pick" || status === "eval-pick" || status === "batch-pick" || status === "generate-pick" || status === "generate-app-pick" || status === "generate-area-pick";
|
|
14559
14716
|
const spinner = useSpinner(isLoading);
|
|
14560
14717
|
const addLog = (text, type = "info") => {
|
|
@@ -14796,14 +14953,14 @@ function AgentRCTui({ repoPath, skipAnimation = false }) {
|
|
|
14796
14953
|
}
|
|
14797
14954
|
return;
|
|
14798
14955
|
}
|
|
14799
|
-
if (input.toLowerCase() === "
|
|
14956
|
+
if (input.toLowerCase() === "n") {
|
|
14800
14957
|
if (repoAreas.length === 0) {
|
|
14801
14958
|
setMessage("No areas detected. Add agentrc.config.json to define areas.");
|
|
14802
14959
|
return;
|
|
14803
14960
|
}
|
|
14804
14961
|
setAreaCursor(0);
|
|
14805
14962
|
setStatus("generate-area-pick");
|
|
14806
|
-
setMessage("Generate
|
|
14963
|
+
setMessage("Generate nested instructions for areas.");
|
|
14807
14964
|
return;
|
|
14808
14965
|
}
|
|
14809
14966
|
if (key.escape) {
|
|
@@ -14866,10 +15023,7 @@ function AgentRCTui({ repoPath, skipAnimation = false }) {
|
|
|
14866
15023
|
if (status === "generate-area-pick") {
|
|
14867
15024
|
if (input.toLowerCase() === "a") {
|
|
14868
15025
|
setStatus("generating-areas");
|
|
14869
|
-
addLog(
|
|
14870
|
-
`Generating file-based instructions for ${repoAreas.length} areas...`,
|
|
14871
|
-
"progress"
|
|
14872
|
-
);
|
|
15026
|
+
addLog(`Generating nested instructions for ${repoAreas.length} areas...`, "progress");
|
|
14873
15027
|
let written = 0;
|
|
14874
15028
|
for (const [i, area] of repoAreas.entries()) {
|
|
14875
15029
|
setMessage(`Generating for "${area.name}" (${i + 1}/${repoAreas.length})...`);
|
|
@@ -14892,9 +15046,7 @@ function AgentRCTui({ repoPath, skipAnimation = false }) {
|
|
|
14892
15046
|
}
|
|
14893
15047
|
}
|
|
14894
15048
|
setStatus("done");
|
|
14895
|
-
setMessage(
|
|
14896
|
-
`Generated file-based instructions for ${written}/${repoAreas.length} areas.`
|
|
14897
|
-
);
|
|
15049
|
+
setMessage(`Generated nested instructions for ${written}/${repoAreas.length} areas.`);
|
|
14898
15050
|
return;
|
|
14899
15051
|
}
|
|
14900
15052
|
if (key.upArrow) {
|
|
@@ -14910,7 +15062,7 @@ function AgentRCTui({ repoPath, skipAnimation = false }) {
|
|
|
14910
15062
|
if (!area) return;
|
|
14911
15063
|
setStatus("generating-areas");
|
|
14912
15064
|
setMessage(`Generating for "${area.name}"...`);
|
|
14913
|
-
addLog(`Generating
|
|
15065
|
+
addLog(`Generating nested instructions for "${area.name}"...`, "progress");
|
|
14914
15066
|
try {
|
|
14915
15067
|
const body = await generateAreaInstructions({
|
|
14916
15068
|
repoPath,
|
|
@@ -15083,6 +15235,36 @@ function AgentRCTui({ repoPath, skipAnimation = false }) {
|
|
|
15083
15235
|
setMessage("Select what to generate.");
|
|
15084
15236
|
return;
|
|
15085
15237
|
}
|
|
15238
|
+
if (input.toLowerCase() === "r") {
|
|
15239
|
+
setStatus("readiness-running");
|
|
15240
|
+
setMessage("Running readiness report\u2026");
|
|
15241
|
+
addLog("Running readiness report\u2026", "progress");
|
|
15242
|
+
try {
|
|
15243
|
+
let policies;
|
|
15244
|
+
try {
|
|
15245
|
+
const config = await loadAgentrcConfig(repoPath);
|
|
15246
|
+
policies = config?.policies;
|
|
15247
|
+
} catch {
|
|
15248
|
+
}
|
|
15249
|
+
const report = await runReadinessReport({ repoPath, policies });
|
|
15250
|
+
const levelName2 = getLevelName(report.achievedLevel);
|
|
15251
|
+
const failCount = report.criteria.filter((c) => c.status === "fail").length;
|
|
15252
|
+
addLog(
|
|
15253
|
+
`Level ${report.achievedLevel} (${levelName2}) \u2014 ${failCount} item(s) to fix`,
|
|
15254
|
+
"success"
|
|
15255
|
+
);
|
|
15256
|
+
setStatus("done");
|
|
15257
|
+
setMessage(
|
|
15258
|
+
`Readiness: Level ${report.achievedLevel} (${levelName2}). ${failCount} improvement(s) available.`
|
|
15259
|
+
);
|
|
15260
|
+
} catch (error) {
|
|
15261
|
+
const msg = error instanceof Error ? error.message : "Failed.";
|
|
15262
|
+
addLog(`Readiness failed: ${msg}`, "error");
|
|
15263
|
+
setStatus("error");
|
|
15264
|
+
setMessage(`Readiness failed: ${msg}`);
|
|
15265
|
+
}
|
|
15266
|
+
return;
|
|
15267
|
+
}
|
|
15086
15268
|
if (input.toLowerCase() === "b") {
|
|
15087
15269
|
setStatus("batch-pick");
|
|
15088
15270
|
setMessage("Select batch provider.");
|
|
@@ -15135,7 +15317,7 @@ function AgentRCTui({ repoPath, skipAnimation = false }) {
|
|
|
15135
15317
|
{ isActive: inputActive }
|
|
15136
15318
|
);
|
|
15137
15319
|
const statusIcon = status === "error" ? accessible ? "ERROR" : "\u2717" : status === "done" ? accessible ? "OK" : "\u2713" : isLoading ? spinner : accessible ? "*" : "\u25CF";
|
|
15138
|
-
const statusLabel = status === "intro" ? "starting" : status === "idle" ? "ready" : status === "bootstrapEvalCount" ? "input" : status === "bootstrapEvalConfirm" ? "confirm" : status === "eval-pick" ? "eval" : status === "batch-pick" ? "batch" : status === "model-pick" ? "models" : status;
|
|
15320
|
+
const statusLabel = status === "intro" ? "starting" : status === "idle" ? "ready" : status === "bootstrapEvalCount" ? "input" : status === "bootstrapEvalConfirm" ? "confirm" : status === "eval-pick" ? "eval" : status === "batch-pick" ? "batch" : status === "model-pick" ? "models" : status === "readiness-running" ? "readiness" : status;
|
|
15139
15321
|
const statusColor = status === "error" ? "red" : status === "done" ? "green" : isLoading ? "yellow" : isMenu ? "magentaBright" : "cyanBright";
|
|
15140
15322
|
const formatTokens = (result) => {
|
|
15141
15323
|
const withUsage = result.metrics?.withInstructions?.tokenUsage;
|
|
@@ -15287,14 +15469,7 @@ function AgentRCTui({ repoPath, skipAnimation = false }) {
|
|
|
15287
15469
|
] }, app2.name)) })
|
|
15288
15470
|
] }),
|
|
15289
15471
|
status === "generate-area-pick" && repoAreas.length > 0 && /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
15290
|
-
/* @__PURE__ */ jsx7(
|
|
15291
|
-
Divider,
|
|
15292
|
-
{
|
|
15293
|
-
columns: terminalColumns,
|
|
15294
|
-
label: "File-based instructions",
|
|
15295
|
-
accessible
|
|
15296
|
-
}
|
|
15297
|
-
),
|
|
15472
|
+
/* @__PURE__ */ jsx7(Divider, { columns: terminalColumns, label: "Nested instructions", accessible }),
|
|
15298
15473
|
/* @__PURE__ */ jsx7(Box5, { flexDirection: "column", paddingLeft: 1, children: repoAreas.map((area, i) => /* @__PURE__ */ jsxs4(Text5, { children: [
|
|
15299
15474
|
/* @__PURE__ */ jsx7(Text5, { color: i === areaCursor ? "cyanBright" : "gray", children: i === areaCursor ? accessible ? ">" : "\u25B6" : " " }),
|
|
15300
15475
|
/* @__PURE__ */ jsx7(Text5, { color: "gray", children: " " }),
|
|
@@ -15375,9 +15550,9 @@ function AgentRCTui({ repoPath, skipAnimation = false }) {
|
|
|
15375
15550
|
/* @__PURE__ */ jsx7(Text5, { color: "cyan", children: " to select " }),
|
|
15376
15551
|
/* @__PURE__ */ jsx7(KeyHint, { k: "Esc", label: "Back" })
|
|
15377
15552
|
] }) : status === "generate-pick" ? /* @__PURE__ */ jsxs4(Box5, { children: [
|
|
15378
|
-
/* @__PURE__ */ jsx7(KeyHint, { k: "C", label: "
|
|
15379
|
-
/* @__PURE__ */ jsx7(KeyHint, { k: "A", label: "
|
|
15380
|
-
repoAreas.length > 0 && /* @__PURE__ */ jsx7(KeyHint, { k: "
|
|
15553
|
+
/* @__PURE__ */ jsx7(KeyHint, { k: "C", label: "Instructions" }),
|
|
15554
|
+
/* @__PURE__ */ jsx7(KeyHint, { k: "A", label: "Agents" }),
|
|
15555
|
+
repoAreas.length > 0 && /* @__PURE__ */ jsx7(KeyHint, { k: "N", label: "Nested (areas)" }),
|
|
15381
15556
|
/* @__PURE__ */ jsx7(KeyHint, { k: "Esc", label: "Back" })
|
|
15382
15557
|
] }) : status === "generate-app-pick" ? /* @__PURE__ */ jsxs4(Box5, { children: [
|
|
15383
15558
|
/* @__PURE__ */ jsx7(KeyHint, { k: "R", label: "Root only" }),
|
|
@@ -15413,6 +15588,7 @@ function AgentRCTui({ repoPath, skipAnimation = false }) {
|
|
|
15413
15588
|
] }) : isLoading ? /* @__PURE__ */ jsx7(Box5, { children: /* @__PURE__ */ jsx7(KeyHint, { k: "Q", label: "Quit" }) }) : /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
|
|
15414
15589
|
/* @__PURE__ */ jsxs4(Box5, { children: [
|
|
15415
15590
|
/* @__PURE__ */ jsx7(KeyHint, { k: "G", label: "Generate" }),
|
|
15591
|
+
/* @__PURE__ */ jsx7(KeyHint, { k: "R", label: "Readiness" }),
|
|
15416
15592
|
/* @__PURE__ */ jsx7(KeyHint, { k: "E", label: "Eval" }),
|
|
15417
15593
|
/* @__PURE__ */ jsx7(KeyHint, { k: "B", label: "Batch" })
|
|
15418
15594
|
] }),
|
|
@@ -15466,7 +15642,7 @@ function withGlobalOpts(fn) {
|
|
|
15466
15642
|
function runCli(argv) {
|
|
15467
15643
|
const program = new Command();
|
|
15468
15644
|
program.name("agentrc").description("Set up repositories for AI-assisted development").version(CLI_VERSION).option("--json", "Output machine-readable JSON to stdout").option("--quiet", "Suppress stderr progress output").option("--accessible", "Enable screen reader friendly output");
|
|
15469
|
-
program.command("init").description("
|
|
15645
|
+
program.command("init").description("Init repository \u2014 analyze & generate instructions").argument("[path]", "Path to a local repository").option("--github", "Use a GitHub repository").option("--provider <provider>", "Repo provider (github|azure)").option("--yes", "Accept defaults (generates instructions, MCP, and VS Code configs)").option("--force", "Overwrite existing files").option("--model <name>", "Model for instructions generation", DEFAULT_MODEL).action(withGlobalOpts(initCommand));
|
|
15470
15646
|
program.command("analyze").description("Detect languages, frameworks, monorepo structure, and areas").argument("[path]", "Path to a local repository").option("--output <path>", "Write report to file (.json or .md)").option("--force", "Overwrite existing output file").action(withGlobalOpts(analyzeCommand));
|
|
15471
15647
|
program.command("generate").description("Generate instructions, agents, MCP, or VS Code configs").addArgument(
|
|
15472
15648
|
new Argument("<type>", "Config type to generate").choices([
|
|
@@ -15475,14 +15651,14 @@ function runCli(argv) {
|
|
|
15475
15651
|
"mcp",
|
|
15476
15652
|
"vscode"
|
|
15477
15653
|
])
|
|
15478
|
-
).argument("[path]", "Path to a local repository").option("--force", "Overwrite existing files").option("--per-app", "
|
|
15654
|
+
).argument("[path]", "Path to a local repository").option("--force", "Overwrite existing files").option("--per-app", "(deprecated) Use `agentrc instructions --areas` instead").option("--model <name>", "Model for instructions generation", DEFAULT_MODEL).option("--strategy <mode>", "Instruction strategy (flat or nested)").action(withGlobalOpts(generateCommand));
|
|
15479
15655
|
program.command("pr").description("Create a PR with generated configs on GitHub or Azure DevOps").argument("[repo]", "Repo identifier (github: owner/name, azure: org/project/repo)").option("--branch <name>", "Branch name").option("--provider <provider>", "Repo provider (github|azure)").option("--model <name>", "Model for instructions generation", DEFAULT_MODEL).action(withGlobalOpts(prCommand));
|
|
15480
15656
|
program.command("eval").description("Compare AI responses with and without instructions").argument("[path]", "Path to eval config JSON").option("--repo <path>", "Repository path", process.cwd()).option("--model <name>", "Model for responses", DEFAULT_MODEL).option("--judge-model <name>", "Model for judging", DEFAULT_JUDGE_MODEL).option("--list-models", "List Copilot CLI models and exit").option("--output <path>", "Write results JSON to file").option("--init", "Create a starter agentrc.eval.json file").option("--count <number>", "Number of eval cases to generate (with --init)").option("--fail-level <number>", "Exit with error if pass rate (%) falls below threshold").action(withGlobalOpts(evalCommand));
|
|
15481
15657
|
program.command("tui").description("Interactive terminal UI for generation, evaluation, and batch workflows").option("--repo <path>", "Repository path", process.cwd()).option("--no-animation", "Skip the animated banner intro").action(withGlobalOpts(tuiCommand));
|
|
15482
|
-
program.command("instructions").description("Generate
|
|
15483
|
-
program.command("readiness").description("
|
|
15658
|
+
program.command("instructions").description("Generate instructions for the repository").option("--repo <path>", "Repository path", process.cwd()).option("--output <path>", "Output path for instructions").option("--model <name>", "Model for instructions generation", DEFAULT_MODEL).option("--force", "Overwrite existing area instruction files").option("--areas", "Also generate instructions for detected areas").option("--areas-only", "Generate only area instructions (skip root)").option("--area <name>", "Generate instructions for a specific area").option("--strategy <mode>", "Instruction strategy (flat or nested)").option("--claude-md", "Generate CLAUDE.md files alongside AGENTS.md (nested strategy)").option("--dry-run", "Preview generated files without writing anything").action(withGlobalOpts(instructionsCommand));
|
|
15659
|
+
program.command("readiness").description("Run readiness report across 9 maturity pillars").argument("[path]", "Path to a local repository").option("--output <path>", "Write report to file (.json, .md, or .html)").option("--force", "Overwrite existing output file").option("--visual", "Generate visual HTML report").option("--per-area", "Show per-area readiness breakdown").option("--policy <sources>", "Policy sources (comma-separated: paths, npm packages)").option("--fail-level <number>", "Exit with error if readiness level is below threshold (1\u20135)").action(withGlobalOpts(readinessCommand));
|
|
15484
15660
|
program.command("batch").description("Batch process multiple repos across orgs").argument("[repos...]", "Repos in owner/name form (GitHub) or org/project/repo (Azure)").option("--output <path>", "Write results JSON to file").option("--provider <provider>", "Repo provider (github|azure)", "github").option("--model <name>", "Model for instructions generation", DEFAULT_MODEL).option("--branch <name>", "Branch name for PRs").action(withGlobalOpts(batchCommand));
|
|
15485
|
-
program.command("batch-readiness").description("
|
|
15661
|
+
program.command("batch-readiness").description("Run batch readiness report for multiple repos").option("--output <path>", "Write HTML report to file").option("--policy <sources>", "Policy sources (comma-separated: paths, npm packages)").action(withGlobalOpts(batchReadinessCommand));
|
|
15486
15662
|
program.parse(argv);
|
|
15487
15663
|
}
|
|
15488
15664
|
|