@theronap/agnoclast-mcp 0.9.190 → 0.9.191

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.
@@ -39,6 +39,48 @@ function pruneSnapshots(dir, keep = SNAPSHOT_RETENTION) {
39
39
  } catch { /* ignore — never break session start */ }
40
40
  }
41
41
 
42
+ /**
43
+ * PURE. The blocks of the startup context a person has to ACT on — every `## ` block except the two
44
+ * static orientation ones — joined with a blank line between them. '' when there are none.
45
+ *
46
+ * WHY THIS IS PRINTED, NOT JUST SAVED (2026-09-30). `snapshot-context` fetched /api/mcp-context and
47
+ * wrote it to a file, printing only "logged startup context". That file is where the steward queue,
48
+ * "Pages handed to you", the successor nudge, file requests, re-tier notices and "records waiting for
49
+ * a home" live — and nothing on a managed seat ever read it back to the model: `hydrate` and the
50
+ * context skill use /api/session-context, which carries none of those blocks. One machine saw them,
51
+ * through a hand-written local script. Every other seat was told nothing at session start, which made
52
+ * "the steward is asked at every session start" true for exactly one person.
53
+ *
54
+ * Printed from THIS run's response, so there is no ordering to get wrong: the local script it
55
+ * replaces read latest.md from a parallel hook and showed the PREVIOUS session's blocks.
56
+ *
57
+ * Skips by distinctive ASCII substring, not the full heading: the pointer block's heading opens with
58
+ * a multibyte character, and a block added later surfaces here with no edit — the failure this
59
+ * inversion was made to end was a hook that named the two blocks it wanted and dropped the rest.
60
+ */
61
+ export const SKIPPED_BLOCK_MARKERS = ['Your place in the org', 'This is a POINTER']
62
+
63
+ export function actionableBlocks(context) {
64
+ if (typeof context !== 'string' || !context) return ''
65
+ const blocks = []
66
+ let cur = null
67
+ for (const line of context.split('\n')) {
68
+ if (line.startsWith('## ')) {
69
+ if (cur) blocks.push(cur)
70
+ cur = { skip: SKIPPED_BLOCK_MARKERS.some((m) => line.includes(m)), lines: [line] }
71
+ } else if (cur) {
72
+ cur.lines.push(line)
73
+ }
74
+ // lines before the first "## " are the title and the clock: orientation, not action
75
+ }
76
+ if (cur) blocks.push(cur)
77
+ return blocks
78
+ .filter((b) => !b.skip)
79
+ .map((b) => b.lines.join('\n').replace(/\s+$/, ''))
80
+ .filter(Boolean)
81
+ .join('\n\n')
82
+ }
83
+
42
84
  export async function runSnapshotContext() {
43
85
  const out = (m) => process.stdout.write(m + '\n')
44
86
  const token = resolveToken()
@@ -92,6 +134,11 @@ export async function runSnapshotContext() {
92
134
 
93
135
  pruneSnapshots(dir)
94
136
 
137
+ // The action blocks go to STDOUT, which a SessionStart hook injects into the session. Before the
138
+ // "logged" line so a truncated preview shows what needs doing rather than a file path.
139
+ const blocks = actionableBlocks(context)
140
+ if (blocks) out(blocks + '\n')
141
+
95
142
  out(`Agnoclast: logged startup context → ${file}`)
96
143
  return 0
97
144
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theronap/agnoclast-mcp",
3
- "version": "0.9.190",
3
+ "version": "0.9.191",
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": {