context-mode 1.0.161 → 1.0.162
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.openclaw-plugin/openclaw.plugin.json +1 -1
- package/.openclaw-plugin/package.json +1 -1
- package/build/session/analytics.d.ts +7 -7
- package/build/session/analytics.js +13 -12
- package/build/session/db.d.ts +1 -0
- package/build/session/db.js +14 -1
- package/build/session/extract.d.ts +46 -0
- package/build/session/extract.js +756 -13
- package/build/session/project-attribution.js +14 -0
- package/cli.bundle.mjs +10 -6
- package/hooks/session-db.bundle.mjs +11 -7
- package/hooks/session-extract.bundle.mjs +2 -2
- package/hooks/session-loaders.mjs +8 -5
- package/hooks/sessionstart.mjs +16 -2
- package/hooks/userpromptsubmit.mjs +9 -2
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server.bundle.mjs +9 -5
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Claude Code plugins by Mert Koseoğlu",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.162"
|
|
10
10
|
},
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
13
13
|
"name": "context-mode",
|
|
14
14
|
"source": "./",
|
|
15
15
|
"description": "Claude Code MCP plugin that saves 98% of your context window. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
|
|
16
|
-
"version": "1.0.
|
|
16
|
+
"version": "1.0.162",
|
|
17
17
|
"author": {
|
|
18
18
|
"name": "Mert Koseoğlu"
|
|
19
19
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-mode",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.162",
|
|
4
4
|
"description": "MCP server that saves 98% of your context window with session continuity. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and automatic state restore across compactions.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mert Koseoğlu",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-mode",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.162",
|
|
4
4
|
"description": "MCP server that saves 98% of your context window with session continuity. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and automatic state restore across compactions.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mert Koseoğlu",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "Context Mode",
|
|
4
4
|
"kind": "tool",
|
|
5
5
|
"description": "OpenClaw plugin that saves 98% of your context window. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.162",
|
|
7
7
|
"sandbox": {
|
|
8
8
|
"mode": "permissive",
|
|
9
9
|
"filesystem_access": "full",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-mode",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.162",
|
|
4
4
|
"description": "OpenClaw plugin that saves 98% of your context window. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mert Koseoğlu",
|
|
@@ -608,11 +608,11 @@ export declare function detectLocaleAndTz(): {
|
|
|
608
608
|
* the section disappears cleanly on a fresh install.
|
|
609
609
|
*
|
|
610
610
|
* Math constants:
|
|
611
|
-
* Opus 4
|
|
612
|
-
* Sonnet 4
|
|
613
|
-
* GPT-4o
|
|
614
|
-
* Gemini 2
|
|
615
|
-
* Haiku 4
|
|
611
|
+
* Opus 4.7/4.8 = $5.00 per 1M input tokens (fallback when PI_CONTEXT_MODE_PRICE_OUTPUT_PER_TOKEN not set)
|
|
612
|
+
* Sonnet 4.6 = $3.00 per 1M input tokens
|
|
613
|
+
* GPT-4o = $2.50 per 1M input tokens
|
|
614
|
+
* Gemini 2 = $1.25 per 1M input tokens
|
|
615
|
+
* Haiku 4.5 = $1.00 per 1M input tokens
|
|
616
616
|
* Cursor Pro = $20 / month → "X months of Cursor Pro"
|
|
617
617
|
* Claude Max = $200 / month → "X.X months of Claude Max"
|
|
618
618
|
* Weekend coding ≈ $73.67 → "X weekends of nonstop API coding"
|
|
@@ -669,8 +669,8 @@ export declare function renderHorizontalTimeline(days: TimelineDay[], locale: st
|
|
|
669
669
|
export declare function formatLocalDateTime(ms: number, locale: string, tz: string): string;
|
|
670
670
|
/**
|
|
671
671
|
* Per-token USD rate — resolves on every call.
|
|
672
|
-
* Dynamic when PI_CONTEXT_MODE_PRICE_OUTPUT_PER_TOKEN is set, Opus 4 input
|
|
673
|
-
* ($
|
|
672
|
+
* Dynamic when PI_CONTEXT_MODE_PRICE_OUTPUT_PER_TOKEN is set, Opus 4.7/4.8 input
|
|
673
|
+
* ($5 per 1M tokens) otherwise.
|
|
674
674
|
*/
|
|
675
675
|
export declare function pricePerToken(): number;
|
|
676
676
|
/**
|
|
@@ -1393,11 +1393,11 @@ function shortPath(abs) {
|
|
|
1393
1393
|
* the section disappears cleanly on a fresh install.
|
|
1394
1394
|
*
|
|
1395
1395
|
* Math constants:
|
|
1396
|
-
* Opus 4
|
|
1397
|
-
* Sonnet 4
|
|
1398
|
-
* GPT-4o
|
|
1399
|
-
* Gemini 2
|
|
1400
|
-
* Haiku 4
|
|
1396
|
+
* Opus 4.7/4.8 = $5.00 per 1M input tokens (fallback when PI_CONTEXT_MODE_PRICE_OUTPUT_PER_TOKEN not set)
|
|
1397
|
+
* Sonnet 4.6 = $3.00 per 1M input tokens
|
|
1398
|
+
* GPT-4o = $2.50 per 1M input tokens
|
|
1399
|
+
* Gemini 2 = $1.25 per 1M input tokens
|
|
1400
|
+
* Haiku 4.5 = $1.00 per 1M input tokens
|
|
1401
1401
|
* Cursor Pro = $20 / month → "X months of Cursor Pro"
|
|
1402
1402
|
* Claude Max = $200 / month → "X.X months of Claude Max"
|
|
1403
1403
|
* Weekend coding ≈ $73.67 → "X weekends of nonstop API coding"
|
|
@@ -1428,7 +1428,7 @@ export function renderCostExample(lifetimeBytes, lifetimeTokens, lifetimeDays) {
|
|
|
1428
1428
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1429
1429
|
const _geminiUsd = ((lifetimeTokens * 1.25) / 1_000_000).toFixed(2);
|
|
1430
1430
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1431
|
-
const _haikuUsd = ((lifetimeTokens * 0
|
|
1431
|
+
const _haikuUsd = ((lifetimeTokens * 1.0) / 1_000_000).toFixed(2);
|
|
1432
1432
|
const usingDynamicPrice = process.env.PI_CONTEXT_MODE_PRICE_OUTPUT_PER_TOKEN !== undefined;
|
|
1433
1433
|
const modelId = process.env.PI_CONTEXT_MODE_MODEL_ID;
|
|
1434
1434
|
// Mert: "daha marketing ve business value e vermeli, math hesaplamalari ile
|
|
@@ -1442,7 +1442,7 @@ export function renderCostExample(lifetimeBytes, lifetimeTokens, lifetimeDays) {
|
|
|
1442
1442
|
out.push(` $${usdStr(lifetimeUsd)} of tokens your team didn't burn.`);
|
|
1443
1443
|
}
|
|
1444
1444
|
else {
|
|
1445
|
-
out.push(` $${usdStr(lifetimeUsd)} of Opus 4 tokens your team didn't burn.`);
|
|
1445
|
+
out.push(` $${usdStr(lifetimeUsd)} of Opus 4.7 tokens your team didn't burn.`);
|
|
1446
1446
|
}
|
|
1447
1447
|
out.push(` context-mode kept ${kb(lifetimeBytes)} out of context — that's ${cursorMonths} months of Cursor Pro paid for itself.`);
|
|
1448
1448
|
if (teamUsd > 0 && teamYearUsd > 0) {
|
|
@@ -1857,7 +1857,8 @@ function fmtNum(n) {
|
|
|
1857
1857
|
// ─────────────────────────────────────────────────────────
|
|
1858
1858
|
// ── Pricing (Bug #6) — per-token USD rate ─────────────────
|
|
1859
1859
|
// Reads PI_CONTEXT_MODE_PRICE_OUTPUT_PER_TOKEN when set by a Pi host;
|
|
1860
|
-
// falls back to the Opus 4 input rate ($
|
|
1860
|
+
// falls back to the Opus 4.7/4.8 input rate ($5/1M) for all other adapters.
|
|
1861
|
+
// Verified against platform.claude.com/docs/en/about-claude/pricing 2026-06.
|
|
1861
1862
|
//
|
|
1862
1863
|
// IMPORTANT: this is a FUNCTION, not a const. Pi sets the env var
|
|
1863
1864
|
// AFTER the MCP server has been imported (the bridge spawns the server
|
|
@@ -1869,8 +1870,8 @@ function fmtNum(n) {
|
|
|
1869
1870
|
// (Reverted module-load const semantics, PR #741 follow-up.)
|
|
1870
1871
|
/**
|
|
1871
1872
|
* Per-token USD rate — resolves on every call.
|
|
1872
|
-
* Dynamic when PI_CONTEXT_MODE_PRICE_OUTPUT_PER_TOKEN is set, Opus 4 input
|
|
1873
|
-
* ($
|
|
1873
|
+
* Dynamic when PI_CONTEXT_MODE_PRICE_OUTPUT_PER_TOKEN is set, Opus 4.7/4.8 input
|
|
1874
|
+
* ($5 per 1M tokens) otherwise.
|
|
1874
1875
|
*/
|
|
1875
1876
|
export function pricePerToken() {
|
|
1876
1877
|
const env = process.env.PI_CONTEXT_MODE_PRICE_OUTPUT_PER_TOKEN;
|
|
@@ -1879,7 +1880,7 @@ export function pricePerToken() {
|
|
|
1879
1880
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
1880
1881
|
return parsed;
|
|
1881
1882
|
}
|
|
1882
|
-
return
|
|
1883
|
+
return 5 / 1_000_000; // Opus 4.7/4.8 input fallback
|
|
1883
1884
|
}
|
|
1884
1885
|
/**
|
|
1885
1886
|
* Back-compat alias for the original Opus-rate const (PR #401 architect
|
|
@@ -1890,7 +1891,7 @@ export function pricePerToken() {
|
|
|
1890
1891
|
*
|
|
1891
1892
|
* @deprecated Use pricePerToken() to honor PI_CONTEXT_MODE_PRICE_OUTPUT_PER_TOKEN.
|
|
1892
1893
|
*/
|
|
1893
|
-
export const OPUS_INPUT_PRICE_PER_TOKEN =
|
|
1894
|
+
export const OPUS_INPUT_PRICE_PER_TOKEN = 5 / 1_000_000;
|
|
1894
1895
|
/** Convert a token count to a USD string at the current per-token rate. */
|
|
1895
1896
|
export function tokensToUsd(tokens) {
|
|
1896
1897
|
const safe = Number.isFinite(tokens) && tokens > 0 ? tokens : 0;
|
package/build/session/db.d.ts
CHANGED
package/build/session/db.js
CHANGED
|
@@ -479,6 +479,7 @@ const S = {
|
|
|
479
479
|
getSessionStats: "getSessionStats",
|
|
480
480
|
getSessionRollup: "getSessionRollup",
|
|
481
481
|
getMaxFileEdits: "getMaxFileEdits",
|
|
482
|
+
getLatestCommitMessage: "getLatestCommitMessage",
|
|
482
483
|
incrementCompactCount: "incrementCompactCount",
|
|
483
484
|
upsertResume: "upsertResume",
|
|
484
485
|
getResume: "getResume",
|
|
@@ -731,7 +732,7 @@ export class SessionDB extends SQLiteBase {
|
|
|
731
732
|
COALESCE(SUM(CASE WHEN category = 'error' THEN 1 ELSE 0 END), 0) AS errors,
|
|
732
733
|
COUNT(DISTINCT type) AS unique_tools,
|
|
733
734
|
COUNT(DISTINCT CASE WHEN category = 'file' THEN data END) AS unique_files,
|
|
734
|
-
CASE WHEN SUM(CASE WHEN
|
|
735
|
+
CASE WHEN SUM(CASE WHEN type = 'git_commit' THEN 1 ELSE 0 END) > 0 THEN 1 ELSE 0 END AS has_commit,
|
|
735
736
|
CAST(COALESCE((MAX(strftime('%s', created_at)) - MIN(strftime('%s', created_at))) / 60.0, 0) AS INTEGER) AS duration_min,
|
|
736
737
|
COALESCE(SUM(CASE WHEN type = 'external_ref' THEN 1 ELSE 0 END), 0) AS sources_indexed,
|
|
737
738
|
CAST(COALESCE(SUM(bytes_avoided) / 1024.0, 0) AS INTEGER) AS total_chunks,
|
|
@@ -747,6 +748,16 @@ export class SessionDB extends SQLiteBase {
|
|
|
747
748
|
WHERE session_id = ? AND category = 'file' AND type IN ('file_edit', 'file_write')
|
|
748
749
|
GROUP BY data
|
|
749
750
|
)`);
|
|
751
|
+
// v1.0.161 (Bug 2): latest commit message from session's type='git_commit'
|
|
752
|
+
// events. Used by rollup spread to stamp commit_message symmetric with
|
|
753
|
+
// has_commit on every outgoing event. Separate prepared statement (vs.
|
|
754
|
+
// sub-select in getSessionRollup) keeps the binding shape uniform — every
|
|
755
|
+
// rollup query takes a single sessionId parameter.
|
|
756
|
+
p(S.getLatestCommitMessage, `SELECT data
|
|
757
|
+
FROM session_events
|
|
758
|
+
WHERE session_id = ? AND type = 'git_commit'
|
|
759
|
+
ORDER BY id DESC
|
|
760
|
+
LIMIT 1`);
|
|
750
761
|
p(S.incrementCompactCount, `UPDATE session_meta SET compact_count = compact_count + 1 WHERE session_id = ?`);
|
|
751
762
|
// ── Resume ──
|
|
752
763
|
p(S.upsertResume, `INSERT INTO session_resume (session_id, snapshot, event_count)
|
|
@@ -1063,6 +1074,7 @@ export class SessionDB extends SQLiteBase {
|
|
|
1063
1074
|
getSessionRollup(sessionId) {
|
|
1064
1075
|
const main = this.stmt(S.getSessionRollup).get(sessionId);
|
|
1065
1076
|
const maxRow = this.stmt(S.getMaxFileEdits).get(sessionId);
|
|
1077
|
+
const commitRow = this.stmt(S.getLatestCommitMessage).get(sessionId);
|
|
1066
1078
|
const meta = this.getSessionStats(sessionId);
|
|
1067
1079
|
// edit_test_cycles: heuristic — min(file edits, errors) approximates
|
|
1068
1080
|
// the number of edit-then-test attempts in a session. Exact pattern
|
|
@@ -1080,6 +1092,7 @@ export class SessionDB extends SQLiteBase {
|
|
|
1080
1092
|
unique_files: main?.unique_files ?? 0,
|
|
1081
1093
|
max_file_edits: maxRow?.max_file_edits ?? 0,
|
|
1082
1094
|
has_commit: main?.has_commit ?? 0,
|
|
1095
|
+
commit_message: commitRow?.data ?? "",
|
|
1083
1096
|
edit_test_cycles: editTestCycles,
|
|
1084
1097
|
duration_min: main?.duration_min ?? 0,
|
|
1085
1098
|
compact_count: meta?.compact_count ?? 0,
|
|
@@ -61,3 +61,49 @@ export declare function extractEvents(rawInput: HookInput): SessionEvent[];
|
|
|
61
61
|
* Returns an array of zero or more SessionEvents. Never throws.
|
|
62
62
|
*/
|
|
63
63
|
export declare function extractUserEvents(message: string): SessionEvent[];
|
|
64
|
+
/**
|
|
65
|
+
* Issue #4 (new PRD) — SessionStart settings + MCP servers snapshot.
|
|
66
|
+
*
|
|
67
|
+
* Emits ONE session_settings_snapshot event when ≥1 setting is available
|
|
68
|
+
* on the SessionStart input. The data field carries key:value tokens
|
|
69
|
+
* (mcp_count, mcp_servers, model, permission_mode) so the platform can
|
|
70
|
+
* compute MCP integration counts and primary-model adoption per org.
|
|
71
|
+
* mcp_servers list is truncated to first 8 names.
|
|
72
|
+
*/
|
|
73
|
+
export declare function extractSessionSettings(input: unknown): SessionEvent[];
|
|
74
|
+
/**
|
|
75
|
+
* §11 Layer 1 + Layer 3 — multilingual prompt features.
|
|
76
|
+
*
|
|
77
|
+
* Reference: context-mode-platform/docs/prds/2026-06-insight-data-flow/
|
|
78
|
+
* 11-multilingual-prompt-algorithm.md
|
|
79
|
+
*
|
|
80
|
+
* Script-agnostic via Unicode property regex (`\p{L}`, `\p{Lu}`,
|
|
81
|
+
* `\p{Script=X}`). No per-language tables, no franc/fasttext deps.
|
|
82
|
+
* Layer 1 returns 10 numeric/string features; Layer 3 appends a
|
|
83
|
+
* `prompt_word_tokens: string[]` array for the platform's streaming
|
|
84
|
+
* word-frequency UPSERT.
|
|
85
|
+
*
|
|
86
|
+
* Privacy: features carry no prose. Layer 3 tokens are deduped
|
|
87
|
+
* letter-only words ≥3 chars; platform aggregates by (org_id, week,
|
|
88
|
+
* word) so no individual token surfaces in UI.
|
|
89
|
+
*/
|
|
90
|
+
export interface PromptFeatures {
|
|
91
|
+
prompt_length: number;
|
|
92
|
+
prompt_word_count: number;
|
|
93
|
+
prompt_uppercase_ratio: number;
|
|
94
|
+
prompt_file_ref_count: number;
|
|
95
|
+
prompt_path_ref_count: number;
|
|
96
|
+
prompt_script_primary: string | null;
|
|
97
|
+
prompt_script_count: number;
|
|
98
|
+
prompt_question_glyph_count: number;
|
|
99
|
+
prompt_code_block_count: number;
|
|
100
|
+
prompt_url_count: number;
|
|
101
|
+
prompt_word_tokens: string[];
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Verbatim mirror of §11 Layer 1 reference implementation + Layer 3
|
|
105
|
+
* token extraction. Uses Unicode property regex per the spec — the
|
|
106
|
+
* "no regex" project default does NOT apply here because the spec
|
|
107
|
+
* explicitly mandates `\p{Script=X}` for script-agnostic classification.
|
|
108
|
+
*/
|
|
109
|
+
export declare function extractUserPromptFeatures(prompt: unknown): PromptFeatures;
|