open-think 0.2.2 → 0.2.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.
Files changed (2) hide show
  1. package/dist/index.js +111 -8
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -276,6 +276,13 @@ var migrations = [
276
276
  db2.exec("ALTER TABLE memories ADD COLUMN episode_key TEXT;");
277
277
  db2.exec("CREATE INDEX IF NOT EXISTS idx_memories_episode_key ON memories(episode_key);");
278
278
  }
279
+ },
280
+ {
281
+ version: 4,
282
+ up: (db2) => {
283
+ db2.exec("ALTER TABLE engrams ADD COLUMN context TEXT;");
284
+ db2.exec("ALTER TABLE engrams ADD COLUMN decisions TEXT;");
285
+ }
279
286
  }
280
287
  ];
281
288
  function getCortexDb(cortexName) {
@@ -307,10 +314,12 @@ function insertEngram(cortexName, params) {
307
314
  const expiresInDays = params.expiresInDays ?? 60;
308
315
  const expires_at = new Date(now.getTime() + expiresInDays * 864e5).toISOString();
309
316
  const episodeKey = params.episodeKey ?? null;
317
+ const context = params.context ?? null;
318
+ const decisions = params.decisions?.length ? JSON.stringify(params.decisions) : null;
310
319
  db2.prepare(
311
- `INSERT INTO engrams (id, content, created_at, expires_at, episode_key) VALUES (?, ?, ?, ?, ?)`
312
- ).run(id, params.content, created_at, expires_at, episodeKey);
313
- return { id, content: params.content, created_at, expires_at, evaluated_at: null, promoted: null, deleted_at: null, episode_key: episodeKey };
320
+ `INSERT INTO engrams (id, content, created_at, expires_at, episode_key, context, decisions) VALUES (?, ?, ?, ?, ?, ?, ?)`
321
+ ).run(id, params.content, created_at, expires_at, episodeKey, context, decisions);
322
+ return { id, content: params.content, created_at, expires_at, evaluated_at: null, promoted: null, deleted_at: null, episode_key: episodeKey, context, decisions };
314
323
  }
315
324
  function getPendingEngrams(cortexName) {
316
325
  const db2 = getCortexDb(cortexName);
@@ -501,7 +510,7 @@ var logCommand = new Command("log").description("Log a note or entry").argument(
501
510
  }
502
511
  closeDb();
503
512
  });
504
- var syncCommand = new Command("sync").description("Log a sync/work-log entry (shorthand for log --category sync)").argument("<message>", "The message to log").option("-s, --source <source>", "Source of the entry", "manual").option("-t, --tags <tags>", "Comma-separated tags").option("-e, --episode <key>", "Tag this engram with an episode identifier").option("--silent", "Suppress output").action(function(message, opts) {
513
+ var syncCommand = new Command("sync").description("Log a sync/work-log entry (shorthand for log --category sync)").argument("<message>", "The message to log").option("-s, --source <source>", "Source of the entry", "manual").option("-t, --tags <tags>", "Comma-separated tags").option("-e, --episode <key>", "Tag this engram with an episode identifier").option("--context <json>", "Attach structured JSON metadata to this engram").option("-d, --decision <text>", "Record a decision (repeatable)", (val, prev) => [...prev, val], []).option("--silent", "Suppress output").action(function(message, opts) {
505
514
  const globalOpts = this.optsWithGlobals();
506
515
  const config = getConfig();
507
516
  if (config.paused) {
@@ -516,7 +525,17 @@ var syncCommand = new Command("sync").description("Log a sync/work-log entry (sh
516
525
  console.log(chalk.yellow(` \u26A0 ${w}`));
517
526
  }
518
527
  }
519
- const engram = insertEngram(cortex, { content: message, episodeKey: opts.episode });
528
+ if (opts.context) {
529
+ try {
530
+ JSON.parse(opts.context);
531
+ } catch {
532
+ console.error(chalk.red("Error: --context must be valid JSON"));
533
+ process.exitCode = 1;
534
+ return;
535
+ }
536
+ }
537
+ const decisions = opts.decision?.length ? opts.decision : void 0;
538
+ const engram = insertEngram(cortex, { content: message, episodeKey: opts.episode, context: opts.context, decisions });
520
539
  if (!opts.silent) {
521
540
  const badge = chalk.cyan(`[${cortex}]`);
522
541
  const ts = chalk.gray(engram.created_at.slice(0, 16).replace("T", " "));
@@ -1214,6 +1233,7 @@ Your task:
1214
1233
  - Blockers encountered or resolved
1215
1234
  - Clusters \u2014 multiple events around the same topic signal importance
1216
1235
  - Weight \u2014 urgency, frustration, or surprise in the language suggests significance
1236
+ - Decisions \u2014 events with explicit decisions attached are high-signal and should almost always be promoted. Preserve the decision rationale in the memory.
1217
1237
  4. Routine, administrative, or low-signal events should be dropped.
1218
1238
  Dropping is correct, not a failure.
1219
1239
 
@@ -1279,7 +1299,24 @@ function assembleCurationPrompt(params) {
1279
1299
  const longtermText = params.longtermSummary ?? "(no long-term context yet)";
1280
1300
  const recentText = params.recentMemories.length > 0 ? params.recentMemories.map((m) => `- [${m.ts}] ${m.author}: ${m.content}`).join("\n") : "(no recent memories)";
1281
1301
  const curatorMdText = params.curatorMd ?? "(none provided)";
1282
- const engramsText = params.pendingEngrams.map((e) => `- [${e.created_at}] (id: ${e.id}) ${e.content}`).join("\n");
1302
+ const engramsText = params.pendingEngrams.map((e) => {
1303
+ let line = `- [${e.created_at}] (id: ${e.id}) ${e.content}`;
1304
+ if (e.decisions) {
1305
+ try {
1306
+ const decisions = JSON.parse(e.decisions);
1307
+ if (decisions.length > 0) {
1308
+ line += `
1309
+ Decisions: ${decisions.map((d) => `"${d}"`).join("; ")}`;
1310
+ }
1311
+ } catch {
1312
+ }
1313
+ }
1314
+ if (e.context) {
1315
+ line += `
1316
+ Context: ${e.context}`;
1317
+ }
1318
+ return line;
1319
+ }).join("\n");
1283
1320
  const userMessage = [
1284
1321
  "## Long-term context (compressed history)",
1285
1322
  wrapData("longterm-summary", longtermText),
@@ -1431,7 +1468,24 @@ Output: Return a JSON object with a single "content" field containing your narra
1431
1468
 
1432
1469
  Do not include markdown, code fences, or explanation outside the JSON.`;
1433
1470
  function assembleEpisodeCurationPrompt(params) {
1434
- const engramsText = params.pendingEngrams.map((e) => `- [${e.created_at}] ${e.content}`).join("\n");
1471
+ const engramsText = params.pendingEngrams.map((e) => {
1472
+ let line = `- [${e.created_at}] ${e.content}`;
1473
+ if (e.decisions) {
1474
+ try {
1475
+ const decisions = JSON.parse(e.decisions);
1476
+ if (decisions.length > 0) {
1477
+ line += `
1478
+ Decisions: ${decisions.map((d) => `"${d}"`).join("; ")}`;
1479
+ }
1480
+ } catch {
1481
+ }
1482
+ }
1483
+ if (e.context) {
1484
+ line += `
1485
+ Context: ${e.context}`;
1486
+ }
1487
+ return line;
1488
+ }).join("\n");
1435
1489
  const sections = [
1436
1490
  "## Episode",
1437
1491
  wrapData("episode-key", params.episodeKey),
@@ -2247,7 +2301,52 @@ var recallCommand = new Command12("recall").argument("<query>", "What to recall"
2247
2301
  // src/commands/memory.ts
2248
2302
  import { Command as Command13 } from "commander";
2249
2303
  import chalk13 from "chalk";
2250
- var memoryCommand = new Command13("memory").description("Show current memories from local store").option("--history", "Show recent memory timeline").action(async (opts) => {
2304
+ var addCommand = new Command13("add").description("Add a memory directly, bypassing curation").argument("<message>", "The memory content").option("--no-push", "Skip pushing to remote after adding").option("--silent", "Suppress output").action(async function(message, opts) {
2305
+ const globalOpts = this.optsWithGlobals();
2306
+ const config = getConfig();
2307
+ const cortex = globalOpts.cortex ?? config.cortex?.active;
2308
+ if (!cortex) {
2309
+ console.error(chalk13.red("No active cortex. Run: think cortex switch <name>"));
2310
+ process.exit(1);
2311
+ }
2312
+ const author = config.cortex?.author ?? "unknown";
2313
+ const validated = validateEngramContent(message);
2314
+ message = validated.content;
2315
+ if (!opts.silent && validated.warnings.length > 0) {
2316
+ for (const w of validated.warnings) {
2317
+ console.log(chalk13.yellow(` \u26A0 ${w}`));
2318
+ }
2319
+ }
2320
+ const row = insertMemory(cortex, {
2321
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
2322
+ author,
2323
+ content: message,
2324
+ source_ids: []
2325
+ });
2326
+ if (!opts.silent) {
2327
+ const badge = chalk13.cyan(`[${cortex}]`);
2328
+ const ts = chalk13.gray(row.ts.slice(0, 16).replace("T", " "));
2329
+ console.log(`${chalk13.green("\u2713")} ${badge} memory added ${ts}`);
2330
+ console.log(` ${row.content}`);
2331
+ }
2332
+ if (opts.push) {
2333
+ const adapter = getSyncAdapter();
2334
+ if (adapter?.isAvailable()) {
2335
+ try {
2336
+ const result = await adapter.push(cortex);
2337
+ if (!opts.silent && result.pushed > 0) {
2338
+ console.log(chalk13.dim(` Pushed ${result.pushed} memories to ${adapter.name}`));
2339
+ }
2340
+ } catch {
2341
+ if (!opts.silent) {
2342
+ console.log(chalk13.dim(" Push skipped (remote unavailable) \u2014 will push on next sync"));
2343
+ }
2344
+ }
2345
+ }
2346
+ }
2347
+ closeCortexDb(cortex);
2348
+ });
2349
+ async function showMemories(opts) {
2251
2350
  const config = getConfig();
2252
2351
  const cortex = config.cortex?.active;
2253
2352
  if (!cortex) {
@@ -2275,7 +2374,11 @@ var memoryCommand = new Command13("memory").description("Show current memories f
2275
2374
  console.log(chalk13.dim(`
2276
2375
  ${memories.length} memories`));
2277
2376
  closeCortexDb(cortex);
2377
+ }
2378
+ var memoryCommand = new Command13("memory").description("Show current memories from local store").option("--history", "Show recent memory timeline").action(async (opts) => {
2379
+ await showMemories(opts);
2278
2380
  });
2381
+ memoryCommand.addCommand(addCommand);
2279
2382
 
2280
2383
  // src/commands/curator-cmd.ts
2281
2384
  import { Command as Command14 } from "commander";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-think",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "description": "Local-first CLI that gives AI agents persistent, curated memory",
6
6
  "bin": {