@theronap/agnoclast-mcp 0.9.171 → 0.9.172

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/lib/server.mjs +75 -0
  2. package/package.json +1 -1
package/lib/server.mjs CHANGED
@@ -4106,6 +4106,81 @@ function renderNudge(payload) {
4106
4106
  },
4107
4107
  )
4108
4108
 
4109
+ // ⭐ THE OTHER HALF OF set_routing_identifier (2026-09-24). A claim was ONE CALL to create and,
4110
+ // through this server, impossible to remove — so a wrong brain decision was permanent. That
4111
+ // contradicts the thing ADR-0066 is built on: filing is a judgment, and judgments get revised.
4112
+ //
4113
+ // ⚠ THE ENGINE AND THE ENDPOINT BOTH ALREADY EXISTED. `clearPageRoutingIdentifier` and the DELETE
4114
+ // on /api/brain/routing-identifiers have been there the whole time; only the agent-facing verb was
4115
+ // missing, so the capability was real and unreachable. Ninth instance of that shape this week.
4116
+ server.registerTool(
4117
+ 'unclaim_routing_identifier',
4118
+ {
4119
+ title: 'Remove a routing claim from a page',
4120
+ description:
4121
+ 'Remove an identifier claim from a page — the counterpart to `set_routing_identifier`. Use it when a claim sends mail to the wrong brain, when a page was claimed by mistake, or when TWO brains claim the same key and you want one of them to stop (that is the case where nothing routes at all, because a split stages rather than picking). ' +
4122
+ '⭐ THE RESPONSE TELLS YOU WHAT ROUTING DOES NOW, which is the reason to call it: removing a claim moves the identifier between "routes", "stages because nothing claims it" and "stages because several do", and the delete count alone cannot tell you which. Computed with the router\'s own logic. ' +
4123
+ '⚠ HISTORY IS NOT UNDONE BY DEFAULT. `set_routing_identifier` HEALS history — it attaches every record already carrying the identifier — but removing the claim leaves those attachments in place, and the response says how many. That asymmetry is deliberate: a claim is a ROUTING RULE, an attachment is a RECORD\'S PLACEMENT, and one such claim was measured accounting for 1,271 attachments on a single page. Pass `detach: true` only when you mean to unfile them too; it never touches a governing attachment, or one a person or an LLM made rather than this claim. ' +
4124
+ '⚠ REVERSIBLE BY CONSTRUCTION: `set_routing_identifier` puts it back in one call and re-heals history. No content is destroyed here, which is why this needs no dry run.',
4125
+ inputSchema: {
4126
+ kind: z.enum(['project', 'person', 'org', 'user']).describe('the page kind'),
4127
+ name: z.string().optional().describe('page title (or pass ref)'),
4128
+ ref: z.string().optional().describe('node ref from read_page — prefer over name when available'),
4129
+ brain: z.string().optional().describe('brain label when the title is ambiguous across brains — REQUIRED in practice when two brains hold a page of the same name, which is the usual reason you are here'),
4130
+ identifier: z.string().describe('the claim to remove, e.g. email:someone@example.com or repo:owner/name. See `my_routing_claims` for what is claimed where'),
4131
+ detach: z.boolean().optional().describe('also remove the attachments this claim made (default false). Leaves governing attachments and anything a person or LLM attached'),
4132
+ },
4133
+ },
4134
+ async ({ kind, name, ref, brain, identifier, detach }) => {
4135
+ if (!name && !ref) return toolError('Pass name or ref')
4136
+ let res
4137
+ try {
4138
+ res = await fetchCortex(`${BASE}/api/brain/routing-identifiers`, {
4139
+ method: 'DELETE',
4140
+ headers: { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json' },
4141
+ body: JSON.stringify({ kind, name, ref, brain, identifier, detach: detach === true }),
4142
+ })
4143
+ } catch (e) {
4144
+ return toolError(`Could not remove the routing claim: ${e.message}`)
4145
+ }
4146
+ const out = await res.json().catch(() => null)
4147
+ if (!res.ok) {
4148
+ if (out?.candidates?.length) {
4149
+ return toolError(`That page title is ambiguous across brains — pass \`brain\`. Candidates: ${out.candidates.join(', ')}`)
4150
+ }
4151
+ return toolError(`Could not remove the routing claim: ${out?.error ?? res.status}`)
4152
+ }
4153
+ // A ZERO IS A VERDICT, NOT AN ERROR — the same convention my_routing_claims states. "No such
4154
+ // claim" is worth saying plainly, because the usual cause is that the claim is on a DIFFERENT
4155
+ // page (or in a different brain) than the caller assumed, and retrying the same call will not
4156
+ // find it either.
4157
+ if (!out?.removed) {
4158
+ return {
4159
+ content: [{
4160
+ type: 'text',
4161
+ text: `No claim on ${identifier} was found on that page, so nothing changed. That usually means the claim lives on a different page or in another brain — \`my_routing_claims ${identifier}\` shows every page that claims it.`,
4162
+ }],
4163
+ }
4164
+ }
4165
+ const left = typeof out?.attachmentsLeft === 'number' ? out.attachmentsLeft : null
4166
+ const historyLine = out?.detached
4167
+ ? `\n ${out.detached} attachment(s) this claim had made were also removed; governing attachments and anything a person or an LLM attached were left alone.`
4168
+ : left
4169
+ ? `\n ⚠ ${left} record(s) this claim previously attached to that page are STILL attached — removing the rule does not unfile history. Re-run with \`detach: true\` if they should come off too.`
4170
+ : ''
4171
+ return {
4172
+ content: [{
4173
+ type: 'text',
4174
+ text:
4175
+ `Removed the claim on ${out?.identifier ?? identifier}.\n` +
4176
+ ` ➜ ${out?.routing?.verdict ?? '(routing outcome unavailable)'}` +
4177
+ historyLine +
4178
+ `\n Reversible: \`set_routing_identifier\` puts it back and re-attaches history.`,
4179
+ }],
4180
+ }
4181
+ },
4182
+ )
4183
+
4109
4184
  // ── Gate 4 record triage, over timeline_claims ────────────────────────────────────────────
4110
4185
  // A connector event materializes in seconds and has no idea what the work WAS. The session that
4111
4186
  // did the work knows exactly, and arrives later. These three tools are that handoff: look at what
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theronap/agnoclast-mcp",
3
- "version": "0.9.171",
3
+ "version": "0.9.172",
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": {