@theronap/agnoclast-mcp 0.9.234 → 0.9.236

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/lib/grep_cli.mjs CHANGED
@@ -54,8 +54,12 @@ export function formatGrepHits(payload, query) {
54
54
  : `${hits.length} match${hits.length === 1 ? '' : 'es'} for "${query}":`
55
55
  const lines = [header, '']
56
56
  for (const h of hits) {
57
+ // Records (server 2026-10-15, ADR-0081) arrive in the same list, already labelled in the title.
58
+ const isRecord = h.kind === 'record'
57
59
  const head = h.heading ? ` > ${h.heading}` : ''
58
- lines.push(`- ${h.title}${head} [${h.tier}]`)
60
+ lines.push(isRecord
61
+ ? `- ${h.title}${h.brain && h.brain.name ? ` · ${h.brain.name}` : ''}\n read_record ${(h.record && h.record.id) || h.documentId}`
62
+ : `- [page] ${h.title}${head} [${h.tier}]`)
59
63
  if (h.snippet) lines.push(` ${String(h.snippet).replace(/\s+/g, ' ').trim()}`)
60
64
  // Cap the link list per hit. Median is 2 but the tail reaches 32, and at ~126 chars/hit the
61
65
  // link lists were the second-largest cost in the payload after snippets. The count is kept so
@@ -63,7 +67,7 @@ export function formatGrepHits(payload, query) {
63
67
  if (h.links && h.links.length) {
64
68
  const shown = h.links.slice(0, LINKS_PER_HIT)
65
69
  const more = h.links.length - shown.length
66
- lines.push(` -> ${shown.map((l) => `[[${l}]]`).join(' ')}${more > 0 ? ` (+${more} more)` : ''}`)
70
+ lines.push(` ${isRecord ? 'filed on' : '->'} ${shown.map((l) => `[[${l}]]`).join(' ')}${more > 0 ? ` (+${more} more)` : ''}`)
67
71
  }
68
72
  }
69
73
  return lines.join('\n')
@@ -50,7 +50,7 @@ export function renderRecord(rec, maxChars = READ_RECORD_DEFAULT_CHARS, part = '
50
50
  out.push('')
51
51
  }
52
52
  if (notes && want === 'notes') {
53
- out.push(`Full transcript: ${content.length.toLocaleString('en-US')} characters, not shown. Call read_record with part: "transcript" when you need the exact words; grep and search already cover it.`)
53
+ out.push(`Full transcript: ${content.length.toLocaleString('en-US')} characters, not shown. Call read_record with part: "transcript" when you need the exact words; grep and search find a meeting by its title and notes, not its raw transcript.`)
54
54
  } else if (!content.trim()) {
55
55
  out.push('(No content was captured for this record.)')
56
56
  } else if (content.length > cap) {
package/lib/server.mjs CHANGED
@@ -1198,6 +1198,7 @@ function renderNudge(payload) {
1198
1198
  inputSchema: {
1199
1199
  claimKind: z.enum(['relevance', 'cleanup']).optional().describe('default relevance'),
1200
1200
  limit: z.number().optional().describe('max items (default 10). Ignored when intakeItemIds is given.'),
1201
+ source: z.string().optional().describe('claim only the oldest units of ONE source — e.g. "imessage", "meeting", "email", "github", "claude-code". Reaches texts without first claiming every older GitHub/session unit ahead of them. Ignored when intakeItemIds is given.'),
1201
1202
  leaseMinutes: z.number().optional().describe('lease length in minutes, 5-60 (default 30). Prefer intake_look for read-only inspection — a short lease is only for briefly exclusive work.'),
1202
1203
  // 🔴 SINGULAR ACCEPTED, AND NOT AS A CONVENIENCE. Every sibling verb takes `intakeItemId`:
1203
1204
  // intake_look, intake_materialize, intake_release, intake_defer, intake_discard. This one
@@ -1221,7 +1222,7 @@ function renderNudge(payload) {
1221
1222
  ),
1222
1223
  },
1223
1224
  },
1224
- async ({ claimKind, limit, intakeItemId, intakeItemIds, leaseMinutes }) => {
1225
+ async ({ claimKind, limit, source, intakeItemId, intakeItemIds, leaseMinutes }) => {
1225
1226
  // Merge the two spellings before anything else looks at them. Passing both is not an error —
1226
1227
  // the union is what the caller plainly meant.
1227
1228
  const ids = [...new Set([...(intakeItemIds ?? []), ...(intakeItemId ? [intakeItemId] : [])])]
@@ -1238,6 +1239,7 @@ function renderNudge(payload) {
1238
1239
  // survive as one; sending `[]` where the caller sent nothing would silently switch a FIFO
1239
1240
  // claim into a no-op.
1240
1241
  ...(intakeItemIds ? { intakeItemIds } : {}),
1242
+ ...(source ? { source } : {}),
1241
1243
  }),
1242
1244
  })
1243
1245
  if (!res.ok) {
@@ -1996,9 +1998,9 @@ function renderNudge(payload) {
1996
1998
  server.registerTool(
1997
1999
  'grep',
1998
2000
  {
1999
- title: 'Grep the brain wiki',
2001
+ title: 'Grep pages and records',
2000
2002
  description:
2001
- 'Ranked keyword search across your visible brain wiki pages. Multi-word natural-language queries work (results are ranked by relevance). Pass mode:"substring" for an exact literal match of symbols, identifiers, or [[links]] — and for an English STOPWORD ("own", "not"), which ranked search drops. Returns matching sections with a context snippet and their outbound [[links]]. A broad query fans out across every brain you can see, so pass `max` when you only need to locate a page; the header always says how many matched in total, so a capped list is never mistaken for the whole answer.',
2003
+ 'Ranked keyword search across your visible brain wiki pages AND the records filed in your brains (meeting/lecture transcripts and their notes, emails, sessions, messages) — one list, each hit labelled [page] or [record · type · date] with its id and the pages it is filed on. An empty result means neither a page nor a record mentions it. Multi-word natural-language queries work (results are ranked by relevance). Pass mode:"substring" for an exact literal match of symbols, identifiers, or [[links]] — and for an English STOPWORD ("own", "not"), which ranked search drops. Returns matching sections with a context snippet and their outbound [[links]]. A broad query fans out across every brain you can see, so pass `max` when you only need to locate a page; the header always says how many matched in total, so a capped list is never mistaken for the whole answer.',
2002
2004
  inputSchema: {
2003
2005
  query: z.string().describe('search terms (natural language is fine)'),
2004
2006
  mode: z.enum(['substring', 'fts']).optional().describe("'fts' (default, ranked keyword) or 'substring' (exact literal — for identifiers / [[links]] / code)"),
@@ -4767,8 +4769,8 @@ function renderNudge(payload) {
4767
4769
  'that does not exist. ' +
4768
4770
  'A meeting or lecture transcript has TWO LAYERS: notes (the gist, decisions, action items) and the full ' +
4769
4771
  'transcript. By default you get the NOTES and the transcript\'s length; read the notes first, and ask for ' +
4770
- 'part: "transcript" only when you need the exact words. To FIND something said in a meeting, grep and ' +
4771
- 'search already cover the transcript.',
4772
+ 'part: "transcript" only when you need the exact words. To FIND a meeting, grep and search ' +
4773
+ 'cover its title and notes (not the raw transcript words).',
4772
4774
  inputSchema: {
4773
4775
  id: z.string().describe('the record id, from list_records, my_day, timeline_pull or another read_record'),
4774
4776
  max_chars: z.number().optional().describe(`cap on the content shown (default ${READ_RECORD_DEFAULT_CHARS}); the reply says how much was left out`),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theronap/agnoclast-mcp",
3
- "version": "0.9.234",
3
+ "version": "0.9.236",
4
4
  "description": "Connect your AI assistant to Cortex — your org's projects, activity, gaps, and directives, scoped to you.",
5
5
  "type": "module",
6
6
  "bin": {