@stitchdb/cli 0.8.0 → 0.9.0

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/cli.js +37 -8
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -628,6 +628,7 @@ async function cmdHook(args) {
628
628
  try {
629
629
  const stitch = client(cfg);
630
630
  const projectTag = (threadName.split('/')[0] || threadName).toLowerCase();
631
+ const baseUrl = cfg.baseUrl || 'https://db.stitchdb.com';
631
632
  const [thread, memHits, workspaces, fileSummaries, aboutMems] = await Promise.all([
632
633
  stitch.thread(threadName).recall({ last: 5 }).catch(() => ({ thread_id: '', recent: [], semantic: [] })),
633
634
  stitch.recall(projectTag, { k: 8 }).catch(() => []),
@@ -635,10 +636,26 @@ async function cmdHook(args) {
635
636
  stitch.list({ limit: 12 }).then((all) => all.filter((m) => m.tags.some((t) => t.startsWith('file:')))).catch(() => []),
636
637
  stitch.list({ tag: 'workspace:about', limit: 1 }).catch(() => []),
637
638
  ]);
638
- const currentWs = Array.isArray(workspaces) && workspaces.length > 0 ? workspaces[0] : null;
639
+ // Look up the current workspace using the client's resolved id; fall
640
+ // back to first if resolveWorkspace failed (shouldn't normally).
641
+ const currentWsId = await stitch.resolveWorkspace().catch(() => null);
642
+ const currentWs = (Array.isArray(workspaces) ? workspaces : [])
643
+ .find((w) => w.id === currentWsId) || (Array.isArray(workspaces) ? workspaces[0] : null);
644
+ // Cross-project user-level memories from the special `_global` workspace.
645
+ // Pull top 8 most-recent — these are user preferences / rules that apply
646
+ // EVERYWHERE, regardless of which project this session is in.
647
+ let globalMems = [];
648
+ try {
649
+ const globalWs = (Array.isArray(workspaces) ? workspaces : []).find((w) => w.name === '_global');
650
+ if (globalWs) {
651
+ const globalClient = new Stitch({ apiKey: cfg.apiKey, baseUrl, workspace: globalWs.id });
652
+ globalMems = await globalClient.list({ limit: 8 }).catch(() => []);
653
+ }
654
+ }
655
+ catch { /* ignore */ }
639
656
  const lines = [];
640
657
  lines.push('<stitch-context>');
641
- lines.push(`Project: ${threadName} · Workspace: ${currentWs?.name || '(unknown)'} · Stitch MCP tools: recall, remember, thread_recall, thread_append, workspace_setup, file_summary, file_summary_save.`);
658
+ lines.push(`Project: ${threadName} · Workspace: ${currentWs?.name || '(unknown)'} · Stitch MCP tools: recall, remember, recall_global, remember_global, thread_recall, thread_append, workspace_setup, file_summary, file_summary_save.`);
642
659
  lines.push('');
643
660
  // Nudge the AI to set a meaningful workspace name once.
644
661
  if (currentWs?.name === 'default') {
@@ -646,6 +663,15 @@ async function cmdHook(args) {
646
663
  lines.push('Call the `workspace_setup` MCP tool with a slug-style name based on this project (e.g. the package.json name or repo dir).');
647
664
  lines.push('');
648
665
  }
666
+ // Global preferences first — they should bias everything else.
667
+ if (globalMems.length > 0) {
668
+ lines.push('### User-level rules & preferences (apply across all projects)');
669
+ for (const m of globalMems) {
670
+ const txt = String(m.content || '').replace(/\n+/g, ' ').slice(0, 350);
671
+ lines.push(`- **[${m.kind}]** ${txt}`);
672
+ }
673
+ lines.push('');
674
+ }
649
675
  if (Array.isArray(aboutMems) && aboutMems.length > 0) {
650
676
  lines.push('### About this workspace');
651
677
  lines.push(String(aboutMems[0].content || '').slice(0, 400));
@@ -679,7 +705,7 @@ async function cmdHook(args) {
679
705
  }
680
706
  lines.push('');
681
707
  }
682
- lines.push('Call `recall` for deeper search, `thread_recall` for older turns, `file_summary` BEFORE reading any non-trivial file (saves tokens).');
708
+ lines.push('Call `recall` for project memory, `recall_global` for cross-project user prefs, `thread_recall` for older turns, `file_summary` BEFORE reading any non-trivial file. Save user-level habits/preferences with `remember_global`; project facts with `remember`.');
683
709
  lines.push('</stitch-context>');
684
710
  process.stdout.write(lines.join('\n'));
685
711
  }
@@ -1054,7 +1080,6 @@ async function cmdSummarizeFile(args) {
1054
1080
  return;
1055
1081
  try {
1056
1082
  const stitch = client(cfg);
1057
- const projectTag = (inferThread() || 'default').split('/')[0];
1058
1083
  // Replace any prior summary for this path.
1059
1084
  const prior = await stitch.list({ tag: `file:${rel}`, limit: 50 }).catch(() => []);
1060
1085
  for (const p of prior) {
@@ -1063,9 +1088,13 @@ async function cmdSummarizeFile(args) {
1063
1088
  }
1064
1089
  catch { }
1065
1090
  }
1091
+ // No project:* tag — the workspace itself is the project identity now.
1092
+ // Adding a project tag based on inferThread() is the bug that caused
1093
+ // cross-workspace contamination when the workspace pin and the thread
1094
+ // pin disagreed.
1066
1095
  await stitch.remember(summary, {
1067
1096
  kind: 'snippet',
1068
- tags: [`file:${rel}`, `hash:${hashPrefix}`, 'auto:file-summary', `project:${projectTag}`],
1097
+ tags: [`file:${rel}`, `hash:${hashPrefix}`, 'auto:file-summary'],
1069
1098
  });
1070
1099
  }
1071
1100
  catch { /* silent — never break a session */ }
@@ -1209,12 +1238,12 @@ async function cmdDistill(args) {
1209
1238
  bumpDistillCooldown(thread);
1210
1239
  return;
1211
1240
  }
1212
- // Push each to Stitch as a memory with auto:true tag.
1213
- const projectTag = thread.split('/')[0] || thread;
1241
+ // Push each to Stitch as a memory with auto:true tag. No project:* tag —
1242
+ // the workspace itself is the project identity.
1214
1243
  let saved = 0;
1215
1244
  for (const m of memories) {
1216
1245
  try {
1217
- const tags = ['auto', 'auto:distill', `thread:${thread}`, `project:${projectTag}`, ...(m.tags || [])];
1246
+ const tags = ['auto', 'auto:distill', `thread:${thread}`, ...(m.tags || [])];
1218
1247
  await stitch.remember(m.content, { kind: m.kind, tags });
1219
1248
  saved++;
1220
1249
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stitchdb/cli",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Stitch CLI — manage memory + run agents from your terminal",
5
5
  "type": "module",
6
6
  "bin": {