@cleocode/cleo 2026.3.17 → 2026.3.18
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/index.js +671 -358
- package/dist/cli/index.js.map +4 -4
- package/dist/mcp/index.js +473 -164
- package/dist/mcp/index.js.map +4 -4
- package/package.json +1 -1
package/dist/mcp/index.js
CHANGED
|
@@ -1809,6 +1809,16 @@ var init_registry = __esm({
|
|
|
1809
1809
|
sessionRequired: false,
|
|
1810
1810
|
requiredParams: ["version"]
|
|
1811
1811
|
},
|
|
1812
|
+
{
|
|
1813
|
+
gateway: "query",
|
|
1814
|
+
domain: "pipeline",
|
|
1815
|
+
operation: "release.channel.show",
|
|
1816
|
+
description: "Show the current release channel based on git branch (latest/beta/alpha)",
|
|
1817
|
+
tier: 0,
|
|
1818
|
+
idempotent: true,
|
|
1819
|
+
sessionRequired: false,
|
|
1820
|
+
requiredParams: []
|
|
1821
|
+
},
|
|
1812
1822
|
{
|
|
1813
1823
|
gateway: "mutate",
|
|
1814
1824
|
domain: "pipeline",
|
|
@@ -1869,6 +1879,16 @@ var init_registry = __esm({
|
|
|
1869
1879
|
sessionRequired: false,
|
|
1870
1880
|
requiredParams: []
|
|
1871
1881
|
},
|
|
1882
|
+
{
|
|
1883
|
+
gateway: "mutate",
|
|
1884
|
+
domain: "pipeline",
|
|
1885
|
+
operation: "release.cancel",
|
|
1886
|
+
description: "pipeline.release.cancel (mutate)",
|
|
1887
|
+
tier: 0,
|
|
1888
|
+
idempotent: false,
|
|
1889
|
+
sessionRequired: false,
|
|
1890
|
+
requiredParams: ["version"]
|
|
1891
|
+
},
|
|
1872
1892
|
{
|
|
1873
1893
|
gateway: "mutate",
|
|
1874
1894
|
domain: "pipeline",
|
|
@@ -19948,10 +19968,10 @@ async function systemLog(projectRoot, filters) {
|
|
|
19948
19968
|
}
|
|
19949
19969
|
async function queryAuditLogSqlite(projectRoot, filters) {
|
|
19950
19970
|
try {
|
|
19951
|
-
const { join:
|
|
19952
|
-
const { existsSync:
|
|
19953
|
-
const dbPath =
|
|
19954
|
-
if (!
|
|
19971
|
+
const { join: join64 } = await import("node:path");
|
|
19972
|
+
const { existsSync: existsSync64 } = await import("node:fs");
|
|
19973
|
+
const dbPath = join64(projectRoot, ".cleo", "tasks.db");
|
|
19974
|
+
if (!existsSync64(dbPath)) {
|
|
19955
19975
|
const offset = filters?.offset ?? 0;
|
|
19956
19976
|
const limit = filters?.limit ?? 20;
|
|
19957
19977
|
return {
|
|
@@ -20695,10 +20715,10 @@ async function readProjectMeta(projectPath) {
|
|
|
20695
20715
|
}
|
|
20696
20716
|
async function readProjectId(projectPath) {
|
|
20697
20717
|
try {
|
|
20698
|
-
const { readFileSync:
|
|
20718
|
+
const { readFileSync: readFileSync46, existsSync: existsSync64 } = await import("node:fs");
|
|
20699
20719
|
const infoPath = join34(projectPath, ".cleo", "project-info.json");
|
|
20700
|
-
if (!
|
|
20701
|
-
const data = JSON.parse(
|
|
20720
|
+
if (!existsSync64(infoPath)) return "";
|
|
20721
|
+
const data = JSON.parse(readFileSync46(infoPath, "utf-8"));
|
|
20702
20722
|
return typeof data.projectId === "string" ? data.projectId : "";
|
|
20703
20723
|
} catch {
|
|
20704
20724
|
return "";
|
|
@@ -28490,7 +28510,8 @@ async function generateReleaseChangelog(version, loadTasksFn, cwd) {
|
|
|
28490
28510
|
}
|
|
28491
28511
|
function buildEntry(task) {
|
|
28492
28512
|
const cleanTitle = capitalize(stripConventionalPrefix(task.title));
|
|
28493
|
-
const
|
|
28513
|
+
const safeDesc = task.description?.replace(/\r?\n/g, " ").replace(/\s{2,}/g, " ").trim();
|
|
28514
|
+
const desc6 = safeDesc;
|
|
28494
28515
|
const shouldIncludeDesc = (() => {
|
|
28495
28516
|
if (!desc6 || desc6.length === 0) return false;
|
|
28496
28517
|
const titleNorm = cleanTitle.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim();
|
|
@@ -28507,23 +28528,29 @@ async function generateReleaseChangelog(version, loadTasksFn, cwd) {
|
|
|
28507
28528
|
}
|
|
28508
28529
|
function categorizeTask(task) {
|
|
28509
28530
|
if (task.type === "epic") return "changes";
|
|
28510
|
-
const
|
|
28511
|
-
|
|
28512
|
-
|
|
28531
|
+
const taskType = (task.type ?? "").toLowerCase();
|
|
28532
|
+
if (taskType === "test") return "tests";
|
|
28533
|
+
if (taskType === "fix" || taskType === "bugfix") return "fixes";
|
|
28534
|
+
if (taskType === "feat" || taskType === "feature") return "features";
|
|
28535
|
+
if (taskType === "docs" || taskType === "doc") return "docs";
|
|
28536
|
+
if (taskType === "chore" || taskType === "refactor") return "chores";
|
|
28513
28537
|
if (/^feat(\([^)]+\))?:/.test(task.title.toLowerCase())) return "features";
|
|
28514
28538
|
if (/^fix(\([^)]+\))?:/.test(task.title.toLowerCase())) return "fixes";
|
|
28515
28539
|
if (/^docs?(\([^)]+\))?:/.test(task.title.toLowerCase())) return "docs";
|
|
28516
28540
|
if (/^test(\([^)]+\))?:/.test(task.title.toLowerCase())) return "tests";
|
|
28517
28541
|
if (/^(chore|refactor|style|ci|build|perf)(\([^)]+\))?:/.test(task.title.toLowerCase())) return "chores";
|
|
28518
|
-
|
|
28542
|
+
const labels = task.labels ?? [];
|
|
28543
|
+
if (labels.some((l) => ["test", "testing"].includes(l.toLowerCase()))) return "tests";
|
|
28519
28544
|
if (labels.some((l) => ["fix", "bug", "bugfix", "regression"].includes(l.toLowerCase()))) return "fixes";
|
|
28545
|
+
if (labels.some((l) => ["feat", "feature", "enhancement", "add"].includes(l.toLowerCase()))) return "features";
|
|
28520
28546
|
if (labels.some((l) => ["docs", "documentation"].includes(l.toLowerCase()))) return "docs";
|
|
28521
|
-
if (labels.some((l) => ["test", "testing"].includes(l.toLowerCase()))) return "tests";
|
|
28522
28547
|
if (labels.some((l) => ["chore", "refactor", "cleanup", "maintenance"].includes(l.toLowerCase()))) return "chores";
|
|
28523
|
-
|
|
28548
|
+
const titleLower = stripConventionalPrefix(task.title).toLowerCase();
|
|
28549
|
+
const rawTitleLower = task.title.toLowerCase();
|
|
28550
|
+
if (titleLower.startsWith("test") || titleLower.includes("test") && titleLower.includes("add")) return "tests";
|
|
28524
28551
|
if (titleLower.includes("bug") || titleLower.startsWith("fix") || titleLower.includes("regression") || titleLower.includes("broken")) return "fixes";
|
|
28552
|
+
if (titleLower.startsWith("add ") || titleLower.includes("implement") || titleLower.startsWith("create ") || titleLower.startsWith("introduce ")) return "features";
|
|
28525
28553
|
if (titleLower.startsWith("doc") || titleLower.includes("documentation") || titleLower.includes("readme") || titleLower.includes("changelog")) return "docs";
|
|
28526
|
-
if (titleLower.startsWith("test") || titleLower.includes("test") && titleLower.includes("add")) return "tests";
|
|
28527
28554
|
if (titleLower.startsWith("chore") || titleLower.includes("refactor") || titleLower.includes("cleanup") || titleLower.includes("migrate") || titleLower.includes("upgrade") || titleLower.includes("remove ") || titleLower.startsWith("audit")) return "chores";
|
|
28528
28555
|
if (rawTitleLower.startsWith("feat")) return "features";
|
|
28529
28556
|
return "changes";
|
|
@@ -28534,6 +28561,10 @@ async function generateReleaseChangelog(version, loadTasksFn, cwd) {
|
|
|
28534
28561
|
if (task.type === "epic") continue;
|
|
28535
28562
|
if (task.labels?.some((l) => l.toLowerCase() === "epic")) continue;
|
|
28536
28563
|
if (/^epic:/i.test(task.title.trim())) continue;
|
|
28564
|
+
const labelsLower = (task.labels ?? []).map((l) => l.toLowerCase());
|
|
28565
|
+
if (labelsLower.some((l) => ["research", "internal", "spike", "audit"].includes(l))) continue;
|
|
28566
|
+
if (["spike", "research"].includes((task.type ?? "").toLowerCase())) continue;
|
|
28567
|
+
if (/^(research|investigate|audit|spike)\s/i.test(task.title.trim())) continue;
|
|
28537
28568
|
const category = categorizeTask(task);
|
|
28538
28569
|
const entry = buildEntry(task);
|
|
28539
28570
|
if (category === "features") features.push(entry);
|
|
@@ -28591,7 +28622,7 @@ async function generateReleaseChangelog(version, loadTasksFn, cwd) {
|
|
|
28591
28622
|
}
|
|
28592
28623
|
const { customBlocks } = parseChangelogBlocks(existingChangelogContent);
|
|
28593
28624
|
const changelogBody = sections.slice(2).join("\n");
|
|
28594
|
-
await writeChangelogSection(normalizedVersion, changelogBody, customBlocks, changelogPath);
|
|
28625
|
+
await writeChangelogSection(normalizedVersion.replace(/^v/, ""), changelogBody, customBlocks, changelogPath);
|
|
28595
28626
|
return {
|
|
28596
28627
|
version: normalizedVersion,
|
|
28597
28628
|
changelog,
|
|
@@ -28664,7 +28695,7 @@ async function tagRelease(version, cwd) {
|
|
|
28664
28695
|
await db.update(releaseManifests).set({ status: "tagged", taggedAt }).where(eq14(releaseManifests.version, normalizedVersion)).run();
|
|
28665
28696
|
return { version: normalizedVersion, status: "tagged", taggedAt };
|
|
28666
28697
|
}
|
|
28667
|
-
async function runReleaseGates(version, loadTasksFn, cwd) {
|
|
28698
|
+
async function runReleaseGates(version, loadTasksFn, cwd, opts) {
|
|
28668
28699
|
if (!version) {
|
|
28669
28700
|
throw new Error("version is required");
|
|
28670
28701
|
}
|
|
@@ -28712,23 +28743,31 @@ async function runReleaseGates(version, loadTasksFn, cwd) {
|
|
|
28712
28743
|
message: existsSync50(distPath) ? "dist/cli/index.js present" : "dist/ not built \u2014 run: npm run build"
|
|
28713
28744
|
});
|
|
28714
28745
|
}
|
|
28715
|
-
|
|
28716
|
-
|
|
28717
|
-
|
|
28718
|
-
|
|
28719
|
-
|
|
28720
|
-
|
|
28721
|
-
|
|
28746
|
+
if (opts?.dryRun) {
|
|
28747
|
+
gates.push({
|
|
28748
|
+
name: "clean_working_tree",
|
|
28749
|
+
status: "passed",
|
|
28750
|
+
message: "Skipped in dry-run mode"
|
|
28751
|
+
});
|
|
28752
|
+
} else {
|
|
28753
|
+
let workingTreeClean = true;
|
|
28754
|
+
let dirtyFiles = [];
|
|
28755
|
+
try {
|
|
28756
|
+
const porcelain = execFileSync7("git", ["status", "--porcelain"], {
|
|
28757
|
+
cwd: projectRoot,
|
|
28758
|
+
encoding: "utf-8",
|
|
28759
|
+
stdio: "pipe"
|
|
28760
|
+
});
|
|
28761
|
+
dirtyFiles = porcelain.split("\n").filter((l) => l.trim()).filter((l) => !l.startsWith("?? ")).map((l) => l.slice(3).trim()).filter((f) => f !== "CHANGELOG.md" && f !== "VERSION" && f !== "package.json");
|
|
28762
|
+
workingTreeClean = dirtyFiles.length === 0;
|
|
28763
|
+
} catch {
|
|
28764
|
+
}
|
|
28765
|
+
gates.push({
|
|
28766
|
+
name: "clean_working_tree",
|
|
28767
|
+
status: workingTreeClean ? "passed" : "failed",
|
|
28768
|
+
message: workingTreeClean ? "Working tree clean (excluding CHANGELOG.md, VERSION, package.json)" : `Uncommitted changes in: ${dirtyFiles.slice(0, 5).join(", ")}${dirtyFiles.length > 5 ? ` (+${dirtyFiles.length - 5} more)` : ""}`
|
|
28722
28769
|
});
|
|
28723
|
-
dirtyFiles = porcelain.split("\n").filter((l) => l.trim()).map((l) => l.slice(3).trim()).filter((f) => f !== "CHANGELOG.md" && f !== "VERSION" && f !== "package.json");
|
|
28724
|
-
workingTreeClean = dirtyFiles.length === 0;
|
|
28725
|
-
} catch {
|
|
28726
28770
|
}
|
|
28727
|
-
gates.push({
|
|
28728
|
-
name: "clean_working_tree",
|
|
28729
|
-
status: workingTreeClean ? "passed" : "failed",
|
|
28730
|
-
message: workingTreeClean ? "Working tree clean (excluding CHANGELOG.md, VERSION, package.json)" : `Uncommitted changes in: ${dirtyFiles.slice(0, 5).join(", ")}${dirtyFiles.length > 5 ? ` (+${dirtyFiles.length - 5} more)` : ""}`
|
|
28731
|
-
});
|
|
28732
28771
|
const isPreRelease = normalizedVersion.includes("-");
|
|
28733
28772
|
let currentBranch = "";
|
|
28734
28773
|
try {
|
|
@@ -28788,6 +28827,28 @@ async function runReleaseGates(version, loadTasksFn, cwd) {
|
|
|
28788
28827
|
metadata
|
|
28789
28828
|
};
|
|
28790
28829
|
}
|
|
28830
|
+
async function cancelRelease(version, projectRoot) {
|
|
28831
|
+
if (!version) {
|
|
28832
|
+
throw new Error("version is required");
|
|
28833
|
+
}
|
|
28834
|
+
const normalizedVersion = normalizeVersion(version);
|
|
28835
|
+
const db = await getDb(projectRoot);
|
|
28836
|
+
const rows = await db.select().from(releaseManifests).where(eq14(releaseManifests.version, normalizedVersion)).limit(1).all();
|
|
28837
|
+
if (rows.length === 0) {
|
|
28838
|
+
return { success: false, message: `Release ${normalizedVersion} not found`, version: normalizedVersion };
|
|
28839
|
+
}
|
|
28840
|
+
const status = rows[0].status;
|
|
28841
|
+
const cancellableStates = ["draft", "prepared"];
|
|
28842
|
+
if (!cancellableStates.includes(status)) {
|
|
28843
|
+
return {
|
|
28844
|
+
success: false,
|
|
28845
|
+
message: `Cannot cancel a release in '${status}' state. Use 'release rollback' instead.`,
|
|
28846
|
+
version: normalizedVersion
|
|
28847
|
+
};
|
|
28848
|
+
}
|
|
28849
|
+
await db.delete(releaseManifests).where(eq14(releaseManifests.version, normalizedVersion)).run();
|
|
28850
|
+
return { success: true, message: `Release ${normalizedVersion} cancelled and removed`, version: normalizedVersion };
|
|
28851
|
+
}
|
|
28791
28852
|
async function rollbackRelease(version, reason, cwd) {
|
|
28792
28853
|
if (!version) {
|
|
28793
28854
|
throw new Error("version is required");
|
|
@@ -28862,7 +28923,8 @@ async function pushRelease(version, remote, cwd, opts) {
|
|
|
28862
28923
|
encoding: "utf-8",
|
|
28863
28924
|
stdio: ["pipe", "pipe", "pipe"]
|
|
28864
28925
|
});
|
|
28865
|
-
|
|
28926
|
+
const trackedDirty = statusOutput.split("\n").filter((l) => l.trim() && !l.startsWith("?? ")).join("\n");
|
|
28927
|
+
if (trackedDirty.trim().length > 0) {
|
|
28866
28928
|
throw new Error(
|
|
28867
28929
|
"Git working tree is not clean. Commit or stash changes before pushing (config: release.push.requireCleanTree=true)."
|
|
28868
28930
|
);
|
|
@@ -28994,6 +29056,179 @@ var init_guards = __esm({
|
|
|
28994
29056
|
}
|
|
28995
29057
|
});
|
|
28996
29058
|
|
|
29059
|
+
// src/core/release/version-bump.ts
|
|
29060
|
+
import { existsSync as existsSync51, readFileSync as readFileSync39, writeFileSync as writeFileSync8 } from "node:fs";
|
|
29061
|
+
import { join as join49 } from "node:path";
|
|
29062
|
+
function readConfigValueSync2(path, defaultValue, cwd) {
|
|
29063
|
+
try {
|
|
29064
|
+
const configPath = join49(getCleoDir(cwd), "config.json");
|
|
29065
|
+
if (!existsSync51(configPath)) return defaultValue;
|
|
29066
|
+
const config = JSON.parse(readFileSync39(configPath, "utf-8"));
|
|
29067
|
+
const keys = path.split(".");
|
|
29068
|
+
let value = config;
|
|
29069
|
+
for (const key of keys) {
|
|
29070
|
+
if (value == null || typeof value !== "object") return defaultValue;
|
|
29071
|
+
value = value[key];
|
|
29072
|
+
}
|
|
29073
|
+
return value ?? defaultValue;
|
|
29074
|
+
} catch {
|
|
29075
|
+
return defaultValue;
|
|
29076
|
+
}
|
|
29077
|
+
}
|
|
29078
|
+
function validateVersionFormat(version) {
|
|
29079
|
+
return VERSION_WITH_PRERELEASE.test(version);
|
|
29080
|
+
}
|
|
29081
|
+
function getVersionBumpConfig(cwd) {
|
|
29082
|
+
try {
|
|
29083
|
+
const raw = readConfigValueSync2("release.versionBump.files", [], cwd);
|
|
29084
|
+
return raw.map((entry) => ({
|
|
29085
|
+
file: entry.path ?? entry.file ?? "",
|
|
29086
|
+
strategy: entry.strategy,
|
|
29087
|
+
field: entry.jsonPath?.replace(/^\./, "") ?? entry.field,
|
|
29088
|
+
key: entry.key,
|
|
29089
|
+
section: entry.section,
|
|
29090
|
+
pattern: entry.sedPattern ?? entry.pattern
|
|
29091
|
+
})).filter((t) => t.file !== "");
|
|
29092
|
+
} catch {
|
|
29093
|
+
return [];
|
|
29094
|
+
}
|
|
29095
|
+
}
|
|
29096
|
+
function bumpFile(target, newVersion, projectRoot) {
|
|
29097
|
+
const filePath = join49(projectRoot, target.file);
|
|
29098
|
+
if (!existsSync51(filePath)) {
|
|
29099
|
+
return {
|
|
29100
|
+
file: target.file,
|
|
29101
|
+
strategy: target.strategy,
|
|
29102
|
+
success: false,
|
|
29103
|
+
error: `File not found: ${target.file}`
|
|
29104
|
+
};
|
|
29105
|
+
}
|
|
29106
|
+
try {
|
|
29107
|
+
const content = readFileSync39(filePath, "utf-8");
|
|
29108
|
+
let previousVersion;
|
|
29109
|
+
let newContent;
|
|
29110
|
+
switch (target.strategy) {
|
|
29111
|
+
case "plain": {
|
|
29112
|
+
previousVersion = content.trim();
|
|
29113
|
+
newContent = newVersion + "\n";
|
|
29114
|
+
break;
|
|
29115
|
+
}
|
|
29116
|
+
case "json": {
|
|
29117
|
+
const field = target.field ?? "version";
|
|
29118
|
+
const json = JSON.parse(content);
|
|
29119
|
+
previousVersion = getNestedField(json, field);
|
|
29120
|
+
setNestedField(json, field, newVersion);
|
|
29121
|
+
newContent = JSON.stringify(json, null, 2) + "\n";
|
|
29122
|
+
break;
|
|
29123
|
+
}
|
|
29124
|
+
case "toml": {
|
|
29125
|
+
const key = target.key ?? "version";
|
|
29126
|
+
const versionRegex = new RegExp(`^(${key}\\s*=\\s*")([^"]+)(")`, "m");
|
|
29127
|
+
const match = content.match(versionRegex);
|
|
29128
|
+
previousVersion = match?.[2];
|
|
29129
|
+
newContent = content.replace(versionRegex, `$1${newVersion}$3`);
|
|
29130
|
+
break;
|
|
29131
|
+
}
|
|
29132
|
+
case "sed": {
|
|
29133
|
+
const pattern = target.pattern ?? "";
|
|
29134
|
+
if (!pattern.includes("{{VERSION}}")) {
|
|
29135
|
+
return {
|
|
29136
|
+
file: target.file,
|
|
29137
|
+
strategy: target.strategy,
|
|
29138
|
+
success: false,
|
|
29139
|
+
error: "sed strategy requires {{VERSION}} placeholder in pattern"
|
|
29140
|
+
};
|
|
29141
|
+
}
|
|
29142
|
+
const regex = new RegExp(pattern.replace("{{VERSION}}", "([\\d.]+)"));
|
|
29143
|
+
const match = content.match(regex);
|
|
29144
|
+
previousVersion = match?.[1];
|
|
29145
|
+
newContent = content.replace(
|
|
29146
|
+
regex,
|
|
29147
|
+
pattern.replace("{{VERSION}}", newVersion)
|
|
29148
|
+
);
|
|
29149
|
+
break;
|
|
29150
|
+
}
|
|
29151
|
+
default:
|
|
29152
|
+
return {
|
|
29153
|
+
file: target.file,
|
|
29154
|
+
strategy: target.strategy,
|
|
29155
|
+
success: false,
|
|
29156
|
+
error: `Unknown strategy: ${target.strategy}`
|
|
29157
|
+
};
|
|
29158
|
+
}
|
|
29159
|
+
writeFileSync8(filePath, newContent, "utf-8");
|
|
29160
|
+
return {
|
|
29161
|
+
file: target.file,
|
|
29162
|
+
strategy: target.strategy,
|
|
29163
|
+
success: true,
|
|
29164
|
+
previousVersion,
|
|
29165
|
+
newVersion
|
|
29166
|
+
};
|
|
29167
|
+
} catch (err) {
|
|
29168
|
+
return {
|
|
29169
|
+
file: target.file,
|
|
29170
|
+
strategy: target.strategy,
|
|
29171
|
+
success: false,
|
|
29172
|
+
error: String(err)
|
|
29173
|
+
};
|
|
29174
|
+
}
|
|
29175
|
+
}
|
|
29176
|
+
function bumpVersionFromConfig(newVersion, options = {}, cwd) {
|
|
29177
|
+
if (!validateVersionFormat(newVersion)) {
|
|
29178
|
+
throw new CleoError(
|
|
29179
|
+
6 /* VALIDATION_ERROR */,
|
|
29180
|
+
`Invalid version: '${newVersion}' (expected X.Y.Z or YYYY.M.patch)`
|
|
29181
|
+
);
|
|
29182
|
+
}
|
|
29183
|
+
const targets = getVersionBumpConfig(cwd);
|
|
29184
|
+
if (targets.length === 0) {
|
|
29185
|
+
throw new CleoError(
|
|
29186
|
+
1 /* GENERAL_ERROR */,
|
|
29187
|
+
"No version bump targets configured. Add release.versionBump.files to .cleo/config.json"
|
|
29188
|
+
);
|
|
29189
|
+
}
|
|
29190
|
+
const projectRoot = getProjectRoot(cwd);
|
|
29191
|
+
const results = [];
|
|
29192
|
+
if (options.dryRun) {
|
|
29193
|
+
for (const target of targets) {
|
|
29194
|
+
results.push({
|
|
29195
|
+
file: target.file,
|
|
29196
|
+
strategy: target.strategy,
|
|
29197
|
+
success: true,
|
|
29198
|
+
newVersion
|
|
29199
|
+
});
|
|
29200
|
+
}
|
|
29201
|
+
return { results, allSuccess: true };
|
|
29202
|
+
}
|
|
29203
|
+
for (const target of targets) {
|
|
29204
|
+
results.push(bumpFile(target, newVersion, projectRoot));
|
|
29205
|
+
}
|
|
29206
|
+
const allSuccess = results.every((r) => r.success);
|
|
29207
|
+
return { results, allSuccess };
|
|
29208
|
+
}
|
|
29209
|
+
function getNestedField(obj, path) {
|
|
29210
|
+
return path.split(".").reduce((acc, key) => acc?.[key], obj);
|
|
29211
|
+
}
|
|
29212
|
+
function setNestedField(obj, path, value) {
|
|
29213
|
+
const parts = path.split(".");
|
|
29214
|
+
let current = obj;
|
|
29215
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
29216
|
+
if (typeof current[parts[i]] !== "object") current[parts[i]] = {};
|
|
29217
|
+
current = current[parts[i]];
|
|
29218
|
+
}
|
|
29219
|
+
current[parts[parts.length - 1]] = value;
|
|
29220
|
+
}
|
|
29221
|
+
var VERSION_WITH_PRERELEASE;
|
|
29222
|
+
var init_version_bump = __esm({
|
|
29223
|
+
"src/core/release/version-bump.ts"() {
|
|
29224
|
+
"use strict";
|
|
29225
|
+
init_paths();
|
|
29226
|
+
init_errors();
|
|
29227
|
+
init_exit_codes();
|
|
29228
|
+
VERSION_WITH_PRERELEASE = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$/;
|
|
29229
|
+
}
|
|
29230
|
+
});
|
|
29231
|
+
|
|
28997
29232
|
// src/dispatch/engines/release-engine.ts
|
|
28998
29233
|
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
28999
29234
|
function isAgentContext() {
|
|
@@ -29116,6 +29351,23 @@ async function releaseRollback(version, reason, projectRoot) {
|
|
|
29116
29351
|
return engineError(code, message);
|
|
29117
29352
|
}
|
|
29118
29353
|
}
|
|
29354
|
+
async function releaseCancel(version, projectRoot) {
|
|
29355
|
+
if (!version) {
|
|
29356
|
+
return engineError("E_INVALID_INPUT", "version is required");
|
|
29357
|
+
}
|
|
29358
|
+
try {
|
|
29359
|
+
const result = await cancelRelease(version, projectRoot);
|
|
29360
|
+
if (!result.success) {
|
|
29361
|
+
const code = result.message.includes("not found") ? "E_NOT_FOUND" : "E_INVALID_STATE";
|
|
29362
|
+
return engineError(code, result.message);
|
|
29363
|
+
}
|
|
29364
|
+
return { success: true, data: result };
|
|
29365
|
+
} catch (err) {
|
|
29366
|
+
const message = err.message;
|
|
29367
|
+
const code = message.includes("not found") ? "E_NOT_FOUND" : "E_CANCEL_FAILED";
|
|
29368
|
+
return engineError(code, message);
|
|
29369
|
+
}
|
|
29370
|
+
}
|
|
29119
29371
|
async function releasePush(version, remote, projectRoot, opts) {
|
|
29120
29372
|
if (isAgentContext()) {
|
|
29121
29373
|
const hasEntry = await hasManifestEntry(version, projectRoot);
|
|
@@ -29159,7 +29411,7 @@ async function releasePush(version, remote, projectRoot, opts) {
|
|
|
29159
29411
|
}
|
|
29160
29412
|
}
|
|
29161
29413
|
async function releaseShip(params, projectRoot) {
|
|
29162
|
-
const { version, epicId, remote, dryRun = false } = params;
|
|
29414
|
+
const { version, epicId, remote, dryRun = false, bump = true } = params;
|
|
29163
29415
|
if (!version) {
|
|
29164
29416
|
return engineError("E_INVALID_INPUT", "version is required");
|
|
29165
29417
|
}
|
|
@@ -29167,30 +29419,51 @@ async function releaseShip(params, projectRoot) {
|
|
|
29167
29419
|
return engineError("E_INVALID_INPUT", "epicId is required");
|
|
29168
29420
|
}
|
|
29169
29421
|
const cwd = projectRoot ?? resolveProjectRoot();
|
|
29422
|
+
const steps = [];
|
|
29170
29423
|
const logStep = (n, total, label, done, error) => {
|
|
29424
|
+
let msg;
|
|
29171
29425
|
if (done === void 0) {
|
|
29172
|
-
|
|
29426
|
+
msg = `[Step ${n}/${total}] ${label}...`;
|
|
29173
29427
|
} else if (done) {
|
|
29174
|
-
|
|
29428
|
+
msg = ` \u2713 ${label}`;
|
|
29175
29429
|
} else {
|
|
29176
|
-
|
|
29430
|
+
msg = ` \u2717 ${label}: ${error ?? "failed"}`;
|
|
29177
29431
|
}
|
|
29432
|
+
steps.push(msg);
|
|
29433
|
+
console.log(msg);
|
|
29178
29434
|
};
|
|
29435
|
+
const bumpTargets = getVersionBumpConfig(cwd);
|
|
29436
|
+
const shouldBump = bump && bumpTargets.length > 0;
|
|
29179
29437
|
try {
|
|
29180
|
-
|
|
29438
|
+
if (shouldBump) {
|
|
29439
|
+
logStep(0, 8, "Bump version files");
|
|
29440
|
+
if (!dryRun) {
|
|
29441
|
+
const bumpResults = bumpVersionFromConfig(version, { dryRun: false }, cwd);
|
|
29442
|
+
if (!bumpResults.allSuccess) {
|
|
29443
|
+
const failed = bumpResults.results.filter((r) => !r.success).map((r) => r.file);
|
|
29444
|
+
steps.push(` ! Version bump partial: failed for ${failed.join(", ")}`);
|
|
29445
|
+
} else {
|
|
29446
|
+
logStep(0, 8, "Bump version files", true);
|
|
29447
|
+
}
|
|
29448
|
+
} else {
|
|
29449
|
+
logStep(0, 8, "Bump version files", true);
|
|
29450
|
+
}
|
|
29451
|
+
}
|
|
29452
|
+
logStep(1, 8, "Validate release gates");
|
|
29181
29453
|
const gatesResult = await runReleaseGates(
|
|
29182
29454
|
version,
|
|
29183
29455
|
() => loadTasks2(projectRoot),
|
|
29184
|
-
projectRoot
|
|
29456
|
+
projectRoot,
|
|
29457
|
+
{ dryRun }
|
|
29185
29458
|
);
|
|
29186
29459
|
if (gatesResult && !gatesResult.allPassed) {
|
|
29187
29460
|
const failedGates = gatesResult.gates.filter((g) => g.status === "failed");
|
|
29188
|
-
logStep(1,
|
|
29461
|
+
logStep(1, 8, "Validate release gates", false, failedGates.map((g) => g.name).join(", "));
|
|
29189
29462
|
return engineError("E_LIFECYCLE_GATE_FAILED", `Release gates failed for ${version}: ${failedGates.map((g) => g.name).join(", ")}`, {
|
|
29190
29463
|
details: { gates: gatesResult.gates, failedCount: gatesResult.failedCount }
|
|
29191
29464
|
});
|
|
29192
29465
|
}
|
|
29193
|
-
logStep(1,
|
|
29466
|
+
logStep(1, 8, "Validate release gates", true);
|
|
29194
29467
|
let resolvedChannel = "latest";
|
|
29195
29468
|
let currentBranchForPR = "HEAD";
|
|
29196
29469
|
try {
|
|
@@ -29210,7 +29483,7 @@ async function releaseShip(params, projectRoot) {
|
|
|
29210
29483
|
if (gateMetadata?.currentBranch) {
|
|
29211
29484
|
currentBranchForPR = gateMetadata.currentBranch;
|
|
29212
29485
|
}
|
|
29213
|
-
logStep(2,
|
|
29486
|
+
logStep(2, 8, "Check epic completeness");
|
|
29214
29487
|
let releaseTaskIds = [];
|
|
29215
29488
|
try {
|
|
29216
29489
|
const manifest = await showManifestRelease(version, projectRoot);
|
|
@@ -29221,13 +29494,13 @@ async function releaseShip(params, projectRoot) {
|
|
|
29221
29494
|
const epicCheck = await checkEpicCompleteness(releaseTaskIds, projectRoot, epicAccessor);
|
|
29222
29495
|
if (epicCheck.hasIncomplete) {
|
|
29223
29496
|
const incomplete = epicCheck.epics.filter((e) => e.missingChildren.length > 0).map((e) => `${e.epicId}: missing ${e.missingChildren.map((c) => c.id).join(", ")}`).join("; ");
|
|
29224
|
-
logStep(2,
|
|
29497
|
+
logStep(2, 8, "Check epic completeness", false, incomplete);
|
|
29225
29498
|
return engineError("E_LIFECYCLE_GATE_FAILED", `Epic completeness check failed: ${incomplete}`, {
|
|
29226
29499
|
details: { epics: epicCheck.epics }
|
|
29227
29500
|
});
|
|
29228
29501
|
}
|
|
29229
|
-
logStep(2,
|
|
29230
|
-
logStep(3,
|
|
29502
|
+
logStep(2, 8, "Check epic completeness", true);
|
|
29503
|
+
logStep(3, 8, "Check task double-listing");
|
|
29231
29504
|
const allReleases = await listManifestReleases(projectRoot);
|
|
29232
29505
|
const existingReleases = (allReleases.releases ?? []).filter((r) => r.version !== version);
|
|
29233
29506
|
const doubleCheck = checkDoubleListing(
|
|
@@ -29236,39 +29509,38 @@ async function releaseShip(params, projectRoot) {
|
|
|
29236
29509
|
);
|
|
29237
29510
|
if (doubleCheck.hasDoubleListing) {
|
|
29238
29511
|
const dupes = doubleCheck.duplicates.map((d) => `${d.taskId} (in ${d.releases.join(", ")})`).join("; ");
|
|
29239
|
-
logStep(3,
|
|
29512
|
+
logStep(3, 8, "Check task double-listing", false, dupes);
|
|
29240
29513
|
return engineError("E_VALIDATION", `Double-listing detected: ${dupes}`, {
|
|
29241
29514
|
details: { duplicates: doubleCheck.duplicates }
|
|
29242
29515
|
});
|
|
29243
29516
|
}
|
|
29244
|
-
logStep(3,
|
|
29245
|
-
logStep(4, 7, "Generate CHANGELOG");
|
|
29246
|
-
const changelogResult = await generateReleaseChangelog(
|
|
29247
|
-
version,
|
|
29248
|
-
() => loadTasks2(projectRoot),
|
|
29249
|
-
projectRoot
|
|
29250
|
-
);
|
|
29251
|
-
const changelogPath = `${cwd}/CHANGELOG.md`;
|
|
29252
|
-
const generatedContent = changelogResult.changelog ?? "";
|
|
29253
|
-
logStep(4, 7, "Generate CHANGELOG", true);
|
|
29517
|
+
logStep(3, 8, "Check task double-listing", true);
|
|
29254
29518
|
const loadedConfig = loadReleaseConfig(cwd);
|
|
29255
29519
|
const pushMode = getPushMode(loadedConfig);
|
|
29256
29520
|
const gitflowCfg = getGitFlowConfig(loadedConfig);
|
|
29257
29521
|
const targetBranch = targetBranchFromGates ?? gitflowCfg.branches.main;
|
|
29258
29522
|
if (dryRun) {
|
|
29523
|
+
logStep(4, 8, "Generate CHANGELOG");
|
|
29524
|
+
logStep(4, 8, "Generate CHANGELOG", true);
|
|
29259
29525
|
const wouldCreatePR = requiresPRFromGates || pushMode === "pr";
|
|
29526
|
+
const filesToStagePreview = ["CHANGELOG.md", ...shouldBump ? bumpTargets.map((t) => t.file) : []];
|
|
29527
|
+
const wouldDo = [];
|
|
29528
|
+
if (shouldBump) {
|
|
29529
|
+
wouldDo.push(`bump version files: ${bumpTargets.map((t) => t.file).join(", ")} \u2192 ${version}`);
|
|
29530
|
+
}
|
|
29531
|
+
wouldDo.push(
|
|
29532
|
+
`write CHANGELOG.md: ## [${version}] - ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]} (preview only, not written in dry-run)`,
|
|
29533
|
+
`git add ${filesToStagePreview.join(" ")}`,
|
|
29534
|
+
`git commit -m "release: ship v${version} (${epicId})"`,
|
|
29535
|
+
`git tag -a v${version} -m "Release v${version}"`
|
|
29536
|
+
);
|
|
29260
29537
|
const dryRunOutput = {
|
|
29261
29538
|
version,
|
|
29262
29539
|
epicId,
|
|
29263
29540
|
dryRun: true,
|
|
29264
29541
|
channel: resolvedChannel,
|
|
29265
29542
|
pushMode,
|
|
29266
|
-
wouldDo
|
|
29267
|
-
`write CHANGELOG section for ${version} (${generatedContent.length} chars)`,
|
|
29268
|
-
"git add CHANGELOG.md",
|
|
29269
|
-
`git commit -m "release: ship v${version} (${epicId})"`,
|
|
29270
|
-
`git tag -a v${version} -m "Release v${version}"`
|
|
29271
|
-
]
|
|
29543
|
+
wouldDo
|
|
29272
29544
|
};
|
|
29273
29545
|
if (wouldCreatePR) {
|
|
29274
29546
|
const ghAvailable = isGhCliAvailable();
|
|
@@ -29285,15 +29557,24 @@ async function releaseShip(params, projectRoot) {
|
|
|
29285
29557
|
dryRunOutput["wouldCreatePR"] = false;
|
|
29286
29558
|
}
|
|
29287
29559
|
dryRunOutput["wouldDo"].push("markReleasePushed(...)");
|
|
29288
|
-
return { success: true, data: dryRunOutput };
|
|
29560
|
+
return { success: true, data: { ...dryRunOutput, steps } };
|
|
29289
29561
|
}
|
|
29290
|
-
logStep(
|
|
29562
|
+
logStep(4, 8, "Generate CHANGELOG");
|
|
29563
|
+
await generateReleaseChangelog(
|
|
29564
|
+
version,
|
|
29565
|
+
() => loadTasks2(projectRoot),
|
|
29566
|
+
projectRoot
|
|
29567
|
+
);
|
|
29568
|
+
const changelogPath = `${cwd}/CHANGELOG.md`;
|
|
29569
|
+
logStep(4, 8, "Generate CHANGELOG", true);
|
|
29570
|
+
logStep(5, 8, "Commit release");
|
|
29291
29571
|
const gitCwd = { cwd, encoding: "utf-8", stdio: "pipe" };
|
|
29572
|
+
const filesToStage = ["CHANGELOG.md", ...shouldBump ? bumpTargets.map((t) => t.file) : []];
|
|
29292
29573
|
try {
|
|
29293
|
-
execFileSync8("git", ["add",
|
|
29574
|
+
execFileSync8("git", ["add", ...filesToStage], gitCwd);
|
|
29294
29575
|
} catch (err) {
|
|
29295
29576
|
const msg = err.message ?? String(err);
|
|
29296
|
-
logStep(5,
|
|
29577
|
+
logStep(5, 8, "Commit release", false, `git add failed: ${msg}`);
|
|
29297
29578
|
return engineError("E_GENERAL", `git add failed: ${msg}`);
|
|
29298
29579
|
}
|
|
29299
29580
|
try {
|
|
@@ -29304,26 +29585,26 @@ async function releaseShip(params, projectRoot) {
|
|
|
29304
29585
|
);
|
|
29305
29586
|
} catch (err) {
|
|
29306
29587
|
const msg = err.stderr ?? err.message ?? String(err);
|
|
29307
|
-
logStep(5,
|
|
29588
|
+
logStep(5, 8, "Commit release", false, `git commit failed: ${msg}`);
|
|
29308
29589
|
return engineError("E_GENERAL", `git commit failed: ${msg}`);
|
|
29309
29590
|
}
|
|
29310
|
-
logStep(5,
|
|
29591
|
+
logStep(5, 8, "Commit release", true);
|
|
29311
29592
|
let commitSha;
|
|
29312
29593
|
try {
|
|
29313
29594
|
commitSha = execFileSync8("git", ["rev-parse", "HEAD"], gitCwd).toString().trim();
|
|
29314
29595
|
} catch {
|
|
29315
29596
|
}
|
|
29316
|
-
logStep(6,
|
|
29597
|
+
logStep(6, 8, "Tag release");
|
|
29317
29598
|
const gitTag = `v${version.replace(/^v/, "")}`;
|
|
29318
29599
|
try {
|
|
29319
29600
|
execFileSync8("git", ["tag", "-a", gitTag, "-m", `Release ${gitTag}`], gitCwd);
|
|
29320
29601
|
} catch (err) {
|
|
29321
29602
|
const msg = err.stderr ?? err.message ?? String(err);
|
|
29322
|
-
logStep(6,
|
|
29603
|
+
logStep(6, 8, "Tag release", false, `git tag failed: ${msg}`);
|
|
29323
29604
|
return engineError("E_GENERAL", `git tag failed: ${msg}`);
|
|
29324
29605
|
}
|
|
29325
|
-
logStep(6,
|
|
29326
|
-
logStep(7,
|
|
29606
|
+
logStep(6, 8, "Tag release", true);
|
|
29607
|
+
logStep(7, 8, "Push / create PR");
|
|
29327
29608
|
let prResult = null;
|
|
29328
29609
|
const pushResult = await pushRelease(version, remote, projectRoot, {
|
|
29329
29610
|
explicitPush: true,
|
|
@@ -29350,24 +29631,34 @@ async function releaseShip(params, projectRoot) {
|
|
|
29350
29631
|
projectRoot: cwd
|
|
29351
29632
|
});
|
|
29352
29633
|
if (prResult.mode === "created") {
|
|
29353
|
-
|
|
29354
|
-
|
|
29355
|
-
|
|
29634
|
+
const m1 = ` \u2713 Push / create PR`;
|
|
29635
|
+
const m2 = ` PR created: ${prResult.prUrl}`;
|
|
29636
|
+
const m3 = ` \u2192 Next: merge the PR, then CI will publish to npm @${resolvedChannel}`;
|
|
29637
|
+
steps.push(m1, m2, m3);
|
|
29638
|
+
console.log(m1);
|
|
29639
|
+
console.log(m2);
|
|
29640
|
+
console.log(m3);
|
|
29356
29641
|
} else if (prResult.mode === "skipped") {
|
|
29357
|
-
|
|
29358
|
-
|
|
29642
|
+
const m1 = ` \u2713 Push / create PR`;
|
|
29643
|
+
const m2 = ` PR already exists: ${prResult.prUrl}`;
|
|
29644
|
+
steps.push(m1, m2);
|
|
29645
|
+
console.log(m1);
|
|
29646
|
+
console.log(m2);
|
|
29359
29647
|
} else {
|
|
29360
|
-
|
|
29361
|
-
|
|
29648
|
+
const m1 = ` ! Push / create PR \u2014 manual PR required:`;
|
|
29649
|
+
const m2 = prResult.instructions ?? "";
|
|
29650
|
+
steps.push(m1, m2);
|
|
29651
|
+
console.log(m1);
|
|
29652
|
+
console.log(m2);
|
|
29362
29653
|
}
|
|
29363
29654
|
} else {
|
|
29364
29655
|
try {
|
|
29365
29656
|
execFileSync8("git", ["push", remote ?? "origin", "--follow-tags"], gitCwd);
|
|
29366
|
-
logStep(7,
|
|
29657
|
+
logStep(7, 8, "Push / create PR", true);
|
|
29367
29658
|
} catch (err) {
|
|
29368
29659
|
const execError = err;
|
|
29369
29660
|
const msg = (execError.stderr ?? execError.message ?? "").slice(0, 500);
|
|
29370
|
-
logStep(7,
|
|
29661
|
+
logStep(7, 8, "Push / create PR", false, `git push failed: ${msg}`);
|
|
29371
29662
|
return engineError("E_GENERAL", `git push failed: ${msg}`, {
|
|
29372
29663
|
details: { exitCode: execError.status }
|
|
29373
29664
|
});
|
|
@@ -29385,6 +29676,7 @@ async function releaseShip(params, projectRoot) {
|
|
|
29385
29676
|
pushedAt,
|
|
29386
29677
|
changelog: changelogPath,
|
|
29387
29678
|
channel: resolvedChannel,
|
|
29679
|
+
steps,
|
|
29388
29680
|
...prResult ? {
|
|
29389
29681
|
pr: {
|
|
29390
29682
|
mode: prResult.mode,
|
|
@@ -29409,13 +29701,14 @@ var init_release_engine = __esm({
|
|
|
29409
29701
|
init_github_pr();
|
|
29410
29702
|
init_channel();
|
|
29411
29703
|
init_release_config();
|
|
29704
|
+
init_version_bump();
|
|
29412
29705
|
init_error();
|
|
29413
29706
|
}
|
|
29414
29707
|
});
|
|
29415
29708
|
|
|
29416
29709
|
// src/dispatch/engines/template-parser.ts
|
|
29417
|
-
import { readFileSync as
|
|
29418
|
-
import { join as
|
|
29710
|
+
import { readFileSync as readFileSync40, readdirSync as readdirSync12, existsSync as existsSync52 } from "fs";
|
|
29711
|
+
import { join as join50 } from "path";
|
|
29419
29712
|
import { parse as parseYaml } from "yaml";
|
|
29420
29713
|
function deriveSubcommand(filename) {
|
|
29421
29714
|
let stem = filename.replace(/\.ya?ml$/i, "");
|
|
@@ -29429,8 +29722,8 @@ function deriveSubcommand(filename) {
|
|
|
29429
29722
|
return firstWord.toLowerCase();
|
|
29430
29723
|
}
|
|
29431
29724
|
function parseTemplateFile(templateDir, filename) {
|
|
29432
|
-
const filePath =
|
|
29433
|
-
const raw =
|
|
29725
|
+
const filePath = join50(templateDir, filename);
|
|
29726
|
+
const raw = readFileSync40(filePath, "utf-8");
|
|
29434
29727
|
const parsed = parseYaml(raw);
|
|
29435
29728
|
const name = typeof parsed.name === "string" ? parsed.name : filename;
|
|
29436
29729
|
const titlePrefix = typeof parsed.title === "string" ? parsed.title : "";
|
|
@@ -29479,8 +29772,8 @@ function parseTemplateFile(templateDir, filename) {
|
|
|
29479
29772
|
};
|
|
29480
29773
|
}
|
|
29481
29774
|
function parseIssueTemplates(projectRoot) {
|
|
29482
|
-
const templateDir =
|
|
29483
|
-
if (!
|
|
29775
|
+
const templateDir = join50(projectRoot, ".github", "ISSUE_TEMPLATE");
|
|
29776
|
+
if (!existsSync52(templateDir)) {
|
|
29484
29777
|
return engineError("E_NOT_FOUND", `Issue template directory not found: ${templateDir}`);
|
|
29485
29778
|
}
|
|
29486
29779
|
let files;
|
|
@@ -31159,26 +31452,26 @@ var init_check = __esm({
|
|
|
31159
31452
|
});
|
|
31160
31453
|
|
|
31161
31454
|
// src/core/adrs/validate.ts
|
|
31162
|
-
import { readFileSync as
|
|
31163
|
-
import { join as
|
|
31455
|
+
import { readFileSync as readFileSync41, readdirSync as readdirSync13, existsSync as existsSync53 } from "node:fs";
|
|
31456
|
+
import { join as join51 } from "node:path";
|
|
31164
31457
|
import AjvModule3 from "ajv";
|
|
31165
31458
|
async function validateAllAdrs(projectRoot) {
|
|
31166
|
-
const adrsDir =
|
|
31167
|
-
const schemaPath =
|
|
31168
|
-
if (!
|
|
31459
|
+
const adrsDir = join51(projectRoot, ".cleo", "adrs");
|
|
31460
|
+
const schemaPath = join51(projectRoot, "schemas", "adr-frontmatter.schema.json");
|
|
31461
|
+
if (!existsSync53(schemaPath)) {
|
|
31169
31462
|
return {
|
|
31170
31463
|
valid: false,
|
|
31171
31464
|
errors: [{ file: "schemas/adr-frontmatter.schema.json", field: "schema", message: "Schema file not found" }],
|
|
31172
31465
|
checked: 0
|
|
31173
31466
|
};
|
|
31174
31467
|
}
|
|
31175
|
-
if (!
|
|
31468
|
+
if (!existsSync53(adrsDir)) {
|
|
31176
31469
|
return { valid: true, errors: [], checked: 0 };
|
|
31177
31470
|
}
|
|
31178
|
-
const schema = JSON.parse(
|
|
31471
|
+
const schema = JSON.parse(readFileSync41(schemaPath, "utf-8"));
|
|
31179
31472
|
const ajv = new Ajv3({ allErrors: true });
|
|
31180
31473
|
const validate = ajv.compile(schema);
|
|
31181
|
-
const files = readdirSync13(adrsDir).filter((f) => f.endsWith(".md") && f.startsWith("ADR-")).map((f) =>
|
|
31474
|
+
const files = readdirSync13(adrsDir).filter((f) => f.endsWith(".md") && f.startsWith("ADR-")).map((f) => join51(adrsDir, f));
|
|
31182
31475
|
const errors = [];
|
|
31183
31476
|
for (const filePath of files) {
|
|
31184
31477
|
const record = parseAdrFile(filePath, projectRoot);
|
|
@@ -31205,15 +31498,15 @@ var init_validate = __esm({
|
|
|
31205
31498
|
});
|
|
31206
31499
|
|
|
31207
31500
|
// src/core/adrs/list.ts
|
|
31208
|
-
import { readdirSync as readdirSync14, existsSync as
|
|
31209
|
-
import { join as
|
|
31501
|
+
import { readdirSync as readdirSync14, existsSync as existsSync54 } from "node:fs";
|
|
31502
|
+
import { join as join52 } from "node:path";
|
|
31210
31503
|
async function listAdrs(projectRoot, opts) {
|
|
31211
|
-
const adrsDir =
|
|
31212
|
-
if (!
|
|
31504
|
+
const adrsDir = join52(projectRoot, ".cleo", "adrs");
|
|
31505
|
+
if (!existsSync54(adrsDir)) {
|
|
31213
31506
|
return { adrs: [], total: 0 };
|
|
31214
31507
|
}
|
|
31215
31508
|
const files = readdirSync14(adrsDir).filter((f) => f.endsWith(".md") && f.startsWith("ADR-")).sort();
|
|
31216
|
-
const records = files.map((f) => parseAdrFile(
|
|
31509
|
+
const records = files.map((f) => parseAdrFile(join52(adrsDir, f), projectRoot));
|
|
31217
31510
|
const filtered = records.filter((r) => {
|
|
31218
31511
|
if (opts?.status && r.frontmatter.Status !== opts.status) return false;
|
|
31219
31512
|
if (opts?.since && r.frontmatter.Date < opts.since) return false;
|
|
@@ -31238,14 +31531,14 @@ var init_list2 = __esm({
|
|
|
31238
31531
|
});
|
|
31239
31532
|
|
|
31240
31533
|
// src/core/adrs/show.ts
|
|
31241
|
-
import { existsSync as
|
|
31242
|
-
import { join as
|
|
31534
|
+
import { existsSync as existsSync55, readdirSync as readdirSync15 } from "node:fs";
|
|
31535
|
+
import { join as join53 } from "node:path";
|
|
31243
31536
|
async function showAdr(projectRoot, adrId) {
|
|
31244
|
-
const adrsDir =
|
|
31245
|
-
if (!
|
|
31537
|
+
const adrsDir = join53(projectRoot, ".cleo", "adrs");
|
|
31538
|
+
if (!existsSync55(adrsDir)) return null;
|
|
31246
31539
|
const files = readdirSync15(adrsDir).filter((f) => f.startsWith(adrId) && f.endsWith(".md"));
|
|
31247
31540
|
if (files.length === 0) return null;
|
|
31248
|
-
const filePath =
|
|
31541
|
+
const filePath = join53(adrsDir, files[0]);
|
|
31249
31542
|
return parseAdrFile(filePath, projectRoot);
|
|
31250
31543
|
}
|
|
31251
31544
|
var init_show2 = __esm({
|
|
@@ -31256,8 +31549,8 @@ var init_show2 = __esm({
|
|
|
31256
31549
|
});
|
|
31257
31550
|
|
|
31258
31551
|
// src/core/adrs/find.ts
|
|
31259
|
-
import { readdirSync as readdirSync16, existsSync as
|
|
31260
|
-
import { join as
|
|
31552
|
+
import { readdirSync as readdirSync16, existsSync as existsSync56 } from "node:fs";
|
|
31553
|
+
import { join as join54 } from "node:path";
|
|
31261
31554
|
function normalise(s) {
|
|
31262
31555
|
return s.toLowerCase().replace(/[^a-z0-9\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
31263
31556
|
}
|
|
@@ -31274,8 +31567,8 @@ function matchedTerms(target, terms) {
|
|
|
31274
31567
|
return terms.filter((term) => t.includes(term));
|
|
31275
31568
|
}
|
|
31276
31569
|
async function findAdrs(projectRoot, query, opts) {
|
|
31277
|
-
const adrsDir =
|
|
31278
|
-
if (!
|
|
31570
|
+
const adrsDir = join54(projectRoot, ".cleo", "adrs");
|
|
31571
|
+
if (!existsSync56(adrsDir)) {
|
|
31279
31572
|
return { adrs: [], query, total: 0 };
|
|
31280
31573
|
}
|
|
31281
31574
|
const files = readdirSync16(adrsDir).filter((f) => f.endsWith(".md") && f.startsWith("ADR-")).sort();
|
|
@@ -31284,7 +31577,7 @@ async function findAdrs(projectRoot, query, opts) {
|
|
|
31284
31577
|
const filterKeywords = opts?.keywords ? parseTags(opts.keywords) : null;
|
|
31285
31578
|
const results = [];
|
|
31286
31579
|
for (const file of files) {
|
|
31287
|
-
const record = parseAdrFile(
|
|
31580
|
+
const record = parseAdrFile(join54(adrsDir, file), projectRoot);
|
|
31288
31581
|
const fm = record.frontmatter;
|
|
31289
31582
|
if (opts?.status && fm.Status !== opts.status) continue;
|
|
31290
31583
|
if (filterTopics && filterTopics.length > 0) {
|
|
@@ -31362,12 +31655,12 @@ var init_adrs = __esm({
|
|
|
31362
31655
|
});
|
|
31363
31656
|
|
|
31364
31657
|
// src/core/admin/sync.ts
|
|
31365
|
-
import { join as
|
|
31658
|
+
import { join as join55 } from "node:path";
|
|
31366
31659
|
import { rm as rm2, rmdir, stat as stat2 } from "node:fs/promises";
|
|
31367
31660
|
async function getSyncStatus(projectRoot) {
|
|
31368
31661
|
try {
|
|
31369
31662
|
const cleoDir = getCleoDir(projectRoot);
|
|
31370
|
-
const stateFile =
|
|
31663
|
+
const stateFile = join55(cleoDir, "sync", "todowrite-session.json");
|
|
31371
31664
|
const sessionState = await readJson(stateFile);
|
|
31372
31665
|
if (!sessionState) {
|
|
31373
31666
|
return {
|
|
@@ -31411,8 +31704,8 @@ async function getSyncStatus(projectRoot) {
|
|
|
31411
31704
|
async function clearSyncState(projectRoot, dryRun) {
|
|
31412
31705
|
try {
|
|
31413
31706
|
const cleoDir = getCleoDir(projectRoot);
|
|
31414
|
-
const syncDir =
|
|
31415
|
-
const stateFile =
|
|
31707
|
+
const syncDir = join55(cleoDir, "sync");
|
|
31708
|
+
const stateFile = join55(syncDir, "todowrite-session.json");
|
|
31416
31709
|
let exists = false;
|
|
31417
31710
|
try {
|
|
31418
31711
|
await stat2(stateFile);
|
|
@@ -32179,8 +32472,8 @@ var init_import_tasks = __esm({
|
|
|
32179
32472
|
// src/core/snapshot/index.ts
|
|
32180
32473
|
import { createHash as createHash8 } from "node:crypto";
|
|
32181
32474
|
import { readFile as readFile13, writeFile as writeFile10, mkdir as mkdir10 } from "node:fs/promises";
|
|
32182
|
-
import { existsSync as
|
|
32183
|
-
import { join as
|
|
32475
|
+
import { existsSync as existsSync57 } from "node:fs";
|
|
32476
|
+
import { join as join56, dirname as dirname14 } from "node:path";
|
|
32184
32477
|
function toSnapshotTask(task) {
|
|
32185
32478
|
return {
|
|
32186
32479
|
id: task.id,
|
|
@@ -32233,7 +32526,7 @@ async function exportSnapshot(cwd) {
|
|
|
32233
32526
|
}
|
|
32234
32527
|
async function writeSnapshot(snapshot, outputPath) {
|
|
32235
32528
|
const dir = dirname14(outputPath);
|
|
32236
|
-
if (!
|
|
32529
|
+
if (!existsSync57(dir)) {
|
|
32237
32530
|
await mkdir10(dir, { recursive: true });
|
|
32238
32531
|
}
|
|
32239
32532
|
await writeFile10(outputPath, JSON.stringify(snapshot, null, 2) + "\n");
|
|
@@ -32249,7 +32542,7 @@ async function readSnapshot(inputPath) {
|
|
|
32249
32542
|
function getDefaultSnapshotPath(cwd) {
|
|
32250
32543
|
const cleoDir = getCleoDirAbsolute(cwd);
|
|
32251
32544
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
32252
|
-
return
|
|
32545
|
+
return join56(cleoDir, "snapshots", `snapshot-${timestamp}.json`);
|
|
32253
32546
|
}
|
|
32254
32547
|
async function importSnapshot(snapshot, cwd) {
|
|
32255
32548
|
const accessor = await getAccessor(cwd);
|
|
@@ -32692,15 +32985,15 @@ var init_field_filter = __esm({
|
|
|
32692
32985
|
});
|
|
32693
32986
|
|
|
32694
32987
|
// src/core/project-info.ts
|
|
32695
|
-
import { readFileSync as
|
|
32696
|
-
import { join as
|
|
32988
|
+
import { readFileSync as readFileSync42, existsSync as existsSync58 } from "node:fs";
|
|
32989
|
+
import { join as join57 } from "node:path";
|
|
32697
32990
|
function getProjectInfoSync(cwd) {
|
|
32698
32991
|
const projectRoot = cwd ?? process.cwd();
|
|
32699
32992
|
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
32700
|
-
const infoPath =
|
|
32701
|
-
if (!
|
|
32993
|
+
const infoPath = join57(cleoDir, "project-info.json");
|
|
32994
|
+
if (!existsSync58(infoPath)) return null;
|
|
32702
32995
|
try {
|
|
32703
|
-
const raw =
|
|
32996
|
+
const raw = readFileSync42(infoPath, "utf-8");
|
|
32704
32997
|
const data = JSON.parse(raw);
|
|
32705
32998
|
if (typeof data.projectHash !== "string" || data.projectHash.length === 0) {
|
|
32706
32999
|
return null;
|
|
@@ -32928,13 +33221,13 @@ var init_field_context = __esm({
|
|
|
32928
33221
|
});
|
|
32929
33222
|
|
|
32930
33223
|
// src/core/sessions/context-alert.ts
|
|
32931
|
-
import { existsSync as
|
|
32932
|
-
import { join as
|
|
33224
|
+
import { existsSync as existsSync59, readFileSync as readFileSync43, writeFileSync as writeFileSync9 } from "node:fs";
|
|
33225
|
+
import { join as join58 } from "node:path";
|
|
32933
33226
|
function getCurrentSessionId(cwd) {
|
|
32934
33227
|
if (process.env.CLEO_SESSION) return process.env.CLEO_SESSION;
|
|
32935
|
-
const sessionFile =
|
|
32936
|
-
if (
|
|
32937
|
-
return
|
|
33228
|
+
const sessionFile = join58(getCleoDir(cwd), ".current-session");
|
|
33229
|
+
if (existsSync59(sessionFile)) {
|
|
33230
|
+
return readFileSync43(sessionFile, "utf-8").trim() || null;
|
|
32938
33231
|
}
|
|
32939
33232
|
return null;
|
|
32940
33233
|
}
|
|
@@ -33982,7 +34275,7 @@ async function stopTask2(sessionId, cwd) {
|
|
|
33982
34275
|
}
|
|
33983
34276
|
async function workHistory(sessionId, limit = 50, cwd) {
|
|
33984
34277
|
const db = await getDb(cwd);
|
|
33985
|
-
const rows = await db.select().from(taskWorkHistory).where(eq16(taskWorkHistory.sessionId, sessionId)).orderBy(desc5(taskWorkHistory.setAt)).limit(limit).all();
|
|
34278
|
+
const rows = await db.select().from(taskWorkHistory).where(eq16(taskWorkHistory.sessionId, sessionId)).orderBy(desc5(taskWorkHistory.setAt), desc5(taskWorkHistory.id)).limit(limit).all();
|
|
33986
34279
|
return rows.map((r) => ({
|
|
33987
34280
|
taskId: r.taskId,
|
|
33988
34281
|
setAt: r.setAt,
|
|
@@ -34335,8 +34628,8 @@ __export(session_grade_exports, {
|
|
|
34335
34628
|
gradeSession: () => gradeSession,
|
|
34336
34629
|
readGrades: () => readGrades
|
|
34337
34630
|
});
|
|
34338
|
-
import { join as
|
|
34339
|
-
import { existsSync as
|
|
34631
|
+
import { join as join59 } from "node:path";
|
|
34632
|
+
import { existsSync as existsSync60 } from "node:fs";
|
|
34340
34633
|
import { readFile as readFile14, appendFile, mkdir as mkdir11 } from "node:fs/promises";
|
|
34341
34634
|
async function gradeSession(sessionId, cwd) {
|
|
34342
34635
|
const sessionEntries = await queryAudit({ sessionId });
|
|
@@ -34516,9 +34809,9 @@ function detectDuplicateCreates(entries) {
|
|
|
34516
34809
|
async function appendGradeResult(result, cwd) {
|
|
34517
34810
|
try {
|
|
34518
34811
|
const cleoDir = getCleoDirAbsolute(cwd);
|
|
34519
|
-
const metricsDir =
|
|
34812
|
+
const metricsDir = join59(cleoDir, "metrics");
|
|
34520
34813
|
await mkdir11(metricsDir, { recursive: true });
|
|
34521
|
-
const gradesPath =
|
|
34814
|
+
const gradesPath = join59(metricsDir, "GRADES.jsonl");
|
|
34522
34815
|
const line = JSON.stringify({ ...result, evaluator: "auto" }) + "\n";
|
|
34523
34816
|
await appendFile(gradesPath, line, "utf8");
|
|
34524
34817
|
} catch {
|
|
@@ -34527,8 +34820,8 @@ async function appendGradeResult(result, cwd) {
|
|
|
34527
34820
|
async function readGrades(sessionId, cwd) {
|
|
34528
34821
|
try {
|
|
34529
34822
|
const cleoDir = getCleoDirAbsolute(cwd);
|
|
34530
|
-
const gradesPath =
|
|
34531
|
-
if (!
|
|
34823
|
+
const gradesPath = join59(cleoDir, "metrics", "GRADES.jsonl");
|
|
34824
|
+
if (!existsSync60(gradesPath)) return [];
|
|
34532
34825
|
const content = await readFile14(gradesPath, "utf8");
|
|
34533
34826
|
const results = content.split("\n").filter((l) => l.trim()).map((l) => JSON.parse(l));
|
|
34534
34827
|
return sessionId ? results.filter((r) => r.sessionId === sessionId) : results;
|
|
@@ -36882,6 +37175,7 @@ var init_pipeline2 = __esm({
|
|
|
36882
37175
|
"release.push",
|
|
36883
37176
|
"release.gates.run",
|
|
36884
37177
|
"release.rollback",
|
|
37178
|
+
"release.cancel",
|
|
36885
37179
|
"release.ship",
|
|
36886
37180
|
"manifest.append",
|
|
36887
37181
|
"manifest.archive",
|
|
@@ -37246,6 +37540,20 @@ var init_pipeline2 = __esm({
|
|
|
37246
37540
|
const result = await releaseRollback(version, reason, this.projectRoot);
|
|
37247
37541
|
return this.wrapEngineResult(result, "mutate", "release.rollback", startTime);
|
|
37248
37542
|
}
|
|
37543
|
+
case "cancel": {
|
|
37544
|
+
const version = params?.version;
|
|
37545
|
+
if (!version) {
|
|
37546
|
+
return this.errorResponse(
|
|
37547
|
+
"mutate",
|
|
37548
|
+
"release.cancel",
|
|
37549
|
+
"E_INVALID_INPUT",
|
|
37550
|
+
"version is required",
|
|
37551
|
+
startTime
|
|
37552
|
+
);
|
|
37553
|
+
}
|
|
37554
|
+
const result = await releaseCancel(version, this.projectRoot);
|
|
37555
|
+
return this.wrapEngineResult(result, "mutate", "release.cancel", startTime);
|
|
37556
|
+
}
|
|
37249
37557
|
case "ship": {
|
|
37250
37558
|
const version = params?.version;
|
|
37251
37559
|
const epicId = params?.epicId;
|
|
@@ -37260,8 +37568,9 @@ var init_pipeline2 = __esm({
|
|
|
37260
37568
|
}
|
|
37261
37569
|
const remote = params?.remote;
|
|
37262
37570
|
const dryRun = params?.dryRun;
|
|
37571
|
+
const bump = params?.bump;
|
|
37263
37572
|
const result = await releaseShip(
|
|
37264
|
-
{ version, epicId, remote, dryRun },
|
|
37573
|
+
{ version, epicId, remote, dryRun, bump },
|
|
37265
37574
|
this.projectRoot
|
|
37266
37575
|
);
|
|
37267
37576
|
return this.wrapEngineResult(result, "mutate", "release.ship", startTime);
|
|
@@ -37787,7 +38096,7 @@ var init_build_config = __esm({
|
|
|
37787
38096
|
"use strict";
|
|
37788
38097
|
BUILD_CONFIG = {
|
|
37789
38098
|
"name": "@cleocode/cleo",
|
|
37790
|
-
"version": "2026.3.
|
|
38099
|
+
"version": "2026.3.18",
|
|
37791
38100
|
"description": "CLEO V2 - TypeScript task management CLI for AI coding agents",
|
|
37792
38101
|
"repository": {
|
|
37793
38102
|
"owner": "kryptobaseddev",
|
|
@@ -37796,7 +38105,7 @@ var init_build_config = __esm({
|
|
|
37796
38105
|
"url": "https://github.com/kryptobaseddev/cleo.git",
|
|
37797
38106
|
"issuesUrl": "https://github.com/kryptobaseddev/cleo/issues"
|
|
37798
38107
|
},
|
|
37799
|
-
"buildDate": "2026-03-
|
|
38108
|
+
"buildDate": "2026-03-07T20:24:31.815Z",
|
|
37800
38109
|
"templates": {
|
|
37801
38110
|
"issueTemplatesDir": "templates/issue-templates"
|
|
37802
38111
|
}
|
|
@@ -37805,8 +38114,8 @@ var init_build_config = __esm({
|
|
|
37805
38114
|
});
|
|
37806
38115
|
|
|
37807
38116
|
// src/core/issue/template-parser.ts
|
|
37808
|
-
import { existsSync as
|
|
37809
|
-
import { join as
|
|
38117
|
+
import { existsSync as existsSync61, readFileSync as readFileSync44, readdirSync as readdirSync17, writeFileSync as writeFileSync10 } from "node:fs";
|
|
38118
|
+
import { join as join60, basename as basename10 } from "node:path";
|
|
37810
38119
|
function extractYamlField(content, field) {
|
|
37811
38120
|
const regex = new RegExp(`^${field}:\\s*["']?(.+?)["']?\\s*$`, "m");
|
|
37812
38121
|
const match = content.match(regex);
|
|
@@ -37838,9 +38147,9 @@ function extractYamlArray(content, field) {
|
|
|
37838
38147
|
return items;
|
|
37839
38148
|
}
|
|
37840
38149
|
function parseTemplateFile2(filePath) {
|
|
37841
|
-
if (!
|
|
38150
|
+
if (!existsSync61(filePath)) return null;
|
|
37842
38151
|
try {
|
|
37843
|
-
const content =
|
|
38152
|
+
const content = readFileSync44(filePath, "utf-8");
|
|
37844
38153
|
const fileName = basename10(filePath);
|
|
37845
38154
|
const stem = fileName.replace(/\.ya?ml$/, "");
|
|
37846
38155
|
const name = extractYamlField(content, "name");
|
|
@@ -37857,12 +38166,12 @@ function parseTemplateFile2(filePath) {
|
|
|
37857
38166
|
function parseIssueTemplates2(projectDir) {
|
|
37858
38167
|
try {
|
|
37859
38168
|
const packageRoot = getPackageRoot();
|
|
37860
|
-
const packagedTemplateDir =
|
|
37861
|
-
if (
|
|
38169
|
+
const packagedTemplateDir = join60(packageRoot, PACKAGED_TEMPLATE_DIR);
|
|
38170
|
+
if (existsSync61(packagedTemplateDir)) {
|
|
37862
38171
|
const templates3 = [];
|
|
37863
38172
|
for (const file of readdirSync17(packagedTemplateDir)) {
|
|
37864
38173
|
if (!file.endsWith(".yml") && !file.endsWith(".yaml")) continue;
|
|
37865
|
-
const template = parseTemplateFile2(
|
|
38174
|
+
const template = parseTemplateFile2(join60(packagedTemplateDir, file));
|
|
37866
38175
|
if (template) templates3.push(template);
|
|
37867
38176
|
}
|
|
37868
38177
|
if (templates3.length > 0) return templates3;
|
|
@@ -37870,12 +38179,12 @@ function parseIssueTemplates2(projectDir) {
|
|
|
37870
38179
|
} catch {
|
|
37871
38180
|
}
|
|
37872
38181
|
const dir = projectDir ?? getProjectRoot();
|
|
37873
|
-
const templateDir =
|
|
37874
|
-
if (!
|
|
38182
|
+
const templateDir = join60(dir, TEMPLATE_DIR);
|
|
38183
|
+
if (!existsSync61(templateDir)) return [];
|
|
37875
38184
|
const templates2 = [];
|
|
37876
38185
|
for (const file of readdirSync17(templateDir)) {
|
|
37877
38186
|
if (!file.endsWith(".yml") && !file.endsWith(".yaml")) continue;
|
|
37878
|
-
const template = parseTemplateFile2(
|
|
38187
|
+
const template = parseTemplateFile2(join60(templateDir, file));
|
|
37879
38188
|
if (template) templates2.push(template);
|
|
37880
38189
|
}
|
|
37881
38190
|
return templates2;
|
|
@@ -37884,10 +38193,10 @@ function getTemplateConfig(cwd) {
|
|
|
37884
38193
|
const projectDir = cwd ?? getProjectRoot();
|
|
37885
38194
|
const liveTemplates = parseIssueTemplates2(projectDir);
|
|
37886
38195
|
if (liveTemplates.length > 0) return liveTemplates;
|
|
37887
|
-
const cachePath =
|
|
37888
|
-
if (
|
|
38196
|
+
const cachePath = join60(getCleoDir(cwd), CACHE_FILE);
|
|
38197
|
+
if (existsSync61(cachePath)) {
|
|
37889
38198
|
try {
|
|
37890
|
-
const cached = JSON.parse(
|
|
38199
|
+
const cached = JSON.parse(readFileSync44(cachePath, "utf-8"));
|
|
37891
38200
|
if (cached.templates?.length > 0) return cached.templates;
|
|
37892
38201
|
} catch {
|
|
37893
38202
|
}
|
|
@@ -38946,8 +39255,8 @@ var init_tools = __esm({
|
|
|
38946
39255
|
});
|
|
38947
39256
|
|
|
38948
39257
|
// src/core/nexus/query.ts
|
|
38949
|
-
import { join as
|
|
38950
|
-
import { existsSync as
|
|
39258
|
+
import { join as join61, basename as basename11 } from "node:path";
|
|
39259
|
+
import { existsSync as existsSync62, readFileSync as readFileSync45 } from "node:fs";
|
|
38951
39260
|
import { z as z3 } from "zod";
|
|
38952
39261
|
function validateSyntax(query) {
|
|
38953
39262
|
if (!query) return false;
|
|
@@ -38983,9 +39292,9 @@ function getCurrentProject() {
|
|
|
38983
39292
|
return process.env["NEXUS_CURRENT_PROJECT"];
|
|
38984
39293
|
}
|
|
38985
39294
|
try {
|
|
38986
|
-
const infoPath =
|
|
38987
|
-
if (
|
|
38988
|
-
const data = JSON.parse(
|
|
39295
|
+
const infoPath = join61(process.cwd(), ".cleo", "project-info.json");
|
|
39296
|
+
if (existsSync62(infoPath)) {
|
|
39297
|
+
const data = JSON.parse(readFileSync45(infoPath, "utf-8"));
|
|
38989
39298
|
if (typeof data.name === "string" && data.name.length > 0) {
|
|
38990
39299
|
return data.name;
|
|
38991
39300
|
}
|
|
@@ -39021,7 +39330,7 @@ async function resolveProjectPath2(projectName) {
|
|
|
39021
39330
|
return project.path;
|
|
39022
39331
|
}
|
|
39023
39332
|
async function readProjectTasks(projectPath) {
|
|
39024
|
-
const tasksDbPath =
|
|
39333
|
+
const tasksDbPath = join61(projectPath, ".cleo", "tasks.db");
|
|
39025
39334
|
try {
|
|
39026
39335
|
const accessor = await getAccessor(projectPath);
|
|
39027
39336
|
const taskFile = await accessor.loadTaskFile();
|
|
@@ -39435,8 +39744,8 @@ var init_deps2 = __esm({
|
|
|
39435
39744
|
|
|
39436
39745
|
// src/core/nexus/sharing/index.ts
|
|
39437
39746
|
import { readFile as readFile15, writeFile as writeFile11 } from "node:fs/promises";
|
|
39438
|
-
import { existsSync as
|
|
39439
|
-
import { join as
|
|
39747
|
+
import { existsSync as existsSync63, readdirSync as readdirSync18, statSync as statSync9 } from "node:fs";
|
|
39748
|
+
import { join as join62, relative as relative5 } from "node:path";
|
|
39440
39749
|
function matchesPattern(filePath, pattern) {
|
|
39441
39750
|
const normalizedPath = filePath.replace(/^\/+|\/+$/g, "");
|
|
39442
39751
|
const normalizedPattern = pattern.replace(/^\/+|\/+$/g, "");
|
|
@@ -39461,7 +39770,7 @@ function collectCleoFiles(cleoDir) {
|
|
|
39461
39770
|
const entries = readdirSync18(dir);
|
|
39462
39771
|
for (const entry of entries) {
|
|
39463
39772
|
if (entry === ".git") continue;
|
|
39464
|
-
const fullPath =
|
|
39773
|
+
const fullPath = join62(dir, entry);
|
|
39465
39774
|
const relPath = relative5(cleoDir, fullPath);
|
|
39466
39775
|
try {
|
|
39467
39776
|
const stat3 = statSync9(fullPath);
|
|
@@ -39521,7 +39830,7 @@ function generateGitignoreEntries(sharing) {
|
|
|
39521
39830
|
async function syncGitignore(cwd) {
|
|
39522
39831
|
const config = await loadConfig2(cwd);
|
|
39523
39832
|
const projectRoot = getProjectRoot(cwd);
|
|
39524
|
-
const gitignorePath =
|
|
39833
|
+
const gitignorePath = join62(projectRoot, ".gitignore");
|
|
39525
39834
|
const entries = generateGitignoreEntries(config.sharing);
|
|
39526
39835
|
const managedSection = [
|
|
39527
39836
|
"",
|
|
@@ -39531,7 +39840,7 @@ async function syncGitignore(cwd) {
|
|
|
39531
39840
|
""
|
|
39532
39841
|
].join("\n");
|
|
39533
39842
|
let content = "";
|
|
39534
|
-
if (
|
|
39843
|
+
if (existsSync63(gitignorePath)) {
|
|
39535
39844
|
content = await readFile15(gitignorePath, "utf-8");
|
|
39536
39845
|
}
|
|
39537
39846
|
const startIdx = content.indexOf(GITIGNORE_START);
|
|
@@ -43649,7 +43958,7 @@ init_logger();
|
|
|
43649
43958
|
init_project_info();
|
|
43650
43959
|
init_scaffold();
|
|
43651
43960
|
init_audit_prune();
|
|
43652
|
-
import { join as
|
|
43961
|
+
import { join as join63 } from "node:path";
|
|
43653
43962
|
var serverState = null;
|
|
43654
43963
|
var startupLog = getLogger("mcp:startup");
|
|
43655
43964
|
async function main() {
|
|
@@ -43719,7 +44028,7 @@ async function main() {
|
|
|
43719
44028
|
}
|
|
43720
44029
|
const config = loadConfig();
|
|
43721
44030
|
const projectInfo = getProjectInfoSync();
|
|
43722
|
-
const cleoDir =
|
|
44031
|
+
const cleoDir = join63(process.cwd(), ".cleo");
|
|
43723
44032
|
initLogger(cleoDir, {
|
|
43724
44033
|
level: config.logLevel ?? "info",
|
|
43725
44034
|
filePath: "logs/cleo.log",
|