@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 CHANGED
@@ -714,8 +714,8 @@ function openNativeDatabase(path, options) {
714
714
  return db;
715
715
  }
716
716
  function createDrizzleCallback(db) {
717
- return async (sql4, params, method) => {
718
- const stmt = db.prepare(sql4);
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, text2) {
5291
+ function fuzzyScore(query, text3) {
5292
5292
  const q = query.toLowerCase();
5293
- const t = text2.toLowerCase();
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
- writeToSqlite(entry, req.requestId).catch((err) => {
10312
- log4.error({ err }, "Failed to persist audit entry to SQLite");
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: and4, eq: eq12, gte, or } = await import("drizzle-orm");
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(eq12(auditLog2.sessionId, options.sessionId));
10325
- if (options?.domain) conditions.push(eq12(auditLog2.domain, options.domain));
10326
- if (options?.operation) conditions.push(or(eq12(auditLog2.operation, options.operation), eq12(auditLog2.action, options.operation)));
10327
- if (options?.taskId) conditions.push(eq12(auditLog2.taskId, options.taskId));
10328
- if (options?.since) conditions.push(gte(auditLog2.timestamp, options.since));
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 ? and4(...conditions) : void 0).orderBy(auditLog2.timestamp).limit(limit);
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 desc2 = addCall.params?.description;
10463
- if (!desc2 || desc2.trim().length === 0) {
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 text2 = renderer(normalized, ctx.quiet);
11488
- if (text2) {
11489
- console.log(text2);
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 eq11, and as and3, desc, isNull as isNull3 } from "drizzle-orm";
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(eq11(sessions.id, sessionId)).all();
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(eq11(sessions.id, sessionId)).run();
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(eq11(sessions.status, "active"));
11697
+ conditions.push(eq12(sessions.status, "active"));
11648
11698
  }
11649
- const query = db.select().from(sessions).where(conditions.length > 0 ? and3(...conditions) : void 0).orderBy(desc(sessions.startedAt));
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(and3(
11671
- eq11(taskWorkHistory.sessionId, sessionId),
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(eq11(sessions.id, sessionId)).run();
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(eq11(sessions.id, sessionId)).all();
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(and3(
11690
- eq11(taskWorkHistory.sessionId, sessionId),
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(eq11(sessions.id, sessionId)).run();
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(eq11(taskWorkHistory.sessionId, sessionId)).orderBy(desc(taskWorkHistory.setAt)).limit(limit).all();
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(and3(
11709
- eq11(sessions.status, "ended")
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(eq11(sessions.status, "ended")).run();
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(eq11(sessions.status, "active")).orderBy(desc(sessions.startedAt)).limit(1).all();
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 drizzle2 } from "drizzle-orm/sqlite-proxy";
11856
- import { migrate as migrate2 } from "drizzle-orm/sqlite-proxy/migrator";
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 = drizzle2(drizzleCallback, batchCallback, { schema: schema_exports });
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 migrate2(db, async (queries) => {
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: eq12, count: count2 } = await import("drizzle-orm");
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(eq12(tasks.status, "archived")).get();
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: eq12 } = await import("drizzle-orm");
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(eq12(tasks.status, "archived")).all();
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 index2 = -1;
14204
+ let index3 = -1;
14155
14205
  async function dispatch(i) {
14156
- if (i <= index2) {
14206
+ if (i <= index3) {
14157
14207
  throw new Error("next() called multiple times in middleware");
14158
14208
  }
14159
- index2 = i;
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
- if (params?.limit && params.limit > 0) {
15607
- result = result.slice(0, params.limit);
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
- const message = err.message;
15976
- return engineError(
15977
- message.includes("not found") ? "E_NOT_FOUND" : "E_NOT_INITIALIZED",
15978
- message
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: sql4 } = await import("drizzle-orm");
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(sql4`(${auditLog2.action} = ${filters.operation} OR ${auditLog2.operation} = ${filters.operation})`);
16994
+ conditions.push(sql5`(${auditLog2.action} = ${filters.operation} OR ${auditLog2.operation} = ${filters.operation})`);
16928
16995
  }
16929
16996
  if (filters?.taskId) {
16930
- conditions.push(sql4`${auditLog2.taskId} = ${filters.taskId}`);
16997
+ conditions.push(sql5`${auditLog2.taskId} = ${filters.taskId}`);
16931
16998
  }
16932
16999
  if (filters?.since) {
16933
- conditions.push(sql4`${auditLog2.timestamp} >= ${filters.since}`);
17000
+ conditions.push(sql5`${auditLog2.timestamp} >= ${filters.since}`);
16934
17001
  }
16935
17002
  if (filters?.until) {
16936
- conditions.push(sql4`${auditLog2.timestamp} <= ${filters.until}`);
17003
+ conditions.push(sql5`${auditLog2.timestamp} <= ${filters.until}`);
16937
17004
  }
16938
- const whereClause = conditions.length > 0 ? sql4.join(conditions, sql4` AND `) : sql4`1=1`;
17005
+ const whereClause = conditions.length > 0 ? sql5.join(conditions, sql5` AND `) : sql5`1=1`;
16939
17006
  const countResult = await db.all(
16940
- sql4`SELECT count(*) as cnt FROM ${auditLog2} WHERE ${whereClause}`
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
- sql4`SELECT * FROM ${auditLog2}
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: eq12 } = await import("drizzle-orm");
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(eq12(schemaTable.tasks.status, "archived"));
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 text2 = `${task.title} ${task.description ?? ""}`.toLowerCase();
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) => text2.includes(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
- function filterManifestEntries(entries, filter) {
21045
- let filtered = entries;
21046
- if (filter.taskId) {
21047
- const taskId = filter.taskId;
21048
- filtered = filtered.filter(
21049
- (e) => e.id.startsWith(taskId) || e.linked_tasks?.includes(taskId)
21050
- );
21051
- }
21052
- if (filter.status) {
21053
- filtered = filtered.filter((e) => e.status === filter.status);
21054
- }
21055
- if (filter.agent_type) {
21056
- filtered = filtered.filter((e) => e.agent_type === filter.agent_type);
21057
- }
21058
- if (filter.topic) {
21059
- filtered = filtered.filter((e) => e.topics.includes(filter.topic));
21060
- }
21061
- if (filter.actionable !== void 0) {
21062
- filtered = filtered.filter((e) => e.actionable === filter.actionable);
21063
- }
21064
- if (filter.dateAfter) {
21065
- filtered = filtered.filter((e) => e.date > filter.dateAfter);
21066
- }
21067
- if (filter.dateBefore) {
21068
- filtered = filtered.filter((e) => e.date < filter.dateBefore);
21069
- }
21070
- if (filter.limit && filter.limit > 0) {
21071
- filtered = filtered.slice(0, filter.limit);
21072
- }
21073
- return filtered;
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(index2, cwd) {
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, index2);
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 index2 = await readReleases(cwd);
21763
- const existing = index2.releases.find((r) => r.version === normalizedVersion);
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: index2.latest
21957
+ previousVersion: index3.latest
21785
21958
  };
21786
- index2.releases.push(release2);
21787
- await writeReleases(index2, cwd);
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 index2 = await readReleases(cwd);
21801
- const release2 = index2.releases.find((r) => r.version === normalizedVersion);
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(index2, cwd);
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 index2 = await readReleases(cwd);
21893
- const release2 = index2.releases.find((r) => r.version === normalizedVersion);
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 index2 = await readReleases(cwd);
21905
- const release2 = index2.releases.find((r) => r.version === normalizedVersion);
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(index2, cwd);
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 index2 = await readReleases(cwd);
21927
- const release2 = index2.releases.find((r) => r.version === normalizedVersion);
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
- index2.latest = normalizedVersion;
21934
- await writeReleases(index2, cwd);
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 index2 = await readReleases(cwd);
21947
- const release2 = index2.releases.find((r) => r.version === normalizedVersion);
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 index2 = await readReleases(cwd);
21992
- const release2 = index2.releases.find((r) => r.version === normalizedVersion);
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 (index2.latest === normalizedVersion) {
21999
- const otherReleases = index2.releases.filter((r) => r.version !== normalizedVersion && r.status !== "rolled_back").sort((a, b) => b.createdAt.localeCompare(a.createdAt));
22000
- index2.latest = otherReleases[0]?.version;
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(index2, cwd);
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 index2 = await readReleases(cwd);
22073
- const release2 = index2.releases.find((r) => r.version === normalizedVersion);
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(index2, cwd);
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 index2 = await locateCommandsIndex();
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: index2.agentWorkflows ?? {} }, { command: "commands" });
28262
+ cliOutput({ workflows: index3.agentWorkflows ?? {} }, { command: "commands" });
28086
28263
  return;
28087
28264
  }
28088
28265
  if (opts["lookup"]) {
28089
- cliOutput({ quickLookup: index2.quickLookup ?? {} }, { command: "commands" });
28266
+ cliOutput({ quickLookup: index3.quickLookup ?? {} }, { command: "commands" });
28090
28267
  return;
28091
28268
  }
28092
- let commands = index2.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 index2 = await readJson(indexPath);
28147
- if (!index2) return [];
28148
- return index2.commands.map((c) => c.name).sort();
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(text2) {
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 text2.replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !stopWords.has(w));
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)) {