@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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theronap/agnoclast-mcp",
3
- "version": "0.9.237",
3
+ "version": "0.9.239",
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": {