@theronap/agnoclast-mcp 0.9.224 → 0.9.226
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/server.mjs +57 -4
- package/package.json +1 -1
package/lib/server.mjs
CHANGED
|
@@ -4685,6 +4685,49 @@ function renderNudge(payload) {
|
|
|
4685
4685
|
},
|
|
4686
4686
|
)
|
|
4687
4687
|
|
|
4688
|
+
// relabel_record_people — put a real name where a text record names its person by a bare phone number
|
|
4689
|
+
// (records filed before desktop 0.1.40 could not read Contacts). Owner-only; labels, never identifiers or
|
|
4690
|
+
// message bodies; dry run unless apply: true; the server keeps each before-state in record history.
|
|
4691
|
+
server.registerTool(
|
|
4692
|
+
'relabel_record_people',
|
|
4693
|
+
{
|
|
4694
|
+
title: 'Put a name on texts that show a bare phone number',
|
|
4695
|
+
description:
|
|
4696
|
+
'On YOUR OWN text-message records, replace a bare phone number standing as a person\'s name ("1 message with ' +
|
|
4697
|
+
'+18015550100") with the name you give: the summary, the thread label and the "who:" speaker prefix of each ' +
|
|
4698
|
+
'message. Never changes the number itself as an identifier, message wording, or who can see the record. ' +
|
|
4699
|
+
'Dry run by default (reports how many records would change); pass apply: true to write. Safe to repeat.',
|
|
4700
|
+
inputSchema: {
|
|
4701
|
+
mappings: z.array(z.object({
|
|
4702
|
+
phone: z.string().describe('E.164, e.g. +18015550100 (a "phone:" prefix is fine)'),
|
|
4703
|
+
name: z.string().describe('the display name to show instead'),
|
|
4704
|
+
})).min(1).max(50).describe('one or more number → name pairs'),
|
|
4705
|
+
apply: z.boolean().optional().describe('true = write; omitted/false = dry run'),
|
|
4706
|
+
},
|
|
4707
|
+
},
|
|
4708
|
+
async ({ mappings, apply }) => {
|
|
4709
|
+
let res
|
|
4710
|
+
try {
|
|
4711
|
+
res = await fetchCortex(`${BASE}/api/records/relabel-people`, {
|
|
4712
|
+
method: 'POST',
|
|
4713
|
+
headers: { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json' },
|
|
4714
|
+
body: JSON.stringify({ mappings, dry_run: apply !== true }),
|
|
4715
|
+
})
|
|
4716
|
+
} catch (e) {
|
|
4717
|
+
return toolError(`Could not reach Agnoclast: ${e.message}`)
|
|
4718
|
+
}
|
|
4719
|
+
const body = await res.json().catch(() => ({}))
|
|
4720
|
+
if (res.status === 404 && !body?.error) return toolError('This server does not relabel records yet. Nothing was written.')
|
|
4721
|
+
if (res.status === 422) return toolError(`Not done: ${body?.detail ?? 'the mappings were refused'}.`)
|
|
4722
|
+
if (!res.ok || !body?.ok) return toolError(`Could not relabel: HTTP ${res.status} ${JSON.stringify(body)}`)
|
|
4723
|
+
const ids = (body.recordIds ?? []).join(', ')
|
|
4724
|
+
const text = body.dryRun
|
|
4725
|
+
? `Dry run: ${body.changed} of your text records would be relabelled (${body.matched} mention the number${body.matched === 1 ? '' : 's'}).${ids ? ` Records: ${ids}.` : ''} Nothing was written; pass apply: true to write.`
|
|
4726
|
+
: `Relabelled ${body.changed} of your text records.${ids ? ` Records: ${ids}.` : ''} Each before-state is kept in record history.`
|
|
4727
|
+
return { content: [{ type: 'text', text }] }
|
|
4728
|
+
},
|
|
4729
|
+
)
|
|
4730
|
+
|
|
4688
4731
|
// ── the questions agents used to answer with SQL (Agnoclast page "Agent SQL gap", 2026-10-07) ──────
|
|
4689
4732
|
// Theron, 2026-10-07: "any information that I have felt the need to get about my own brains, but was
|
|
4690
4733
|
// not able to do it with Agnoclast tools … we either need to make tools for that, or …". Measured the
|
|
@@ -5270,13 +5313,14 @@ function renderNudge(payload) {
|
|
|
5270
5313
|
'set_routing_identifier',
|
|
5271
5314
|
{
|
|
5272
5315
|
title: 'Claim a routing identifier on a page',
|
|
5273
|
-
description: 'Declare that a page is a Gate 4 attach HOME for an identifier (repo:owner/name or file:owner/name:path). Body [[repo:…]] stamps are navigation only and do NOT drive attach — use this instead. Prefer the narrowest id: mother pages own repo:; feature pages own file: paths. Do not copy every body mention into a routing claim.'
|
|
5316
|
+
description: 'Declare that a page is a Gate 4 attach HOME for an identifier (repo:owner/name or file:owner/name:path). Body [[repo:…]] stamps are navigation only and do NOT drive attach — use this instead. Prefer the narrowest id: mother pages own repo:; feature pages own file: paths. Do not copy every body mention into a routing claim. ' +
|
|
5317
|
+
'PRIVATE CONTACT CLAIMS (ADR-0079): on a PERSON page you may claim `phone:<number>` (normalized to E.164, US default — `phone:(801) 636-7505` stores `phone:+18016367505`) or `email:<address>` (lowercased). These are visible ONLY to you — never in the page body, grep, or to other brain members — and they make your captured texts / mail from that contact propose that person page. This is the right place for a contact\'s number; never put it in page text.',
|
|
5274
5318
|
inputSchema: {
|
|
5275
5319
|
kind: z.enum(['project', 'person', 'org', 'user']).describe('the page kind'),
|
|
5276
5320
|
name: z.string().optional().describe('page title (or pass ref)'),
|
|
5277
5321
|
ref: z.string().optional().describe('node ref from read_page — prefer over name when available'),
|
|
5278
5322
|
brain: z.string().optional().describe('brain label when the title is ambiguous across brains'),
|
|
5279
|
-
identifier: z.string().describe('canonical identifier, e.g. repo:theronap/cortex
|
|
5323
|
+
identifier: z.string().describe('canonical identifier, e.g. repo:theronap/cortex, file:theronap/cortex:web/lib/engine/github_intake.ts, or on a person page phone:+18015550123 / email:someone@example.com (private to you)'),
|
|
5280
5324
|
},
|
|
5281
5325
|
},
|
|
5282
5326
|
async ({ kind, name, ref, brain, identifier }) => {
|
|
@@ -5292,7 +5336,12 @@ function renderNudge(payload) {
|
|
|
5292
5336
|
return toolError(`Could not set routing identifier: ${e.message}`)
|
|
5293
5337
|
}
|
|
5294
5338
|
const out = await res.json().catch(() => null)
|
|
5295
|
-
if (!res.ok)
|
|
5339
|
+
if (!res.ok) {
|
|
5340
|
+
// A per-identifier refusal arrives in `errors[]` with a top-level 400 — name it, not just the status.
|
|
5341
|
+
const why = out?.error ?? out?.errors?.map((e) => e.error).join(', ') ?? res.status
|
|
5342
|
+
const hint = /phone_claims_person_pages_only/.test(String(why)) ? ' A phone: claim goes on the PERSON page for that contact (kind: person).' : ''
|
|
5343
|
+
return toolError(`Could not set routing identifier: ${why}.${hint}`)
|
|
5344
|
+
}
|
|
5296
5345
|
const set = out?.set?.join(', ') ?? identifier
|
|
5297
5346
|
// ⚠ SAY WHAT ALREADY HAPPENED, NOT ONLY WHAT WILL. The claim heals history in the same
|
|
5298
5347
|
// statement, so by the time this renders, existing records are ALREADY attached. The previous
|
|
@@ -5306,7 +5355,11 @@ function renderNudge(payload) {
|
|
|
5306
5355
|
: healed > 0
|
|
5307
5356
|
? ` ${healed} existing record(s) ALREADY attached to this page as a result.`
|
|
5308
5357
|
: ' 0 existing records attached — either nothing carries this identifier yet, or records do but belong to another owner (an identity claim only attaches your own).'
|
|
5309
|
-
|
|
5358
|
+
const isContact = /^(phone|email):/.test(String(out?.set?.[0] ?? identifier).toLowerCase())
|
|
5359
|
+
const privacyLine = isContact
|
|
5360
|
+
? ' This contact claim is PRIVATE to you: no other brain member can see it, and it is never rendered in the page. Your captured texts/mail from this contact will now propose this page.'
|
|
5361
|
+
: ''
|
|
5362
|
+
return { content: [{ type: 'text', text: `Routing identifier set on document ${out?.documentId ?? '?'}: ${set}.${healedLine} Future matching events will attach here too (body mentions alone will not).${privacyLine}` }] }
|
|
5310
5363
|
},
|
|
5311
5364
|
)
|
|
5312
5365
|
|
package/package.json
CHANGED