kairn-cli 2.15.0 → 2.16.1
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/dist/cli.js +145 -30
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3892,14 +3892,56 @@ function detectFramework(deps) {
|
|
|
3892
3892
|
}
|
|
3893
3893
|
return detected.length > 0 ? detected.join(" + ") : null;
|
|
3894
3894
|
}
|
|
3895
|
-
function
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
return
|
|
3895
|
+
function detectLanguagesFromFiles(files) {
|
|
3896
|
+
const matched = [];
|
|
3897
|
+
for (const signal of LANGUAGE_SIGNALS) {
|
|
3898
|
+
if (files.some((f) => signal.files.includes(f))) {
|
|
3899
|
+
matched.push(signal.language);
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3902
|
+
return matched;
|
|
3903
|
+
}
|
|
3904
|
+
async function detectLanguageLocations(dir, keyFiles) {
|
|
3905
|
+
const rootHits = detectLanguagesFromFiles(keyFiles);
|
|
3906
|
+
if (rootHits.length > 0) {
|
|
3907
|
+
return rootHits.map((language) => ({ language, subdirs: [] }));
|
|
3908
|
+
}
|
|
3909
|
+
const entries = await listDirSafe(dir);
|
|
3910
|
+
const langSubdirs = /* @__PURE__ */ new Map();
|
|
3911
|
+
const counts = /* @__PURE__ */ new Map();
|
|
3912
|
+
for (const entry of entries) {
|
|
3913
|
+
const subPath = path10.join(dir, entry);
|
|
3914
|
+
try {
|
|
3915
|
+
const stat = await fs10.stat(subPath);
|
|
3916
|
+
if (!stat.isDirectory()) continue;
|
|
3917
|
+
} catch {
|
|
3918
|
+
continue;
|
|
3919
|
+
}
|
|
3920
|
+
const subFiles = await listDirSafe(subPath);
|
|
3921
|
+
const subLangs = detectLanguagesFromFiles(subFiles);
|
|
3922
|
+
for (const lang of subLangs) {
|
|
3923
|
+
counts.set(lang, (counts.get(lang) ?? 0) + 1);
|
|
3924
|
+
const existing = langSubdirs.get(lang);
|
|
3925
|
+
if (existing) {
|
|
3926
|
+
existing.push(entry);
|
|
3927
|
+
} else {
|
|
3928
|
+
langSubdirs.set(lang, [entry]);
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
if (counts.size === 0) return [];
|
|
3933
|
+
const precedence = /* @__PURE__ */ new Map();
|
|
3934
|
+
for (let i = 0; i < LANGUAGE_SIGNALS.length; i++) {
|
|
3935
|
+
precedence.set(LANGUAGE_SIGNALS[i].language, i);
|
|
3936
|
+
}
|
|
3937
|
+
return [...counts.entries()].sort((a, b) => {
|
|
3938
|
+
const freqDiff = b[1] - a[1];
|
|
3939
|
+
if (freqDiff !== 0) return freqDiff;
|
|
3940
|
+
return (precedence.get(a[0]) ?? 999) - (precedence.get(b[0]) ?? 999);
|
|
3941
|
+
}).map(([lang]) => ({
|
|
3942
|
+
language: lang,
|
|
3943
|
+
subdirs: langSubdirs.get(lang) ?? []
|
|
3944
|
+
}));
|
|
3903
3945
|
}
|
|
3904
3946
|
function extractEnvKeys(content) {
|
|
3905
3947
|
const keys = [];
|
|
@@ -3934,7 +3976,9 @@ async function scanProject(dir) {
|
|
|
3934
3976
|
"CLAUDE.md"
|
|
3935
3977
|
].includes(f)
|
|
3936
3978
|
);
|
|
3937
|
-
const
|
|
3979
|
+
const languageLocations = await detectLanguageLocations(dir, keyFiles);
|
|
3980
|
+
const detectedLanguages = languageLocations.map((d) => d.language);
|
|
3981
|
+
const language = detectedLanguages[0] ?? null;
|
|
3938
3982
|
const framework = detectFramework(allDeps);
|
|
3939
3983
|
const typescript = keyFiles.includes("tsconfig.json") || allDeps.includes("typescript");
|
|
3940
3984
|
const testCommand = scripts.test && scripts.test !== 'echo "Error: no test specified" && exit 1' ? scripts.test : null;
|
|
@@ -3983,6 +4027,8 @@ async function scanProject(dir) {
|
|
|
3983
4027
|
description,
|
|
3984
4028
|
directory: dir,
|
|
3985
4029
|
language,
|
|
4030
|
+
languages: detectedLanguages,
|
|
4031
|
+
languageLocations,
|
|
3986
4032
|
framework,
|
|
3987
4033
|
typescript,
|
|
3988
4034
|
dependencies: deps,
|
|
@@ -4010,9 +4056,18 @@ async function scanProject(dir) {
|
|
|
4010
4056
|
keyFiles
|
|
4011
4057
|
};
|
|
4012
4058
|
}
|
|
4059
|
+
var LANGUAGE_SIGNALS;
|
|
4013
4060
|
var init_scan = __esm({
|
|
4014
4061
|
"src/scanner/scan.ts"() {
|
|
4015
4062
|
"use strict";
|
|
4063
|
+
LANGUAGE_SIGNALS = [
|
|
4064
|
+
{ files: ["tsconfig.json"], language: "TypeScript" },
|
|
4065
|
+
{ files: ["package.json"], language: "JavaScript" },
|
|
4066
|
+
{ files: ["pyproject.toml", "setup.py", "requirements.txt"], language: "Python" },
|
|
4067
|
+
{ files: ["Cargo.toml"], language: "Rust" },
|
|
4068
|
+
{ files: ["go.mod"], language: "Go" },
|
|
4069
|
+
{ files: ["Gemfile"], language: "Ruby" }
|
|
4070
|
+
];
|
|
4016
4071
|
}
|
|
4017
4072
|
});
|
|
4018
4073
|
|
|
@@ -4040,6 +4095,7 @@ function getStrategy(language) {
|
|
|
4040
4095
|
return null;
|
|
4041
4096
|
}
|
|
4042
4097
|
const key = language.toLowerCase();
|
|
4098
|
+
if (key === "javascript") return STRATEGIES["typescript"] ?? null;
|
|
4043
4099
|
return STRATEGIES[key] ?? null;
|
|
4044
4100
|
}
|
|
4045
4101
|
function getAlwaysInclude() {
|
|
@@ -4070,6 +4126,26 @@ function classifyFilePriority(filePath, strategy) {
|
|
|
4070
4126
|
}
|
|
4071
4127
|
return 3 /* OTHER */;
|
|
4072
4128
|
}
|
|
4129
|
+
function dedupe(arr) {
|
|
4130
|
+
return Array.from(new Set(arr));
|
|
4131
|
+
}
|
|
4132
|
+
function mergeStrategies(strategies) {
|
|
4133
|
+
if (strategies.length === 0) {
|
|
4134
|
+
throw new Error("mergeStrategies requires at least one strategy");
|
|
4135
|
+
}
|
|
4136
|
+
if (strategies.length === 1) {
|
|
4137
|
+
return strategies[0];
|
|
4138
|
+
}
|
|
4139
|
+
return {
|
|
4140
|
+
language: strategies.map((s) => s.language).join("/"),
|
|
4141
|
+
extensions: dedupe(strategies.flatMap((s) => s.extensions)),
|
|
4142
|
+
entryPoints: dedupe(strategies.flatMap((s) => s.entryPoints)),
|
|
4143
|
+
domainPatterns: dedupe(strategies.flatMap((s) => s.domainPatterns)),
|
|
4144
|
+
configPatterns: dedupe(strategies.flatMap((s) => s.configPatterns)),
|
|
4145
|
+
excludePatterns: dedupe(strategies.flatMap((s) => s.excludePatterns)),
|
|
4146
|
+
maxFilesPerCategory: Math.max(...strategies.map((s) => s.maxFilesPerCategory))
|
|
4147
|
+
};
|
|
4148
|
+
}
|
|
4073
4149
|
function extractPathsFromScripts(scripts) {
|
|
4074
4150
|
const paths = [];
|
|
4075
4151
|
const interestingScripts = ["start", "dev", "serve", "main", "server"];
|
|
@@ -4541,6 +4617,39 @@ function validateArray(raw, guard) {
|
|
|
4541
4617
|
if (!Array.isArray(raw)) return [];
|
|
4542
4618
|
return raw.filter(guard);
|
|
4543
4619
|
}
|
|
4620
|
+
function scopeStrategyToSubdirs(strategy, subdirs) {
|
|
4621
|
+
if (subdirs.length === 0) return strategy;
|
|
4622
|
+
return {
|
|
4623
|
+
...strategy,
|
|
4624
|
+
entryPoints: subdirs.flatMap(
|
|
4625
|
+
(dir) => strategy.entryPoints.map((ep) => `${dir}/${ep}`)
|
|
4626
|
+
),
|
|
4627
|
+
domainPatterns: subdirs.flatMap(
|
|
4628
|
+
(dir) => strategy.domainPatterns.map((dp) => `${dir}/${dp}`)
|
|
4629
|
+
),
|
|
4630
|
+
configPatterns: subdirs.flatMap(
|
|
4631
|
+
(dir) => strategy.configPatterns.map((cp) => `${dir}/${cp}`)
|
|
4632
|
+
)
|
|
4633
|
+
// excludePatterns: keep global (they use ** globs)
|
|
4634
|
+
};
|
|
4635
|
+
}
|
|
4636
|
+
function getLanguageWeight(filePath, languageLocations) {
|
|
4637
|
+
if (languageLocations.length <= 1) return 0;
|
|
4638
|
+
const subdirToRank = /* @__PURE__ */ new Map();
|
|
4639
|
+
for (let rank2 = 0; rank2 < languageLocations.length; rank2++) {
|
|
4640
|
+
for (const subdir of languageLocations[rank2].subdirs) {
|
|
4641
|
+
subdirToRank.set(subdir, rank2);
|
|
4642
|
+
}
|
|
4643
|
+
}
|
|
4644
|
+
if (subdirToRank.size === 0) return 0;
|
|
4645
|
+
const firstSlash = filePath.indexOf("/");
|
|
4646
|
+
if (firstSlash === -1) {
|
|
4647
|
+
return 0;
|
|
4648
|
+
}
|
|
4649
|
+
const firstSegment = filePath.slice(0, firstSlash);
|
|
4650
|
+
const rank = subdirToRank.get(firstSegment);
|
|
4651
|
+
return rank ?? 0;
|
|
4652
|
+
}
|
|
4544
4653
|
async function analyzeProject(dir, profile, config, options) {
|
|
4545
4654
|
if (!options?.refresh) {
|
|
4546
4655
|
const cache = await readCache(dir);
|
|
@@ -4557,20 +4666,24 @@ async function analyzeProject(dir, profile, config, options) {
|
|
|
4557
4666
|
}
|
|
4558
4667
|
}
|
|
4559
4668
|
}
|
|
4560
|
-
const
|
|
4561
|
-
|
|
4669
|
+
const languageLocations = profile.languageLocations ?? profile.languages.map((lang) => ({ language: lang, subdirs: [] }));
|
|
4670
|
+
const resolvedStrategies = await Promise.all(
|
|
4671
|
+
languageLocations.map(async ({ language, subdirs }) => {
|
|
4672
|
+
const base = getStrategy(language);
|
|
4673
|
+
if (!base) return null;
|
|
4674
|
+
const enriched = await resolveStrategy(dir, base, profile.framework, profile.scripts);
|
|
4675
|
+
return scopeStrategyToSubdirs(enriched, subdirs);
|
|
4676
|
+
})
|
|
4677
|
+
);
|
|
4678
|
+
const validStrategies = resolvedStrategies.filter((s) => s !== null);
|
|
4679
|
+
if (validStrategies.length === 0) {
|
|
4562
4680
|
throw new AnalysisError(
|
|
4563
|
-
`No sampling strategy for
|
|
4681
|
+
`No sampling strategy for languages: ${profile.languages.join(", ") || "none detected"}`,
|
|
4564
4682
|
"no_entry_point",
|
|
4565
4683
|
"Supported: Python, TypeScript, Go, Rust"
|
|
4566
4684
|
);
|
|
4567
4685
|
}
|
|
4568
|
-
const strategy =
|
|
4569
|
-
dir,
|
|
4570
|
-
baseStrategy,
|
|
4571
|
-
profile.framework,
|
|
4572
|
-
profile.scripts
|
|
4573
|
-
);
|
|
4686
|
+
const strategy = mergeStrategies(validStrategies);
|
|
4574
4687
|
const include = [
|
|
4575
4688
|
...strategy.entryPoints,
|
|
4576
4689
|
...strategy.domainPatterns.map((p) => p + "**/*"),
|
|
@@ -4581,7 +4694,11 @@ async function analyzeProject(dir, profile, config, options) {
|
|
|
4581
4694
|
include,
|
|
4582
4695
|
exclude: strategy.excludePatterns,
|
|
4583
4696
|
maxTokens: options?.tokenBudget ?? DEFAULT_TOKEN_BUDGET,
|
|
4584
|
-
prioritize: (filePath) =>
|
|
4697
|
+
prioritize: (filePath) => {
|
|
4698
|
+
const baseTier = classifyFilePriority(filePath, strategy);
|
|
4699
|
+
const langWeight = getLanguageWeight(filePath, languageLocations);
|
|
4700
|
+
return baseTier + langWeight * 0.1;
|
|
4701
|
+
}
|
|
4585
4702
|
});
|
|
4586
4703
|
if (packed.fileCount === 0) {
|
|
4587
4704
|
throw new AnalysisError(
|
|
@@ -4751,7 +4868,7 @@ function buildProfileSummary(profile) {
|
|
|
4751
4868
|
const lines = [];
|
|
4752
4869
|
lines.push(`Project: ${profile.name}`);
|
|
4753
4870
|
if (profile.description) lines.push(`Description: ${profile.description}`);
|
|
4754
|
-
if (profile.
|
|
4871
|
+
if (profile.languages.length > 0) lines.push(`Languages: ${profile.languages.join(", ")}`);
|
|
4755
4872
|
if (profile.framework) lines.push(`Framework: ${profile.framework}`);
|
|
4756
4873
|
if (profile.dependencies.length > 0) {
|
|
4757
4874
|
lines.push(`Dependencies: ${profile.dependencies.join(", ")}`);
|
|
@@ -4900,7 +5017,7 @@ var init_optimize = __esm({
|
|
|
4900
5017
|
const scanSpinner = ora({ text: "Scanning project...", indent: 2 }).start();
|
|
4901
5018
|
const profile = await scanProject(targetDir);
|
|
4902
5019
|
scanSpinner.stop();
|
|
4903
|
-
if (profile.
|
|
5020
|
+
if (profile.languages.length > 0) console.log(ui.kv("Languages:", profile.languages.join(", ")));
|
|
4904
5021
|
if (profile.framework) console.log(ui.kv("Framework:", profile.framework));
|
|
4905
5022
|
console.log(ui.kv("Dependencies:", String(profile.dependencies.length)));
|
|
4906
5023
|
if (profile.testCommand) console.log(ui.kv("Tests:", profile.testCommand));
|
|
@@ -9308,12 +9425,6 @@ async function evolve(workspacePath, tasks, kairnConfig, evolveConfig, onProgres
|
|
|
9308
9425
|
evolveConfig.proposerModel,
|
|
9309
9426
|
principalProjectCtx
|
|
9310
9427
|
);
|
|
9311
|
-
if (principalProposal.mutations.length > evolveConfig.maxMutationsPerIteration) {
|
|
9312
|
-
principalProposal = {
|
|
9313
|
-
...principalProposal,
|
|
9314
|
-
mutations: principalProposal.mutations.slice(0, evolveConfig.maxMutationsPerIteration)
|
|
9315
|
-
};
|
|
9316
|
-
}
|
|
9317
9428
|
const principalIterNum = history.length;
|
|
9318
9429
|
const principalIterDir = path31.join(workspacePath, "iterations", principalIterNum.toString());
|
|
9319
9430
|
const mutResult = await applyMutations(baselineHarnessPath, principalIterDir, principalProposal.mutations);
|
|
@@ -11392,7 +11503,7 @@ function buildAnalysisContext(analysis) {
|
|
|
11392
11503
|
}
|
|
11393
11504
|
function buildTaskGenerationMessage(claudeMd, projectProfile, templates, analysis) {
|
|
11394
11505
|
const profileLines = [
|
|
11395
|
-
`
|
|
11506
|
+
`Languages: ${projectProfile.languages.length > 0 ? projectProfile.languages.join(", ") : "unknown"}`,
|
|
11396
11507
|
`Framework: ${projectProfile.framework ?? "none"}`,
|
|
11397
11508
|
`Scripts: ${Object.entries(projectProfile.scripts).map(([k, v]) => `${k}=${v}`).join(", ") || "none"}`,
|
|
11398
11509
|
`Key files: ${projectProfile.keyFiles.join(", ") || "none"}`
|
|
@@ -11489,6 +11600,7 @@ async function writeTasksFile(workspacePath, tasks) {
|
|
|
11489
11600
|
async function buildProjectProfile(projectRoot) {
|
|
11490
11601
|
const profile = {
|
|
11491
11602
|
language: null,
|
|
11603
|
+
languages: [],
|
|
11492
11604
|
framework: null,
|
|
11493
11605
|
scripts: {},
|
|
11494
11606
|
keyFiles: []
|
|
@@ -11500,6 +11612,7 @@ async function buildProjectProfile(projectRoot) {
|
|
|
11500
11612
|
);
|
|
11501
11613
|
const pkg2 = JSON.parse(pkgStr);
|
|
11502
11614
|
profile.language = "typescript";
|
|
11615
|
+
profile.languages = ["typescript"];
|
|
11503
11616
|
if (pkg2.scripts && typeof pkg2.scripts === "object") {
|
|
11504
11617
|
profile.scripts = pkg2.scripts;
|
|
11505
11618
|
}
|
|
@@ -11524,10 +11637,12 @@ async function buildProjectProfile(projectRoot) {
|
|
|
11524
11637
|
try {
|
|
11525
11638
|
await fs20.access(path20.join(projectRoot, "pyproject.toml"));
|
|
11526
11639
|
profile.language = "python";
|
|
11640
|
+
profile.languages = ["python"];
|
|
11527
11641
|
} catch {
|
|
11528
11642
|
try {
|
|
11529
11643
|
await fs20.access(path20.join(projectRoot, "requirements.txt"));
|
|
11530
11644
|
profile.language = "python";
|
|
11645
|
+
profile.languages = ["python"];
|
|
11531
11646
|
} catch {
|
|
11532
11647
|
}
|
|
11533
11648
|
}
|
|
@@ -12910,8 +13025,8 @@ async function analyzeAction(options) {
|
|
|
12910
13025
|
const profile = await scanProject(targetDir);
|
|
12911
13026
|
scanSpinner?.succeed("Project scanned");
|
|
12912
13027
|
if (!options.json) {
|
|
12913
|
-
if (profile.
|
|
12914
|
-
console.log(ui.kv("
|
|
13028
|
+
if (profile.languages.length > 0)
|
|
13029
|
+
console.log(ui.kv("Languages:", profile.languages.join(", ")));
|
|
12915
13030
|
if (profile.framework)
|
|
12916
13031
|
console.log(ui.kv("Framework:", profile.framework));
|
|
12917
13032
|
}
|