@lousy-agents/cli 2.3.4 → 2.5.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 +3 -1
- package/dist/index.js +638 -21
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +1040 -10
- package/dist/mcp-server.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -10032,7 +10032,7 @@ function resolveArgs(argsDef) {
|
|
|
10032
10032
|
function defineCommand(def) {
|
|
10033
10033
|
return def;
|
|
10034
10034
|
}
|
|
10035
|
-
async function
|
|
10035
|
+
async function dist_runCommand(cmd, opts) {
|
|
10036
10036
|
const cmdArgs = await resolveValue(cmd.args || {});
|
|
10037
10037
|
const parsedArgs = parseArgs(opts.rawArgs, cmdArgs);
|
|
10038
10038
|
const context = {
|
|
@@ -10051,7 +10051,7 @@ async function runCommand(cmd, opts) {
|
|
|
10051
10051
|
if (subCommandName) {
|
|
10052
10052
|
if (!subCommands[subCommandName]) throw new CLIError(`Unknown command ${cyan(subCommandName)}`, "E_UNKNOWN_COMMAND");
|
|
10053
10053
|
const subCommand = await resolveValue(subCommands[subCommandName]);
|
|
10054
|
-
if (subCommand) await
|
|
10054
|
+
if (subCommand) await dist_runCommand(subCommand, { rawArgs: opts.rawArgs.slice(subCommandArgIndex + 1) });
|
|
10055
10055
|
} else if (!cmd.run) throw new CLIError(`No command specified.`, "E_NO_COMMAND");
|
|
10056
10056
|
}
|
|
10057
10057
|
if (typeof cmd.run === "function") result = await cmd.run(context);
|
|
@@ -10151,7 +10151,7 @@ async function runMain(cmd, opts = {}) {
|
|
|
10151
10151
|
const meta = typeof cmd.meta === "function" ? await cmd.meta() : await cmd.meta;
|
|
10152
10152
|
if (!meta?.version) throw new CLIError("No version specified", "E_NO_VERSION");
|
|
10153
10153
|
console.log(meta.version);
|
|
10154
|
-
} else await
|
|
10154
|
+
} else await dist_runCommand(cmd, { rawArgs });
|
|
10155
10155
|
} catch (error) {
|
|
10156
10156
|
if (error instanceof CLIError) {
|
|
10157
10157
|
await showUsage$1(...await resolveSubCommand(cmd, rawArgs));
|
|
@@ -11754,7 +11754,7 @@ const consola = dist_createConsola();
|
|
|
11754
11754
|
*/
|
|
11755
11755
|
/**
|
|
11756
11756
|
* Checks if a file or directory exists
|
|
11757
|
-
*/ async function
|
|
11757
|
+
*/ async function file_system_utils_fileExists(path) {
|
|
11758
11758
|
try {
|
|
11759
11759
|
await (0,promises_.access)(path);
|
|
11760
11760
|
return true;
|
|
@@ -11778,7 +11778,7 @@ const consola = dist_createConsola();
|
|
|
11778
11778
|
}
|
|
11779
11779
|
async agentFileExists(targetDir, agentName) {
|
|
11780
11780
|
const filePath = this.getAgentFilePath(targetDir, agentName);
|
|
11781
|
-
return
|
|
11781
|
+
return file_system_utils_fileExists(filePath);
|
|
11782
11782
|
}
|
|
11783
11783
|
async ensureAgentsDirectory(targetDir) {
|
|
11784
11784
|
const agentsDir = (0,external_node_path_.join)(targetDir, ".github", "agents");
|
|
@@ -11799,6 +11799,27 @@ const consola = dist_createConsola();
|
|
|
11799
11799
|
return new FileSystemAgentFileGateway();
|
|
11800
11800
|
}
|
|
11801
11801
|
|
|
11802
|
+
;// CONCATENATED MODULE: ./src/entities/copilot-setup.ts
|
|
11803
|
+
/**
|
|
11804
|
+
* Core domain entities for the Copilot Setup Steps feature.
|
|
11805
|
+
* These are the fundamental types that represent the business domain.
|
|
11806
|
+
*/ /**
|
|
11807
|
+
* Types of version files supported for detection
|
|
11808
|
+
*/ /**
|
|
11809
|
+
* Node.js package manager types (in priority order: npm > yarn > pnpm)
|
|
11810
|
+
*/ const NODE_PACKAGE_MANAGERS = [
|
|
11811
|
+
"npm",
|
|
11812
|
+
"yarn",
|
|
11813
|
+
"pnpm"
|
|
11814
|
+
];
|
|
11815
|
+
/**
|
|
11816
|
+
* Python package manager types (in priority order)
|
|
11817
|
+
*/ const PYTHON_PACKAGE_MANAGERS = [
|
|
11818
|
+
"poetry",
|
|
11819
|
+
"pipenv",
|
|
11820
|
+
"pip"
|
|
11821
|
+
];
|
|
11822
|
+
|
|
11802
11823
|
// EXTERNAL MODULE: external "node:fs"
|
|
11803
11824
|
var external_node_fs_ = __webpack_require__(3024);
|
|
11804
11825
|
// EXTERNAL MODULE: ./node_modules/pathe/dist/shared/pathe.M-eThtNZ.mjs
|
|
@@ -14086,12 +14107,102 @@ async function watchConfig(options) {
|
|
|
14086
14107
|
"actions/setup-ruby",
|
|
14087
14108
|
"jdx/mise-action"
|
|
14088
14109
|
];
|
|
14110
|
+
/**
|
|
14111
|
+
* Default package manager mappings
|
|
14112
|
+
* Based on Dependabot supported ecosystems
|
|
14113
|
+
*/ const DEFAULT_PACKAGE_MANAGERS = [
|
|
14114
|
+
// Node.js package managers
|
|
14115
|
+
{
|
|
14116
|
+
type: "npm",
|
|
14117
|
+
manifestFile: "package.json",
|
|
14118
|
+
lockfile: "package-lock.json",
|
|
14119
|
+
installCommand: "npm ci"
|
|
14120
|
+
},
|
|
14121
|
+
{
|
|
14122
|
+
type: "yarn",
|
|
14123
|
+
manifestFile: "package.json",
|
|
14124
|
+
lockfile: "yarn.lock",
|
|
14125
|
+
installCommand: "yarn install --frozen-lockfile"
|
|
14126
|
+
},
|
|
14127
|
+
{
|
|
14128
|
+
type: "pnpm",
|
|
14129
|
+
manifestFile: "package.json",
|
|
14130
|
+
lockfile: "pnpm-lock.yaml",
|
|
14131
|
+
installCommand: "pnpm install --frozen-lockfile"
|
|
14132
|
+
},
|
|
14133
|
+
// Python package managers
|
|
14134
|
+
{
|
|
14135
|
+
type: "pip",
|
|
14136
|
+
manifestFile: "requirements.txt",
|
|
14137
|
+
installCommand: "pip install -r requirements.txt"
|
|
14138
|
+
},
|
|
14139
|
+
{
|
|
14140
|
+
type: "pipenv",
|
|
14141
|
+
manifestFile: "Pipfile",
|
|
14142
|
+
lockfile: "Pipfile.lock",
|
|
14143
|
+
installCommand: "pipenv install --deploy"
|
|
14144
|
+
},
|
|
14145
|
+
{
|
|
14146
|
+
type: "poetry",
|
|
14147
|
+
manifestFile: "pyproject.toml",
|
|
14148
|
+
lockfile: "poetry.lock",
|
|
14149
|
+
requiresLockfile: true,
|
|
14150
|
+
installCommand: "poetry install --no-root"
|
|
14151
|
+
},
|
|
14152
|
+
// Ruby
|
|
14153
|
+
{
|
|
14154
|
+
type: "bundler",
|
|
14155
|
+
manifestFile: "Gemfile",
|
|
14156
|
+
lockfile: "Gemfile.lock",
|
|
14157
|
+
installCommand: "bundle install"
|
|
14158
|
+
},
|
|
14159
|
+
// Rust
|
|
14160
|
+
{
|
|
14161
|
+
type: "cargo",
|
|
14162
|
+
manifestFile: "Cargo.toml",
|
|
14163
|
+
lockfile: "Cargo.lock",
|
|
14164
|
+
installCommand: "cargo build"
|
|
14165
|
+
},
|
|
14166
|
+
// PHP
|
|
14167
|
+
{
|
|
14168
|
+
type: "composer",
|
|
14169
|
+
manifestFile: "composer.json",
|
|
14170
|
+
lockfile: "composer.lock",
|
|
14171
|
+
installCommand: "composer install"
|
|
14172
|
+
},
|
|
14173
|
+
// Java
|
|
14174
|
+
{
|
|
14175
|
+
type: "maven",
|
|
14176
|
+
manifestFile: "pom.xml",
|
|
14177
|
+
installCommand: "mvn install -DskipTests"
|
|
14178
|
+
},
|
|
14179
|
+
{
|
|
14180
|
+
type: "gradle",
|
|
14181
|
+
manifestFile: "build.gradle",
|
|
14182
|
+
installCommand: "gradle build -x test"
|
|
14183
|
+
},
|
|
14184
|
+
// Go
|
|
14185
|
+
{
|
|
14186
|
+
type: "gomod",
|
|
14187
|
+
manifestFile: "go.mod",
|
|
14188
|
+
lockfile: "go.sum",
|
|
14189
|
+
installCommand: "go mod download"
|
|
14190
|
+
},
|
|
14191
|
+
// Dart/Flutter
|
|
14192
|
+
{
|
|
14193
|
+
type: "pub",
|
|
14194
|
+
manifestFile: "pubspec.yaml",
|
|
14195
|
+
lockfile: "pubspec.lock",
|
|
14196
|
+
installCommand: "dart pub get"
|
|
14197
|
+
}
|
|
14198
|
+
];
|
|
14089
14199
|
/**
|
|
14090
14200
|
* Default copilot-setup configuration
|
|
14091
14201
|
*/ const DEFAULT_CONFIG = {
|
|
14092
14202
|
versionFiles: DEFAULT_VERSION_FILES,
|
|
14093
14203
|
setupActions: DEFAULT_SETUP_ACTIONS,
|
|
14094
|
-
setupActionPatterns: DEFAULT_SETUP_ACTION_PATTERNS
|
|
14204
|
+
setupActionPatterns: DEFAULT_SETUP_ACTION_PATTERNS,
|
|
14205
|
+
packageManagers: DEFAULT_PACKAGE_MANAGERS
|
|
14095
14206
|
};
|
|
14096
14207
|
/**
|
|
14097
14208
|
* Loads the copilot-setup configuration using c12
|
|
@@ -14150,6 +14261,7 @@ async function watchConfig(options) {
|
|
|
14150
14261
|
|
|
14151
14262
|
|
|
14152
14263
|
|
|
14264
|
+
|
|
14153
14265
|
/**
|
|
14154
14266
|
* Reads the content of a version file and trims whitespace
|
|
14155
14267
|
*/ async function readVersionFileContent(filePath) {
|
|
@@ -14167,14 +14279,26 @@ async function watchConfig(options) {
|
|
|
14167
14279
|
return this.config;
|
|
14168
14280
|
}
|
|
14169
14281
|
async detectEnvironment(targetDir) {
|
|
14170
|
-
const miseTomlPath = (0,external_node_path_.join)(targetDir, "mise.toml");
|
|
14171
|
-
const hasMise = await fileExists(miseTomlPath);
|
|
14172
14282
|
const config = await this.getConfig();
|
|
14283
|
+
const hasMise = await this.detectMise(targetDir);
|
|
14284
|
+
const versionFiles = await this.detectVersionFiles(targetDir, config);
|
|
14285
|
+
const packageManagers = await this.detectPackageManagers(targetDir, config);
|
|
14286
|
+
return {
|
|
14287
|
+
hasMise,
|
|
14288
|
+
versionFiles,
|
|
14289
|
+
packageManagers
|
|
14290
|
+
};
|
|
14291
|
+
}
|
|
14292
|
+
async detectMise(targetDir) {
|
|
14293
|
+
const miseTomlPath = (0,external_node_path_.join)(targetDir, "mise.toml");
|
|
14294
|
+
return file_system_utils_fileExists(miseTomlPath);
|
|
14295
|
+
}
|
|
14296
|
+
async detectVersionFiles(targetDir, config) {
|
|
14173
14297
|
const filenameToType = getVersionFilenameToTypeMap(config);
|
|
14174
14298
|
const versionFiles = [];
|
|
14175
14299
|
for (const fileConfig of config.versionFiles){
|
|
14176
14300
|
const filePath = (0,external_node_path_.join)(targetDir, fileConfig.filename);
|
|
14177
|
-
if (await
|
|
14301
|
+
if (await file_system_utils_fileExists(filePath)) {
|
|
14178
14302
|
const version = await readVersionFileContent(filePath);
|
|
14179
14303
|
versionFiles.push({
|
|
14180
14304
|
type: filenameToType[fileConfig.filename],
|
|
@@ -14183,10 +14307,109 @@ async function watchConfig(options) {
|
|
|
14183
14307
|
});
|
|
14184
14308
|
}
|
|
14185
14309
|
}
|
|
14186
|
-
return
|
|
14187
|
-
|
|
14188
|
-
|
|
14189
|
-
|
|
14310
|
+
return versionFiles;
|
|
14311
|
+
}
|
|
14312
|
+
async detectPackageManagers(targetDir, config) {
|
|
14313
|
+
const packageManagers = [];
|
|
14314
|
+
// Helper to check if a package manager type is in a list
|
|
14315
|
+
const isPackageManagerType = (pm, types)=>types.includes(pm.type);
|
|
14316
|
+
const nodePackageManagers = config.packageManagers.filter((pm)=>isPackageManagerType(pm, NODE_PACKAGE_MANAGERS));
|
|
14317
|
+
const pythonPackageManagers = config.packageManagers.filter((pm)=>isPackageManagerType(pm, PYTHON_PACKAGE_MANAGERS));
|
|
14318
|
+
const otherPackageManagers = config.packageManagers.filter((pm)=>!isPackageManagerType(pm, NODE_PACKAGE_MANAGERS) && !isPackageManagerType(pm, PYTHON_PACKAGE_MANAGERS));
|
|
14319
|
+
// Detect Node.js package manager (with prioritization)
|
|
14320
|
+
const nodePackageManager = await this.detectNodePackageManager(targetDir, nodePackageManagers);
|
|
14321
|
+
if (nodePackageManager) {
|
|
14322
|
+
packageManagers.push(nodePackageManager);
|
|
14323
|
+
}
|
|
14324
|
+
// Detect Python package manager (with prioritization)
|
|
14325
|
+
const pythonPackageManager = await this.detectPythonPackageManager(targetDir, pythonPackageManagers);
|
|
14326
|
+
if (pythonPackageManager) {
|
|
14327
|
+
packageManagers.push(pythonPackageManager);
|
|
14328
|
+
}
|
|
14329
|
+
// Detect other package managers
|
|
14330
|
+
const otherDetectedManagers = await this.detectOtherPackageManagers(targetDir, otherPackageManagers);
|
|
14331
|
+
packageManagers.push(...otherDetectedManagers);
|
|
14332
|
+
return packageManagers;
|
|
14333
|
+
}
|
|
14334
|
+
async detectNodePackageManager(targetDir, nodePackageManagers) {
|
|
14335
|
+
const packageJsonPath = (0,external_node_path_.join)(targetDir, "package.json");
|
|
14336
|
+
if (!await file_system_utils_fileExists(packageJsonPath)) {
|
|
14337
|
+
return null;
|
|
14338
|
+
}
|
|
14339
|
+
// Priority order for Node.js package managers: npm > yarn > pnpm
|
|
14340
|
+
const lockfileOrder = [
|
|
14341
|
+
"npm",
|
|
14342
|
+
"yarn",
|
|
14343
|
+
"pnpm"
|
|
14344
|
+
];
|
|
14345
|
+
for (const pmType of lockfileOrder){
|
|
14346
|
+
const pmConfig = nodePackageManagers.find((pm)=>pm.type === pmType);
|
|
14347
|
+
if (!pmConfig?.lockfile) {
|
|
14348
|
+
continue;
|
|
14349
|
+
}
|
|
14350
|
+
const lockfilePath = (0,external_node_path_.join)(targetDir, pmConfig.lockfile);
|
|
14351
|
+
if (await file_system_utils_fileExists(lockfilePath)) {
|
|
14352
|
+
return {
|
|
14353
|
+
type: pmConfig.type,
|
|
14354
|
+
filename: pmConfig.manifestFile,
|
|
14355
|
+
lockfile: pmConfig.lockfile
|
|
14356
|
+
};
|
|
14357
|
+
}
|
|
14358
|
+
}
|
|
14359
|
+
// Default to npm if no lockfile found
|
|
14360
|
+
const npmConfig = nodePackageManagers.find((pm)=>pm.type === "npm");
|
|
14361
|
+
if (npmConfig) {
|
|
14362
|
+
return {
|
|
14363
|
+
type: npmConfig.type,
|
|
14364
|
+
filename: npmConfig.manifestFile,
|
|
14365
|
+
lockfile: undefined
|
|
14366
|
+
};
|
|
14367
|
+
}
|
|
14368
|
+
return null;
|
|
14369
|
+
}
|
|
14370
|
+
async detectPythonPackageManager(targetDir, pythonPackageManagers) {
|
|
14371
|
+
// Priority order for Python package managers: poetry > pipenv > pip
|
|
14372
|
+
for (const pmType of PYTHON_PACKAGE_MANAGERS){
|
|
14373
|
+
const pmConfig = pythonPackageManagers.find((pm)=>pm.type === pmType);
|
|
14374
|
+
if (!pmConfig) {
|
|
14375
|
+
continue;
|
|
14376
|
+
}
|
|
14377
|
+
const manifestPath = (0,external_node_path_.join)(targetDir, pmConfig.manifestFile);
|
|
14378
|
+
if (await file_system_utils_fileExists(manifestPath)) {
|
|
14379
|
+
const lockfilePath = pmConfig.lockfile ? (0,external_node_path_.join)(targetDir, pmConfig.lockfile) : undefined;
|
|
14380
|
+
const hasLockfile = lockfilePath ? await file_system_utils_fileExists(lockfilePath) : false;
|
|
14381
|
+
// Skip if lockfile is required but not present
|
|
14382
|
+
if (pmConfig.requiresLockfile && !hasLockfile) {
|
|
14383
|
+
continue;
|
|
14384
|
+
}
|
|
14385
|
+
return {
|
|
14386
|
+
type: pmConfig.type,
|
|
14387
|
+
filename: pmConfig.manifestFile,
|
|
14388
|
+
lockfile: hasLockfile ? pmConfig.lockfile : undefined
|
|
14389
|
+
};
|
|
14390
|
+
}
|
|
14391
|
+
}
|
|
14392
|
+
return null;
|
|
14393
|
+
}
|
|
14394
|
+
async detectOtherPackageManagers(targetDir, otherPackageManagers) {
|
|
14395
|
+
const packageManagers = [];
|
|
14396
|
+
for (const pmConfig of otherPackageManagers){
|
|
14397
|
+
const manifestPath = (0,external_node_path_.join)(targetDir, pmConfig.manifestFile);
|
|
14398
|
+
if (await file_system_utils_fileExists(manifestPath)) {
|
|
14399
|
+
const lockfilePath = pmConfig.lockfile ? (0,external_node_path_.join)(targetDir, pmConfig.lockfile) : undefined;
|
|
14400
|
+
const hasLockfile = lockfilePath ? await file_system_utils_fileExists(lockfilePath) : false;
|
|
14401
|
+
// Skip if lockfile is required but not present
|
|
14402
|
+
if (pmConfig.requiresLockfile && !hasLockfile) {
|
|
14403
|
+
continue;
|
|
14404
|
+
}
|
|
14405
|
+
packageManagers.push({
|
|
14406
|
+
type: pmConfig.type,
|
|
14407
|
+
filename: pmConfig.manifestFile,
|
|
14408
|
+
lockfile: hasLockfile ? pmConfig.lockfile : undefined
|
|
14409
|
+
});
|
|
14410
|
+
}
|
|
14411
|
+
}
|
|
14412
|
+
return packageManagers;
|
|
14190
14413
|
}
|
|
14191
14414
|
}
|
|
14192
14415
|
/**
|
|
@@ -14195,6 +14418,174 @@ async function watchConfig(options) {
|
|
|
14195
14418
|
return new FileSystemEnvironmentGateway();
|
|
14196
14419
|
}
|
|
14197
14420
|
|
|
14421
|
+
;// CONCATENATED MODULE: ./src/gateways/instruction-analysis-gateway.ts
|
|
14422
|
+
/**
|
|
14423
|
+
* Gateway for analyzing repository instructions for feedback loop coverage
|
|
14424
|
+
*/
|
|
14425
|
+
|
|
14426
|
+
|
|
14427
|
+
/**
|
|
14428
|
+
* File system implementation of instruction analysis gateway
|
|
14429
|
+
*/ class FileSystemInstructionAnalysisGateway {
|
|
14430
|
+
async analyzeCoverage(targetDir, scripts, tools) {
|
|
14431
|
+
// Find all instruction files
|
|
14432
|
+
const instructionFiles = await this.findInstructionFiles(targetDir);
|
|
14433
|
+
// Read and search instruction content
|
|
14434
|
+
const references = [];
|
|
14435
|
+
const documentedTargets = new Set();
|
|
14436
|
+
for (const file of instructionFiles){
|
|
14437
|
+
const content = await readFile(file, "utf-8");
|
|
14438
|
+
const lines = content.split("\n");
|
|
14439
|
+
// Check for script references (e.g., "npm test", "npm run build")
|
|
14440
|
+
for (const script of scripts){
|
|
14441
|
+
const scriptRefs = this.findReferencesInContent(script.name, content, lines, file, targetDir);
|
|
14442
|
+
if (scriptRefs.length > 0) {
|
|
14443
|
+
references.push(...scriptRefs);
|
|
14444
|
+
documentedTargets.add(script.name);
|
|
14445
|
+
}
|
|
14446
|
+
}
|
|
14447
|
+
// Check for tool references (e.g., "mise run test", "biome check")
|
|
14448
|
+
for (const tool of tools){
|
|
14449
|
+
const toolRefs = this.findReferencesInContent(tool.name, content, lines, file, targetDir);
|
|
14450
|
+
if (toolRefs.length > 0) {
|
|
14451
|
+
references.push(...toolRefs);
|
|
14452
|
+
documentedTargets.add(tool.name);
|
|
14453
|
+
}
|
|
14454
|
+
}
|
|
14455
|
+
}
|
|
14456
|
+
// Filter mandatory scripts/tools
|
|
14457
|
+
const mandatoryScripts = scripts.filter((s)=>s.isMandatory);
|
|
14458
|
+
const mandatoryTools = tools.filter((t)=>t.isMandatory);
|
|
14459
|
+
const allMandatory = [
|
|
14460
|
+
...mandatoryScripts,
|
|
14461
|
+
...mandatoryTools
|
|
14462
|
+
];
|
|
14463
|
+
// Categorize as missing or documented
|
|
14464
|
+
const missingInInstructions = allMandatory.filter((item)=>!documentedTargets.has(item.name));
|
|
14465
|
+
const documentedInInstructions = allMandatory.filter((item)=>documentedTargets.has(item.name));
|
|
14466
|
+
const totalMandatory = allMandatory.length;
|
|
14467
|
+
const totalDocumented = documentedInInstructions.length;
|
|
14468
|
+
const coveragePercentage = totalMandatory === 0 ? 100 : totalDocumented / totalMandatory * 100;
|
|
14469
|
+
return {
|
|
14470
|
+
missingInInstructions,
|
|
14471
|
+
documentedInInstructions,
|
|
14472
|
+
references,
|
|
14473
|
+
summary: {
|
|
14474
|
+
totalMandatory,
|
|
14475
|
+
totalDocumented,
|
|
14476
|
+
coveragePercentage: Math.round(coveragePercentage * 100) / 100
|
|
14477
|
+
}
|
|
14478
|
+
};
|
|
14479
|
+
}
|
|
14480
|
+
async findInstructionFiles(targetDir) {
|
|
14481
|
+
const files = [];
|
|
14482
|
+
// Check for .github/copilot-instructions.md
|
|
14483
|
+
const copilotInstructions = join(targetDir, ".github", "copilot-instructions.md");
|
|
14484
|
+
if (await fileExists(copilotInstructions)) {
|
|
14485
|
+
files.push(copilotInstructions);
|
|
14486
|
+
}
|
|
14487
|
+
// Check for .github/instructions/*.md
|
|
14488
|
+
const instructionsDir = join(targetDir, ".github", "instructions");
|
|
14489
|
+
if (await fileExists(instructionsDir)) {
|
|
14490
|
+
try {
|
|
14491
|
+
const instructionFiles = await readdir(instructionsDir);
|
|
14492
|
+
for (const file of instructionFiles){
|
|
14493
|
+
if (file.endsWith(".md")) {
|
|
14494
|
+
files.push(join(instructionsDir, file));
|
|
14495
|
+
}
|
|
14496
|
+
}
|
|
14497
|
+
} catch {
|
|
14498
|
+
// Skip directory if we can't read it (e.g., permissions issues)
|
|
14499
|
+
// Similar to how workflow parsing errors are handled
|
|
14500
|
+
}
|
|
14501
|
+
}
|
|
14502
|
+
return files;
|
|
14503
|
+
}
|
|
14504
|
+
findReferencesInContent(target, content, lines, file, targetDir) {
|
|
14505
|
+
const references = [];
|
|
14506
|
+
// Build a case-insensitive, word-boundary-aware pattern for the target.
|
|
14507
|
+
// This reduces false positives from simple substring matches like
|
|
14508
|
+
// "test" in "testing" or "latest", while still matching common
|
|
14509
|
+
// separators such as spaces, punctuation, etc.
|
|
14510
|
+
const escapedTarget = target.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14511
|
+
const targetPattern = new RegExp(`(?:^|[^\\w])(${escapedTarget})(?=$|[^\\w])`, "i");
|
|
14512
|
+
// Fast path: skip line-by-line processing if the target pattern
|
|
14513
|
+
// never appears in the full content.
|
|
14514
|
+
if (!targetPattern.test(content)) {
|
|
14515
|
+
return references;
|
|
14516
|
+
}
|
|
14517
|
+
// Find line numbers where target appears
|
|
14518
|
+
for(let i = 0; i < lines.length; i++){
|
|
14519
|
+
const line = lines[i];
|
|
14520
|
+
if (targetPattern.test(line)) {
|
|
14521
|
+
// Get context (line before and after if available)
|
|
14522
|
+
const contextLines = [];
|
|
14523
|
+
if (i > 0) contextLines.push(lines[i - 1]);
|
|
14524
|
+
contextLines.push(line);
|
|
14525
|
+
if (i < lines.length - 1) contextLines.push(lines[i + 1]);
|
|
14526
|
+
const relativePath = relative(targetDir, file);
|
|
14527
|
+
references.push({
|
|
14528
|
+
target,
|
|
14529
|
+
file: relativePath,
|
|
14530
|
+
line: i + 1,
|
|
14531
|
+
context: contextLines.join("\n")
|
|
14532
|
+
});
|
|
14533
|
+
}
|
|
14534
|
+
}
|
|
14535
|
+
return references;
|
|
14536
|
+
}
|
|
14537
|
+
}
|
|
14538
|
+
/**
|
|
14539
|
+
* Creates and returns the default instruction analysis gateway
|
|
14540
|
+
*/ function createInstructionAnalysisGateway() {
|
|
14541
|
+
return new FileSystemInstructionAnalysisGateway();
|
|
14542
|
+
}
|
|
14543
|
+
|
|
14544
|
+
;// CONCATENATED MODULE: ./src/gateways/script-discovery-gateway.ts
|
|
14545
|
+
/**
|
|
14546
|
+
* Gateway for discovering scripts from package.json manifests
|
|
14547
|
+
*/
|
|
14548
|
+
|
|
14549
|
+
|
|
14550
|
+
|
|
14551
|
+
/**
|
|
14552
|
+
* File system implementation of script discovery gateway
|
|
14553
|
+
*/ class FileSystemScriptDiscoveryGateway {
|
|
14554
|
+
async discoverScripts(targetDir) {
|
|
14555
|
+
const packageJsonPath = join(targetDir, "package.json");
|
|
14556
|
+
if (!await fileExists(packageJsonPath)) {
|
|
14557
|
+
return [];
|
|
14558
|
+
}
|
|
14559
|
+
try {
|
|
14560
|
+
const content = await readFile(packageJsonPath, "utf-8");
|
|
14561
|
+
const packageJson = JSON.parse(content);
|
|
14562
|
+
if (!packageJson.scripts) {
|
|
14563
|
+
return [];
|
|
14564
|
+
}
|
|
14565
|
+
const scripts = [];
|
|
14566
|
+
for (const [name, command] of Object.entries(packageJson.scripts)){
|
|
14567
|
+
const phase = determineScriptPhase(name, command);
|
|
14568
|
+
const isMandatory = isScriptMandatory(phase);
|
|
14569
|
+
scripts.push({
|
|
14570
|
+
name,
|
|
14571
|
+
command,
|
|
14572
|
+
phase,
|
|
14573
|
+
isMandatory
|
|
14574
|
+
});
|
|
14575
|
+
}
|
|
14576
|
+
return scripts;
|
|
14577
|
+
} catch {
|
|
14578
|
+
// If package.json is malformed or cannot be parsed, return empty array
|
|
14579
|
+
return [];
|
|
14580
|
+
}
|
|
14581
|
+
}
|
|
14582
|
+
}
|
|
14583
|
+
/**
|
|
14584
|
+
* Creates and returns the default script discovery gateway
|
|
14585
|
+
*/ function createScriptDiscoveryGateway() {
|
|
14586
|
+
return new FileSystemScriptDiscoveryGateway();
|
|
14587
|
+
}
|
|
14588
|
+
|
|
14198
14589
|
;// CONCATENATED MODULE: ./src/gateways/skill-file-gateway.ts
|
|
14199
14590
|
/**
|
|
14200
14591
|
* Gateway for skill file system operations.
|
|
@@ -14213,7 +14604,7 @@ async function watchConfig(options) {
|
|
|
14213
14604
|
}
|
|
14214
14605
|
async skillDirectoryExists(targetDir, skillName) {
|
|
14215
14606
|
const dirPath = this.getSkillDirectoryPath(targetDir, skillName);
|
|
14216
|
-
return
|
|
14607
|
+
return file_system_utils_fileExists(dirPath);
|
|
14217
14608
|
}
|
|
14218
14609
|
async ensureSkillDirectory(targetDir, skillName) {
|
|
14219
14610
|
const skillDir = this.getSkillDirectoryPath(targetDir, skillName);
|
|
@@ -14236,6 +14627,160 @@ async function watchConfig(options) {
|
|
|
14236
14627
|
|
|
14237
14628
|
// EXTERNAL MODULE: ./node_modules/yaml/dist/index.js
|
|
14238
14629
|
var dist = __webpack_require__(1198);
|
|
14630
|
+
;// CONCATENATED MODULE: ./src/gateways/tool-discovery-gateway.ts
|
|
14631
|
+
/**
|
|
14632
|
+
* Gateway for discovering CLI tools and commands from GitHub Actions workflows
|
|
14633
|
+
*/
|
|
14634
|
+
|
|
14635
|
+
|
|
14636
|
+
|
|
14637
|
+
|
|
14638
|
+
/**
|
|
14639
|
+
* File system implementation of tool discovery gateway
|
|
14640
|
+
*/ class FileSystemToolDiscoveryGateway {
|
|
14641
|
+
async discoverTools(targetDir) {
|
|
14642
|
+
const workflowsDir = join(targetDir, ".github", "workflows");
|
|
14643
|
+
if (!await fileExists(workflowsDir)) {
|
|
14644
|
+
return [];
|
|
14645
|
+
}
|
|
14646
|
+
const files = await readdir(workflowsDir);
|
|
14647
|
+
const yamlFiles = files.filter((f)=>f.endsWith(".yml") || f.endsWith(".yaml"));
|
|
14648
|
+
const allTools = [];
|
|
14649
|
+
for (const file of yamlFiles){
|
|
14650
|
+
const filePath = join(workflowsDir, file);
|
|
14651
|
+
try {
|
|
14652
|
+
const content = await readFile(filePath, "utf-8");
|
|
14653
|
+
const workflow = parseYaml(content);
|
|
14654
|
+
const tools = this.extractToolsFromWorkflow(workflow, file);
|
|
14655
|
+
allTools.push(...tools);
|
|
14656
|
+
} catch {
|
|
14657
|
+
// Skip files that can't be parsed as valid YAML
|
|
14658
|
+
}
|
|
14659
|
+
}
|
|
14660
|
+
return this.deduplicateTools(allTools);
|
|
14661
|
+
}
|
|
14662
|
+
extractToolsFromWorkflow(workflow, sourceFile) {
|
|
14663
|
+
const tools = [];
|
|
14664
|
+
if (!workflow || typeof workflow !== "object") {
|
|
14665
|
+
return tools;
|
|
14666
|
+
}
|
|
14667
|
+
const jobs = workflow.jobs;
|
|
14668
|
+
if (!jobs || typeof jobs !== "object") {
|
|
14669
|
+
return tools;
|
|
14670
|
+
}
|
|
14671
|
+
for (const job of Object.values(jobs)){
|
|
14672
|
+
if (!job || typeof job !== "object") {
|
|
14673
|
+
continue;
|
|
14674
|
+
}
|
|
14675
|
+
const steps = job.steps;
|
|
14676
|
+
if (!Array.isArray(steps)) {
|
|
14677
|
+
continue;
|
|
14678
|
+
}
|
|
14679
|
+
for (const step of steps){
|
|
14680
|
+
if (!step || typeof step !== "object") {
|
|
14681
|
+
continue;
|
|
14682
|
+
}
|
|
14683
|
+
const stepObj = step;
|
|
14684
|
+
const run = stepObj.run;
|
|
14685
|
+
if (typeof run === "string") {
|
|
14686
|
+
// Extract tools from run commands
|
|
14687
|
+
const extractedTools = this.extractToolsFromRunCommand(run, sourceFile);
|
|
14688
|
+
tools.push(...extractedTools);
|
|
14689
|
+
}
|
|
14690
|
+
}
|
|
14691
|
+
}
|
|
14692
|
+
return tools;
|
|
14693
|
+
}
|
|
14694
|
+
extractToolsFromRunCommand(runCommand, sourceFile) {
|
|
14695
|
+
const tools = [];
|
|
14696
|
+
// Split by newlines and pipe tokens with surrounding whitespace to handle
|
|
14697
|
+
// multi-line and piped commands without breaking on constructs like "cmd || true"
|
|
14698
|
+
const commands = runCommand.split(/\n|\s\|\s/).map((c)=>c.trim()).filter((c)=>c.length > 0 && !c.startsWith("#"));
|
|
14699
|
+
for (const command of commands){
|
|
14700
|
+
// Extract the base command (first word)
|
|
14701
|
+
const parts = command.split(/\s+/);
|
|
14702
|
+
const baseCommand = parts[0];
|
|
14703
|
+
// Skip shell built-ins and common utilities
|
|
14704
|
+
if (this.isShellBuiltin(baseCommand)) {
|
|
14705
|
+
continue;
|
|
14706
|
+
}
|
|
14707
|
+
// Determine tool name and full command
|
|
14708
|
+
let toolName;
|
|
14709
|
+
const fullCommand = command;
|
|
14710
|
+
// Handle special cases like "npm run", "mise run", etc.
|
|
14711
|
+
if (parts.length >= 2 && (baseCommand === "npm" || baseCommand === "mise") && parts[1] === "run") {
|
|
14712
|
+
if (parts.length >= 3 && parts[2]) {
|
|
14713
|
+
// "npm run test" -> name: "npm run test"
|
|
14714
|
+
toolName = parts.slice(0, 3).join(" ");
|
|
14715
|
+
} else {
|
|
14716
|
+
// Handle commands like "npm run" without a script name
|
|
14717
|
+
toolName = parts.slice(0, 2).join(" ");
|
|
14718
|
+
}
|
|
14719
|
+
} else if (parts.length >= 2) {
|
|
14720
|
+
// For most tools, include the subcommand for better specificity
|
|
14721
|
+
// e.g., "npm test", "npx biome", "pnpm lint"
|
|
14722
|
+
toolName = parts.slice(0, 2).join(" ");
|
|
14723
|
+
} else {
|
|
14724
|
+
// Fallback to the base command if no subcommand is present
|
|
14725
|
+
toolName = baseCommand;
|
|
14726
|
+
}
|
|
14727
|
+
const phase = this.determineToolPhase(toolName, fullCommand);
|
|
14728
|
+
const isMandatory = isScriptMandatory(phase);
|
|
14729
|
+
tools.push({
|
|
14730
|
+
name: toolName,
|
|
14731
|
+
fullCommand,
|
|
14732
|
+
phase,
|
|
14733
|
+
isMandatory,
|
|
14734
|
+
sourceWorkflow: sourceFile
|
|
14735
|
+
});
|
|
14736
|
+
}
|
|
14737
|
+
return tools;
|
|
14738
|
+
}
|
|
14739
|
+
isShellBuiltin(command) {
|
|
14740
|
+
const builtins = [
|
|
14741
|
+
"cd",
|
|
14742
|
+
"echo",
|
|
14743
|
+
"mkdir",
|
|
14744
|
+
"rm",
|
|
14745
|
+
"cp",
|
|
14746
|
+
"mv",
|
|
14747
|
+
"test",
|
|
14748
|
+
"[",
|
|
14749
|
+
"if",
|
|
14750
|
+
"then",
|
|
14751
|
+
"else",
|
|
14752
|
+
"fi",
|
|
14753
|
+
"for",
|
|
14754
|
+
"while",
|
|
14755
|
+
"do",
|
|
14756
|
+
"done",
|
|
14757
|
+
"case",
|
|
14758
|
+
"esac"
|
|
14759
|
+
];
|
|
14760
|
+
return builtins.includes(command);
|
|
14761
|
+
}
|
|
14762
|
+
determineToolPhase(toolName, fullCommand) {
|
|
14763
|
+
// Use the same logic as script phase determination
|
|
14764
|
+
return determineScriptPhase(toolName, fullCommand);
|
|
14765
|
+
}
|
|
14766
|
+
deduplicateTools(tools) {
|
|
14767
|
+
const seen = new Map();
|
|
14768
|
+
for (const tool of tools){
|
|
14769
|
+
// Use full command as key for deduplication
|
|
14770
|
+
const key = tool.fullCommand;
|
|
14771
|
+
if (!seen.has(key)) {
|
|
14772
|
+
seen.set(key, tool);
|
|
14773
|
+
}
|
|
14774
|
+
}
|
|
14775
|
+
return Array.from(seen.values());
|
|
14776
|
+
}
|
|
14777
|
+
}
|
|
14778
|
+
/**
|
|
14779
|
+
* Creates and returns the default tool discovery gateway
|
|
14780
|
+
*/ function createToolDiscoveryGateway() {
|
|
14781
|
+
return new FileSystemToolDiscoveryGateway();
|
|
14782
|
+
}
|
|
14783
|
+
|
|
14239
14784
|
;// CONCATENATED MODULE: ./src/use-cases/setup-step-discovery.ts
|
|
14240
14785
|
/**
|
|
14241
14786
|
* Use case for discovering setup steps in workflows.
|
|
@@ -14459,7 +15004,7 @@ var dist = __webpack_require__(1198);
|
|
|
14459
15004
|
const workflowsDir = (0,external_node_path_.join)(targetDir, ".github", "workflows");
|
|
14460
15005
|
for (const filename of COPILOT_SETUP_WORKFLOW_FILENAMES){
|
|
14461
15006
|
const workflowPath = (0,external_node_path_.join)(workflowsDir, filename);
|
|
14462
|
-
if (await
|
|
15007
|
+
if (await file_system_utils_fileExists(workflowPath)) {
|
|
14463
15008
|
return workflowPath;
|
|
14464
15009
|
}
|
|
14465
15010
|
}
|
|
@@ -14467,7 +15012,7 @@ var dist = __webpack_require__(1198);
|
|
|
14467
15012
|
}
|
|
14468
15013
|
async parseWorkflowsForSetupActions(targetDir) {
|
|
14469
15014
|
const workflowsDir = (0,external_node_path_.join)(targetDir, ".github", "workflows");
|
|
14470
|
-
if (!await
|
|
15015
|
+
if (!await file_system_utils_fileExists(workflowsDir)) {
|
|
14471
15016
|
return [];
|
|
14472
15017
|
}
|
|
14473
15018
|
const files = await (0,promises_.readdir)(workflowsDir);
|
|
@@ -14534,11 +15079,14 @@ var dist = __webpack_require__(1198);
|
|
|
14534
15079
|
|
|
14535
15080
|
|
|
14536
15081
|
|
|
15082
|
+
|
|
15083
|
+
|
|
15084
|
+
|
|
14537
15085
|
;// CONCATENATED MODULE: ./src/use-cases/candidate-builder.ts
|
|
14538
15086
|
/**
|
|
14539
15087
|
* Use case for building setup step candidates from environment detection.
|
|
14540
15088
|
* This module handles the logic of determining which GitHub Actions
|
|
14541
|
-
* setup steps should be added based on detected version files.
|
|
15089
|
+
* setup steps should be added based on detected version files and package managers.
|
|
14542
15090
|
*/
|
|
14543
15091
|
|
|
14544
15092
|
/**
|
|
@@ -14563,7 +15111,12 @@ var dist = __webpack_require__(1198);
|
|
|
14563
15111
|
return candidates;
|
|
14564
15112
|
}
|
|
14565
15113
|
// Otherwise, add individual setup actions for each version file
|
|
14566
|
-
|
|
15114
|
+
const setupCandidates = await buildCandidatesFromVersionFiles(environment.versionFiles, versionTypeToAction, versionFileConfigKeys, versionGateway);
|
|
15115
|
+
candidates.push(...setupCandidates);
|
|
15116
|
+
// Add install steps for detected package managers
|
|
15117
|
+
const installCandidates = buildInstallCandidatesFromPackageManagers(environment.packageManagers, loadedConfig);
|
|
15118
|
+
candidates.push(...installCandidates);
|
|
15119
|
+
return candidates;
|
|
14567
15120
|
}
|
|
14568
15121
|
/**
|
|
14569
15122
|
* Builds setup step candidates from individual version files
|
|
@@ -14598,6 +15151,59 @@ var dist = __webpack_require__(1198);
|
|
|
14598
15151
|
}
|
|
14599
15152
|
return candidates;
|
|
14600
15153
|
}
|
|
15154
|
+
/**
|
|
15155
|
+
* Builds install step candidates from detected package managers
|
|
15156
|
+
* @param packageManagers Array of detected package managers
|
|
15157
|
+
* @param config Configuration for package manager mappings
|
|
15158
|
+
* @returns Array of install step candidates
|
|
15159
|
+
*/ function buildInstallCandidatesFromPackageManagers(packageManagers, config) {
|
|
15160
|
+
const candidates = [];
|
|
15161
|
+
const addedTypes = new Set();
|
|
15162
|
+
for (const pm of packageManagers){
|
|
15163
|
+
// Skip if we've already added this package manager type
|
|
15164
|
+
if (addedTypes.has(pm.type)) {
|
|
15165
|
+
continue;
|
|
15166
|
+
}
|
|
15167
|
+
addedTypes.add(pm.type);
|
|
15168
|
+
// Find the config for this package manager
|
|
15169
|
+
const pmConfig = config.packageManagers.find((c)=>c.type === pm.type);
|
|
15170
|
+
if (!pmConfig) {
|
|
15171
|
+
continue;
|
|
15172
|
+
}
|
|
15173
|
+
// Determine a descriptive name for the install step
|
|
15174
|
+
const stepName = getInstallStepName(pm.type);
|
|
15175
|
+
// Create install step candidate
|
|
15176
|
+
// Note: Empty action string indicates this is a run step (uses 'run' field instead of 'uses')
|
|
15177
|
+
// This is checked in workflow-generator.ts buildStepFromCandidate()
|
|
15178
|
+
candidates.push({
|
|
15179
|
+
action: "",
|
|
15180
|
+
source: "version-file",
|
|
15181
|
+
name: stepName,
|
|
15182
|
+
run: pmConfig.installCommand
|
|
15183
|
+
});
|
|
15184
|
+
}
|
|
15185
|
+
return candidates;
|
|
15186
|
+
}
|
|
15187
|
+
/**
|
|
15188
|
+
* Gets a descriptive name for an install step based on package manager type
|
|
15189
|
+
*/ function getInstallStepName(packageManagerType) {
|
|
15190
|
+
const names = {
|
|
15191
|
+
npm: "Install Node.js dependencies",
|
|
15192
|
+
yarn: "Install Node.js dependencies",
|
|
15193
|
+
pnpm: "Install Node.js dependencies",
|
|
15194
|
+
pip: "Install Python dependencies",
|
|
15195
|
+
pipenv: "Install Python dependencies",
|
|
15196
|
+
poetry: "Install Python dependencies",
|
|
15197
|
+
bundler: "Install Ruby dependencies",
|
|
15198
|
+
cargo: "Build Rust project",
|
|
15199
|
+
composer: "Install PHP dependencies",
|
|
15200
|
+
maven: "Install Java dependencies",
|
|
15201
|
+
gradle: "Build Gradle project",
|
|
15202
|
+
gomod: "Download Go dependencies",
|
|
15203
|
+
pub: "Install Dart dependencies"
|
|
15204
|
+
};
|
|
15205
|
+
return names[packageManagerType] || "Install dependencies";
|
|
15206
|
+
}
|
|
14601
15207
|
|
|
14602
15208
|
;// CONCATENATED MODULE: ./node_modules/@github-actions-workflow-ts/lib/dist/esm/workflow/index.js
|
|
14603
15209
|
/**
|
|
@@ -15146,11 +15752,22 @@ Example resolved format: actions/setup-node@1a2b3c4d5e6f # v4.0.0`;
|
|
|
15146
15752
|
* @param options Optional conversion options for placeholders and resolved versions
|
|
15147
15753
|
* @returns A typed Step object
|
|
15148
15754
|
*/ function buildStepFromCandidate(candidate, options) {
|
|
15755
|
+
// Handle run steps (install commands)
|
|
15756
|
+
// Run steps have a 'run' field and no action (or empty action string)
|
|
15757
|
+
if (candidate.run && !candidate.action) {
|
|
15758
|
+
const stepProps = {
|
|
15759
|
+
name: candidate.name || "Run command",
|
|
15760
|
+
run: candidate.run
|
|
15761
|
+
};
|
|
15762
|
+
// Type assertion is safe here - Step constructor accepts both 'uses' and 'run' at runtime
|
|
15763
|
+
return new Step(stepProps);
|
|
15764
|
+
}
|
|
15765
|
+
// Handle action steps (uses)
|
|
15149
15766
|
const version = getVersionForAction(candidate.action, candidate.version, options);
|
|
15150
15767
|
const usesValue = buildUsesValue(candidate.action, version, options);
|
|
15151
15768
|
const withConfig = candidate.config && Object.keys(candidate.config).length > 0 ? candidate.config : undefined;
|
|
15152
15769
|
const stepProps = {
|
|
15153
|
-
name: generateStepName(candidate.action),
|
|
15770
|
+
name: candidate.name || generateStepName(candidate.action),
|
|
15154
15771
|
uses: usesValue,
|
|
15155
15772
|
with: withConfig
|
|
15156
15773
|
};
|
|
@@ -15327,7 +15944,7 @@ const copilotSetupArgs = {};
|
|
|
15327
15944
|
}
|
|
15328
15945
|
// Step 2: Parse existing workflows for setup actions
|
|
15329
15946
|
const workflowsDir = (0,external_node_path_.join)(targetDir, ".github", "workflows");
|
|
15330
|
-
const workflowsDirExists = await
|
|
15947
|
+
const workflowsDirExists = await file_system_utils_fileExists(workflowsDir);
|
|
15331
15948
|
const workflowCandidates = workflowsDirExists ? await workflowGateway.parseWorkflowsForSetupActions(targetDir) : [];
|
|
15332
15949
|
if (workflowCandidates.length > 0) {
|
|
15333
15950
|
const actionNames = workflowCandidates.map((c)=>c.action).join(", ");
|
|
@@ -30219,7 +30836,7 @@ var Eta = class extends Eta$1 {
|
|
|
30219
30836
|
for (const node of structure.nodes){
|
|
30220
30837
|
const fullPath = (0,external_node_path_.join)(targetDir, node.path);
|
|
30221
30838
|
// Skip if already exists to preserve existing files/directories
|
|
30222
|
-
if (await
|
|
30839
|
+
if (await file_system_utils_fileExists(fullPath)) {
|
|
30223
30840
|
consola.debug(`Skipping existing: ${fullPath}`);
|
|
30224
30841
|
continue;
|
|
30225
30842
|
}
|