@theronap/agnoclast-mcp 0.9.237 → 0.9.239
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/arrivals_notice.mjs +17 -0
- package/lib/server.mjs +48 -0
- package/package.json +1 -1
package/lib/arrivals_notice.mjs
CHANGED
|
@@ -59,6 +59,8 @@ import { fetchCortex, resolveBase, resolveTokenSource } from './diagnose.mjs'
|
|
|
59
59
|
// Enough to hold a session's own recent output in full; small enough that the notice is READ rather
|
|
60
60
|
// than spilled to a file, which is what happened at 49 KB.
|
|
61
61
|
const MAX_YOURS = 25
|
|
62
|
+
/** Assigned groups listed per prompt; the server hands out at most 5 new groups per prompt anyway. */
|
|
63
|
+
const MAX_ASSIGNED = 8
|
|
62
64
|
|
|
63
65
|
// A title is somebody else's text — anyone can send a calendar invite — and this prints into a
|
|
64
66
|
// session's context. One line, bounded, and quoted so it reads as the name of a thing.
|
|
@@ -176,6 +178,21 @@ export function formatNotice(signals) {
|
|
|
176
178
|
const total = Number(signals?.settling?.total ?? offers.length)
|
|
177
179
|
const delta = Number(signals?.arrival?.count ?? 0)
|
|
178
180
|
|
|
181
|
+
// ⭐ ADR-0083 §2.3 — arrivals ASSIGNED to this session. Not an offer: this session is their one owner, and
|
|
182
|
+
// it is told at a prompt boundary so it handles them before the user's request. A conversation stays with
|
|
183
|
+
// this session for its lifetime, so its later texts come here too.
|
|
184
|
+
const assigned = Array.isArray(signals?.assigned) ? signals.assigned : []
|
|
185
|
+
if (assigned.length) {
|
|
186
|
+
const n = assigned.reduce((t, g) => t + (Number(g?.count) || 1), 0)
|
|
187
|
+
lines.push(`📥 ${n} arrival${n === 1 ? ' is' : 's are'} ASSIGNED TO THIS SESSION — you are ${n === 1 ? 'its' : 'their'} only owner. Handle ${n === 1 ? 'it' : 'them'} before the user's request, then answer the user:`)
|
|
188
|
+
for (const g of assigned.slice(0, MAX_ASSIGNED)) {
|
|
189
|
+
const many = Number(g?.count) > 1 ? ` ×${g.count}` : ''
|
|
190
|
+
const ids = (g?.ids ?? []).slice(0, 3).join(', ') + ((g?.ids ?? []).length > 3 ? ', …' : '')
|
|
191
|
+
lines.push(` ${g?.source ?? '?'}${many} — ${g?.title ?? '(unreadable)'} · ${g?.hoursAgo ?? '?'}h · ids: ${ids}`)
|
|
192
|
+
}
|
|
193
|
+
if (assigned.length > MAX_ASSIGNED) lines.push(` … and ${assigned.length - MAX_ASSIGNED} more groups`)
|
|
194
|
+
lines.push(' `intake_claim {intakeItemIds}` → `intake_materialize` (or `intake_discard` for junk) · `not_mine` hands one to the next session · only what only the user can decide → `intake_defer`.')
|
|
195
|
+
}
|
|
179
196
|
if (delta) {
|
|
180
197
|
lines.push(`⚡ ${delta} new arrival${delta === 1 ? '' : 's'} in the pile since this session was last told.`)
|
|
181
198
|
}
|
package/lib/server.mjs
CHANGED
|
@@ -4797,6 +4797,54 @@ function renderNudge(payload) {
|
|
|
4797
4797
|
},
|
|
4798
4798
|
)
|
|
4799
4799
|
|
|
4800
|
+
// share_record — a share link for one of your own transcripts (Theron, 2026-10-17; obligation e65b7a83).
|
|
4801
|
+
// Anyone with the link gets their OWN copy (an unfiled record in their brain) or, without an account, a
|
|
4802
|
+
// preview and a way to join. Never grants access to the original; never for a confidential record. NOT in
|
|
4803
|
+
// the auto-allowed list (editors/claude.mjs): handing content to someone outside the brain is a disclosure,
|
|
4804
|
+
// so it prompts.
|
|
4805
|
+
server.registerTool(
|
|
4806
|
+
'share_record',
|
|
4807
|
+
{
|
|
4808
|
+
title: 'Make a share link for a transcript',
|
|
4809
|
+
description:
|
|
4810
|
+
'Make a link (agnoclast.com/s/…) that shares one of YOUR OWN meeting or lecture transcripts with anyone, ' +
|
|
4811
|
+
'including people outside Agnoclast. Whoever opens it signed in gets their own copy as an unfiled record; ' +
|
|
4812
|
+
'someone without an account sees a preview and can join free. It never gives access to the original record. ' +
|
|
4813
|
+
'scope "full" (default) shares the transcript and its notes; "notes" shares only the notes. Confidential ' +
|
|
4814
|
+
'records cannot be shared. The link is shown ONCE — give it to the person straight away. Only when the person ' +
|
|
4815
|
+
'asks to share; never on your own initiative. Turn a link off from the record\'s page on agnoclast.com.',
|
|
4816
|
+
inputSchema: {
|
|
4817
|
+
record_id: z.string().describe('the transcript record id (uuid)'),
|
|
4818
|
+
scope: z.enum(['full', 'notes']).optional().describe('full = transcript and notes (default); notes = notes only'),
|
|
4819
|
+
expires_in_days: z.number().int().min(1).max(365).optional().describe('how long the link works; default 30'),
|
|
4820
|
+
},
|
|
4821
|
+
},
|
|
4822
|
+
async ({ record_id, scope, expires_in_days }) => {
|
|
4823
|
+
let res
|
|
4824
|
+
try {
|
|
4825
|
+
res = await fetchCortex(`${BASE}/api/records/${encodeURIComponent(record_id)}/share`, {
|
|
4826
|
+
method: 'POST',
|
|
4827
|
+
headers: { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json' },
|
|
4828
|
+
body: JSON.stringify({ scope: scope ?? 'full', ...(expires_in_days ? { expiresInDays: expires_in_days } : {}) }),
|
|
4829
|
+
})
|
|
4830
|
+
} catch (e) {
|
|
4831
|
+
return toolError(`Could not make a share link: ${e.message}`)
|
|
4832
|
+
}
|
|
4833
|
+
if (res.status === 404 || res.status === 409) {
|
|
4834
|
+
const b = await res.json().catch(() => null)
|
|
4835
|
+
return toolError(`Not shared: ${b?.detail ?? b?.error ?? 'refused'}`)
|
|
4836
|
+
}
|
|
4837
|
+
if (!res.ok) {
|
|
4838
|
+
const d = classify(res.status, res.headers.get('content-type'), await res.text(), res.headers.get('x-vercel-id'))
|
|
4839
|
+
return toolError(`Could not make a share link: ${d.message}`)
|
|
4840
|
+
}
|
|
4841
|
+
const out = await res.json()
|
|
4842
|
+
return { content: [{ type: 'text', text:
|
|
4843
|
+
`Share link for "${out.title}" (${out.scope === 'notes' ? 'notes only' : 'full transcript and notes'}), works until ${out.expiresAt.slice(0, 10)}:\n${out.url}\n` +
|
|
4844
|
+
`This link is shown only once. Anyone who opens it gets their own copy; it never opens the original. share id: ${out.shareId}` }] }
|
|
4845
|
+
},
|
|
4846
|
+
)
|
|
4847
|
+
|
|
4800
4848
|
// set_record_notes — write the NOTES layer of one of your own transcripts (Theron, 2026-10-08: "two
|
|
4801
4849
|
// layers … a summary and notes from the transcript … the full transcript"). The server keeps the
|
|
4802
4850
|
// before-state in record history and refuses anything that is not your own kept transcript.
|
package/package.json
CHANGED