@cleocode/cleo 2026.3.29 → 2026.3.31
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 +591 -332
- package/dist/cli/index.js.map +4 -4
- package/dist/mcp/index.js +576 -341
- package/dist/mcp/index.js.map +4 -4
- package/package.json +1 -1
- package/server.json +1 -1
- package/templates/CLEO-INJECTION.md +11 -0
package/dist/mcp/index.js
CHANGED
|
@@ -4599,6 +4599,118 @@ var init_handoff = __esm({
|
|
|
4599
4599
|
}
|
|
4600
4600
|
});
|
|
4601
4601
|
|
|
4602
|
+
// src/core/metrics/provider-detection.ts
|
|
4603
|
+
var provider_detection_exports = {};
|
|
4604
|
+
__export(provider_detection_exports, {
|
|
4605
|
+
detectRuntimeProviderContext: () => detectRuntimeProviderContext,
|
|
4606
|
+
resetRuntimeProviderContextCache: () => resetRuntimeProviderContextCache,
|
|
4607
|
+
selectRuntimeProviderContext: () => selectRuntimeProviderContext
|
|
4608
|
+
});
|
|
4609
|
+
import { basename as basename2 } from "node:path";
|
|
4610
|
+
import {
|
|
4611
|
+
detectProjectProviders,
|
|
4612
|
+
getProvider,
|
|
4613
|
+
resolveAlias
|
|
4614
|
+
} from "@cleocode/caamp";
|
|
4615
|
+
function inferProviderFromVendor(vendor) {
|
|
4616
|
+
const value = (vendor ?? "").trim().toLowerCase();
|
|
4617
|
+
if (!value) return void 0;
|
|
4618
|
+
if (value.includes("anthropic") || value.includes("claude")) return "anthropic";
|
|
4619
|
+
if (value.includes("openai") || value.includes("codex") || value.includes("chatgpt"))
|
|
4620
|
+
return "openai";
|
|
4621
|
+
if (value.includes("google") || value.includes("gemini")) return "google";
|
|
4622
|
+
if (value.includes("xai") || value.includes("grok")) return "xai";
|
|
4623
|
+
return void 0;
|
|
4624
|
+
}
|
|
4625
|
+
function getRuntimeHints(snapshot) {
|
|
4626
|
+
const argv = snapshot.argv ?? process.argv;
|
|
4627
|
+
const env = snapshot.env ?? process.env;
|
|
4628
|
+
const hints = /* @__PURE__ */ new Set();
|
|
4629
|
+
const bin = basename2(argv[1] ?? argv[0] ?? "").replace(/\.[^.]+$/, "");
|
|
4630
|
+
if (bin) hints.add(bin);
|
|
4631
|
+
if (env["CLAUDE_CODE_ENABLE_TELEMETRY"] || env["CLAUDE_CODE_ENTRYPOINT"]) {
|
|
4632
|
+
hints.add("claude-code");
|
|
4633
|
+
hints.add("claude");
|
|
4634
|
+
}
|
|
4635
|
+
if (env["OPENCODE_AGENT"] || env["OPENCODE"]) {
|
|
4636
|
+
hints.add("opencode");
|
|
4637
|
+
}
|
|
4638
|
+
if (env["CURSOR_TRACE_ID"] || env["CURSOR_AGENT"]) {
|
|
4639
|
+
hints.add("cursor");
|
|
4640
|
+
}
|
|
4641
|
+
return Array.from(hints);
|
|
4642
|
+
}
|
|
4643
|
+
function pickDetectionByHint(detections, hints) {
|
|
4644
|
+
for (const hint of hints) {
|
|
4645
|
+
const resolved = resolveAlias(hint);
|
|
4646
|
+
const direct = detections.find(
|
|
4647
|
+
(entry) => entry.provider.id === resolved || entry.provider.id === hint
|
|
4648
|
+
);
|
|
4649
|
+
if (direct) return direct;
|
|
4650
|
+
const byAlias = detections.find(
|
|
4651
|
+
(entry) => entry.provider.aliases.includes(hint) || entry.provider.agentFlag === hint || entry.provider.toolName.toLowerCase() === hint.toLowerCase()
|
|
4652
|
+
);
|
|
4653
|
+
if (byAlias) return byAlias;
|
|
4654
|
+
const provider = getProvider(resolved);
|
|
4655
|
+
if (provider) {
|
|
4656
|
+
return {
|
|
4657
|
+
provider,
|
|
4658
|
+
installed: true,
|
|
4659
|
+
methods: [],
|
|
4660
|
+
projectDetected: false
|
|
4661
|
+
};
|
|
4662
|
+
}
|
|
4663
|
+
}
|
|
4664
|
+
return null;
|
|
4665
|
+
}
|
|
4666
|
+
function selectRuntimeProviderContext(detections, snapshot = {}) {
|
|
4667
|
+
const hints = getRuntimeHints(snapshot);
|
|
4668
|
+
const hinted = pickDetectionByHint(detections, hints);
|
|
4669
|
+
const projectMatches = detections.filter((entry) => entry.projectDetected);
|
|
4670
|
+
const installed = detections.filter((entry) => entry.installed);
|
|
4671
|
+
const selected = hinted ?? (projectMatches.length === 1 ? projectMatches[0] : null) ?? (installed.length === 1 ? installed[0] : null);
|
|
4672
|
+
if (!selected) {
|
|
4673
|
+
return {
|
|
4674
|
+
runtimeCandidates: installed.map((entry) => entry.provider.id)
|
|
4675
|
+
};
|
|
4676
|
+
}
|
|
4677
|
+
return {
|
|
4678
|
+
runtimeProviderId: selected.provider.id,
|
|
4679
|
+
runtimeToolName: selected.provider.toolName,
|
|
4680
|
+
runtimeVendor: selected.provider.vendor,
|
|
4681
|
+
runtimeInstructionFile: selected.provider.instructFile,
|
|
4682
|
+
runtimeProjectDetected: selected.projectDetected,
|
|
4683
|
+
runtimeDetectionMethods: selected.methods,
|
|
4684
|
+
runtimeCandidates: installed.map((entry) => entry.provider.id),
|
|
4685
|
+
inferredModelProvider: inferProviderFromVendor(selected.provider.vendor)
|
|
4686
|
+
};
|
|
4687
|
+
}
|
|
4688
|
+
function detectRuntimeProviderContext(snapshot = {}) {
|
|
4689
|
+
if (!snapshot.cwd && !snapshot.argv && !snapshot.env && cachedRuntimeProvider) {
|
|
4690
|
+
return cachedRuntimeProvider;
|
|
4691
|
+
}
|
|
4692
|
+
try {
|
|
4693
|
+
const detections = detectProjectProviders(snapshot.cwd ?? process.cwd());
|
|
4694
|
+
const context = selectRuntimeProviderContext(detections, snapshot);
|
|
4695
|
+
if (!snapshot.cwd && !snapshot.argv && !snapshot.env) {
|
|
4696
|
+
cachedRuntimeProvider = context;
|
|
4697
|
+
}
|
|
4698
|
+
return context;
|
|
4699
|
+
} catch {
|
|
4700
|
+
return {};
|
|
4701
|
+
}
|
|
4702
|
+
}
|
|
4703
|
+
function resetRuntimeProviderContextCache() {
|
|
4704
|
+
cachedRuntimeProvider = null;
|
|
4705
|
+
}
|
|
4706
|
+
var cachedRuntimeProvider;
|
|
4707
|
+
var init_provider_detection = __esm({
|
|
4708
|
+
"src/core/metrics/provider-detection.ts"() {
|
|
4709
|
+
"use strict";
|
|
4710
|
+
cachedRuntimeProvider = null;
|
|
4711
|
+
}
|
|
4712
|
+
});
|
|
4713
|
+
|
|
4602
4714
|
// src/store/data-safety.ts
|
|
4603
4715
|
import { eq as eq8 } from "drizzle-orm";
|
|
4604
4716
|
async function checkTaskExists(taskId, cwd, config = {}) {
|
|
@@ -7067,14 +7179,16 @@ async function writeMemoryBridge(projectRoot, config) {
|
|
|
7067
7179
|
}
|
|
7068
7180
|
writeFileSync2(bridgePath, content, "utf-8");
|
|
7069
7181
|
return { path: bridgePath, written: true };
|
|
7070
|
-
} catch {
|
|
7182
|
+
} catch (err) {
|
|
7183
|
+
console.error("[CLEO] Failed to write memory bridge:", err instanceof Error ? err.message : String(err));
|
|
7071
7184
|
return { path: bridgePath, written: false };
|
|
7072
7185
|
}
|
|
7073
7186
|
}
|
|
7074
7187
|
async function refreshMemoryBridge(projectRoot) {
|
|
7075
7188
|
try {
|
|
7076
7189
|
await writeMemoryBridge(projectRoot);
|
|
7077
|
-
} catch {
|
|
7190
|
+
} catch (err) {
|
|
7191
|
+
console.error("[CLEO] Memory bridge refresh failed:", err instanceof Error ? err.message : String(err));
|
|
7078
7192
|
}
|
|
7079
7193
|
}
|
|
7080
7194
|
async function getLastHandoffSafe(projectRoot) {
|
|
@@ -8470,28 +8584,25 @@ async function ensureInjection(projectRoot) {
|
|
|
8470
8584
|
}
|
|
8471
8585
|
const { getInstalledProviders: getInstalledProviders2, inject, injectAll: injectAll2, buildInjectionContent: buildInjectionContent2 } = caamp;
|
|
8472
8586
|
const providers = getInstalledProviders2();
|
|
8473
|
-
if (providers.length === 0) {
|
|
8474
|
-
return {
|
|
8475
|
-
action: "skipped",
|
|
8476
|
-
path: join26(projectRoot, "AGENTS.md"),
|
|
8477
|
-
details: "No AI agent providers detected, skipping injection"
|
|
8478
|
-
};
|
|
8479
|
-
}
|
|
8480
8587
|
const actions = [];
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
const
|
|
8494
|
-
|
|
8588
|
+
if (providers.length === 0) {
|
|
8589
|
+
actions.push("No providers detected (AGENTS.md created without provider injection)");
|
|
8590
|
+
} else {
|
|
8591
|
+
for (const provider of providers) {
|
|
8592
|
+
const instructFile = join26(projectRoot, provider.pathProject, provider.instructFile);
|
|
8593
|
+
await stripCLEOBlocks(instructFile);
|
|
8594
|
+
}
|
|
8595
|
+
await stripCLEOBlocks(join26(projectRoot, "AGENTS.md"));
|
|
8596
|
+
const removedStale = await removeStaleAgentInjection(projectRoot);
|
|
8597
|
+
if (removedStale) {
|
|
8598
|
+
actions.push("removed deprecated AGENT-INJECTION.md");
|
|
8599
|
+
}
|
|
8600
|
+
const injectionContent = buildInjectionContent2({ references: ["@AGENTS.md"] });
|
|
8601
|
+
const results = await injectAll2(providers, projectRoot, "project", injectionContent);
|
|
8602
|
+
for (const [filePath, action] of results) {
|
|
8603
|
+
const fileName = basename3(filePath);
|
|
8604
|
+
actions.push(`${fileName} (${action})`);
|
|
8605
|
+
}
|
|
8495
8606
|
}
|
|
8496
8607
|
const agentsMdPath = join26(projectRoot, "AGENTS.md");
|
|
8497
8608
|
const agentsMdLines = ["@~/.cleo/templates/CLEO-INJECTION.md"];
|
|
@@ -8499,6 +8610,10 @@ async function ensureInjection(projectRoot) {
|
|
|
8499
8610
|
if (existsSync23(projectContextPath)) {
|
|
8500
8611
|
agentsMdLines.push("@.cleo/project-context.json");
|
|
8501
8612
|
}
|
|
8613
|
+
const memoryBridgePath = join26(projectRoot, ".cleo", "memory-bridge.md");
|
|
8614
|
+
if (existsSync23(memoryBridgePath)) {
|
|
8615
|
+
agentsMdLines.push("@.cleo/memory-bridge.md");
|
|
8616
|
+
}
|
|
8502
8617
|
const contributorBlock = buildContributorInjectionBlock(projectRoot);
|
|
8503
8618
|
if (contributorBlock) {
|
|
8504
8619
|
agentsMdLines.push(contributorBlock);
|
|
@@ -8699,6 +8814,7 @@ __export(scaffold_exports, {
|
|
|
8699
8814
|
CLEO_GITIGNORE_FALLBACK: () => CLEO_GITIGNORE_FALLBACK,
|
|
8700
8815
|
REQUIRED_CLEO_SUBDIRS: () => REQUIRED_CLEO_SUBDIRS,
|
|
8701
8816
|
REQUIRED_GLOBAL_SUBDIRS: () => REQUIRED_GLOBAL_SUBDIRS,
|
|
8817
|
+
checkBrainDb: () => checkBrainDb,
|
|
8702
8818
|
checkCleoGitRepo: () => checkCleoGitRepo,
|
|
8703
8819
|
checkCleoStructure: () => checkCleoStructure,
|
|
8704
8820
|
checkConfig: () => checkConfig,
|
|
@@ -8706,10 +8822,12 @@ __export(scaffold_exports, {
|
|
|
8706
8822
|
checkGlobalHome: () => checkGlobalHome,
|
|
8707
8823
|
checkGlobalTemplates: () => checkGlobalTemplates,
|
|
8708
8824
|
checkLogDir: () => checkLogDir,
|
|
8825
|
+
checkMemoryBridge: () => checkMemoryBridge,
|
|
8709
8826
|
checkProjectContext: () => checkProjectContext,
|
|
8710
8827
|
checkProjectInfo: () => checkProjectInfo,
|
|
8711
8828
|
checkSqliteDb: () => checkSqliteDb,
|
|
8712
8829
|
createDefaultConfig: () => createDefaultConfig,
|
|
8830
|
+
ensureBrainDb: () => ensureBrainDb,
|
|
8713
8831
|
ensureCleoGitRepo: () => ensureCleoGitRepo,
|
|
8714
8832
|
ensureCleoStructure: () => ensureCleoStructure,
|
|
8715
8833
|
ensureConfig: () => ensureConfig,
|
|
@@ -9324,6 +9442,79 @@ function checkSqliteDb(projectRoot) {
|
|
|
9324
9442
|
fix: null
|
|
9325
9443
|
};
|
|
9326
9444
|
}
|
|
9445
|
+
async function ensureBrainDb(projectRoot) {
|
|
9446
|
+
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
9447
|
+
const dbPath = join27(cleoDir, "brain.db");
|
|
9448
|
+
if (existsSync24(dbPath)) {
|
|
9449
|
+
return { action: "skipped", path: dbPath, details: "brain.db already exists" };
|
|
9450
|
+
}
|
|
9451
|
+
try {
|
|
9452
|
+
const { getBrainDb: getBrainDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
|
|
9453
|
+
await getBrainDb2(projectRoot);
|
|
9454
|
+
return { action: "created", path: dbPath, details: "Brain database initialized" };
|
|
9455
|
+
} catch (err) {
|
|
9456
|
+
return {
|
|
9457
|
+
action: "skipped",
|
|
9458
|
+
path: dbPath,
|
|
9459
|
+
details: `Failed to initialize brain.db: ${err instanceof Error ? err.message : String(err)}`
|
|
9460
|
+
};
|
|
9461
|
+
}
|
|
9462
|
+
}
|
|
9463
|
+
function checkBrainDb(projectRoot) {
|
|
9464
|
+
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
9465
|
+
const dbPath = join27(cleoDir, "brain.db");
|
|
9466
|
+
if (!existsSync24(dbPath)) {
|
|
9467
|
+
return {
|
|
9468
|
+
id: "brain_db",
|
|
9469
|
+
category: "scaffold",
|
|
9470
|
+
status: "failed",
|
|
9471
|
+
message: "brain.db not found",
|
|
9472
|
+
details: { path: dbPath, exists: false },
|
|
9473
|
+
fix: "cleo init"
|
|
9474
|
+
};
|
|
9475
|
+
}
|
|
9476
|
+
const stat3 = statSync3(dbPath);
|
|
9477
|
+
if (stat3.size === 0) {
|
|
9478
|
+
return {
|
|
9479
|
+
id: "brain_db",
|
|
9480
|
+
category: "scaffold",
|
|
9481
|
+
status: "warning",
|
|
9482
|
+
message: "brain.db exists but is empty (0 bytes)",
|
|
9483
|
+
details: { path: dbPath, exists: true, size: 0 },
|
|
9484
|
+
fix: "cleo upgrade"
|
|
9485
|
+
};
|
|
9486
|
+
}
|
|
9487
|
+
return {
|
|
9488
|
+
id: "brain_db",
|
|
9489
|
+
category: "scaffold",
|
|
9490
|
+
status: "passed",
|
|
9491
|
+
message: `brain.db exists (${stat3.size} bytes)`,
|
|
9492
|
+
details: { path: dbPath, exists: true, size: stat3.size },
|
|
9493
|
+
fix: null
|
|
9494
|
+
};
|
|
9495
|
+
}
|
|
9496
|
+
function checkMemoryBridge(projectRoot) {
|
|
9497
|
+
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
9498
|
+
const bridgePath = join27(cleoDir, "memory-bridge.md");
|
|
9499
|
+
if (!existsSync24(bridgePath)) {
|
|
9500
|
+
return {
|
|
9501
|
+
id: "memory_bridge",
|
|
9502
|
+
category: "scaffold",
|
|
9503
|
+
status: "warning",
|
|
9504
|
+
message: "memory-bridge.md not found",
|
|
9505
|
+
details: { path: bridgePath, exists: false },
|
|
9506
|
+
fix: "cleo init or cleo refresh-memory"
|
|
9507
|
+
};
|
|
9508
|
+
}
|
|
9509
|
+
return {
|
|
9510
|
+
id: "memory_bridge",
|
|
9511
|
+
category: "scaffold",
|
|
9512
|
+
status: "passed",
|
|
9513
|
+
message: "memory-bridge.md exists",
|
|
9514
|
+
details: { path: bridgePath, exists: true },
|
|
9515
|
+
fix: null
|
|
9516
|
+
};
|
|
9517
|
+
}
|
|
9327
9518
|
async function ensureGlobalHome() {
|
|
9328
9519
|
const cleoHome = getCleoHome();
|
|
9329
9520
|
const alreadyExists = existsSync24(cleoHome);
|
|
@@ -10404,6 +10595,28 @@ var init_registry2 = __esm({
|
|
|
10404
10595
|
}
|
|
10405
10596
|
});
|
|
10406
10597
|
|
|
10598
|
+
// src/core/adapters/adapter-registry.ts
|
|
10599
|
+
var ADAPTER_REGISTRY;
|
|
10600
|
+
var init_adapter_registry = __esm({
|
|
10601
|
+
"src/core/adapters/adapter-registry.ts"() {
|
|
10602
|
+
"use strict";
|
|
10603
|
+
ADAPTER_REGISTRY = {
|
|
10604
|
+
"claude-code": async () => {
|
|
10605
|
+
const { ClaudeCodeAdapter } = await import("@cleocode/adapter-claude-code");
|
|
10606
|
+
return new ClaudeCodeAdapter();
|
|
10607
|
+
},
|
|
10608
|
+
"opencode": async () => {
|
|
10609
|
+
const { OpenCodeAdapter } = await import("@cleocode/adapter-opencode");
|
|
10610
|
+
return new OpenCodeAdapter();
|
|
10611
|
+
},
|
|
10612
|
+
"cursor": async () => {
|
|
10613
|
+
const { CursorAdapter } = await import("@cleocode/adapter-cursor");
|
|
10614
|
+
return new CursorAdapter();
|
|
10615
|
+
}
|
|
10616
|
+
};
|
|
10617
|
+
}
|
|
10618
|
+
});
|
|
10619
|
+
|
|
10407
10620
|
// src/core/adapters/discovery.ts
|
|
10408
10621
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
10409
10622
|
import { existsSync as existsSync28, readdirSync as readdirSync12, readFileSync as readFileSync18 } from "node:fs";
|
|
@@ -10469,13 +10682,16 @@ var log4, AdapterManager;
|
|
|
10469
10682
|
var init_manager = __esm({
|
|
10470
10683
|
"src/core/adapters/manager.ts"() {
|
|
10471
10684
|
"use strict";
|
|
10685
|
+
init_registry();
|
|
10472
10686
|
init_logger();
|
|
10687
|
+
init_adapter_registry();
|
|
10473
10688
|
init_discovery();
|
|
10474
10689
|
log4 = getLogger("adapter-manager");
|
|
10475
10690
|
AdapterManager = class _AdapterManager {
|
|
10476
10691
|
static instance = null;
|
|
10477
10692
|
adapters = /* @__PURE__ */ new Map();
|
|
10478
10693
|
manifests = /* @__PURE__ */ new Map();
|
|
10694
|
+
hookCleanups = /* @__PURE__ */ new Map();
|
|
10479
10695
|
activeId = null;
|
|
10480
10696
|
projectRoot;
|
|
10481
10697
|
constructor(projectRoot) {
|
|
@@ -10519,7 +10735,7 @@ var init_manager = __esm({
|
|
|
10519
10735
|
}
|
|
10520
10736
|
/**
|
|
10521
10737
|
* Load and initialize an adapter by manifest ID.
|
|
10522
|
-
*
|
|
10738
|
+
* Uses the static adapter registry for reliable bundled operation.
|
|
10523
10739
|
*/
|
|
10524
10740
|
async activate(adapterId) {
|
|
10525
10741
|
const manifest = this.manifests.get(adapterId);
|
|
@@ -10531,20 +10747,18 @@ var init_manager = __esm({
|
|
|
10531
10747
|
this.activeId = adapterId;
|
|
10532
10748
|
return existing;
|
|
10533
10749
|
}
|
|
10534
|
-
const
|
|
10535
|
-
|
|
10536
|
-
|
|
10537
|
-
|
|
10538
|
-
"adapters",
|
|
10539
|
-
manifest.provider,
|
|
10540
|
-
manifest.entryPoint
|
|
10541
|
-
);
|
|
10750
|
+
const factory = ADAPTER_REGISTRY[adapterId];
|
|
10751
|
+
if (!factory) {
|
|
10752
|
+
throw new Error(`No adapter registered in static registry: ${adapterId}`);
|
|
10753
|
+
}
|
|
10542
10754
|
try {
|
|
10543
|
-
const
|
|
10544
|
-
const adapter = typeof mod.default === "function" ? new mod.default() : typeof mod.createAdapter === "function" ? await mod.createAdapter() : mod.default;
|
|
10755
|
+
const adapter = await factory();
|
|
10545
10756
|
await adapter.initialize(this.projectRoot);
|
|
10546
10757
|
this.adapters.set(adapterId, adapter);
|
|
10547
10758
|
this.activeId = adapterId;
|
|
10759
|
+
if (adapter.hooks) {
|
|
10760
|
+
await this.wireAdapterHooks(adapterId, adapter);
|
|
10761
|
+
}
|
|
10548
10762
|
log4.info({ adapterId, provider: manifest.provider }, "Adapter activated");
|
|
10549
10763
|
return adapter;
|
|
10550
10764
|
} catch (err) {
|
|
@@ -10626,6 +10840,7 @@ var init_manager = __esm({
|
|
|
10626
10840
|
async dispose() {
|
|
10627
10841
|
for (const [id, adapter] of this.adapters) {
|
|
10628
10842
|
try {
|
|
10843
|
+
await this.cleanupAdapterHooks(id, adapter);
|
|
10629
10844
|
await adapter.dispose();
|
|
10630
10845
|
log4.info({ adapterId: id }, "Adapter disposed");
|
|
10631
10846
|
} catch (err) {
|
|
@@ -10633,6 +10848,7 @@ var init_manager = __esm({
|
|
|
10633
10848
|
}
|
|
10634
10849
|
}
|
|
10635
10850
|
this.adapters.clear();
|
|
10851
|
+
this.hookCleanups.clear();
|
|
10636
10852
|
this.activeId = null;
|
|
10637
10853
|
}
|
|
10638
10854
|
/** Dispose a single adapter. */
|
|
@@ -10640,6 +10856,7 @@ var init_manager = __esm({
|
|
|
10640
10856
|
const adapter = this.adapters.get(adapterId);
|
|
10641
10857
|
if (!adapter) return;
|
|
10642
10858
|
try {
|
|
10859
|
+
await this.cleanupAdapterHooks(adapterId, adapter);
|
|
10643
10860
|
await adapter.dispose();
|
|
10644
10861
|
} catch (err) {
|
|
10645
10862
|
log4.error({ adapterId, err }, "Failed to dispose adapter");
|
|
@@ -10649,6 +10866,51 @@ var init_manager = __esm({
|
|
|
10649
10866
|
this.activeId = null;
|
|
10650
10867
|
}
|
|
10651
10868
|
}
|
|
10869
|
+
/**
|
|
10870
|
+
* Wire an adapter's hook event map into CLEO's HookRegistry.
|
|
10871
|
+
* Creates bridging handlers at priority 50 for each mapped event.
|
|
10872
|
+
*/
|
|
10873
|
+
async wireAdapterHooks(adapterId, adapter) {
|
|
10874
|
+
if (!adapter.hooks) return;
|
|
10875
|
+
try {
|
|
10876
|
+
await adapter.hooks.registerNativeHooks(this.projectRoot);
|
|
10877
|
+
} catch (err) {
|
|
10878
|
+
log4.error({ adapterId, err }, "Failed to register native hooks");
|
|
10879
|
+
}
|
|
10880
|
+
const eventMap = adapter.hooks.getEventMap?.();
|
|
10881
|
+
if (!eventMap) return;
|
|
10882
|
+
const cleanups = [];
|
|
10883
|
+
for (const [_providerEvent, caampEvent] of Object.entries(eventMap)) {
|
|
10884
|
+
const hookId = `adapter-${adapterId}-${caampEvent}`;
|
|
10885
|
+
const unregister = hooks.register({
|
|
10886
|
+
id: hookId,
|
|
10887
|
+
event: caampEvent,
|
|
10888
|
+
priority: 50,
|
|
10889
|
+
handler: async (_projectRoot, payload) => {
|
|
10890
|
+
log4.debug({ adapterId, event: caampEvent, payload }, "Adapter hook dispatched");
|
|
10891
|
+
}
|
|
10892
|
+
});
|
|
10893
|
+
cleanups.push(unregister);
|
|
10894
|
+
}
|
|
10895
|
+
this.hookCleanups.set(adapterId, cleanups);
|
|
10896
|
+
}
|
|
10897
|
+
/**
|
|
10898
|
+
* Clean up hook registrations for an adapter.
|
|
10899
|
+
*/
|
|
10900
|
+
async cleanupAdapterHooks(adapterId, adapter) {
|
|
10901
|
+
const cleanups = this.hookCleanups.get(adapterId);
|
|
10902
|
+
if (cleanups) {
|
|
10903
|
+
for (const fn of cleanups) {
|
|
10904
|
+
fn();
|
|
10905
|
+
}
|
|
10906
|
+
this.hookCleanups.delete(adapterId);
|
|
10907
|
+
}
|
|
10908
|
+
try {
|
|
10909
|
+
await adapter.hooks?.unregisterNativeHooks();
|
|
10910
|
+
} catch (err) {
|
|
10911
|
+
log4.error({ adapterId, err }, "Failed to unregister native hooks");
|
|
10912
|
+
}
|
|
10913
|
+
}
|
|
10652
10914
|
};
|
|
10653
10915
|
}
|
|
10654
10916
|
});
|
|
@@ -10656,6 +10918,7 @@ var init_manager = __esm({
|
|
|
10656
10918
|
// src/core/adapters/index.ts
|
|
10657
10919
|
var adapters_exports = {};
|
|
10658
10920
|
__export(adapters_exports, {
|
|
10921
|
+
ADAPTER_REGISTRY: () => ADAPTER_REGISTRY,
|
|
10659
10922
|
AdapterManager: () => AdapterManager,
|
|
10660
10923
|
detectProvider: () => detectProvider,
|
|
10661
10924
|
discoverAdapterManifests: () => discoverAdapterManifests
|
|
@@ -10663,6 +10926,7 @@ __export(adapters_exports, {
|
|
|
10663
10926
|
var init_adapters = __esm({
|
|
10664
10927
|
"src/core/adapters/index.ts"() {
|
|
10665
10928
|
"use strict";
|
|
10929
|
+
init_adapter_registry();
|
|
10666
10930
|
init_manager();
|
|
10667
10931
|
init_discovery();
|
|
10668
10932
|
}
|
|
@@ -12893,6 +13157,13 @@ async function startSession(options, cwd, accessor) {
|
|
|
12893
13157
|
);
|
|
12894
13158
|
}
|
|
12895
13159
|
}
|
|
13160
|
+
let detectedProviderId = null;
|
|
13161
|
+
try {
|
|
13162
|
+
const { detectRuntimeProviderContext: detectRuntimeProviderContext2 } = await Promise.resolve().then(() => (init_provider_detection(), provider_detection_exports));
|
|
13163
|
+
const ctx = detectRuntimeProviderContext2();
|
|
13164
|
+
detectedProviderId = ctx.runtimeProviderId ?? null;
|
|
13165
|
+
} catch {
|
|
13166
|
+
}
|
|
12896
13167
|
const session = {
|
|
12897
13168
|
id: generateSessionId(),
|
|
12898
13169
|
name: options.name,
|
|
@@ -12907,7 +13178,7 @@ async function startSession(options, cwd, accessor) {
|
|
|
12907
13178
|
notes: [],
|
|
12908
13179
|
tasksCompleted: [],
|
|
12909
13180
|
tasksCreated: [],
|
|
12910
|
-
providerId: options.providerId ?? null
|
|
13181
|
+
providerId: options.providerId ?? detectedProviderId ?? null
|
|
12911
13182
|
};
|
|
12912
13183
|
if (options.grade) {
|
|
12913
13184
|
session.notes = ["[grade-mode:enabled]", ...session.notes ?? []];
|
|
@@ -12917,13 +13188,22 @@ async function startSession(options, cwd, accessor) {
|
|
|
12917
13188
|
}
|
|
12918
13189
|
sessions2.push(session);
|
|
12919
13190
|
await saveSessions(sessions2, cwd, accessor);
|
|
13191
|
+
if (session.providerId) {
|
|
13192
|
+
Promise.resolve().then(() => (init_adapters(), adapters_exports)).then(({ AdapterManager: AdapterManager2 }) => {
|
|
13193
|
+
const mgr = AdapterManager2.getInstance(cwd ?? process.cwd());
|
|
13194
|
+
mgr.discover();
|
|
13195
|
+
return mgr.activate(session.providerId);
|
|
13196
|
+
}).catch(() => {
|
|
13197
|
+
});
|
|
13198
|
+
}
|
|
12920
13199
|
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
12921
13200
|
hooks2.dispatch("onSessionStart", cwd ?? process.cwd(), {
|
|
12922
13201
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12923
13202
|
sessionId: session.id,
|
|
12924
13203
|
name: options.name,
|
|
12925
13204
|
scope,
|
|
12926
|
-
agent: options.agent
|
|
13205
|
+
agent: options.agent,
|
|
13206
|
+
providerId: session.providerId ?? void 0
|
|
12927
13207
|
}).catch(() => {
|
|
12928
13208
|
});
|
|
12929
13209
|
return session;
|
|
@@ -12959,7 +13239,8 @@ async function endSession(options = {}, cwd, accessor) {
|
|
|
12959
13239
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12960
13240
|
sessionId: session.id,
|
|
12961
13241
|
duration,
|
|
12962
|
-
tasksCompleted: session.tasksCompleted || []
|
|
13242
|
+
tasksCompleted: session.tasksCompleted || [],
|
|
13243
|
+
providerId: session.providerId ?? void 0
|
|
12963
13244
|
}).catch(() => {
|
|
12964
13245
|
});
|
|
12965
13246
|
const { bridgeSessionToMemory: bridgeSessionToMemory2 } = await Promise.resolve().then(() => (init_session_memory_bridge(), session_memory_bridge_exports));
|
|
@@ -13329,7 +13610,7 @@ async function initializeDefaultAdapters() {
|
|
|
13329
13610
|
}
|
|
13330
13611
|
}
|
|
13331
13612
|
var SpawnAdapterRegistry, spawnRegistry;
|
|
13332
|
-
var
|
|
13613
|
+
var init_adapter_registry2 = __esm({
|
|
13333
13614
|
"src/core/spawn/adapter-registry.ts"() {
|
|
13334
13615
|
"use strict";
|
|
13335
13616
|
SpawnAdapterRegistry = class {
|
|
@@ -14577,6 +14858,18 @@ async function startupHealthCheck(projectRoot) {
|
|
|
14577
14858
|
} else {
|
|
14578
14859
|
checks.push({ check: "log_dir", status: "pass", message: "Log directory present" });
|
|
14579
14860
|
}
|
|
14861
|
+
const brainDbCheck = checkBrainDb(root);
|
|
14862
|
+
checks.push({
|
|
14863
|
+
check: "brain_db",
|
|
14864
|
+
status: brainDbCheck.status === "passed" ? "pass" : "warn",
|
|
14865
|
+
message: brainDbCheck.message
|
|
14866
|
+
});
|
|
14867
|
+
const memBridgeCheck = checkMemoryBridge(root);
|
|
14868
|
+
checks.push({
|
|
14869
|
+
check: "memory_bridge",
|
|
14870
|
+
status: memBridgeCheck.status === "passed" ? "pass" : "warn",
|
|
14871
|
+
message: memBridgeCheck.message
|
|
14872
|
+
});
|
|
14580
14873
|
const hasFailures = failures.length > 0;
|
|
14581
14874
|
const state = hasFailures && !projectHealthy ? "needs_upgrade" : "healthy";
|
|
14582
14875
|
return {
|
|
@@ -14665,7 +14958,7 @@ async function loadCompletionEnforcement(cwd) {
|
|
|
14665
14958
|
const lifecycleModeRaw = await getRawConfigValue("lifecycle.mode", cwd);
|
|
14666
14959
|
const acceptanceMode = modeRaw === "off" || modeRaw === "warn" || modeRaw === "block" ? modeRaw : "warn";
|
|
14667
14960
|
const acceptanceRequiredForPriorities = Array.isArray(prioritiesRaw) ? prioritiesRaw.filter((p) => typeof p === "string") : ["critical", "high"];
|
|
14668
|
-
const verificationEnabled = verificationEnabledRaw
|
|
14961
|
+
const verificationEnabled = verificationEnabledRaw === true;
|
|
14669
14962
|
const verificationRequiredGates = Array.isArray(verificationRequiredGatesRaw) ? verificationRequiredGatesRaw.filter((g) => typeof g === "string").filter(isVerificationGate) : DEFAULT_VERIFICATION_REQUIRED_GATES;
|
|
14670
14963
|
const verificationMaxRounds = typeof verificationMaxRoundsRaw === "number" && Number.isInteger(verificationMaxRoundsRaw) ? verificationMaxRoundsRaw : 5;
|
|
14671
14964
|
const lifecycleMode = lifecycleModeRaw === "strict" || lifecycleModeRaw === "warn" || lifecycleModeRaw === "advisory" || lifecycleModeRaw === "none" || lifecycleModeRaw === "off" ? lifecycleModeRaw : "off";
|
|
@@ -20993,116 +21286,20 @@ async function resolveProviderFromModelRegistry(model) {
|
|
|
20993
21286
|
return resolveProviderFromModelIndex(index5, model);
|
|
20994
21287
|
}
|
|
20995
21288
|
|
|
20996
|
-
// src/core/metrics/
|
|
20997
|
-
|
|
20998
|
-
|
|
20999
|
-
|
|
21000
|
-
|
|
21001
|
-
|
|
21002
|
-
|
|
21003
|
-
|
|
21004
|
-
const value = (vendor ?? "").trim().toLowerCase();
|
|
21005
|
-
if (!value) return void 0;
|
|
21006
|
-
if (value.includes("anthropic") || value.includes("claude")) return "anthropic";
|
|
21007
|
-
if (value.includes("openai") || value.includes("codex") || value.includes("chatgpt"))
|
|
21289
|
+
// src/core/metrics/token-service.ts
|
|
21290
|
+
init_provider_detection();
|
|
21291
|
+
function normalizeProvider(provider, model, runtimeProvider) {
|
|
21292
|
+
const value = (provider ?? "").trim().toLowerCase();
|
|
21293
|
+
const modelValue = (model ?? "").trim().toLowerCase();
|
|
21294
|
+
const runtimeValue = (runtimeProvider ?? "").trim().toLowerCase();
|
|
21295
|
+
if (value) return value;
|
|
21296
|
+
if (modelValue.startsWith("gpt") || modelValue.startsWith("o1") || modelValue.startsWith("o3") || modelValue.startsWith("text-embedding")) {
|
|
21008
21297
|
return "openai";
|
|
21009
|
-
if (value.includes("google") || value.includes("gemini")) return "google";
|
|
21010
|
-
if (value.includes("xai") || value.includes("grok")) return "xai";
|
|
21011
|
-
return void 0;
|
|
21012
|
-
}
|
|
21013
|
-
function getRuntimeHints(snapshot) {
|
|
21014
|
-
const argv = snapshot.argv ?? process.argv;
|
|
21015
|
-
const env = snapshot.env ?? process.env;
|
|
21016
|
-
const hints = /* @__PURE__ */ new Set();
|
|
21017
|
-
const bin = basename2(argv[1] ?? argv[0] ?? "").replace(/\.[^.]+$/, "");
|
|
21018
|
-
if (bin) hints.add(bin);
|
|
21019
|
-
if (env["CLAUDE_CODE_ENABLE_TELEMETRY"] || env["CLAUDE_CODE_ENTRYPOINT"]) {
|
|
21020
|
-
hints.add("claude-code");
|
|
21021
|
-
hints.add("claude");
|
|
21022
21298
|
}
|
|
21023
|
-
if (
|
|
21024
|
-
|
|
21025
|
-
|
|
21026
|
-
|
|
21027
|
-
hints.add("cursor");
|
|
21028
|
-
}
|
|
21029
|
-
return Array.from(hints);
|
|
21030
|
-
}
|
|
21031
|
-
function pickDetectionByHint(detections, hints) {
|
|
21032
|
-
for (const hint of hints) {
|
|
21033
|
-
const resolved = resolveAlias(hint);
|
|
21034
|
-
const direct = detections.find(
|
|
21035
|
-
(entry) => entry.provider.id === resolved || entry.provider.id === hint
|
|
21036
|
-
);
|
|
21037
|
-
if (direct) return direct;
|
|
21038
|
-
const byAlias = detections.find(
|
|
21039
|
-
(entry) => entry.provider.aliases.includes(hint) || entry.provider.agentFlag === hint || entry.provider.toolName.toLowerCase() === hint.toLowerCase()
|
|
21040
|
-
);
|
|
21041
|
-
if (byAlias) return byAlias;
|
|
21042
|
-
const provider = getProvider(resolved);
|
|
21043
|
-
if (provider) {
|
|
21044
|
-
return {
|
|
21045
|
-
provider,
|
|
21046
|
-
installed: true,
|
|
21047
|
-
methods: [],
|
|
21048
|
-
projectDetected: false
|
|
21049
|
-
};
|
|
21050
|
-
}
|
|
21051
|
-
}
|
|
21052
|
-
return null;
|
|
21053
|
-
}
|
|
21054
|
-
function selectRuntimeProviderContext(detections, snapshot = {}) {
|
|
21055
|
-
const hints = getRuntimeHints(snapshot);
|
|
21056
|
-
const hinted = pickDetectionByHint(detections, hints);
|
|
21057
|
-
const projectMatches = detections.filter((entry) => entry.projectDetected);
|
|
21058
|
-
const installed = detections.filter((entry) => entry.installed);
|
|
21059
|
-
const selected = hinted ?? (projectMatches.length === 1 ? projectMatches[0] : null) ?? (installed.length === 1 ? installed[0] : null);
|
|
21060
|
-
if (!selected) {
|
|
21061
|
-
return {
|
|
21062
|
-
runtimeCandidates: installed.map((entry) => entry.provider.id)
|
|
21063
|
-
};
|
|
21064
|
-
}
|
|
21065
|
-
return {
|
|
21066
|
-
runtimeProviderId: selected.provider.id,
|
|
21067
|
-
runtimeToolName: selected.provider.toolName,
|
|
21068
|
-
runtimeVendor: selected.provider.vendor,
|
|
21069
|
-
runtimeInstructionFile: selected.provider.instructFile,
|
|
21070
|
-
runtimeProjectDetected: selected.projectDetected,
|
|
21071
|
-
runtimeDetectionMethods: selected.methods,
|
|
21072
|
-
runtimeCandidates: installed.map((entry) => entry.provider.id),
|
|
21073
|
-
inferredModelProvider: inferProviderFromVendor(selected.provider.vendor)
|
|
21074
|
-
};
|
|
21075
|
-
}
|
|
21076
|
-
var cachedRuntimeProvider = null;
|
|
21077
|
-
function detectRuntimeProviderContext(snapshot = {}) {
|
|
21078
|
-
if (!snapshot.cwd && !snapshot.argv && !snapshot.env && cachedRuntimeProvider) {
|
|
21079
|
-
return cachedRuntimeProvider;
|
|
21080
|
-
}
|
|
21081
|
-
try {
|
|
21082
|
-
const detections = detectProjectProviders(snapshot.cwd ?? process.cwd());
|
|
21083
|
-
const context = selectRuntimeProviderContext(detections, snapshot);
|
|
21084
|
-
if (!snapshot.cwd && !snapshot.argv && !snapshot.env) {
|
|
21085
|
-
cachedRuntimeProvider = context;
|
|
21086
|
-
}
|
|
21087
|
-
return context;
|
|
21088
|
-
} catch {
|
|
21089
|
-
return {};
|
|
21090
|
-
}
|
|
21091
|
-
}
|
|
21092
|
-
|
|
21093
|
-
// src/core/metrics/token-service.ts
|
|
21094
|
-
function normalizeProvider(provider, model, runtimeProvider) {
|
|
21095
|
-
const value = (provider ?? "").trim().toLowerCase();
|
|
21096
|
-
const modelValue = (model ?? "").trim().toLowerCase();
|
|
21097
|
-
const runtimeValue = (runtimeProvider ?? "").trim().toLowerCase();
|
|
21098
|
-
if (value) return value;
|
|
21099
|
-
if (modelValue.startsWith("gpt") || modelValue.startsWith("o1") || modelValue.startsWith("o3") || modelValue.startsWith("text-embedding")) {
|
|
21100
|
-
return "openai";
|
|
21101
|
-
}
|
|
21102
|
-
if (modelValue.includes("claude")) return "anthropic";
|
|
21103
|
-
if (modelValue.includes("gemini")) return "google";
|
|
21104
|
-
if (runtimeValue) return runtimeValue;
|
|
21105
|
-
return "unknown";
|
|
21299
|
+
if (modelValue.includes("claude")) return "anthropic";
|
|
21300
|
+
if (modelValue.includes("gemini")) return "google";
|
|
21301
|
+
if (runtimeValue) return runtimeValue;
|
|
21302
|
+
return "unknown";
|
|
21106
21303
|
}
|
|
21107
21304
|
async function resolveMeasurementProvider(input) {
|
|
21108
21305
|
const runtime = detectRuntimeProviderContext({ cwd: input.cwd });
|
|
@@ -22205,6 +22402,7 @@ init_agent_outputs();
|
|
|
22205
22402
|
init_paths();
|
|
22206
22403
|
init_scaffold();
|
|
22207
22404
|
init_schema_management();
|
|
22405
|
+
init_memory_bridge();
|
|
22208
22406
|
import { existsSync as existsSync29, readdirSync as readdirSync13, readFileSync as readFileSync19 } from "node:fs";
|
|
22209
22407
|
import { copyFile as copyFile3, lstat, mkdir as mkdir9, readFile as readFile8, symlink, unlink as unlink3 } from "node:fs/promises";
|
|
22210
22408
|
import { basename as basename5, dirname as dirname10, join as join33 } from "node:path";
|
|
@@ -22378,6 +22576,14 @@ async function initProject(opts = {}) {
|
|
|
22378
22576
|
} catch (err) {
|
|
22379
22577
|
created.push(`tasks.db (deferred: ${err instanceof Error ? err.message : String(err)})`);
|
|
22380
22578
|
}
|
|
22579
|
+
try {
|
|
22580
|
+
const brainResult = await ensureBrainDb(projRoot);
|
|
22581
|
+
if (brainResult.action === "created") {
|
|
22582
|
+
created.push("brain.db");
|
|
22583
|
+
}
|
|
22584
|
+
} catch (err) {
|
|
22585
|
+
created.push(`brain.db (deferred: ${err instanceof Error ? err.message : String(err)})`);
|
|
22586
|
+
}
|
|
22381
22587
|
if (force) {
|
|
22382
22588
|
const gitignoreResult = await ensureGitignore(projRoot);
|
|
22383
22589
|
if (gitignoreResult.action === "skipped") {
|
|
@@ -22467,6 +22673,14 @@ async function initProject(opts = {}) {
|
|
|
22467
22673
|
} catch (err) {
|
|
22468
22674
|
warnings.push(`Project detection failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
22469
22675
|
}
|
|
22676
|
+
try {
|
|
22677
|
+
const bridgeResult = await writeMemoryBridge(projRoot);
|
|
22678
|
+
if (bridgeResult.written) {
|
|
22679
|
+
created.push("memory-bridge.md");
|
|
22680
|
+
}
|
|
22681
|
+
} catch (err) {
|
|
22682
|
+
warnings.push(`Memory bridge: ${err instanceof Error ? err.message : String(err)}`);
|
|
22683
|
+
}
|
|
22470
22684
|
try {
|
|
22471
22685
|
const injectionResult = await ensureInjection(projRoot);
|
|
22472
22686
|
if (injectionResult.action !== "skipped") {
|
|
@@ -22500,6 +22714,21 @@ async function initProject(opts = {}) {
|
|
|
22500
22714
|
const detected = mgr.detectActive();
|
|
22501
22715
|
if (detected.length > 0) {
|
|
22502
22716
|
created.push(`adapters: active provider detected (${detected.join(", ")})`);
|
|
22717
|
+
for (const adapterId of detected) {
|
|
22718
|
+
try {
|
|
22719
|
+
const adapter = await mgr.activate(adapterId);
|
|
22720
|
+
const installResult = await adapter.install.install({
|
|
22721
|
+
projectDir: projRoot
|
|
22722
|
+
});
|
|
22723
|
+
if (installResult.success) {
|
|
22724
|
+
created.push(`adapter install (${adapterId}): installed`);
|
|
22725
|
+
} else {
|
|
22726
|
+
warnings.push(`adapter install (${adapterId}): failed`);
|
|
22727
|
+
}
|
|
22728
|
+
} catch (err) {
|
|
22729
|
+
warnings.push(`adapter activate/install (${adapterId}): ${err instanceof Error ? err.message : String(err)}`);
|
|
22730
|
+
}
|
|
22731
|
+
}
|
|
22503
22732
|
}
|
|
22504
22733
|
}
|
|
22505
22734
|
} catch (err) {
|
|
@@ -24604,6 +24833,7 @@ function injectContext(protocolType, params, projectRoot) {
|
|
|
24604
24833
|
// src/dispatch/engines/session-engine.ts
|
|
24605
24834
|
init_handoff();
|
|
24606
24835
|
init_sessions();
|
|
24836
|
+
init_sessions();
|
|
24607
24837
|
|
|
24608
24838
|
// src/core/sessions/session-id.ts
|
|
24609
24839
|
import { randomBytes as randomBytes9 } from "node:crypto";
|
|
@@ -24893,29 +25123,31 @@ async function sessionStart(projectRoot, params) {
|
|
|
24893
25123
|
try {
|
|
24894
25124
|
let accessor = await getAccessor(projectRoot);
|
|
24895
25125
|
let taskData = await accessor.loadTaskFile();
|
|
25126
|
+
let scope;
|
|
25127
|
+
try {
|
|
25128
|
+
scope = parseScope2(params.scope);
|
|
25129
|
+
} catch (err) {
|
|
25130
|
+
return engineError("E_INVALID_INPUT", err instanceof Error ? err.message : "Invalid scope");
|
|
25131
|
+
}
|
|
25132
|
+
if (scope.type !== "global") {
|
|
25133
|
+
const rootTask = taskData.tasks?.find((t) => t.id === scope.rootTaskId);
|
|
25134
|
+
if (!rootTask) {
|
|
25135
|
+
return engineError("E_NOT_FOUND", `Root task '${scope.rootTaskId}' not found`);
|
|
25136
|
+
}
|
|
25137
|
+
}
|
|
24896
25138
|
const activeSessionId = taskData._meta?.activeSession;
|
|
24897
25139
|
if (activeSessionId) {
|
|
24898
25140
|
await sessionEnd(projectRoot);
|
|
24899
25141
|
accessor = await getAccessor(projectRoot);
|
|
24900
25142
|
taskData = await accessor.loadTaskFile();
|
|
24901
25143
|
}
|
|
24902
|
-
const scopeParts = params.scope.split(":");
|
|
24903
|
-
const scopeType = scopeParts[0] || "task";
|
|
24904
|
-
const rootTaskId = scopeParts[1] || "";
|
|
24905
|
-
if (!rootTaskId) {
|
|
24906
|
-
return engineError("E_INVALID_INPUT", "Scope must include a task ID (e.g., epic:T001)");
|
|
24907
|
-
}
|
|
24908
|
-
const rootTask = taskData.tasks?.find((t) => t.id === rootTaskId);
|
|
24909
|
-
if (!rootTask) {
|
|
24910
|
-
return engineError("E_NOT_FOUND", `Root task '${rootTaskId}' not found`);
|
|
24911
|
-
}
|
|
24912
25144
|
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
24913
25145
|
const sessionId = generateSessionId2();
|
|
24914
25146
|
let previousSessionId = null;
|
|
24915
25147
|
{
|
|
24916
25148
|
const sessions2 = await accessor.loadSessions();
|
|
24917
25149
|
const sameScope = sessions2.filter(
|
|
24918
|
-
(s) => s.status === "ended" && s.endedAt && s.scope?.
|
|
25150
|
+
(s) => s.status === "ended" && s.endedAt && s.scope?.type === scope.type && (scope.type === "global" || s.scope?.rootTaskId === scope.rootTaskId)
|
|
24919
25151
|
).sort(
|
|
24920
25152
|
(a, b) => new Date(b.endedAt).getTime() - new Date(a.endedAt).getTime()
|
|
24921
25153
|
);
|
|
@@ -24924,16 +25156,13 @@ async function sessionStart(projectRoot, params) {
|
|
|
24924
25156
|
}
|
|
24925
25157
|
}
|
|
24926
25158
|
const agentIdentifier = params.agentIdentifier ?? process.env.CLEO_AGENT_ID ?? null;
|
|
24927
|
-
const
|
|
25159
|
+
const rootTaskId = scope.type !== "global" ? scope.rootTaskId : void 0;
|
|
25160
|
+
const startingTaskId = params.startTask || (params.autoStart && rootTaskId ? rootTaskId : null);
|
|
24928
25161
|
const newSession = {
|
|
24929
25162
|
id: sessionId,
|
|
24930
25163
|
status: "active",
|
|
24931
25164
|
name: params.name || `session-${sessionId}`,
|
|
24932
|
-
scope: {
|
|
24933
|
-
type: scopeType,
|
|
24934
|
-
rootTaskId,
|
|
24935
|
-
includeDescendants: true
|
|
24936
|
-
},
|
|
25165
|
+
scope: scope.type === "global" ? { type: "global" } : { type: scope.type, rootTaskId: scope.rootTaskId, includeDescendants: true },
|
|
24937
25166
|
taskWork: {
|
|
24938
25167
|
taskId: startingTaskId,
|
|
24939
25168
|
setAt: now2
|
|
@@ -24964,7 +25193,7 @@ async function sessionStart(projectRoot, params) {
|
|
|
24964
25193
|
const startingTask = params.startTask;
|
|
24965
25194
|
if (startingTask) {
|
|
24966
25195
|
taskData.focus.currentTask = startingTask;
|
|
24967
|
-
} else if (params.autoStart) {
|
|
25196
|
+
} else if (params.autoStart && rootTaskId) {
|
|
24968
25197
|
taskData.focus.currentTask = rootTaskId;
|
|
24969
25198
|
}
|
|
24970
25199
|
if (taskData._meta) {
|
|
@@ -25570,7 +25799,7 @@ async function orchestrateValidate(taskId, projectRoot) {
|
|
|
25570
25799
|
async function orchestrateSpawnExecute(taskId, adapterId, protocolType, projectRoot, _tier) {
|
|
25571
25800
|
const cwd = projectRoot ?? process.cwd();
|
|
25572
25801
|
try {
|
|
25573
|
-
const { initializeDefaultAdapters: initializeDefaultAdapters2, spawnRegistry: spawnRegistry2 } = await Promise.resolve().then(() => (
|
|
25802
|
+
const { initializeDefaultAdapters: initializeDefaultAdapters2, spawnRegistry: spawnRegistry2 } = await Promise.resolve().then(() => (init_adapter_registry2(), adapter_registry_exports));
|
|
25574
25803
|
await initializeDefaultAdapters2();
|
|
25575
25804
|
let adapter;
|
|
25576
25805
|
if (adapterId) {
|
|
@@ -26699,7 +26928,10 @@ async function checkEpicCompleteness(releaseTaskIds, cwd, accessor) {
|
|
|
26699
26928
|
if (!epic) continue;
|
|
26700
26929
|
const allChildren = data.tasks.filter((t) => t.parentId === epicId && t.id !== epicId);
|
|
26701
26930
|
const includedSet = new Set(includedTasks);
|
|
26702
|
-
const
|
|
26931
|
+
const parentIds = new Set(data.tasks.filter((t) => t.parentId).map((t) => t.parentId));
|
|
26932
|
+
const missingChildren = allChildren.filter(
|
|
26933
|
+
(t) => t.status === "done" && !parentIds.has(t.id) && !includedSet.has(t.id) && !releaseSet.has(t.id)
|
|
26934
|
+
).map((t) => ({ id: t.id, title: t.title, status: t.status }));
|
|
26703
26935
|
if (missingChildren.length > 0) hasIncomplete = true;
|
|
26704
26936
|
epics.push({
|
|
26705
26937
|
epicId,
|
|
@@ -26854,9 +27086,9 @@ init_json();
|
|
|
26854
27086
|
init_sqlite();
|
|
26855
27087
|
init_tasks_schema();
|
|
26856
27088
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
26857
|
-
import { existsSync as
|
|
27089
|
+
import { existsSync as existsSync42, renameSync as renameSync7 } from "node:fs";
|
|
26858
27090
|
import { readFile as readFile11 } from "node:fs/promises";
|
|
26859
|
-
import { join as
|
|
27091
|
+
import { join as join43 } from "node:path";
|
|
26860
27092
|
import { and as and6, count as count4, desc as desc5, eq as eq15 } from "drizzle-orm";
|
|
26861
27093
|
init_paths();
|
|
26862
27094
|
|
|
@@ -26951,6 +27183,170 @@ function escapeRegex(str) {
|
|
|
26951
27183
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26952
27184
|
}
|
|
26953
27185
|
|
|
27186
|
+
// src/core/release/version-bump.ts
|
|
27187
|
+
init_exit_codes();
|
|
27188
|
+
init_errors();
|
|
27189
|
+
init_paths();
|
|
27190
|
+
import { existsSync as existsSync41, readFileSync as readFileSync26, writeFileSync as writeFileSync6 } from "node:fs";
|
|
27191
|
+
import { join as join42 } from "node:path";
|
|
27192
|
+
function readConfigValueSync2(path, defaultValue, cwd) {
|
|
27193
|
+
try {
|
|
27194
|
+
const configPath = join42(getCleoDir(cwd), "config.json");
|
|
27195
|
+
if (!existsSync41(configPath)) return defaultValue;
|
|
27196
|
+
const config = JSON.parse(readFileSync26(configPath, "utf-8"));
|
|
27197
|
+
const keys = path.split(".");
|
|
27198
|
+
let value = config;
|
|
27199
|
+
for (const key of keys) {
|
|
27200
|
+
if (value == null || typeof value !== "object") return defaultValue;
|
|
27201
|
+
value = value[key];
|
|
27202
|
+
}
|
|
27203
|
+
return value ?? defaultValue;
|
|
27204
|
+
} catch {
|
|
27205
|
+
return defaultValue;
|
|
27206
|
+
}
|
|
27207
|
+
}
|
|
27208
|
+
var VERSION_WITH_PRERELEASE = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$/;
|
|
27209
|
+
function validateVersionFormat(version) {
|
|
27210
|
+
return VERSION_WITH_PRERELEASE.test(version);
|
|
27211
|
+
}
|
|
27212
|
+
function getVersionBumpConfig(cwd) {
|
|
27213
|
+
try {
|
|
27214
|
+
const raw = readConfigValueSync2("release.versionBump.files", [], cwd);
|
|
27215
|
+
return raw.map((entry) => ({
|
|
27216
|
+
file: entry.path ?? entry.file ?? "",
|
|
27217
|
+
strategy: entry.strategy,
|
|
27218
|
+
field: entry.jsonPath?.replace(/^\./, "") ?? entry.field,
|
|
27219
|
+
key: entry.key,
|
|
27220
|
+
section: entry.section,
|
|
27221
|
+
pattern: entry.sedPattern ?? entry.pattern
|
|
27222
|
+
})).filter((t) => t.file !== "");
|
|
27223
|
+
} catch {
|
|
27224
|
+
return [];
|
|
27225
|
+
}
|
|
27226
|
+
}
|
|
27227
|
+
function bumpFile(target, newVersion, projectRoot) {
|
|
27228
|
+
const filePath = join42(projectRoot, target.file);
|
|
27229
|
+
if (!existsSync41(filePath)) {
|
|
27230
|
+
return {
|
|
27231
|
+
file: target.file,
|
|
27232
|
+
strategy: target.strategy,
|
|
27233
|
+
success: false,
|
|
27234
|
+
error: `File not found: ${target.file}`
|
|
27235
|
+
};
|
|
27236
|
+
}
|
|
27237
|
+
try {
|
|
27238
|
+
const content = readFileSync26(filePath, "utf-8");
|
|
27239
|
+
let previousVersion;
|
|
27240
|
+
let newContent;
|
|
27241
|
+
switch (target.strategy) {
|
|
27242
|
+
case "plain": {
|
|
27243
|
+
previousVersion = content.trim();
|
|
27244
|
+
newContent = newVersion + "\n";
|
|
27245
|
+
break;
|
|
27246
|
+
}
|
|
27247
|
+
case "json": {
|
|
27248
|
+
const field = target.field ?? "version";
|
|
27249
|
+
const json = JSON.parse(content);
|
|
27250
|
+
previousVersion = getNestedField(json, field);
|
|
27251
|
+
setNestedField(json, field, newVersion);
|
|
27252
|
+
newContent = JSON.stringify(json, null, 2) + "\n";
|
|
27253
|
+
break;
|
|
27254
|
+
}
|
|
27255
|
+
case "toml": {
|
|
27256
|
+
const key = target.key ?? "version";
|
|
27257
|
+
const versionRegex = new RegExp(`^(${key}\\s*=\\s*")([^"]+)(")`, "m");
|
|
27258
|
+
const match = content.match(versionRegex);
|
|
27259
|
+
previousVersion = match?.[2];
|
|
27260
|
+
newContent = content.replace(versionRegex, `$1${newVersion}$3`);
|
|
27261
|
+
break;
|
|
27262
|
+
}
|
|
27263
|
+
case "sed": {
|
|
27264
|
+
const pattern = target.pattern ?? "";
|
|
27265
|
+
if (!pattern.includes("{{VERSION}}")) {
|
|
27266
|
+
return {
|
|
27267
|
+
file: target.file,
|
|
27268
|
+
strategy: target.strategy,
|
|
27269
|
+
success: false,
|
|
27270
|
+
error: "sed strategy requires {{VERSION}} placeholder in pattern"
|
|
27271
|
+
};
|
|
27272
|
+
}
|
|
27273
|
+
const regex = new RegExp(pattern.replace("{{VERSION}}", "([\\d.]+)"));
|
|
27274
|
+
const match = content.match(regex);
|
|
27275
|
+
previousVersion = match?.[1];
|
|
27276
|
+
newContent = content.replace(regex, pattern.replace("{{VERSION}}", newVersion));
|
|
27277
|
+
break;
|
|
27278
|
+
}
|
|
27279
|
+
default:
|
|
27280
|
+
return {
|
|
27281
|
+
file: target.file,
|
|
27282
|
+
strategy: target.strategy,
|
|
27283
|
+
success: false,
|
|
27284
|
+
error: `Unknown strategy: ${target.strategy}`
|
|
27285
|
+
};
|
|
27286
|
+
}
|
|
27287
|
+
writeFileSync6(filePath, newContent, "utf-8");
|
|
27288
|
+
return {
|
|
27289
|
+
file: target.file,
|
|
27290
|
+
strategy: target.strategy,
|
|
27291
|
+
success: true,
|
|
27292
|
+
previousVersion,
|
|
27293
|
+
newVersion
|
|
27294
|
+
};
|
|
27295
|
+
} catch (err) {
|
|
27296
|
+
return {
|
|
27297
|
+
file: target.file,
|
|
27298
|
+
strategy: target.strategy,
|
|
27299
|
+
success: false,
|
|
27300
|
+
error: String(err)
|
|
27301
|
+
};
|
|
27302
|
+
}
|
|
27303
|
+
}
|
|
27304
|
+
function bumpVersionFromConfig(newVersion, options = {}, cwd) {
|
|
27305
|
+
if (!validateVersionFormat(newVersion)) {
|
|
27306
|
+
throw new CleoError(
|
|
27307
|
+
6 /* VALIDATION_ERROR */,
|
|
27308
|
+
`Invalid version: '${newVersion}' (expected X.Y.Z or YYYY.M.patch)`
|
|
27309
|
+
);
|
|
27310
|
+
}
|
|
27311
|
+
const targets = getVersionBumpConfig(cwd);
|
|
27312
|
+
if (targets.length === 0) {
|
|
27313
|
+
throw new CleoError(
|
|
27314
|
+
1 /* GENERAL_ERROR */,
|
|
27315
|
+
"No version bump targets configured. Add release.versionBump.files to .cleo/config.json"
|
|
27316
|
+
);
|
|
27317
|
+
}
|
|
27318
|
+
const projectRoot = getProjectRoot(cwd);
|
|
27319
|
+
const results = [];
|
|
27320
|
+
if (options.dryRun) {
|
|
27321
|
+
for (const target of targets) {
|
|
27322
|
+
results.push({
|
|
27323
|
+
file: target.file,
|
|
27324
|
+
strategy: target.strategy,
|
|
27325
|
+
success: true,
|
|
27326
|
+
newVersion
|
|
27327
|
+
});
|
|
27328
|
+
}
|
|
27329
|
+
return { results, allSuccess: true };
|
|
27330
|
+
}
|
|
27331
|
+
for (const target of targets) {
|
|
27332
|
+
results.push(bumpFile(target, newVersion, projectRoot));
|
|
27333
|
+
}
|
|
27334
|
+
const allSuccess = results.every((r) => r.success);
|
|
27335
|
+
return { results, allSuccess };
|
|
27336
|
+
}
|
|
27337
|
+
function getNestedField(obj, path) {
|
|
27338
|
+
return path.split(".").reduce((acc, key) => acc?.[key], obj);
|
|
27339
|
+
}
|
|
27340
|
+
function setNestedField(obj, path, value) {
|
|
27341
|
+
const parts = path.split(".");
|
|
27342
|
+
let current = obj;
|
|
27343
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
27344
|
+
if (typeof current[parts[i]] !== "object") current[parts[i]] = {};
|
|
27345
|
+
current = current[parts[i]];
|
|
27346
|
+
}
|
|
27347
|
+
current[parts[parts.length - 1]] = value;
|
|
27348
|
+
}
|
|
27349
|
+
|
|
26954
27350
|
// src/core/release/release-manifest.ts
|
|
26955
27351
|
function normalizeLimit2(limit) {
|
|
26956
27352
|
return typeof limit === "number" && limit > 0 ? limit : void 0;
|
|
@@ -27176,7 +27572,7 @@ async function generateReleaseChangelog(version, loadTasksFn, cwd) {
|
|
|
27176
27572
|
}
|
|
27177
27573
|
const changelog = sections.join("\n");
|
|
27178
27574
|
await db.update(releaseManifests).set({ changelog }).where(eq15(releaseManifests.version, normalizedVersion)).run();
|
|
27179
|
-
const changelogPath =
|
|
27575
|
+
const changelogPath = join43(cwd ?? process.cwd(), "CHANGELOG.md");
|
|
27180
27576
|
let existingChangelogContent = "";
|
|
27181
27577
|
try {
|
|
27182
27578
|
existingChangelogContent = await readFile11(changelogPath, "utf8");
|
|
@@ -27290,13 +27686,13 @@ async function runReleaseGates(version, loadTasksFn, cwd, opts) {
|
|
|
27290
27686
|
message: incompleteTasks.length === 0 ? "All tasks completed" : `${incompleteTasks.length} tasks not completed: ${incompleteTasks.join(", ")}`
|
|
27291
27687
|
});
|
|
27292
27688
|
const projectRoot = cwd ?? getProjectRoot();
|
|
27293
|
-
const distPath =
|
|
27294
|
-
const isNodeProject =
|
|
27689
|
+
const distPath = join43(projectRoot, "dist", "cli", "index.js");
|
|
27690
|
+
const isNodeProject = existsSync42(join43(projectRoot, "package.json"));
|
|
27295
27691
|
if (isNodeProject) {
|
|
27296
27692
|
gates.push({
|
|
27297
27693
|
name: "build_artifact",
|
|
27298
|
-
status:
|
|
27299
|
-
message:
|
|
27694
|
+
status: existsSync42(distPath) ? "passed" : "failed",
|
|
27695
|
+
message: existsSync42(distPath) ? "dist/cli/index.js present" : "dist/ not built \u2014 run: npm run build"
|
|
27300
27696
|
});
|
|
27301
27697
|
}
|
|
27302
27698
|
if (opts?.dryRun) {
|
|
@@ -27306,6 +27702,8 @@ async function runReleaseGates(version, loadTasksFn, cwd, opts) {
|
|
|
27306
27702
|
message: "Skipped in dry-run mode"
|
|
27307
27703
|
});
|
|
27308
27704
|
} else {
|
|
27705
|
+
const bumpTargets = getVersionBumpConfig(cwd);
|
|
27706
|
+
const allowedDirty = /* @__PURE__ */ new Set(["CHANGELOG.md", ...bumpTargets.map((t) => t.file)]);
|
|
27309
27707
|
let workingTreeClean = true;
|
|
27310
27708
|
let dirtyFiles = [];
|
|
27311
27709
|
try {
|
|
@@ -27314,14 +27712,15 @@ async function runReleaseGates(version, loadTasksFn, cwd, opts) {
|
|
|
27314
27712
|
encoding: "utf-8",
|
|
27315
27713
|
stdio: "pipe"
|
|
27316
27714
|
});
|
|
27317
|
-
dirtyFiles = porcelain.split("\n").filter((l) => l.trim()).filter((l) => !l.startsWith("?? ")).map((l) => l.slice(3).trim()).filter((f) =>
|
|
27715
|
+
dirtyFiles = porcelain.split("\n").filter((l) => l.trim()).filter((l) => !l.startsWith("?? ")).map((l) => l.slice(3).trim()).filter((f) => !allowedDirty.has(f));
|
|
27318
27716
|
workingTreeClean = dirtyFiles.length === 0;
|
|
27319
27717
|
} catch {
|
|
27320
27718
|
}
|
|
27719
|
+
const excludeList = [...allowedDirty].join(", ");
|
|
27321
27720
|
gates.push({
|
|
27322
27721
|
name: "clean_working_tree",
|
|
27323
27722
|
status: workingTreeClean ? "passed" : "failed",
|
|
27324
|
-
message: workingTreeClean ?
|
|
27723
|
+
message: workingTreeClean ? `Working tree clean (excluding ${excludeList})` : `Uncommitted changes in: ${dirtyFiles.slice(0, 5).join(", ")}${dirtyFiles.length > 5 ? ` (+${dirtyFiles.length - 5} more)` : ""}`
|
|
27325
27724
|
});
|
|
27326
27725
|
}
|
|
27327
27726
|
const isPreRelease = normalizedVersion.includes("-");
|
|
@@ -27436,7 +27835,7 @@ async function rollbackRelease(version, reason, cwd) {
|
|
|
27436
27835
|
};
|
|
27437
27836
|
}
|
|
27438
27837
|
async function readPushPolicy(cwd) {
|
|
27439
|
-
const configPath =
|
|
27838
|
+
const configPath = join43(getCleoDirAbsolute(cwd), "config.json");
|
|
27440
27839
|
const config = await readJson(configPath);
|
|
27441
27840
|
if (!config) return void 0;
|
|
27442
27841
|
const release2 = config.release;
|
|
@@ -27534,170 +27933,6 @@ async function markReleasePushed(version, pushedAt, cwd, provenance) {
|
|
|
27534
27933
|
}).where(eq15(releaseManifests.version, normalizedVersion)).run();
|
|
27535
27934
|
}
|
|
27536
27935
|
|
|
27537
|
-
// src/core/release/version-bump.ts
|
|
27538
|
-
init_exit_codes();
|
|
27539
|
-
init_errors();
|
|
27540
|
-
init_paths();
|
|
27541
|
-
import { existsSync as existsSync42, readFileSync as readFileSync26, writeFileSync as writeFileSync6 } from "node:fs";
|
|
27542
|
-
import { join as join43 } from "node:path";
|
|
27543
|
-
function readConfigValueSync2(path, defaultValue, cwd) {
|
|
27544
|
-
try {
|
|
27545
|
-
const configPath = join43(getCleoDir(cwd), "config.json");
|
|
27546
|
-
if (!existsSync42(configPath)) return defaultValue;
|
|
27547
|
-
const config = JSON.parse(readFileSync26(configPath, "utf-8"));
|
|
27548
|
-
const keys = path.split(".");
|
|
27549
|
-
let value = config;
|
|
27550
|
-
for (const key of keys) {
|
|
27551
|
-
if (value == null || typeof value !== "object") return defaultValue;
|
|
27552
|
-
value = value[key];
|
|
27553
|
-
}
|
|
27554
|
-
return value ?? defaultValue;
|
|
27555
|
-
} catch {
|
|
27556
|
-
return defaultValue;
|
|
27557
|
-
}
|
|
27558
|
-
}
|
|
27559
|
-
var VERSION_WITH_PRERELEASE = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$/;
|
|
27560
|
-
function validateVersionFormat(version) {
|
|
27561
|
-
return VERSION_WITH_PRERELEASE.test(version);
|
|
27562
|
-
}
|
|
27563
|
-
function getVersionBumpConfig(cwd) {
|
|
27564
|
-
try {
|
|
27565
|
-
const raw = readConfigValueSync2("release.versionBump.files", [], cwd);
|
|
27566
|
-
return raw.map((entry) => ({
|
|
27567
|
-
file: entry.path ?? entry.file ?? "",
|
|
27568
|
-
strategy: entry.strategy,
|
|
27569
|
-
field: entry.jsonPath?.replace(/^\./, "") ?? entry.field,
|
|
27570
|
-
key: entry.key,
|
|
27571
|
-
section: entry.section,
|
|
27572
|
-
pattern: entry.sedPattern ?? entry.pattern
|
|
27573
|
-
})).filter((t) => t.file !== "");
|
|
27574
|
-
} catch {
|
|
27575
|
-
return [];
|
|
27576
|
-
}
|
|
27577
|
-
}
|
|
27578
|
-
function bumpFile(target, newVersion, projectRoot) {
|
|
27579
|
-
const filePath = join43(projectRoot, target.file);
|
|
27580
|
-
if (!existsSync42(filePath)) {
|
|
27581
|
-
return {
|
|
27582
|
-
file: target.file,
|
|
27583
|
-
strategy: target.strategy,
|
|
27584
|
-
success: false,
|
|
27585
|
-
error: `File not found: ${target.file}`
|
|
27586
|
-
};
|
|
27587
|
-
}
|
|
27588
|
-
try {
|
|
27589
|
-
const content = readFileSync26(filePath, "utf-8");
|
|
27590
|
-
let previousVersion;
|
|
27591
|
-
let newContent;
|
|
27592
|
-
switch (target.strategy) {
|
|
27593
|
-
case "plain": {
|
|
27594
|
-
previousVersion = content.trim();
|
|
27595
|
-
newContent = newVersion + "\n";
|
|
27596
|
-
break;
|
|
27597
|
-
}
|
|
27598
|
-
case "json": {
|
|
27599
|
-
const field = target.field ?? "version";
|
|
27600
|
-
const json = JSON.parse(content);
|
|
27601
|
-
previousVersion = getNestedField(json, field);
|
|
27602
|
-
setNestedField(json, field, newVersion);
|
|
27603
|
-
newContent = JSON.stringify(json, null, 2) + "\n";
|
|
27604
|
-
break;
|
|
27605
|
-
}
|
|
27606
|
-
case "toml": {
|
|
27607
|
-
const key = target.key ?? "version";
|
|
27608
|
-
const versionRegex = new RegExp(`^(${key}\\s*=\\s*")([^"]+)(")`, "m");
|
|
27609
|
-
const match = content.match(versionRegex);
|
|
27610
|
-
previousVersion = match?.[2];
|
|
27611
|
-
newContent = content.replace(versionRegex, `$1${newVersion}$3`);
|
|
27612
|
-
break;
|
|
27613
|
-
}
|
|
27614
|
-
case "sed": {
|
|
27615
|
-
const pattern = target.pattern ?? "";
|
|
27616
|
-
if (!pattern.includes("{{VERSION}}")) {
|
|
27617
|
-
return {
|
|
27618
|
-
file: target.file,
|
|
27619
|
-
strategy: target.strategy,
|
|
27620
|
-
success: false,
|
|
27621
|
-
error: "sed strategy requires {{VERSION}} placeholder in pattern"
|
|
27622
|
-
};
|
|
27623
|
-
}
|
|
27624
|
-
const regex = new RegExp(pattern.replace("{{VERSION}}", "([\\d.]+)"));
|
|
27625
|
-
const match = content.match(regex);
|
|
27626
|
-
previousVersion = match?.[1];
|
|
27627
|
-
newContent = content.replace(regex, pattern.replace("{{VERSION}}", newVersion));
|
|
27628
|
-
break;
|
|
27629
|
-
}
|
|
27630
|
-
default:
|
|
27631
|
-
return {
|
|
27632
|
-
file: target.file,
|
|
27633
|
-
strategy: target.strategy,
|
|
27634
|
-
success: false,
|
|
27635
|
-
error: `Unknown strategy: ${target.strategy}`
|
|
27636
|
-
};
|
|
27637
|
-
}
|
|
27638
|
-
writeFileSync6(filePath, newContent, "utf-8");
|
|
27639
|
-
return {
|
|
27640
|
-
file: target.file,
|
|
27641
|
-
strategy: target.strategy,
|
|
27642
|
-
success: true,
|
|
27643
|
-
previousVersion,
|
|
27644
|
-
newVersion
|
|
27645
|
-
};
|
|
27646
|
-
} catch (err) {
|
|
27647
|
-
return {
|
|
27648
|
-
file: target.file,
|
|
27649
|
-
strategy: target.strategy,
|
|
27650
|
-
success: false,
|
|
27651
|
-
error: String(err)
|
|
27652
|
-
};
|
|
27653
|
-
}
|
|
27654
|
-
}
|
|
27655
|
-
function bumpVersionFromConfig(newVersion, options = {}, cwd) {
|
|
27656
|
-
if (!validateVersionFormat(newVersion)) {
|
|
27657
|
-
throw new CleoError(
|
|
27658
|
-
6 /* VALIDATION_ERROR */,
|
|
27659
|
-
`Invalid version: '${newVersion}' (expected X.Y.Z or YYYY.M.patch)`
|
|
27660
|
-
);
|
|
27661
|
-
}
|
|
27662
|
-
const targets = getVersionBumpConfig(cwd);
|
|
27663
|
-
if (targets.length === 0) {
|
|
27664
|
-
throw new CleoError(
|
|
27665
|
-
1 /* GENERAL_ERROR */,
|
|
27666
|
-
"No version bump targets configured. Add release.versionBump.files to .cleo/config.json"
|
|
27667
|
-
);
|
|
27668
|
-
}
|
|
27669
|
-
const projectRoot = getProjectRoot(cwd);
|
|
27670
|
-
const results = [];
|
|
27671
|
-
if (options.dryRun) {
|
|
27672
|
-
for (const target of targets) {
|
|
27673
|
-
results.push({
|
|
27674
|
-
file: target.file,
|
|
27675
|
-
strategy: target.strategy,
|
|
27676
|
-
success: true,
|
|
27677
|
-
newVersion
|
|
27678
|
-
});
|
|
27679
|
-
}
|
|
27680
|
-
return { results, allSuccess: true };
|
|
27681
|
-
}
|
|
27682
|
-
for (const target of targets) {
|
|
27683
|
-
results.push(bumpFile(target, newVersion, projectRoot));
|
|
27684
|
-
}
|
|
27685
|
-
const allSuccess = results.every((r) => r.success);
|
|
27686
|
-
return { results, allSuccess };
|
|
27687
|
-
}
|
|
27688
|
-
function getNestedField(obj, path) {
|
|
27689
|
-
return path.split(".").reduce((acc, key) => acc?.[key], obj);
|
|
27690
|
-
}
|
|
27691
|
-
function setNestedField(obj, path, value) {
|
|
27692
|
-
const parts = path.split(".");
|
|
27693
|
-
let current = obj;
|
|
27694
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
27695
|
-
if (typeof current[parts[i]] !== "object") current[parts[i]] = {};
|
|
27696
|
-
current = current[parts[i]];
|
|
27697
|
-
}
|
|
27698
|
-
current[parts[parts.length - 1]] = value;
|
|
27699
|
-
}
|
|
27700
|
-
|
|
27701
27936
|
// src/dispatch/engines/release-engine.ts
|
|
27702
27937
|
init_data_accessor();
|
|
27703
27938
|
init_error();
|