@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 +10 -2
- package/bin/cortex-mcp.mjs +8 -1
- package/lib/context_log.mjs +80 -0
- package/lib/setup.mjs +8 -0
- package/package.json +1 -1
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,
|
|
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 |
|
package/bin/cortex-mcp.mjs
CHANGED
|
@@ -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.
|
|
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)' : ''}`)
|