context-mode 1.0.160 → 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.
@@ -6,14 +6,14 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Claude Code plugins by Mert Koseoğlu",
9
- "version": "1.0.160"
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.160",
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.160",
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.160",
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.160",
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.160",
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 = $15.00 per 1M input tokens (fallback when PI_CONTEXT_MODE_PRICE_OUTPUT_PER_TOKEN not set)
612
- * Sonnet 4 = $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 = $0.80 per 1M input tokens
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
- * ($15 per 1M tokens) otherwise.
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 = $15.00 per 1M input tokens (fallback when PI_CONTEXT_MODE_PRICE_OUTPUT_PER_TOKEN not set)
1397
- * Sonnet 4 = $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 = $0.80 per 1M input tokens
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.8) / 1_000_000).toFixed(2);
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 ($15/1M) for all other adapters.
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
- * ($15 per 1M tokens) otherwise.
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 15 / 1_000_000; // Opus 4 input fallback
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 = 15 / 1_000_000;
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;
@@ -179,6 +179,7 @@ export interface SessionRollup {
179
179
  unique_files: number;
180
180
  max_file_edits: number;
181
181
  has_commit: 0 | 1;
182
+ commit_message: string;
182
183
  edit_test_cycles: number;
183
184
  duration_min: number;
184
185
  compact_count: number;
@@ -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 category = 'git' THEN 1 ELSE 0 END) > 0 THEN 1 ELSE 0 END AS has_commit,
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;