@cleocode/cleo 2026.3.2-beta.1 → 2026.3.4
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 +319 -142
- package/dist/cli/index.js.map +4 -4
- package/dist/mcp/index.js +283 -110
- package/dist/mcp/index.js.map +4 -4
- package/package.json +1 -1
- package/packages/ct-skills/skills/ct-grade/SKILL.md +214 -0
- package/templates/CLEO-INJECTION.md +13 -0
package/dist/cli/index.js
CHANGED
|
@@ -714,8 +714,8 @@ function openNativeDatabase(path, options) {
|
|
|
714
714
|
return db;
|
|
715
715
|
}
|
|
716
716
|
function createDrizzleCallback(db) {
|
|
717
|
-
return async (
|
|
718
|
-
const stmt = db.prepare(
|
|
717
|
+
return async (sql5, params, method) => {
|
|
718
|
+
const stmt = db.prepare(sql5);
|
|
719
719
|
const p = params;
|
|
720
720
|
switch (method) {
|
|
721
721
|
case "run": {
|
|
@@ -5288,9 +5288,9 @@ var init_list = __esm({
|
|
|
5288
5288
|
});
|
|
5289
5289
|
|
|
5290
5290
|
// src/core/tasks/find.ts
|
|
5291
|
-
function fuzzyScore(query,
|
|
5291
|
+
function fuzzyScore(query, text3) {
|
|
5292
5292
|
const q = query.toLowerCase();
|
|
5293
|
-
const t =
|
|
5293
|
+
const t = text3.toLowerCase();
|
|
5294
5294
|
if (t === q) return 100;
|
|
5295
5295
|
if (t.includes(q)) return 80;
|
|
5296
5296
|
const words = t.split(/\s+/);
|
|
@@ -6793,6 +6793,51 @@ var init_session_view = __esm({
|
|
|
6793
6793
|
}
|
|
6794
6794
|
});
|
|
6795
6795
|
|
|
6796
|
+
// src/core/sessions/find.ts
|
|
6797
|
+
async function findSessions(accessor, params) {
|
|
6798
|
+
let sessions2 = await accessor.loadSessions();
|
|
6799
|
+
if (params?.status) {
|
|
6800
|
+
sessions2 = sessions2.filter((s) => s.status === params.status);
|
|
6801
|
+
}
|
|
6802
|
+
if (params?.scope) {
|
|
6803
|
+
const scopeParts = params.scope.split(":");
|
|
6804
|
+
const scopeType = scopeParts[0];
|
|
6805
|
+
const scopeId = scopeParts[1];
|
|
6806
|
+
sessions2 = sessions2.filter((s) => {
|
|
6807
|
+
if (s.scope.type !== scopeType) return false;
|
|
6808
|
+
if (scopeId && s.scope.rootTaskId !== scopeId && s.scope.epicId !== scopeId) return false;
|
|
6809
|
+
return true;
|
|
6810
|
+
});
|
|
6811
|
+
}
|
|
6812
|
+
if (params?.query) {
|
|
6813
|
+
const q = params.query.toLowerCase();
|
|
6814
|
+
sessions2 = sessions2.filter(
|
|
6815
|
+
(s) => s.id.toLowerCase().includes(q) || s.name.toLowerCase().includes(q)
|
|
6816
|
+
);
|
|
6817
|
+
}
|
|
6818
|
+
sessions2.sort(
|
|
6819
|
+
(a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime()
|
|
6820
|
+
);
|
|
6821
|
+
if (params?.limit && params.limit > 0) {
|
|
6822
|
+
sessions2 = sessions2.slice(0, params.limit);
|
|
6823
|
+
}
|
|
6824
|
+
return sessions2.map(toMinimal);
|
|
6825
|
+
}
|
|
6826
|
+
function toMinimal(s) {
|
|
6827
|
+
return {
|
|
6828
|
+
id: s.id,
|
|
6829
|
+
name: s.name,
|
|
6830
|
+
status: s.status,
|
|
6831
|
+
startedAt: s.startedAt,
|
|
6832
|
+
scope: s.scope
|
|
6833
|
+
};
|
|
6834
|
+
}
|
|
6835
|
+
var init_find2 = __esm({
|
|
6836
|
+
"src/core/sessions/find.ts"() {
|
|
6837
|
+
"use strict";
|
|
6838
|
+
}
|
|
6839
|
+
});
|
|
6840
|
+
|
|
6796
6841
|
// src/core/sessions/index.ts
|
|
6797
6842
|
var init_sessions = __esm({
|
|
6798
6843
|
"src/core/sessions/index.ts"() {
|
|
@@ -6814,6 +6859,7 @@ var init_sessions = __esm({
|
|
|
6814
6859
|
init_handoff();
|
|
6815
6860
|
init_briefing();
|
|
6816
6861
|
init_session_view();
|
|
6862
|
+
init_find2();
|
|
6817
6863
|
}
|
|
6818
6864
|
});
|
|
6819
6865
|
|
|
@@ -10308,9 +10354,13 @@ function createAudit() {
|
|
|
10308
10354
|
},
|
|
10309
10355
|
`${entry.metadata.gateway ?? "dispatch"} ${entry.domain}.${entry.operation}`
|
|
10310
10356
|
);
|
|
10311
|
-
|
|
10312
|
-
|
|
10313
|
-
}
|
|
10357
|
+
if (isGradeSession) {
|
|
10358
|
+
await writeToSqlite(entry, req.requestId);
|
|
10359
|
+
} else {
|
|
10360
|
+
writeToSqlite(entry, req.requestId).catch((err) => {
|
|
10361
|
+
log4.error({ err }, "Failed to persist audit entry to SQLite");
|
|
10362
|
+
});
|
|
10363
|
+
}
|
|
10314
10364
|
return response;
|
|
10315
10365
|
};
|
|
10316
10366
|
}
|
|
@@ -10318,16 +10368,16 @@ async function queryAudit(options) {
|
|
|
10318
10368
|
try {
|
|
10319
10369
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
|
|
10320
10370
|
const { auditLog: auditLog2 } = await Promise.resolve().then(() => (init_schema(), schema_exports));
|
|
10321
|
-
const { and:
|
|
10371
|
+
const { and: and5, eq: eq13, gte: gte2, or } = await import("drizzle-orm");
|
|
10322
10372
|
const db = await getDb2(process.cwd());
|
|
10323
10373
|
const conditions = [];
|
|
10324
|
-
if (options?.sessionId) conditions.push(
|
|
10325
|
-
if (options?.domain) conditions.push(
|
|
10326
|
-
if (options?.operation) conditions.push(or(
|
|
10327
|
-
if (options?.taskId) conditions.push(
|
|
10328
|
-
if (options?.since) conditions.push(
|
|
10374
|
+
if (options?.sessionId) conditions.push(eq13(auditLog2.sessionId, options.sessionId));
|
|
10375
|
+
if (options?.domain) conditions.push(eq13(auditLog2.domain, options.domain));
|
|
10376
|
+
if (options?.operation) conditions.push(or(eq13(auditLog2.operation, options.operation), eq13(auditLog2.action, options.operation)));
|
|
10377
|
+
if (options?.taskId) conditions.push(eq13(auditLog2.taskId, options.taskId));
|
|
10378
|
+
if (options?.since) conditions.push(gte2(auditLog2.timestamp, options.since));
|
|
10329
10379
|
const limit = options?.limit ?? 1e3;
|
|
10330
|
-
const rows = await db.select().from(auditLog2).where(conditions.length > 0 ?
|
|
10380
|
+
const rows = await db.select().from(auditLog2).where(conditions.length > 0 ? and5(...conditions) : void 0).orderBy(auditLog2.timestamp).limit(limit);
|
|
10331
10381
|
return rows.map((row) => ({
|
|
10332
10382
|
timestamp: row.timestamp,
|
|
10333
10383
|
sessionId: row.sessionId,
|
|
@@ -10459,8 +10509,8 @@ async function gradeSession(sessionId, cwd) {
|
|
|
10459
10509
|
);
|
|
10460
10510
|
let hygieneScore = 20;
|
|
10461
10511
|
for (const addCall of addCalls) {
|
|
10462
|
-
const
|
|
10463
|
-
if (!
|
|
10512
|
+
const desc4 = addCall.params?.description;
|
|
10513
|
+
if (!desc4 || desc4.trim().length === 0) {
|
|
10464
10514
|
hygieneScore -= 5;
|
|
10465
10515
|
result.flags.push(
|
|
10466
10516
|
`tasks.add without description (taskId: ${addCall.metadata?.taskId ?? "unknown"})`
|
|
@@ -11484,9 +11534,9 @@ function cliOutput(data, opts) {
|
|
|
11484
11534
|
}
|
|
11485
11535
|
const normalized = normalizeForHuman(opts.command, dataToRender);
|
|
11486
11536
|
const renderer = fieldExtracted ? renderGeneric : renderers[opts.command] ?? renderGeneric;
|
|
11487
|
-
const
|
|
11488
|
-
if (
|
|
11489
|
-
console.log(
|
|
11537
|
+
const text3 = renderer(normalized, ctx.quiet);
|
|
11538
|
+
if (text3) {
|
|
11539
|
+
console.log(text3);
|
|
11490
11540
|
}
|
|
11491
11541
|
return;
|
|
11492
11542
|
}
|
|
@@ -11591,7 +11641,7 @@ __export(session_store_exports, {
|
|
|
11591
11641
|
updateSession: () => updateSession,
|
|
11592
11642
|
workHistory: () => workHistory
|
|
11593
11643
|
});
|
|
11594
|
-
import { eq as
|
|
11644
|
+
import { eq as eq12, and as and4, desc as desc3, isNull as isNull3 } from "drizzle-orm";
|
|
11595
11645
|
async function createSession(session, cwd) {
|
|
11596
11646
|
const db = await getDb(cwd);
|
|
11597
11647
|
const tw = session.taskWork;
|
|
@@ -11613,7 +11663,7 @@ async function createSession(session, cwd) {
|
|
|
11613
11663
|
}
|
|
11614
11664
|
async function getSession(sessionId, cwd) {
|
|
11615
11665
|
const db = await getDb(cwd);
|
|
11616
|
-
const rows = await db.select().from(sessions).where(
|
|
11666
|
+
const rows = await db.select().from(sessions).where(eq12(sessions.id, sessionId)).all();
|
|
11617
11667
|
if (rows.length === 0) return null;
|
|
11618
11668
|
return rowToSession(rows[0]);
|
|
11619
11669
|
}
|
|
@@ -11637,16 +11687,16 @@ async function updateSession(sessionId, updates, cwd) {
|
|
|
11637
11687
|
if (updates.handoffConsumedBy !== void 0) updateRow.handoffConsumedBy = updates.handoffConsumedBy;
|
|
11638
11688
|
if (updates.debriefJson !== void 0) updateRow.debriefJson = updates.debriefJson;
|
|
11639
11689
|
if (updates.handoffJson !== void 0) updateRow.handoffJson = updates.handoffJson;
|
|
11640
|
-
db.update(sessions).set(updateRow).where(
|
|
11690
|
+
db.update(sessions).set(updateRow).where(eq12(sessions.id, sessionId)).run();
|
|
11641
11691
|
return getSession(sessionId, cwd);
|
|
11642
11692
|
}
|
|
11643
11693
|
async function listSessions(filters, cwd) {
|
|
11644
11694
|
const db = await getDb(cwd);
|
|
11645
11695
|
const conditions = [];
|
|
11646
11696
|
if (filters?.active) {
|
|
11647
|
-
conditions.push(
|
|
11697
|
+
conditions.push(eq12(sessions.status, "active"));
|
|
11648
11698
|
}
|
|
11649
|
-
const query = db.select().from(sessions).where(conditions.length > 0 ?
|
|
11699
|
+
const query = db.select().from(sessions).where(conditions.length > 0 ? and4(...conditions) : void 0).orderBy(desc3(sessions.startedAt));
|
|
11650
11700
|
const rows = filters?.limit ? await query.limit(filters.limit).all() : await query.all();
|
|
11651
11701
|
return rows.map(rowToSession);
|
|
11652
11702
|
}
|
|
@@ -11667,34 +11717,34 @@ async function endSession(sessionId, note, cwd) {
|
|
|
11667
11717
|
async function startTask2(sessionId, taskId, cwd) {
|
|
11668
11718
|
const db = await getDb(cwd);
|
|
11669
11719
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
11670
|
-
db.update(taskWorkHistory).set({ clearedAt: now }).where(
|
|
11671
|
-
|
|
11720
|
+
db.update(taskWorkHistory).set({ clearedAt: now }).where(and4(
|
|
11721
|
+
eq12(taskWorkHistory.sessionId, sessionId),
|
|
11672
11722
|
isNull3(taskWorkHistory.clearedAt)
|
|
11673
11723
|
)).run();
|
|
11674
11724
|
db.insert(taskWorkHistory).values({ sessionId, taskId, setAt: now }).run();
|
|
11675
|
-
db.update(sessions).set({ currentTask: taskId, taskStartedAt: now }).where(
|
|
11725
|
+
db.update(sessions).set({ currentTask: taskId, taskStartedAt: now }).where(eq12(sessions.id, sessionId)).run();
|
|
11676
11726
|
}
|
|
11677
11727
|
async function getCurrentTask(sessionId, cwd) {
|
|
11678
11728
|
const db = await getDb(cwd);
|
|
11679
11729
|
const rows = await db.select({
|
|
11680
11730
|
currentTask: sessions.currentTask,
|
|
11681
11731
|
taskStartedAt: sessions.taskStartedAt
|
|
11682
|
-
}).from(sessions).where(
|
|
11732
|
+
}).from(sessions).where(eq12(sessions.id, sessionId)).all();
|
|
11683
11733
|
if (rows.length === 0) return { taskId: null, since: null };
|
|
11684
11734
|
return { taskId: rows[0].currentTask, since: rows[0].taskStartedAt };
|
|
11685
11735
|
}
|
|
11686
11736
|
async function stopTask2(sessionId, cwd) {
|
|
11687
11737
|
const db = await getDb(cwd);
|
|
11688
11738
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
11689
|
-
db.update(taskWorkHistory).set({ clearedAt: now }).where(
|
|
11690
|
-
|
|
11739
|
+
db.update(taskWorkHistory).set({ clearedAt: now }).where(and4(
|
|
11740
|
+
eq12(taskWorkHistory.sessionId, sessionId),
|
|
11691
11741
|
isNull3(taskWorkHistory.clearedAt)
|
|
11692
11742
|
)).run();
|
|
11693
|
-
db.update(sessions).set({ currentTask: null, taskStartedAt: null }).where(
|
|
11743
|
+
db.update(sessions).set({ currentTask: null, taskStartedAt: null }).where(eq12(sessions.id, sessionId)).run();
|
|
11694
11744
|
}
|
|
11695
11745
|
async function workHistory(sessionId, limit = 50, cwd) {
|
|
11696
11746
|
const db = await getDb(cwd);
|
|
11697
|
-
const rows = await db.select().from(taskWorkHistory).where(
|
|
11747
|
+
const rows = await db.select().from(taskWorkHistory).where(eq12(taskWorkHistory.sessionId, sessionId)).orderBy(desc3(taskWorkHistory.setAt)).limit(limit).all();
|
|
11698
11748
|
return rows.map((r) => ({
|
|
11699
11749
|
taskId: r.taskId,
|
|
11700
11750
|
setAt: r.setAt,
|
|
@@ -11705,18 +11755,18 @@ async function gcSessions(maxAgeDays = 30, cwd) {
|
|
|
11705
11755
|
const db = await getDb(cwd);
|
|
11706
11756
|
const threshold = /* @__PURE__ */ new Date();
|
|
11707
11757
|
threshold.setDate(threshold.getDate() - maxAgeDays);
|
|
11708
|
-
const before = await db.select({ id: sessions.id }).from(sessions).where(
|
|
11709
|
-
|
|
11758
|
+
const before = await db.select({ id: sessions.id }).from(sessions).where(and4(
|
|
11759
|
+
eq12(sessions.status, "ended")
|
|
11710
11760
|
)).all();
|
|
11711
11761
|
const toUpdate = before;
|
|
11712
11762
|
if (toUpdate.length > 0) {
|
|
11713
|
-
db.update(sessions).set({ status: "orphaned" }).where(
|
|
11763
|
+
db.update(sessions).set({ status: "orphaned" }).where(eq12(sessions.status, "ended")).run();
|
|
11714
11764
|
}
|
|
11715
11765
|
return toUpdate.length;
|
|
11716
11766
|
}
|
|
11717
11767
|
async function getActiveSession(cwd) {
|
|
11718
11768
|
const db = await getDb(cwd);
|
|
11719
|
-
const rows = await db.select().from(sessions).where(
|
|
11769
|
+
const rows = await db.select().from(sessions).where(eq12(sessions.status, "active")).orderBy(desc3(sessions.startedAt)).limit(1).all();
|
|
11720
11770
|
if (rows.length === 0) return null;
|
|
11721
11771
|
return rowToSession(rows[0]);
|
|
11722
11772
|
}
|
|
@@ -11852,8 +11902,8 @@ __export(migration_sqlite_exports, {
|
|
|
11852
11902
|
import { existsSync as existsSync63, readFileSync as readFileSync46 } from "node:fs";
|
|
11853
11903
|
import { join as join67, dirname as dirname17 } from "node:path";
|
|
11854
11904
|
import { mkdirSync as mkdirSync19 } from "node:fs";
|
|
11855
|
-
import { drizzle as
|
|
11856
|
-
import { migrate as
|
|
11905
|
+
import { drizzle as drizzle3 } from "drizzle-orm/sqlite-proxy";
|
|
11906
|
+
import { migrate as migrate3 } from "drizzle-orm/sqlite-proxy/migrator";
|
|
11857
11907
|
function topoSortTasks(tasks2) {
|
|
11858
11908
|
const taskMap = new Map(tasks2.map((t) => [t.id, t]));
|
|
11859
11909
|
const sorted = [];
|
|
@@ -11935,10 +11985,10 @@ async function migrateJsonToSqliteAtomic(cwd, tempDbPath, logger) {
|
|
|
11935
11985
|
const nativeDb = openNativeDatabase(tempDbPath, { enableWal: true });
|
|
11936
11986
|
const drizzleCallback = createDrizzleCallback(nativeDb);
|
|
11937
11987
|
const batchCallback = createBatchCallback(nativeDb);
|
|
11938
|
-
const db =
|
|
11988
|
+
const db = drizzle3(drizzleCallback, batchCallback, { schema: schema_exports });
|
|
11939
11989
|
logger?.info("import", "create-tables", "Running drizzle migrations to create tables");
|
|
11940
11990
|
const migrationsFolder = resolveMigrationsFolder();
|
|
11941
|
-
await
|
|
11991
|
+
await migrate3(db, async (queries) => {
|
|
11942
11992
|
nativeDb.prepare("BEGIN").run();
|
|
11943
11993
|
try {
|
|
11944
11994
|
for (const query of queries) {
|
|
@@ -12188,10 +12238,10 @@ async function migrateJsonToSqlite(cwd, options) {
|
|
|
12188
12238
|
const jsonCounts = countJsonRecords(cleoDir);
|
|
12189
12239
|
result.jsonCounts = jsonCounts;
|
|
12190
12240
|
if (dbExists(cwd)) {
|
|
12191
|
-
const { ne: ne3, eq:
|
|
12241
|
+
const { ne: ne3, eq: eq13, count: count2 } = await import("drizzle-orm");
|
|
12192
12242
|
const db2 = await getDb(cwd);
|
|
12193
12243
|
const tasksResult = await db2.select({ count: count2() }).from(tasks).where(ne3(tasks.status, "archived")).get();
|
|
12194
|
-
const archivedResult = await db2.select({ count: count2() }).from(tasks).where(
|
|
12244
|
+
const archivedResult = await db2.select({ count: count2() }).from(tasks).where(eq13(tasks.status, "archived")).get();
|
|
12195
12245
|
const sessionsResult = await db2.select({ count: count2() }).from(sessions).get();
|
|
12196
12246
|
const existingCounts = {
|
|
12197
12247
|
tasks: tasksResult?.count ?? 0,
|
|
@@ -12391,10 +12441,10 @@ async function migrateJsonToSqlite(cwd, options) {
|
|
|
12391
12441
|
async function exportToJson(cwd) {
|
|
12392
12442
|
const { listTasks: listTasks3 } = await Promise.resolve().then(() => (init_task_store(), task_store_exports));
|
|
12393
12443
|
const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_store(), session_store_exports));
|
|
12394
|
-
const { eq:
|
|
12444
|
+
const { eq: eq13 } = await import("drizzle-orm");
|
|
12395
12445
|
const tasks2 = await listTasks3(void 0, cwd);
|
|
12396
12446
|
const db = await getDb(cwd);
|
|
12397
|
-
const archivedRows = await db.select().from(tasks).where(
|
|
12447
|
+
const archivedRows = await db.select().from(tasks).where(eq13(tasks.status, "archived")).all();
|
|
12398
12448
|
const archived = archivedRows.map((row) => ({
|
|
12399
12449
|
id: row.id,
|
|
12400
12450
|
title: row.title,
|
|
@@ -14151,12 +14201,12 @@ function compose(middlewares) {
|
|
|
14151
14201
|
return async (_req, next) => next();
|
|
14152
14202
|
}
|
|
14153
14203
|
return async (request, next) => {
|
|
14154
|
-
let
|
|
14204
|
+
let index3 = -1;
|
|
14155
14205
|
async function dispatch(i) {
|
|
14156
|
-
if (i <=
|
|
14206
|
+
if (i <= index3) {
|
|
14157
14207
|
throw new Error("next() called multiple times in middleware");
|
|
14158
14208
|
}
|
|
14159
|
-
|
|
14209
|
+
index3 = i;
|
|
14160
14210
|
let fn = middlewares[i];
|
|
14161
14211
|
if (i === middlewares.length) {
|
|
14162
14212
|
fn = async (_req, nxt) => nxt();
|
|
@@ -15594,6 +15644,7 @@ async function sessionStatus(projectRoot) {
|
|
|
15594
15644
|
return engineError("E_NOT_INITIALIZED", "Task database not initialized");
|
|
15595
15645
|
}
|
|
15596
15646
|
}
|
|
15647
|
+
var SESSION_LIST_DEFAULT_LIMIT = 10;
|
|
15597
15648
|
async function sessionList(projectRoot, params) {
|
|
15598
15649
|
try {
|
|
15599
15650
|
const accessor = await getAccessor(projectRoot);
|
|
@@ -15603,9 +15654,25 @@ async function sessionList(projectRoot, params) {
|
|
|
15603
15654
|
} else if (params?.active === false) {
|
|
15604
15655
|
result = result.filter((s) => s.status !== "active");
|
|
15605
15656
|
}
|
|
15606
|
-
|
|
15607
|
-
|
|
15608
|
-
|
|
15657
|
+
const total = result.length;
|
|
15658
|
+
const limit = params?.limit && params.limit > 0 ? params.limit : SESSION_LIST_DEFAULT_LIMIT;
|
|
15659
|
+
const truncated = total > limit;
|
|
15660
|
+
result = result.slice(0, limit);
|
|
15661
|
+
return {
|
|
15662
|
+
success: true,
|
|
15663
|
+
data: {
|
|
15664
|
+
sessions: result,
|
|
15665
|
+
_meta: { truncated, total }
|
|
15666
|
+
}
|
|
15667
|
+
};
|
|
15668
|
+
} catch {
|
|
15669
|
+
return engineError("E_NOT_INITIALIZED", "Task database not initialized");
|
|
15670
|
+
}
|
|
15671
|
+
}
|
|
15672
|
+
async function sessionFind(projectRoot, params) {
|
|
15673
|
+
try {
|
|
15674
|
+
const accessor = await getAccessor(projectRoot);
|
|
15675
|
+
const result = await findSessions(accessor, params);
|
|
15609
15676
|
return { success: true, data: result };
|
|
15610
15677
|
} catch {
|
|
15611
15678
|
return engineError("E_NOT_INITIALIZED", "Task database not initialized");
|
|
@@ -15765,6 +15832,7 @@ async function sessionStart(projectRoot, params) {
|
|
|
15765
15832
|
if (params.grade) {
|
|
15766
15833
|
process.env.CLEO_SESSION_GRADE = "true";
|
|
15767
15834
|
process.env.CLEO_SESSION_ID = sessionId;
|
|
15835
|
+
process.env.CLEO_SESSION_GRADE_ID = sessionId;
|
|
15768
15836
|
}
|
|
15769
15837
|
let briefing = null;
|
|
15770
15838
|
let previousDebrief = null;
|
|
@@ -15807,10 +15875,6 @@ async function sessionEnd(projectRoot, notes) {
|
|
|
15807
15875
|
const taskData = await accessor.loadTaskFile();
|
|
15808
15876
|
const sessionId = taskData._meta?.activeSession || "default";
|
|
15809
15877
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
15810
|
-
if (process.env.CLEO_SESSION_GRADE === "true") {
|
|
15811
|
-
delete process.env.CLEO_SESSION_GRADE;
|
|
15812
|
-
delete process.env.CLEO_SESSION_ID;
|
|
15813
|
-
}
|
|
15814
15878
|
if (taskData.focus) {
|
|
15815
15879
|
taskData.focus.currentTask = null;
|
|
15816
15880
|
if (notes) {
|
|
@@ -15972,11 +16036,14 @@ async function sessionHandoff(projectRoot, scope) {
|
|
|
15972
16036
|
const result = await getLastHandoff(projectRoot, scope);
|
|
15973
16037
|
return { success: true, data: result };
|
|
15974
16038
|
} catch (err) {
|
|
15975
|
-
|
|
15976
|
-
|
|
15977
|
-
|
|
15978
|
-
|
|
15979
|
-
|
|
16039
|
+
if (err instanceof CleoError) {
|
|
16040
|
+
const stringCode = `E_${getExitCodeName(err.code)}`;
|
|
16041
|
+
return engineError(stringCode, err.message, {
|
|
16042
|
+
...err.fix && { fix: err.fix }
|
|
16043
|
+
});
|
|
16044
|
+
}
|
|
16045
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
16046
|
+
return engineError("E_GENERAL", message);
|
|
15980
16047
|
}
|
|
15981
16048
|
}
|
|
15982
16049
|
async function sessionComputeHandoff(projectRoot, sessionId, options) {
|
|
@@ -16919,32 +16986,32 @@ async function queryAuditLogSqlite(projectRoot, filters) {
|
|
|
16919
16986
|
if (!existsSync68(dbPath)) return null;
|
|
16920
16987
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
|
|
16921
16988
|
const { auditLog: auditLog2 } = await Promise.resolve().then(() => (init_schema(), schema_exports));
|
|
16922
|
-
const { sql:
|
|
16989
|
+
const { sql: sql5 } = await import("drizzle-orm");
|
|
16923
16990
|
const db = await getDb2(projectRoot);
|
|
16924
16991
|
try {
|
|
16925
16992
|
const conditions = [];
|
|
16926
16993
|
if (filters?.operation) {
|
|
16927
|
-
conditions.push(
|
|
16994
|
+
conditions.push(sql5`(${auditLog2.action} = ${filters.operation} OR ${auditLog2.operation} = ${filters.operation})`);
|
|
16928
16995
|
}
|
|
16929
16996
|
if (filters?.taskId) {
|
|
16930
|
-
conditions.push(
|
|
16997
|
+
conditions.push(sql5`${auditLog2.taskId} = ${filters.taskId}`);
|
|
16931
16998
|
}
|
|
16932
16999
|
if (filters?.since) {
|
|
16933
|
-
conditions.push(
|
|
17000
|
+
conditions.push(sql5`${auditLog2.timestamp} >= ${filters.since}`);
|
|
16934
17001
|
}
|
|
16935
17002
|
if (filters?.until) {
|
|
16936
|
-
conditions.push(
|
|
17003
|
+
conditions.push(sql5`${auditLog2.timestamp} <= ${filters.until}`);
|
|
16937
17004
|
}
|
|
16938
|
-
const whereClause = conditions.length > 0 ?
|
|
17005
|
+
const whereClause = conditions.length > 0 ? sql5.join(conditions, sql5` AND `) : sql5`1=1`;
|
|
16939
17006
|
const countResult = await db.all(
|
|
16940
|
-
|
|
17007
|
+
sql5`SELECT count(*) as cnt FROM ${auditLog2} WHERE ${whereClause}`
|
|
16941
17008
|
);
|
|
16942
17009
|
const total = countResult[0]?.cnt ?? 0;
|
|
16943
17010
|
if (total === 0) return null;
|
|
16944
17011
|
const offset = filters?.offset ?? 0;
|
|
16945
17012
|
const limit = filters?.limit ?? 20;
|
|
16946
17013
|
const rows = await db.all(
|
|
16947
|
-
|
|
17014
|
+
sql5`SELECT * FROM ${auditLog2}
|
|
16948
17015
|
WHERE ${whereClause}
|
|
16949
17016
|
ORDER BY ${auditLog2.timestamp} DESC
|
|
16950
17017
|
LIMIT ${limit} OFFSET ${offset}`
|
|
@@ -19215,7 +19282,7 @@ async function validateSqliteRows(type, projectRoot) {
|
|
|
19215
19282
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
|
|
19216
19283
|
const schemaTable = await Promise.resolve().then(() => (init_schema(), schema_exports));
|
|
19217
19284
|
const zodSchemas = await Promise.resolve().then(() => (init_validation_schemas(), validation_schemas_exports));
|
|
19218
|
-
const { ne: ne3, eq:
|
|
19285
|
+
const { ne: ne3, eq: eq13 } = await import("drizzle-orm");
|
|
19219
19286
|
const db = await getDb2(projectRoot);
|
|
19220
19287
|
const errors = [];
|
|
19221
19288
|
switch (type) {
|
|
@@ -19227,7 +19294,7 @@ async function validateSqliteRows(type, projectRoot) {
|
|
|
19227
19294
|
break;
|
|
19228
19295
|
}
|
|
19229
19296
|
case "archive": {
|
|
19230
|
-
const rows = await db.select().from(schemaTable.tasks).where(
|
|
19297
|
+
const rows = await db.select().from(schemaTable.tasks).where(eq13(schemaTable.tasks.status, "archived"));
|
|
19231
19298
|
for (const row of rows) {
|
|
19232
19299
|
errors.push(...collectZodErrors(zodSchemas.selectTaskSchema.safeParse(row), row.id));
|
|
19233
19300
|
}
|
|
@@ -20033,9 +20100,9 @@ function autoDispatch(task) {
|
|
|
20033
20100
|
}
|
|
20034
20101
|
}
|
|
20035
20102
|
if (task.type === "epic") return "decomposition";
|
|
20036
|
-
const
|
|
20103
|
+
const text3 = `${task.title} ${task.description ?? ""}`.toLowerCase();
|
|
20037
20104
|
for (const [protocol, config] of Object.entries(DISPATCH_MAP)) {
|
|
20038
|
-
if (config.keywords.some((kw) =>
|
|
20105
|
+
if (config.keywords.some((kw) => text3.includes(kw))) {
|
|
20039
20106
|
return protocol;
|
|
20040
20107
|
}
|
|
20041
20108
|
}
|
|
@@ -21041,37 +21108,110 @@ init_errors();
|
|
|
21041
21108
|
init_exit_codes();
|
|
21042
21109
|
init_paths();
|
|
21043
21110
|
init_add();
|
|
21044
|
-
|
|
21045
|
-
|
|
21046
|
-
|
|
21047
|
-
|
|
21048
|
-
|
|
21049
|
-
|
|
21050
|
-
|
|
21051
|
-
|
|
21052
|
-
|
|
21053
|
-
|
|
21054
|
-
|
|
21055
|
-
|
|
21056
|
-
|
|
21057
|
-
|
|
21058
|
-
|
|
21059
|
-
|
|
21060
|
-
|
|
21061
|
-
|
|
21062
|
-
|
|
21063
|
-
|
|
21064
|
-
|
|
21065
|
-
|
|
21066
|
-
|
|
21067
|
-
|
|
21068
|
-
|
|
21069
|
-
|
|
21070
|
-
|
|
21071
|
-
|
|
21072
|
-
}
|
|
21073
|
-
|
|
21074
|
-
|
|
21111
|
+
|
|
21112
|
+
// src/store/brain-accessor.ts
|
|
21113
|
+
import { eq as eq11, and as and3, gte, desc, asc as asc2 } from "drizzle-orm";
|
|
21114
|
+
|
|
21115
|
+
// src/store/brain-sqlite.ts
|
|
21116
|
+
import { readMigrationFiles as readMigrationFiles2 } from "drizzle-orm/migrator";
|
|
21117
|
+
import { drizzle as drizzle2 } from "drizzle-orm/sqlite-proxy";
|
|
21118
|
+
import { migrate as migrate2 } from "drizzle-orm/sqlite-proxy/migrator";
|
|
21119
|
+
|
|
21120
|
+
// src/store/brain-schema.ts
|
|
21121
|
+
import {
|
|
21122
|
+
sqliteTable as sqliteTable2,
|
|
21123
|
+
text as text2,
|
|
21124
|
+
integer as integer2,
|
|
21125
|
+
real,
|
|
21126
|
+
index as index2,
|
|
21127
|
+
primaryKey as primaryKey2
|
|
21128
|
+
} from "drizzle-orm/sqlite-core";
|
|
21129
|
+
import { sql as sql4 } from "drizzle-orm";
|
|
21130
|
+
var BRAIN_DECISION_TYPES = ["architecture", "technical", "process", "strategic", "tactical"];
|
|
21131
|
+
var BRAIN_CONFIDENCE_LEVELS = ["low", "medium", "high"];
|
|
21132
|
+
var BRAIN_OUTCOME_TYPES = ["success", "failure", "mixed", "pending"];
|
|
21133
|
+
var BRAIN_PATTERN_TYPES = ["workflow", "blocker", "success", "failure", "optimization"];
|
|
21134
|
+
var BRAIN_IMPACT_LEVELS = ["low", "medium", "high"];
|
|
21135
|
+
var BRAIN_LINK_TYPES = ["produced_by", "applies_to", "informed_by", "contradicts"];
|
|
21136
|
+
var BRAIN_MEMORY_TYPES = ["decision", "pattern", "learning"];
|
|
21137
|
+
var brainDecisions = sqliteTable2("brain_decisions", {
|
|
21138
|
+
id: text2("id").primaryKey(),
|
|
21139
|
+
type: text2("type", { enum: BRAIN_DECISION_TYPES }).notNull(),
|
|
21140
|
+
decision: text2("decision").notNull(),
|
|
21141
|
+
rationale: text2("rationale").notNull(),
|
|
21142
|
+
confidence: text2("confidence", { enum: BRAIN_CONFIDENCE_LEVELS }).notNull(),
|
|
21143
|
+
outcome: text2("outcome", { enum: BRAIN_OUTCOME_TYPES }),
|
|
21144
|
+
alternativesJson: text2("alternatives_json"),
|
|
21145
|
+
contextEpicId: text2("context_epic_id"),
|
|
21146
|
+
// soft FK to tasks.id in tasks.db
|
|
21147
|
+
contextTaskId: text2("context_task_id"),
|
|
21148
|
+
// soft FK to tasks.id in tasks.db
|
|
21149
|
+
contextPhase: text2("context_phase"),
|
|
21150
|
+
createdAt: text2("created_at").notNull().default(sql4`(datetime('now'))`),
|
|
21151
|
+
updatedAt: text2("updated_at")
|
|
21152
|
+
}, (table) => [
|
|
21153
|
+
index2("idx_brain_decisions_type").on(table.type),
|
|
21154
|
+
index2("idx_brain_decisions_confidence").on(table.confidence),
|
|
21155
|
+
index2("idx_brain_decisions_outcome").on(table.outcome),
|
|
21156
|
+
index2("idx_brain_decisions_context_epic").on(table.contextEpicId),
|
|
21157
|
+
index2("idx_brain_decisions_context_task").on(table.contextTaskId)
|
|
21158
|
+
]);
|
|
21159
|
+
var brainPatterns = sqliteTable2("brain_patterns", {
|
|
21160
|
+
id: text2("id").primaryKey(),
|
|
21161
|
+
type: text2("type", { enum: BRAIN_PATTERN_TYPES }).notNull(),
|
|
21162
|
+
pattern: text2("pattern").notNull(),
|
|
21163
|
+
context: text2("context").notNull(),
|
|
21164
|
+
frequency: integer2("frequency").notNull().default(1),
|
|
21165
|
+
successRate: real("success_rate"),
|
|
21166
|
+
impact: text2("impact", { enum: BRAIN_IMPACT_LEVELS }),
|
|
21167
|
+
antiPattern: text2("anti_pattern"),
|
|
21168
|
+
mitigation: text2("mitigation"),
|
|
21169
|
+
examplesJson: text2("examples_json").default("[]"),
|
|
21170
|
+
extractedAt: text2("extracted_at").notNull().default(sql4`(datetime('now'))`),
|
|
21171
|
+
updatedAt: text2("updated_at")
|
|
21172
|
+
}, (table) => [
|
|
21173
|
+
index2("idx_brain_patterns_type").on(table.type),
|
|
21174
|
+
index2("idx_brain_patterns_impact").on(table.impact),
|
|
21175
|
+
index2("idx_brain_patterns_frequency").on(table.frequency)
|
|
21176
|
+
]);
|
|
21177
|
+
var brainLearnings = sqliteTable2("brain_learnings", {
|
|
21178
|
+
id: text2("id").primaryKey(),
|
|
21179
|
+
insight: text2("insight").notNull(),
|
|
21180
|
+
source: text2("source").notNull(),
|
|
21181
|
+
confidence: real("confidence").notNull(),
|
|
21182
|
+
// 0.0-1.0
|
|
21183
|
+
actionable: integer2("actionable", { mode: "boolean" }).notNull().default(false),
|
|
21184
|
+
application: text2("application"),
|
|
21185
|
+
applicableTypesJson: text2("applicable_types_json"),
|
|
21186
|
+
createdAt: text2("created_at").notNull().default(sql4`(datetime('now'))`),
|
|
21187
|
+
updatedAt: text2("updated_at")
|
|
21188
|
+
}, (table) => [
|
|
21189
|
+
index2("idx_brain_learnings_confidence").on(table.confidence),
|
|
21190
|
+
index2("idx_brain_learnings_actionable").on(table.actionable)
|
|
21191
|
+
]);
|
|
21192
|
+
var brainMemoryLinks = sqliteTable2("brain_memory_links", {
|
|
21193
|
+
memoryType: text2("memory_type", { enum: BRAIN_MEMORY_TYPES }).notNull(),
|
|
21194
|
+
memoryId: text2("memory_id").notNull(),
|
|
21195
|
+
taskId: text2("task_id").notNull(),
|
|
21196
|
+
// soft FK to tasks.id in tasks.db
|
|
21197
|
+
linkType: text2("link_type", { enum: BRAIN_LINK_TYPES }).notNull(),
|
|
21198
|
+
createdAt: text2("created_at").notNull().default(sql4`(datetime('now'))`)
|
|
21199
|
+
}, (table) => [
|
|
21200
|
+
primaryKey2({ columns: [table.memoryType, table.memoryId, table.taskId, table.linkType] }),
|
|
21201
|
+
index2("idx_brain_links_task").on(table.taskId),
|
|
21202
|
+
index2("idx_brain_links_memory").on(table.memoryType, table.memoryId)
|
|
21203
|
+
]);
|
|
21204
|
+
var brainSchemaMeta = sqliteTable2("brain_schema_meta", {
|
|
21205
|
+
key: text2("key").primaryKey(),
|
|
21206
|
+
value: text2("value").notNull()
|
|
21207
|
+
});
|
|
21208
|
+
|
|
21209
|
+
// src/store/brain-sqlite.ts
|
|
21210
|
+
init_paths();
|
|
21211
|
+
init_node_sqlite_adapter();
|
|
21212
|
+
|
|
21213
|
+
// src/core/memory/decisions.ts
|
|
21214
|
+
import { desc as desc2 } from "drizzle-orm";
|
|
21075
21215
|
|
|
21076
21216
|
// src/core/memory/patterns.ts
|
|
21077
21217
|
import { randomBytes as randomBytes6 } from "node:crypto";
|
|
@@ -21324,6 +21464,39 @@ function learningStats(projectRoot) {
|
|
|
21324
21464
|
};
|
|
21325
21465
|
}
|
|
21326
21466
|
|
|
21467
|
+
// src/core/memory/index.ts
|
|
21468
|
+
function filterManifestEntries(entries, filter) {
|
|
21469
|
+
let filtered = entries;
|
|
21470
|
+
if (filter.taskId) {
|
|
21471
|
+
const taskId = filter.taskId;
|
|
21472
|
+
filtered = filtered.filter(
|
|
21473
|
+
(e) => e.id.startsWith(taskId) || e.linked_tasks?.includes(taskId)
|
|
21474
|
+
);
|
|
21475
|
+
}
|
|
21476
|
+
if (filter.status) {
|
|
21477
|
+
filtered = filtered.filter((e) => e.status === filter.status);
|
|
21478
|
+
}
|
|
21479
|
+
if (filter.agent_type) {
|
|
21480
|
+
filtered = filtered.filter((e) => e.agent_type === filter.agent_type);
|
|
21481
|
+
}
|
|
21482
|
+
if (filter.topic) {
|
|
21483
|
+
filtered = filtered.filter((e) => e.topics.includes(filter.topic));
|
|
21484
|
+
}
|
|
21485
|
+
if (filter.actionable !== void 0) {
|
|
21486
|
+
filtered = filtered.filter((e) => e.actionable === filter.actionable);
|
|
21487
|
+
}
|
|
21488
|
+
if (filter.dateAfter) {
|
|
21489
|
+
filtered = filtered.filter((e) => e.date > filter.dateAfter);
|
|
21490
|
+
}
|
|
21491
|
+
if (filter.dateBefore) {
|
|
21492
|
+
filtered = filtered.filter((e) => e.date < filter.dateBefore);
|
|
21493
|
+
}
|
|
21494
|
+
if (filter.limit && filter.limit > 0) {
|
|
21495
|
+
filtered = filtered.slice(0, filter.limit);
|
|
21496
|
+
}
|
|
21497
|
+
return filtered;
|
|
21498
|
+
}
|
|
21499
|
+
|
|
21327
21500
|
// src/core/memory/engine-compat.ts
|
|
21328
21501
|
function getManifestPath2(projectRoot) {
|
|
21329
21502
|
return getManifestPath(projectRoot);
|
|
@@ -21737,13 +21910,13 @@ async function readReleases(cwd) {
|
|
|
21737
21910
|
const data = await readJson(getReleasesPath(cwd));
|
|
21738
21911
|
return data ?? { releases: [] };
|
|
21739
21912
|
}
|
|
21740
|
-
async function writeReleases(
|
|
21913
|
+
async function writeReleases(index3, cwd) {
|
|
21741
21914
|
const releasesPath = getReleasesPath(cwd);
|
|
21742
21915
|
const dir = dirname13(releasesPath);
|
|
21743
21916
|
if (!existsSync40(dir)) {
|
|
21744
21917
|
mkdirSync16(dir, { recursive: true });
|
|
21745
21918
|
}
|
|
21746
|
-
await saveJson(releasesPath,
|
|
21919
|
+
await saveJson(releasesPath, index3);
|
|
21747
21920
|
}
|
|
21748
21921
|
function isValidVersion(version) {
|
|
21749
21922
|
return /^v?\d+\.\d+\.\d+(-[\w.]+)?(\+[\w.]+)?$/.test(version);
|
|
@@ -21759,8 +21932,8 @@ async function prepareRelease(version, tasks2, notes, loadTasksFn, cwd) {
|
|
|
21759
21932
|
throw new Error(`Invalid version format: ${version} (expected X.Y.Z or YYYY.M.patch)`);
|
|
21760
21933
|
}
|
|
21761
21934
|
const normalizedVersion = normalizeVersion(version);
|
|
21762
|
-
const
|
|
21763
|
-
const existing =
|
|
21935
|
+
const index3 = await readReleases(cwd);
|
|
21936
|
+
const existing = index3.releases.find((r) => r.version === normalizedVersion);
|
|
21764
21937
|
if (existing) {
|
|
21765
21938
|
throw new Error(`Release ${normalizedVersion} already exists (status: ${existing.status})`);
|
|
21766
21939
|
}
|
|
@@ -21781,10 +21954,10 @@ async function prepareRelease(version, tasks2, notes, loadTasksFn, cwd) {
|
|
|
21781
21954
|
preparedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21782
21955
|
tasks: releaseTasks,
|
|
21783
21956
|
notes,
|
|
21784
|
-
previousVersion:
|
|
21957
|
+
previousVersion: index3.latest
|
|
21785
21958
|
};
|
|
21786
|
-
|
|
21787
|
-
await writeReleases(
|
|
21959
|
+
index3.releases.push(release2);
|
|
21960
|
+
await writeReleases(index3, cwd);
|
|
21788
21961
|
return {
|
|
21789
21962
|
version: normalizedVersion,
|
|
21790
21963
|
status: "prepared",
|
|
@@ -21797,8 +21970,8 @@ async function generateReleaseChangelog(version, loadTasksFn, cwd) {
|
|
|
21797
21970
|
throw new Error("version is required");
|
|
21798
21971
|
}
|
|
21799
21972
|
const normalizedVersion = normalizeVersion(version);
|
|
21800
|
-
const
|
|
21801
|
-
const release2 =
|
|
21973
|
+
const index3 = await readReleases(cwd);
|
|
21974
|
+
const release2 = index3.releases.find((r) => r.version === normalizedVersion);
|
|
21802
21975
|
if (!release2) {
|
|
21803
21976
|
throw new Error(`Release ${normalizedVersion} not found`);
|
|
21804
21977
|
}
|
|
@@ -21869,7 +22042,7 @@ async function generateReleaseChangelog(version, loadTasksFn, cwd) {
|
|
|
21869
22042
|
}
|
|
21870
22043
|
const changelog = sections.join("\n");
|
|
21871
22044
|
release2.changelog = changelog;
|
|
21872
|
-
await writeReleases(
|
|
22045
|
+
await writeReleases(index3, cwd);
|
|
21873
22046
|
return {
|
|
21874
22047
|
version: normalizedVersion,
|
|
21875
22048
|
changelog,
|
|
@@ -21889,8 +22062,8 @@ async function showManifestRelease(version, cwd) {
|
|
|
21889
22062
|
throw new Error("version is required");
|
|
21890
22063
|
}
|
|
21891
22064
|
const normalizedVersion = normalizeVersion(version);
|
|
21892
|
-
const
|
|
21893
|
-
const release2 =
|
|
22065
|
+
const index3 = await readReleases(cwd);
|
|
22066
|
+
const release2 = index3.releases.find((r) => r.version === normalizedVersion);
|
|
21894
22067
|
if (!release2) {
|
|
21895
22068
|
throw new Error(`Release ${normalizedVersion} not found`);
|
|
21896
22069
|
}
|
|
@@ -21901,8 +22074,8 @@ async function commitRelease(version, cwd) {
|
|
|
21901
22074
|
throw new Error("version is required");
|
|
21902
22075
|
}
|
|
21903
22076
|
const normalizedVersion = normalizeVersion(version);
|
|
21904
|
-
const
|
|
21905
|
-
const release2 =
|
|
22077
|
+
const index3 = await readReleases(cwd);
|
|
22078
|
+
const release2 = index3.releases.find((r) => r.version === normalizedVersion);
|
|
21906
22079
|
if (!release2) {
|
|
21907
22080
|
throw new Error(`Release ${normalizedVersion} not found`);
|
|
21908
22081
|
}
|
|
@@ -21911,7 +22084,7 @@ async function commitRelease(version, cwd) {
|
|
|
21911
22084
|
}
|
|
21912
22085
|
release2.status = "committed";
|
|
21913
22086
|
release2.committedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21914
|
-
await writeReleases(
|
|
22087
|
+
await writeReleases(index3, cwd);
|
|
21915
22088
|
return {
|
|
21916
22089
|
version: normalizedVersion,
|
|
21917
22090
|
status: "committed",
|
|
@@ -21923,15 +22096,15 @@ async function tagRelease(version, cwd) {
|
|
|
21923
22096
|
throw new Error("version is required");
|
|
21924
22097
|
}
|
|
21925
22098
|
const normalizedVersion = normalizeVersion(version);
|
|
21926
|
-
const
|
|
21927
|
-
const release2 =
|
|
22099
|
+
const index3 = await readReleases(cwd);
|
|
22100
|
+
const release2 = index3.releases.find((r) => r.version === normalizedVersion);
|
|
21928
22101
|
if (!release2) {
|
|
21929
22102
|
throw new Error(`Release ${normalizedVersion} not found`);
|
|
21930
22103
|
}
|
|
21931
22104
|
release2.status = "tagged";
|
|
21932
22105
|
release2.taggedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21933
|
-
|
|
21934
|
-
await writeReleases(
|
|
22106
|
+
index3.latest = normalizedVersion;
|
|
22107
|
+
await writeReleases(index3, cwd);
|
|
21935
22108
|
return {
|
|
21936
22109
|
version: normalizedVersion,
|
|
21937
22110
|
status: "tagged",
|
|
@@ -21943,8 +22116,8 @@ async function runReleaseGates(version, loadTasksFn, cwd) {
|
|
|
21943
22116
|
throw new Error("version is required");
|
|
21944
22117
|
}
|
|
21945
22118
|
const normalizedVersion = normalizeVersion(version);
|
|
21946
|
-
const
|
|
21947
|
-
const release2 =
|
|
22119
|
+
const index3 = await readReleases(cwd);
|
|
22120
|
+
const release2 = index3.releases.find((r) => r.version === normalizedVersion);
|
|
21948
22121
|
if (!release2) {
|
|
21949
22122
|
throw new Error(`Release ${normalizedVersion} not found`);
|
|
21950
22123
|
}
|
|
@@ -21988,18 +22161,18 @@ async function rollbackRelease(version, reason, cwd) {
|
|
|
21988
22161
|
throw new Error("version is required");
|
|
21989
22162
|
}
|
|
21990
22163
|
const normalizedVersion = normalizeVersion(version);
|
|
21991
|
-
const
|
|
21992
|
-
const release2 =
|
|
22164
|
+
const index3 = await readReleases(cwd);
|
|
22165
|
+
const release2 = index3.releases.find((r) => r.version === normalizedVersion);
|
|
21993
22166
|
if (!release2) {
|
|
21994
22167
|
throw new Error(`Release ${normalizedVersion} not found`);
|
|
21995
22168
|
}
|
|
21996
22169
|
const previousStatus = release2.status;
|
|
21997
22170
|
release2.status = "rolled_back";
|
|
21998
|
-
if (
|
|
21999
|
-
const otherReleases =
|
|
22000
|
-
|
|
22171
|
+
if (index3.latest === normalizedVersion) {
|
|
22172
|
+
const otherReleases = index3.releases.filter((r) => r.version !== normalizedVersion && r.status !== "rolled_back").sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
22173
|
+
index3.latest = otherReleases[0]?.version;
|
|
22001
22174
|
}
|
|
22002
|
-
await writeReleases(
|
|
22175
|
+
await writeReleases(index3, cwd);
|
|
22003
22176
|
return {
|
|
22004
22177
|
version: normalizedVersion,
|
|
22005
22178
|
previousStatus,
|
|
@@ -22069,12 +22242,12 @@ async function pushRelease(version, remote, cwd, opts) {
|
|
|
22069
22242
|
}
|
|
22070
22243
|
async function markReleasePushed(version, pushedAt, cwd) {
|
|
22071
22244
|
const normalizedVersion = normalizeVersion(version);
|
|
22072
|
-
const
|
|
22073
|
-
const release2 =
|
|
22245
|
+
const index3 = await readReleases(cwd);
|
|
22246
|
+
const release2 = index3.releases.find((r) => r.version === normalizedVersion);
|
|
22074
22247
|
if (release2) {
|
|
22075
22248
|
release2.status = "pushed";
|
|
22076
22249
|
release2.pushedAt = pushedAt;
|
|
22077
|
-
await writeReleases(
|
|
22250
|
+
await writeReleases(index3, cwd);
|
|
22078
22251
|
}
|
|
22079
22252
|
}
|
|
22080
22253
|
|
|
@@ -22841,6 +23014,10 @@ var SessionHandler = class {
|
|
|
22841
23014
|
const result = await sessionChainShow(this.projectRoot, chainSessionId);
|
|
22842
23015
|
return this.wrapEngineResult(result, "query", "session", operation, startTime);
|
|
22843
23016
|
}
|
|
23017
|
+
case "find": {
|
|
23018
|
+
const result = await sessionFind(this.projectRoot, params);
|
|
23019
|
+
return this.wrapEngineResult(result, "query", "session", operation, startTime);
|
|
23020
|
+
}
|
|
22844
23021
|
default:
|
|
22845
23022
|
return this.unsupported("query", "session", operation, startTime);
|
|
22846
23023
|
}
|
|
@@ -22961,7 +23138,7 @@ var SessionHandler = class {
|
|
|
22961
23138
|
// -----------------------------------------------------------------------
|
|
22962
23139
|
getSupportedOperations() {
|
|
22963
23140
|
return {
|
|
22964
|
-
query: ["status", "list", "show", "history", "decision.log", "context.drift", "handoff.show", "briefing.show", "debrief.show", "chain.show"],
|
|
23141
|
+
query: ["status", "list", "show", "find", "history", "decision.log", "context.drift", "handoff.show", "briefing.show", "debrief.show", "chain.show"],
|
|
22965
23142
|
mutate: ["start", "end", "resume", "suspend", "gc", "record.decision", "record.assumption"]
|
|
22966
23143
|
};
|
|
22967
23144
|
}
|
|
@@ -28077,19 +28254,19 @@ function registerCommandsCommand(program2) {
|
|
|
28077
28254
|
`Invalid relevance: ${relevance}. Valid: ${VALID_RELEVANCE.join(", ")}`
|
|
28078
28255
|
);
|
|
28079
28256
|
}
|
|
28080
|
-
const
|
|
28257
|
+
const index3 = await locateCommandsIndex();
|
|
28081
28258
|
console.error(
|
|
28082
28259
|
"[DEPRECATED] cleo commands reads from COMMANDS-INDEX.json which is deprecated.\nThe canonical operations reference is: docs/specs/CLEO-OPERATIONS-REFERENCE.md\nUse cleo_query/cleo_mutate MCP tools for programmatic access.\n"
|
|
28083
28260
|
);
|
|
28084
28261
|
if (opts["workflows"]) {
|
|
28085
|
-
cliOutput({ workflows:
|
|
28262
|
+
cliOutput({ workflows: index3.agentWorkflows ?? {} }, { command: "commands" });
|
|
28086
28263
|
return;
|
|
28087
28264
|
}
|
|
28088
28265
|
if (opts["lookup"]) {
|
|
28089
|
-
cliOutput({ quickLookup:
|
|
28266
|
+
cliOutput({ quickLookup: index3.quickLookup ?? {} }, { command: "commands" });
|
|
28090
28267
|
return;
|
|
28091
28268
|
}
|
|
28092
|
-
let commands =
|
|
28269
|
+
let commands = index3.commands;
|
|
28093
28270
|
if (category) {
|
|
28094
28271
|
commands = commands.filter((c) => c.category === category);
|
|
28095
28272
|
}
|
|
@@ -28143,9 +28320,9 @@ async function getScriptNames(projectRoot) {
|
|
|
28143
28320
|
}
|
|
28144
28321
|
async function getIndexedCommands(projectRoot) {
|
|
28145
28322
|
const indexPath = join54(projectRoot, "docs", "commands", "COMMANDS-INDEX.json");
|
|
28146
|
-
const
|
|
28147
|
-
if (!
|
|
28148
|
-
return
|
|
28323
|
+
const index3 = await readJson(indexPath);
|
|
28324
|
+
if (!index3) return [];
|
|
28325
|
+
return index3.commands.map((c) => c.name).sort();
|
|
28149
28326
|
}
|
|
28150
28327
|
async function detectDrift(projectRoot) {
|
|
28151
28328
|
const scripts = await getScriptNames(projectRoot);
|
|
@@ -29994,7 +30171,7 @@ async function discoverRelatedTasks(taskQuery, method, limit) {
|
|
|
29994
30171
|
candidates.sort((a, b) => b.score - a.score);
|
|
29995
30172
|
return candidates.slice(0, limit);
|
|
29996
30173
|
}
|
|
29997
|
-
function extractKeywords(
|
|
30174
|
+
function extractKeywords(text3) {
|
|
29998
30175
|
const stopWords = /* @__PURE__ */ new Set([
|
|
29999
30176
|
"the",
|
|
30000
30177
|
"a",
|
|
@@ -30077,7 +30254,7 @@ function extractKeywords(text2) {
|
|
|
30077
30254
|
"it",
|
|
30078
30255
|
"its"
|
|
30079
30256
|
]);
|
|
30080
|
-
return
|
|
30257
|
+
return text3.replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !stopWords.has(w));
|
|
30081
30258
|
}
|
|
30082
30259
|
async function searchAcrossProjects(pattern, projectFilter, limit = 20) {
|
|
30083
30260
|
if (/^\*:.+$/.test(pattern)) {
|