opencode-dux 1.0.0 → 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/dist/index.js CHANGED
@@ -18186,8 +18186,9 @@ var require_turndown_cjs = __commonJS((exports, module) => {
18186
18186
  });
18187
18187
 
18188
18188
  // src/index.ts
18189
- import { existsSync as existsSync10, readdirSync as readdirSync2 } from "node:fs";
18190
- import { join as join15 } from "node:path";
18189
+ import { existsSync as existsSync10, readFileSync as readFileSync9, readdirSync as readdirSync2 } from "node:fs";
18190
+ import { dirname as dirname7, join as join15 } from "node:path";
18191
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
18191
18192
 
18192
18193
  // src/config/constants.ts
18193
18194
  var AGENT_ALIASES = {
@@ -30931,6 +30932,18 @@ var HEALTH_CHECK = {
30931
30932
  minTools: 5,
30932
30933
  minMcps: 1
30933
30934
  };
30935
+ function readPluginVersion() {
30936
+ try {
30937
+ const modDir = dirname7(fileURLToPath2(import.meta.url));
30938
+ const rootDir = dirname7(modDir);
30939
+ const pkgPath = join15(rootDir, "package.json");
30940
+ if (existsSync10(pkgPath)) {
30941
+ const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
30942
+ return typeof pkg.version === "string" ? pkg.version : null;
30943
+ }
30944
+ } catch {}
30945
+ return null;
30946
+ }
30934
30947
  function asNumber(value) {
30935
30948
  return typeof value === "number" && Number.isFinite(value) ? value : null;
30936
30949
  }
@@ -31251,6 +31264,27 @@ var OhMyOpenCodeLite = async (ctx) => {
31251
31264
  if (isFirstInit) {
31252
31265
  console.log(`✅ opencode-dux initialized (${Object.keys(agents).length} agents, ${toolCount} tools, ${Object.keys(builtinMcps).length} MCPs)`);
31253
31266
  didLogVerboseInit = true;
31267
+ try {
31268
+ const snap = readTuiSnapshot();
31269
+ const savedVersion = snap.pluginVersion;
31270
+ const currentVersion = readPluginVersion();
31271
+ if (savedVersion && currentVersion && savedVersion !== currentVersion) {
31272
+ appLog(ctx, "info", `Updated from v${savedVersion} to v${currentVersion}`).catch(() => {});
31273
+ ctx.client.tui.showToast({
31274
+ body: {
31275
+ title: "OpenCode Dux",
31276
+ message: `Updated to v${currentVersion}`,
31277
+ variant: "info",
31278
+ duration: 5000
31279
+ }
31280
+ }).catch(() => {});
31281
+ }
31282
+ if (currentVersion) {
31283
+ updateSnapshot((s) => {
31284
+ s.pluginVersion = currentVersion;
31285
+ });
31286
+ }
31287
+ } catch {}
31254
31288
  }
31255
31289
  } catch (err) {
31256
31290
  log("[plugin] FATAL: init failed", String(err));
@@ -50,6 +50,7 @@ export interface TuiSessionBundle {
50
50
  }
51
51
  export interface TuiSnapshot {
52
52
  version: 6;
53
+ pluginVersion?: string;
53
54
  updatedAt: number;
54
55
  sessions: Record<string, TuiSessionBundle>;
55
56
  subscriptionUsage: Record<string, SubscriptionUsageEntry>;
package/dist/tui.js CHANGED
@@ -33,6 +33,9 @@ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports,
33
33
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
34
34
 
35
35
  // src/tui.ts
36
+ import { readFileSync as readFileSync2, existsSync } from "node:fs";
37
+ import { dirname as dirname2, join as join2 } from "node:path";
38
+ import { fileURLToPath } from "node:url";
36
39
  import { createElement, insert, setProp } from "@opentui/solid";
37
40
  import { createSignal } from "solid-js";
38
41
 
@@ -900,6 +903,19 @@ function recordActiveSubscriptionForProvider(provider, name) {
900
903
  }
901
904
 
902
905
  // src/tui.ts
906
+ function getPluginVersion() {
907
+ try {
908
+ const modDir = dirname2(fileURLToPath(import.meta.url));
909
+ const rootDir = dirname2(modDir);
910
+ const pkgPath = join2(rootDir, "package.json");
911
+ if (existsSync(pkgPath)) {
912
+ const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
913
+ return pkg.version || "0.0.0";
914
+ }
915
+ } catch {}
916
+ return "0.0.0";
917
+ }
918
+ var PLUGIN_VERSION = getPluginVersion();
903
919
  var PLUGIN_NAME = "opencode-dux";
904
920
  var BORDER = { type: "single" };
905
921
  var SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
@@ -1797,6 +1813,15 @@ function renderSidebar(snapshot, theme) {
1797
1813
  paddingLeft: 0,
1798
1814
  paddingRight: 0
1799
1815
  }, [
1816
+ box({
1817
+ width: "100%",
1818
+ flexDirection: "row",
1819
+ justifyContent: "space-between"
1820
+ }, [
1821
+ text({ fg: theme.accent }, ["opencode-dux"]),
1822
+ text({ fg: theme.accent }, [`v${PLUGIN_VERSION}`])
1823
+ ]),
1824
+ box({ width: "100%", height: 1 }),
1800
1825
  box({
1801
1826
  width: "100%",
1802
1827
  flexDirection: "row",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-dux",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Agent orchestration, management, and operations plugin for OpenCode",
5
5
  "main": "index.ts",
6
6
  "types": "src/index.ts",
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { existsSync, readdirSync } from 'node:fs';
2
- import { join } from 'node:path';
1
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
3
4
  import type { Plugin } from '@opencode-ai/plugin';
4
5
  import { createAgents, getAgentConfigs } from './agents';
5
6
  import { buildOrchestratorPrompt } from './agents/orchestrator';
@@ -107,6 +108,19 @@ const HEALTH_CHECK = {
107
108
  minMcps: 1,
108
109
  } as const;
109
110
 
111
+ function readPluginVersion(): string | null {
112
+ try {
113
+ const modDir = dirname(fileURLToPath(import.meta.url));
114
+ const rootDir = dirname(modDir);
115
+ const pkgPath = join(rootDir, 'package.json');
116
+ if (existsSync(pkgPath)) {
117
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
118
+ return typeof pkg.version === 'string' ? pkg.version : null;
119
+ }
120
+ } catch {}
121
+ return null;
122
+ }
123
+
110
124
  function asNumber(value: unknown): number | null {
111
125
  return typeof value === 'number' && Number.isFinite(value) ? value : null;
112
126
  }
@@ -659,6 +673,37 @@ const OhMyOpenCodeLite: Plugin = async (ctx) => {
659
673
  if (isFirstInit) {
660
674
  console.log(`\u{2705} opencode-dux initialized (${Object.keys(agents).length} agents, ${toolCount} tools, ${Object.keys(builtinMcps).length} MCPs)`);
661
675
  didLogVerboseInit = true;
676
+
677
+ // Check if plugin was updated since last run
678
+ try {
679
+ const snap = readTuiSnapshot();
680
+ const savedVersion = snap.pluginVersion;
681
+ const currentVersion = readPluginVersion();
682
+ if (savedVersion && currentVersion && savedVersion !== currentVersion) {
683
+ appLog(
684
+ ctx,
685
+ 'info',
686
+ `Updated from v${savedVersion} to v${currentVersion}`,
687
+ ).catch(() => {});
688
+ ctx.client.tui
689
+ .showToast({
690
+ body: {
691
+ title: 'OpenCode Dux',
692
+ message: `Updated to v${currentVersion}`,
693
+ variant: 'info',
694
+ duration: 5000,
695
+ },
696
+ })
697
+ .catch(() => {});
698
+ }
699
+ if (currentVersion) {
700
+ updateSnapshot((s) => {
701
+ s.pluginVersion = currentVersion;
702
+ });
703
+ }
704
+ } catch {
705
+ // best-effort
706
+ }
662
707
  }
663
708
  } catch (err) {
664
709
  // Plugin init failed: log visibly before re-throwing so the user
package/src/tui-state.ts CHANGED
@@ -63,6 +63,7 @@ export interface TuiSessionBundle {
63
63
 
64
64
  export interface TuiSnapshot {
65
65
  version: 6;
66
+ pluginVersion?: string;
66
67
  updatedAt: number;
67
68
  sessions: Record<string, TuiSessionBundle>;
68
69
  subscriptionUsage: Record<string, SubscriptionUsageEntry>;
package/src/tui.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import { readFileSync, existsSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
1
4
  import type { TuiPluginModule } from '@opencode-ai/plugin/tui';
2
5
  import type { JSX } from '@opentui/solid';
3
6
  import { createElement, insert, setProp } from '@opentui/solid';
@@ -19,6 +22,21 @@ import {
19
22
  type TuiSnapshot,
20
23
  } from './tui-state';
21
24
 
25
+ function getPluginVersion(): string {
26
+ try {
27
+ const modDir = dirname(fileURLToPath(import.meta.url));
28
+ const rootDir = dirname(modDir);
29
+ const pkgPath = join(rootDir, 'package.json');
30
+ if (existsSync(pkgPath)) {
31
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
32
+ return pkg.version || '0.0.0';
33
+ }
34
+ } catch {}
35
+ return '0.0.0';
36
+ }
37
+
38
+ const PLUGIN_VERSION = getPluginVersion();
39
+
22
40
  const PLUGIN_NAME = 'opencode-dux';
23
41
  const BORDER = { type: 'single' };
24
42
  const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
@@ -1424,6 +1442,18 @@ function renderSidebar(
1424
1442
  paddingRight: 0,
1425
1443
  },
1426
1444
  [
1445
+ box(
1446
+ {
1447
+ width: '100%',
1448
+ flexDirection: 'row',
1449
+ justifyContent: 'space-between',
1450
+ },
1451
+ [
1452
+ text({ fg: theme.accent }, ['opencode-dux']),
1453
+ text({ fg: theme.accent }, [`v${PLUGIN_VERSION}`]),
1454
+ ],
1455
+ ),
1456
+ box({ width: '100%', height: 1 }),
1427
1457
  box(
1428
1458
  {
1429
1459
  width: '100%',