@geoql/mdr 0.0.1 → 1.0.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.
package/opencode/tools.ts CHANGED
@@ -4,31 +4,31 @@
4
4
  * Separate tools for memory operations
5
5
  */
6
6
 
7
- import { tool } from "@opencode-ai/plugin";
8
- import { existsSync, readFileSync, writeFileSync, readdirSync, mkdirSync, unlinkSync } from "fs";
9
- import { join } from "path";
10
- import { getRemindersDir } from "../src/config.js";
7
+ import { tool } from '@opencode-ai/plugin';
8
+ import { existsSync, readFileSync, writeFileSync, readdirSync, mkdirSync, unlinkSync } from 'fs';
9
+ import { join } from 'path';
10
+ import { getRemindersDir } from '../src/config.js';
11
11
  import {
12
12
  logJournal,
13
13
  getRecentJournal,
14
14
  getRecentSummaries,
15
15
  saveConversationSummary,
16
- } from "./journal.js";
17
- import { searchMemory, rebuildMemoryIndex, getMemoryIndexStats } from "./search.js";
16
+ } from './journal.js';
17
+ import { searchMemory, rebuildMemoryIndex, getMemoryIndexStats } from './search.js';
18
18
  import {
19
19
  searchConversations,
20
20
  rebuildConversationIndex,
21
21
  getConversationIndexStats,
22
- } from "./conversations.js";
23
- import { logger } from "./logger.js";
22
+ } from './conversations.js';
23
+ import { logger } from './logger.js';
24
24
 
25
25
  interface Schedule {
26
26
  id: string;
27
- type: "cron" | "once";
27
+ type: 'cron' | 'once';
28
28
  expression: string;
29
29
  description: string;
30
30
  payload: string;
31
- agent?: "opencode" | "claude";
31
+ agent?: 'opencode' | 'claude';
32
32
  model?: string;
33
33
  createdAt: string;
34
34
  }
@@ -40,10 +40,10 @@ function loadAllSchedules(): Schedule[] {
40
40
  try {
41
41
  if (!existsSync(remindersDir)) return schedules;
42
42
 
43
- const files = readdirSync(remindersDir).filter((f) => f.endsWith(".json"));
43
+ const files = readdirSync(remindersDir).filter((f) => f.endsWith('.json'));
44
44
  for (const file of files) {
45
45
  try {
46
- const content = readFileSync(join(remindersDir, file), "utf-8");
46
+ const content = readFileSync(join(remindersDir, file), 'utf-8');
47
47
  schedules.push(JSON.parse(content));
48
48
  } catch {
49
49
  // Skip malformed files
@@ -84,10 +84,10 @@ function deleteScheduleFile(id: string): boolean {
84
84
 
85
85
  export const logJournalTool = tool({
86
86
  description:
87
- "Write a journal entry. Use this to record observations, decisions, or things to remember.",
87
+ 'Write a journal entry. Use this to record observations, decisions, or things to remember.',
88
88
  args: {
89
- topic: tool.schema.string().describe("Short topic/category for the entry"),
90
- content: tool.schema.string().describe("The journal entry content"),
89
+ topic: tool.schema.string().describe('Short topic/category for the entry'),
90
+ content: tool.schema.string().describe('The journal entry content'),
91
91
  agentIntent: tool.schema.string().optional().describe("Optional: why you're logging this"),
92
92
  },
93
93
  async execute(args) {
@@ -96,7 +96,7 @@ export const logJournalTool = tool({
96
96
  }
97
97
 
98
98
  await logJournal(args.topic, args.content, {
99
- source: "opencode-tool",
99
+ source: 'opencode-tool',
100
100
  intent: args.agentIntent,
101
101
  });
102
102
 
@@ -105,9 +105,9 @@ export const logJournalTool = tool({
105
105
  });
106
106
 
107
107
  export const getRecentJournalTool = tool({
108
- description: "Retrieve recent journal entries for context",
108
+ description: 'Retrieve recent journal entries for context',
109
109
  args: {
110
- count: tool.schema.number().optional().describe("Number of entries to retrieve (default: 40)"),
110
+ count: tool.schema.number().optional().describe('Number of entries to retrieve (default: 40)'),
111
111
  },
112
112
  async execute(args) {
113
113
  const entries = getRecentJournal(args.count || 40);
@@ -118,21 +118,21 @@ export const getRecentJournalTool = tool({
118
118
  // --- Summary Tools ---
119
119
 
120
120
  export const saveConversationSummaryTool = tool({
121
- description: "Save a summary of the current conversation for context recovery in future sessions",
121
+ description: 'Save a summary of the current conversation for context recovery in future sessions',
122
122
  args: {
123
- summary: tool.schema.string().describe("Brief summary of what was discussed/accomplished"),
123
+ summary: tool.schema.string().describe('Brief summary of what was discussed/accomplished'),
124
124
  keyDecisions: tool.schema
125
125
  .array(tool.schema.string())
126
126
  .optional()
127
- .describe("Important decisions made"),
127
+ .describe('Important decisions made'),
128
128
  openThreads: tool.schema
129
129
  .array(tool.schema.string())
130
130
  .optional()
131
- .describe("Topics to follow up on"),
131
+ .describe('Topics to follow up on'),
132
132
  learnedPatterns: tool.schema
133
133
  .array(tool.schema.string())
134
134
  .optional()
135
- .describe("New patterns learned about the user"),
135
+ .describe('New patterns learned about the user'),
136
136
  notes: tool.schema
137
137
  .string()
138
138
  .optional()
@@ -151,14 +151,14 @@ export const saveConversationSummaryTool = tool({
151
151
  notes: args.notes,
152
152
  });
153
153
 
154
- return JSON.stringify({ success: true, message: "Conversation summary saved" });
154
+ return JSON.stringify({ success: true, message: 'Conversation summary saved' });
155
155
  },
156
156
  });
157
157
 
158
158
  export const getRecentSummariesTool = tool({
159
- description: "Get recent conversation summaries for context recovery",
159
+ description: 'Get recent conversation summaries for context recovery',
160
160
  args: {
161
- count: tool.schema.number().optional().describe("Number of summaries to retrieve (default: 7)"),
161
+ count: tool.schema.number().optional().describe('Number of summaries to retrieve (default: 7)'),
162
162
  },
163
163
  async execute(args) {
164
164
  const summaries = getRecentSummaries(args.count || 7);
@@ -170,15 +170,15 @@ export const getRecentSummariesTool = tool({
170
170
 
171
171
  export const searchMemoryTool = tool({
172
172
  description:
173
- "Semantic search over your history - journal, state files, projects, people. Use to find relevant context.",
173
+ 'Semantic search over your history - journal, state files, projects, people. Use to find relevant context.',
174
174
  args: {
175
- query: tool.schema.string().describe("Natural language query to search for"),
175
+ query: tool.schema.string().describe('Natural language query to search for'),
176
176
  type: tool.schema
177
- .enum(["journal", "state", "project", "person", "meeting", "topic"])
177
+ .enum(['journal', 'state', 'project', 'person', 'meeting', 'topic'])
178
178
  .optional()
179
- .describe("Filter by content type"),
180
- limit: tool.schema.number().optional().describe("Maximum results to return (default: 5)"),
181
- since: tool.schema.string().optional().describe("Only include items after this ISO date"),
179
+ .describe('Filter by content type'),
180
+ limit: tool.schema.number().optional().describe('Maximum results to return (default: 5)'),
181
+ since: tool.schema.string().optional().describe('Only include items after this ISO date'),
182
182
  },
183
183
  async execute(args) {
184
184
  if (!args.query) {
@@ -194,7 +194,7 @@ export const searchMemoryTool = tool({
194
194
  if (results.length === 0) {
195
195
  return JSON.stringify({
196
196
  success: true,
197
- message: "No matches found. Try rebuilding the index with rebuild_memory_index",
197
+ message: 'No matches found. Try rebuilding the index with rebuild_memory_index',
198
198
  results: [],
199
199
  });
200
200
  }
@@ -214,11 +214,11 @@ export const searchMemoryTool = tool({
214
214
  });
215
215
 
216
216
  export const searchConversationsTool = tool({
217
- description: "Search past OpenCode sessions",
217
+ description: 'Search past OpenCode sessions',
218
218
  args: {
219
- query: tool.schema.string().describe("Natural language query to search for"),
220
- projectOnly: tool.schema.boolean().optional().describe("Only search current project"),
221
- limit: tool.schema.number().optional().describe("Maximum results to return (default: 5)"),
219
+ query: tool.schema.string().describe('Natural language query to search for'),
220
+ projectOnly: tool.schema.boolean().optional().describe('Only search current project'),
221
+ limit: tool.schema.number().optional().describe('Maximum results to return (default: 5)'),
222
222
  },
223
223
  async execute(args) {
224
224
  if (!args.query) {
@@ -234,7 +234,7 @@ export const searchConversationsTool = tool({
234
234
  if (results.length === 0) {
235
235
  return JSON.stringify({
236
236
  success: true,
237
- message: "No matching conversations. Try rebuilding with rebuild_memory_index",
237
+ message: 'No matching conversations. Try rebuilding with rebuild_memory_index',
238
238
  results: [],
239
239
  });
240
240
  }
@@ -258,7 +258,7 @@ export const searchConversationsTool = tool({
258
258
 
259
259
  export const rebuildMemoryIndexTool = tool({
260
260
  description:
261
- "Rebuild the semantic search index from scratch. Use if index seems stale or corrupted.",
261
+ 'Rebuild the semantic search index from scratch. Use if index seems stale or corrupted.',
262
262
  args: {},
263
263
  async execute() {
264
264
  // Rebuild memory index synchronously (fast)
@@ -272,7 +272,7 @@ export const rebuildMemoryIndexTool = tool({
272
272
 
273
273
  return JSON.stringify({
274
274
  success: true,
275
- message: "Memory index rebuilt. Conversation index rebuilding in background.",
275
+ message: 'Memory index rebuilt. Conversation index rebuilding in background.',
276
276
  stats: {
277
277
  memoryItems: memoryStats.itemCount,
278
278
  },
@@ -281,7 +281,7 @@ export const rebuildMemoryIndexTool = tool({
281
281
  });
282
282
 
283
283
  export const getMemoryIndexStatsTool = tool({
284
- description: "Get statistics about the memory index",
284
+ description: 'Get statistics about the memory index',
285
285
  args: {},
286
286
  async execute() {
287
287
  const memoryStats = await getMemoryIndexStats();
@@ -301,17 +301,17 @@ export const scheduleReminderTool = tool({
301
301
  description:
302
302
  "Schedule a recurring reminder using cron syntax. Examples: '0 9 * * *' = 9am daily, '0 */2 * * *' = every 2 hours. IMPORTANT: Check the current time before using this tool to ensure accurate scheduling.",
303
303
  args: {
304
- id: tool.schema.string().describe("Unique reminder identifier"),
304
+ id: tool.schema.string().describe('Unique reminder identifier'),
305
305
  cronExpression: tool.schema
306
306
  .string()
307
307
  .describe("Cron expression (e.g., '0 9 * * *' for 9am daily)"),
308
- description: tool.schema.string().describe("What this reminder is for"),
309
- payload: tool.schema.string().describe("Message to process when reminder fires"),
308
+ description: tool.schema.string().describe('What this reminder is for'),
309
+ payload: tool.schema.string().describe('Message to process when reminder fires'),
310
310
  model: tool.schema
311
311
  .string()
312
312
  .optional()
313
313
  .describe(
314
- "Model to use for this reminder (see macrodata-models in context for available options)",
314
+ 'Model to use for this reminder (see macrodata-models in context for available options)',
315
315
  ),
316
316
  },
317
317
  async execute(args) {
@@ -324,11 +324,11 @@ export const scheduleReminderTool = tool({
324
324
 
325
325
  const schedule: Schedule = {
326
326
  id: args.id,
327
- type: "cron",
327
+ type: 'cron',
328
328
  expression: args.cronExpression,
329
329
  description: args.description,
330
330
  payload: args.payload,
331
- agent: "opencode",
331
+ agent: 'opencode',
332
332
  model: args.model,
333
333
  createdAt: new Date().toISOString(),
334
334
  };
@@ -337,24 +337,24 @@ export const scheduleReminderTool = tool({
337
337
 
338
338
  return JSON.stringify({
339
339
  success: true,
340
- message: `Created recurring reminder: ${args.id} (${args.cronExpression})${args.model ? ` with model ${args.model}` : ""}`,
340
+ message: `Created recurring reminder: ${args.id} (${args.cronExpression})${args.model ? ` with model ${args.model}` : ''}`,
341
341
  });
342
342
  },
343
343
  });
344
344
 
345
345
  export const scheduleOnceTool = tool({
346
346
  description:
347
- "Schedule a one-shot reminder at a specific date/time. The reminder fires once and is automatically removed. IMPORTANT: Check the current time before using this tool to ensure accurate scheduling.",
347
+ 'Schedule a one-shot reminder at a specific date/time. The reminder fires once and is automatically removed. IMPORTANT: Check the current time before using this tool to ensure accurate scheduling.',
348
348
  args: {
349
- id: tool.schema.string().describe("Unique reminder identifier"),
349
+ id: tool.schema.string().describe('Unique reminder identifier'),
350
350
  datetime: tool.schema.string().describe("ISO 8601 datetime (e.g., '2026-01-06T10:00:00')"),
351
- description: tool.schema.string().describe("What this reminder is for"),
352
- payload: tool.schema.string().describe("Message to process when reminder fires"),
351
+ description: tool.schema.string().describe('What this reminder is for'),
352
+ payload: tool.schema.string().describe('Message to process when reminder fires'),
353
353
  model: tool.schema
354
354
  .string()
355
355
  .optional()
356
356
  .describe(
357
- "Model to use for this reminder (see macrodata-models in context for available options)",
357
+ 'Model to use for this reminder (see macrodata-models in context for available options)',
358
358
  ),
359
359
  },
360
360
  async execute(args) {
@@ -367,11 +367,11 @@ export const scheduleOnceTool = tool({
367
367
 
368
368
  const schedule: Schedule = {
369
369
  id: args.id,
370
- type: "once",
370
+ type: 'once',
371
371
  expression: args.datetime,
372
372
  description: args.description,
373
373
  payload: args.payload,
374
- agent: "opencode",
374
+ agent: 'opencode',
375
375
  model: args.model,
376
376
  createdAt: new Date().toISOString(),
377
377
  };
@@ -380,15 +380,15 @@ export const scheduleOnceTool = tool({
380
380
 
381
381
  return JSON.stringify({
382
382
  success: true,
383
- message: `Scheduled one-shot reminder: ${args.id} at ${args.datetime}${args.model ? ` with model ${args.model}` : ""}`,
383
+ message: `Scheduled one-shot reminder: ${args.id} at ${args.datetime}${args.model ? ` with model ${args.model}` : ''}`,
384
384
  });
385
385
  },
386
386
  });
387
387
 
388
388
  export const removeReminderTool = tool({
389
- description: "Remove a scheduled reminder",
389
+ description: 'Remove a scheduled reminder',
390
390
  args: {
391
- id: tool.schema.string().describe("Reminder ID to remove"),
391
+ id: tool.schema.string().describe('Reminder ID to remove'),
392
392
  },
393
393
  async execute(args) {
394
394
  if (!args.id) {
@@ -405,7 +405,7 @@ export const removeReminderTool = tool({
405
405
  });
406
406
 
407
407
  export const listRemindersTool = tool({
408
- description: "List all scheduled reminders",
408
+ description: 'List all scheduled reminders',
409
409
  args: {},
410
410
  async execute() {
411
411
  const schedules = loadAllSchedules();
@@ -417,9 +417,9 @@ export const listRemindersTool = tool({
417
417
 
418
418
  export const getRelatedTool = tool({
419
419
  description:
420
- "Get entries related to a specific memory item. Useful for exploring associative connections in your memory.",
420
+ 'Get entries related to a specific memory item. Useful for exploring associative connections in your memory.',
421
421
  args: {
422
- id: tool.schema.string().describe("The ID of the memory item to find related entries for"),
422
+ id: tool.schema.string().describe('The ID of the memory item to find related entries for'),
423
423
  },
424
424
  async execute(args) {
425
425
  if (!args.id) {
@@ -429,7 +429,7 @@ export const getRelatedTool = tool({
429
429
  // TODO: Implement related items lookup
430
430
  return JSON.stringify({
431
431
  success: true,
432
- message: "Related items feature not yet implemented",
432
+ message: 'Related items feature not yet implemented',
433
433
  related: [],
434
434
  });
435
435
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geoql/mdr",
3
- "version": "0.0.1",
3
+ "version": "1.0.0",
4
4
  "description": "Persistent layered memory for coding agents (OpenCode, Claude Code) — journal, entities, state files, semantic search, daemon, scheduled reminders. A hard fork of ascorbic/macrodata by Matt Kane.",
5
5
  "keywords": [
6
6
  "agent",
@@ -29,7 +29,7 @@
29
29
  "repository": {
30
30
  "type": "git",
31
31
  "url": "git+https://github.com/geoql/mdr.git",
32
- "directory": "plugins/macrodata"
32
+ "directory": "packages/macrodata"
33
33
  },
34
34
  "files": [
35
35
  "dist",
@@ -44,19 +44,6 @@
44
44
  "publishConfig": {
45
45
  "access": "public"
46
46
  },
47
- "scripts": {
48
- "build": "tsdown",
49
- "prepublishOnly": "pnpm build",
50
- "start": "node dist/src/index.js",
51
- "daemon": "node dist/bin/macrodata-daemon.js",
52
- "pretest": "pnpm build",
53
- "test": "vitest run",
54
- "check": "oxlint --type-aware --type-check",
55
- "lint": "oxlint",
56
- "lint:fix": "oxlint --fix",
57
- "format": "oxfmt --write .",
58
- "format:check": "oxfmt --check ."
59
- },
60
47
  "dependencies": {
61
48
  "@huggingface/transformers": "^4.2.0",
62
49
  "@modelcontextprotocol/sdk": "^1.29.0",
@@ -69,10 +56,10 @@
69
56
  },
70
57
  "devDependencies": {
71
58
  "@types/node": "^26.1.1",
72
- "oxfmt": "catalog:",
59
+ "oxfmt": "^0.58.0",
73
60
  "oxlint": "^1.73.0",
74
61
  "oxlint-tsgolint": "latest",
75
- "tsdown": "latest"
62
+ "vite-plus": "^0.2.4"
76
63
  },
77
64
  "engines": {
78
65
  "node": ">=24.11.0"
@@ -83,5 +70,17 @@
83
70
  "chat.message",
84
71
  "experimental.session.compacting"
85
72
  ]
73
+ },
74
+ "scripts": {
75
+ "build": "vp pack",
76
+ "start": "node dist/src/index.js",
77
+ "daemon": "node dist/bin/macrodata-daemon.js",
78
+ "pretest": "pnpm build",
79
+ "test": "vitest run",
80
+ "check": "vp lint --type-aware --type-check",
81
+ "lint": "vp lint",
82
+ "lint:fix": "vp lint --fix",
83
+ "format": "vp fmt",
84
+ "format:check": "vp fmt --check"
86
85
  }
87
- }
86
+ }
package/src/config.ts CHANGED
@@ -5,11 +5,11 @@
5
5
  * so that config changes take effect without restart.
6
6
  */
7
7
 
8
- import { existsSync, readFileSync } from "fs";
9
- import { homedir } from "os";
10
- import { join } from "path";
8
+ import { existsSync, readFileSync } from 'fs';
9
+ import { homedir } from 'os';
10
+ import { join } from 'path';
11
11
 
12
- const DEFAULT_ROOT = join(homedir(), ".config", "macrodata");
12
+ const DEFAULT_ROOT = join(homedir(), '.config', 'macrodata');
13
13
 
14
14
  /**
15
15
  * Get the macrodata state root directory.
@@ -24,10 +24,10 @@ export function getStateRoot(): string {
24
24
  }
25
25
 
26
26
  // Check config file in default location
27
- const configPath = join(DEFAULT_ROOT, "config.json");
27
+ const configPath = join(DEFAULT_ROOT, 'config.json');
28
28
  if (existsSync(configPath)) {
29
29
  try {
30
- const config = JSON.parse(readFileSync(configPath, "utf-8"));
30
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'));
31
31
  if (config.root) return config.root;
32
32
  } catch {
33
33
  // Ignore parse errors
@@ -38,29 +38,29 @@ export function getStateRoot(): string {
38
38
  }
39
39
 
40
40
  export function getStateDir(): string {
41
- return join(getStateRoot(), "state");
41
+ return join(getStateRoot(), 'state');
42
42
  }
43
43
 
44
44
  export function getEntitiesDir(): string {
45
- return join(getStateRoot(), "entities");
45
+ return join(getStateRoot(), 'entities');
46
46
  }
47
47
 
48
48
  export function getJournalDir(): string {
49
- return join(getStateRoot(), "journal");
49
+ return join(getStateRoot(), 'journal');
50
50
  }
51
51
 
52
52
  export function getSignalsDir(): string {
53
- return join(getStateRoot(), "signals");
53
+ return join(getStateRoot(), 'signals');
54
54
  }
55
55
 
56
56
  export function getIndexDir(): string {
57
- return join(getStateRoot(), ".index");
57
+ return join(getStateRoot(), '.index');
58
58
  }
59
59
 
60
60
  export function getTopicsDir(): string {
61
- return join(getStateRoot(), "topics");
61
+ return join(getStateRoot(), 'topics');
62
62
  }
63
63
 
64
64
  export function getRemindersDir(): string {
65
- return join(getStateRoot(), "reminders");
65
+ return join(getStateRoot(), 'reminders');
66
66
  }