sessionmem 1.0.5 → 1.1.0
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/LICENSE +21 -21
- package/README.md +372 -365
- package/dist/adapters/capabilities/fallbackTools.js +33 -18
- package/dist/adapters/claudeMdInjector.js +164 -0
- package/dist/adapters/factory.js +68 -9
- package/dist/adapters/generic.js +221 -15
- package/dist/adapters/global/antigravity.js +14 -7
- package/dist/adapters/global/claudeCode.js +46 -10
- package/dist/adapters/global/codex.js +73 -13
- package/dist/adapters/global/qcoder.js +18 -5
- package/dist/adapters/ide/cline.js +54 -9
- package/dist/adapters/ide/cursor.js +15 -13
- package/dist/adapters/ide/installer.js +201 -8
- package/dist/adapters/ide/windsurf.js +14 -13
- package/dist/adapters/tools/ping.js +4 -1
- package/dist/cli/commands/config.js +10 -1
- package/dist/cli/commands/import.js +6 -1
- package/dist/cli/commands/install.js +63 -5
- package/dist/cli/commands/ping.js +42 -8
- package/dist/cli/commands/reEmbed.js +48 -0
- package/dist/cli/commands/run.js +18 -2
- package/dist/cli/commands/savings.js +91 -0
- package/dist/cli/commands/sessionEnd.js +124 -0
- package/dist/cli/commands/sessionStart.js +52 -0
- package/dist/cli/commands/sync.js +39 -9
- package/dist/cli/commands/uninstall.js +37 -1
- package/dist/cli/context.js +14 -18
- package/dist/cli/index.js +30 -4
- package/dist/cli/output.js +11 -3
- package/dist/cli/projectId.js +69 -0
- package/dist/core/api/contracts.js +182 -45
- package/dist/core/api/errors.js +4 -7
- package/dist/core/api/memoryCoreService.js +409 -240
- package/dist/core/api/sessionLifecycleService.js +20 -2
- package/dist/core/config/policyConfig.js +53 -6
- package/dist/core/injection/formatStartupInjection.js +55 -10
- package/dist/core/injection/tokenBudget.js +8 -0
- package/dist/core/retrieve/importance.js +4 -3
- package/dist/core/retrieve/recencyBands.js +6 -10
- package/dist/core/retrieve/retrieveMemories.js +19 -4
- package/dist/core/retrieve/score.js +11 -1
- package/dist/core/schema/migrations/005_team_provenance.sql +14 -9
- package/dist/core/schema/migrations/006_access_pattern_boosting.sql +10 -0
- package/dist/core/schema/migrations/007_feedback_manual_delete.sql +23 -0
- package/dist/core/schema/migrations/008_fts5_search.sql +37 -0
- package/dist/core/schema/migrations/009_session_events_unique.sql +24 -0
- package/dist/core/schema/runMigrations.js +64 -2
- package/dist/core/storage/db.js +6 -0
- package/dist/core/storage/memoryFeedbackRepo.js +14 -4
- package/dist/core/storage/memoryRepo.js +292 -121
- package/dist/core/storage/memorySearchRepo.js +125 -13
- package/dist/core/storage/sessionEventsRepo.js +33 -10
- package/dist/core/storage/summarizationFailuresRepo.js +36 -26
- package/dist/core/storage/tokenSavingsRepo.js +20 -0
- package/dist/core/summarize/cloudSummarizer.js +34 -5
- package/dist/core/summarize/localSummarizer.js +1 -10
- package/dist/core/summarize/redaction.js +45 -8
- package/package.json +50 -48
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export function insertSummarizationFailure(db, input) {
|
|
9
|
-
const stmt = db.prepare(`
|
|
1
|
+
const sumFailStmtCache = new WeakMap();
|
|
2
|
+
function getSumFailStatements(db) {
|
|
3
|
+
let stmts = sumFailStmtCache.get(db);
|
|
4
|
+
if (stmts)
|
|
5
|
+
return stmts;
|
|
6
|
+
stmts = {
|
|
7
|
+
insertFailure: db.prepare(`
|
|
10
8
|
INSERT INTO summarization_failures (
|
|
11
9
|
id, project_id, session_id, source_adapter, reason, attempt_count, last_error_json, created_at, updated_at
|
|
12
10
|
) VALUES (
|
|
@@ -14,26 +12,38 @@ export function insertSummarizationFailure(db, input) {
|
|
|
14
12
|
COALESCE(@created_at, strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
15
13
|
COALESCE(@updated_at, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
16
14
|
)
|
|
17
|
-
`)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
WHERE project_id = ? AND session_id = ?
|
|
27
|
-
ORDER BY updated_at DESC
|
|
28
|
-
`);
|
|
29
|
-
return stmt.all(projectId, sessionId);
|
|
30
|
-
}
|
|
31
|
-
const stmt = db.prepare(`
|
|
15
|
+
`),
|
|
16
|
+
listByProjectAndSession: db.prepare(`
|
|
17
|
+
SELECT
|
|
18
|
+
id, project_id, session_id, source_adapter, reason, attempt_count, last_error_json, created_at, updated_at
|
|
19
|
+
FROM summarization_failures
|
|
20
|
+
WHERE project_id = ? AND session_id = ?
|
|
21
|
+
ORDER BY updated_at DESC
|
|
22
|
+
`),
|
|
23
|
+
listByProject: db.prepare(`
|
|
32
24
|
SELECT
|
|
33
25
|
id, project_id, session_id, source_adapter, reason, attempt_count, last_error_json, created_at, updated_at
|
|
34
26
|
FROM summarization_failures
|
|
35
27
|
WHERE project_id = ?
|
|
36
28
|
ORDER BY updated_at DESC
|
|
37
|
-
`)
|
|
38
|
-
|
|
29
|
+
`),
|
|
30
|
+
};
|
|
31
|
+
sumFailStmtCache.set(db, stmts);
|
|
32
|
+
return stmts;
|
|
33
|
+
}
|
|
34
|
+
function toParams(input) {
|
|
35
|
+
return {
|
|
36
|
+
...input,
|
|
37
|
+
created_at: input.created_at ?? null,
|
|
38
|
+
updated_at: input.updated_at ?? null,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function insertSummarizationFailure(db, input) {
|
|
42
|
+
getSumFailStatements(db).insertFailure.run(toParams(input));
|
|
43
|
+
}
|
|
44
|
+
export function listSummarizationFailures(db, projectId, sessionId) {
|
|
45
|
+
if (sessionId) {
|
|
46
|
+
return getSumFailStatements(db).listByProjectAndSession.all(projectId, sessionId);
|
|
47
|
+
}
|
|
48
|
+
return getSumFailStatements(db).listByProject.all(projectId);
|
|
39
49
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const tokenSavingsStmtCache = new WeakMap();
|
|
2
|
+
function getTokenSavingsStatements(db) {
|
|
3
|
+
let stmts = tokenSavingsStmtCache.get(db);
|
|
4
|
+
if (stmts)
|
|
5
|
+
return stmts;
|
|
6
|
+
stmts = {
|
|
7
|
+
countDistinctSessions: db.prepare("SELECT COUNT(DISTINCT session_id) AS count FROM session_events WHERE project_id = ?"),
|
|
8
|
+
listPayloads: db.prepare("SELECT payload_json FROM session_events WHERE project_id = ?"),
|
|
9
|
+
};
|
|
10
|
+
tokenSavingsStmtCache.set(db, stmts);
|
|
11
|
+
return stmts;
|
|
12
|
+
}
|
|
13
|
+
export function countDistinctSessions(db, projectId) {
|
|
14
|
+
const row = getTokenSavingsStatements(db).countDistinctSessions.get(projectId);
|
|
15
|
+
return row.count;
|
|
16
|
+
}
|
|
17
|
+
export function listEventPayloads(db, projectId) {
|
|
18
|
+
const rows = getTokenSavingsStatements(db).listPayloads.all(projectId);
|
|
19
|
+
return rows.map(r => r.payload_json);
|
|
20
|
+
}
|
|
@@ -1,19 +1,48 @@
|
|
|
1
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
1
2
|
import { summarizeLocalSessionEvents } from "./localSummarizer.js";
|
|
2
|
-
|
|
3
|
+
import { DEFAULT_SUMMARIZER_MODEL } from "../config/policyConfig.js";
|
|
4
|
+
const CLOUD_SYSTEM_PROMPT = "You are a memory compressor for AI coding sessions. Given this session transcript summary, produce a compact, high-signal list of facts, decisions, and context that should be remembered. Be extremely concise.";
|
|
3
5
|
export async function summarizeWithCloud(input) {
|
|
4
6
|
if (!input.anthropicApiKey.trim()) {
|
|
5
7
|
throw new Error("Missing anthropicApiKey");
|
|
6
8
|
}
|
|
7
|
-
|
|
9
|
+
// Step 1: Preprocess via local summarizer (extract, redact, structure)
|
|
10
|
+
const localResult = await summarizeLocalSessionEvents({
|
|
8
11
|
events: input.events,
|
|
9
12
|
summaryTokenCap: input.summaryTokenCap,
|
|
10
13
|
redactionEnabled: input.redactionEnabled,
|
|
11
14
|
factMode: input.factMode,
|
|
12
15
|
redactionRules: input.redactionRules,
|
|
13
16
|
});
|
|
14
|
-
|
|
17
|
+
// Step 2: Send preprocessed summary to Claude for compression
|
|
18
|
+
const model = input.model ?? DEFAULT_SUMMARIZER_MODEL;
|
|
19
|
+
const client = new Anthropic({ apiKey: input.anthropicApiKey });
|
|
20
|
+
const response = await client.messages.create({
|
|
21
|
+
model,
|
|
22
|
+
// Cap the per-response token budget so a large summaryTokenCap cannot pass
|
|
23
|
+
// an out-of-range max_tokens to the API (which would error).
|
|
24
|
+
max_tokens: Math.min(Math.floor((input.summaryTokenCap ?? 4000) * 1.5), 8192),
|
|
25
|
+
system: CLOUD_SYSTEM_PROMPT,
|
|
26
|
+
messages: [{ role: "user", content: localResult.summary }],
|
|
27
|
+
});
|
|
28
|
+
// Extract text from response content blocks
|
|
29
|
+
let text = response.content
|
|
30
|
+
.filter((block) => block.type === "text")
|
|
31
|
+
.map((block) => block.text)
|
|
32
|
+
.join("\n");
|
|
33
|
+
// Throw on an empty response rather than storing an empty memory; the
|
|
34
|
+
// session-lifecycle retry/fallback-to-local path handles the failure.
|
|
35
|
+
if (!text || text.trim().length === 0) {
|
|
36
|
+
throw new Error("Cloud summarizer returned empty response");
|
|
37
|
+
}
|
|
38
|
+
// Cap cloud output to summaryTokenCap (rough token→char ratio) for parity
|
|
39
|
+
// with the local summarizer, so a verbose cloud response cannot blow past the
|
|
40
|
+
// configured budget.
|
|
41
|
+
if (input.summaryTokenCap && text.length > input.summaryTokenCap * 4) {
|
|
42
|
+
text = text.slice(0, input.summaryTokenCap * 4);
|
|
43
|
+
}
|
|
15
44
|
return {
|
|
16
|
-
summary:
|
|
17
|
-
warningCodes:
|
|
45
|
+
summary: text,
|
|
46
|
+
warningCodes: localResult.warningCodes,
|
|
18
47
|
};
|
|
19
48
|
}
|
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
import { normalizeEmbeddingText } from "../embed/textNormalize.js";
|
|
2
|
+
import { capTokens, countTokens } from "../injection/tokenBudget.js";
|
|
2
3
|
import { applyRedaction } from "./redaction.js";
|
|
3
4
|
import { buildStructuredSummary } from "./summaryShape.js";
|
|
4
|
-
function countTokens(text) {
|
|
5
|
-
return text.trim().split(/\s+/).filter(Boolean).length;
|
|
6
|
-
}
|
|
7
|
-
function capTokens(text, cap) {
|
|
8
|
-
const tokens = text.trim().split(/\s+/).filter(Boolean);
|
|
9
|
-
if (tokens.length <= cap) {
|
|
10
|
-
return text;
|
|
11
|
-
}
|
|
12
|
-
return `${tokens.slice(0, cap).join(" ")} ...`;
|
|
13
|
-
}
|
|
14
5
|
export async function summarizeLocalSessionEvents(input) {
|
|
15
6
|
const structured = buildStructuredSummary(input.events, {
|
|
16
7
|
factMode: input.factMode,
|
|
@@ -3,8 +3,20 @@
|
|
|
3
3
|
// a fragment of a larger secret and leave a partial body behind. All patterns are
|
|
4
4
|
// anchored with explicit literal prefixes/markers and use bounded quantifiers to
|
|
5
5
|
// avoid catastrophic backtracking (ReDoS).
|
|
6
|
-
|
|
6
|
+
//
|
|
7
|
+
// The rule set is allocated once at module load (not per call): the rules are
|
|
8
|
+
// pure, stateless closures, so hoisting avoids re-allocating 8 closures on every
|
|
9
|
+
// applyRedaction invocation — a measurable saving in batch/import/pull loops.
|
|
10
|
+
// The regex literals carry no `lastIndex` state because every pattern is used
|
|
11
|
+
// with String.prototype.replace (not stateful .test()/.exec() on a shared regex).
|
|
12
|
+
const DEFAULT_RULES = createDefaultRules();
|
|
13
|
+
function createDefaultRules() {
|
|
7
14
|
return [
|
|
15
|
+
// URL-embedded credentials: scheme://user:password@host. Run BEFORE the
|
|
16
|
+
// email rule so the `password@host` segment is collapsed here rather than
|
|
17
|
+
// partially matched as an email. Scheme + host are preserved; the
|
|
18
|
+
// user:password pair is redacted. Bounded quantifiers stay ReDoS-safe.
|
|
19
|
+
(input) => input.replace(/\b([a-z][a-z0-9+.-]{0,20}:\/\/)[^\s:/@]{1,256}:[^\s/@]{1,256}@/gi, "$1[REDACTED_CREDENTIALS]@"),
|
|
8
20
|
// Email (original rule — unchanged).
|
|
9
21
|
(input) => input.replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, "[REDACTED_EMAIL]"),
|
|
10
22
|
// PEM private key block: ----BEGIN <type> PRIVATE KEY---- ... ----END ... ----.
|
|
@@ -14,14 +26,39 @@ function defaultRules() {
|
|
|
14
26
|
(input) => input.replace(/\beyJ[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}\b/g, "[REDACTED_JWT]"),
|
|
15
27
|
// AWS access key id: AKIA + 16 uppercase alphanumerics.
|
|
16
28
|
(input) => input.replace(/\bAKIA[A-Z0-9]{16}\b/g, "[REDACTED_AWS_KEY]"),
|
|
17
|
-
//
|
|
18
|
-
(input) => input.replace(/\
|
|
19
|
-
//
|
|
20
|
-
(
|
|
29
|
+
// AWS temporary credentials access key id: ASIA + 16 uppercase alphanumerics.
|
|
30
|
+
(input) => input.replace(/\bASIA[A-Z0-9]{16}\b/g, "[REDACTED_AWS_KEY]"),
|
|
31
|
+
// GitHub tokens: ghp_/gho_/ghu_/ghs_/ghr_ + 36 OR MORE alphanumerics
|
|
32
|
+
// (GitHub has lengthened tokens over time; `{36,}` future-proofs the rule).
|
|
33
|
+
(input) => input.replace(/\bgh[poushr]_[A-Za-z0-9]{36,}\b/g, "[REDACTED_GITHUB_TOKEN]"),
|
|
34
|
+
// GitHub fine-grained personal access tokens: github_pat_ + long body.
|
|
35
|
+
(input) => input.replace(/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, "[REDACTED_GITHUB_TOKEN]"),
|
|
36
|
+
// Slack tokens: xoxb-/xoxp-/xoxa-/xoxr-/xoxs-/xoxe-/xoxc-/xoxt- and the
|
|
37
|
+
// app-level xapp- prefix + dash-delimited segments.
|
|
38
|
+
(input) => input.replace(/\b(?:xox[baprsect]|xapp)-[A-Za-z0-9-]{10,256}\b/g, "[REDACTED_SLACK_TOKEN]"),
|
|
39
|
+
// Stripe live keys: secret (sk_live_), restricted (rk_live_), and
|
|
40
|
+
// publishable (pk_live_) + 24 or more alphanumerics.
|
|
41
|
+
(input) => input.replace(/\b[srp]k_live_[A-Za-z0-9]{24,}\b/g, "[REDACTED_STRIPE_KEY]"),
|
|
42
|
+
// npm access tokens: npm_ + 36 alphanumerics.
|
|
43
|
+
(input) => input.replace(/\bnpm_[A-Za-z0-9]{36}\b/g, "[REDACTED_NPM_TOKEN]"),
|
|
44
|
+
// Google API keys: AIza + 35 url-safe chars (39 total).
|
|
45
|
+
(input) => input.replace(/\bAIza[0-9A-Za-z_-]{35}\b/g, "[REDACTED_GOOGLE_API_KEY]"),
|
|
46
|
+
// OpenAI-style API key. Allow an optional internal dash segment so
|
|
47
|
+
// project-scoped keys (sk-proj-...) are fully redacted rather than leaving
|
|
48
|
+
// the project segment behind. Bounded quantifiers stay ReDoS-safe.
|
|
49
|
+
(input) => input.replace(/\bsk-(?:[a-zA-Z0-9]{1,32}-){0,4}[a-zA-Z0-9]{12,200}\b/g, "[REDACTED_API_KEY]"),
|
|
21
50
|
// Bearer token header value: "Bearer <token>" (case-insensitive), token redacted.
|
|
22
51
|
(input) => input.replace(/\bBearer\s+[A-Za-z0-9._~+/-]{8,}=*/gi, "Bearer [REDACTED_BEARER_TOKEN]"),
|
|
23
|
-
//
|
|
24
|
-
|
|
52
|
+
// Config/connection-string assignments: key=value where key is a known
|
|
53
|
+
// secret-bearing name. The key is kept and the value redacted. Covers
|
|
54
|
+
// password/secret plus api_key/apikey/token/access_token/pwd in URL query
|
|
55
|
+
// strings and config files. The `=` separator may carry surrounding spaces.
|
|
56
|
+
(input) => input.replace(/\b(password|passwd|pwd|secret|api[_-]?key|access[_-]?token|token)\s*=\s*([^\s"'&;]+)/gi, "$1=[REDACTED]"),
|
|
57
|
+
// JSON-form secret assignments: "key": "value" for known secret-bearing
|
|
58
|
+
// keys. Complements the key=value rule above so secrets embedded in JSON
|
|
59
|
+
// payloads (config files, logged request bodies) are redacted too. The key
|
|
60
|
+
// is preserved; the quoted value is collapsed.
|
|
61
|
+
(input) => input.replace(/"(password|secret|api_key|token|access_token|auth_token|client_secret|private_key|pwd|passwd)"\s*:\s*"[^"]{4,}"/gi, '"$1": "[REDACTED]"'),
|
|
25
62
|
];
|
|
26
63
|
}
|
|
27
64
|
export function applyRedaction(input, options) {
|
|
@@ -33,7 +70,7 @@ export function applyRedaction(input, options) {
|
|
|
33
70
|
}
|
|
34
71
|
let text = input;
|
|
35
72
|
const warningCodes = [];
|
|
36
|
-
for (const rule of options.rules ??
|
|
73
|
+
for (const rule of options.rules ?? DEFAULT_RULES) {
|
|
37
74
|
try {
|
|
38
75
|
text = rule(text);
|
|
39
76
|
}
|
package/package.json
CHANGED
|
@@ -1,48 +1,50 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "sessionmem",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"private": false,
|
|
5
|
-
"type": "module",
|
|
6
|
-
"description": "Local-first MCP memory layer for coding agents across Claude Code, Codex, Cursor, Cline, Windsurf, and other MCP-compatible hosts.",
|
|
7
|
-
"license": "MIT",
|
|
8
|
-
"author": "kavishdua",
|
|
9
|
-
"repository": {
|
|
10
|
-
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/catfish-1234/sessionmem.git"
|
|
12
|
-
},
|
|
13
|
-
"mcpName": "io.github.catfish-1234/sessionmem",
|
|
14
|
-
"files": [
|
|
15
|
-
"dist"
|
|
16
|
-
],
|
|
17
|
-
"publishConfig": {
|
|
18
|
-
"access": "public"
|
|
19
|
-
},
|
|
20
|
-
"bin": {
|
|
21
|
-
"sessionmem": "./dist/cli/index.js"
|
|
22
|
-
},
|
|
23
|
-
"scripts": {
|
|
24
|
-
"build": "tsc && node scripts/copy-migrations.mjs",
|
|
25
|
-
"prepack": "npm run build",
|
|
26
|
-
"test": "vitest run --reporter=dot",
|
|
27
|
-
"test:schema": "vitest run tests/integration/storage/schema.spec.ts --reporter=dot",
|
|
28
|
-
"lint": "eslint .",
|
|
29
|
-
"typecheck": "tsc --noEmit",
|
|
30
|
-
"benchmark": "node scripts/benchmark.mjs"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"eslint": "^10.
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "sessionmem",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Local-first MCP memory layer for coding agents across Claude Code, Codex, Cursor, Cline, Windsurf, and other MCP-compatible hosts.",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"author": "kavishdua",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/catfish-1234/sessionmem.git"
|
|
12
|
+
},
|
|
13
|
+
"mcpName": "io.github.catfish-1234/sessionmem",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"bin": {
|
|
21
|
+
"sessionmem": "./dist/cli/index.js"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc && node scripts/copy-migrations.mjs",
|
|
25
|
+
"prepack": "npm run build",
|
|
26
|
+
"test": "vitest run --reporter=dot",
|
|
27
|
+
"test:schema": "vitest run tests/integration/storage/schema.spec.ts --reporter=dot",
|
|
28
|
+
"lint": "eslint .",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"benchmark": "node scripts/benchmark.mjs",
|
|
31
|
+
"postversion": "node -e \"const v=require('./package.json').version; ['package/package.json','.claude-plugin/plugin.json','server.json'].forEach(f=>{const o=require('./'+f);o.version=v;if(o.packages&&o.packages[0])o.packages[0].version=v;require('fs').writeFileSync('./'+f,JSON.stringify(o,null,2)+'\\n')})\" && npm run build"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@anthropic-ai/sdk": "^0.105.0",
|
|
35
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
36
|
+
"better-sqlite3": "^12.4.1",
|
|
37
|
+
"commander": "^15.0.0",
|
|
38
|
+
"js-tiktoken": "^1.0.21",
|
|
39
|
+
"zod": "^4.4.3"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@eslint/js": "^10.0.1",
|
|
43
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
44
|
+
"eslint": "^10.4.1",
|
|
45
|
+
"globals": "^17.6.0",
|
|
46
|
+
"typescript": "^6.0.3",
|
|
47
|
+
"typescript-eslint": "^8.61.0",
|
|
48
|
+
"vitest": "^4.1.8"
|
|
49
|
+
}
|
|
50
|
+
}
|