@theronap/cortex-mcp 0.9.2 → 0.9.4

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/README.md CHANGED
@@ -19,8 +19,9 @@ Connect your AI assistant to **Cortex** — your org's projects, recent activity
19
19
  }
20
20
  ```
21
21
 
22
- 3. Restart Claude Code. Your AI now sees your org context automatically, and the managed startup skill
23
- will prefer query-centered `session_context` on substantive session opens.
22
+ 3. Restart Claude Code. Your AI now sees your org context automatically, the managed startup skill
23
+ will prefer query-centered `session_context` on substantive session opens, and each session start
24
+ will log the exact baseline Cortex context to `~/.cortex/context-snapshots/`.
24
25
 
25
26
  No clone, no path, no build step — `npx` fetches and runs it.
26
27
 
@@ -31,6 +32,13 @@ No clone, no path, no build step — `npx` fetches and runs it.
31
32
  - **search_org** — search your visible activity and projects by keyword.
32
33
  - **project_status** — status of a specific project by key.
33
34
 
35
+ ## Startup snapshots
36
+
37
+ Every Claude session start runs `snapshot-context`, which fetches the exact `my_context` payload and writes:
38
+ - `~/.cortex/context-snapshots/latest.md`
39
+ - `~/.cortex/context-snapshots/<timestamp>.md`
40
+ - `~/.cortex/context-snapshots/index.jsonl`
41
+
34
42
  ## Environment
35
43
 
36
44
  | Var | Required | Default |
@@ -7,6 +7,7 @@
7
7
  * setup <TOKEN> wire BOTH the MCP server + capture hook into your Claude config
8
8
  * doctor live health check — is the token actually working? (no restart needed)
9
9
  * capture the Stop-hook capturer (invoked by Claude Code, not by hand)
10
+ * snapshot-context save the exact startup context served by Cortex to a local log file
10
11
  * --version | -v
11
12
  * --help | -h
12
13
  *
@@ -16,7 +17,7 @@
16
17
  * Get your token from the Cortex console → Connect your AI.
17
18
  */
18
19
 
19
- const VERSION = '0.9.1'
20
+ const VERSION = '0.9.4'
20
21
  const cmd = process.argv[2]
21
22
  const rest = process.argv.slice(3)
22
23
 
@@ -37,6 +38,7 @@ if (cmd === '--help' || cmd === '-h' || cmd === 'help') {
37
38
  ` doctor live health check — confirm your token works (no restart needed)\n` +
38
39
  ` status one-line connected/not-connected check (used by the SessionStart hook)\n` +
39
40
  ` skills install/repair the managed Cortex skills (also wired by setup)\n` +
41
+ ` snapshot-context save the exact startup context Cortex served to a local snapshot\n` +
40
42
  ` capture Stop-hook capturer (invoked by Claude Code)\n` +
41
43
  ` (no args) run the MCP server (used by your Claude config)\n\n` +
42
44
  `Get your token from the Cortex console → Connect your AI.\n`,
@@ -72,6 +74,11 @@ if (cmd === 'setup') {
72
74
  await runCapture()
73
75
  const { closeFetch } = await import('../lib/diagnose.mjs')
74
76
  await closeFetch()
77
+ } else if (cmd === 'snapshot-context') {
78
+ const { runSnapshotContext } = await import('../lib/context_log.mjs')
79
+ process.exitCode = await runSnapshotContext()
80
+ const { closeFetch } = await import('../lib/diagnose.mjs')
81
+ await closeFetch()
75
82
  } else if (cmd === 'skills') {
76
83
  // Install / repair the managed Cortex skills repository. No network — exits naturally.
77
84
  const { runSkills } = await import('../lib/skills.mjs')
@@ -0,0 +1,80 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs'
2
+ import { homedir } from 'os'
3
+ import { join } from 'path'
4
+ import { fetchCortex, classify, resolveBase } from './diagnose.mjs'
5
+
6
+ function resolveToken() {
7
+ if (process.env.CORTEX_TOKEN) return process.env.CORTEX_TOKEN
8
+ const claudeJson = join(homedir(), '.claude.json')
9
+ if (!existsSync(claudeJson)) return null
10
+ try {
11
+ const cfg = JSON.parse(readFileSync(claudeJson, 'utf8'))
12
+ return cfg?.mcpServers?.cortex?.env?.CORTEX_TOKEN ?? null
13
+ } catch {
14
+ return null
15
+ }
16
+ }
17
+
18
+ function ensureDir(path) {
19
+ if (!existsSync(path)) mkdirSync(path, { recursive: true })
20
+ }
21
+
22
+ function stamp(now = new Date()) {
23
+ const pad = (n) => String(n).padStart(2, '0')
24
+ return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}T${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`
25
+ }
26
+
27
+ function snapshotDir() {
28
+ return join(homedir(), '.cortex', 'context-snapshots')
29
+ }
30
+
31
+ export async function runSnapshotContext() {
32
+ const out = (m) => process.stdout.write(m + '\n')
33
+ const token = resolveToken()
34
+ if (!token) {
35
+ out('Cortex: context snapshot skipped — no token found.')
36
+ return 0
37
+ }
38
+
39
+ const base = resolveBase(process.env.CORTEX_URL)
40
+ let res
41
+ try {
42
+ res = await fetchCortex(`${base}/api/mcp-context`, { headers: { Authorization: `Bearer ${token}` } })
43
+ } catch (e) {
44
+ out(`Cortex: context snapshot failed — ${e?.message ?? String(e)}`)
45
+ return 0
46
+ }
47
+
48
+ if (!res.ok) {
49
+ const body = await res.text()
50
+ out(`Cortex: context snapshot failed — ${classify(res.status, res.headers.get('content-type'), body, res.headers.get('x-vercel-id')).message}`)
51
+ return 0
52
+ }
53
+
54
+ const payload = await res.json().catch(() => ({}))
55
+ const context = typeof payload?.context === 'string' ? payload.context : ''
56
+ const dir = snapshotDir()
57
+ ensureDir(dir)
58
+
59
+ const capturedAt = new Date().toISOString()
60
+ const file = join(dir, `${stamp()}.md`)
61
+ const header = [
62
+ '# Cortex startup context snapshot',
63
+ `- Captured: ${capturedAt}`,
64
+ `- Source: ${base}/api/mcp-context`,
65
+ '',
66
+ ].join('\n')
67
+ const text = `${header}${context}\n`
68
+
69
+ writeFileSync(file, text)
70
+ writeFileSync(join(dir, 'latest.md'), text)
71
+ writeFileSync(join(dir, 'index.jsonl'), JSON.stringify({
72
+ captured_at: capturedAt,
73
+ file,
74
+ base,
75
+ chars: context.length,
76
+ }) + '\n', { flag: 'a' })
77
+
78
+ out(`Cortex: logged startup context → ${file}`)
79
+ return 0
80
+ }
package/lib/setup.mjs CHANGED
@@ -170,6 +170,14 @@ export async function runSetup(argv, version) {
170
170
  }
171
171
  sgrp.hooks.push({ type: 'command', command: skillsCmd })
172
172
 
173
+ const snapshotCmd = `npx -y ${spec} snapshot-context`
174
+ for (const sg of s.hooks.SessionStart) {
175
+ if (Array.isArray(sg.hooks)) {
176
+ sg.hooks = sg.hooks.filter((h) => !/cortex-mcp(@[^ ]*)? snapshot-context/.test(h.command ?? ''))
177
+ }
178
+ }
179
+ sgrp.hooks.push({ type: 'command', command: snapshotCmd })
180
+
173
181
  ensureDir(settingsJson)
174
182
  writeFileSync(settingsJson, JSON.stringify(s, null, 2))
175
183
  log(` ✓ Capture hook + status line → ${settingsJson}${bak ? ' (backup saved)' : ''}`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theronap/cortex-mcp",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
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": {