@theronap/agnoclast-mcp 0.9.252 → 0.9.254
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/obligations_render.mjs +2 -0
- package/lib/release_gate.mjs +1 -1
- package/lib/server.mjs +65 -9
- package/package.json +1 -1
|
@@ -122,6 +122,8 @@ export function renderObligations(obs, now = Date.now(), extras = null) {
|
|
|
122
122
|
const pages = Array.isArray(o.pages) ? o.pages.filter((p) => p?.origin !== 'fallback') : []
|
|
123
123
|
if (pages.length) lines.push(` on: ${pages.slice(0, 4).map((p) => `“${String(p.title ?? '').replace(/\s+/g, ' ').trim().slice(0, 60)}”`).join(' · ')}${pages.length > 4 ? ` … and ${pages.length - 4} more` : ''}`)
|
|
124
124
|
if (o.needsPage === true) lines.push(' ⚠ on no page anyone chose — set_obligation_pages')
|
|
125
|
+
// ADR-0093: who is waiting on it. Absent on an older server: nothing is said.
|
|
126
|
+
if (o.owedTo?.title) lines.push(` → owed to “${String(o.owedTo.title).replace(/\s+/g, ' ').trim().slice(0, 60)}” (ref ${o.owedTo.ref}) — read their page for context`)
|
|
125
127
|
// Only when it is wider than the default: who else can see this when they look at its page.
|
|
126
128
|
if (tierReads(o.tier)) lines.push(` visible to: ${tierReads(o.tier)} — they can see it; nobody but you is told about it`)
|
|
127
129
|
// Whose idea it was, and whether it is on its way to someone else. Both change what to DO with it.
|
package/lib/release_gate.mjs
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// that web/lib/engine/release.test.ts pins to the server's registry.
|
|
6
6
|
|
|
7
7
|
/** Tools any release flag gates — hidden when the server cannot be asked. Mirror of allGatedTools(). */
|
|
8
|
-
export const GATED_FALLBACK = ['my_messages', 'read_conversation', 'send_message']
|
|
8
|
+
export const GATED_FALLBACK = ['my_messages', 'read_conversation', 'send_message', 'set_manager']
|
|
9
9
|
|
|
10
10
|
export const RELEASE_FETCH_TIMEOUT_MS = 2500
|
|
11
11
|
|
package/lib/server.mjs
CHANGED
|
@@ -3095,9 +3095,10 @@ function renderNudge(payload) {
|
|
|
3095
3095
|
closed: z.boolean().optional().describe('true = also show discharged/cancelled ones'),
|
|
3096
3096
|
limit: z.number().optional().describe('default 50'),
|
|
3097
3097
|
page: z.string().optional().describe("a page's `ref:` as read_page prints it. Lists EVERYONE's open obligations on that page that the person may see — theirs first, then other people's under each owner's name. Use it when a page read says other people have obligations there and the person asks to see them; seeing one does not make it theirs."),
|
|
3098
|
+
owed_to: z.string().optional().describe("a person's page `ref:` — only what the person owes THEM (\"what do I owe Tanner?\"), across every page"),
|
|
3098
3099
|
},
|
|
3099
3100
|
},
|
|
3100
|
-
async ({ closed, limit, page }) => {
|
|
3101
|
+
async ({ closed, limit, page, owed_to }) => {
|
|
3101
3102
|
let res
|
|
3102
3103
|
if (page) {
|
|
3103
3104
|
try {
|
|
@@ -3111,6 +3112,7 @@ function renderNudge(payload) {
|
|
|
3111
3112
|
const qs = new URLSearchParams()
|
|
3112
3113
|
if (closed) qs.set('closed', 'true')
|
|
3113
3114
|
if (limit) qs.set('limit', String(limit))
|
|
3115
|
+
if (owed_to) qs.set('owedTo', owed_to.trim())
|
|
3114
3116
|
res = await fetchCortex(`${BASE}/api/obligations?${qs}`, { headers: { Authorization: `Bearer ${TOKEN}` } })
|
|
3115
3117
|
} catch (e) { return toolError(`Could not reach obligations: ${e.message}`) }
|
|
3116
3118
|
const out = await res.json().catch(() => null)
|
|
@@ -3124,7 +3126,7 @@ function renderNudge(payload) {
|
|
|
3124
3126
|
'track_obligation',
|
|
3125
3127
|
{
|
|
3126
3128
|
title: 'Record something you owe',
|
|
3127
|
-
description: "Record something you owe: a subject, the page or pages it is about, optionally when it comes due, optionally whose reply would discharge it. ⚠ EVERY OBLIGATION LIVES ON A PAGE, CHOSEN NOW. `pages` is required: READ the page this is about first (read_page prints its `ref:`), then pass that ref — several when it genuinely belongs on several. Never guess a page to get past the check, and never default to the person's
|
|
3129
|
+
description: "Record something you owe: a subject, the page or pages it is about, optionally when it comes due, optionally whose reply would discharge it. ⚠ EVERY OBLIGATION LIVES ON A PAGE, CHOSEN NOW. `pages` is required: READ the page this is about first (read_page prints its `ref:`), then pass that ref — several when it genuinely belongs on several. Never guess a page to get past the check, and never default to the person's OWN page: if you cannot tell where it belongs, ask them. A page says where the obligation is FOUND, not who can see it: it is visible to its owner only unless the person later widens it (`set_obligation_tier`). ⚠ ONLY A DATE MAKES IT COME BACK. A DATED obligation is raised to the person's sessions by time, unasked, BEFORE it lapses: counted on the day it is due, and named when a stated clock time is within the hour. ⚠ A DEADLINE IS NOT WHEN TO START: pass `work_from` when the work needs lead time (a 10-day project opens 10 days ahead; an exam, days of study). From then it is named daily as \"work on now\", and once on the desktop when it opens. Once late it is never raised again, and an UNDATED one is never raised by anything — it surfaces only when someone asks with my_obligations. ⚠ NEVER INVENT A DUE DATE: an invented date will interrupt someone. Omit due_at when there is no real deadline (a standing obligation); a guessed date is indistinguishable from a real one once stored, and leads straight to nagging about something that was never late. ⚠ OWED TO SOMEONE? Pass `owed_to`: the ref of their page (\"I owe Tanner a text\" → Tanner's page). It is attached, so a later agent reads it instead of asking who, and records from their email or phone count as evidence this may be done. `owed_to` is who WAITS; `for` is who OWES. `anchor_identifier` (e.g. `repo:owner/name`) covers evidence that is not a person.",
|
|
3128
3130
|
inputSchema: {
|
|
3129
3131
|
subject: z.string().describe('what is owed, in your own words'),
|
|
3130
3132
|
pages: z.array(z.string()).min(1).describe('REQUIRED. The `ref:` of each page this obligation is about, exactly as read_page prints it. Read the page first; do not guess.'),
|
|
@@ -3132,18 +3134,19 @@ function renderNudge(payload) {
|
|
|
3132
3134
|
note: z.string().optional().describe('with `for`: a short note to the person it is given to'),
|
|
3133
3135
|
due_at: z.string().optional().describe('ISO 8601. OMIT when there is no real deadline — never guess one.'),
|
|
3134
3136
|
work_from: z.string().optional().describe('ISO 8601: when work should START — the window opens (a bare date = the start of that day). Needs due_at, and must come before it. Estimate it from what the work involves; omit for things needing no lead time.'),
|
|
3135
|
-
|
|
3137
|
+
owed_to: z.string().optional().describe("the `ref:` of the page of the person (or org) this is owed TO — who is waiting on it. Read their page first. Omit when it is owed to nobody in particular."),
|
|
3138
|
+
anchor_identifier: z.string().optional().describe('e.g. "repo:owner/name" — records carrying it become evidence this may be done. For a person, prefer owed_to.'),
|
|
3136
3139
|
source_record_id: z.string().optional().describe('the record this came from, if any'),
|
|
3137
|
-
brain: z.string().optional().describe('required only if you belong to more than one
|
|
3140
|
+
brain: z.string().optional().describe('the brain\'s name or id — required only if you belong to more than one'),
|
|
3138
3141
|
},
|
|
3139
3142
|
},
|
|
3140
|
-
async ({ subject, pages, due_at, work_from, anchor_identifier, source_record_id, brain, for: giveTo, note: giveNote }) => {
|
|
3143
|
+
async ({ subject, pages, due_at, work_from, anchor_identifier, source_record_id, brain, for: giveTo, note: giveNote, owed_to }) => {
|
|
3141
3144
|
let res
|
|
3142
3145
|
try {
|
|
3143
3146
|
res = await fetchCortex(`${BASE}/api/obligations`, {
|
|
3144
3147
|
method: 'POST',
|
|
3145
3148
|
headers: { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json' },
|
|
3146
|
-
body: JSON.stringify({ subject, pages, dueAt: due_at, workFrom: work_from, anchorIdentifier: anchor_identifier, sourceRecordId: source_record_id, brain, for: giveTo, note: giveNote }),
|
|
3149
|
+
body: JSON.stringify({ subject, pages, dueAt: due_at, workFrom: work_from, anchorIdentifier: anchor_identifier, sourceRecordId: source_record_id, brain, for: giveTo, note: giveNote, owedTo: owed_to }),
|
|
3147
3150
|
})
|
|
3148
3151
|
} catch (e) { return toolError(`Could not reach obligations: ${e.message}`) }
|
|
3149
3152
|
const out = await res.json().catch(() => null)
|
|
@@ -3154,9 +3157,9 @@ function renderNudge(payload) {
|
|
|
3154
3157
|
? (work_from ? `From ${work_from.slice(0, 10)} it is named daily as "work on now" (and once on the desktop). ` : '')
|
|
3155
3158
|
+ 'It will be raised to your sessions on the day it is due' + (/T\d{2}:\d{2}/.test(due_at) ? ', and again when it is within the hour.' : '.')
|
|
3156
3159
|
: 'It has no date, so nothing will raise it \u2014 ask with my_obligations.'
|
|
3157
|
-
const note =
|
|
3158
|
-
? `\nRecords carrying ${anchor_identifier} will be offered as evidence this is done
|
|
3159
|
-
|
|
3160
|
+
const note = (owed_to ? '\nOwed to that person: their page is attached, and records from them will be offered as evidence this is done.' : '')
|
|
3161
|
+
+ (anchor_identifier ? `\nRecords carrying ${anchor_identifier} will be offered as evidence this is done.` : '')
|
|
3162
|
+
+ `\n${nudge}`
|
|
3160
3163
|
const on = Number(out.pages) > 0 ? ` — on ${out.pages} page${out.pages === 1 ? '' : 's'}` : ''
|
|
3161
3164
|
// Given to someone else: say plainly which of the two things happened. "Assigned" and "asked"
|
|
3162
3165
|
// leave the obligation with different people, and the agent must not report one as the other.
|
|
@@ -3344,6 +3347,33 @@ function renderNudge(payload) {
|
|
|
3344
3347
|
},
|
|
3345
3348
|
)
|
|
3346
3349
|
|
|
3350
|
+
// 2026-10-21. Change who a member reports to — people and AI agents (Theron: "It's got to be real").
|
|
3351
|
+
server.registerTool(
|
|
3352
|
+
'set_manager',
|
|
3353
|
+
{
|
|
3354
|
+
title: 'Change who someone reports to',
|
|
3355
|
+
description: "Move a member of one of the person's brains — a person or an AI agent — to report to someone else (a person or an agent). ONLY when the person asked you to. Everyone below the member moves with them. This changes permissions: the new manager and everyone above them can see the member's scoped work, and what the manager gives them becomes an assignment instead of a request; the old chain loses both. Reversible: move them back the same way. Only an owner or admin of the brain can do it; nobody reports to themselves or to someone in their own line of reports, and owners stay at the top. Use an email address when a name could match two people.",
|
|
3356
|
+
inputSchema: {
|
|
3357
|
+
member: z.string().describe('who moves: their email address, or their name as it appears in the brain'),
|
|
3358
|
+
manager: z.string().describe('who they will report to: an email address or a name as it appears in the brain'),
|
|
3359
|
+
brain: z.string().optional().describe('which brain — required if the person belongs to more than one'),
|
|
3360
|
+
},
|
|
3361
|
+
},
|
|
3362
|
+
async ({ member, manager, brain }) => {
|
|
3363
|
+
let res
|
|
3364
|
+
try {
|
|
3365
|
+
res = await fetchCortex(`${BASE}/api/members/manager`, {
|
|
3366
|
+
method: 'POST',
|
|
3367
|
+
headers: { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json' },
|
|
3368
|
+
body: JSON.stringify({ member, manager, brain }),
|
|
3369
|
+
})
|
|
3370
|
+
} catch (e) { return toolError(`Could not reach Agnoclast: ${e.message}`) }
|
|
3371
|
+
const out = await res.json().catch(() => null)
|
|
3372
|
+
if (!res.ok) return toolError(`Not moved: ${out?.detail ?? out?.error ?? res.status}`)
|
|
3373
|
+
return { content: [{ type: 'text', text: out.summary }] }
|
|
3374
|
+
},
|
|
3375
|
+
)
|
|
3376
|
+
|
|
3347
3377
|
// 2026-10-12. A member leaves a brain THEMSELVES — the remove_member path with the caller as the target.
|
|
3348
3378
|
server.registerTool(
|
|
3349
3379
|
'leave_brain',
|
|
@@ -3446,6 +3476,32 @@ function renderNudge(payload) {
|
|
|
3446
3476
|
},
|
|
3447
3477
|
)
|
|
3448
3478
|
|
|
3479
|
+
server.registerTool(
|
|
3480
|
+
'set_obligation_owed_to',
|
|
3481
|
+
{
|
|
3482
|
+
title: 'Say who an obligation is owed to',
|
|
3483
|
+
description: "Say who an existing obligation is owed TO — the person waiting on it (ADR-0093) — or clear it. Pass the `ref:` of their page (person or org), read first. Their page is attached to the obligation, my_obligations shows \"→ owed to …\", and records from any email, thread or phone claimed on that page become evidence it may be done. Pass an empty string to clear it; clearing does not take the obligation off their page (use set_obligation_pages for that). Owner only.",
|
|
3484
|
+
inputSchema: {
|
|
3485
|
+
obligation_id: z.string().describe('from my_obligations'),
|
|
3486
|
+
owed_to: z.string().describe("the person's page `ref:` as read_page prints it, or \"\" to clear"),
|
|
3487
|
+
},
|
|
3488
|
+
},
|
|
3489
|
+
async ({ obligation_id, owed_to }) => {
|
|
3490
|
+
let res
|
|
3491
|
+
try {
|
|
3492
|
+
res = await fetchCortex(`${BASE}/api/obligations/owed-to`, {
|
|
3493
|
+
method: 'POST',
|
|
3494
|
+
headers: { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json' },
|
|
3495
|
+
body: JSON.stringify({ obligationId: obligation_id, owedTo: owed_to }),
|
|
3496
|
+
})
|
|
3497
|
+
} catch (e) { return toolError(`Could not reach obligations: ${e.message}`) }
|
|
3498
|
+
const out = await res.json().catch(() => null)
|
|
3499
|
+
if (!res.ok) return toolError(`Could not set it: ${out?.detail ?? out?.error ?? res.status}`)
|
|
3500
|
+
const t = out?.owedTo?.title
|
|
3501
|
+
return { content: [{ type: 'text', text: t ? `Owed to “${String(t).replace(/\s+/g, ' ').trim().slice(0, 60)}” — their page is attached.` : 'No longer marked as owed to anyone. Its pages are unchanged.' }] }
|
|
3502
|
+
},
|
|
3503
|
+
)
|
|
3504
|
+
|
|
3449
3505
|
server.registerTool(
|
|
3450
3506
|
'propose_obligation',
|
|
3451
3507
|
{
|
package/package.json
CHANGED