@cleocode/cleo 2026.3.29 → 2026.3.30
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 +554 -292
- package/dist/cli/index.js.map +4 -4
- package/dist/mcp/index.js +558 -320
- 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/cli/index.js
CHANGED
|
@@ -4439,6 +4439,118 @@ var init_sqlite = __esm({
|
|
|
4439
4439
|
}
|
|
4440
4440
|
});
|
|
4441
4441
|
|
|
4442
|
+
// src/core/metrics/provider-detection.ts
|
|
4443
|
+
var provider_detection_exports = {};
|
|
4444
|
+
__export(provider_detection_exports, {
|
|
4445
|
+
detectRuntimeProviderContext: () => detectRuntimeProviderContext,
|
|
4446
|
+
resetRuntimeProviderContextCache: () => resetRuntimeProviderContextCache,
|
|
4447
|
+
selectRuntimeProviderContext: () => selectRuntimeProviderContext
|
|
4448
|
+
});
|
|
4449
|
+
import { basename as basename3 } from "node:path";
|
|
4450
|
+
import {
|
|
4451
|
+
detectProjectProviders,
|
|
4452
|
+
getProvider,
|
|
4453
|
+
resolveAlias
|
|
4454
|
+
} from "@cleocode/caamp";
|
|
4455
|
+
function inferProviderFromVendor(vendor) {
|
|
4456
|
+
const value = (vendor ?? "").trim().toLowerCase();
|
|
4457
|
+
if (!value) return void 0;
|
|
4458
|
+
if (value.includes("anthropic") || value.includes("claude")) return "anthropic";
|
|
4459
|
+
if (value.includes("openai") || value.includes("codex") || value.includes("chatgpt"))
|
|
4460
|
+
return "openai";
|
|
4461
|
+
if (value.includes("google") || value.includes("gemini")) return "google";
|
|
4462
|
+
if (value.includes("xai") || value.includes("grok")) return "xai";
|
|
4463
|
+
return void 0;
|
|
4464
|
+
}
|
|
4465
|
+
function getRuntimeHints(snapshot) {
|
|
4466
|
+
const argv = snapshot.argv ?? process.argv;
|
|
4467
|
+
const env = snapshot.env ?? process.env;
|
|
4468
|
+
const hints = /* @__PURE__ */ new Set();
|
|
4469
|
+
const bin = basename3(argv[1] ?? argv[0] ?? "").replace(/\.[^.]+$/, "");
|
|
4470
|
+
if (bin) hints.add(bin);
|
|
4471
|
+
if (env["CLAUDE_CODE_ENABLE_TELEMETRY"] || env["CLAUDE_CODE_ENTRYPOINT"]) {
|
|
4472
|
+
hints.add("claude-code");
|
|
4473
|
+
hints.add("claude");
|
|
4474
|
+
}
|
|
4475
|
+
if (env["OPENCODE_AGENT"] || env["OPENCODE"]) {
|
|
4476
|
+
hints.add("opencode");
|
|
4477
|
+
}
|
|
4478
|
+
if (env["CURSOR_TRACE_ID"] || env["CURSOR_AGENT"]) {
|
|
4479
|
+
hints.add("cursor");
|
|
4480
|
+
}
|
|
4481
|
+
return Array.from(hints);
|
|
4482
|
+
}
|
|
4483
|
+
function pickDetectionByHint(detections, hints) {
|
|
4484
|
+
for (const hint of hints) {
|
|
4485
|
+
const resolved = resolveAlias(hint);
|
|
4486
|
+
const direct = detections.find(
|
|
4487
|
+
(entry) => entry.provider.id === resolved || entry.provider.id === hint
|
|
4488
|
+
);
|
|
4489
|
+
if (direct) return direct;
|
|
4490
|
+
const byAlias = detections.find(
|
|
4491
|
+
(entry) => entry.provider.aliases.includes(hint) || entry.provider.agentFlag === hint || entry.provider.toolName.toLowerCase() === hint.toLowerCase()
|
|
4492
|
+
);
|
|
4493
|
+
if (byAlias) return byAlias;
|
|
4494
|
+
const provider = getProvider(resolved);
|
|
4495
|
+
if (provider) {
|
|
4496
|
+
return {
|
|
4497
|
+
provider,
|
|
4498
|
+
installed: true,
|
|
4499
|
+
methods: [],
|
|
4500
|
+
projectDetected: false
|
|
4501
|
+
};
|
|
4502
|
+
}
|
|
4503
|
+
}
|
|
4504
|
+
return null;
|
|
4505
|
+
}
|
|
4506
|
+
function selectRuntimeProviderContext(detections, snapshot = {}) {
|
|
4507
|
+
const hints = getRuntimeHints(snapshot);
|
|
4508
|
+
const hinted = pickDetectionByHint(detections, hints);
|
|
4509
|
+
const projectMatches = detections.filter((entry) => entry.projectDetected);
|
|
4510
|
+
const installed = detections.filter((entry) => entry.installed);
|
|
4511
|
+
const selected = hinted ?? (projectMatches.length === 1 ? projectMatches[0] : null) ?? (installed.length === 1 ? installed[0] : null);
|
|
4512
|
+
if (!selected) {
|
|
4513
|
+
return {
|
|
4514
|
+
runtimeCandidates: installed.map((entry) => entry.provider.id)
|
|
4515
|
+
};
|
|
4516
|
+
}
|
|
4517
|
+
return {
|
|
4518
|
+
runtimeProviderId: selected.provider.id,
|
|
4519
|
+
runtimeToolName: selected.provider.toolName,
|
|
4520
|
+
runtimeVendor: selected.provider.vendor,
|
|
4521
|
+
runtimeInstructionFile: selected.provider.instructFile,
|
|
4522
|
+
runtimeProjectDetected: selected.projectDetected,
|
|
4523
|
+
runtimeDetectionMethods: selected.methods,
|
|
4524
|
+
runtimeCandidates: installed.map((entry) => entry.provider.id),
|
|
4525
|
+
inferredModelProvider: inferProviderFromVendor(selected.provider.vendor)
|
|
4526
|
+
};
|
|
4527
|
+
}
|
|
4528
|
+
function detectRuntimeProviderContext(snapshot = {}) {
|
|
4529
|
+
if (!snapshot.cwd && !snapshot.argv && !snapshot.env && cachedRuntimeProvider) {
|
|
4530
|
+
return cachedRuntimeProvider;
|
|
4531
|
+
}
|
|
4532
|
+
try {
|
|
4533
|
+
const detections = detectProjectProviders(snapshot.cwd ?? process.cwd());
|
|
4534
|
+
const context = selectRuntimeProviderContext(detections, snapshot);
|
|
4535
|
+
if (!snapshot.cwd && !snapshot.argv && !snapshot.env) {
|
|
4536
|
+
cachedRuntimeProvider = context;
|
|
4537
|
+
}
|
|
4538
|
+
return context;
|
|
4539
|
+
} catch {
|
|
4540
|
+
return {};
|
|
4541
|
+
}
|
|
4542
|
+
}
|
|
4543
|
+
function resetRuntimeProviderContextCache() {
|
|
4544
|
+
cachedRuntimeProvider = null;
|
|
4545
|
+
}
|
|
4546
|
+
var cachedRuntimeProvider;
|
|
4547
|
+
var init_provider_detection = __esm({
|
|
4548
|
+
"src/core/metrics/provider-detection.ts"() {
|
|
4549
|
+
"use strict";
|
|
4550
|
+
cachedRuntimeProvider = null;
|
|
4551
|
+
}
|
|
4552
|
+
});
|
|
4553
|
+
|
|
4442
4554
|
// src/store/parsers.ts
|
|
4443
4555
|
function safeParseJson(str) {
|
|
4444
4556
|
if (!str) return void 0;
|
|
@@ -8482,14 +8594,16 @@ async function writeMemoryBridge(projectRoot, config) {
|
|
|
8482
8594
|
}
|
|
8483
8595
|
writeFileSync4(bridgePath, content, "utf-8");
|
|
8484
8596
|
return { path: bridgePath, written: true };
|
|
8485
|
-
} catch {
|
|
8597
|
+
} catch (err) {
|
|
8598
|
+
console.error("[CLEO] Failed to write memory bridge:", err instanceof Error ? err.message : String(err));
|
|
8486
8599
|
return { path: bridgePath, written: false };
|
|
8487
8600
|
}
|
|
8488
8601
|
}
|
|
8489
8602
|
async function refreshMemoryBridge(projectRoot) {
|
|
8490
8603
|
try {
|
|
8491
8604
|
await writeMemoryBridge(projectRoot);
|
|
8492
|
-
} catch {
|
|
8605
|
+
} catch (err) {
|
|
8606
|
+
console.error("[CLEO] Memory bridge refresh failed:", err instanceof Error ? err.message : String(err));
|
|
8493
8607
|
}
|
|
8494
8608
|
}
|
|
8495
8609
|
async function getLastHandoffSafe(projectRoot) {
|
|
@@ -9914,6 +10028,10 @@ async function ensureInjection(projectRoot) {
|
|
|
9914
10028
|
if (existsSync26(projectContextPath)) {
|
|
9915
10029
|
agentsMdLines.push("@.cleo/project-context.json");
|
|
9916
10030
|
}
|
|
10031
|
+
const memoryBridgePath = join28(projectRoot, ".cleo", "memory-bridge.md");
|
|
10032
|
+
if (existsSync26(memoryBridgePath)) {
|
|
10033
|
+
agentsMdLines.push("@.cleo/memory-bridge.md");
|
|
10034
|
+
}
|
|
9917
10035
|
const contributorBlock = buildContributorInjectionBlock(projectRoot);
|
|
9918
10036
|
if (contributorBlock) {
|
|
9919
10037
|
agentsMdLines.push(contributorBlock);
|
|
@@ -10114,6 +10232,7 @@ __export(scaffold_exports, {
|
|
|
10114
10232
|
CLEO_GITIGNORE_FALLBACK: () => CLEO_GITIGNORE_FALLBACK,
|
|
10115
10233
|
REQUIRED_CLEO_SUBDIRS: () => REQUIRED_CLEO_SUBDIRS,
|
|
10116
10234
|
REQUIRED_GLOBAL_SUBDIRS: () => REQUIRED_GLOBAL_SUBDIRS,
|
|
10235
|
+
checkBrainDb: () => checkBrainDb,
|
|
10117
10236
|
checkCleoGitRepo: () => checkCleoGitRepo,
|
|
10118
10237
|
checkCleoStructure: () => checkCleoStructure,
|
|
10119
10238
|
checkConfig: () => checkConfig,
|
|
@@ -10121,10 +10240,12 @@ __export(scaffold_exports, {
|
|
|
10121
10240
|
checkGlobalHome: () => checkGlobalHome,
|
|
10122
10241
|
checkGlobalTemplates: () => checkGlobalTemplates,
|
|
10123
10242
|
checkLogDir: () => checkLogDir,
|
|
10243
|
+
checkMemoryBridge: () => checkMemoryBridge,
|
|
10124
10244
|
checkProjectContext: () => checkProjectContext,
|
|
10125
10245
|
checkProjectInfo: () => checkProjectInfo,
|
|
10126
10246
|
checkSqliteDb: () => checkSqliteDb,
|
|
10127
10247
|
createDefaultConfig: () => createDefaultConfig,
|
|
10248
|
+
ensureBrainDb: () => ensureBrainDb,
|
|
10128
10249
|
ensureCleoGitRepo: () => ensureCleoGitRepo,
|
|
10129
10250
|
ensureCleoStructure: () => ensureCleoStructure,
|
|
10130
10251
|
ensureConfig: () => ensureConfig,
|
|
@@ -10739,6 +10860,79 @@ function checkSqliteDb(projectRoot) {
|
|
|
10739
10860
|
fix: null
|
|
10740
10861
|
};
|
|
10741
10862
|
}
|
|
10863
|
+
async function ensureBrainDb(projectRoot) {
|
|
10864
|
+
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
10865
|
+
const dbPath = join29(cleoDir, "brain.db");
|
|
10866
|
+
if (existsSync27(dbPath)) {
|
|
10867
|
+
return { action: "skipped", path: dbPath, details: "brain.db already exists" };
|
|
10868
|
+
}
|
|
10869
|
+
try {
|
|
10870
|
+
const { getBrainDb: getBrainDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
|
|
10871
|
+
await getBrainDb2(projectRoot);
|
|
10872
|
+
return { action: "created", path: dbPath, details: "Brain database initialized" };
|
|
10873
|
+
} catch (err) {
|
|
10874
|
+
return {
|
|
10875
|
+
action: "skipped",
|
|
10876
|
+
path: dbPath,
|
|
10877
|
+
details: `Failed to initialize brain.db: ${err instanceof Error ? err.message : String(err)}`
|
|
10878
|
+
};
|
|
10879
|
+
}
|
|
10880
|
+
}
|
|
10881
|
+
function checkBrainDb(projectRoot) {
|
|
10882
|
+
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
10883
|
+
const dbPath = join29(cleoDir, "brain.db");
|
|
10884
|
+
if (!existsSync27(dbPath)) {
|
|
10885
|
+
return {
|
|
10886
|
+
id: "brain_db",
|
|
10887
|
+
category: "scaffold",
|
|
10888
|
+
status: "failed",
|
|
10889
|
+
message: "brain.db not found",
|
|
10890
|
+
details: { path: dbPath, exists: false },
|
|
10891
|
+
fix: "cleo init"
|
|
10892
|
+
};
|
|
10893
|
+
}
|
|
10894
|
+
const stat5 = statSync4(dbPath);
|
|
10895
|
+
if (stat5.size === 0) {
|
|
10896
|
+
return {
|
|
10897
|
+
id: "brain_db",
|
|
10898
|
+
category: "scaffold",
|
|
10899
|
+
status: "warning",
|
|
10900
|
+
message: "brain.db exists but is empty (0 bytes)",
|
|
10901
|
+
details: { path: dbPath, exists: true, size: 0 },
|
|
10902
|
+
fix: "cleo upgrade"
|
|
10903
|
+
};
|
|
10904
|
+
}
|
|
10905
|
+
return {
|
|
10906
|
+
id: "brain_db",
|
|
10907
|
+
category: "scaffold",
|
|
10908
|
+
status: "passed",
|
|
10909
|
+
message: `brain.db exists (${stat5.size} bytes)`,
|
|
10910
|
+
details: { path: dbPath, exists: true, size: stat5.size },
|
|
10911
|
+
fix: null
|
|
10912
|
+
};
|
|
10913
|
+
}
|
|
10914
|
+
function checkMemoryBridge(projectRoot) {
|
|
10915
|
+
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
10916
|
+
const bridgePath = join29(cleoDir, "memory-bridge.md");
|
|
10917
|
+
if (!existsSync27(bridgePath)) {
|
|
10918
|
+
return {
|
|
10919
|
+
id: "memory_bridge",
|
|
10920
|
+
category: "scaffold",
|
|
10921
|
+
status: "warning",
|
|
10922
|
+
message: "memory-bridge.md not found",
|
|
10923
|
+
details: { path: bridgePath, exists: false },
|
|
10924
|
+
fix: "cleo init or cleo refresh-memory"
|
|
10925
|
+
};
|
|
10926
|
+
}
|
|
10927
|
+
return {
|
|
10928
|
+
id: "memory_bridge",
|
|
10929
|
+
category: "scaffold",
|
|
10930
|
+
status: "passed",
|
|
10931
|
+
message: "memory-bridge.md exists",
|
|
10932
|
+
details: { path: bridgePath, exists: true },
|
|
10933
|
+
fix: null
|
|
10934
|
+
};
|
|
10935
|
+
}
|
|
10742
10936
|
async function ensureGlobalHome() {
|
|
10743
10937
|
const cleoHome = getCleoHome();
|
|
10744
10938
|
const alreadyExists = existsSync27(cleoHome);
|
|
@@ -11924,6 +12118,28 @@ var init_registry2 = __esm({
|
|
|
11924
12118
|
}
|
|
11925
12119
|
});
|
|
11926
12120
|
|
|
12121
|
+
// src/core/adapters/adapter-registry.ts
|
|
12122
|
+
var ADAPTER_REGISTRY;
|
|
12123
|
+
var init_adapter_registry = __esm({
|
|
12124
|
+
"src/core/adapters/adapter-registry.ts"() {
|
|
12125
|
+
"use strict";
|
|
12126
|
+
ADAPTER_REGISTRY = {
|
|
12127
|
+
"claude-code": async () => {
|
|
12128
|
+
const { ClaudeCodeAdapter } = await import("@cleocode/adapter-claude-code");
|
|
12129
|
+
return new ClaudeCodeAdapter();
|
|
12130
|
+
},
|
|
12131
|
+
"opencode": async () => {
|
|
12132
|
+
const { OpenCodeAdapter } = await import("@cleocode/adapter-opencode");
|
|
12133
|
+
return new OpenCodeAdapter();
|
|
12134
|
+
},
|
|
12135
|
+
"cursor": async () => {
|
|
12136
|
+
const { CursorAdapter } = await import("@cleocode/adapter-cursor");
|
|
12137
|
+
return new CursorAdapter();
|
|
12138
|
+
}
|
|
12139
|
+
};
|
|
12140
|
+
}
|
|
12141
|
+
});
|
|
12142
|
+
|
|
11927
12143
|
// src/core/adapters/discovery.ts
|
|
11928
12144
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
11929
12145
|
import { existsSync as existsSync31, readdirSync as readdirSync13, readFileSync as readFileSync22 } from "node:fs";
|
|
@@ -11993,13 +12209,16 @@ var log4, AdapterManager;
|
|
|
11993
12209
|
var init_manager = __esm({
|
|
11994
12210
|
"src/core/adapters/manager.ts"() {
|
|
11995
12211
|
"use strict";
|
|
12212
|
+
init_registry();
|
|
11996
12213
|
init_logger();
|
|
12214
|
+
init_adapter_registry();
|
|
11997
12215
|
init_discovery();
|
|
11998
12216
|
log4 = getLogger("adapter-manager");
|
|
11999
12217
|
AdapterManager = class _AdapterManager {
|
|
12000
12218
|
static instance = null;
|
|
12001
12219
|
adapters = /* @__PURE__ */ new Map();
|
|
12002
12220
|
manifests = /* @__PURE__ */ new Map();
|
|
12221
|
+
hookCleanups = /* @__PURE__ */ new Map();
|
|
12003
12222
|
activeId = null;
|
|
12004
12223
|
projectRoot;
|
|
12005
12224
|
constructor(projectRoot) {
|
|
@@ -12043,7 +12262,7 @@ var init_manager = __esm({
|
|
|
12043
12262
|
}
|
|
12044
12263
|
/**
|
|
12045
12264
|
* Load and initialize an adapter by manifest ID.
|
|
12046
|
-
*
|
|
12265
|
+
* Uses the static adapter registry for reliable bundled operation.
|
|
12047
12266
|
*/
|
|
12048
12267
|
async activate(adapterId) {
|
|
12049
12268
|
const manifest = this.manifests.get(adapterId);
|
|
@@ -12055,20 +12274,18 @@ var init_manager = __esm({
|
|
|
12055
12274
|
this.activeId = adapterId;
|
|
12056
12275
|
return existing;
|
|
12057
12276
|
}
|
|
12058
|
-
const
|
|
12059
|
-
|
|
12060
|
-
|
|
12061
|
-
|
|
12062
|
-
"adapters",
|
|
12063
|
-
manifest.provider,
|
|
12064
|
-
manifest.entryPoint
|
|
12065
|
-
);
|
|
12277
|
+
const factory = ADAPTER_REGISTRY[adapterId];
|
|
12278
|
+
if (!factory) {
|
|
12279
|
+
throw new Error(`No adapter registered in static registry: ${adapterId}`);
|
|
12280
|
+
}
|
|
12066
12281
|
try {
|
|
12067
|
-
const
|
|
12068
|
-
const adapter = typeof mod.default === "function" ? new mod.default() : typeof mod.createAdapter === "function" ? await mod.createAdapter() : mod.default;
|
|
12282
|
+
const adapter = await factory();
|
|
12069
12283
|
await adapter.initialize(this.projectRoot);
|
|
12070
12284
|
this.adapters.set(adapterId, adapter);
|
|
12071
12285
|
this.activeId = adapterId;
|
|
12286
|
+
if (adapter.hooks) {
|
|
12287
|
+
await this.wireAdapterHooks(adapterId, adapter);
|
|
12288
|
+
}
|
|
12072
12289
|
log4.info({ adapterId, provider: manifest.provider }, "Adapter activated");
|
|
12073
12290
|
return adapter;
|
|
12074
12291
|
} catch (err) {
|
|
@@ -12150,6 +12367,7 @@ var init_manager = __esm({
|
|
|
12150
12367
|
async dispose() {
|
|
12151
12368
|
for (const [id, adapter] of this.adapters) {
|
|
12152
12369
|
try {
|
|
12370
|
+
await this.cleanupAdapterHooks(id, adapter);
|
|
12153
12371
|
await adapter.dispose();
|
|
12154
12372
|
log4.info({ adapterId: id }, "Adapter disposed");
|
|
12155
12373
|
} catch (err) {
|
|
@@ -12157,6 +12375,7 @@ var init_manager = __esm({
|
|
|
12157
12375
|
}
|
|
12158
12376
|
}
|
|
12159
12377
|
this.adapters.clear();
|
|
12378
|
+
this.hookCleanups.clear();
|
|
12160
12379
|
this.activeId = null;
|
|
12161
12380
|
}
|
|
12162
12381
|
/** Dispose a single adapter. */
|
|
@@ -12164,6 +12383,7 @@ var init_manager = __esm({
|
|
|
12164
12383
|
const adapter = this.adapters.get(adapterId);
|
|
12165
12384
|
if (!adapter) return;
|
|
12166
12385
|
try {
|
|
12386
|
+
await this.cleanupAdapterHooks(adapterId, adapter);
|
|
12167
12387
|
await adapter.dispose();
|
|
12168
12388
|
} catch (err) {
|
|
12169
12389
|
log4.error({ adapterId, err }, "Failed to dispose adapter");
|
|
@@ -12173,6 +12393,51 @@ var init_manager = __esm({
|
|
|
12173
12393
|
this.activeId = null;
|
|
12174
12394
|
}
|
|
12175
12395
|
}
|
|
12396
|
+
/**
|
|
12397
|
+
* Wire an adapter's hook event map into CLEO's HookRegistry.
|
|
12398
|
+
* Creates bridging handlers at priority 50 for each mapped event.
|
|
12399
|
+
*/
|
|
12400
|
+
async wireAdapterHooks(adapterId, adapter) {
|
|
12401
|
+
if (!adapter.hooks) return;
|
|
12402
|
+
try {
|
|
12403
|
+
await adapter.hooks.registerNativeHooks(this.projectRoot);
|
|
12404
|
+
} catch (err) {
|
|
12405
|
+
log4.error({ adapterId, err }, "Failed to register native hooks");
|
|
12406
|
+
}
|
|
12407
|
+
const eventMap = adapter.hooks.getEventMap?.();
|
|
12408
|
+
if (!eventMap) return;
|
|
12409
|
+
const cleanups = [];
|
|
12410
|
+
for (const [_providerEvent, caampEvent] of Object.entries(eventMap)) {
|
|
12411
|
+
const hookId = `adapter-${adapterId}-${caampEvent}`;
|
|
12412
|
+
const unregister = hooks.register({
|
|
12413
|
+
id: hookId,
|
|
12414
|
+
event: caampEvent,
|
|
12415
|
+
priority: 50,
|
|
12416
|
+
handler: async (_projectRoot, payload) => {
|
|
12417
|
+
log4.debug({ adapterId, event: caampEvent, payload }, "Adapter hook dispatched");
|
|
12418
|
+
}
|
|
12419
|
+
});
|
|
12420
|
+
cleanups.push(unregister);
|
|
12421
|
+
}
|
|
12422
|
+
this.hookCleanups.set(adapterId, cleanups);
|
|
12423
|
+
}
|
|
12424
|
+
/**
|
|
12425
|
+
* Clean up hook registrations for an adapter.
|
|
12426
|
+
*/
|
|
12427
|
+
async cleanupAdapterHooks(adapterId, adapter) {
|
|
12428
|
+
const cleanups = this.hookCleanups.get(adapterId);
|
|
12429
|
+
if (cleanups) {
|
|
12430
|
+
for (const fn of cleanups) {
|
|
12431
|
+
fn();
|
|
12432
|
+
}
|
|
12433
|
+
this.hookCleanups.delete(adapterId);
|
|
12434
|
+
}
|
|
12435
|
+
try {
|
|
12436
|
+
await adapter.hooks?.unregisterNativeHooks();
|
|
12437
|
+
} catch (err) {
|
|
12438
|
+
log4.error({ adapterId, err }, "Failed to unregister native hooks");
|
|
12439
|
+
}
|
|
12440
|
+
}
|
|
12176
12441
|
};
|
|
12177
12442
|
}
|
|
12178
12443
|
});
|
|
@@ -12180,6 +12445,7 @@ var init_manager = __esm({
|
|
|
12180
12445
|
// src/core/adapters/index.ts
|
|
12181
12446
|
var adapters_exports = {};
|
|
12182
12447
|
__export(adapters_exports, {
|
|
12448
|
+
ADAPTER_REGISTRY: () => ADAPTER_REGISTRY,
|
|
12183
12449
|
AdapterManager: () => AdapterManager,
|
|
12184
12450
|
detectProvider: () => detectProvider,
|
|
12185
12451
|
discoverAdapterManifests: () => discoverAdapterManifests
|
|
@@ -12187,6 +12453,7 @@ __export(adapters_exports, {
|
|
|
12187
12453
|
var init_adapters = __esm({
|
|
12188
12454
|
"src/core/adapters/index.ts"() {
|
|
12189
12455
|
"use strict";
|
|
12456
|
+
init_adapter_registry();
|
|
12190
12457
|
init_manager();
|
|
12191
12458
|
init_discovery();
|
|
12192
12459
|
}
|
|
@@ -12410,6 +12677,14 @@ async function initProject(opts = {}) {
|
|
|
12410
12677
|
} catch (err) {
|
|
12411
12678
|
created.push(`tasks.db (deferred: ${err instanceof Error ? err.message : String(err)})`);
|
|
12412
12679
|
}
|
|
12680
|
+
try {
|
|
12681
|
+
const brainResult = await ensureBrainDb(projRoot);
|
|
12682
|
+
if (brainResult.action === "created") {
|
|
12683
|
+
created.push("brain.db");
|
|
12684
|
+
}
|
|
12685
|
+
} catch (err) {
|
|
12686
|
+
created.push(`brain.db (deferred: ${err instanceof Error ? err.message : String(err)})`);
|
|
12687
|
+
}
|
|
12413
12688
|
if (force) {
|
|
12414
12689
|
const gitignoreResult = await ensureGitignore(projRoot);
|
|
12415
12690
|
if (gitignoreResult.action === "skipped") {
|
|
@@ -12532,11 +12807,34 @@ async function initProject(opts = {}) {
|
|
|
12532
12807
|
const detected = mgr.detectActive();
|
|
12533
12808
|
if (detected.length > 0) {
|
|
12534
12809
|
created.push(`adapters: active provider detected (${detected.join(", ")})`);
|
|
12810
|
+
for (const adapterId of detected) {
|
|
12811
|
+
try {
|
|
12812
|
+
const adapter = await mgr.activate(adapterId);
|
|
12813
|
+
const installResult = await adapter.install.install({
|
|
12814
|
+
projectDir: projRoot
|
|
12815
|
+
});
|
|
12816
|
+
if (installResult.success) {
|
|
12817
|
+
created.push(`adapter install (${adapterId}): installed`);
|
|
12818
|
+
} else {
|
|
12819
|
+
warnings.push(`adapter install (${adapterId}): failed`);
|
|
12820
|
+
}
|
|
12821
|
+
} catch (err) {
|
|
12822
|
+
warnings.push(`adapter activate/install (${adapterId}): ${err instanceof Error ? err.message : String(err)}`);
|
|
12823
|
+
}
|
|
12824
|
+
}
|
|
12535
12825
|
}
|
|
12536
12826
|
}
|
|
12537
12827
|
} catch (err) {
|
|
12538
12828
|
warnings.push(`Adapter discovery: ${err instanceof Error ? err.message : String(err)}`);
|
|
12539
12829
|
}
|
|
12830
|
+
try {
|
|
12831
|
+
const bridgeResult = await writeMemoryBridge(projRoot);
|
|
12832
|
+
if (bridgeResult.written) {
|
|
12833
|
+
created.push("memory-bridge.md");
|
|
12834
|
+
}
|
|
12835
|
+
} catch (err) {
|
|
12836
|
+
warnings.push(`Memory bridge: ${err instanceof Error ? err.message : String(err)}`);
|
|
12837
|
+
}
|
|
12540
12838
|
const rootGitignoreResult = await removeCleoFromRootGitignore(projRoot);
|
|
12541
12839
|
if (rootGitignoreResult.removed) {
|
|
12542
12840
|
warnings.push(
|
|
@@ -12598,6 +12896,7 @@ var init_init = __esm({
|
|
|
12598
12896
|
init_paths();
|
|
12599
12897
|
init_scaffold();
|
|
12600
12898
|
init_schema_management();
|
|
12899
|
+
init_memory_bridge();
|
|
12601
12900
|
}
|
|
12602
12901
|
});
|
|
12603
12902
|
|
|
@@ -14546,6 +14845,13 @@ async function startSession(options, cwd, accessor) {
|
|
|
14546
14845
|
);
|
|
14547
14846
|
}
|
|
14548
14847
|
}
|
|
14848
|
+
let detectedProviderId = null;
|
|
14849
|
+
try {
|
|
14850
|
+
const { detectRuntimeProviderContext: detectRuntimeProviderContext2 } = await Promise.resolve().then(() => (init_provider_detection(), provider_detection_exports));
|
|
14851
|
+
const ctx = detectRuntimeProviderContext2();
|
|
14852
|
+
detectedProviderId = ctx.runtimeProviderId ?? null;
|
|
14853
|
+
} catch {
|
|
14854
|
+
}
|
|
14549
14855
|
const session = {
|
|
14550
14856
|
id: generateSessionId(),
|
|
14551
14857
|
name: options.name,
|
|
@@ -14560,7 +14866,7 @@ async function startSession(options, cwd, accessor) {
|
|
|
14560
14866
|
notes: [],
|
|
14561
14867
|
tasksCompleted: [],
|
|
14562
14868
|
tasksCreated: [],
|
|
14563
|
-
providerId: options.providerId ?? null
|
|
14869
|
+
providerId: options.providerId ?? detectedProviderId ?? null
|
|
14564
14870
|
};
|
|
14565
14871
|
if (options.grade) {
|
|
14566
14872
|
session.notes = ["[grade-mode:enabled]", ...session.notes ?? []];
|
|
@@ -14570,13 +14876,22 @@ async function startSession(options, cwd, accessor) {
|
|
|
14570
14876
|
}
|
|
14571
14877
|
sessions2.push(session);
|
|
14572
14878
|
await saveSessions(sessions2, cwd, accessor);
|
|
14879
|
+
if (session.providerId) {
|
|
14880
|
+
Promise.resolve().then(() => (init_adapters(), adapters_exports)).then(({ AdapterManager: AdapterManager2 }) => {
|
|
14881
|
+
const mgr = AdapterManager2.getInstance(cwd ?? process.cwd());
|
|
14882
|
+
mgr.discover();
|
|
14883
|
+
return mgr.activate(session.providerId);
|
|
14884
|
+
}).catch(() => {
|
|
14885
|
+
});
|
|
14886
|
+
}
|
|
14573
14887
|
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
14574
14888
|
hooks2.dispatch("onSessionStart", cwd ?? process.cwd(), {
|
|
14575
14889
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14576
14890
|
sessionId: session.id,
|
|
14577
14891
|
name: options.name,
|
|
14578
14892
|
scope,
|
|
14579
|
-
agent: options.agent
|
|
14893
|
+
agent: options.agent,
|
|
14894
|
+
providerId: session.providerId ?? void 0
|
|
14580
14895
|
}).catch(() => {
|
|
14581
14896
|
});
|
|
14582
14897
|
return session;
|
|
@@ -14612,7 +14927,8 @@ async function endSession(options = {}, cwd, accessor) {
|
|
|
14612
14927
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14613
14928
|
sessionId: session.id,
|
|
14614
14929
|
duration,
|
|
14615
|
-
tasksCompleted: session.tasksCompleted || []
|
|
14930
|
+
tasksCompleted: session.tasksCompleted || [],
|
|
14931
|
+
providerId: session.providerId ?? void 0
|
|
14616
14932
|
}).catch(() => {
|
|
14617
14933
|
});
|
|
14618
14934
|
const { bridgeSessionToMemory: bridgeSessionToMemory2 } = await Promise.resolve().then(() => (init_session_memory_bridge(), session_memory_bridge_exports));
|
|
@@ -15130,7 +15446,7 @@ async function initializeDefaultAdapters() {
|
|
|
15130
15446
|
}
|
|
15131
15447
|
}
|
|
15132
15448
|
var SpawnAdapterRegistry, spawnRegistry;
|
|
15133
|
-
var
|
|
15449
|
+
var init_adapter_registry2 = __esm({
|
|
15134
15450
|
"src/core/spawn/adapter-registry.ts"() {
|
|
15135
15451
|
"use strict";
|
|
15136
15452
|
SpawnAdapterRegistry = class {
|
|
@@ -16359,6 +16675,18 @@ async function startupHealthCheck(projectRoot) {
|
|
|
16359
16675
|
} else {
|
|
16360
16676
|
checks.push({ check: "log_dir", status: "pass", message: "Log directory present" });
|
|
16361
16677
|
}
|
|
16678
|
+
const brainDbCheck = checkBrainDb(root);
|
|
16679
|
+
checks.push({
|
|
16680
|
+
check: "brain_db",
|
|
16681
|
+
status: brainDbCheck.status === "passed" ? "pass" : "warn",
|
|
16682
|
+
message: brainDbCheck.message
|
|
16683
|
+
});
|
|
16684
|
+
const memBridgeCheck = checkMemoryBridge(root);
|
|
16685
|
+
checks.push({
|
|
16686
|
+
check: "memory_bridge",
|
|
16687
|
+
status: memBridgeCheck.status === "passed" ? "pass" : "warn",
|
|
16688
|
+
message: memBridgeCheck.message
|
|
16689
|
+
});
|
|
16362
16690
|
const hasFailures = failures.length > 0;
|
|
16363
16691
|
const state = hasFailures && !projectHealthy ? "needs_upgrade" : "healthy";
|
|
16364
16692
|
return {
|
|
@@ -20625,104 +20953,8 @@ async function resolveProviderFromModelRegistry(model) {
|
|
|
20625
20953
|
return resolveProviderFromModelIndex(index5, model);
|
|
20626
20954
|
}
|
|
20627
20955
|
|
|
20628
|
-
// src/core/metrics/provider-detection.ts
|
|
20629
|
-
import { basename as basename3 } from "node:path";
|
|
20630
|
-
import {
|
|
20631
|
-
detectProjectProviders,
|
|
20632
|
-
getProvider,
|
|
20633
|
-
resolveAlias
|
|
20634
|
-
} from "@cleocode/caamp";
|
|
20635
|
-
function inferProviderFromVendor(vendor) {
|
|
20636
|
-
const value = (vendor ?? "").trim().toLowerCase();
|
|
20637
|
-
if (!value) return void 0;
|
|
20638
|
-
if (value.includes("anthropic") || value.includes("claude")) return "anthropic";
|
|
20639
|
-
if (value.includes("openai") || value.includes("codex") || value.includes("chatgpt"))
|
|
20640
|
-
return "openai";
|
|
20641
|
-
if (value.includes("google") || value.includes("gemini")) return "google";
|
|
20642
|
-
if (value.includes("xai") || value.includes("grok")) return "xai";
|
|
20643
|
-
return void 0;
|
|
20644
|
-
}
|
|
20645
|
-
function getRuntimeHints(snapshot) {
|
|
20646
|
-
const argv = snapshot.argv ?? process.argv;
|
|
20647
|
-
const env = snapshot.env ?? process.env;
|
|
20648
|
-
const hints = /* @__PURE__ */ new Set();
|
|
20649
|
-
const bin = basename3(argv[1] ?? argv[0] ?? "").replace(/\.[^.]+$/, "");
|
|
20650
|
-
if (bin) hints.add(bin);
|
|
20651
|
-
if (env["CLAUDE_CODE_ENABLE_TELEMETRY"] || env["CLAUDE_CODE_ENTRYPOINT"]) {
|
|
20652
|
-
hints.add("claude-code");
|
|
20653
|
-
hints.add("claude");
|
|
20654
|
-
}
|
|
20655
|
-
if (env["OPENCODE_AGENT"] || env["OPENCODE"]) {
|
|
20656
|
-
hints.add("opencode");
|
|
20657
|
-
}
|
|
20658
|
-
if (env["CURSOR_TRACE_ID"] || env["CURSOR_AGENT"]) {
|
|
20659
|
-
hints.add("cursor");
|
|
20660
|
-
}
|
|
20661
|
-
return Array.from(hints);
|
|
20662
|
-
}
|
|
20663
|
-
function pickDetectionByHint(detections, hints) {
|
|
20664
|
-
for (const hint of hints) {
|
|
20665
|
-
const resolved = resolveAlias(hint);
|
|
20666
|
-
const direct = detections.find(
|
|
20667
|
-
(entry) => entry.provider.id === resolved || entry.provider.id === hint
|
|
20668
|
-
);
|
|
20669
|
-
if (direct) return direct;
|
|
20670
|
-
const byAlias = detections.find(
|
|
20671
|
-
(entry) => entry.provider.aliases.includes(hint) || entry.provider.agentFlag === hint || entry.provider.toolName.toLowerCase() === hint.toLowerCase()
|
|
20672
|
-
);
|
|
20673
|
-
if (byAlias) return byAlias;
|
|
20674
|
-
const provider = getProvider(resolved);
|
|
20675
|
-
if (provider) {
|
|
20676
|
-
return {
|
|
20677
|
-
provider,
|
|
20678
|
-
installed: true,
|
|
20679
|
-
methods: [],
|
|
20680
|
-
projectDetected: false
|
|
20681
|
-
};
|
|
20682
|
-
}
|
|
20683
|
-
}
|
|
20684
|
-
return null;
|
|
20685
|
-
}
|
|
20686
|
-
function selectRuntimeProviderContext(detections, snapshot = {}) {
|
|
20687
|
-
const hints = getRuntimeHints(snapshot);
|
|
20688
|
-
const hinted = pickDetectionByHint(detections, hints);
|
|
20689
|
-
const projectMatches = detections.filter((entry) => entry.projectDetected);
|
|
20690
|
-
const installed = detections.filter((entry) => entry.installed);
|
|
20691
|
-
const selected = hinted ?? (projectMatches.length === 1 ? projectMatches[0] : null) ?? (installed.length === 1 ? installed[0] : null);
|
|
20692
|
-
if (!selected) {
|
|
20693
|
-
return {
|
|
20694
|
-
runtimeCandidates: installed.map((entry) => entry.provider.id)
|
|
20695
|
-
};
|
|
20696
|
-
}
|
|
20697
|
-
return {
|
|
20698
|
-
runtimeProviderId: selected.provider.id,
|
|
20699
|
-
runtimeToolName: selected.provider.toolName,
|
|
20700
|
-
runtimeVendor: selected.provider.vendor,
|
|
20701
|
-
runtimeInstructionFile: selected.provider.instructFile,
|
|
20702
|
-
runtimeProjectDetected: selected.projectDetected,
|
|
20703
|
-
runtimeDetectionMethods: selected.methods,
|
|
20704
|
-
runtimeCandidates: installed.map((entry) => entry.provider.id),
|
|
20705
|
-
inferredModelProvider: inferProviderFromVendor(selected.provider.vendor)
|
|
20706
|
-
};
|
|
20707
|
-
}
|
|
20708
|
-
var cachedRuntimeProvider = null;
|
|
20709
|
-
function detectRuntimeProviderContext(snapshot = {}) {
|
|
20710
|
-
if (!snapshot.cwd && !snapshot.argv && !snapshot.env && cachedRuntimeProvider) {
|
|
20711
|
-
return cachedRuntimeProvider;
|
|
20712
|
-
}
|
|
20713
|
-
try {
|
|
20714
|
-
const detections = detectProjectProviders(snapshot.cwd ?? process.cwd());
|
|
20715
|
-
const context = selectRuntimeProviderContext(detections, snapshot);
|
|
20716
|
-
if (!snapshot.cwd && !snapshot.argv && !snapshot.env) {
|
|
20717
|
-
cachedRuntimeProvider = context;
|
|
20718
|
-
}
|
|
20719
|
-
return context;
|
|
20720
|
-
} catch {
|
|
20721
|
-
return {};
|
|
20722
|
-
}
|
|
20723
|
-
}
|
|
20724
|
-
|
|
20725
20956
|
// src/core/metrics/token-service.ts
|
|
20957
|
+
init_provider_detection();
|
|
20726
20958
|
function normalizeProvider(provider, model, runtimeProvider) {
|
|
20727
20959
|
const value = (provider ?? "").trim().toLowerCase();
|
|
20728
20960
|
const modelValue = (model ?? "").trim().toLowerCase();
|
|
@@ -28570,7 +28802,7 @@ async function orchestrateValidate(taskId, projectRoot) {
|
|
|
28570
28802
|
async function orchestrateSpawnExecute(taskId, adapterId, protocolType, projectRoot, _tier) {
|
|
28571
28803
|
const cwd = projectRoot ?? process.cwd();
|
|
28572
28804
|
try {
|
|
28573
|
-
const { initializeDefaultAdapters: initializeDefaultAdapters2, spawnRegistry: spawnRegistry2 } = await Promise.resolve().then(() => (
|
|
28805
|
+
const { initializeDefaultAdapters: initializeDefaultAdapters2, spawnRegistry: spawnRegistry2 } = await Promise.resolve().then(() => (init_adapter_registry2(), adapter_registry_exports));
|
|
28574
28806
|
await initializeDefaultAdapters2();
|
|
28575
28807
|
let adapter;
|
|
28576
28808
|
if (adapterId) {
|
|
@@ -29699,7 +29931,10 @@ async function checkEpicCompleteness(releaseTaskIds, cwd, accessor) {
|
|
|
29699
29931
|
if (!epic) continue;
|
|
29700
29932
|
const allChildren = data.tasks.filter((t) => t.parentId === epicId && t.id !== epicId);
|
|
29701
29933
|
const includedSet = new Set(includedTasks);
|
|
29702
|
-
const
|
|
29934
|
+
const parentIds = new Set(data.tasks.filter((t) => t.parentId).map((t) => t.parentId));
|
|
29935
|
+
const missingChildren = allChildren.filter(
|
|
29936
|
+
(t) => t.status === "done" && !parentIds.has(t.id) && !includedSet.has(t.id) && !releaseSet.has(t.id)
|
|
29937
|
+
).map((t) => ({ id: t.id, title: t.title, status: t.status }));
|
|
29703
29938
|
if (missingChildren.length > 0) hasIncomplete = true;
|
|
29704
29939
|
epics.push({
|
|
29705
29940
|
epicId,
|
|
@@ -29856,9 +30091,9 @@ init_tasks_schema();
|
|
|
29856
30091
|
init_pagination();
|
|
29857
30092
|
init_paths();
|
|
29858
30093
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
29859
|
-
import { existsSync as
|
|
30094
|
+
import { existsSync as existsSync43, renameSync as renameSync7 } from "node:fs";
|
|
29860
30095
|
import { readFile as readFile11 } from "node:fs/promises";
|
|
29861
|
-
import { join as
|
|
30096
|
+
import { join as join44 } from "node:path";
|
|
29862
30097
|
import { and as and6, count as count4, desc as desc5, eq as eq15 } from "drizzle-orm";
|
|
29863
30098
|
|
|
29864
30099
|
// src/core/release/changelog-writer.ts
|
|
@@ -29952,6 +30187,170 @@ function escapeRegex(str) {
|
|
|
29952
30187
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
29953
30188
|
}
|
|
29954
30189
|
|
|
30190
|
+
// src/core/release/version-bump.ts
|
|
30191
|
+
init_exit_codes();
|
|
30192
|
+
init_errors();
|
|
30193
|
+
init_paths();
|
|
30194
|
+
import { existsSync as existsSync42, readFileSync as readFileSync29, writeFileSync as writeFileSync7 } from "node:fs";
|
|
30195
|
+
import { join as join43 } from "node:path";
|
|
30196
|
+
function readConfigValueSync2(path, defaultValue, cwd) {
|
|
30197
|
+
try {
|
|
30198
|
+
const configPath = join43(getCleoDir(cwd), "config.json");
|
|
30199
|
+
if (!existsSync42(configPath)) return defaultValue;
|
|
30200
|
+
const config = JSON.parse(readFileSync29(configPath, "utf-8"));
|
|
30201
|
+
const keys = path.split(".");
|
|
30202
|
+
let value = config;
|
|
30203
|
+
for (const key of keys) {
|
|
30204
|
+
if (value == null || typeof value !== "object") return defaultValue;
|
|
30205
|
+
value = value[key];
|
|
30206
|
+
}
|
|
30207
|
+
return value ?? defaultValue;
|
|
30208
|
+
} catch {
|
|
30209
|
+
return defaultValue;
|
|
30210
|
+
}
|
|
30211
|
+
}
|
|
30212
|
+
var VERSION_WITH_PRERELEASE = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$/;
|
|
30213
|
+
function validateVersionFormat(version) {
|
|
30214
|
+
return VERSION_WITH_PRERELEASE.test(version);
|
|
30215
|
+
}
|
|
30216
|
+
function getVersionBumpConfig(cwd) {
|
|
30217
|
+
try {
|
|
30218
|
+
const raw = readConfigValueSync2("release.versionBump.files", [], cwd);
|
|
30219
|
+
return raw.map((entry) => ({
|
|
30220
|
+
file: entry.path ?? entry.file ?? "",
|
|
30221
|
+
strategy: entry.strategy,
|
|
30222
|
+
field: entry.jsonPath?.replace(/^\./, "") ?? entry.field,
|
|
30223
|
+
key: entry.key,
|
|
30224
|
+
section: entry.section,
|
|
30225
|
+
pattern: entry.sedPattern ?? entry.pattern
|
|
30226
|
+
})).filter((t) => t.file !== "");
|
|
30227
|
+
} catch {
|
|
30228
|
+
return [];
|
|
30229
|
+
}
|
|
30230
|
+
}
|
|
30231
|
+
function bumpFile(target, newVersion, projectRoot) {
|
|
30232
|
+
const filePath = join43(projectRoot, target.file);
|
|
30233
|
+
if (!existsSync42(filePath)) {
|
|
30234
|
+
return {
|
|
30235
|
+
file: target.file,
|
|
30236
|
+
strategy: target.strategy,
|
|
30237
|
+
success: false,
|
|
30238
|
+
error: `File not found: ${target.file}`
|
|
30239
|
+
};
|
|
30240
|
+
}
|
|
30241
|
+
try {
|
|
30242
|
+
const content = readFileSync29(filePath, "utf-8");
|
|
30243
|
+
let previousVersion;
|
|
30244
|
+
let newContent;
|
|
30245
|
+
switch (target.strategy) {
|
|
30246
|
+
case "plain": {
|
|
30247
|
+
previousVersion = content.trim();
|
|
30248
|
+
newContent = newVersion + "\n";
|
|
30249
|
+
break;
|
|
30250
|
+
}
|
|
30251
|
+
case "json": {
|
|
30252
|
+
const field = target.field ?? "version";
|
|
30253
|
+
const json = JSON.parse(content);
|
|
30254
|
+
previousVersion = getNestedField(json, field);
|
|
30255
|
+
setNestedField(json, field, newVersion);
|
|
30256
|
+
newContent = JSON.stringify(json, null, 2) + "\n";
|
|
30257
|
+
break;
|
|
30258
|
+
}
|
|
30259
|
+
case "toml": {
|
|
30260
|
+
const key = target.key ?? "version";
|
|
30261
|
+
const versionRegex = new RegExp(`^(${key}\\s*=\\s*")([^"]+)(")`, "m");
|
|
30262
|
+
const match = content.match(versionRegex);
|
|
30263
|
+
previousVersion = match?.[2];
|
|
30264
|
+
newContent = content.replace(versionRegex, `$1${newVersion}$3`);
|
|
30265
|
+
break;
|
|
30266
|
+
}
|
|
30267
|
+
case "sed": {
|
|
30268
|
+
const pattern = target.pattern ?? "";
|
|
30269
|
+
if (!pattern.includes("{{VERSION}}")) {
|
|
30270
|
+
return {
|
|
30271
|
+
file: target.file,
|
|
30272
|
+
strategy: target.strategy,
|
|
30273
|
+
success: false,
|
|
30274
|
+
error: "sed strategy requires {{VERSION}} placeholder in pattern"
|
|
30275
|
+
};
|
|
30276
|
+
}
|
|
30277
|
+
const regex = new RegExp(pattern.replace("{{VERSION}}", "([\\d.]+)"));
|
|
30278
|
+
const match = content.match(regex);
|
|
30279
|
+
previousVersion = match?.[1];
|
|
30280
|
+
newContent = content.replace(regex, pattern.replace("{{VERSION}}", newVersion));
|
|
30281
|
+
break;
|
|
30282
|
+
}
|
|
30283
|
+
default:
|
|
30284
|
+
return {
|
|
30285
|
+
file: target.file,
|
|
30286
|
+
strategy: target.strategy,
|
|
30287
|
+
success: false,
|
|
30288
|
+
error: `Unknown strategy: ${target.strategy}`
|
|
30289
|
+
};
|
|
30290
|
+
}
|
|
30291
|
+
writeFileSync7(filePath, newContent, "utf-8");
|
|
30292
|
+
return {
|
|
30293
|
+
file: target.file,
|
|
30294
|
+
strategy: target.strategy,
|
|
30295
|
+
success: true,
|
|
30296
|
+
previousVersion,
|
|
30297
|
+
newVersion
|
|
30298
|
+
};
|
|
30299
|
+
} catch (err) {
|
|
30300
|
+
return {
|
|
30301
|
+
file: target.file,
|
|
30302
|
+
strategy: target.strategy,
|
|
30303
|
+
success: false,
|
|
30304
|
+
error: String(err)
|
|
30305
|
+
};
|
|
30306
|
+
}
|
|
30307
|
+
}
|
|
30308
|
+
function bumpVersionFromConfig(newVersion, options = {}, cwd) {
|
|
30309
|
+
if (!validateVersionFormat(newVersion)) {
|
|
30310
|
+
throw new CleoError(
|
|
30311
|
+
6 /* VALIDATION_ERROR */,
|
|
30312
|
+
`Invalid version: '${newVersion}' (expected X.Y.Z or YYYY.M.patch)`
|
|
30313
|
+
);
|
|
30314
|
+
}
|
|
30315
|
+
const targets = getVersionBumpConfig(cwd);
|
|
30316
|
+
if (targets.length === 0) {
|
|
30317
|
+
throw new CleoError(
|
|
30318
|
+
1 /* GENERAL_ERROR */,
|
|
30319
|
+
"No version bump targets configured. Add release.versionBump.files to .cleo/config.json"
|
|
30320
|
+
);
|
|
30321
|
+
}
|
|
30322
|
+
const projectRoot = getProjectRoot(cwd);
|
|
30323
|
+
const results = [];
|
|
30324
|
+
if (options.dryRun) {
|
|
30325
|
+
for (const target of targets) {
|
|
30326
|
+
results.push({
|
|
30327
|
+
file: target.file,
|
|
30328
|
+
strategy: target.strategy,
|
|
30329
|
+
success: true,
|
|
30330
|
+
newVersion
|
|
30331
|
+
});
|
|
30332
|
+
}
|
|
30333
|
+
return { results, allSuccess: true };
|
|
30334
|
+
}
|
|
30335
|
+
for (const target of targets) {
|
|
30336
|
+
results.push(bumpFile(target, newVersion, projectRoot));
|
|
30337
|
+
}
|
|
30338
|
+
const allSuccess = results.every((r) => r.success);
|
|
30339
|
+
return { results, allSuccess };
|
|
30340
|
+
}
|
|
30341
|
+
function getNestedField(obj, path) {
|
|
30342
|
+
return path.split(".").reduce((acc, key) => acc?.[key], obj);
|
|
30343
|
+
}
|
|
30344
|
+
function setNestedField(obj, path, value) {
|
|
30345
|
+
const parts = path.split(".");
|
|
30346
|
+
let current = obj;
|
|
30347
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
30348
|
+
if (typeof current[parts[i]] !== "object") current[parts[i]] = {};
|
|
30349
|
+
current = current[parts[i]];
|
|
30350
|
+
}
|
|
30351
|
+
current[parts[parts.length - 1]] = value;
|
|
30352
|
+
}
|
|
30353
|
+
|
|
29955
30354
|
// src/core/release/release-manifest.ts
|
|
29956
30355
|
function normalizeLimit2(limit) {
|
|
29957
30356
|
return typeof limit === "number" && limit > 0 ? limit : void 0;
|
|
@@ -30177,7 +30576,7 @@ async function generateReleaseChangelog(version, loadTasksFn, cwd) {
|
|
|
30177
30576
|
}
|
|
30178
30577
|
const changelog = sections.join("\n");
|
|
30179
30578
|
await db.update(releaseManifests).set({ changelog }).where(eq15(releaseManifests.version, normalizedVersion)).run();
|
|
30180
|
-
const changelogPath =
|
|
30579
|
+
const changelogPath = join44(cwd ?? process.cwd(), "CHANGELOG.md");
|
|
30181
30580
|
let existingChangelogContent = "";
|
|
30182
30581
|
try {
|
|
30183
30582
|
existingChangelogContent = await readFile11(changelogPath, "utf8");
|
|
@@ -30291,13 +30690,13 @@ async function runReleaseGates(version, loadTasksFn, cwd, opts) {
|
|
|
30291
30690
|
message: incompleteTasks.length === 0 ? "All tasks completed" : `${incompleteTasks.length} tasks not completed: ${incompleteTasks.join(", ")}`
|
|
30292
30691
|
});
|
|
30293
30692
|
const projectRoot = cwd ?? getProjectRoot();
|
|
30294
|
-
const distPath =
|
|
30295
|
-
const isNodeProject =
|
|
30693
|
+
const distPath = join44(projectRoot, "dist", "cli", "index.js");
|
|
30694
|
+
const isNodeProject = existsSync43(join44(projectRoot, "package.json"));
|
|
30296
30695
|
if (isNodeProject) {
|
|
30297
30696
|
gates.push({
|
|
30298
30697
|
name: "build_artifact",
|
|
30299
|
-
status:
|
|
30300
|
-
message:
|
|
30698
|
+
status: existsSync43(distPath) ? "passed" : "failed",
|
|
30699
|
+
message: existsSync43(distPath) ? "dist/cli/index.js present" : "dist/ not built \u2014 run: npm run build"
|
|
30301
30700
|
});
|
|
30302
30701
|
}
|
|
30303
30702
|
if (opts?.dryRun) {
|
|
@@ -30307,6 +30706,8 @@ async function runReleaseGates(version, loadTasksFn, cwd, opts) {
|
|
|
30307
30706
|
message: "Skipped in dry-run mode"
|
|
30308
30707
|
});
|
|
30309
30708
|
} else {
|
|
30709
|
+
const bumpTargets = getVersionBumpConfig(cwd);
|
|
30710
|
+
const allowedDirty = /* @__PURE__ */ new Set(["CHANGELOG.md", ...bumpTargets.map((t) => t.file)]);
|
|
30310
30711
|
let workingTreeClean = true;
|
|
30311
30712
|
let dirtyFiles = [];
|
|
30312
30713
|
try {
|
|
@@ -30315,14 +30716,15 @@ async function runReleaseGates(version, loadTasksFn, cwd, opts) {
|
|
|
30315
30716
|
encoding: "utf-8",
|
|
30316
30717
|
stdio: "pipe"
|
|
30317
30718
|
});
|
|
30318
|
-
dirtyFiles = porcelain.split("\n").filter((l) => l.trim()).filter((l) => !l.startsWith("?? ")).map((l) => l.slice(3).trim()).filter((f) =>
|
|
30719
|
+
dirtyFiles = porcelain.split("\n").filter((l) => l.trim()).filter((l) => !l.startsWith("?? ")).map((l) => l.slice(3).trim()).filter((f) => !allowedDirty.has(f));
|
|
30319
30720
|
workingTreeClean = dirtyFiles.length === 0;
|
|
30320
30721
|
} catch {
|
|
30321
30722
|
}
|
|
30723
|
+
const excludeList = [...allowedDirty].join(", ");
|
|
30322
30724
|
gates.push({
|
|
30323
30725
|
name: "clean_working_tree",
|
|
30324
30726
|
status: workingTreeClean ? "passed" : "failed",
|
|
30325
|
-
message: workingTreeClean ?
|
|
30727
|
+
message: workingTreeClean ? `Working tree clean (excluding ${excludeList})` : `Uncommitted changes in: ${dirtyFiles.slice(0, 5).join(", ")}${dirtyFiles.length > 5 ? ` (+${dirtyFiles.length - 5} more)` : ""}`
|
|
30326
30728
|
});
|
|
30327
30729
|
}
|
|
30328
30730
|
const isPreRelease = normalizedVersion.includes("-");
|
|
@@ -30437,7 +30839,7 @@ async function rollbackRelease(version, reason, cwd) {
|
|
|
30437
30839
|
};
|
|
30438
30840
|
}
|
|
30439
30841
|
async function readPushPolicy(cwd) {
|
|
30440
|
-
const configPath =
|
|
30842
|
+
const configPath = join44(getCleoDirAbsolute(cwd), "config.json");
|
|
30441
30843
|
const config = await readJson(configPath);
|
|
30442
30844
|
if (!config) return void 0;
|
|
30443
30845
|
const release2 = config.release;
|
|
@@ -30535,170 +30937,6 @@ async function markReleasePushed(version, pushedAt, cwd, provenance) {
|
|
|
30535
30937
|
}).where(eq15(releaseManifests.version, normalizedVersion)).run();
|
|
30536
30938
|
}
|
|
30537
30939
|
|
|
30538
|
-
// src/core/release/version-bump.ts
|
|
30539
|
-
init_exit_codes();
|
|
30540
|
-
init_errors();
|
|
30541
|
-
init_paths();
|
|
30542
|
-
import { existsSync as existsSync43, readFileSync as readFileSync29, writeFileSync as writeFileSync7 } from "node:fs";
|
|
30543
|
-
import { join as join44 } from "node:path";
|
|
30544
|
-
function readConfigValueSync2(path, defaultValue, cwd) {
|
|
30545
|
-
try {
|
|
30546
|
-
const configPath = join44(getCleoDir(cwd), "config.json");
|
|
30547
|
-
if (!existsSync43(configPath)) return defaultValue;
|
|
30548
|
-
const config = JSON.parse(readFileSync29(configPath, "utf-8"));
|
|
30549
|
-
const keys = path.split(".");
|
|
30550
|
-
let value = config;
|
|
30551
|
-
for (const key of keys) {
|
|
30552
|
-
if (value == null || typeof value !== "object") return defaultValue;
|
|
30553
|
-
value = value[key];
|
|
30554
|
-
}
|
|
30555
|
-
return value ?? defaultValue;
|
|
30556
|
-
} catch {
|
|
30557
|
-
return defaultValue;
|
|
30558
|
-
}
|
|
30559
|
-
}
|
|
30560
|
-
var VERSION_WITH_PRERELEASE = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$/;
|
|
30561
|
-
function validateVersionFormat(version) {
|
|
30562
|
-
return VERSION_WITH_PRERELEASE.test(version);
|
|
30563
|
-
}
|
|
30564
|
-
function getVersionBumpConfig(cwd) {
|
|
30565
|
-
try {
|
|
30566
|
-
const raw = readConfigValueSync2("release.versionBump.files", [], cwd);
|
|
30567
|
-
return raw.map((entry) => ({
|
|
30568
|
-
file: entry.path ?? entry.file ?? "",
|
|
30569
|
-
strategy: entry.strategy,
|
|
30570
|
-
field: entry.jsonPath?.replace(/^\./, "") ?? entry.field,
|
|
30571
|
-
key: entry.key,
|
|
30572
|
-
section: entry.section,
|
|
30573
|
-
pattern: entry.sedPattern ?? entry.pattern
|
|
30574
|
-
})).filter((t) => t.file !== "");
|
|
30575
|
-
} catch {
|
|
30576
|
-
return [];
|
|
30577
|
-
}
|
|
30578
|
-
}
|
|
30579
|
-
function bumpFile(target, newVersion, projectRoot) {
|
|
30580
|
-
const filePath = join44(projectRoot, target.file);
|
|
30581
|
-
if (!existsSync43(filePath)) {
|
|
30582
|
-
return {
|
|
30583
|
-
file: target.file,
|
|
30584
|
-
strategy: target.strategy,
|
|
30585
|
-
success: false,
|
|
30586
|
-
error: `File not found: ${target.file}`
|
|
30587
|
-
};
|
|
30588
|
-
}
|
|
30589
|
-
try {
|
|
30590
|
-
const content = readFileSync29(filePath, "utf-8");
|
|
30591
|
-
let previousVersion;
|
|
30592
|
-
let newContent;
|
|
30593
|
-
switch (target.strategy) {
|
|
30594
|
-
case "plain": {
|
|
30595
|
-
previousVersion = content.trim();
|
|
30596
|
-
newContent = newVersion + "\n";
|
|
30597
|
-
break;
|
|
30598
|
-
}
|
|
30599
|
-
case "json": {
|
|
30600
|
-
const field = target.field ?? "version";
|
|
30601
|
-
const json = JSON.parse(content);
|
|
30602
|
-
previousVersion = getNestedField(json, field);
|
|
30603
|
-
setNestedField(json, field, newVersion);
|
|
30604
|
-
newContent = JSON.stringify(json, null, 2) + "\n";
|
|
30605
|
-
break;
|
|
30606
|
-
}
|
|
30607
|
-
case "toml": {
|
|
30608
|
-
const key = target.key ?? "version";
|
|
30609
|
-
const versionRegex = new RegExp(`^(${key}\\s*=\\s*")([^"]+)(")`, "m");
|
|
30610
|
-
const match = content.match(versionRegex);
|
|
30611
|
-
previousVersion = match?.[2];
|
|
30612
|
-
newContent = content.replace(versionRegex, `$1${newVersion}$3`);
|
|
30613
|
-
break;
|
|
30614
|
-
}
|
|
30615
|
-
case "sed": {
|
|
30616
|
-
const pattern = target.pattern ?? "";
|
|
30617
|
-
if (!pattern.includes("{{VERSION}}")) {
|
|
30618
|
-
return {
|
|
30619
|
-
file: target.file,
|
|
30620
|
-
strategy: target.strategy,
|
|
30621
|
-
success: false,
|
|
30622
|
-
error: "sed strategy requires {{VERSION}} placeholder in pattern"
|
|
30623
|
-
};
|
|
30624
|
-
}
|
|
30625
|
-
const regex = new RegExp(pattern.replace("{{VERSION}}", "([\\d.]+)"));
|
|
30626
|
-
const match = content.match(regex);
|
|
30627
|
-
previousVersion = match?.[1];
|
|
30628
|
-
newContent = content.replace(regex, pattern.replace("{{VERSION}}", newVersion));
|
|
30629
|
-
break;
|
|
30630
|
-
}
|
|
30631
|
-
default:
|
|
30632
|
-
return {
|
|
30633
|
-
file: target.file,
|
|
30634
|
-
strategy: target.strategy,
|
|
30635
|
-
success: false,
|
|
30636
|
-
error: `Unknown strategy: ${target.strategy}`
|
|
30637
|
-
};
|
|
30638
|
-
}
|
|
30639
|
-
writeFileSync7(filePath, newContent, "utf-8");
|
|
30640
|
-
return {
|
|
30641
|
-
file: target.file,
|
|
30642
|
-
strategy: target.strategy,
|
|
30643
|
-
success: true,
|
|
30644
|
-
previousVersion,
|
|
30645
|
-
newVersion
|
|
30646
|
-
};
|
|
30647
|
-
} catch (err) {
|
|
30648
|
-
return {
|
|
30649
|
-
file: target.file,
|
|
30650
|
-
strategy: target.strategy,
|
|
30651
|
-
success: false,
|
|
30652
|
-
error: String(err)
|
|
30653
|
-
};
|
|
30654
|
-
}
|
|
30655
|
-
}
|
|
30656
|
-
function bumpVersionFromConfig(newVersion, options = {}, cwd) {
|
|
30657
|
-
if (!validateVersionFormat(newVersion)) {
|
|
30658
|
-
throw new CleoError(
|
|
30659
|
-
6 /* VALIDATION_ERROR */,
|
|
30660
|
-
`Invalid version: '${newVersion}' (expected X.Y.Z or YYYY.M.patch)`
|
|
30661
|
-
);
|
|
30662
|
-
}
|
|
30663
|
-
const targets = getVersionBumpConfig(cwd);
|
|
30664
|
-
if (targets.length === 0) {
|
|
30665
|
-
throw new CleoError(
|
|
30666
|
-
1 /* GENERAL_ERROR */,
|
|
30667
|
-
"No version bump targets configured. Add release.versionBump.files to .cleo/config.json"
|
|
30668
|
-
);
|
|
30669
|
-
}
|
|
30670
|
-
const projectRoot = getProjectRoot(cwd);
|
|
30671
|
-
const results = [];
|
|
30672
|
-
if (options.dryRun) {
|
|
30673
|
-
for (const target of targets) {
|
|
30674
|
-
results.push({
|
|
30675
|
-
file: target.file,
|
|
30676
|
-
strategy: target.strategy,
|
|
30677
|
-
success: true,
|
|
30678
|
-
newVersion
|
|
30679
|
-
});
|
|
30680
|
-
}
|
|
30681
|
-
return { results, allSuccess: true };
|
|
30682
|
-
}
|
|
30683
|
-
for (const target of targets) {
|
|
30684
|
-
results.push(bumpFile(target, newVersion, projectRoot));
|
|
30685
|
-
}
|
|
30686
|
-
const allSuccess = results.every((r) => r.success);
|
|
30687
|
-
return { results, allSuccess };
|
|
30688
|
-
}
|
|
30689
|
-
function getNestedField(obj, path) {
|
|
30690
|
-
return path.split(".").reduce((acc, key) => acc?.[key], obj);
|
|
30691
|
-
}
|
|
30692
|
-
function setNestedField(obj, path, value) {
|
|
30693
|
-
const parts = path.split(".");
|
|
30694
|
-
let current = obj;
|
|
30695
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
30696
|
-
if (typeof current[parts[i]] !== "object") current[parts[i]] = {};
|
|
30697
|
-
current = current[parts[i]];
|
|
30698
|
-
}
|
|
30699
|
-
current[parts[parts.length - 1]] = value;
|
|
30700
|
-
}
|
|
30701
|
-
|
|
30702
30940
|
// src/dispatch/engines/release-engine.ts
|
|
30703
30941
|
init_data_accessor();
|
|
30704
30942
|
init_error();
|
|
@@ -45215,7 +45453,7 @@ import { execFileSync as execFileSync13 } from "node:child_process";
|
|
|
45215
45453
|
// src/config/build-config.ts
|
|
45216
45454
|
var BUILD_CONFIG = {
|
|
45217
45455
|
"name": "@cleocode/cleo",
|
|
45218
|
-
"version": "2026.3.
|
|
45456
|
+
"version": "2026.3.30",
|
|
45219
45457
|
"description": "CLEO V2 - TypeScript task management CLI for AI coding agents",
|
|
45220
45458
|
"repository": {
|
|
45221
45459
|
"owner": "kryptobaseddev",
|
|
@@ -45224,7 +45462,7 @@ var BUILD_CONFIG = {
|
|
|
45224
45462
|
"url": "https://github.com/kryptobaseddev/cleo.git",
|
|
45225
45463
|
"issuesUrl": "https://github.com/kryptobaseddev/cleo/issues"
|
|
45226
45464
|
},
|
|
45227
|
-
"buildDate": "2026-03-
|
|
45465
|
+
"buildDate": "2026-03-16T17:27:58.735Z",
|
|
45228
45466
|
"templates": {
|
|
45229
45467
|
"issueTemplatesDir": "templates/issue-templates"
|
|
45230
45468
|
}
|
|
@@ -47933,6 +48171,30 @@ async function runUpgrade(options = {}) {
|
|
|
47933
48171
|
}
|
|
47934
48172
|
} catch {
|
|
47935
48173
|
}
|
|
48174
|
+
try {
|
|
48175
|
+
const { ensureBrainDb: ensureBrainDb2 } = await Promise.resolve().then(() => (init_scaffold(), scaffold_exports));
|
|
48176
|
+
const brainResult = await ensureBrainDb2(projectRootForMaint);
|
|
48177
|
+
if (brainResult.action !== "skipped") {
|
|
48178
|
+
actions.push({
|
|
48179
|
+
action: "ensure_brain_db",
|
|
48180
|
+
status: "applied",
|
|
48181
|
+
details: brainResult.details ?? "brain.db initialized"
|
|
48182
|
+
});
|
|
48183
|
+
}
|
|
48184
|
+
} catch {
|
|
48185
|
+
}
|
|
48186
|
+
try {
|
|
48187
|
+
const { writeMemoryBridge: writeMemoryBridge2 } = await Promise.resolve().then(() => (init_memory_bridge(), memory_bridge_exports));
|
|
48188
|
+
const bridgeResult = await writeMemoryBridge2(projectRootForMaint);
|
|
48189
|
+
if (bridgeResult.written) {
|
|
48190
|
+
actions.push({
|
|
48191
|
+
action: "memory_bridge",
|
|
48192
|
+
status: "applied",
|
|
48193
|
+
details: "memory-bridge.md regenerated"
|
|
48194
|
+
});
|
|
48195
|
+
}
|
|
48196
|
+
} catch {
|
|
48197
|
+
}
|
|
47936
48198
|
try {
|
|
47937
48199
|
const rootGitignoreResult = await removeCleoFromRootGitignore(projectRootForMaint);
|
|
47938
48200
|
if (rootGitignoreResult.removed) {
|