dsh-context-mode 0.2.0 → 0.2.2

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.
@@ -72,8 +72,23 @@ import { resolveProjectDir } from "./util/project-dir.js";
72
72
  import { loadDatabase } from "./db-base.js";
73
73
  import { AnalyticsEngine, formatReport, getConversationStats, getContentBytesAllSessions, getConversationWindowStats, getLifetimeStats, getMultiAdapterLifetimeStats, getRealBytesStats, pricePerToken } from "./session/analytics.js";
74
74
  const __pkg_dir = dirname(fileURLToPath(import.meta.url));
75
+ /**
76
+ * Version of the engine this bundle was built from.
77
+ *
78
+ * The bundle is a single file, so the directory walk below resolves against
79
+ * wherever it happens to sit. It looks for the vendored `package.json` (the
80
+ * dsh-context-mode layout), then the upstream package layout, then the classic
81
+ * installed-package layouts. `CONTEXT_MODE_VERSION` overrides everything, which
82
+ * is how a host pins the reported version without shipping a package.json.
83
+ */
75
84
  const VERSION: string = (() => {
76
- for (const rel of ["../package.json", "./package.json"]) {
85
+ const override = process.env.CONTEXT_MODE_VERSION;
86
+ if (override !== undefined && override.trim().length > 0) return override.trim();
87
+ for (const rel of [
88
+ "../../package.json", // vendor/context-mode/server.bundle.mjs → package root
89
+ "../package.json", // upstream build/ layout
90
+ "./package.json",
91
+ ]) {
77
92
  const p = resolve(__pkg_dir, rel);
78
93
  if (existsSync(p)) {
79
94
  try { return JSON.parse(readFileSync(p, "utf8")).version; } catch {}
@@ -82,6 +97,20 @@ const VERSION: string = (() => {
82
97
  return "unknown";
83
98
  })();
84
99
 
100
+ /**
101
+ * Whether this build should check npm for a newer upstream release.
102
+ *
103
+ * This fork ships its own engine, so the published `context-mode` version is
104
+ * not a valid upgrade target: reporting it as "outdated" is noise, and the
105
+ * upgrade command it suggests would replace this build with a different
106
+ * engine. The check is therefore OFF by default and baked in at build time.
107
+ *
108
+ * Set `CONTEXT_MODE_UPSTREAM_CHECK=1` at runtime to re-enable it for an
109
+ * upstream-style deployment built from this source.
110
+ */
111
+ const UPSTREAM_CHECK_ENABLED: boolean =
112
+ process.env.CONTEXT_MODE_UPSTREAM_CHECK === "1";
113
+
85
114
  function getPackageRoot(): string {
86
115
  return existsSync(resolve(__pkg_dir, "package.json")) ? __pkg_dir : dirname(__pkg_dir);
87
116
  }
@@ -800,6 +829,7 @@ async function fetchLatestVersion(): Promise<string> {
800
829
  }
801
830
 
802
831
  function getUpgradeHint(): string {
832
+ if (!UPSTREAM_CHECK_ENABLED) return "upgrade dsh-context-mode";
803
833
  const name = _detectedAdapter?.name;
804
834
  if (name === "Claude Code") return "/ctx-upgrade";
805
835
  if (name === "OpenClaw") return "npm run install:openclaw";
@@ -818,6 +848,7 @@ function semverNewer(a: string, b: string): boolean {
818
848
  }
819
849
 
820
850
  function isOutdated(): boolean {
851
+ if (!UPSTREAM_CHECK_ENABLED) return false;
821
852
  if (!_latestVersion || _latestVersion === "unknown") return false;
822
853
  return semverNewer(_latestVersion, VERSION);
823
854
  }
@@ -4334,6 +4365,33 @@ server.registerTool(
4334
4365
  } catch { /* best effort — don't block upgrade */ }
4335
4366
 
4336
4367
 
4368
+ // A self-contained fork upgrades itself, not the upstream npm package.
4369
+ // Returning the upstream upgrade command here would replace this build
4370
+ // with a different engine, so answer with the fork's own instructions.
4371
+ if (!UPSTREAM_CHECK_ENABLED) {
4372
+ return trackResponse("ctx_upgrade", {
4373
+ content: [{
4374
+ type: "text",
4375
+ text: [
4376
+ "## ctx-upgrade",
4377
+ "",
4378
+ "This build is self-contained: the engine is vendored and the package ships",
4379
+ "its own bundle, so there is no upstream package to update.",
4380
+ "",
4381
+ "To upgrade, run this command with your shell tool and show the output as a checklist:",
4382
+ "",
4383
+ "```",
4384
+ "npm install -g dsh-context-mode@latest",
4385
+ "```",
4386
+ "",
4387
+ "Then tell the user to restart their DSH session so the new bundle is loaded.",
4388
+ "",
4389
+ `Current engine version: ${VERSION}`,
4390
+ ].join("\n"),
4391
+ }],
4392
+ });
4393
+ }
4394
+
4337
4395
  let cmd: string;
4338
4396
 
4339
4397
  if (existsSync(bundlePath)) {
@@ -4952,11 +5010,14 @@ async function main() {
4952
5010
  // First fetch at startup, then refresh every hour so long-running sessions
4953
5011
  // (some users keep the MCP server alive 24h+) catch new releases without a
4954
5012
  // restart. `.unref()` lets the process exit normally on SIGTERM regardless
4955
- // of pending intervals.
4956
- fetchLatestVersion().then(v => { if (v !== "unknown") _latestVersion = v; });
4957
- setInterval(() => {
5013
+ // of pending intervals. A self-contained fork skips the network check
5014
+ // entirely: the published upstream version is not its upgrade target.
5015
+ if (UPSTREAM_CHECK_ENABLED) {
4958
5016
  fetchLatestVersion().then(v => { if (v !== "unknown") _latestVersion = v; });
4959
- }, 60 * 60 * 1000).unref();
5017
+ setInterval(() => {
5018
+ fetchLatestVersion().then(v => { if (v !== "unknown") _latestVersion = v; });
5019
+ }, 60 * 60 * 1000).unref();
5020
+ }
4960
5021
 
4961
5022
  // Stats heartbeat — keep the statusline truthful while the user works in
4962
5023
  // tools other than MCP (Bash/Read/Edit during long sessions or post-/compact