From ebc620bc15471941ba567bae2e8a3045c1c61b09 Mon Sep 17 00:00:00 2001 From: kaghni Date: Wed, 22 Apr 2026 21:53:55 -0700 Subject: [PATCH 1/4] send X-Deeplake-Client: hivemind/ on deeplake-api calls The deeplake-api backend reads X-Deeplake-Client to attribute traffic for analytics (signup_source, login_source, daily retention rollup). Without the header, hivemind requests look identical to the generic cli_device_flow and are invisible in PostHog. - Add src/utils/client-header.ts with deeplakeClientHeader() using a build-time __HIVEMIND_VERSION__ define; dev runs fall back to "dev" so tsx/vitest don't crash on the undefined symbol. - Extend esbuild.config.mjs: define __HIVEMIND_VERSION__ for the CC and Codex bundles (openclaw already had an analogous define for its own version). - Apply the header at every outbound fetch site: DeepLakeAPI (query + listTables), commands/auth.ts (whoami / orgs / workspaces / device-code / device-token), and both wiki-worker.ts entry points. - Rebuild CC + Codex bundles so the shipped plugin carries the version literal baked in. No PostHog SDK in hivemind; backend does all analytics. --- claude-code/bundle/capture.js | 24 +++++++++++-- claude-code/bundle/commands/auth-login.js | 39 ++++++++++++++++++---- claude-code/bundle/pre-tool-use.js | 24 +++++++++++-- claude-code/bundle/session-start-setup.js | 26 +++++++++++++-- claude-code/bundle/session-start.js | 26 +++++++++++++-- claude-code/bundle/shell/deeplake-shell.js | 24 +++++++++++-- claude-code/bundle/wiki-worker.js | 21 +++++++++++- codex/bundle/capture.js | 24 +++++++++++-- codex/bundle/commands/auth-login.js | 39 ++++++++++++++++++---- codex/bundle/pre-tool-use.js | 24 +++++++++++-- codex/bundle/session-start-setup.js | 26 +++++++++++++-- codex/bundle/shell/deeplake-shell.js | 24 +++++++++++-- codex/bundle/stop.js | 24 +++++++++++-- codex/bundle/wiki-worker.js | 21 +++++++++++- esbuild.config.mjs | 7 ++++ src/commands/auth.ts | 8 +++-- src/deeplake-api.ts | 3 ++ src/hooks/codex/wiki-worker.ts | 2 ++ src/hooks/wiki-worker.ts | 2 ++ src/utils/client-header.ts | 34 +++++++++++++++++++ 20 files changed, 384 insertions(+), 38 deletions(-) create mode 100644 src/utils/client-header.ts diff --git a/claude-code/bundle/capture.js b/claude-code/bundle/capture.js index 7251cf96..41b9eaa4 100755 --- a/claude-code/bundle/capture.js +++ b/claude-code/bundle/capture.js @@ -76,6 +76,24 @@ function sqlStr(value) { return value.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/\0/g, "").replace(/[\x01-\x08\x0b\x0c\x0e-\x1f\x7f]/g, ""); } +// dist/src/utils/client-header.js +function pluginVersion() { + try { + if ("0.6.45") { + return "0.6.45"; + } + } catch { + } + return "dev"; +} +var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; +function deeplakeClientValue() { + return `hivemind/${pluginVersion()}`; +} +function deeplakeClientHeader() { + return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; +} + // dist/src/deeplake-api.js var log2 = (msg) => log("sdk", msg); function summarizeSql(sql, maxLen = 220) { @@ -187,7 +205,8 @@ var DeeplakeApi = class { headers: { Authorization: `Bearer ${this.token}`, "Content-Type": "application/json", - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() }, signal, body: JSON.stringify({ query: sql }) @@ -339,7 +358,8 @@ var DeeplakeApi = class { const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, { headers: { Authorization: `Bearer ${this.token}`, - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() } }); if (resp.ok) { diff --git a/claude-code/bundle/commands/auth-login.js b/claude-code/bundle/commands/auth-login.js index aa19693f..9770442c 100755 --- a/claude-code/bundle/commands/auth-login.js +++ b/claude-code/bundle/commands/auth-login.js @@ -5,6 +5,26 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync } from " import { join } from "node:path"; import { homedir } from "node:os"; import { execSync } from "node:child_process"; + +// dist/src/utils/client-header.js +function pluginVersion() { + try { + if ("0.6.45") { + return "0.6.45"; + } + } catch { + } + return "dev"; +} +var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; +function deeplakeClientValue() { + return `hivemind/${pluginVersion()}`; +} +function deeplakeClientHeader() { + return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; +} + +// dist/src/commands/auth.js var CONFIG_DIR = join(homedir(), ".deeplake"); var CREDS_PATH = join(CONFIG_DIR, "credentials.json"); var DEFAULT_API_URL = "https://api.deeplake.ai"; @@ -32,7 +52,8 @@ function deleteCredentials() { async function apiGet(path, token, apiUrl, orgId) { const headers = { Authorization: `Bearer ${token}`, - "Content-Type": "application/json" + "Content-Type": "application/json", + ...deeplakeClientHeader() }; if (orgId) headers["X-Activeloop-Org-Id"] = orgId; @@ -44,7 +65,8 @@ async function apiGet(path, token, apiUrl, orgId) { async function apiPost(path, body, token, apiUrl, orgId) { const headers = { Authorization: `Bearer ${token}`, - "Content-Type": "application/json" + "Content-Type": "application/json", + ...deeplakeClientHeader() }; if (orgId) headers["X-Activeloop-Org-Id"] = orgId; @@ -56,7 +78,8 @@ async function apiPost(path, body, token, apiUrl, orgId) { async function apiDelete(path, token, apiUrl, orgId) { const headers = { Authorization: `Bearer ${token}`, - "Content-Type": "application/json" + "Content-Type": "application/json", + ...deeplakeClientHeader() }; if (orgId) headers["X-Activeloop-Org-Id"] = orgId; @@ -67,7 +90,7 @@ async function apiDelete(path, token, apiUrl, orgId) { async function requestDeviceCode(apiUrl = DEFAULT_API_URL) { const resp = await fetch(`${apiUrl}/auth/device/code`, { method: "POST", - headers: { "Content-Type": "application/json" } + headers: { "Content-Type": "application/json", ...deeplakeClientHeader() } }); if (!resp.ok) throw new Error(`Device flow unavailable: HTTP ${resp.status}`); @@ -76,7 +99,7 @@ async function requestDeviceCode(apiUrl = DEFAULT_API_URL) { async function pollForToken(deviceCode, apiUrl = DEFAULT_API_URL) { const resp = await fetch(`${apiUrl}/auth/device/token`, { method: "POST", - headers: { "Content-Type": "application/json" }, + headers: { "Content-Type": "application/json", ...deeplakeClientHeader() }, body: JSON.stringify({ device_code: deviceCode }) }); if (resp.ok) @@ -368,7 +391,8 @@ var DeeplakeApi = class { headers: { Authorization: `Bearer ${this.token}`, "Content-Type": "application/json", - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() }, signal, body: JSON.stringify({ query: sql }) @@ -520,7 +544,8 @@ var DeeplakeApi = class { const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, { headers: { Authorization: `Bearer ${this.token}`, - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() } }); if (resp.ok) { diff --git a/claude-code/bundle/pre-tool-use.js b/claude-code/bundle/pre-tool-use.js index 94a5d724..cc0ad712 100755 --- a/claude-code/bundle/pre-tool-use.js +++ b/claude-code/bundle/pre-tool-use.js @@ -82,6 +82,24 @@ function sqlLike(value) { return sqlStr(value).replace(/%/g, "\\%").replace(/_/g, "\\_"); } +// dist/src/utils/client-header.js +function pluginVersion() { + try { + if ("0.6.45") { + return "0.6.45"; + } + } catch { + } + return "dev"; +} +var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; +function deeplakeClientValue() { + return `hivemind/${pluginVersion()}`; +} +function deeplakeClientHeader() { + return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; +} + // dist/src/deeplake-api.js var log2 = (msg) => log("sdk", msg); function summarizeSql(sql, maxLen = 220) { @@ -193,7 +211,8 @@ var DeeplakeApi = class { headers: { Authorization: `Bearer ${this.token}`, "Content-Type": "application/json", - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() }, signal, body: JSON.stringify({ query: sql }) @@ -345,7 +364,8 @@ var DeeplakeApi = class { const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, { headers: { Authorization: `Bearer ${this.token}`, - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() } }); if (resp.ok) { diff --git a/claude-code/bundle/session-start-setup.js b/claude-code/bundle/session-start-setup.js index e184bce2..7061b9c8 100755 --- a/claude-code/bundle/session-start-setup.js +++ b/claude-code/bundle/session-start-setup.js @@ -11,6 +11,26 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync } from " import { join } from "node:path"; import { homedir } from "node:os"; import { execSync } from "node:child_process"; + +// dist/src/utils/client-header.js +function pluginVersion() { + try { + if ("0.6.45") { + return "0.6.45"; + } + } catch { + } + return "dev"; +} +var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; +function deeplakeClientValue() { + return `hivemind/${pluginVersion()}`; +} +function deeplakeClientHeader() { + return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; +} + +// dist/src/commands/auth.js var CONFIG_DIR = join(homedir(), ".deeplake"); var CREDS_PATH = join(CONFIG_DIR, "credentials.json"); function loadCredentials() { @@ -198,7 +218,8 @@ var DeeplakeApi = class { headers: { Authorization: `Bearer ${this.token}`, "Content-Type": "application/json", - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() }, signal, body: JSON.stringify({ query: sql }) @@ -350,7 +371,8 @@ var DeeplakeApi = class { const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, { headers: { Authorization: `Bearer ${this.token}`, - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() } }); if (resp.ok) { diff --git a/claude-code/bundle/session-start.js b/claude-code/bundle/session-start.js index f5b51fc8..e4f9b6fd 100755 --- a/claude-code/bundle/session-start.js +++ b/claude-code/bundle/session-start.js @@ -12,6 +12,26 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync } from " import { join } from "node:path"; import { homedir } from "node:os"; import { execSync } from "node:child_process"; + +// dist/src/utils/client-header.js +function pluginVersion() { + try { + if ("0.6.45") { + return "0.6.45"; + } + } catch { + } + return "dev"; +} +var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; +function deeplakeClientValue() { + return `hivemind/${pluginVersion()}`; +} +function deeplakeClientHeader() { + return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; +} + +// dist/src/commands/auth.js var CONFIG_DIR = join(homedir(), ".deeplake"); var CREDS_PATH = join(CONFIG_DIR, "credentials.json"); function loadCredentials() { @@ -199,7 +219,8 @@ var DeeplakeApi = class { headers: { Authorization: `Bearer ${this.token}`, "Content-Type": "application/json", - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() }, signal, body: JSON.stringify({ query: sql }) @@ -351,7 +372,8 @@ var DeeplakeApi = class { const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, { headers: { Authorization: `Bearer ${this.token}`, - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() } }); if (resp.ok) { diff --git a/claude-code/bundle/shell/deeplake-shell.js b/claude-code/bundle/shell/deeplake-shell.js index 7e140a93..3d786e92 100755 --- a/claude-code/bundle/shell/deeplake-shell.js +++ b/claude-code/bundle/shell/deeplake-shell.js @@ -66779,6 +66779,24 @@ function sqlLike(value) { return sqlStr(value).replace(/%/g, "\\%").replace(/_/g, "\\_"); } +// dist/src/utils/client-header.js +function pluginVersion() { + try { + if ("0.6.45") { + return "0.6.45"; + } + } catch { + } + return "dev"; +} +var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; +function deeplakeClientValue() { + return `hivemind/${pluginVersion()}`; +} +function deeplakeClientHeader() { + return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; +} + // dist/src/deeplake-api.js var log2 = (msg) => log("sdk", msg); function summarizeSql(sql, maxLen = 220) { @@ -66890,7 +66908,8 @@ var DeeplakeApi = class { headers: { Authorization: `Bearer ${this.token}`, "Content-Type": "application/json", - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() }, signal, body: JSON.stringify({ query: sql }) @@ -67042,7 +67061,8 @@ var DeeplakeApi = class { const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, { headers: { Authorization: `Bearer ${this.token}`, - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() } }); if (resp.ok) { diff --git a/claude-code/bundle/wiki-worker.js b/claude-code/bundle/wiki-worker.js index b2f974fc..c36f1a8b 100755 --- a/claude-code/bundle/wiki-worker.js +++ b/claude-code/bundle/wiki-worker.js @@ -21,6 +21,24 @@ function log(tag, msg) { `); } +// dist/src/utils/client-header.js +function pluginVersion() { + try { + if ("0.6.45") { + return "0.6.45"; + } + } catch { + } + return "dev"; +} +var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; +function deeplakeClientValue() { + return `hivemind/${pluginVersion()}`; +} +function deeplakeClientHeader() { + return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; +} + // dist/src/hooks/summary-state.js import { readFileSync, writeFileSync, writeSync, mkdirSync, renameSync, existsSync, unlinkSync, openSync, closeSync } from "node:fs"; import { homedir as homedir2 } from "node:os"; @@ -154,7 +172,8 @@ async function query(sql, retries = 4) { headers: { Authorization: `Bearer ${cfg.token}`, "Content-Type": "application/json", - "X-Activeloop-Org-Id": cfg.orgId + "X-Activeloop-Org-Id": cfg.orgId, + ...deeplakeClientHeader() }, body: JSON.stringify({ query: sql }) }); diff --git a/codex/bundle/capture.js b/codex/bundle/capture.js index b16405a6..2af00e55 100755 --- a/codex/bundle/capture.js +++ b/codex/bundle/capture.js @@ -76,6 +76,24 @@ function sqlStr(value) { return value.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/\0/g, "").replace(/[\x01-\x08\x0b\x0c\x0e-\x1f\x7f]/g, ""); } +// dist/src/utils/client-header.js +function pluginVersion() { + try { + if ("0.6.45") { + return "0.6.45"; + } + } catch { + } + return "dev"; +} +var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; +function deeplakeClientValue() { + return `hivemind/${pluginVersion()}`; +} +function deeplakeClientHeader() { + return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; +} + // dist/src/deeplake-api.js var log2 = (msg) => log("sdk", msg); function summarizeSql(sql, maxLen = 220) { @@ -187,7 +205,8 @@ var DeeplakeApi = class { headers: { Authorization: `Bearer ${this.token}`, "Content-Type": "application/json", - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() }, signal, body: JSON.stringify({ query: sql }) @@ -339,7 +358,8 @@ var DeeplakeApi = class { const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, { headers: { Authorization: `Bearer ${this.token}`, - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() } }); if (resp.ok) { diff --git a/codex/bundle/commands/auth-login.js b/codex/bundle/commands/auth-login.js index aa19693f..9770442c 100755 --- a/codex/bundle/commands/auth-login.js +++ b/codex/bundle/commands/auth-login.js @@ -5,6 +5,26 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync } from " import { join } from "node:path"; import { homedir } from "node:os"; import { execSync } from "node:child_process"; + +// dist/src/utils/client-header.js +function pluginVersion() { + try { + if ("0.6.45") { + return "0.6.45"; + } + } catch { + } + return "dev"; +} +var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; +function deeplakeClientValue() { + return `hivemind/${pluginVersion()}`; +} +function deeplakeClientHeader() { + return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; +} + +// dist/src/commands/auth.js var CONFIG_DIR = join(homedir(), ".deeplake"); var CREDS_PATH = join(CONFIG_DIR, "credentials.json"); var DEFAULT_API_URL = "https://api.deeplake.ai"; @@ -32,7 +52,8 @@ function deleteCredentials() { async function apiGet(path, token, apiUrl, orgId) { const headers = { Authorization: `Bearer ${token}`, - "Content-Type": "application/json" + "Content-Type": "application/json", + ...deeplakeClientHeader() }; if (orgId) headers["X-Activeloop-Org-Id"] = orgId; @@ -44,7 +65,8 @@ async function apiGet(path, token, apiUrl, orgId) { async function apiPost(path, body, token, apiUrl, orgId) { const headers = { Authorization: `Bearer ${token}`, - "Content-Type": "application/json" + "Content-Type": "application/json", + ...deeplakeClientHeader() }; if (orgId) headers["X-Activeloop-Org-Id"] = orgId; @@ -56,7 +78,8 @@ async function apiPost(path, body, token, apiUrl, orgId) { async function apiDelete(path, token, apiUrl, orgId) { const headers = { Authorization: `Bearer ${token}`, - "Content-Type": "application/json" + "Content-Type": "application/json", + ...deeplakeClientHeader() }; if (orgId) headers["X-Activeloop-Org-Id"] = orgId; @@ -67,7 +90,7 @@ async function apiDelete(path, token, apiUrl, orgId) { async function requestDeviceCode(apiUrl = DEFAULT_API_URL) { const resp = await fetch(`${apiUrl}/auth/device/code`, { method: "POST", - headers: { "Content-Type": "application/json" } + headers: { "Content-Type": "application/json", ...deeplakeClientHeader() } }); if (!resp.ok) throw new Error(`Device flow unavailable: HTTP ${resp.status}`); @@ -76,7 +99,7 @@ async function requestDeviceCode(apiUrl = DEFAULT_API_URL) { async function pollForToken(deviceCode, apiUrl = DEFAULT_API_URL) { const resp = await fetch(`${apiUrl}/auth/device/token`, { method: "POST", - headers: { "Content-Type": "application/json" }, + headers: { "Content-Type": "application/json", ...deeplakeClientHeader() }, body: JSON.stringify({ device_code: deviceCode }) }); if (resp.ok) @@ -368,7 +391,8 @@ var DeeplakeApi = class { headers: { Authorization: `Bearer ${this.token}`, "Content-Type": "application/json", - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() }, signal, body: JSON.stringify({ query: sql }) @@ -520,7 +544,8 @@ var DeeplakeApi = class { const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, { headers: { Authorization: `Bearer ${this.token}`, - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() } }); if (resp.ok) { diff --git a/codex/bundle/pre-tool-use.js b/codex/bundle/pre-tool-use.js index c7aeda76..c348ae02 100755 --- a/codex/bundle/pre-tool-use.js +++ b/codex/bundle/pre-tool-use.js @@ -82,6 +82,24 @@ function sqlLike(value) { return sqlStr(value).replace(/%/g, "\\%").replace(/_/g, "\\_"); } +// dist/src/utils/client-header.js +function pluginVersion() { + try { + if ("0.6.45") { + return "0.6.45"; + } + } catch { + } + return "dev"; +} +var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; +function deeplakeClientValue() { + return `hivemind/${pluginVersion()}`; +} +function deeplakeClientHeader() { + return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; +} + // dist/src/deeplake-api.js var log2 = (msg) => log("sdk", msg); function summarizeSql(sql, maxLen = 220) { @@ -193,7 +211,8 @@ var DeeplakeApi = class { headers: { Authorization: `Bearer ${this.token}`, "Content-Type": "application/json", - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() }, signal, body: JSON.stringify({ query: sql }) @@ -345,7 +364,8 @@ var DeeplakeApi = class { const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, { headers: { Authorization: `Bearer ${this.token}`, - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() } }); if (resp.ok) { diff --git a/codex/bundle/session-start-setup.js b/codex/bundle/session-start-setup.js index 166c22b7..4cd8459b 100755 --- a/codex/bundle/session-start-setup.js +++ b/codex/bundle/session-start-setup.js @@ -11,6 +11,26 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync } from " import { join } from "node:path"; import { homedir } from "node:os"; import { execSync } from "node:child_process"; + +// dist/src/utils/client-header.js +function pluginVersion() { + try { + if ("0.6.45") { + return "0.6.45"; + } + } catch { + } + return "dev"; +} +var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; +function deeplakeClientValue() { + return `hivemind/${pluginVersion()}`; +} +function deeplakeClientHeader() { + return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; +} + +// dist/src/commands/auth.js var CONFIG_DIR = join(homedir(), ".deeplake"); var CREDS_PATH = join(CONFIG_DIR, "credentials.json"); function loadCredentials() { @@ -198,7 +218,8 @@ var DeeplakeApi = class { headers: { Authorization: `Bearer ${this.token}`, "Content-Type": "application/json", - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() }, signal, body: JSON.stringify({ query: sql }) @@ -350,7 +371,8 @@ var DeeplakeApi = class { const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, { headers: { Authorization: `Bearer ${this.token}`, - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() } }); if (resp.ok) { diff --git a/codex/bundle/shell/deeplake-shell.js b/codex/bundle/shell/deeplake-shell.js index 7e140a93..3d786e92 100755 --- a/codex/bundle/shell/deeplake-shell.js +++ b/codex/bundle/shell/deeplake-shell.js @@ -66779,6 +66779,24 @@ function sqlLike(value) { return sqlStr(value).replace(/%/g, "\\%").replace(/_/g, "\\_"); } +// dist/src/utils/client-header.js +function pluginVersion() { + try { + if ("0.6.45") { + return "0.6.45"; + } + } catch { + } + return "dev"; +} +var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; +function deeplakeClientValue() { + return `hivemind/${pluginVersion()}`; +} +function deeplakeClientHeader() { + return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; +} + // dist/src/deeplake-api.js var log2 = (msg) => log("sdk", msg); function summarizeSql(sql, maxLen = 220) { @@ -66890,7 +66908,8 @@ var DeeplakeApi = class { headers: { Authorization: `Bearer ${this.token}`, "Content-Type": "application/json", - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() }, signal, body: JSON.stringify({ query: sql }) @@ -67042,7 +67061,8 @@ var DeeplakeApi = class { const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, { headers: { Authorization: `Bearer ${this.token}`, - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() } }); if (resp.ok) { diff --git a/codex/bundle/stop.js b/codex/bundle/stop.js index 729c2c4d..11df7022 100755 --- a/codex/bundle/stop.js +++ b/codex/bundle/stop.js @@ -79,6 +79,24 @@ function sqlStr(value) { return value.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/\0/g, "").replace(/[\x01-\x08\x0b\x0c\x0e-\x1f\x7f]/g, ""); } +// dist/src/utils/client-header.js +function pluginVersion() { + try { + if ("0.6.45") { + return "0.6.45"; + } + } catch { + } + return "dev"; +} +var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; +function deeplakeClientValue() { + return `hivemind/${pluginVersion()}`; +} +function deeplakeClientHeader() { + return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; +} + // dist/src/deeplake-api.js var log2 = (msg) => log("sdk", msg); function summarizeSql(sql, maxLen = 220) { @@ -190,7 +208,8 @@ var DeeplakeApi = class { headers: { Authorization: `Bearer ${this.token}`, "Content-Type": "application/json", - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() }, signal, body: JSON.stringify({ query: sql }) @@ -342,7 +361,8 @@ var DeeplakeApi = class { const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, { headers: { Authorization: `Bearer ${this.token}`, - "X-Activeloop-Org-Id": this.orgId + "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader() } }); if (resp.ok) { diff --git a/codex/bundle/wiki-worker.js b/codex/bundle/wiki-worker.js index bf134ede..1337c939 100755 --- a/codex/bundle/wiki-worker.js +++ b/codex/bundle/wiki-worker.js @@ -129,6 +129,24 @@ async function uploadSummary(query2, params) { return { path: "insert", sql, descLength: desc.length, summaryLength: text.length }; } +// dist/src/utils/client-header.js +function pluginVersion() { + try { + if ("0.6.45") { + return "0.6.45"; + } + } catch { + } + return "dev"; +} +var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; +function deeplakeClientValue() { + return `hivemind/${pluginVersion()}`; +} +function deeplakeClientHeader() { + return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; +} + // dist/src/hooks/codex/wiki-worker.js var dlog2 = (msg) => log("codex-wiki-worker", msg); var cfg = JSON.parse(readFileSync2(process.argv[2], "utf-8")); @@ -153,7 +171,8 @@ async function query(sql, retries = 4) { headers: { Authorization: `Bearer ${cfg.token}`, "Content-Type": "application/json", - "X-Activeloop-Org-Id": cfg.orgId + "X-Activeloop-Org-Id": cfg.orgId, + ...deeplakeClientHeader() }, body: JSON.stringify({ query: sql }) }); diff --git a/esbuild.config.mjs b/esbuild.config.mjs index 54d5fedd..b357a482 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -2,6 +2,7 @@ import { build } from "esbuild"; import { chmodSync, writeFileSync, readFileSync } from "node:fs"; const esmPackageJson = '{"type":"module"}\n'; +const hivemindVersion = JSON.parse(readFileSync("package.json", "utf-8")).version; const openclawVersion = JSON.parse(readFileSync("openclaw/package.json", "utf-8")).version; // Claude Code plugin @@ -31,6 +32,9 @@ await build({ format: "esm", outdir: "claude-code/bundle", external: ["node:*", "node-liblzma", "@mongodb-js/zstd"], + define: { + __HIVEMIND_VERSION__: JSON.stringify(hivemindVersion), + }, }); for (const h of ccAll) { @@ -65,6 +69,9 @@ await build({ format: "esm", outdir: "codex/bundle", external: ["node:*", "node-liblzma", "@mongodb-js/zstd"], + define: { + __HIVEMIND_VERSION__: JSON.stringify(hivemindVersion), + }, }); for (const h of codexAll) { diff --git a/src/commands/auth.ts b/src/commands/auth.ts index 1519f582..67e859f9 100644 --- a/src/commands/auth.ts +++ b/src/commands/auth.ts @@ -7,6 +7,7 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync } from " import { join } from "node:path"; import { homedir } from "node:os"; import { execSync } from "node:child_process"; +import { deeplakeClientHeader } from "../utils/client-header.js"; const CONFIG_DIR = join(homedir(), ".deeplake"); const CREDS_PATH = join(CONFIG_DIR, "credentials.json"); @@ -88,6 +89,7 @@ async function apiGet(path: string, token: string, apiUrl: string, orgId?: strin const headers: Record = { Authorization: `Bearer ${token}`, "Content-Type": "application/json", + ...deeplakeClientHeader(), }; if (orgId) headers["X-Activeloop-Org-Id"] = orgId; const resp = await fetch(`${apiUrl}${path}`, { headers }); @@ -99,6 +101,7 @@ async function apiPost(path: string, body: unknown, token: string, apiUrl: strin const headers: Record = { Authorization: `Bearer ${token}`, "Content-Type": "application/json", + ...deeplakeClientHeader(), }; if (orgId) headers["X-Activeloop-Org-Id"] = orgId; const resp = await fetch(`${apiUrl}${path}`, { method: "POST", headers, body: JSON.stringify(body) }); @@ -110,6 +113,7 @@ async function apiDelete(path: string, token: string, apiUrl: string, orgId?: st const headers: Record = { Authorization: `Bearer ${token}`, "Content-Type": "application/json", + ...deeplakeClientHeader(), }; if (orgId) headers["X-Activeloop-Org-Id"] = orgId; const resp = await fetch(`${apiUrl}${path}`, { method: "DELETE", headers }); @@ -121,7 +125,7 @@ async function apiDelete(path: string, token: string, apiUrl: string, orgId?: st export async function requestDeviceCode(apiUrl = DEFAULT_API_URL): Promise { const resp = await fetch(`${apiUrl}/auth/device/code`, { method: "POST", - headers: { "Content-Type": "application/json" }, + headers: { "Content-Type": "application/json", ...deeplakeClientHeader() }, }); if (!resp.ok) throw new Error(`Device flow unavailable: HTTP ${resp.status}`); return resp.json() as Promise; @@ -130,7 +134,7 @@ export async function requestDeviceCode(apiUrl = DEFAULT_API_URL): Promise { const resp = await fetch(`${apiUrl}/auth/device/token`, { method: "POST", - headers: { "Content-Type": "application/json" }, + headers: { "Content-Type": "application/json", ...deeplakeClientHeader() }, body: JSON.stringify({ device_code: deviceCode }), }); if (resp.ok) return resp.json() as Promise; diff --git a/src/deeplake-api.ts b/src/deeplake-api.ts index 5e763b2a..0bf9895a 100644 --- a/src/deeplake-api.ts +++ b/src/deeplake-api.ts @@ -4,6 +4,7 @@ import { join } from "node:path"; import { tmpdir } from "node:os"; import { log as _log } from "./utils/debug.js"; import { sqlStr } from "./utils/sql.js"; +import { deeplakeClientHeader } from "./utils/client-header.js"; const log = (msg: string) => _log("sdk", msg); @@ -146,6 +147,7 @@ export class DeeplakeApi { Authorization: `Bearer ${this.token}`, "Content-Type": "application/json", "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader(), }, signal, body: JSON.stringify({ query: sql }), @@ -319,6 +321,7 @@ export class DeeplakeApi { headers: { Authorization: `Bearer ${this.token}`, "X-Activeloop-Org-Id": this.orgId, + ...deeplakeClientHeader(), }, }); if (resp.ok) { diff --git a/src/hooks/codex/wiki-worker.ts b/src/hooks/codex/wiki-worker.ts index 7d74f759..73cc86e0 100644 --- a/src/hooks/codex/wiki-worker.ts +++ b/src/hooks/codex/wiki-worker.ts @@ -13,6 +13,7 @@ import { join } from "node:path"; import { finalizeSummary, releaseLock } from "../summary-state.js"; import { uploadSummary } from "../upload-summary.js"; import { log as _log } from "../../utils/debug.js"; +import { deeplakeClientHeader } from "../../utils/client-header.js"; const dlog = (msg: string) => _log("codex-wiki-worker", msg); @@ -60,6 +61,7 @@ async function query(sql: string, retries = 4): Promise[ Authorization: `Bearer ${cfg.token}`, "Content-Type": "application/json", "X-Activeloop-Org-Id": cfg.orgId, + ...deeplakeClientHeader(), }, body: JSON.stringify({ query: sql }), }); diff --git a/src/hooks/wiki-worker.ts b/src/hooks/wiki-worker.ts index 2359ea02..34025403 100644 --- a/src/hooks/wiki-worker.ts +++ b/src/hooks/wiki-worker.ts @@ -11,6 +11,7 @@ import { readFileSync, writeFileSync, existsSync, appendFileSync, mkdirSync, rmS import { execFileSync } from "node:child_process"; import { join } from "node:path"; import { utcTimestamp, log as _log } from "../utils/debug.js"; +import { deeplakeClientHeader } from "../utils/client-header.js"; const dlog = (msg: string) => _log("wiki-worker", msg); import { finalizeSummary, releaseLock } from "./summary-state.js"; @@ -61,6 +62,7 @@ async function query(sql: string, retries = 4): Promise[ Authorization: `Bearer ${cfg.token}`, "Content-Type": "application/json", "X-Activeloop-Org-Id": cfg.orgId, + ...deeplakeClientHeader(), }, body: JSON.stringify({ query: sql }), }); diff --git a/src/utils/client-header.ts b/src/utils/client-header.ts new file mode 100644 index 00000000..cc859ed7 --- /dev/null +++ b/src/utils/client-header.ts @@ -0,0 +1,34 @@ +/** + * X-Deeplake-Client header helper. + * + * The deeplake-api backend reads X-Deeplake-Client to attribute traffic + * (analytics source + engagement metrics). Every outbound request to + * deeplake-api should carry this header; without it, hivemind traffic + * looks indistinguishable from the activeloop-cli / device-code flow. + * + * __HIVEMIND_VERSION__ is a build-time constant injected by esbuild + * (see esbuild.config.mjs). In dev (tsx, vitest) the constant is not + * defined, so we fall back to "dev". + */ +declare const __HIVEMIND_VERSION__: string; + +function pluginVersion(): string { + try { + if (typeof __HIVEMIND_VERSION__ === "string" && __HIVEMIND_VERSION__) { + return __HIVEMIND_VERSION__; + } + } catch { /* reference error in unbundled dev → fall through */ } + return "dev"; +} + +export const DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; + +/** Returns "hivemind/" — the value for the X-Deeplake-Client header. */ +export function deeplakeClientValue(): string { + return `hivemind/${pluginVersion()}`; +} + +/** Returns { "X-Deeplake-Client": "hivemind/" } for spreading into a headers object. */ +export function deeplakeClientHeader(): Record { + return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; +} From 00d73bc9bf2772456ac4ff23028c9af3a3c3dc34 Mon Sep 17 00:00:00 2001 From: kaghni Date: Wed, 22 Apr 2026 22:48:06 -0700 Subject: [PATCH 2/4] cover the openclaw plugin: send X-Deeplake-Client on the API-token fetch too OpenClaw is the same product as hivemind analytics-wise (same install base per user, same retention story), so it sends the same "hivemind/" value via the shared helper. Only one outbound deeplake-api call (POST /users/me/tokens) needed the change; openclaw already has __HIVEMIND_VERSION__ defined by esbuild so no config changes. openclaw/dist/ is gitignored; rebuilds at release time. --- openclaw/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openclaw/src/index.ts b/openclaw/src/index.ts index 5170f8b3..ebe5c7b0 100644 --- a/openclaw/src/index.ts +++ b/openclaw/src/index.ts @@ -4,6 +4,7 @@ import { loadConfig } from "../../src/config.js"; import { loadCredentials, saveCredentials, requestDeviceCode, pollForToken, listOrgs, switchOrg, listWorkspaces, switchWorkspace } from "../../src/commands/auth.js"; import { DeeplakeApi } from "../../src/deeplake-api.js"; import { sqlStr, sqlLike } from "../../src/utils/sql.js"; +import { deeplakeClientHeader } from "../../src/utils/client-header.js"; interface PluginConfig { autoCapture?: boolean; @@ -108,6 +109,7 @@ async function requestAuth(): Promise { Authorization: `Bearer ${token}`, "Content-Type": "application/json", "X-Activeloop-Org-Id": orgId, + ...deeplakeClientHeader(), }, body: JSON.stringify({ name: `hivemind-${new Date().toISOString().split("T")[0]}`, duration: 365 * 24 * 60 * 60, organization_id: orgId }), }); From dbb7386d980084fc8e2a63364086de7d38b449ed Mon Sep 17 00:00:00 2001 From: kaghni Date: Tue, 28 Apr 2026 00:03:04 -0700 Subject: [PATCH 3/4] client-header: drop unnecessary try/catch + rebuild bundles post-merge typeof on an undeclared identifier returns "undefined", it never throws ReferenceError. The try/catch wrapper around the __HIVEMIND_VERSION__ guard was dead code (caught block could never execute). Replace with a plain typeof check + clearer comment explaining why the guard exists. Also rebuilds CC + Codex bundles after merging origin/main so the shipped artifacts reflect the new dist/ output. Marketplace bundle version stays in sync with package.json (now 0.6.48). --- claude-code/bundle/capture.js | 7 ++----- claude-code/bundle/commands/auth-login.js | 7 ++----- claude-code/bundle/pre-tool-use.js | 7 ++----- claude-code/bundle/session-start-setup.js | 7 ++----- claude-code/bundle/session-start.js | 7 ++----- claude-code/bundle/shell/deeplake-shell.js | 7 ++----- claude-code/bundle/wiki-worker.js | 7 ++----- codex/bundle/capture.js | 7 ++----- codex/bundle/commands/auth-login.js | 7 ++----- codex/bundle/pre-tool-use.js | 7 ++----- codex/bundle/session-start-setup.js | 7 ++----- codex/bundle/shell/deeplake-shell.js | 7 ++----- codex/bundle/stop.js | 7 ++----- codex/bundle/wiki-worker.js | 7 ++----- 14 files changed, 28 insertions(+), 70 deletions(-) diff --git a/claude-code/bundle/capture.js b/claude-code/bundle/capture.js index 41b9eaa4..30e47907 100755 --- a/claude-code/bundle/capture.js +++ b/claude-code/bundle/capture.js @@ -78,11 +78,8 @@ function sqlStr(value) { // dist/src/utils/client-header.js function pluginVersion() { - try { - if ("0.6.45") { - return "0.6.45"; - } - } catch { + if ("0.6.48") { + return "0.6.48"; } return "dev"; } diff --git a/claude-code/bundle/commands/auth-login.js b/claude-code/bundle/commands/auth-login.js index 9770442c..c72aea68 100755 --- a/claude-code/bundle/commands/auth-login.js +++ b/claude-code/bundle/commands/auth-login.js @@ -8,11 +8,8 @@ import { execSync } from "node:child_process"; // dist/src/utils/client-header.js function pluginVersion() { - try { - if ("0.6.45") { - return "0.6.45"; - } - } catch { + if ("0.6.48") { + return "0.6.48"; } return "dev"; } diff --git a/claude-code/bundle/pre-tool-use.js b/claude-code/bundle/pre-tool-use.js index cc0ad712..ba15aeca 100755 --- a/claude-code/bundle/pre-tool-use.js +++ b/claude-code/bundle/pre-tool-use.js @@ -84,11 +84,8 @@ function sqlLike(value) { // dist/src/utils/client-header.js function pluginVersion() { - try { - if ("0.6.45") { - return "0.6.45"; - } - } catch { + if ("0.6.48") { + return "0.6.48"; } return "dev"; } diff --git a/claude-code/bundle/session-start-setup.js b/claude-code/bundle/session-start-setup.js index 96f4fd0f..56cb52f0 100755 --- a/claude-code/bundle/session-start-setup.js +++ b/claude-code/bundle/session-start-setup.js @@ -14,11 +14,8 @@ import { execSync } from "node:child_process"; // dist/src/utils/client-header.js function pluginVersion() { - try { - if ("0.6.45") { - return "0.6.45"; - } - } catch { + if ("0.6.48") { + return "0.6.48"; } return "dev"; } diff --git a/claude-code/bundle/session-start.js b/claude-code/bundle/session-start.js index c8f60cad..94f9b3b0 100755 --- a/claude-code/bundle/session-start.js +++ b/claude-code/bundle/session-start.js @@ -14,11 +14,8 @@ import { execSync } from "node:child_process"; // dist/src/utils/client-header.js function pluginVersion() { - try { - if ("0.6.45") { - return "0.6.45"; - } - } catch { + if ("0.6.48") { + return "0.6.48"; } return "dev"; } diff --git a/claude-code/bundle/shell/deeplake-shell.js b/claude-code/bundle/shell/deeplake-shell.js index 3d786e92..64d1b3a5 100755 --- a/claude-code/bundle/shell/deeplake-shell.js +++ b/claude-code/bundle/shell/deeplake-shell.js @@ -66781,11 +66781,8 @@ function sqlLike(value) { // dist/src/utils/client-header.js function pluginVersion() { - try { - if ("0.6.45") { - return "0.6.45"; - } - } catch { + if ("0.6.48") { + return "0.6.48"; } return "dev"; } diff --git a/claude-code/bundle/wiki-worker.js b/claude-code/bundle/wiki-worker.js index c36f1a8b..9d61142f 100755 --- a/claude-code/bundle/wiki-worker.js +++ b/claude-code/bundle/wiki-worker.js @@ -23,11 +23,8 @@ function log(tag, msg) { // dist/src/utils/client-header.js function pluginVersion() { - try { - if ("0.6.45") { - return "0.6.45"; - } - } catch { + if ("0.6.48") { + return "0.6.48"; } return "dev"; } diff --git a/codex/bundle/capture.js b/codex/bundle/capture.js index bb09a547..c0b01e18 100755 --- a/codex/bundle/capture.js +++ b/codex/bundle/capture.js @@ -78,11 +78,8 @@ function sqlStr(value) { // dist/src/utils/client-header.js function pluginVersion() { - try { - if ("0.6.45") { - return "0.6.45"; - } - } catch { + if ("0.6.48") { + return "0.6.48"; } return "dev"; } diff --git a/codex/bundle/commands/auth-login.js b/codex/bundle/commands/auth-login.js index 9770442c..c72aea68 100755 --- a/codex/bundle/commands/auth-login.js +++ b/codex/bundle/commands/auth-login.js @@ -8,11 +8,8 @@ import { execSync } from "node:child_process"; // dist/src/utils/client-header.js function pluginVersion() { - try { - if ("0.6.45") { - return "0.6.45"; - } - } catch { + if ("0.6.48") { + return "0.6.48"; } return "dev"; } diff --git a/codex/bundle/pre-tool-use.js b/codex/bundle/pre-tool-use.js index c348ae02..19c8ab2d 100755 --- a/codex/bundle/pre-tool-use.js +++ b/codex/bundle/pre-tool-use.js @@ -84,11 +84,8 @@ function sqlLike(value) { // dist/src/utils/client-header.js function pluginVersion() { - try { - if ("0.6.45") { - return "0.6.45"; - } - } catch { + if ("0.6.48") { + return "0.6.48"; } return "dev"; } diff --git a/codex/bundle/session-start-setup.js b/codex/bundle/session-start-setup.js index 4cd8459b..371d67af 100755 --- a/codex/bundle/session-start-setup.js +++ b/codex/bundle/session-start-setup.js @@ -14,11 +14,8 @@ import { execSync } from "node:child_process"; // dist/src/utils/client-header.js function pluginVersion() { - try { - if ("0.6.45") { - return "0.6.45"; - } - } catch { + if ("0.6.48") { + return "0.6.48"; } return "dev"; } diff --git a/codex/bundle/shell/deeplake-shell.js b/codex/bundle/shell/deeplake-shell.js index 3d786e92..64d1b3a5 100755 --- a/codex/bundle/shell/deeplake-shell.js +++ b/codex/bundle/shell/deeplake-shell.js @@ -66781,11 +66781,8 @@ function sqlLike(value) { // dist/src/utils/client-header.js function pluginVersion() { - try { - if ("0.6.45") { - return "0.6.45"; - } - } catch { + if ("0.6.48") { + return "0.6.48"; } return "dev"; } diff --git a/codex/bundle/stop.js b/codex/bundle/stop.js index 55acb81d..e2b5c4e2 100755 --- a/codex/bundle/stop.js +++ b/codex/bundle/stop.js @@ -81,11 +81,8 @@ function sqlStr(value) { // dist/src/utils/client-header.js function pluginVersion() { - try { - if ("0.6.45") { - return "0.6.45"; - } - } catch { + if ("0.6.48") { + return "0.6.48"; } return "dev"; } diff --git a/codex/bundle/wiki-worker.js b/codex/bundle/wiki-worker.js index 1337c939..51ebf1ed 100755 --- a/codex/bundle/wiki-worker.js +++ b/codex/bundle/wiki-worker.js @@ -131,11 +131,8 @@ async function uploadSummary(query2, params) { // dist/src/utils/client-header.js function pluginVersion() { - try { - if ("0.6.45") { - return "0.6.45"; - } - } catch { + if ("0.6.48") { + return "0.6.48"; } return "dev"; } From 3bea735f5f7ecde3c75ce06f296de36375fef57c Mon Sep 17 00:00:00 2001 From: kaghni Date: Tue, 28 Apr 2026 00:14:14 -0700 Subject: [PATCH 4/4] client-header: drop dead-code guard; use vitest define for parity The post-substitution bundle had an always-true conditional: if ("0.6.48") { return "0.6.48"; } Useless at runtime and confusing on read. Root cause: source code wrote a typeof guard so vitest (where esbuild's define hadn't run) could fall back to "dev" without a ReferenceError. Better fix: mirror the esbuild define in vitest.config.ts so tests also get __HIVEMIND_VERSION__ substituted (with the literal "dev"), then drop the guard at the source. Bundles now emit a clean return \`hivemind/\${"0.6.48"}\`; which becomes "hivemind/0.6.48" at runtime with no dead branches. --- claude-code/bundle/capture.js | 8 +------- claude-code/bundle/commands/auth-login.js | 8 +------- claude-code/bundle/pre-tool-use.js | 8 +------- claude-code/bundle/session-start-setup.js | 8 +------- claude-code/bundle/session-start.js | 8 +------- claude-code/bundle/shell/deeplake-shell.js | 8 +------- claude-code/bundle/wiki-worker.js | 8 +------- codex/bundle/capture.js | 8 +------- codex/bundle/commands/auth-login.js | 8 +------- codex/bundle/pre-tool-use.js | 8 +------- codex/bundle/session-start-setup.js | 8 +------- codex/bundle/shell/deeplake-shell.js | 8 +------- codex/bundle/stop.js | 8 +------- codex/bundle/wiki-worker.js | 8 +------- src/utils/client-header.ts | 19 +++++-------------- vitest.config.ts | 7 +++++++ 16 files changed, 26 insertions(+), 112 deletions(-) diff --git a/claude-code/bundle/capture.js b/claude-code/bundle/capture.js index 30e47907..8b550a9d 100755 --- a/claude-code/bundle/capture.js +++ b/claude-code/bundle/capture.js @@ -77,15 +77,9 @@ function sqlStr(value) { } // dist/src/utils/client-header.js -function pluginVersion() { - if ("0.6.48") { - return "0.6.48"; - } - return "dev"; -} var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; function deeplakeClientValue() { - return `hivemind/${pluginVersion()}`; + return `hivemind/${"0.6.48"}`; } function deeplakeClientHeader() { return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; diff --git a/claude-code/bundle/commands/auth-login.js b/claude-code/bundle/commands/auth-login.js index c72aea68..8caea41f 100755 --- a/claude-code/bundle/commands/auth-login.js +++ b/claude-code/bundle/commands/auth-login.js @@ -7,15 +7,9 @@ import { homedir } from "node:os"; import { execSync } from "node:child_process"; // dist/src/utils/client-header.js -function pluginVersion() { - if ("0.6.48") { - return "0.6.48"; - } - return "dev"; -} var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; function deeplakeClientValue() { - return `hivemind/${pluginVersion()}`; + return `hivemind/${"0.6.48"}`; } function deeplakeClientHeader() { return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; diff --git a/claude-code/bundle/pre-tool-use.js b/claude-code/bundle/pre-tool-use.js index ba15aeca..9c281166 100755 --- a/claude-code/bundle/pre-tool-use.js +++ b/claude-code/bundle/pre-tool-use.js @@ -83,15 +83,9 @@ function sqlLike(value) { } // dist/src/utils/client-header.js -function pluginVersion() { - if ("0.6.48") { - return "0.6.48"; - } - return "dev"; -} var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; function deeplakeClientValue() { - return `hivemind/${pluginVersion()}`; + return `hivemind/${"0.6.48"}`; } function deeplakeClientHeader() { return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; diff --git a/claude-code/bundle/session-start-setup.js b/claude-code/bundle/session-start-setup.js index 56cb52f0..9f2430e8 100755 --- a/claude-code/bundle/session-start-setup.js +++ b/claude-code/bundle/session-start-setup.js @@ -13,15 +13,9 @@ import { homedir } from "node:os"; import { execSync } from "node:child_process"; // dist/src/utils/client-header.js -function pluginVersion() { - if ("0.6.48") { - return "0.6.48"; - } - return "dev"; -} var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; function deeplakeClientValue() { - return `hivemind/${pluginVersion()}`; + return `hivemind/${"0.6.48"}`; } function deeplakeClientHeader() { return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; diff --git a/claude-code/bundle/session-start.js b/claude-code/bundle/session-start.js index 94f9b3b0..199bbf30 100755 --- a/claude-code/bundle/session-start.js +++ b/claude-code/bundle/session-start.js @@ -13,15 +13,9 @@ import { homedir } from "node:os"; import { execSync } from "node:child_process"; // dist/src/utils/client-header.js -function pluginVersion() { - if ("0.6.48") { - return "0.6.48"; - } - return "dev"; -} var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; function deeplakeClientValue() { - return `hivemind/${pluginVersion()}`; + return `hivemind/${"0.6.48"}`; } function deeplakeClientHeader() { return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; diff --git a/claude-code/bundle/shell/deeplake-shell.js b/claude-code/bundle/shell/deeplake-shell.js index 64d1b3a5..df3dbefa 100755 --- a/claude-code/bundle/shell/deeplake-shell.js +++ b/claude-code/bundle/shell/deeplake-shell.js @@ -66780,15 +66780,9 @@ function sqlLike(value) { } // dist/src/utils/client-header.js -function pluginVersion() { - if ("0.6.48") { - return "0.6.48"; - } - return "dev"; -} var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; function deeplakeClientValue() { - return `hivemind/${pluginVersion()}`; + return `hivemind/${"0.6.48"}`; } function deeplakeClientHeader() { return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; diff --git a/claude-code/bundle/wiki-worker.js b/claude-code/bundle/wiki-worker.js index 9d61142f..f28a15ec 100755 --- a/claude-code/bundle/wiki-worker.js +++ b/claude-code/bundle/wiki-worker.js @@ -22,15 +22,9 @@ function log(tag, msg) { } // dist/src/utils/client-header.js -function pluginVersion() { - if ("0.6.48") { - return "0.6.48"; - } - return "dev"; -} var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; function deeplakeClientValue() { - return `hivemind/${pluginVersion()}`; + return `hivemind/${"0.6.48"}`; } function deeplakeClientHeader() { return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; diff --git a/codex/bundle/capture.js b/codex/bundle/capture.js index c0b01e18..a1844518 100755 --- a/codex/bundle/capture.js +++ b/codex/bundle/capture.js @@ -77,15 +77,9 @@ function sqlStr(value) { } // dist/src/utils/client-header.js -function pluginVersion() { - if ("0.6.48") { - return "0.6.48"; - } - return "dev"; -} var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; function deeplakeClientValue() { - return `hivemind/${pluginVersion()}`; + return `hivemind/${"0.6.48"}`; } function deeplakeClientHeader() { return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; diff --git a/codex/bundle/commands/auth-login.js b/codex/bundle/commands/auth-login.js index c72aea68..8caea41f 100755 --- a/codex/bundle/commands/auth-login.js +++ b/codex/bundle/commands/auth-login.js @@ -7,15 +7,9 @@ import { homedir } from "node:os"; import { execSync } from "node:child_process"; // dist/src/utils/client-header.js -function pluginVersion() { - if ("0.6.48") { - return "0.6.48"; - } - return "dev"; -} var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; function deeplakeClientValue() { - return `hivemind/${pluginVersion()}`; + return `hivemind/${"0.6.48"}`; } function deeplakeClientHeader() { return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; diff --git a/codex/bundle/pre-tool-use.js b/codex/bundle/pre-tool-use.js index 19c8ab2d..beb5eac1 100755 --- a/codex/bundle/pre-tool-use.js +++ b/codex/bundle/pre-tool-use.js @@ -83,15 +83,9 @@ function sqlLike(value) { } // dist/src/utils/client-header.js -function pluginVersion() { - if ("0.6.48") { - return "0.6.48"; - } - return "dev"; -} var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; function deeplakeClientValue() { - return `hivemind/${pluginVersion()}`; + return `hivemind/${"0.6.48"}`; } function deeplakeClientHeader() { return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; diff --git a/codex/bundle/session-start-setup.js b/codex/bundle/session-start-setup.js index 371d67af..6a40ec13 100755 --- a/codex/bundle/session-start-setup.js +++ b/codex/bundle/session-start-setup.js @@ -13,15 +13,9 @@ import { homedir } from "node:os"; import { execSync } from "node:child_process"; // dist/src/utils/client-header.js -function pluginVersion() { - if ("0.6.48") { - return "0.6.48"; - } - return "dev"; -} var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; function deeplakeClientValue() { - return `hivemind/${pluginVersion()}`; + return `hivemind/${"0.6.48"}`; } function deeplakeClientHeader() { return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; diff --git a/codex/bundle/shell/deeplake-shell.js b/codex/bundle/shell/deeplake-shell.js index 64d1b3a5..df3dbefa 100755 --- a/codex/bundle/shell/deeplake-shell.js +++ b/codex/bundle/shell/deeplake-shell.js @@ -66780,15 +66780,9 @@ function sqlLike(value) { } // dist/src/utils/client-header.js -function pluginVersion() { - if ("0.6.48") { - return "0.6.48"; - } - return "dev"; -} var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; function deeplakeClientValue() { - return `hivemind/${pluginVersion()}`; + return `hivemind/${"0.6.48"}`; } function deeplakeClientHeader() { return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; diff --git a/codex/bundle/stop.js b/codex/bundle/stop.js index e2b5c4e2..e6c9ef68 100755 --- a/codex/bundle/stop.js +++ b/codex/bundle/stop.js @@ -80,15 +80,9 @@ function sqlStr(value) { } // dist/src/utils/client-header.js -function pluginVersion() { - if ("0.6.48") { - return "0.6.48"; - } - return "dev"; -} var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; function deeplakeClientValue() { - return `hivemind/${pluginVersion()}`; + return `hivemind/${"0.6.48"}`; } function deeplakeClientHeader() { return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; diff --git a/codex/bundle/wiki-worker.js b/codex/bundle/wiki-worker.js index 51ebf1ed..3eca1881 100755 --- a/codex/bundle/wiki-worker.js +++ b/codex/bundle/wiki-worker.js @@ -130,15 +130,9 @@ async function uploadSummary(query2, params) { } // dist/src/utils/client-header.js -function pluginVersion() { - if ("0.6.48") { - return "0.6.48"; - } - return "dev"; -} var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; function deeplakeClientValue() { - return `hivemind/${pluginVersion()}`; + return `hivemind/${"0.6.48"}`; } function deeplakeClientHeader() { return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() }; diff --git a/src/utils/client-header.ts b/src/utils/client-header.ts index 71594d17..60d76f68 100644 --- a/src/utils/client-header.ts +++ b/src/utils/client-header.ts @@ -6,27 +6,18 @@ * deeplake-api should carry this header; without it, hivemind traffic * looks indistinguishable from the activeloop-cli / device-code flow. * - * __HIVEMIND_VERSION__ is a build-time constant injected by esbuild - * (see esbuild.config.mjs). In dev (tsx, vitest) the constant is not - * defined, so we fall back to "dev". + * __HIVEMIND_VERSION__ is replaced at build/test time: + * - production bundles: esbuild.config.mjs sets it to the real package.json version + * - vitest: vitest.config.ts sets it to "dev" + * Source code therefore reads it directly, no runtime guard needed. */ declare const __HIVEMIND_VERSION__: string; -function pluginVersion(): string { - // typeof on an undeclared identifier returns "undefined" (never throws), - // so unbundled dev runs (where esbuild's define hasn't run) fall through - // to the "dev" sentinel without needing an exception handler. - if (typeof __HIVEMIND_VERSION__ === "string" && __HIVEMIND_VERSION__) { - return __HIVEMIND_VERSION__; - } - return "dev"; -} - export const DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client"; /** Returns "hivemind/" — the value for the X-Deeplake-Client header. */ export function deeplakeClientValue(): string { - return `hivemind/${pluginVersion()}`; + return `hivemind/${__HIVEMIND_VERSION__}`; } /** Returns { "X-Deeplake-Client": "hivemind/" } for spreading into a headers object. */ diff --git a/vitest.config.ts b/vitest.config.ts index 882e6e09..c11efce7 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -10,6 +10,13 @@ import { defineConfig } from "vitest/config"; // that hides regressions in new code. export default defineConfig({ + // Match esbuild's `define` for __HIVEMIND_VERSION__ so source files that + // read it directly (e.g. src/utils/client-header.ts) don't need a typeof + // guard for tests. Bundled builds substitute the real version; tests get + // the "dev" sentinel. + define: { + __HIVEMIND_VERSION__: JSON.stringify("dev"), + }, test: { include: [ "claude-code/tests/**/*.test.ts",