ninja-terminals 2.2.1 → 2.2.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.
Files changed (3) hide show
  1. package/cli.js +120 -0
  2. package/package.json +1 -1
  3. package/server.js +10 -3
package/cli.js CHANGED
@@ -30,6 +30,7 @@ USAGE
30
30
  npx ninja-terminals [options]
31
31
 
32
32
  OPTIONS
33
+ --setup Configure MCP server + orchestrator prompt (run once)
33
34
  --port <number> Port to listen on (default: 3300)
34
35
  --terminals <number> Number of terminals to spawn (default: 4)
35
36
  --cwd <path> Working directory for terminals (default: current dir)
@@ -59,6 +60,125 @@ if (hasFlag('--version') || hasFlag('-v')) {
59
60
  process.exit(0);
60
61
  }
61
62
 
63
+ // ── Setup command ───────────────────────────────────────────
64
+ if (hasFlag('--setup')) {
65
+ const fs = require('fs');
66
+ const path = require('path');
67
+ const os = require('os');
68
+
69
+ console.log('\n🥷 NINJA TERMINALS SETUP\n');
70
+
71
+ // 1. Find or create .mcp.json
72
+ const projectMcp = path.join(process.cwd(), '.mcp.json');
73
+ const globalMcp = path.join(os.homedir(), '.mcp.json');
74
+ const mcpPath = fs.existsSync(projectMcp) ? projectMcp : globalMcp;
75
+
76
+ let mcpConfig = { mcpServers: {} };
77
+ if (fs.existsSync(mcpPath)) {
78
+ try {
79
+ mcpConfig = JSON.parse(fs.readFileSync(mcpPath, 'utf-8'));
80
+ if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
81
+ } catch (e) {
82
+ console.log(`⚠️ Could not parse ${mcpPath}, creating new config`);
83
+ }
84
+ }
85
+
86
+ // 2. Add ninja-terminals MCP server
87
+ const npmRoot = path.dirname(require.resolve('ninja-terminals/package.json'));
88
+ mcpConfig.mcpServers['ninja-terminals'] = {
89
+ command: 'node',
90
+ args: [path.join(npmRoot, 'mcp-server.js')],
91
+ env: {
92
+ NINJA_TERMINAL_COUNT: '4',
93
+ NINJA_LOG_LEVEL: 'info'
94
+ }
95
+ };
96
+
97
+ fs.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2) + '\n');
98
+ console.log(`✅ Added ninja-terminals to ${mcpPath}`);
99
+
100
+ // 3. Copy orchestrator prompt to CLAUDE.md
101
+ const claudeMd = path.join(process.cwd(), 'CLAUDE.md');
102
+ const orchestratorPrompt = path.join(npmRoot, 'prompts', 'orchestrator-lite.md');
103
+
104
+ if (fs.existsSync(orchestratorPrompt)) {
105
+ const prompt = fs.readFileSync(orchestratorPrompt, 'utf-8');
106
+ const marker = '<!-- NINJA TERMINALS ORCHESTRATOR -->';
107
+
108
+ let claudeContent = '';
109
+ if (fs.existsSync(claudeMd)) {
110
+ claudeContent = fs.readFileSync(claudeMd, 'utf-8');
111
+ if (claudeContent.includes(marker)) {
112
+ console.log(`✅ Orchestrator prompt already in CLAUDE.md`);
113
+ } else {
114
+ claudeContent += `\n\n${marker}\n${prompt}`;
115
+ fs.writeFileSync(claudeMd, claudeContent);
116
+ console.log(`✅ Added orchestrator prompt to CLAUDE.md`);
117
+ }
118
+ } else {
119
+ fs.writeFileSync(claudeMd, `${marker}\n${prompt}`);
120
+ console.log(`✅ Created CLAUDE.md with orchestrator prompt`);
121
+ }
122
+ }
123
+
124
+ // 4. Add required MCP dependencies (Playwright + Fetch)
125
+ // These are needed for browser automation and API calls
126
+
127
+ if (!mcpConfig.mcpServers['playwright']) {
128
+ mcpConfig.mcpServers['playwright'] = {
129
+ command: 'npx',
130
+ args: ['@anthropic-ai/playwright-mcp@latest']
131
+ };
132
+ console.log(`✅ Added Playwright MCP (browser automation)`);
133
+ } else {
134
+ console.log(`✅ Playwright MCP already configured`);
135
+ }
136
+
137
+ if (!mcpConfig.mcpServers['fetch']) {
138
+ mcpConfig.mcpServers['fetch'] = {
139
+ command: 'npx',
140
+ args: ['@anthropic-ai/fetch-mcp@latest']
141
+ };
142
+ console.log(`✅ Added Fetch MCP (API calls)`);
143
+ } else {
144
+ console.log(`✅ Fetch MCP already configured`);
145
+ }
146
+
147
+ // Save updated config with all MCPs
148
+ fs.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2) + '\n');
149
+
150
+ // 5. Check for Claude in Chrome (optional but recommended)
151
+ const chromeExt = mcpConfig.mcpServers['claude-in-chrome'];
152
+ if (chromeExt) {
153
+ console.log(`✅ Claude in Chrome detected (recommended)`);
154
+ } else {
155
+ console.log(`ℹ️ Claude in Chrome not found (optional - Playwright will be used)`);
156
+ }
157
+
158
+ console.log(`
159
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
160
+ ✨ Setup complete!
161
+
162
+ MCPs configured:
163
+ • ninja-terminals - orchestrates parallel Claude Code instances
164
+ • playwright - browser automation (screenshots, clicks, reading)
165
+ • fetch - API calls to /api/terminals
166
+
167
+ Next steps:
168
+ 1. Restart Claude Code to load MCP servers
169
+ 2. Run: npx ninja-terminals
170
+ 3. Or use MCP tools directly in Claude Code
171
+
172
+ MCP tools available after restart:
173
+ mcp__ninja-terminals__spawn_terminal
174
+ mcp__ninja-terminals__send_input
175
+ mcp__ninja-terminals__list_terminals
176
+ ... and 9 more
177
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
178
+ `);
179
+ process.exit(0);
180
+ }
181
+
62
182
  const port = parseInt(getArg('--port', '3300'), 10);
63
183
  const terminals = parseInt(getArg('--terminals', '4'), 10);
64
184
  const cwd = getArg('--cwd', process.cwd());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ninja-terminals",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "description": "MCP server for multi-terminal Claude Code orchestration with DAG task management, parallel execution, and self-improvement",
5
5
  "main": "server.js",
6
6
  "bin": {
package/server.js CHANGED
@@ -1009,7 +1009,6 @@ app.post('/api/auth/register', async (req, res) => {
1009
1009
 
1010
1010
  server.listen(PORT, () => {
1011
1011
  console.log(`Ninja Terminals v2 running on http://localhost:${PORT}`);
1012
- console.log(`Auth required: POST /api/session with Bearer token to start`);
1013
1012
 
1014
1013
  // Start SSE heartbeat
1015
1014
  sse.startHeartbeat(15000);
@@ -1017,6 +1016,14 @@ server.listen(PORT, () => {
1017
1016
  // Start session heartbeat — re-validates tokens every 5 minutes
1018
1017
  startSessionHeartbeat(sessionCache, handleSessionInvalidation, 5 * 60 * 1000);
1019
1018
 
1020
- // NOTE: Terminals are NOT spawned on startup.
1021
- // Users must POST /api/session with a valid token to create a session and spawn terminals.
1019
+ // Auto-spawn terminals based on DEFAULT_TERMINALS env var
1020
+ const terminalCount = DEFAULT_TERMINALS;
1021
+ const labels = ['T1', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7', 'T8'];
1022
+
1023
+ console.log(`Auto-spawning ${terminalCount} terminals...`);
1024
+ for (let i = 0; i < terminalCount; i++) {
1025
+ const label = labels[i] || `T${i + 1}`;
1026
+ spawnTerminal(label, [], DEFAULT_CWD || process.cwd(), 'pro');
1027
+ }
1028
+ console.log(`All ${terminalCount} terminals ready`);
1022
1029
  });