@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/mcp/index.js CHANGED
@@ -895,8 +895,8 @@ function openNativeDatabase(path, options) {
895
895
  return db;
896
896
  }
897
897
  function createDrizzleCallback(db) {
898
- return async (sql4, params, method) => {
899
- const stmt = db.prepare(sql4);
898
+ return async (sql5, params, method) => {
899
+ const stmt = db.prepare(sql5);
900
900
  const p = params;
901
901
  switch (method) {
902
902
  case "run": {
@@ -6963,9 +6963,13 @@ function createAudit() {
6963
6963
  },
6964
6964
  `${entry.metadata.gateway ?? "dispatch"} ${entry.domain}.${entry.operation}`
6965
6965
  );
6966
- writeToSqlite(entry, req.requestId).catch((err) => {
6967
- log4.error({ err }, "Failed to persist audit entry to SQLite");
6968
- });
6966
+ if (isGradeSession) {
6967
+ await writeToSqlite(entry, req.requestId);
6968
+ } else {
6969
+ writeToSqlite(entry, req.requestId).catch((err) => {
6970
+ log4.error({ err }, "Failed to persist audit entry to SQLite");
6971
+ });
6972
+ }
6969
6973
  return response;
6970
6974
  };
6971
6975
  }
@@ -6973,16 +6977,16 @@ async function queryAudit(options) {
6973
6977
  try {
6974
6978
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
6975
6979
  const { auditLog: auditLog2 } = await Promise.resolve().then(() => (init_schema(), schema_exports));
6976
- const { and: and3, eq: eq11, gte, or } = await import("drizzle-orm");
6980
+ const { and: and4, eq: eq12, gte: gte2, or } = await import("drizzle-orm");
6977
6981
  const db = await getDb2(process.cwd());
6978
6982
  const conditions = [];
6979
- if (options?.sessionId) conditions.push(eq11(auditLog2.sessionId, options.sessionId));
6980
- if (options?.domain) conditions.push(eq11(auditLog2.domain, options.domain));
6981
- if (options?.operation) conditions.push(or(eq11(auditLog2.operation, options.operation), eq11(auditLog2.action, options.operation)));
6982
- if (options?.taskId) conditions.push(eq11(auditLog2.taskId, options.taskId));
6983
- if (options?.since) conditions.push(gte(auditLog2.timestamp, options.since));
6983
+ if (options?.sessionId) conditions.push(eq12(auditLog2.sessionId, options.sessionId));
6984
+ if (options?.domain) conditions.push(eq12(auditLog2.domain, options.domain));
6985
+ if (options?.operation) conditions.push(or(eq12(auditLog2.operation, options.operation), eq12(auditLog2.action, options.operation)));
6986
+ if (options?.taskId) conditions.push(eq12(auditLog2.taskId, options.taskId));
6987
+ if (options?.since) conditions.push(gte2(auditLog2.timestamp, options.since));
6984
6988
  const limit = options?.limit ?? 1e3;
6985
- const rows = await db.select().from(auditLog2).where(conditions.length > 0 ? and3(...conditions) : void 0).orderBy(auditLog2.timestamp).limit(limit);
6989
+ const rows = await db.select().from(auditLog2).where(conditions.length > 0 ? and4(...conditions) : void 0).orderBy(auditLog2.timestamp).limit(limit);
6986
6990
  return rows.map((row) => ({
6987
6991
  timestamp: row.timestamp,
6988
6992
  sessionId: row.sessionId,
@@ -7114,8 +7118,8 @@ async function gradeSession(sessionId, cwd) {
7114
7118
  );
7115
7119
  let hygieneScore = 20;
7116
7120
  for (const addCall of addCalls) {
7117
- const desc = addCall.params?.description;
7118
- if (!desc || desc.trim().length === 0) {
7121
+ const desc3 = addCall.params?.description;
7122
+ if (!desc3 || desc3.trim().length === 0) {
7119
7123
  hygieneScore -= 5;
7120
7124
  result.flags.push(
7121
7125
  `tasks.add without description (taskId: ${addCall.metadata?.taskId ?? "unknown"})`
@@ -7276,6 +7280,8 @@ var QUERY_OPERATIONS = {
7276
7280
  // List all sessions
7277
7281
  "show",
7278
7282
  // Session details
7283
+ "find",
7284
+ // Lightweight session discovery (T5119)
7279
7285
  "history",
7280
7286
  // Session history
7281
7287
  "decision.log",
@@ -10053,12 +10059,12 @@ function compose(middlewares) {
10053
10059
  return async (_req, next) => next();
10054
10060
  }
10055
10061
  return async (request, next) => {
10056
- let index2 = -1;
10062
+ let index3 = -1;
10057
10063
  async function dispatch(i) {
10058
- if (i <= index2) {
10064
+ if (i <= index3) {
10059
10065
  throw new Error("next() called multiple times in middleware");
10060
10066
  }
10061
- index2 = i;
10067
+ index3 = i;
10062
10068
  let fn = middlewares[i];
10063
10069
  if (i === middlewares.length) {
10064
10070
  fn = async (_req, nxt) => nxt();
@@ -12255,9 +12261,9 @@ init_json();
12255
12261
  init_errors();
12256
12262
  init_exit_codes();
12257
12263
  init_paths();
12258
- function fuzzyScore(query, text2) {
12264
+ function fuzzyScore(query, text3) {
12259
12265
  const q = query.toLowerCase();
12260
- const t = text2.toLowerCase();
12266
+ const t = text3.toLowerCase();
12261
12267
  if (t === q) return 100;
12262
12268
  if (t.includes(q)) return 80;
12263
12269
  const words = t.split(/\s+/);
@@ -14054,6 +14060,46 @@ function computePipelineStage(current) {
14054
14060
  return void 0;
14055
14061
  }
14056
14062
 
14063
+ // src/core/sessions/find.ts
14064
+ async function findSessions(accessor, params) {
14065
+ let sessions2 = await accessor.loadSessions();
14066
+ if (params?.status) {
14067
+ sessions2 = sessions2.filter((s) => s.status === params.status);
14068
+ }
14069
+ if (params?.scope) {
14070
+ const scopeParts = params.scope.split(":");
14071
+ const scopeType = scopeParts[0];
14072
+ const scopeId = scopeParts[1];
14073
+ sessions2 = sessions2.filter((s) => {
14074
+ if (s.scope.type !== scopeType) return false;
14075
+ if (scopeId && s.scope.rootTaskId !== scopeId && s.scope.epicId !== scopeId) return false;
14076
+ return true;
14077
+ });
14078
+ }
14079
+ if (params?.query) {
14080
+ const q = params.query.toLowerCase();
14081
+ sessions2 = sessions2.filter(
14082
+ (s) => s.id.toLowerCase().includes(q) || s.name.toLowerCase().includes(q)
14083
+ );
14084
+ }
14085
+ sessions2.sort(
14086
+ (a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime()
14087
+ );
14088
+ if (params?.limit && params.limit > 0) {
14089
+ sessions2 = sessions2.slice(0, params.limit);
14090
+ }
14091
+ return sessions2.map(toMinimal);
14092
+ }
14093
+ function toMinimal(s) {
14094
+ return {
14095
+ id: s.id,
14096
+ name: s.name,
14097
+ status: s.status,
14098
+ startedAt: s.startedAt,
14099
+ scope: s.scope
14100
+ };
14101
+ }
14102
+
14057
14103
  // src/core/sessions/session-id.ts
14058
14104
  import { randomBytes as randomBytes5 } from "node:crypto";
14059
14105
  function generateSessionId() {
@@ -14183,6 +14229,7 @@ async function sessionStatus(projectRoot) {
14183
14229
  return engineError("E_NOT_INITIALIZED", "Task database not initialized");
14184
14230
  }
14185
14231
  }
14232
+ var SESSION_LIST_DEFAULT_LIMIT = 10;
14186
14233
  async function sessionList(projectRoot, params) {
14187
14234
  try {
14188
14235
  const accessor = await getAccessor(projectRoot);
@@ -14192,9 +14239,25 @@ async function sessionList(projectRoot, params) {
14192
14239
  } else if (params?.active === false) {
14193
14240
  result = result.filter((s) => s.status !== "active");
14194
14241
  }
14195
- if (params?.limit && params.limit > 0) {
14196
- result = result.slice(0, params.limit);
14197
- }
14242
+ const total = result.length;
14243
+ const limit = params?.limit && params.limit > 0 ? params.limit : SESSION_LIST_DEFAULT_LIMIT;
14244
+ const truncated = total > limit;
14245
+ result = result.slice(0, limit);
14246
+ return {
14247
+ success: true,
14248
+ data: {
14249
+ sessions: result,
14250
+ _meta: { truncated, total }
14251
+ }
14252
+ };
14253
+ } catch {
14254
+ return engineError("E_NOT_INITIALIZED", "Task database not initialized");
14255
+ }
14256
+ }
14257
+ async function sessionFind(projectRoot, params) {
14258
+ try {
14259
+ const accessor = await getAccessor(projectRoot);
14260
+ const result = await findSessions(accessor, params);
14198
14261
  return { success: true, data: result };
14199
14262
  } catch {
14200
14263
  return engineError("E_NOT_INITIALIZED", "Task database not initialized");
@@ -14354,6 +14417,7 @@ async function sessionStart(projectRoot, params) {
14354
14417
  if (params.grade) {
14355
14418
  process.env.CLEO_SESSION_GRADE = "true";
14356
14419
  process.env.CLEO_SESSION_ID = sessionId;
14420
+ process.env.CLEO_SESSION_GRADE_ID = sessionId;
14357
14421
  }
14358
14422
  let briefing = null;
14359
14423
  let previousDebrief = null;
@@ -14396,10 +14460,6 @@ async function sessionEnd(projectRoot, notes) {
14396
14460
  const taskData = await accessor.loadTaskFile();
14397
14461
  const sessionId = taskData._meta?.activeSession || "default";
14398
14462
  const now = (/* @__PURE__ */ new Date()).toISOString();
14399
- if (process.env.CLEO_SESSION_GRADE === "true") {
14400
- delete process.env.CLEO_SESSION_GRADE;
14401
- delete process.env.CLEO_SESSION_ID;
14402
- }
14403
14463
  if (taskData.focus) {
14404
14464
  taskData.focus.currentTask = null;
14405
14465
  if (notes) {
@@ -14561,11 +14621,14 @@ async function sessionHandoff(projectRoot, scope) {
14561
14621
  const result = await getLastHandoff(projectRoot, scope);
14562
14622
  return { success: true, data: result };
14563
14623
  } catch (err) {
14564
- const message = err.message;
14565
- return engineError(
14566
- message.includes("not found") ? "E_NOT_FOUND" : "E_NOT_INITIALIZED",
14567
- message
14568
- );
14624
+ if (err instanceof CleoError) {
14625
+ const stringCode = `E_${getExitCodeName(err.code)}`;
14626
+ return engineError(stringCode, err.message, {
14627
+ ...err.fix && { fix: err.fix }
14628
+ });
14629
+ }
14630
+ const message = err instanceof Error ? err.message : String(err);
14631
+ return engineError("E_GENERAL", message);
14569
14632
  }
14570
14633
  }
14571
14634
  async function sessionComputeHandoff(projectRoot, sessionId, options) {
@@ -15508,32 +15571,32 @@ async function queryAuditLogSqlite(projectRoot, filters) {
15508
15571
  if (!existsSync51(dbPath)) return null;
15509
15572
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
15510
15573
  const { auditLog: auditLog2 } = await Promise.resolve().then(() => (init_schema(), schema_exports));
15511
- const { sql: sql4 } = await import("drizzle-orm");
15574
+ const { sql: sql5 } = await import("drizzle-orm");
15512
15575
  const db = await getDb2(projectRoot);
15513
15576
  try {
15514
15577
  const conditions = [];
15515
15578
  if (filters?.operation) {
15516
- conditions.push(sql4`(${auditLog2.action} = ${filters.operation} OR ${auditLog2.operation} = ${filters.operation})`);
15579
+ conditions.push(sql5`(${auditLog2.action} = ${filters.operation} OR ${auditLog2.operation} = ${filters.operation})`);
15517
15580
  }
15518
15581
  if (filters?.taskId) {
15519
- conditions.push(sql4`${auditLog2.taskId} = ${filters.taskId}`);
15582
+ conditions.push(sql5`${auditLog2.taskId} = ${filters.taskId}`);
15520
15583
  }
15521
15584
  if (filters?.since) {
15522
- conditions.push(sql4`${auditLog2.timestamp} >= ${filters.since}`);
15585
+ conditions.push(sql5`${auditLog2.timestamp} >= ${filters.since}`);
15523
15586
  }
15524
15587
  if (filters?.until) {
15525
- conditions.push(sql4`${auditLog2.timestamp} <= ${filters.until}`);
15588
+ conditions.push(sql5`${auditLog2.timestamp} <= ${filters.until}`);
15526
15589
  }
15527
- const whereClause = conditions.length > 0 ? sql4.join(conditions, sql4` AND `) : sql4`1=1`;
15590
+ const whereClause = conditions.length > 0 ? sql5.join(conditions, sql5` AND `) : sql5`1=1`;
15528
15591
  const countResult = await db.all(
15529
- sql4`SELECT count(*) as cnt FROM ${auditLog2} WHERE ${whereClause}`
15592
+ sql5`SELECT count(*) as cnt FROM ${auditLog2} WHERE ${whereClause}`
15530
15593
  );
15531
15594
  const total = countResult[0]?.cnt ?? 0;
15532
15595
  if (total === 0) return null;
15533
15596
  const offset = filters?.offset ?? 0;
15534
15597
  const limit = filters?.limit ?? 20;
15535
15598
  const rows = await db.all(
15536
- sql4`SELECT * FROM ${auditLog2}
15599
+ sql5`SELECT * FROM ${auditLog2}
15537
15600
  WHERE ${whereClause}
15538
15601
  ORDER BY ${auditLog2.timestamp} DESC
15539
15602
  LIMIT ${limit} OFFSET ${offset}`
@@ -17806,7 +17869,7 @@ async function validateSqliteRows(type, projectRoot) {
17806
17869
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
17807
17870
  const schemaTable = await Promise.resolve().then(() => (init_schema(), schema_exports));
17808
17871
  const zodSchemas = await Promise.resolve().then(() => (init_validation_schemas(), validation_schemas_exports));
17809
- const { ne: ne3, eq: eq11 } = await import("drizzle-orm");
17872
+ const { ne: ne3, eq: eq12 } = await import("drizzle-orm");
17810
17873
  const db = await getDb2(projectRoot);
17811
17874
  const errors = [];
17812
17875
  switch (type) {
@@ -17818,7 +17881,7 @@ async function validateSqliteRows(type, projectRoot) {
17818
17881
  break;
17819
17882
  }
17820
17883
  case "archive": {
17821
- const rows = await db.select().from(schemaTable.tasks).where(eq11(schemaTable.tasks.status, "archived"));
17884
+ const rows = await db.select().from(schemaTable.tasks).where(eq12(schemaTable.tasks.status, "archived"));
17822
17885
  for (const row of rows) {
17823
17886
  errors.push(...collectZodErrors(zodSchemas.selectTaskSchema.safeParse(row), row.id));
17824
17887
  }
@@ -18624,9 +18687,9 @@ function autoDispatch(task) {
18624
18687
  }
18625
18688
  }
18626
18689
  if (task.type === "epic") return "decomposition";
18627
- const text2 = `${task.title} ${task.description ?? ""}`.toLowerCase();
18690
+ const text3 = `${task.title} ${task.description ?? ""}`.toLowerCase();
18628
18691
  for (const [protocol, config] of Object.entries(DISPATCH_MAP)) {
18629
- if (config.keywords.some((kw) => text2.includes(kw))) {
18692
+ if (config.keywords.some((kw) => text3.includes(kw))) {
18630
18693
  return protocol;
18631
18694
  }
18632
18695
  }
@@ -19631,37 +19694,110 @@ init_atomic();
19631
19694
  init_errors();
19632
19695
  init_exit_codes();
19633
19696
  init_paths();
19634
- function filterManifestEntries(entries, filter) {
19635
- let filtered = entries;
19636
- if (filter.taskId) {
19637
- const taskId = filter.taskId;
19638
- filtered = filtered.filter(
19639
- (e) => e.id.startsWith(taskId) || e.linked_tasks?.includes(taskId)
19640
- );
19641
- }
19642
- if (filter.status) {
19643
- filtered = filtered.filter((e) => e.status === filter.status);
19644
- }
19645
- if (filter.agent_type) {
19646
- filtered = filtered.filter((e) => e.agent_type === filter.agent_type);
19647
- }
19648
- if (filter.topic) {
19649
- filtered = filtered.filter((e) => e.topics.includes(filter.topic));
19650
- }
19651
- if (filter.actionable !== void 0) {
19652
- filtered = filtered.filter((e) => e.actionable === filter.actionable);
19653
- }
19654
- if (filter.dateAfter) {
19655
- filtered = filtered.filter((e) => e.date > filter.dateAfter);
19656
- }
19657
- if (filter.dateBefore) {
19658
- filtered = filtered.filter((e) => e.date < filter.dateBefore);
19659
- }
19660
- if (filter.limit && filter.limit > 0) {
19661
- filtered = filtered.slice(0, filter.limit);
19662
- }
19663
- return filtered;
19664
- }
19697
+
19698
+ // src/store/brain-accessor.ts
19699
+ import { eq as eq11, and as and3, gte, desc, asc as asc2 } from "drizzle-orm";
19700
+
19701
+ // src/store/brain-sqlite.ts
19702
+ import { readMigrationFiles as readMigrationFiles2 } from "drizzle-orm/migrator";
19703
+ import { drizzle as drizzle2 } from "drizzle-orm/sqlite-proxy";
19704
+ import { migrate as migrate2 } from "drizzle-orm/sqlite-proxy/migrator";
19705
+
19706
+ // src/store/brain-schema.ts
19707
+ import {
19708
+ sqliteTable as sqliteTable2,
19709
+ text as text2,
19710
+ integer as integer2,
19711
+ real,
19712
+ index as index2,
19713
+ primaryKey as primaryKey2
19714
+ } from "drizzle-orm/sqlite-core";
19715
+ import { sql as sql4 } from "drizzle-orm";
19716
+ var BRAIN_DECISION_TYPES = ["architecture", "technical", "process", "strategic", "tactical"];
19717
+ var BRAIN_CONFIDENCE_LEVELS = ["low", "medium", "high"];
19718
+ var BRAIN_OUTCOME_TYPES = ["success", "failure", "mixed", "pending"];
19719
+ var BRAIN_PATTERN_TYPES = ["workflow", "blocker", "success", "failure", "optimization"];
19720
+ var BRAIN_IMPACT_LEVELS = ["low", "medium", "high"];
19721
+ var BRAIN_LINK_TYPES = ["produced_by", "applies_to", "informed_by", "contradicts"];
19722
+ var BRAIN_MEMORY_TYPES = ["decision", "pattern", "learning"];
19723
+ var brainDecisions = sqliteTable2("brain_decisions", {
19724
+ id: text2("id").primaryKey(),
19725
+ type: text2("type", { enum: BRAIN_DECISION_TYPES }).notNull(),
19726
+ decision: text2("decision").notNull(),
19727
+ rationale: text2("rationale").notNull(),
19728
+ confidence: text2("confidence", { enum: BRAIN_CONFIDENCE_LEVELS }).notNull(),
19729
+ outcome: text2("outcome", { enum: BRAIN_OUTCOME_TYPES }),
19730
+ alternativesJson: text2("alternatives_json"),
19731
+ contextEpicId: text2("context_epic_id"),
19732
+ // soft FK to tasks.id in tasks.db
19733
+ contextTaskId: text2("context_task_id"),
19734
+ // soft FK to tasks.id in tasks.db
19735
+ contextPhase: text2("context_phase"),
19736
+ createdAt: text2("created_at").notNull().default(sql4`(datetime('now'))`),
19737
+ updatedAt: text2("updated_at")
19738
+ }, (table) => [
19739
+ index2("idx_brain_decisions_type").on(table.type),
19740
+ index2("idx_brain_decisions_confidence").on(table.confidence),
19741
+ index2("idx_brain_decisions_outcome").on(table.outcome),
19742
+ index2("idx_brain_decisions_context_epic").on(table.contextEpicId),
19743
+ index2("idx_brain_decisions_context_task").on(table.contextTaskId)
19744
+ ]);
19745
+ var brainPatterns = sqliteTable2("brain_patterns", {
19746
+ id: text2("id").primaryKey(),
19747
+ type: text2("type", { enum: BRAIN_PATTERN_TYPES }).notNull(),
19748
+ pattern: text2("pattern").notNull(),
19749
+ context: text2("context").notNull(),
19750
+ frequency: integer2("frequency").notNull().default(1),
19751
+ successRate: real("success_rate"),
19752
+ impact: text2("impact", { enum: BRAIN_IMPACT_LEVELS }),
19753
+ antiPattern: text2("anti_pattern"),
19754
+ mitigation: text2("mitigation"),
19755
+ examplesJson: text2("examples_json").default("[]"),
19756
+ extractedAt: text2("extracted_at").notNull().default(sql4`(datetime('now'))`),
19757
+ updatedAt: text2("updated_at")
19758
+ }, (table) => [
19759
+ index2("idx_brain_patterns_type").on(table.type),
19760
+ index2("idx_brain_patterns_impact").on(table.impact),
19761
+ index2("idx_brain_patterns_frequency").on(table.frequency)
19762
+ ]);
19763
+ var brainLearnings = sqliteTable2("brain_learnings", {
19764
+ id: text2("id").primaryKey(),
19765
+ insight: text2("insight").notNull(),
19766
+ source: text2("source").notNull(),
19767
+ confidence: real("confidence").notNull(),
19768
+ // 0.0-1.0
19769
+ actionable: integer2("actionable", { mode: "boolean" }).notNull().default(false),
19770
+ application: text2("application"),
19771
+ applicableTypesJson: text2("applicable_types_json"),
19772
+ createdAt: text2("created_at").notNull().default(sql4`(datetime('now'))`),
19773
+ updatedAt: text2("updated_at")
19774
+ }, (table) => [
19775
+ index2("idx_brain_learnings_confidence").on(table.confidence),
19776
+ index2("idx_brain_learnings_actionable").on(table.actionable)
19777
+ ]);
19778
+ var brainMemoryLinks = sqliteTable2("brain_memory_links", {
19779
+ memoryType: text2("memory_type", { enum: BRAIN_MEMORY_TYPES }).notNull(),
19780
+ memoryId: text2("memory_id").notNull(),
19781
+ taskId: text2("task_id").notNull(),
19782
+ // soft FK to tasks.id in tasks.db
19783
+ linkType: text2("link_type", { enum: BRAIN_LINK_TYPES }).notNull(),
19784
+ createdAt: text2("created_at").notNull().default(sql4`(datetime('now'))`)
19785
+ }, (table) => [
19786
+ primaryKey2({ columns: [table.memoryType, table.memoryId, table.taskId, table.linkType] }),
19787
+ index2("idx_brain_links_task").on(table.taskId),
19788
+ index2("idx_brain_links_memory").on(table.memoryType, table.memoryId)
19789
+ ]);
19790
+ var brainSchemaMeta = sqliteTable2("brain_schema_meta", {
19791
+ key: text2("key").primaryKey(),
19792
+ value: text2("value").notNull()
19793
+ });
19794
+
19795
+ // src/store/brain-sqlite.ts
19796
+ init_paths();
19797
+ init_node_sqlite_adapter();
19798
+
19799
+ // src/core/memory/decisions.ts
19800
+ import { desc as desc2 } from "drizzle-orm";
19665
19801
 
19666
19802
  // src/core/memory/patterns.ts
19667
19803
  import { randomBytes as randomBytes7 } from "node:crypto";
@@ -19914,6 +20050,39 @@ function learningStats(projectRoot) {
19914
20050
  };
19915
20051
  }
19916
20052
 
20053
+ // src/core/memory/index.ts
20054
+ function filterManifestEntries(entries, filter) {
20055
+ let filtered = entries;
20056
+ if (filter.taskId) {
20057
+ const taskId = filter.taskId;
20058
+ filtered = filtered.filter(
20059
+ (e) => e.id.startsWith(taskId) || e.linked_tasks?.includes(taskId)
20060
+ );
20061
+ }
20062
+ if (filter.status) {
20063
+ filtered = filtered.filter((e) => e.status === filter.status);
20064
+ }
20065
+ if (filter.agent_type) {
20066
+ filtered = filtered.filter((e) => e.agent_type === filter.agent_type);
20067
+ }
20068
+ if (filter.topic) {
20069
+ filtered = filtered.filter((e) => e.topics.includes(filter.topic));
20070
+ }
20071
+ if (filter.actionable !== void 0) {
20072
+ filtered = filtered.filter((e) => e.actionable === filter.actionable);
20073
+ }
20074
+ if (filter.dateAfter) {
20075
+ filtered = filtered.filter((e) => e.date > filter.dateAfter);
20076
+ }
20077
+ if (filter.dateBefore) {
20078
+ filtered = filtered.filter((e) => e.date < filter.dateBefore);
20079
+ }
20080
+ if (filter.limit && filter.limit > 0) {
20081
+ filtered = filtered.slice(0, filter.limit);
20082
+ }
20083
+ return filtered;
20084
+ }
20085
+
19917
20086
  // src/core/memory/engine-compat.ts
19918
20087
  function getManifestPath2(projectRoot) {
19919
20088
  return getManifestPath(projectRoot);
@@ -20327,13 +20496,13 @@ async function readReleases(cwd) {
20327
20496
  const data = await readJson(getReleasesPath(cwd));
20328
20497
  return data ?? { releases: [] };
20329
20498
  }
20330
- async function writeReleases(index2, cwd) {
20499
+ async function writeReleases(index3, cwd) {
20331
20500
  const releasesPath = getReleasesPath(cwd);
20332
20501
  const dir = dirname12(releasesPath);
20333
20502
  if (!existsSync41(dir)) {
20334
20503
  mkdirSync15(dir, { recursive: true });
20335
20504
  }
20336
- await saveJson(releasesPath, index2);
20505
+ await saveJson(releasesPath, index3);
20337
20506
  }
20338
20507
  function isValidVersion(version) {
20339
20508
  return /^v?\d+\.\d+\.\d+(-[\w.]+)?(\+[\w.]+)?$/.test(version);
@@ -20349,8 +20518,8 @@ async function prepareRelease(version, tasks2, notes, loadTasksFn, cwd) {
20349
20518
  throw new Error(`Invalid version format: ${version} (expected X.Y.Z or YYYY.M.patch)`);
20350
20519
  }
20351
20520
  const normalizedVersion = normalizeVersion(version);
20352
- const index2 = await readReleases(cwd);
20353
- const existing = index2.releases.find((r) => r.version === normalizedVersion);
20521
+ const index3 = await readReleases(cwd);
20522
+ const existing = index3.releases.find((r) => r.version === normalizedVersion);
20354
20523
  if (existing) {
20355
20524
  throw new Error(`Release ${normalizedVersion} already exists (status: ${existing.status})`);
20356
20525
  }
@@ -20371,10 +20540,10 @@ async function prepareRelease(version, tasks2, notes, loadTasksFn, cwd) {
20371
20540
  preparedAt: (/* @__PURE__ */ new Date()).toISOString(),
20372
20541
  tasks: releaseTasks,
20373
20542
  notes,
20374
- previousVersion: index2.latest
20543
+ previousVersion: index3.latest
20375
20544
  };
20376
- index2.releases.push(release2);
20377
- await writeReleases(index2, cwd);
20545
+ index3.releases.push(release2);
20546
+ await writeReleases(index3, cwd);
20378
20547
  return {
20379
20548
  version: normalizedVersion,
20380
20549
  status: "prepared",
@@ -20387,8 +20556,8 @@ async function generateReleaseChangelog(version, loadTasksFn, cwd) {
20387
20556
  throw new Error("version is required");
20388
20557
  }
20389
20558
  const normalizedVersion = normalizeVersion(version);
20390
- const index2 = await readReleases(cwd);
20391
- const release2 = index2.releases.find((r) => r.version === normalizedVersion);
20559
+ const index3 = await readReleases(cwd);
20560
+ const release2 = index3.releases.find((r) => r.version === normalizedVersion);
20392
20561
  if (!release2) {
20393
20562
  throw new Error(`Release ${normalizedVersion} not found`);
20394
20563
  }
@@ -20459,7 +20628,7 @@ async function generateReleaseChangelog(version, loadTasksFn, cwd) {
20459
20628
  }
20460
20629
  const changelog = sections.join("\n");
20461
20630
  release2.changelog = changelog;
20462
- await writeReleases(index2, cwd);
20631
+ await writeReleases(index3, cwd);
20463
20632
  return {
20464
20633
  version: normalizedVersion,
20465
20634
  changelog,
@@ -20479,8 +20648,8 @@ async function showManifestRelease(version, cwd) {
20479
20648
  throw new Error("version is required");
20480
20649
  }
20481
20650
  const normalizedVersion = normalizeVersion(version);
20482
- const index2 = await readReleases(cwd);
20483
- const release2 = index2.releases.find((r) => r.version === normalizedVersion);
20651
+ const index3 = await readReleases(cwd);
20652
+ const release2 = index3.releases.find((r) => r.version === normalizedVersion);
20484
20653
  if (!release2) {
20485
20654
  throw new Error(`Release ${normalizedVersion} not found`);
20486
20655
  }
@@ -20491,8 +20660,8 @@ async function commitRelease(version, cwd) {
20491
20660
  throw new Error("version is required");
20492
20661
  }
20493
20662
  const normalizedVersion = normalizeVersion(version);
20494
- const index2 = await readReleases(cwd);
20495
- const release2 = index2.releases.find((r) => r.version === normalizedVersion);
20663
+ const index3 = await readReleases(cwd);
20664
+ const release2 = index3.releases.find((r) => r.version === normalizedVersion);
20496
20665
  if (!release2) {
20497
20666
  throw new Error(`Release ${normalizedVersion} not found`);
20498
20667
  }
@@ -20501,7 +20670,7 @@ async function commitRelease(version, cwd) {
20501
20670
  }
20502
20671
  release2.status = "committed";
20503
20672
  release2.committedAt = (/* @__PURE__ */ new Date()).toISOString();
20504
- await writeReleases(index2, cwd);
20673
+ await writeReleases(index3, cwd);
20505
20674
  return {
20506
20675
  version: normalizedVersion,
20507
20676
  status: "committed",
@@ -20513,15 +20682,15 @@ async function tagRelease(version, cwd) {
20513
20682
  throw new Error("version is required");
20514
20683
  }
20515
20684
  const normalizedVersion = normalizeVersion(version);
20516
- const index2 = await readReleases(cwd);
20517
- const release2 = index2.releases.find((r) => r.version === normalizedVersion);
20685
+ const index3 = await readReleases(cwd);
20686
+ const release2 = index3.releases.find((r) => r.version === normalizedVersion);
20518
20687
  if (!release2) {
20519
20688
  throw new Error(`Release ${normalizedVersion} not found`);
20520
20689
  }
20521
20690
  release2.status = "tagged";
20522
20691
  release2.taggedAt = (/* @__PURE__ */ new Date()).toISOString();
20523
- index2.latest = normalizedVersion;
20524
- await writeReleases(index2, cwd);
20692
+ index3.latest = normalizedVersion;
20693
+ await writeReleases(index3, cwd);
20525
20694
  return {
20526
20695
  version: normalizedVersion,
20527
20696
  status: "tagged",
@@ -20533,8 +20702,8 @@ async function runReleaseGates(version, loadTasksFn, cwd) {
20533
20702
  throw new Error("version is required");
20534
20703
  }
20535
20704
  const normalizedVersion = normalizeVersion(version);
20536
- const index2 = await readReleases(cwd);
20537
- const release2 = index2.releases.find((r) => r.version === normalizedVersion);
20705
+ const index3 = await readReleases(cwd);
20706
+ const release2 = index3.releases.find((r) => r.version === normalizedVersion);
20538
20707
  if (!release2) {
20539
20708
  throw new Error(`Release ${normalizedVersion} not found`);
20540
20709
  }
@@ -20578,18 +20747,18 @@ async function rollbackRelease(version, reason, cwd) {
20578
20747
  throw new Error("version is required");
20579
20748
  }
20580
20749
  const normalizedVersion = normalizeVersion(version);
20581
- const index2 = await readReleases(cwd);
20582
- const release2 = index2.releases.find((r) => r.version === normalizedVersion);
20750
+ const index3 = await readReleases(cwd);
20751
+ const release2 = index3.releases.find((r) => r.version === normalizedVersion);
20583
20752
  if (!release2) {
20584
20753
  throw new Error(`Release ${normalizedVersion} not found`);
20585
20754
  }
20586
20755
  const previousStatus = release2.status;
20587
20756
  release2.status = "rolled_back";
20588
- if (index2.latest === normalizedVersion) {
20589
- const otherReleases = index2.releases.filter((r) => r.version !== normalizedVersion && r.status !== "rolled_back").sort((a, b) => b.createdAt.localeCompare(a.createdAt));
20590
- index2.latest = otherReleases[0]?.version;
20757
+ if (index3.latest === normalizedVersion) {
20758
+ const otherReleases = index3.releases.filter((r) => r.version !== normalizedVersion && r.status !== "rolled_back").sort((a, b) => b.createdAt.localeCompare(a.createdAt));
20759
+ index3.latest = otherReleases[0]?.version;
20591
20760
  }
20592
- await writeReleases(index2, cwd);
20761
+ await writeReleases(index3, cwd);
20593
20762
  return {
20594
20763
  version: normalizedVersion,
20595
20764
  previousStatus,
@@ -20659,12 +20828,12 @@ async function pushRelease(version, remote, cwd, opts) {
20659
20828
  }
20660
20829
  async function markReleasePushed(version, pushedAt, cwd) {
20661
20830
  const normalizedVersion = normalizeVersion(version);
20662
- const index2 = await readReleases(cwd);
20663
- const release2 = index2.releases.find((r) => r.version === normalizedVersion);
20831
+ const index3 = await readReleases(cwd);
20832
+ const release2 = index3.releases.find((r) => r.version === normalizedVersion);
20664
20833
  if (release2) {
20665
20834
  release2.status = "pushed";
20666
20835
  release2.pushedAt = pushedAt;
20667
- await writeReleases(index2, cwd);
20836
+ await writeReleases(index3, cwd);
20668
20837
  }
20669
20838
  }
20670
20839
 
@@ -21431,6 +21600,10 @@ var SessionHandler = class {
21431
21600
  const result = await sessionChainShow(this.projectRoot, chainSessionId);
21432
21601
  return this.wrapEngineResult(result, "query", "session", operation, startTime);
21433
21602
  }
21603
+ case "find": {
21604
+ const result = await sessionFind(this.projectRoot, params);
21605
+ return this.wrapEngineResult(result, "query", "session", operation, startTime);
21606
+ }
21434
21607
  default:
21435
21608
  return this.unsupported("query", "session", operation, startTime);
21436
21609
  }
@@ -21551,7 +21724,7 @@ var SessionHandler = class {
21551
21724
  // -----------------------------------------------------------------------
21552
21725
  getSupportedOperations() {
21553
21726
  return {
21554
- query: ["status", "list", "show", "history", "decision.log", "context.drift", "handoff.show", "briefing.show", "debrief.show", "chain.show"],
21727
+ query: ["status", "list", "show", "find", "history", "decision.log", "context.drift", "handoff.show", "briefing.show", "debrief.show", "chain.show"],
21555
21728
  mutate: ["start", "end", "resume", "suspend", "gc", "record.decision", "record.assumption"]
21556
21729
  };
21557
21730
  }
@@ -25626,8 +25799,8 @@ var DECOMPOSITION_RULES = [
25626
25799
  validate: (entry) => {
25627
25800
  const title = entry.title;
25628
25801
  const description = entry.description;
25629
- const text2 = `${title} ${description}`;
25630
- return !/\b\d+\s*(hour|day|week|minute|hr|min)s?\b/i.test(text2);
25802
+ const text3 = `${title} ${description}`;
25803
+ return !/\b\d+\s*(hour|day|week|minute|hr|min)s?\b/i.test(text3);
25631
25804
  }
25632
25805
  },
25633
25806
  {
@@ -25636,9 +25809,9 @@ var DECOMPOSITION_RULES = [
25636
25809
  message: "Must include acceptance criteria in task description",
25637
25810
  fix: "Add clear acceptance criteria: what must be true when the task is done",
25638
25811
  validate: (entry) => {
25639
- const desc = entry.description;
25640
- if (!desc) return false;
25641
- return /\b(must|should|acceptance|criteria|verify|test|passes when|done when|complete when)\b/i.test(desc);
25812
+ const desc3 = entry.description;
25813
+ if (!desc3) return false;
25814
+ return /\b(must|should|acceptance|criteria|verify|test|passes when|done when|complete when)\b/i.test(desc3);
25642
25815
  }
25643
25816
  },
25644
25817
  {