@lousy-agents/cli 4.0.2 → 5.1.0
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
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# @lousy-agents/cli
|
|
2
|
+
|
|
3
|
+
CLI scaffolding for Lousy Agents.
|
|
4
|
+
|
|
5
|
+
Use this package to bootstrap new projects with testing, linting, AI assistant instructions, and GitHub Copilot setup.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx @lousy-agents/cli init
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Common follow-up commands:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Generate Copilot setup workflow in an existing repository
|
|
17
|
+
npx @lousy-agents/cli copilot-setup
|
|
18
|
+
|
|
19
|
+
# Create new resources such as custom agents
|
|
20
|
+
npx @lousy-agents/cli new
|
|
21
|
+
|
|
22
|
+
# Validate skills, agents, and instruction files
|
|
23
|
+
npx @lousy-agents/cli lint
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Documentation
|
|
27
|
+
|
|
28
|
+
- Project overview: [README](https://github.com/zpratt/lousy-agents#readme)
|
|
29
|
+
- `init` command: [`docs/init.md`](https://github.com/zpratt/lousy-agents/blob/main/docs/init.md)
|
|
30
|
+
- `new` command: [`docs/new.md`](https://github.com/zpratt/lousy-agents/blob/main/docs/new.md)
|
|
31
|
+
- `lint` command: [`docs/lint.md`](https://github.com/zpratt/lousy-agents/blob/main/docs/lint.md)
|
|
32
|
+
- `copilot-setup` command: [`docs/copilot-setup.md`](https://github.com/zpratt/lousy-agents/blob/main/docs/copilot-setup.md)
|
|
33
|
+
|
|
34
|
+
## Reference Examples
|
|
35
|
+
|
|
36
|
+
- React webapp scaffold: [`packages/cli/ui/copilot-with-react`](https://github.com/zpratt/lousy-agents/tree/main/packages/cli/ui/copilot-with-react)
|
|
37
|
+
- Fastify API scaffold: [`packages/cli/api/copilot-with-fastify`](https://github.com/zpratt/lousy-agents/tree/main/packages/cli/api/copilot-with-fastify)
|
|
38
|
+
- Citty CLI scaffold: [`packages/cli/cli/copilot-with-citty`](https://github.com/zpratt/lousy-agents/tree/main/packages/cli/cli/copilot-with-citty)
|
package/dist/index.js
CHANGED
|
@@ -31542,6 +31542,34 @@ function defaultExec(command, args, options) {
|
|
|
31542
31542
|
return new FileSystemInstructionAnalysisGateway();
|
|
31543
31543
|
}
|
|
31544
31544
|
|
|
31545
|
+
;// CONCATENATED MODULE: ../core/src/gateways/npmrc-gateway.ts
|
|
31546
|
+
/**
|
|
31547
|
+
* Gateway for reading and writing `.npmrc` configuration files.
|
|
31548
|
+
*/
|
|
31549
|
+
|
|
31550
|
+
const MAX_NPMRC_BYTES = 64 * 1024;
|
|
31551
|
+
/**
|
|
31552
|
+
* File system implementation of the NpmrcGateway.
|
|
31553
|
+
*/ class FileSystemNpmrcGateway {
|
|
31554
|
+
async readNpmrc(targetDir) {
|
|
31555
|
+
const npmrcPath = await file_system_utils_resolveSafePath(targetDir, ".npmrc");
|
|
31556
|
+
if (!await file_system_utils_fileExists(npmrcPath)) {
|
|
31557
|
+
return null;
|
|
31558
|
+
}
|
|
31559
|
+
await assertFileSizeWithinLimit(npmrcPath, MAX_NPMRC_BYTES, "`.npmrc` file");
|
|
31560
|
+
return (0,promises_.readFile)(npmrcPath, "utf-8");
|
|
31561
|
+
}
|
|
31562
|
+
async writeNpmrc(targetDir, content) {
|
|
31563
|
+
const npmrcPath = await file_system_utils_resolveSafePath(targetDir, ".npmrc");
|
|
31564
|
+
await (0,promises_.writeFile)(npmrcPath, content, "utf-8");
|
|
31565
|
+
}
|
|
31566
|
+
}
|
|
31567
|
+
/**
|
|
31568
|
+
* Creates and returns the default NpmrcGateway.
|
|
31569
|
+
*/ function createNpmrcGateway() {
|
|
31570
|
+
return new FileSystemNpmrcGateway();
|
|
31571
|
+
}
|
|
31572
|
+
|
|
31545
31573
|
;// CONCATENATED MODULE: ../core/src/entities/feedback-loop.ts
|
|
31546
31574
|
/**
|
|
31547
31575
|
* Core domain entities for SDLC feedback loop discovery and validation.
|
|
@@ -32281,6 +32309,53 @@ function createWorkflowGateway() {
|
|
|
32281
32309
|
|
|
32282
32310
|
|
|
32283
32311
|
|
|
32312
|
+
|
|
32313
|
+
;// CONCATENATED MODULE: ../core/src/use-cases/add-agent-shell.ts
|
|
32314
|
+
/**
|
|
32315
|
+
* Use case for adding agent-shell to an npm project's `.npmrc` configuration.
|
|
32316
|
+
* Enables npm script observability via the agent-shell script-shell shim.
|
|
32317
|
+
*/ /**
|
|
32318
|
+
* The script-shell entry added to `.npmrc` to enable agent-shell.
|
|
32319
|
+
* Uses a PATH-resolved binary name so it works independently of local node_modules.
|
|
32320
|
+
*/ const AGENT_SHELL_NPMRC_ENTRY = "script-shell=agent-shell";
|
|
32321
|
+
/**
|
|
32322
|
+
* Checks whether `.npmrc` content already has an active (non-comment) script-shell entry.
|
|
32323
|
+
* Lines starting with `#` or `;` are treated as comments and ignored.
|
|
32324
|
+
*/ function hasScriptShellEntry(content) {
|
|
32325
|
+
return /^\s*script-shell\s*=/m.test(content);
|
|
32326
|
+
}
|
|
32327
|
+
/**
|
|
32328
|
+
* Adds agent-shell to the project's `.npmrc` if not already configured.
|
|
32329
|
+
* Only operates on npm projects.
|
|
32330
|
+
*/ async function addAgentShell(input, npmrcGateway) {
|
|
32331
|
+
if (input.packageManager.type !== "npm") {
|
|
32332
|
+
return {
|
|
32333
|
+
wasAdded: false,
|
|
32334
|
+
alreadyConfigured: false
|
|
32335
|
+
};
|
|
32336
|
+
}
|
|
32337
|
+
const existingContent = await npmrcGateway.readNpmrc(input.targetDir);
|
|
32338
|
+
if (existingContent !== null && hasScriptShellEntry(existingContent)) {
|
|
32339
|
+
return {
|
|
32340
|
+
wasAdded: false,
|
|
32341
|
+
alreadyConfigured: true
|
|
32342
|
+
};
|
|
32343
|
+
}
|
|
32344
|
+
const newEntry = `${AGENT_SHELL_NPMRC_ENTRY}\n`;
|
|
32345
|
+
let updatedContent;
|
|
32346
|
+
if (existingContent !== null) {
|
|
32347
|
+
const separator = existingContent.length > 0 && !existingContent.endsWith("\n") ? "\n" : "";
|
|
32348
|
+
updatedContent = `${existingContent}${separator}${newEntry}`;
|
|
32349
|
+
} else {
|
|
32350
|
+
updatedContent = newEntry;
|
|
32351
|
+
}
|
|
32352
|
+
await npmrcGateway.writeNpmrc(input.targetDir, updatedContent);
|
|
32353
|
+
return {
|
|
32354
|
+
wasAdded: true,
|
|
32355
|
+
alreadyConfigured: false
|
|
32356
|
+
};
|
|
32357
|
+
}
|
|
32358
|
+
|
|
32284
32359
|
;// CONCATENATED MODULE: ../core/src/use-cases/check-copilot-review-ruleset.ts
|
|
32285
32360
|
function isCopilotCodeReviewRule(rule) {
|
|
32286
32361
|
return rule.type === "copilot_code_review";
|
|
@@ -34759,6 +34834,7 @@ const consola = dist_createConsola();
|
|
|
34759
34834
|
|
|
34760
34835
|
|
|
34761
34836
|
|
|
34837
|
+
|
|
34762
34838
|
const copilotSetupArgs = {};
|
|
34763
34839
|
const copilotSetupCommand = defineCommand({
|
|
34764
34840
|
meta: {
|
|
@@ -34772,6 +34848,7 @@ const copilotSetupCommand = defineCommand({
|
|
|
34772
34848
|
const workflowGateway = createWorkflowGateway();
|
|
34773
34849
|
const copilotSetupConfig = await loadCopilotSetupConfig();
|
|
34774
34850
|
const rulesetGateway = context.data?.rulesetGateway ?? await createGitHubRulesetGateway();
|
|
34851
|
+
const npmrcGateway = context.data?.npmrcGateway ?? createNpmrcGateway();
|
|
34775
34852
|
const prompt = context.data?.prompt ?? ((message, options)=>consola.prompt(message, options));
|
|
34776
34853
|
consola.info("Detecting environment configuration...");
|
|
34777
34854
|
// Step 1: Detect environment configuration files
|
|
@@ -34814,7 +34891,7 @@ const copilotSetupCommand = defineCommand({
|
|
|
34814
34891
|
const missingCandidates = findMissingCandidates(allCandidates, existingActions);
|
|
34815
34892
|
if (missingCandidates.length === 0) {
|
|
34816
34893
|
consola.success("Copilot Setup Steps workflow already contains all detected setup steps. No changes needed.");
|
|
34817
|
-
await
|
|
34894
|
+
await runPostWorkflowSteps(rulesetGateway, npmrcGateway, targetDir, prompt, environment);
|
|
34818
34895
|
return;
|
|
34819
34896
|
}
|
|
34820
34897
|
const missingNames = missingCandidates.map((c)=>c.action).join(", ");
|
|
@@ -34834,8 +34911,8 @@ const copilotSetupCommand = defineCommand({
|
|
|
34834
34911
|
consola.info(`Included setup steps: ${actionNames}`);
|
|
34835
34912
|
}
|
|
34836
34913
|
}
|
|
34837
|
-
// Step 6:
|
|
34838
|
-
await
|
|
34914
|
+
// Step 6: Run post-workflow steps (ruleset + agent-shell)
|
|
34915
|
+
await runPostWorkflowSteps(rulesetGateway, npmrcGateway, targetDir, prompt, environment);
|
|
34839
34916
|
}
|
|
34840
34917
|
});
|
|
34841
34918
|
async function checkAndPromptRuleset(rulesetGateway, targetDir, prompt) {
|
|
@@ -34878,6 +34955,33 @@ async function checkAndPromptRuleset(rulesetGateway, targetDir, prompt) {
|
|
|
34878
34955
|
consola.error(`Failed to create ruleset: ${message}. You may need admin access to the repository.`);
|
|
34879
34956
|
}
|
|
34880
34957
|
}
|
|
34958
|
+
async function runPostWorkflowSteps(rulesetGateway, npmrcGateway, targetDir, prompt, environment) {
|
|
34959
|
+
await checkAndPromptRuleset(rulesetGateway, targetDir, prompt);
|
|
34960
|
+
await checkAndPromptAgentShell(npmrcGateway, targetDir, prompt, environment);
|
|
34961
|
+
}
|
|
34962
|
+
async function checkAndPromptAgentShell(npmrcGateway, targetDir, prompt, environment) {
|
|
34963
|
+
const npmPackageManager = environment.packageManagers.find((pm)=>pm.type === "npm");
|
|
34964
|
+
if (!npmPackageManager) {
|
|
34965
|
+
return;
|
|
34966
|
+
}
|
|
34967
|
+
const shouldAdd = await prompt("Would you like to add agent-shell to observe npm script execution?", {
|
|
34968
|
+
type: "confirm",
|
|
34969
|
+
default: true
|
|
34970
|
+
});
|
|
34971
|
+
if (!shouldAdd) {
|
|
34972
|
+
consola.info("Skipping agent-shell setup.");
|
|
34973
|
+
return;
|
|
34974
|
+
}
|
|
34975
|
+
const result = await addAgentShell({
|
|
34976
|
+
targetDir,
|
|
34977
|
+
packageManager: npmPackageManager
|
|
34978
|
+
}, npmrcGateway);
|
|
34979
|
+
if (result.alreadyConfigured) {
|
|
34980
|
+
consola.success("agent-shell is already configured in .npmrc.");
|
|
34981
|
+
return;
|
|
34982
|
+
}
|
|
34983
|
+
consola.success("Added agent-shell to .npmrc. Run `npm install -g @lousy-agents/agent-shell` to complete setup.");
|
|
34984
|
+
}
|
|
34881
34985
|
|
|
34882
34986
|
;// CONCATENATED MODULE: ./src/lib/config.ts
|
|
34883
34987
|
|
|
@@ -55810,6 +55914,84 @@ const remark = unified().use(remarkParse).use(remarkStringify).freeze()
|
|
|
55810
55914
|
}
|
|
55811
55915
|
}
|
|
55812
55916
|
|
|
55917
|
+
;// CONCATENATED MODULE: ../core/src/use-cases/apply-severity-filter.ts
|
|
55918
|
+
/**
|
|
55919
|
+
* Shared severity filtering for lint outputs.
|
|
55920
|
+
* Applies rule severity configuration to diagnostics, filtering out "off" rules,
|
|
55921
|
+
* remapping "warn" → "warning", and recalculating summary counts.
|
|
55922
|
+
*/ /** Maps a lint target to its config key */ const TARGET_TO_CONFIG_KEY = {
|
|
55923
|
+
skill: "skills",
|
|
55924
|
+
agent: "agents",
|
|
55925
|
+
instruction: "instructions"
|
|
55926
|
+
};
|
|
55927
|
+
/**
|
|
55928
|
+
* Maps config severity to diagnostic severity.
|
|
55929
|
+
* "warn" → "warning", "error" → "error", "off" → null (drop).
|
|
55930
|
+
*/ function apply_severity_filter_mapSeverity(configSeverity) {
|
|
55931
|
+
if (configSeverity === "off") {
|
|
55932
|
+
return null;
|
|
55933
|
+
}
|
|
55934
|
+
if (configSeverity === "warn") {
|
|
55935
|
+
return "warning";
|
|
55936
|
+
}
|
|
55937
|
+
return configSeverity;
|
|
55938
|
+
}
|
|
55939
|
+
/**
|
|
55940
|
+
* Filters instruction suggestions based on rule severity configuration.
|
|
55941
|
+
* Drops suggestions whose corresponding rule is "off".
|
|
55942
|
+
* Suggestions without a ruleId pass through unchanged.
|
|
55943
|
+
*/ function filterInstructionSuggestions(suggestions, rules) {
|
|
55944
|
+
return suggestions.filter((suggestion)=>{
|
|
55945
|
+
if (!suggestion.ruleId) {
|
|
55946
|
+
return true;
|
|
55947
|
+
}
|
|
55948
|
+
return rules[suggestion.ruleId] !== "off";
|
|
55949
|
+
});
|
|
55950
|
+
}
|
|
55951
|
+
/**
|
|
55952
|
+
* Applies severity filtering to a LintOutput based on rule configuration.
|
|
55953
|
+
* Drops diagnostics for "off" rules, remaps severity for "warn"/"error" rules.
|
|
55954
|
+
* Diagnostics without a ruleId pass through unchanged.
|
|
55955
|
+
* For instruction targets, also filters qualityResult.suggestions.
|
|
55956
|
+
*/ function applySeverityFilter(output, rulesConfig) {
|
|
55957
|
+
const configKey = TARGET_TO_CONFIG_KEY[output.target];
|
|
55958
|
+
const targetRules = rulesConfig[configKey];
|
|
55959
|
+
const filteredDiagnostics = [];
|
|
55960
|
+
for (const diagnostic of output.diagnostics){
|
|
55961
|
+
const configuredSeverity = diagnostic.ruleId ? targetRules[diagnostic.ruleId] : undefined;
|
|
55962
|
+
if (!configuredSeverity) {
|
|
55963
|
+
filteredDiagnostics.push(diagnostic);
|
|
55964
|
+
continue;
|
|
55965
|
+
}
|
|
55966
|
+
const mappedSeverity = apply_severity_filter_mapSeverity(configuredSeverity);
|
|
55967
|
+
if (mappedSeverity === null) {
|
|
55968
|
+
continue;
|
|
55969
|
+
}
|
|
55970
|
+
filteredDiagnostics.push({
|
|
55971
|
+
...diagnostic,
|
|
55972
|
+
severity: mappedSeverity
|
|
55973
|
+
});
|
|
55974
|
+
}
|
|
55975
|
+
const totalErrors = filteredDiagnostics.filter((d)=>d.severity === "error").length;
|
|
55976
|
+
const totalWarnings = filteredDiagnostics.filter((d)=>d.severity === "warning").length;
|
|
55977
|
+
const totalInfos = filteredDiagnostics.filter((d)=>d.severity === "info").length;
|
|
55978
|
+
const filteredQualityResult = output.qualityResult && configKey === "instructions" ? {
|
|
55979
|
+
...output.qualityResult,
|
|
55980
|
+
suggestions: filterInstructionSuggestions(output.qualityResult.suggestions, targetRules)
|
|
55981
|
+
} : output.qualityResult;
|
|
55982
|
+
return {
|
|
55983
|
+
...output,
|
|
55984
|
+
diagnostics: filteredDiagnostics,
|
|
55985
|
+
qualityResult: filteredQualityResult,
|
|
55986
|
+
summary: {
|
|
55987
|
+
...output.summary,
|
|
55988
|
+
totalErrors,
|
|
55989
|
+
totalWarnings,
|
|
55990
|
+
totalInfos
|
|
55991
|
+
}
|
|
55992
|
+
};
|
|
55993
|
+
}
|
|
55994
|
+
|
|
55813
55995
|
;// CONCATENATED MODULE: ../core/src/use-cases/lint-agent-frontmatter.ts
|
|
55814
55996
|
/**
|
|
55815
55997
|
* Use case for linting GitHub Copilot custom agent frontmatter.
|
|
@@ -56111,6 +56293,7 @@ function hasFrontmatterDelimiters(content) {
|
|
|
56111
56293
|
|
|
56112
56294
|
|
|
56113
56295
|
|
|
56296
|
+
|
|
56114
56297
|
/** Schema for validating target directory */ const TargetDirSchema = schemas_string().min(1, "Target directory is required");
|
|
56115
56298
|
/**
|
|
56116
56299
|
* Validates the target directory.
|
|
@@ -56275,78 +56458,6 @@ function hasFrontmatterDelimiters(content) {
|
|
|
56275
56458
|
consola.warn(suggestion.message);
|
|
56276
56459
|
}
|
|
56277
56460
|
}
|
|
56278
|
-
/** Maps a lint target to its config key */ const TARGET_TO_CONFIG_KEY = {
|
|
56279
|
-
skill: "skills",
|
|
56280
|
-
agent: "agents",
|
|
56281
|
-
instruction: "instructions"
|
|
56282
|
-
};
|
|
56283
|
-
/**
|
|
56284
|
-
* Maps config-facing severity to diagnostic-facing severity.
|
|
56285
|
-
* "warn" → "warning", "error" → "error", "off" → null (drop).
|
|
56286
|
-
*/ function lint_mapSeverity(configSeverity) {
|
|
56287
|
-
if (configSeverity === "off") {
|
|
56288
|
-
return null;
|
|
56289
|
-
}
|
|
56290
|
-
if (configSeverity === "warn") {
|
|
56291
|
-
return "warning";
|
|
56292
|
-
}
|
|
56293
|
-
return configSeverity;
|
|
56294
|
-
}
|
|
56295
|
-
/**
|
|
56296
|
-
* Filters instruction suggestions based on rule severity configuration.
|
|
56297
|
-
* Drops suggestions whose corresponding rule is "off".
|
|
56298
|
-
* Suggestions without a ruleId pass through unchanged.
|
|
56299
|
-
*/ function filterInstructionSuggestions(suggestions, rules) {
|
|
56300
|
-
return suggestions.filter((suggestion)=>{
|
|
56301
|
-
if (!suggestion.ruleId) {
|
|
56302
|
-
return true;
|
|
56303
|
-
}
|
|
56304
|
-
return rules[suggestion.ruleId] !== "off";
|
|
56305
|
-
});
|
|
56306
|
-
}
|
|
56307
|
-
/**
|
|
56308
|
-
* Applies severity filtering to a LintOutput based on rule configuration.
|
|
56309
|
-
* Drops diagnostics for "off" rules, remaps severity for "warn"/"error" rules.
|
|
56310
|
-
* Diagnostics without a ruleId pass through unchanged.
|
|
56311
|
-
* For instruction targets, also filters qualityResult.suggestions.
|
|
56312
|
-
*/ function applySeverityFilter(output, rulesConfig) {
|
|
56313
|
-
const configKey = TARGET_TO_CONFIG_KEY[output.target];
|
|
56314
|
-
const targetRules = rulesConfig[configKey];
|
|
56315
|
-
const filteredDiagnostics = [];
|
|
56316
|
-
for (const diagnostic of output.diagnostics){
|
|
56317
|
-
const configuredSeverity = diagnostic.ruleId ? targetRules[diagnostic.ruleId] : undefined;
|
|
56318
|
-
if (!configuredSeverity) {
|
|
56319
|
-
filteredDiagnostics.push(diagnostic);
|
|
56320
|
-
continue;
|
|
56321
|
-
}
|
|
56322
|
-
const mappedSeverity = lint_mapSeverity(configuredSeverity);
|
|
56323
|
-
if (mappedSeverity === null) {
|
|
56324
|
-
continue;
|
|
56325
|
-
}
|
|
56326
|
-
filteredDiagnostics.push({
|
|
56327
|
-
...diagnostic,
|
|
56328
|
-
severity: mappedSeverity
|
|
56329
|
-
});
|
|
56330
|
-
}
|
|
56331
|
-
const totalErrors = filteredDiagnostics.filter((d)=>d.severity === "error").length;
|
|
56332
|
-
const totalWarnings = filteredDiagnostics.filter((d)=>d.severity === "warning").length;
|
|
56333
|
-
const totalInfos = filteredDiagnostics.filter((d)=>d.severity === "info").length;
|
|
56334
|
-
const filteredQualityResult = output.qualityResult && configKey === "instructions" ? {
|
|
56335
|
-
...output.qualityResult,
|
|
56336
|
-
suggestions: filterInstructionSuggestions(output.qualityResult.suggestions, targetRules)
|
|
56337
|
-
} : output.qualityResult;
|
|
56338
|
-
return {
|
|
56339
|
-
...output,
|
|
56340
|
-
diagnostics: filteredDiagnostics,
|
|
56341
|
-
qualityResult: filteredQualityResult,
|
|
56342
|
-
summary: {
|
|
56343
|
-
...output.summary,
|
|
56344
|
-
totalErrors,
|
|
56345
|
-
totalWarnings,
|
|
56346
|
-
totalInfos
|
|
56347
|
-
}
|
|
56348
|
-
};
|
|
56349
|
-
}
|
|
56350
56461
|
/**
|
|
56351
56462
|
* The `lint` command for validating agent skills, custom agents, and instruction files.
|
|
56352
56463
|
*/ const lintCommand = defineCommand({
|