tmux-ide 1.0.0 → 1.2.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/README.md +84 -35
- package/bin/cli.js +133 -85
- package/package.json +26 -5
- package/scripts/postinstall.js +46 -7
- package/skill/SKILL.md +63 -12
- package/src/attach.js +7 -12
- package/src/config.js +100 -18
- package/src/detect.js +77 -23
- package/src/doctor.js +23 -14
- package/src/init.js +10 -18
- package/src/inspect.js +127 -0
- package/src/launch.js +186 -179
- package/src/lib/errors.js +35 -0
- package/src/lib/launch-plan.js +49 -0
- package/src/lib/output.js +18 -22
- package/src/lib/session-monitor.js +179 -0
- package/src/lib/session-options.js +95 -0
- package/src/lib/tmux.js +234 -0
- package/src/lib/yaml-io.js +2 -2
- package/src/ls.js +2 -4
- package/src/restart.js +6 -13
- package/src/status.js +5 -23
- package/src/stop.js +12 -10
- package/src/validate.js +1 -17
- package/src/detect.test.js +0 -115
- package/src/integration.test.js +0 -94
- package/src/lib/dot-path.test.js +0 -67
- package/src/lib/sizes.test.js +0 -74
- package/src/validate.test.js +0 -141
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# tmux-ide
|
|
2
2
|
|
|
3
|
+
[](https://github.com/wavyrai/tmux-ide/actions/workflows/ci.yml)
|
|
4
|
+
|
|
3
5
|
Turn any project into a tmux-powered terminal IDE with a simple `ide.yml` config file.
|
|
4
6
|
|
|
5
7
|
## Install
|
|
@@ -8,6 +10,8 @@ Turn any project into a tmux-powered terminal IDE with a simple `ide.yml` config
|
|
|
8
10
|
npm install -g tmux-ide
|
|
9
11
|
```
|
|
10
12
|
|
|
13
|
+
Global install also registers the bundled Claude Code skill and enables `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` in `~/.claude/settings.json` if Claude Code is installed locally on the machine.
|
|
14
|
+
|
|
11
15
|
## Quick Start
|
|
12
16
|
|
|
13
17
|
```bash
|
|
@@ -16,24 +20,25 @@ tmux-ide # Launch the IDE
|
|
|
16
20
|
tmux-ide stop # Kill the session
|
|
17
21
|
tmux-ide restart # Stop and relaunch
|
|
18
22
|
tmux-ide attach # Reattach to a running session
|
|
23
|
+
tmux-ide inspect # Inspect effective config + runtime state
|
|
19
24
|
```
|
|
20
25
|
|
|
21
26
|
## ide.yml Format
|
|
22
27
|
|
|
23
28
|
```yaml
|
|
24
|
-
name: project-name
|
|
29
|
+
name: project-name # tmux session name
|
|
25
30
|
|
|
26
|
-
before: pnpm install
|
|
31
|
+
before: pnpm install # optional pre-launch hook
|
|
27
32
|
|
|
28
33
|
rows:
|
|
29
|
-
- size: 70%
|
|
34
|
+
- size: 70% # row height percentage
|
|
30
35
|
panes:
|
|
31
|
-
- title: Editor
|
|
32
|
-
command: vim
|
|
33
|
-
size: 60%
|
|
34
|
-
dir: apps/web
|
|
35
|
-
focus: true
|
|
36
|
-
env:
|
|
36
|
+
- title: Editor # pane border label
|
|
37
|
+
command: vim # command to run (optional)
|
|
38
|
+
size: 60% # pane width percentage (optional)
|
|
39
|
+
dir: apps/web # per-pane working directory (optional)
|
|
40
|
+
focus: true # initial focus (optional)
|
|
41
|
+
env: # environment variables (optional)
|
|
37
42
|
PORT: 3000
|
|
38
43
|
- title: Shell
|
|
39
44
|
|
|
@@ -43,7 +48,7 @@ rows:
|
|
|
43
48
|
- title: Tests
|
|
44
49
|
command: pnpm test
|
|
45
50
|
|
|
46
|
-
theme:
|
|
51
|
+
theme: # optional color overrides
|
|
47
52
|
accent: colour75
|
|
48
53
|
border: colour238
|
|
49
54
|
bg: colour235
|
|
@@ -52,38 +57,82 @@ theme: # optional color overrides
|
|
|
52
57
|
|
|
53
58
|
## Commands
|
|
54
59
|
|
|
55
|
-
| Command
|
|
56
|
-
|
|
57
|
-
| `tmux-ide`
|
|
58
|
-
| `tmux-ide <path>`
|
|
59
|
-
| `tmux-ide init [--template <name>]`
|
|
60
|
-
| `tmux-ide stop`
|
|
61
|
-
| `tmux-ide restart`
|
|
62
|
-
| `tmux-ide attach`
|
|
63
|
-
| `tmux-ide ls`
|
|
64
|
-
| `tmux-ide status`
|
|
65
|
-
| `tmux-ide
|
|
66
|
-
| `tmux-ide
|
|
67
|
-
| `tmux-ide
|
|
68
|
-
| `tmux-ide detect
|
|
69
|
-
| `tmux-ide
|
|
70
|
-
| `tmux-ide config
|
|
71
|
-
| `tmux-ide config
|
|
72
|
-
| `tmux-ide config
|
|
73
|
-
| `tmux-ide config
|
|
60
|
+
| Command | Description |
|
|
61
|
+
| -------------------------------------------------- | --------------------------------------- |
|
|
62
|
+
| `tmux-ide` | Launch IDE from `ide.yml` |
|
|
63
|
+
| `tmux-ide <path>` | Launch from a specific directory |
|
|
64
|
+
| `tmux-ide init [--template <name>]` | Scaffold a new `ide.yml` |
|
|
65
|
+
| `tmux-ide stop` | Kill the current IDE session |
|
|
66
|
+
| `tmux-ide restart` | Stop and relaunch the IDE session |
|
|
67
|
+
| `tmux-ide attach` | Reattach to a running session |
|
|
68
|
+
| `tmux-ide ls` | List all tmux sessions |
|
|
69
|
+
| `tmux-ide status` | Show session status |
|
|
70
|
+
| `tmux-ide inspect` | Show effective config and runtime state |
|
|
71
|
+
| `tmux-ide doctor` | Check system requirements |
|
|
72
|
+
| `tmux-ide validate` | Validate `ide.yml` |
|
|
73
|
+
| `tmux-ide detect` | Detect project stack and explain why |
|
|
74
|
+
| `tmux-ide detect --write` | Detect and write `ide.yml` |
|
|
75
|
+
| `tmux-ide config` | Dump config as JSON |
|
|
76
|
+
| `tmux-ide config set <path> <value>` | Set a config value |
|
|
77
|
+
| `tmux-ide config add-pane --row <N>` | Add a pane to a row |
|
|
78
|
+
| `tmux-ide config remove-pane --row <N> --pane <M>` | Remove a pane |
|
|
79
|
+
| `tmux-ide config add-row [--size <percent>]` | Add a new row |
|
|
80
|
+
| `tmux-ide config enable-team --name <name>` | Enable agent teams |
|
|
81
|
+
| `tmux-ide config disable-team` | Disable agent teams |
|
|
74
82
|
|
|
75
83
|
All commands support `--json` for structured output.
|
|
76
84
|
|
|
85
|
+
`tmux-ide detect` now includes reasoning about the package manager, language, framework, and dev-command signals it used. `tmux-ide inspect` combines config validation, resolved layout details, and live tmux state in one command.
|
|
86
|
+
|
|
77
87
|
## Templates
|
|
78
88
|
|
|
79
89
|
Use `tmux-ide init --template <name>` with one of:
|
|
80
90
|
|
|
81
|
-
- `default`
|
|
82
|
-
- `nextjs`
|
|
83
|
-
- `convex`
|
|
84
|
-
- `vite`
|
|
85
|
-
- `python`
|
|
86
|
-
- `go`
|
|
91
|
+
- `default` - General-purpose layout
|
|
92
|
+
- `nextjs` - Next.js development
|
|
93
|
+
- `convex` - Convex + Next.js
|
|
94
|
+
- `vite` - Vite project
|
|
95
|
+
- `python` - Python development
|
|
96
|
+
- `go` - Go development
|
|
97
|
+
- `agent-team` - Agent team with lead + teammates
|
|
98
|
+
- `agent-team-nextjs` - Agent team for Next.js
|
|
99
|
+
- `agent-team-monorepo` - Agent team for monorepos
|
|
100
|
+
|
|
101
|
+
## Contributor Workflow
|
|
102
|
+
|
|
103
|
+
The repo now uses a pnpm workspace with a root CLI package and a separate docs app package:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
pnpm install
|
|
107
|
+
pnpm test
|
|
108
|
+
pnpm docs:build
|
|
109
|
+
pnpm check
|
|
110
|
+
pnpm pack:check
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`pnpm check` is the intended local pre-push command and matches the default release checklist. `npm publish` is still guarded by `prepublishOnly`, so publishing runs the same full check path automatically.
|
|
114
|
+
|
|
115
|
+
## CI
|
|
116
|
+
|
|
117
|
+
GitHub Actions validates:
|
|
118
|
+
|
|
119
|
+
- the Node CLI test suite on Node 18, 20, and 22
|
|
120
|
+
- the docs site production build
|
|
121
|
+
- the package can be packed successfully with `npm pack --dry-run`
|
|
122
|
+
|
|
123
|
+
That keeps the release surface small but catches the main regressions for a CLI-first package.
|
|
124
|
+
|
|
125
|
+
## Open Source Project Files
|
|
126
|
+
|
|
127
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md) for local setup and contribution workflow
|
|
128
|
+
- [RELEASE.md](RELEASE.md) for the publish checklist
|
|
129
|
+
- [CHANGELOG.md](CHANGELOG.md) for release notes
|
|
130
|
+
- [SECURITY.md](SECURITY.md) for vulnerability reporting
|
|
131
|
+
|
|
132
|
+
Release note convention:
|
|
133
|
+
|
|
134
|
+
- Keep the next version under an `Unreleased` heading in `CHANGELOG.md` until the tag is cut.
|
|
135
|
+
- Move it to a dated release entry when the release is actually published.
|
|
87
136
|
|
|
88
137
|
## Requirements
|
|
89
138
|
|
package/bin/cli.js
CHANGED
|
@@ -8,10 +8,13 @@ import { attach } from "../src/attach.js";
|
|
|
8
8
|
import { ls } from "../src/ls.js";
|
|
9
9
|
import { doctor } from "../src/doctor.js";
|
|
10
10
|
import { status } from "../src/status.js";
|
|
11
|
+
import { inspect } from "../src/inspect.js";
|
|
11
12
|
import { validate } from "../src/validate.js";
|
|
12
13
|
import { detect } from "../src/detect.js";
|
|
13
14
|
import { config } from "../src/config.js";
|
|
14
15
|
import { restart } from "../src/restart.js";
|
|
16
|
+
import { IdeError } from "../src/lib/errors.js";
|
|
17
|
+
import { printCommandError } from "../src/lib/output.js";
|
|
15
18
|
|
|
16
19
|
const { positionals, values } = parseArgs({
|
|
17
20
|
allowPositionals: true,
|
|
@@ -26,11 +29,28 @@ const { positionals, values } = parseArgs({
|
|
|
26
29
|
write: { type: "boolean" },
|
|
27
30
|
template: { type: "string" },
|
|
28
31
|
name: { type: "string" },
|
|
32
|
+
verbose: { type: "boolean", default: false },
|
|
29
33
|
help: { type: "boolean", short: "h" },
|
|
30
34
|
version: { type: "boolean", short: "v" },
|
|
31
35
|
},
|
|
32
36
|
});
|
|
33
37
|
|
|
38
|
+
const knownCommands = new Set([
|
|
39
|
+
"start",
|
|
40
|
+
"init",
|
|
41
|
+
"stop",
|
|
42
|
+
"attach",
|
|
43
|
+
"restart",
|
|
44
|
+
"ls",
|
|
45
|
+
"doctor",
|
|
46
|
+
"status",
|
|
47
|
+
"inspect",
|
|
48
|
+
"validate",
|
|
49
|
+
"detect",
|
|
50
|
+
"config",
|
|
51
|
+
"help",
|
|
52
|
+
]);
|
|
53
|
+
|
|
34
54
|
// --version / -v
|
|
35
55
|
if (values.version) {
|
|
36
56
|
const require = createRequire(import.meta.url);
|
|
@@ -39,7 +59,14 @@ if (values.version) {
|
|
|
39
59
|
process.exit(0);
|
|
40
60
|
}
|
|
41
61
|
|
|
42
|
-
|
|
62
|
+
if (values.verbose) {
|
|
63
|
+
globalThis.__tmuxIdeVerbose = true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const firstPositional = positionals[0];
|
|
67
|
+
const hasKnownCommand = firstPositional ? knownCommands.has(firstPositional) : false;
|
|
68
|
+
const command = hasKnownCommand ? firstPositional : "start";
|
|
69
|
+
const startTargetDir = hasKnownCommand ? positionals[1] : firstPositional;
|
|
43
70
|
const json = values.json ?? false;
|
|
44
71
|
|
|
45
72
|
const noColor = "NO_COLOR" in process.env;
|
|
@@ -47,6 +74,11 @@ const bold = (s) => (noColor ? s : `\x1b[1m${s}\x1b[22m`);
|
|
|
47
74
|
const cyan = (s) => (noColor ? s : `\x1b[36m${s}\x1b[39m`);
|
|
48
75
|
const dim = (s) => (noColor ? s : `\x1b[2m${s}\x1b[22m`);
|
|
49
76
|
|
|
77
|
+
if (values.help) {
|
|
78
|
+
printHelp();
|
|
79
|
+
process.exit(0);
|
|
80
|
+
}
|
|
81
|
+
|
|
50
82
|
function printHelp() {
|
|
51
83
|
console.log(`${bold("tmux-ide")} — Terminal IDE powered by tmux
|
|
52
84
|
|
|
@@ -59,6 +91,7 @@ ${bold("Usage:")}
|
|
|
59
91
|
${cyan("tmux-ide attach")} ${dim("Reattach to a running session")}
|
|
60
92
|
${cyan("tmux-ide ls")} ${dim("List all tmux sessions")}
|
|
61
93
|
${cyan("tmux-ide status")} [--json] ${dim("Show session status")}
|
|
94
|
+
${cyan("tmux-ide inspect")} [--json] ${dim("Show effective config and runtime state")}
|
|
62
95
|
${cyan("tmux-ide doctor")} ${dim("Check system requirements")}
|
|
63
96
|
${cyan("tmux-ide validate")} [--json] ${dim("Validate ide.yml")}
|
|
64
97
|
${cyan("tmux-ide detect")} [--json] ${dim("Detect project stack")}
|
|
@@ -75,94 +108,109 @@ ${bold("Flags:")}
|
|
|
75
108
|
${cyan("--json")} ${dim("Output as JSON (all commands)")}
|
|
76
109
|
${cyan("--template <name>")} ${dim("Use specific template for init")}
|
|
77
110
|
${cyan("--write")} ${dim("Write detected config to ide.yml")}
|
|
111
|
+
${cyan("--verbose")} ${dim("Log all tmux commands (or set TMUX_IDE_DEBUG=1)")}
|
|
112
|
+
${cyan("-h, --help")} ${dim("Show usage")}
|
|
78
113
|
${cyan("-v, --version")} ${dim("Show version number")}`);
|
|
79
114
|
}
|
|
80
115
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
116
|
+
try {
|
|
117
|
+
switch (command) {
|
|
118
|
+
case "start":
|
|
119
|
+
await launch(startTargetDir, { json });
|
|
120
|
+
break;
|
|
121
|
+
|
|
122
|
+
case "init":
|
|
123
|
+
await init({ template: values.template, json });
|
|
124
|
+
break;
|
|
125
|
+
|
|
126
|
+
case "stop":
|
|
127
|
+
await stop(positionals[1], { json });
|
|
128
|
+
break;
|
|
129
|
+
|
|
130
|
+
case "attach":
|
|
131
|
+
await attach(positionals[1], { json });
|
|
132
|
+
break;
|
|
133
|
+
|
|
134
|
+
case "restart":
|
|
135
|
+
await restart(positionals[1], { json });
|
|
136
|
+
break;
|
|
137
|
+
|
|
138
|
+
case "ls":
|
|
139
|
+
await ls({ json });
|
|
140
|
+
break;
|
|
141
|
+
|
|
142
|
+
case "doctor":
|
|
143
|
+
await doctor({ json });
|
|
144
|
+
break;
|
|
145
|
+
|
|
146
|
+
case "status":
|
|
147
|
+
await status(positionals[1], { json });
|
|
148
|
+
break;
|
|
149
|
+
|
|
150
|
+
case "inspect":
|
|
151
|
+
await inspect(positionals[1], { json });
|
|
152
|
+
break;
|
|
153
|
+
|
|
154
|
+
case "validate":
|
|
155
|
+
await validate(positionals[1], { json });
|
|
156
|
+
break;
|
|
157
|
+
|
|
158
|
+
case "detect":
|
|
159
|
+
await detect(positionals[1], { json, write: values.write });
|
|
160
|
+
break;
|
|
161
|
+
|
|
162
|
+
case "config": {
|
|
163
|
+
const sub = positionals[1]; // set, add-pane, remove-pane, add-row, or undefined (dump)
|
|
164
|
+
let action = "dump";
|
|
165
|
+
let configArgs = [];
|
|
166
|
+
|
|
167
|
+
if (sub === "set") {
|
|
168
|
+
action = "set";
|
|
169
|
+
configArgs = positionals.slice(2);
|
|
170
|
+
} else if (sub === "add-pane") {
|
|
171
|
+
action = "add-pane";
|
|
172
|
+
// Pass named flags as args array
|
|
173
|
+
configArgs = [];
|
|
174
|
+
if (values.row !== undefined) configArgs.push("--row", values.row);
|
|
175
|
+
if (values.title !== undefined) configArgs.push("--title", values.title);
|
|
176
|
+
if (values.command !== undefined) configArgs.push("--command", values.command);
|
|
177
|
+
if (values.size !== undefined) configArgs.push("--size", values.size);
|
|
178
|
+
} else if (sub === "remove-pane") {
|
|
179
|
+
action = "remove-pane";
|
|
180
|
+
configArgs = [];
|
|
181
|
+
if (values.row !== undefined) configArgs.push("--row", values.row);
|
|
182
|
+
if (values.pane !== undefined) configArgs.push("--pane", values.pane);
|
|
183
|
+
} else if (sub === "add-row") {
|
|
184
|
+
action = "add-row";
|
|
185
|
+
configArgs = [];
|
|
186
|
+
if (values.size !== undefined) configArgs.push("--size", values.size);
|
|
187
|
+
} else if (sub === "enable-team") {
|
|
188
|
+
action = "enable-team";
|
|
189
|
+
configArgs = [];
|
|
190
|
+
if (values.name !== undefined) configArgs.push("--name", values.name);
|
|
191
|
+
} else if (sub === "disable-team") {
|
|
192
|
+
action = "disable-team";
|
|
193
|
+
configArgs = [];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
await config(null, { json, action, args: configArgs });
|
|
197
|
+
break;
|
|
154
198
|
}
|
|
155
199
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
case "help":
|
|
161
|
-
printHelp();
|
|
162
|
-
break;
|
|
200
|
+
case "help":
|
|
201
|
+
printHelp();
|
|
202
|
+
break;
|
|
163
203
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
204
|
+
default:
|
|
205
|
+
throw new IdeError(`Unknown command: ${command}\nRun "tmux-ide help" for usage.`, {
|
|
206
|
+
code: "USAGE",
|
|
207
|
+
exitCode: 1,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
} catch (error) {
|
|
211
|
+
if (error instanceof IdeError) {
|
|
212
|
+
printCommandError(error, { json });
|
|
213
|
+
} else {
|
|
214
|
+
throw error;
|
|
215
|
+
}
|
|
168
216
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tmux-ide",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Turn any project into a tmux-powered terminal IDE with a simple ide.yml",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,16 +8,29 @@
|
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"bin",
|
|
11
|
-
"src",
|
|
11
|
+
"src/**/*.js",
|
|
12
|
+
"!src/**/*.test.js",
|
|
12
13
|
"scripts",
|
|
13
14
|
"skill",
|
|
14
15
|
"templates"
|
|
15
16
|
],
|
|
16
17
|
"scripts": {
|
|
17
18
|
"dev": "node bin/cli.js",
|
|
18
|
-
"test": "node --test
|
|
19
|
+
"test": "node --test src/*.test.js src/lib/*.test.js",
|
|
20
|
+
"test:unit": "node --test src/cli.test.js src/config-cli.test.js src/detect.test.js src/launch.test.js src/validate.test.js src/lib/*.test.js",
|
|
21
|
+
"test:integration": "node --test src/integration.test.js",
|
|
22
|
+
"lint": "eslint .",
|
|
23
|
+
"lint:workspace": "turbo run lint",
|
|
24
|
+
"format": "prettier --write .",
|
|
25
|
+
"format:check": "prettier --check .",
|
|
26
|
+
"build:workspace": "turbo run build",
|
|
27
|
+
"typecheck:workspace": "turbo run typecheck",
|
|
28
|
+
"docs:build": "turbo run build --filter=@tmux-ide/docs",
|
|
29
|
+
"pack:check": "npm pack --dry-run --cache /tmp/tmux-ide-npm-cache > /dev/null",
|
|
30
|
+
"check": "pnpm run lint:workspace && pnpm run format:check && pnpm run test:unit && pnpm run docs:build && pnpm run pack:check",
|
|
31
|
+
"prepublishOnly": "pnpm run check",
|
|
19
32
|
"postinstall": "node scripts/postinstall.js",
|
|
20
|
-
"docs": "
|
|
33
|
+
"docs": "turbo run dev --filter=@tmux-ide/docs"
|
|
21
34
|
},
|
|
22
35
|
"keywords": [
|
|
23
36
|
"tmux",
|
|
@@ -38,7 +51,15 @@
|
|
|
38
51
|
"url": "https://github.com/wavyrai/tmux-ide/issues"
|
|
39
52
|
},
|
|
40
53
|
"license": "MIT",
|
|
54
|
+
"packageManager": "pnpm@10.21.0",
|
|
41
55
|
"dependencies": {
|
|
42
|
-
"js-yaml": "^4.1.
|
|
56
|
+
"js-yaml": "^4.1.1"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@eslint/js": "^10.0.1",
|
|
60
|
+
"eslint": "^10.0.3",
|
|
61
|
+
"globals": "^17.4.0",
|
|
62
|
+
"prettier": "^3.8.1",
|
|
63
|
+
"turbo": "^2.3.3"
|
|
43
64
|
}
|
|
44
65
|
}
|
package/scripts/postinstall.js
CHANGED
|
@@ -1,13 +1,52 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, copyFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, mkdirSync, copyFileSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { resolve, dirname } from "node:path";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
|
|
5
5
|
const claudeDir = resolve(homedir(), ".claude");
|
|
6
|
-
if (existsSync(claudeDir)) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
if (!shouldInstallClaudeIntegration() || !existsSync(claudeDir)) {
|
|
7
|
+
process.exit(0);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const skillDir = resolve(claudeDir, "skills", "tmux-ide");
|
|
11
|
+
mkdirSync(skillDir, { recursive: true });
|
|
12
|
+
const src = resolve(dirname(import.meta.dirname), "skill", "SKILL.md");
|
|
13
|
+
if (existsSync(src)) {
|
|
14
|
+
copyFileSync(src, resolve(skillDir, "SKILL.md"));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const settingsPath = resolve(claudeDir, "settings.json");
|
|
18
|
+
let settings = {};
|
|
19
|
+
|
|
20
|
+
if (existsSync(settingsPath)) {
|
|
21
|
+
try {
|
|
22
|
+
settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.warn(
|
|
25
|
+
`[tmux-ide] Skipping Claude settings update: could not parse ${settingsPath}: ${error.message}`,
|
|
26
|
+
);
|
|
27
|
+
process.exit(0);
|
|
12
28
|
}
|
|
13
29
|
}
|
|
30
|
+
|
|
31
|
+
if (settings == null || typeof settings !== "object" || Array.isArray(settings)) {
|
|
32
|
+
console.warn(
|
|
33
|
+
`[tmux-ide] Skipping Claude settings update: ${settingsPath} does not contain a JSON object.`,
|
|
34
|
+
);
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const nextSettings = {
|
|
39
|
+
...settings,
|
|
40
|
+
env: {
|
|
41
|
+
...(settings.env && typeof settings.env === "object" && !Array.isArray(settings.env)
|
|
42
|
+
? settings.env
|
|
43
|
+
: {}),
|
|
44
|
+
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "1",
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
writeFileSync(settingsPath, `${JSON.stringify(nextSettings, null, 2)}\n`);
|
|
49
|
+
|
|
50
|
+
function shouldInstallClaudeIntegration() {
|
|
51
|
+
return process.env.npm_config_global === "true";
|
|
52
|
+
}
|