@cleocode/cleo 2026.3.32 → 2026.3.33

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
@@ -15285,6 +15285,205 @@ var init_brain_retrieval = __esm({
15285
15285
  }
15286
15286
  });
15287
15287
 
15288
+ // src/core/memory/decisions.ts
15289
+ import { desc as desc3 } from "drizzle-orm";
15290
+ async function nextDecisionId(projectRoot) {
15291
+ const db = await getBrainDb(projectRoot);
15292
+ const rows = await db.select({ id: brainDecisions.id }).from(brainDecisions).orderBy(desc3(brainDecisions.id)).limit(1);
15293
+ if (rows.length === 0) {
15294
+ return "D001";
15295
+ }
15296
+ const lastId = rows[0].id;
15297
+ const num = parseInt(lastId.slice(1), 10);
15298
+ if (Number.isNaN(num)) {
15299
+ return "D001";
15300
+ }
15301
+ return `D${String(num + 1).padStart(3, "0")}`;
15302
+ }
15303
+ async function storeDecision(projectRoot, params) {
15304
+ if (!params.decision || !params.decision.trim()) {
15305
+ throw new Error("Decision text is required");
15306
+ }
15307
+ if (!params.rationale || !params.rationale.trim()) {
15308
+ throw new Error("Rationale is required");
15309
+ }
15310
+ const accessor = await getBrainAccessor(projectRoot);
15311
+ const existing = await accessor.findDecisions({ type: params.type });
15312
+ const duplicate = existing.find(
15313
+ (d) => d.decision.toLowerCase() === params.decision.toLowerCase()
15314
+ );
15315
+ if (duplicate) {
15316
+ const now2 = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
15317
+ await accessor.updateDecision(duplicate.id, {
15318
+ rationale: params.rationale.trim(),
15319
+ confidence: params.confidence,
15320
+ outcome: params.outcome ?? duplicate.outcome,
15321
+ alternativesJson: params.alternatives ? JSON.stringify(params.alternatives) : duplicate.alternativesJson,
15322
+ updatedAt: now2
15323
+ });
15324
+ const updated = await accessor.getDecision(duplicate.id);
15325
+ return updated;
15326
+ }
15327
+ const id = await nextDecisionId(projectRoot);
15328
+ const row = {
15329
+ id,
15330
+ type: params.type,
15331
+ decision: params.decision.trim(),
15332
+ rationale: params.rationale.trim(),
15333
+ confidence: params.confidence,
15334
+ outcome: params.outcome,
15335
+ alternativesJson: params.alternatives ? JSON.stringify(params.alternatives) : void 0,
15336
+ contextEpicId: params.contextEpicId,
15337
+ contextTaskId: params.contextTaskId,
15338
+ contextPhase: params.contextPhase
15339
+ };
15340
+ return accessor.addDecision(row);
15341
+ }
15342
+ var init_decisions2 = __esm({
15343
+ "src/core/memory/decisions.ts"() {
15344
+ "use strict";
15345
+ init_brain_accessor();
15346
+ init_brain_schema();
15347
+ init_brain_sqlite();
15348
+ }
15349
+ });
15350
+
15351
+ // src/core/memory/learnings.ts
15352
+ import { randomBytes as randomBytes5 } from "node:crypto";
15353
+ function generateLearningId() {
15354
+ return `L-${randomBytes5(4).toString("hex")}`;
15355
+ }
15356
+ async function storeLearning(projectRoot, params) {
15357
+ if (!params.insight || !params.insight.trim()) {
15358
+ throw new Error("Insight text is required");
15359
+ }
15360
+ if (!params.source || !params.source.trim()) {
15361
+ throw new Error("Source is required");
15362
+ }
15363
+ if (params.confidence < 0 || params.confidence > 1) {
15364
+ throw new Error("Confidence must be between 0.0 and 1.0");
15365
+ }
15366
+ const accessor = await getBrainAccessor(projectRoot);
15367
+ const now2 = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
15368
+ const existingLearnings = await accessor.findLearnings();
15369
+ const duplicate = existingLearnings.find(
15370
+ (e) => e.insight.toLowerCase() === params.insight.toLowerCase()
15371
+ );
15372
+ if (duplicate) {
15373
+ }
15374
+ const entry = {
15375
+ id: generateLearningId(),
15376
+ insight: params.insight.trim(),
15377
+ source: params.source.trim(),
15378
+ confidence: params.confidence,
15379
+ actionable: params.actionable ?? false,
15380
+ application: params.application ?? null,
15381
+ applicableTypesJson: params.applicableTypes ? JSON.stringify(params.applicableTypes) : "[]",
15382
+ extractedAt: now2
15383
+ };
15384
+ const saved = await accessor.addLearning(entry);
15385
+ return {
15386
+ ...saved,
15387
+ applicableTypes: JSON.parse(saved.applicableTypesJson || "[]")
15388
+ };
15389
+ }
15390
+ async function searchLearnings(projectRoot, params = {}) {
15391
+ const accessor = await getBrainAccessor(projectRoot);
15392
+ let entries = await accessor.findLearnings({
15393
+ minConfidence: params.minConfidence,
15394
+ actionable: params.actionableOnly,
15395
+ limit: params.limit
15396
+ });
15397
+ if (params.applicableType) {
15398
+ entries = entries.filter((e) => {
15399
+ const types = JSON.parse(e.applicableTypesJson || "[]");
15400
+ return types.includes(params.applicableType);
15401
+ });
15402
+ }
15403
+ if (params.query) {
15404
+ const q = params.query.toLowerCase();
15405
+ entries = entries.filter(
15406
+ (e) => e.insight.toLowerCase().includes(q) || e.source.toLowerCase().includes(q) || e.application?.toLowerCase().includes(q)
15407
+ );
15408
+ }
15409
+ entries.sort((a, b) => b.confidence - a.confidence);
15410
+ return entries.map((e) => ({
15411
+ ...e,
15412
+ applicableTypes: JSON.parse(e.applicableTypesJson || "[]")
15413
+ }));
15414
+ }
15415
+ var init_learnings = __esm({
15416
+ "src/core/memory/learnings.ts"() {
15417
+ "use strict";
15418
+ init_brain_accessor();
15419
+ }
15420
+ });
15421
+
15422
+ // src/core/memory/patterns.ts
15423
+ import { randomBytes as randomBytes6 } from "node:crypto";
15424
+ function generatePatternId() {
15425
+ return `P-${randomBytes6(4).toString("hex")}`;
15426
+ }
15427
+ async function storePattern(projectRoot, params) {
15428
+ if (!params.pattern || !params.pattern.trim()) {
15429
+ throw new Error("Pattern description is required");
15430
+ }
15431
+ if (!params.context || !params.context.trim()) {
15432
+ throw new Error("Pattern context is required");
15433
+ }
15434
+ const accessor = await getBrainAccessor(projectRoot);
15435
+ const existingPatterns = await accessor.findPatterns({ type: params.type });
15436
+ const duplicate = existingPatterns.find(
15437
+ (e) => e.pattern.toLowerCase() === params.pattern.toLowerCase()
15438
+ );
15439
+ const now2 = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
15440
+ if (duplicate) {
15441
+ }
15442
+ const entry = {
15443
+ id: generatePatternId(),
15444
+ type: params.type,
15445
+ pattern: params.pattern.trim(),
15446
+ context: params.context.trim(),
15447
+ frequency: 1,
15448
+ successRate: params.successRate ?? null,
15449
+ impact: params.impact ?? null,
15450
+ antiPattern: params.antiPattern ?? null,
15451
+ mitigation: params.mitigation ?? null,
15452
+ examplesJson: params.examples ? JSON.stringify(params.examples) : "[]",
15453
+ extractedAt: now2
15454
+ };
15455
+ const saved = await accessor.addPattern(entry);
15456
+ return {
15457
+ ...saved,
15458
+ examples: JSON.parse(saved.examplesJson || "[]")
15459
+ };
15460
+ }
15461
+ async function searchPatterns(projectRoot, params = {}) {
15462
+ const accessor = await getBrainAccessor(projectRoot);
15463
+ let entries = await accessor.findPatterns({
15464
+ type: params.type,
15465
+ impact: params.impact,
15466
+ minFrequency: params.minFrequency,
15467
+ limit: params.limit
15468
+ });
15469
+ if (params.query) {
15470
+ const q = params.query.toLowerCase();
15471
+ entries = entries.filter(
15472
+ (e) => e.pattern.toLowerCase().includes(q) || e.context.toLowerCase().includes(q) || e.antiPattern?.toLowerCase().includes(q) || e.mitigation?.toLowerCase().includes(q)
15473
+ );
15474
+ }
15475
+ return entries.map((e) => ({
15476
+ ...e,
15477
+ examples: JSON.parse(e.examplesJson || "[]")
15478
+ }));
15479
+ }
15480
+ var init_patterns = __esm({
15481
+ "src/core/memory/patterns.ts"() {
15482
+ "use strict";
15483
+ init_brain_accessor();
15484
+ }
15485
+ });
15486
+
15288
15487
  // src/dispatch/engines/_error.ts
15289
15488
  function logLevel(exitCode) {
15290
15489
  if (exitCode === 0 || exitCode >= 100) return "debug";
@@ -22493,6 +22692,123 @@ var init_session_history = __esm({
22493
22692
  }
22494
22693
  });
22495
22694
 
22695
+ // src/core/memory/auto-extract.ts
22696
+ var auto_extract_exports = {};
22697
+ __export(auto_extract_exports, {
22698
+ extractSessionEndMemory: () => extractSessionEndMemory,
22699
+ extractTaskCompletionMemory: () => extractTaskCompletionMemory,
22700
+ resolveTaskDetails: () => resolveTaskDetails
22701
+ });
22702
+ async function extractTaskCompletionMemory(projectRoot, task, _parentTask) {
22703
+ try {
22704
+ await storeLearning(projectRoot, {
22705
+ insight: `Completed: ${task.title} \u2014 ${task.description ?? ""}`,
22706
+ source: `task-completion:${task.id}`,
22707
+ confidence: 0.7,
22708
+ actionable: true
22709
+ });
22710
+ const deps = task.depends ?? [];
22711
+ if (deps.length > 0) {
22712
+ await storeLearning(projectRoot, {
22713
+ insight: `Task ${task.id} depended on ${deps.join(", ")} \u2014 dependency chain completed successfully`,
22714
+ source: `task-completion:${task.id}`,
22715
+ confidence: 0.7
22716
+ });
22717
+ }
22718
+ const { getAccessor: getAccessor2 } = await Promise.resolve().then(() => (init_data_accessor(), data_accessor_exports));
22719
+ const accessor = await getAccessor2(projectRoot);
22720
+ let taskFile;
22721
+ try {
22722
+ taskFile = await accessor.loadTaskFile();
22723
+ } finally {
22724
+ await accessor.close();
22725
+ }
22726
+ const recentDone = taskFile.tasks.filter((t) => t.status === "done").slice(-50);
22727
+ const labelCounts = /* @__PURE__ */ new Map();
22728
+ for (const t of recentDone) {
22729
+ for (const label of t.labels ?? []) {
22730
+ const existing = labelCounts.get(label) ?? [];
22731
+ existing.push(t.id);
22732
+ labelCounts.set(label, existing);
22733
+ }
22734
+ }
22735
+ for (const [label, taskIds] of labelCounts.entries()) {
22736
+ if (taskIds.length >= 3) {
22737
+ await storePattern(projectRoot, {
22738
+ type: "success",
22739
+ pattern: `Recurring label "${label}" seen in ${taskIds.length} completed tasks`,
22740
+ context: `Auto-detected from task completion of ${task.id}`,
22741
+ impact: "medium",
22742
+ examples: taskIds
22743
+ });
22744
+ }
22745
+ }
22746
+ } catch {
22747
+ }
22748
+ }
22749
+ async function extractSessionEndMemory(projectRoot, sessionData, taskDetails) {
22750
+ try {
22751
+ if (taskDetails.length > 0) {
22752
+ await storeDecision(projectRoot, {
22753
+ type: "process",
22754
+ decision: `Session ${sessionData.sessionId} completed ${taskDetails.length} tasks: ${taskDetails.map((t) => t.id).join(", ")}`,
22755
+ rationale: `Session scope: ${sessionData.scope}. Duration: ${Math.round(sessionData.duration / 60)} min.`,
22756
+ confidence: "medium"
22757
+ });
22758
+ }
22759
+ for (const t of taskDetails) {
22760
+ await storeLearning(projectRoot, {
22761
+ insight: `Completed: ${t.title} \u2014 ${t.description ?? ""}`,
22762
+ source: `session-end:${sessionData.sessionId}`,
22763
+ confidence: 0.7,
22764
+ actionable: true
22765
+ });
22766
+ }
22767
+ const labelCounts = /* @__PURE__ */ new Map();
22768
+ for (const t of taskDetails) {
22769
+ for (const label of t.labels ?? []) {
22770
+ const existing = labelCounts.get(label) ?? [];
22771
+ existing.push(t.id);
22772
+ labelCounts.set(label, existing);
22773
+ }
22774
+ }
22775
+ for (const [label, taskIds] of labelCounts.entries()) {
22776
+ if (taskIds.length >= 2) {
22777
+ await storePattern(projectRoot, {
22778
+ type: "workflow",
22779
+ pattern: `Session ${sessionData.sessionId} completed ${taskIds.length} tasks with label "${label}"`,
22780
+ context: `Auto-detected from session end: ${sessionData.sessionId}`,
22781
+ impact: "medium",
22782
+ examples: taskIds
22783
+ });
22784
+ }
22785
+ }
22786
+ } catch {
22787
+ }
22788
+ }
22789
+ async function resolveTaskDetails(projectRoot, taskIds) {
22790
+ if (taskIds.length === 0) {
22791
+ return [];
22792
+ }
22793
+ const { getAccessor: getAccessor2 } = await Promise.resolve().then(() => (init_data_accessor(), data_accessor_exports));
22794
+ const accessor = await getAccessor2(projectRoot);
22795
+ try {
22796
+ const taskFile = await accessor.loadTaskFile();
22797
+ const idSet = new Set(taskIds);
22798
+ return taskFile.tasks.filter((t) => idSet.has(t.id));
22799
+ } finally {
22800
+ await accessor.close();
22801
+ }
22802
+ }
22803
+ var init_auto_extract = __esm({
22804
+ "src/core/memory/auto-extract.ts"() {
22805
+ "use strict";
22806
+ init_decisions2();
22807
+ init_learnings();
22808
+ init_patterns();
22809
+ }
22810
+ });
22811
+
22496
22812
  // src/core/sessions/session-memory-bridge.ts
22497
22813
  var session_memory_bridge_exports = {};
22498
22814
  __export(session_memory_bridge_exports, {
@@ -22515,6 +22831,12 @@ async function bridgeSessionToMemory(projectRoot, sessionData) {
22515
22831
  sourceSessionId: sessionData.sessionId,
22516
22832
  sourceType: "agent"
22517
22833
  });
22834
+ try {
22835
+ const { extractSessionEndMemory: extractSessionEndMemory2, resolveTaskDetails: resolveTaskDetails2 } = await Promise.resolve().then(() => (init_auto_extract(), auto_extract_exports));
22836
+ const taskDetails = await resolveTaskDetails2(projectRoot, sessionData.tasksCompleted);
22837
+ await extractSessionEndMemory2(projectRoot, sessionData, taskDetails);
22838
+ } catch {
22839
+ }
22518
22840
  } catch {
22519
22841
  }
22520
22842
  }
@@ -25083,6 +25405,10 @@ async function completeTask(options, cwd, accessor) {
25083
25405
  }
25084
25406
  Promise.resolve().then(() => (init_memory_bridge(), memory_bridge_exports)).then(({ refreshMemoryBridge: refreshMemoryBridge2 }) => refreshMemoryBridge2(cwd ?? process.cwd())).catch(() => {
25085
25407
  });
25408
+ Promise.resolve().then(() => (init_auto_extract(), auto_extract_exports)).then(
25409
+ ({ extractTaskCompletionMemory: extractTaskCompletionMemory2 }) => extractTaskCompletionMemory2(cwd ?? process.cwd(), task)
25410
+ ).catch(() => {
25411
+ });
25086
25412
  return {
25087
25413
  task,
25088
25414
  ...autoCompleted.length > 0 && { autoCompleted },
@@ -33359,140 +33685,9 @@ import { join as join25 } from "node:path";
33359
33685
  // src/core/memory/index.ts
33360
33686
  init_brain_retrieval();
33361
33687
  init_brain_search();
33362
-
33363
- // src/core/memory/decisions.ts
33364
- init_brain_accessor();
33365
- init_brain_schema();
33366
- init_brain_sqlite();
33367
- import { desc as desc3 } from "drizzle-orm";
33368
-
33369
- // src/core/memory/learnings.ts
33370
- init_brain_accessor();
33371
- import { randomBytes as randomBytes5 } from "node:crypto";
33372
- function generateLearningId() {
33373
- return `L-${randomBytes5(4).toString("hex")}`;
33374
- }
33375
- async function storeLearning(projectRoot, params) {
33376
- if (!params.insight || !params.insight.trim()) {
33377
- throw new Error("Insight text is required");
33378
- }
33379
- if (!params.source || !params.source.trim()) {
33380
- throw new Error("Source is required");
33381
- }
33382
- if (params.confidence < 0 || params.confidence > 1) {
33383
- throw new Error("Confidence must be between 0.0 and 1.0");
33384
- }
33385
- const accessor = await getBrainAccessor(projectRoot);
33386
- const now2 = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
33387
- const existingLearnings = await accessor.findLearnings();
33388
- const duplicate = existingLearnings.find(
33389
- (e) => e.insight.toLowerCase() === params.insight.toLowerCase()
33390
- );
33391
- if (duplicate) {
33392
- }
33393
- const entry = {
33394
- id: generateLearningId(),
33395
- insight: params.insight.trim(),
33396
- source: params.source.trim(),
33397
- confidence: params.confidence,
33398
- actionable: params.actionable ?? false,
33399
- application: params.application ?? null,
33400
- applicableTypesJson: params.applicableTypes ? JSON.stringify(params.applicableTypes) : "[]",
33401
- extractedAt: now2
33402
- };
33403
- const saved = await accessor.addLearning(entry);
33404
- return {
33405
- ...saved,
33406
- applicableTypes: JSON.parse(saved.applicableTypesJson || "[]")
33407
- };
33408
- }
33409
- async function searchLearnings(projectRoot, params = {}) {
33410
- const accessor = await getBrainAccessor(projectRoot);
33411
- let entries = await accessor.findLearnings({
33412
- minConfidence: params.minConfidence,
33413
- actionable: params.actionableOnly,
33414
- limit: params.limit
33415
- });
33416
- if (params.applicableType) {
33417
- entries = entries.filter((e) => {
33418
- const types = JSON.parse(e.applicableTypesJson || "[]");
33419
- return types.includes(params.applicableType);
33420
- });
33421
- }
33422
- if (params.query) {
33423
- const q = params.query.toLowerCase();
33424
- entries = entries.filter(
33425
- (e) => e.insight.toLowerCase().includes(q) || e.source.toLowerCase().includes(q) || e.application?.toLowerCase().includes(q)
33426
- );
33427
- }
33428
- entries.sort((a, b) => b.confidence - a.confidence);
33429
- return entries.map((e) => ({
33430
- ...e,
33431
- applicableTypes: JSON.parse(e.applicableTypesJson || "[]")
33432
- }));
33433
- }
33434
-
33435
- // src/core/memory/patterns.ts
33436
- init_brain_accessor();
33437
- import { randomBytes as randomBytes6 } from "node:crypto";
33438
- function generatePatternId() {
33439
- return `P-${randomBytes6(4).toString("hex")}`;
33440
- }
33441
- async function storePattern(projectRoot, params) {
33442
- if (!params.pattern || !params.pattern.trim()) {
33443
- throw new Error("Pattern description is required");
33444
- }
33445
- if (!params.context || !params.context.trim()) {
33446
- throw new Error("Pattern context is required");
33447
- }
33448
- const accessor = await getBrainAccessor(projectRoot);
33449
- const existingPatterns = await accessor.findPatterns({ type: params.type });
33450
- const duplicate = existingPatterns.find(
33451
- (e) => e.pattern.toLowerCase() === params.pattern.toLowerCase()
33452
- );
33453
- const now2 = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
33454
- if (duplicate) {
33455
- }
33456
- const entry = {
33457
- id: generatePatternId(),
33458
- type: params.type,
33459
- pattern: params.pattern.trim(),
33460
- context: params.context.trim(),
33461
- frequency: 1,
33462
- successRate: params.successRate ?? null,
33463
- impact: params.impact ?? null,
33464
- antiPattern: params.antiPattern ?? null,
33465
- mitigation: params.mitigation ?? null,
33466
- examplesJson: params.examples ? JSON.stringify(params.examples) : "[]",
33467
- extractedAt: now2
33468
- };
33469
- const saved = await accessor.addPattern(entry);
33470
- return {
33471
- ...saved,
33472
- examples: JSON.parse(saved.examplesJson || "[]")
33473
- };
33474
- }
33475
- async function searchPatterns(projectRoot, params = {}) {
33476
- const accessor = await getBrainAccessor(projectRoot);
33477
- let entries = await accessor.findPatterns({
33478
- type: params.type,
33479
- impact: params.impact,
33480
- minFrequency: params.minFrequency,
33481
- limit: params.limit
33482
- });
33483
- if (params.query) {
33484
- const q = params.query.toLowerCase();
33485
- entries = entries.filter(
33486
- (e) => e.pattern.toLowerCase().includes(q) || e.context.toLowerCase().includes(q) || e.antiPattern?.toLowerCase().includes(q) || e.mitigation?.toLowerCase().includes(q)
33487
- );
33488
- }
33489
- return entries.map((e) => ({
33490
- ...e,
33491
- examples: JSON.parse(e.examplesJson || "[]")
33492
- }));
33493
- }
33494
-
33495
- // src/core/memory/index.ts
33688
+ init_decisions2();
33689
+ init_learnings();
33690
+ init_patterns();
33496
33691
  function filterManifestEntries(entries, filter) {
33497
33692
  let filtered = entries;
33498
33693
  if (filter.taskId) {
@@ -34998,6 +35193,8 @@ init_data_accessor();
34998
35193
  init_paths();
34999
35194
  init_brain_links();
35000
35195
  init_brain_retrieval();
35196
+ init_learnings();
35197
+ init_patterns();
35001
35198
  function resolveRoot(projectRoot) {
35002
35199
  return projectRoot || getProjectRoot();
35003
35200
  }
@@ -53579,7 +53776,7 @@ import { execFileSync as execFileSync14 } from "node:child_process";
53579
53776
  // src/config/build-config.ts
53580
53777
  var BUILD_CONFIG = {
53581
53778
  "name": "@cleocode/cleo",
53582
- "version": "2026.3.32",
53779
+ "version": "2026.3.33",
53583
53780
  "description": "CLEO V2 - TypeScript task management CLI for AI coding agents",
53584
53781
  "repository": {
53585
53782
  "owner": "kryptobaseddev",
@@ -53588,7 +53785,7 @@ var BUILD_CONFIG = {
53588
53785
  "url": "https://github.com/kryptobaseddev/cleo.git",
53589
53786
  "issuesUrl": "https://github.com/kryptobaseddev/cleo/issues"
53590
53787
  },
53591
- "buildDate": "2026-03-17T04:37:37.462Z",
53788
+ "buildDate": "2026-03-17T05:12:56.827Z",
53592
53789
  "templates": {
53593
53790
  "issueTemplatesDir": "templates/issue-templates"
53594
53791
  }
@@ -54042,6 +54239,28 @@ function registerMemoryBrainCommand(program2) {
54042
54239
  { command: "memory", operation: "memory.observe" }
54043
54240
  );
54044
54241
  });
54242
+ memory.command("timeline <anchor>").description("Show chronological context around an anchor observation ID").option("--before <n>", "Number of entries before anchor", parseInt).option("--after <n>", "Number of entries after anchor", parseInt).option("--json", "Output as JSON").action(async (anchor, opts) => {
54243
+ await dispatchFromCli(
54244
+ "query",
54245
+ "memory",
54246
+ "timeline",
54247
+ {
54248
+ anchor,
54249
+ depthBefore: opts["before"],
54250
+ depthAfter: opts["after"]
54251
+ },
54252
+ { command: "memory", operation: "memory.timeline" }
54253
+ );
54254
+ });
54255
+ memory.command("fetch <ids...>").description("Fetch full details for specific observation IDs").option("--json", "Output as JSON").action(async (ids, _opts) => {
54256
+ await dispatchFromCli(
54257
+ "query",
54258
+ "memory",
54259
+ "fetch",
54260
+ { ids },
54261
+ { command: "memory", operation: "memory.fetch" }
54262
+ );
54263
+ });
54045
54264
  }
54046
54265
 
54047
54266
  // src/core/memory/claude-mem-migration.ts
@@ -56963,6 +57182,33 @@ function registerSessionCommand(program2) {
56963
57182
  { command: "session", operation: "session.gc" }
56964
57183
  );
56965
57184
  });
57185
+ session.command("record-decision").description("Record a decision made during the current session").requiredOption("--session-id <sessionId>", "Session ID").requiredOption("--task-id <taskId>", "Task ID the decision relates to").requiredOption("--decision <decision>", "Decision text").requiredOption("--rationale <rationale>", "Rationale for the decision").option("--alternatives <alternatives>", "Alternatives considered").action(async (opts) => {
57186
+ await dispatchFromCli(
57187
+ "mutate",
57188
+ "session",
57189
+ "record.decision",
57190
+ {
57191
+ sessionId: opts["sessionId"],
57192
+ taskId: opts["taskId"],
57193
+ decision: opts["decision"],
57194
+ rationale: opts["rationale"],
57195
+ alternatives: opts["alternatives"]
57196
+ },
57197
+ { command: "session", operation: "session.record.decision" }
57198
+ );
57199
+ });
57200
+ session.command("decision-log").description("Show decisions recorded in a session").option("--session-id <sessionId>", "Session ID to filter by").option("--task-id <taskId>", "Task ID to filter by").action(async (opts) => {
57201
+ await dispatchFromCli(
57202
+ "query",
57203
+ "session",
57204
+ "decision.log",
57205
+ {
57206
+ sessionId: opts["sessionId"],
57207
+ taskId: opts["taskId"]
57208
+ },
57209
+ { command: "session", operation: "session.decision.log" }
57210
+ );
57211
+ });
56966
57212
  }
56967
57213
 
56968
57214
  // src/cli/commands/show.ts