ninja-terminals 2.2.0 → 2.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.
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,95 @@ 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. Check for Claude in Chrome
125
+ const chromeExt = mcpConfig.mcpServers['claude-in-chrome'];
126
+ if (chromeExt) {
127
+ console.log(`✅ Claude in Chrome detected`);
128
+ } else {
129
+ console.log(`⚠️ Claude in Chrome not found in MCP config`);
130
+ console.log(` For browser automation, install: https://github.com/anthropics/claude-in-chrome`);
131
+ }
132
+
133
+ console.log(`
134
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
135
+ ✨ Setup complete!
136
+
137
+ Next steps:
138
+ 1. Restart Claude Code to load MCP server
139
+ 2. Run: npx ninja-terminals
140
+ 3. Or use MCP tools directly in Claude Code
141
+
142
+ MCP tools available after restart:
143
+ mcp__ninja-terminals__spawn_terminal
144
+ mcp__ninja-terminals__send_input
145
+ mcp__ninja-terminals__list_terminals
146
+ ... and 9 more
147
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
148
+ `);
149
+ process.exit(0);
150
+ }
151
+
62
152
  const port = parseInt(getArg('--port', '3300'), 10);
63
153
  const terminals = parseInt(getArg('--terminals', '4'), 10);
64
154
  const cwd = getArg('--cwd', process.cwd());
package/mcp-server.js CHANGED
@@ -698,6 +698,19 @@ async function main() {
698
698
  // Start HTTP server for browser UI
699
699
  httpServer.listen(HTTP_PORT, () => {
700
700
  console.error(`Ninja Terminals HTTP server running on http://localhost:${HTTP_PORT}`);
701
+
702
+ // Auto-spawn terminals based on tier (NINJA_TERMINAL_COUNT env var)
703
+ // Free = 2, Paid = 4
704
+ const terminalCount = parseInt(process.env.NINJA_TERMINAL_COUNT || '2', 10);
705
+ const labels = ['T1', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7', 'T8'];
706
+
707
+ console.error(`Auto-spawning ${terminalCount} terminals...`);
708
+ for (let i = 0; i < terminalCount; i++) {
709
+ const label = labels[i] || `T${i + 1}`;
710
+ spawnTerminal(label, [], process.cwd(), 'pro');
711
+ console.error(` Spawned ${label}`);
712
+ }
713
+ console.error(`All ${terminalCount} terminals ready`);
701
714
  });
702
715
 
703
716
  // Start MCP server on stdio
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ninja-terminals",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
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
  });