opentmux 1.3.3

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.
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/scripts/install.ts
4
+ import fs from "fs";
5
+ import path from "path";
6
+ import os from "os";
7
+ import { fileURLToPath } from "url";
8
+ var __filename = fileURLToPath(import.meta.url);
9
+ var __dirname = path.dirname(__filename);
10
+ var HOME = os.homedir();
11
+ function detectShell() {
12
+ const shell = process.env.SHELL || "";
13
+ const platform = process.platform;
14
+ if (platform === "win32") {
15
+ const documents = path.join(HOME, "Documents");
16
+ const psDir = path.join(documents, "PowerShell");
17
+ const psProfile = path.join(psDir, "Microsoft.PowerShell_profile.ps1");
18
+ return {
19
+ name: "powershell",
20
+ rcFile: psProfile,
21
+ dir: psDir
22
+ };
23
+ }
24
+ if (shell.includes("zsh")) {
25
+ return { name: "zsh", rcFile: path.join(HOME, ".zshrc") };
26
+ } else if (shell.includes("bash")) {
27
+ const bashProfile = path.join(HOME, ".bash_profile");
28
+ const bashrc = path.join(HOME, ".bashrc");
29
+ return {
30
+ name: "bash",
31
+ rcFile: fs.existsSync(bashProfile) ? bashProfile : bashrc
32
+ };
33
+ } else if (shell.includes("fish")) {
34
+ return {
35
+ name: "fish",
36
+ rcFile: path.join(HOME, ".config", "fish", "config.fish")
37
+ };
38
+ }
39
+ return { name: "unknown", rcFile: path.join(HOME, ".profile") };
40
+ }
41
+ function getAliasContent(shellName) {
42
+ if (shellName === "powershell") {
43
+ return `
44
+ function opencode {
45
+ opentmux $args
46
+ }
47
+ `;
48
+ }
49
+ return `alias opencode='opentmux'`;
50
+ }
51
+ function getExportLine() {
52
+ return `export OPENCODE_PORT=4096`;
53
+ }
54
+ function setupAlias() {
55
+ const shell = detectShell();
56
+ console.log("");
57
+ console.log("\u{1F527} Setting up opentmux auto-launcher...");
58
+ console.log(` Detected shell: ${shell.name}`);
59
+ console.log(` Config file: ${shell.rcFile}`);
60
+ if (shell.name === "powershell") {
61
+ if (shell.dir && !fs.existsSync(shell.dir)) {
62
+ fs.mkdirSync(shell.dir, { recursive: true });
63
+ }
64
+ }
65
+ if (!fs.existsSync(shell.rcFile)) {
66
+ console.log(` Creating ${shell.rcFile}...`);
67
+ fs.writeFileSync(shell.rcFile, "", "utf-8");
68
+ }
69
+ let rcContent = fs.readFileSync(shell.rcFile, "utf-8");
70
+ const aliasContent = getAliasContent(shell.name);
71
+ const MARKER_START = "# >>> opentmux >>>";
72
+ const MARKER_END = "# <<< opentmux <<<";
73
+ const OLD_MARKER_START = "# >>> opencode-agent-tmux >>>";
74
+ const OLD_MARKER_END = "# <<< opencode-agent-tmux <<<";
75
+ const LEGACY_MARKER_START = "# >>> opencode-subagent-tmux >>>";
76
+ const LEGACY_MARKER_END = "# <<< opencode-subagent-tmux <<<";
77
+ const escapeRegExp = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
78
+ if (rcContent.includes(LEGACY_MARKER_START)) {
79
+ console.log(" Removing legacy opencode-subagent-tmux alias...");
80
+ const regex = new RegExp(`${escapeRegExp(LEGACY_MARKER_START)}[\\s\\S]*?${escapeRegExp(LEGACY_MARKER_END)}\\n?`, "g");
81
+ rcContent = rcContent.replace(regex, "");
82
+ fs.writeFileSync(shell.rcFile, rcContent, "utf-8");
83
+ rcContent = fs.readFileSync(shell.rcFile, "utf-8");
84
+ }
85
+ if (rcContent.includes(OLD_MARKER_START)) {
86
+ console.log(" Updating legacy opencode-agent-tmux alias...");
87
+ console.warn(" Deprecation: Using legacy opencode-agent-tmux markers. Updating to opentmux.");
88
+ const regex = new RegExp(`${escapeRegExp(OLD_MARKER_START)}[\\s\\S]*?${escapeRegExp(OLD_MARKER_END)}\\n?`, "g");
89
+ rcContent = rcContent.replace(regex, "");
90
+ fs.writeFileSync(shell.rcFile, rcContent, "utf-8");
91
+ rcContent = fs.readFileSync(shell.rcFile, "utf-8");
92
+ }
93
+ if (rcContent.includes(MARKER_START)) {
94
+ console.log(" Updating opentmux alias...");
95
+ const regex = new RegExp(`${escapeRegExp(MARKER_START)}[\\s\\S]*?${escapeRegExp(MARKER_END)}\\n?`, "g");
96
+ rcContent = rcContent.replace(regex, "");
97
+ fs.writeFileSync(shell.rcFile, rcContent, "utf-8");
98
+ rcContent = fs.readFileSync(shell.rcFile, "utf-8");
99
+ }
100
+ let configBlock = "";
101
+ if (shell.name === "powershell") {
102
+ configBlock = `
103
+ ${MARKER_START}
104
+ $env:OPENCODE_PORT="4096"
105
+ ${aliasContent}
106
+ ${MARKER_END}
107
+ `;
108
+ } else {
109
+ configBlock = `
110
+ ${MARKER_START}
111
+ ${getExportLine()}
112
+ ${aliasContent}
113
+ ${MARKER_END}
114
+ `;
115
+ }
116
+ fs.appendFileSync(shell.rcFile, configBlock);
117
+ console.log(" \u2713 Auto-launcher configured successfully!");
118
+ console.log("");
119
+ console.log(" To activate now:");
120
+ if (shell.name === "powershell") {
121
+ console.log(` . ${shell.rcFile}`);
122
+ } else {
123
+ console.log(` source ${shell.rcFile}`);
124
+ }
125
+ console.log("");
126
+ console.log(" Or restart your terminal.");
127
+ console.log("");
128
+ console.log(' Usage: Just type "opencode" and tmux + port 4096 will be auto-configured!');
129
+ console.log("");
130
+ }
131
+ try {
132
+ setupAlias();
133
+ } catch (error) {
134
+ console.error("");
135
+ console.error("\u26A0\uFE0F Failed to auto-configure shell alias:", error.message);
136
+ console.error("");
137
+ process.exit(0);
138
+ }
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/scripts/update-plugins.ts
4
+ import { spawnSync } from "child_process";
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import os from "os";
8
+ var HOME = os.homedir();
9
+ var CONFIG_PATH = path.join(HOME, ".config", "opencode", "opencode.json");
10
+ var NEW_STATE_DIR = path.join(HOME, ".config", "opencode", "opentmux");
11
+ var OLD_STATE_DIR = path.join(
12
+ HOME,
13
+ ".config",
14
+ "opencode",
15
+ "opencode-agent-tmux"
16
+ );
17
+ function getStateDir() {
18
+ if (fs.existsSync(NEW_STATE_DIR)) {
19
+ return NEW_STATE_DIR;
20
+ }
21
+ if (fs.existsSync(OLD_STATE_DIR)) {
22
+ console.warn(
23
+ "Deprecation: Using legacy opencode-agent-tmux state directory. Please update to opentmux"
24
+ );
25
+ return OLD_STATE_DIR;
26
+ }
27
+ return NEW_STATE_DIR;
28
+ }
29
+ var STATE_DIR = getStateDir();
30
+ var STATE_PATH = path.join(STATE_DIR, "update-state.json");
31
+ var UPDATE_INTERVAL_HOURS = 12;
32
+ function ensureStateDir() {
33
+ if (!fs.existsSync(STATE_DIR)) {
34
+ fs.mkdirSync(STATE_DIR, { recursive: true });
35
+ }
36
+ }
37
+ function shouldRunUpdate() {
38
+ try {
39
+ if (!fs.existsSync(STATE_PATH)) return true;
40
+ const raw = fs.readFileSync(STATE_PATH, "utf-8");
41
+ const parsed = JSON.parse(raw);
42
+ if (!parsed.lastRun) return true;
43
+ const lastRun = new Date(parsed.lastRun).getTime();
44
+ if (Number.isNaN(lastRun)) return true;
45
+ const diffHours = (Date.now() - lastRun) / (1e3 * 60 * 60);
46
+ return diffHours >= UPDATE_INTERVAL_HOURS;
47
+ } catch {
48
+ return true;
49
+ }
50
+ }
51
+ function writeLastRun() {
52
+ try {
53
+ ensureStateDir();
54
+ fs.writeFileSync(
55
+ STATE_PATH,
56
+ JSON.stringify({ lastRun: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
57
+ "utf-8"
58
+ );
59
+ } catch {
60
+ }
61
+ }
62
+ function normalizePluginName(name) {
63
+ const trimmed = name.trim();
64
+ if (!trimmed) return null;
65
+ if (trimmed.startsWith("./") || trimmed.startsWith("../")) return null;
66
+ if (trimmed.startsWith("file:") || trimmed.startsWith("git+")) return null;
67
+ if (trimmed.includes(path.sep)) return null;
68
+ const atIndex = trimmed.lastIndexOf("@");
69
+ if (atIndex > 0) {
70
+ return trimmed.slice(0, atIndex);
71
+ }
72
+ return trimmed;
73
+ }
74
+ function loadConfig() {
75
+ try {
76
+ if (!fs.existsSync(CONFIG_PATH)) return null;
77
+ const raw = fs.readFileSync(CONFIG_PATH, "utf-8");
78
+ return JSON.parse(raw);
79
+ } catch {
80
+ return null;
81
+ }
82
+ }
83
+ function saveConfig(config) {
84
+ try {
85
+ const dir = path.dirname(CONFIG_PATH);
86
+ if (!fs.existsSync(dir)) {
87
+ fs.mkdirSync(dir, { recursive: true });
88
+ }
89
+ fs.writeFileSync(
90
+ CONFIG_PATH,
91
+ JSON.stringify(config, null, 2) + "\n",
92
+ "utf-8"
93
+ );
94
+ } catch {
95
+ }
96
+ }
97
+ function ensurePluginEntry(config) {
98
+ const existingRaw = config.plugin || config.plugins;
99
+ const existing = Array.isArray(existingRaw) ? [...existingRaw] : [];
100
+ const normalized = existing.map((plugin) => {
101
+ if (plugin === "opencode-subagent-tmux" || plugin === "opencode-agent-tmux") {
102
+ return "opentmux";
103
+ }
104
+ return plugin;
105
+ });
106
+ if (!normalized.includes("opentmux")) {
107
+ normalized.push("opentmux");
108
+ }
109
+ if (JSON.stringify(existing) !== JSON.stringify(normalized)) {
110
+ config.plugin = normalized;
111
+ delete config.plugins;
112
+ saveConfig(config);
113
+ }
114
+ return normalized;
115
+ }
116
+ function installLatest(plugins) {
117
+ const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
118
+ const unique = Array.from(new Set(plugins));
119
+ for (const plugin of unique) {
120
+ const normalized = normalizePluginName(plugin);
121
+ if (!normalized) continue;
122
+ const pkgName = normalized === "opentmux" ? "opentmux" : normalized;
123
+ const target = `${pkgName}@latest`;
124
+ spawnSync(npmCmd, ["install", "-g", target], { stdio: "ignore" });
125
+ }
126
+ }
127
+ function main() {
128
+ if (!shouldRunUpdate()) return;
129
+ if (process.env.OPENCODE_TMUX_UPDATE !== "1") return;
130
+ const config = loadConfig() ?? {};
131
+ const plugins = ensurePluginEntry(config);
132
+ const updateList = ["opentmux", ...plugins];
133
+ installLatest(updateList);
134
+ writeLastRun();
135
+ }
136
+ try {
137
+ main();
138
+ } catch {
139
+ }
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "opentmux",
3
+ "version": "1.3.3",
4
+ "description": "OpenCode tmux integration: automatically opens subagent panes and renders real-time agent execution with smart layouts",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "opentmux": "./dist/bin/opentmux.js"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsup",
16
+ "dev": "tsup --watch",
17
+ "typecheck": "tsc --noEmit",
18
+ "prepublishOnly": "bun run build",
19
+ "postinstall": "test -f dist/scripts/install.js && node dist/scripts/install.js || echo 'Skipping postinstall setup (dist not found)'"
20
+ },
21
+ "keywords": [
22
+ "opencode",
23
+ "opencode-plugin",
24
+ "tmux",
25
+ "agent",
26
+ "subagent",
27
+ "visualization"
28
+ ],
29
+ "author": "Angan Samadder",
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/AnganSamadder/opentmux.git"
34
+ },
35
+ "bugs": {
36
+ "url": "https://github.com/AnganSamadder/opentmux/issues"
37
+ },
38
+ "homepage": "https://github.com/AnganSamadder/opentmux#readme",
39
+ "dependencies": {
40
+ "zod": "^3.24.1"
41
+ },
42
+ "devDependencies": {
43
+ "@types/bun": "^1.2.4",
44
+ "@types/node": "^25.0.10",
45
+ "tsup": "^8.3.6",
46
+ "typescript": "^5.7.3"
47
+ }
48
+ }