@nokai/cli 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 +16 -173
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +239 -0
- package/dist/cli.js.map +1 -0
- package/dist/connection-manager.d.ts +9 -1
- package/dist/connection-manager.d.ts.map +1 -1
- package/dist/connection-manager.js +85 -1
- package/dist/connection-manager.js.map +1 -1
- package/dist/index.js +16 -4
- package/dist/index.js.map +1 -1
- package/dist/message-protocol.d.ts +3 -1
- package/dist/message-protocol.d.ts.map +1 -1
- package/dist/message-protocol.js +25 -1
- package/dist/message-protocol.js.map +1 -1
- package/dist/peer-connection.d.ts.map +1 -1
- package/dist/peer-connection.js +2 -5
- package/dist/peer-connection.js.map +1 -1
- package/dist/profile.d.ts +9 -0
- package/dist/profile.d.ts.map +1 -1
- package/dist/profile.js +31 -2
- package/dist/profile.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +113 -6
- package/dist/server.js.map +1 -1
- package/dist/shared/constants.d.ts +12 -0
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/constants.js +13 -1
- package/dist/shared/constants.js.map +1 -1
- package/dist/shared/types.d.ts +19 -1
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +7 -0
- package/dist/shared/types.js.map +1 -1
- package/dist/signaling-client.d.ts +18 -3
- package/dist/signaling-client.d.ts.map +1 -1
- package/dist/signaling-client.js +83 -7
- package/dist/signaling-client.js.map +1 -1
- package/dist/tools/ask.d.ts.map +1 -1
- package/dist/tools/ask.js +2 -1
- package/dist/tools/ask.js.map +1 -1
- package/dist/tools/connect.d.ts +19 -2
- package/dist/tools/connect.d.ts.map +1 -1
- package/dist/tools/connect.js +187 -43
- package/dist/tools/connect.js.map +1 -1
- package/dist/tools/discover.d.ts +12 -0
- package/dist/tools/discover.d.ts.map +1 -0
- package/dist/tools/discover.js +67 -0
- package/dist/tools/discover.js.map +1 -0
- package/dist/tools/id.d.ts +12 -0
- package/dist/tools/id.d.ts.map +1 -0
- package/dist/tools/id.js +24 -0
- package/dist/tools/id.js.map +1 -0
- package/dist/tools/invite.d.ts +32 -0
- package/dist/tools/invite.d.ts.map +1 -0
- package/dist/tools/invite.js +144 -0
- package/dist/tools/invite.js.map +1 -0
- package/dist/tools/reconnect.d.ts.map +1 -1
- package/dist/tools/reconnect.js +6 -2
- package/dist/tools/reconnect.js.map +1 -1
- package/dist/tools/share.d.ts +37 -0
- package/dist/tools/share.d.ts.map +1 -0
- package/dist/tools/share.js +153 -0
- package/dist/tools/share.js.map +1 -0
- package/dist/tools/tell.d.ts.map +1 -1
- package/dist/tools/tell.js +2 -1
- package/dist/tools/tell.js.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -4,190 +4,33 @@
|
|
|
4
4
|
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
NokAI
|
|
7
|
+
NokAI lets AI coding assistants talk to each other. Connect your Claude Code with your teammate's Cursor, ask questions about their codebase, share files, and send action requests — without leaving your editor.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## Quick Start
|
|
9
|
+
## Get Started
|
|
12
10
|
|
|
13
11
|
```bash
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# Add to Claude Code MCP settings
|
|
18
|
-
# See docs/setup/ for your specific tool
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
### Connect with a Teammate
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
You: "Connect me with my teammate"
|
|
25
|
-
NokAI: 🔗 Connection code: 847293 (expires in 5 minutes)
|
|
26
|
-
|
|
27
|
-
--- Your teammate ---
|
|
28
|
-
|
|
29
|
-
Teammate: "Join NokAI with code 847293"
|
|
30
|
-
NokAI: ✓ Connected with Michael!
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Ask Questions Across Codebases
|
|
34
|
-
|
|
35
|
-
```
|
|
36
|
-
You: "Ask Sara what the message type for /cmd_vel is
|
|
37
|
-
and build me the Flutter model for it"
|
|
38
|
-
|
|
39
|
-
NokAI: → Asking Sara...
|
|
40
|
-
← Sara: geometry_msgs/msg/Twist at 10Hz
|
|
41
|
-
Fields: linear.x (float64), angular.z (float64)
|
|
42
|
-
|
|
43
|
-
Building your Flutter model class...
|
|
44
|
-
✓ Created lib/models/twist_model.dart
|
|
12
|
+
npm install -g @nokai/cli
|
|
13
|
+
nokai
|
|
45
14
|
```
|
|
46
15
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
| Platform | Status | Setup Guide |
|
|
50
|
-
|---|---|---|
|
|
51
|
-
| Claude Code (CLI & VS Code) | ✅ Full support | [docs/setup/claude-code.md](docs/setup/claude-code.md) |
|
|
52
|
-
| Cursor | ✅ Full support | [docs/setup/cursor.md](docs/setup/cursor.md) |
|
|
53
|
-
| Windsurf (Codeium) | ✅ Full support | [docs/setup/windsurf.md](docs/setup/windsurf.md) |
|
|
54
|
-
| Any MCP tool | ✅ Full support | [docs/setup/generic-mcp.md](docs/setup/generic-mcp.md) |
|
|
55
|
-
|
|
56
|
-
## Tools (13)
|
|
57
|
-
|
|
58
|
-
### Connection
|
|
59
|
-
|
|
60
|
-
| Tool | Description |
|
|
61
|
-
|---|---|
|
|
62
|
-
| `nokai_connect` | Generate a 6-digit OTP connection code |
|
|
63
|
-
| `nokai_join` | Join using an OTP code |
|
|
64
|
-
| `nokai_reconnect` | Reconnect to a saved peer (no new OTP) |
|
|
65
|
-
| `nokai_disconnect` | Disconnect from a peer |
|
|
66
|
-
| `nokai_connections` | List all active and saved connections |
|
|
67
|
-
|
|
68
|
-
### Communication
|
|
16
|
+
The setup wizard will ask your name, which AI tool you use, and configure everything automatically. No JSON editing required.
|
|
69
17
|
|
|
70
|
-
|
|
71
|
-
|---|---|
|
|
72
|
-
| `nokai_ask` | Ask a question to a peer's AI agent |
|
|
73
|
-
| `nokai_respond` | Reply to an incoming question |
|
|
74
|
-
| `nokai_tell` | Send an action request (requires read-write permission) |
|
|
75
|
-
|
|
76
|
-
### Management
|
|
77
|
-
|
|
78
|
-
| Tool | Description |
|
|
79
|
-
|---|---|
|
|
80
|
-
| `nokai_permissions` | View/change permission levels (read-only, read-write, ask-only) |
|
|
81
|
-
| `nokai_approve` | Toggle manual approval mode for incoming queries |
|
|
82
|
-
| `nokai_history` | Browse past message exchanges |
|
|
83
|
-
| `nokai_audit` | View audit log of all events |
|
|
84
|
-
| `nokai_profile` | Manage agent profile and capability cards |
|
|
85
|
-
|
|
86
|
-
## Architecture
|
|
87
|
-
|
|
88
|
-
```
|
|
89
|
-
Your Machine Teammate's Machine
|
|
90
|
-
┌────────────────┐ ┌────────────────┐
|
|
91
|
-
│ AI Assistant │ │ AI Assistant │
|
|
92
|
-
│ (Claude/Cursor) │ │ (Claude/Cursor) │
|
|
93
|
-
│ ↕ MCP │ │ ↕ MCP │
|
|
94
|
-
│ NokAI Server │◄══════════════════►│ NokAI Server │
|
|
95
|
-
│ (local) │ Encrypted P2P │ (local) │
|
|
96
|
-
└────────────────┘ (WebRTC) └────────────────┘
|
|
97
|
-
│ │
|
|
98
|
-
└──────── Signaling Server ───────────┘
|
|
99
|
-
(handshake only)
|
|
100
|
-
```
|
|
18
|
+
## What You Can Do
|
|
101
19
|
|
|
102
|
-
- **
|
|
103
|
-
- **
|
|
104
|
-
- **
|
|
105
|
-
- **
|
|
20
|
+
- **Ask across codebases** — query a teammate's agent about their code
|
|
21
|
+
- **Send action requests** — ask a peer's agent to make changes
|
|
22
|
+
- **Share files** — send files and project context directly to another agent
|
|
23
|
+
- **Connect your own projects** — link your mobile and web sessions
|
|
24
|
+
- **Discover peers** — see who's online and reconnect instantly
|
|
106
25
|
|
|
107
|
-
##
|
|
26
|
+
## Works With
|
|
108
27
|
|
|
109
|
-
|
|
110
|
-
|---|---|
|
|
111
|
-
| Agent identity | Ed25519 keypair per agent |
|
|
112
|
-
| Connection auth | 6-digit OTP, 5-min expiry, single-use |
|
|
113
|
-
| Transport | WebRTC DTLS encryption |
|
|
114
|
-
| Server access | Signaling server never sees message content |
|
|
115
|
-
| Local storage | Private keys at `~/.nokai/profile.json` (chmod 600) |
|
|
116
|
-
| Reconnection | Peer confirmation required, public key verification |
|
|
28
|
+
Claude Code, Cursor, Windsurf, and any MCP-compatible tool.
|
|
117
29
|
|
|
118
|
-
##
|
|
30
|
+
## Full Docs
|
|
119
31
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
```bash
|
|
123
|
-
cd packages/signaling-server
|
|
124
|
-
npx wrangler d1 create nokai-signaling # Create D1 database
|
|
125
|
-
# Update wrangler.toml with the database ID
|
|
126
|
-
npx wrangler deploy # Deploy to Cloudflare
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
Set your deployed URL as `NOKAI_SIGNALING_URL` in your MCP config.
|
|
130
|
-
|
|
131
|
-
## Environment Variables
|
|
132
|
-
|
|
133
|
-
| Variable | Required | Default | Description |
|
|
134
|
-
|---|---|---|---|
|
|
135
|
-
| `NOKAI_AGENT_NAME` | No | "Agent" | Your agent's display name |
|
|
136
|
-
| `NOKAI_SIGNALING_URL` | No | — | Signaling server WebSocket URL |
|
|
137
|
-
| `NOKAI_TURN_SERVER` | No | — | TURN relay server URL |
|
|
138
|
-
| `NOKAI_TURN_USERNAME` | No | — | TURN server username |
|
|
139
|
-
| `NOKAI_TURN_PASSWORD` | No | — | TURN server password |
|
|
140
|
-
|
|
141
|
-
## Development
|
|
142
|
-
|
|
143
|
-
```bash
|
|
144
|
-
# Clone and install
|
|
145
|
-
git clone https://github.com/heiisenberrg/nokAI.git
|
|
146
|
-
cd nokAI
|
|
147
|
-
npm install
|
|
148
|
-
|
|
149
|
-
# Build all packages
|
|
150
|
-
npm run build
|
|
151
|
-
|
|
152
|
-
# Run tests (125 tests)
|
|
153
|
-
npm test
|
|
154
|
-
|
|
155
|
-
# Dev mode (MCP server)
|
|
156
|
-
cd packages/mcp-server && npm run dev
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
## Project Structure
|
|
160
|
-
|
|
161
|
-
```
|
|
162
|
-
nokai/
|
|
163
|
-
├── packages/
|
|
164
|
-
│ ├── shared/ # Shared types, constants, type guards
|
|
165
|
-
│ ├── mcp-server/ # MCP server + P2P engine (13 tools)
|
|
166
|
-
│ │ ├── src/tools/ # Tool handlers
|
|
167
|
-
│ │ └── tests/ # 100+ tests
|
|
168
|
-
│ └── signaling-server/ # Cloudflare Workers signaling server
|
|
169
|
-
└── docs/setup/ # Platform-specific setup guides
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
## Roadmap
|
|
173
|
-
|
|
174
|
-
- [x] v0.1.0 — Core: connect, ask, respond via P2P
|
|
175
|
-
- [x] v0.2.0 — Reconnection, history, TURN, offline queue, approval mode
|
|
176
|
-
- [x] v0.3.0 — Actions (tell), permission levels
|
|
177
|
-
- [x] v0.4.0 — Audit logs, agent profiles
|
|
178
|
-
- [x] v1.0.0 — Multi-platform, npm packaging
|
|
179
|
-
- [ ] v1.1.0 — Web dashboard for connection management
|
|
180
|
-
- [ ] v1.2.0 — Agent capability discovery within organizations
|
|
181
|
-
- [ ] v2.0.0 — Cross-organization connections
|
|
32
|
+
https://nokai.pages.dev
|
|
182
33
|
|
|
183
34
|
## License
|
|
184
35
|
|
|
185
|
-
MIT
|
|
186
|
-
|
|
187
|
-
## Contributing
|
|
188
|
-
|
|
189
|
-
Contributions welcome! Please open an issue first to discuss.
|
|
190
|
-
|
|
191
|
-
---
|
|
192
|
-
|
|
193
|
-
Built with frustration at copy-pasting between Slack and Claude.
|
|
36
|
+
MIT
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAuPA,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAS5C"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runCli = runCli;
|
|
4
|
+
const node_readline_1 = require("node:readline");
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
const profile_js_1 = require("./profile.js");
|
|
8
|
+
const rl = (0, node_readline_1.createInterface)({ input: process.stdin, output: process.stdout });
|
|
9
|
+
function ask(question) {
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
rl.question(question, (answer) => resolve(answer.trim()));
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function choose(question, options) {
|
|
15
|
+
return new Promise((resolve) => {
|
|
16
|
+
console.log(`\n ${question}\n`);
|
|
17
|
+
options.forEach((opt, i) => {
|
|
18
|
+
console.log(` ${i + 1}) ${opt}`);
|
|
19
|
+
});
|
|
20
|
+
console.log();
|
|
21
|
+
rl.question(" Enter number: ", (answer) => {
|
|
22
|
+
const idx = parseInt(answer.trim(), 10) - 1;
|
|
23
|
+
if (idx >= 0 && idx < options.length) {
|
|
24
|
+
resolve(options[idx]);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
resolve(options[0]);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function getPlatforms() {
|
|
33
|
+
const home = process.env.HOME || process.env.USERPROFILE || "~";
|
|
34
|
+
return [
|
|
35
|
+
{
|
|
36
|
+
name: "Claude Code",
|
|
37
|
+
configPath: (0, node_path_1.join)(home, ".claude.json"),
|
|
38
|
+
configDir: (0, node_path_1.join)(home),
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: "Cursor",
|
|
42
|
+
configPath: (0, node_path_1.join)(process.cwd(), ".cursor", "mcp.json"),
|
|
43
|
+
configDir: (0, node_path_1.join)(process.cwd(), ".cursor"),
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "Windsurf",
|
|
47
|
+
configPath: (0, node_path_1.join)(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
48
|
+
configDir: (0, node_path_1.join)(home, ".codeium", "windsurf"),
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "VS Code (Extension)",
|
|
52
|
+
configPath: "",
|
|
53
|
+
configDir: "",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "Other",
|
|
57
|
+
configPath: "",
|
|
58
|
+
configDir: "",
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
function writeMcpConfig(platform, agentName, signalingUrl) {
|
|
63
|
+
if (!platform.configPath)
|
|
64
|
+
return false;
|
|
65
|
+
try {
|
|
66
|
+
// Ensure directory exists
|
|
67
|
+
if (platform.configDir && !(0, node_fs_1.existsSync)(platform.configDir)) {
|
|
68
|
+
(0, node_fs_1.mkdirSync)(platform.configDir, { recursive: true });
|
|
69
|
+
}
|
|
70
|
+
// Read existing config or create new
|
|
71
|
+
let config = {};
|
|
72
|
+
if ((0, node_fs_1.existsSync)(platform.configPath)) {
|
|
73
|
+
try {
|
|
74
|
+
config = JSON.parse((0, node_fs_1.readFileSync)(platform.configPath, "utf-8"));
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
config = {};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Add/update mcpServers.nokai
|
|
81
|
+
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
82
|
+
config.mcpServers = {};
|
|
83
|
+
}
|
|
84
|
+
config.mcpServers.nokai = {
|
|
85
|
+
command: "nokai",
|
|
86
|
+
args: ["serve"],
|
|
87
|
+
env: {
|
|
88
|
+
NOKAI_AGENT_NAME: agentName,
|
|
89
|
+
NOKAI_SIGNALING_URL: signalingUrl,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
(0, node_fs_1.writeFileSync)(platform.configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const SIGNALING_URL = "wss://nokai-signaling.ajaykkumar-rajen.workers.dev";
|
|
100
|
+
async function firstTimeSetup() {
|
|
101
|
+
console.log("\n ✨ Welcome to NokAI! Let's set you up.\n");
|
|
102
|
+
// Ask for agent name
|
|
103
|
+
const name = await ask(" What would you like to name your agent? ");
|
|
104
|
+
if (!name) {
|
|
105
|
+
console.log(" Agent name is required.");
|
|
106
|
+
rl.close();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// Choose platform
|
|
110
|
+
const platforms = getPlatforms();
|
|
111
|
+
const platformNames = platforms.map((p) => p.name);
|
|
112
|
+
const chosen = await choose("Which AI tool are you using?", platformNames);
|
|
113
|
+
const platform = platforms.find((p) => p.name === chosen) || platforms[platforms.length - 1];
|
|
114
|
+
// Create profile
|
|
115
|
+
const profileDir = (0, profile_js_1.getProfileDir)();
|
|
116
|
+
const profile = (0, profile_js_1.createProfile)(name, profileDir);
|
|
117
|
+
console.log(`\n ✓ Agent created: ${name}`);
|
|
118
|
+
console.log(` ✓ Your NokAI ID: ${profile.nokaiId}`);
|
|
119
|
+
// Configure MCP
|
|
120
|
+
if (platform.configPath) {
|
|
121
|
+
const confirm = await ask(`\n Add NokAI to ${platform.name} config? (${platform.configPath}) [Y/n] `);
|
|
122
|
+
if (confirm.toLowerCase() !== "n") {
|
|
123
|
+
const success = writeMcpConfig(platform, name, SIGNALING_URL);
|
|
124
|
+
if (success) {
|
|
125
|
+
console.log(` ✓ MCP configuration added to ${platform.name}`);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
console.log(` ✗ Failed to write config. You can add it manually.`);
|
|
129
|
+
showManualConfig(name);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
showManualConfig(name);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else if (platform.name === "VS Code (Extension)") {
|
|
137
|
+
console.log(`\n Install the NokAI VS Code extension and set your Signaling URL in settings.`);
|
|
138
|
+
console.log(` Signaling URL: ${SIGNALING_URL}`);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
showManualConfig(name);
|
|
142
|
+
}
|
|
143
|
+
console.log(`\n You're ready! Restart your AI tool to activate NokAI.`);
|
|
144
|
+
console.log(` Share your NokAI ID with teammates: ${profile.nokaiId}\n`);
|
|
145
|
+
rl.close();
|
|
146
|
+
}
|
|
147
|
+
function showManualConfig(agentName) {
|
|
148
|
+
console.log(`\n Add this to your MCP configuration:\n`);
|
|
149
|
+
console.log(JSON.stringify({
|
|
150
|
+
mcpServers: {
|
|
151
|
+
nokai: {
|
|
152
|
+
command: "nokai",
|
|
153
|
+
args: ["serve"],
|
|
154
|
+
env: {
|
|
155
|
+
NOKAI_AGENT_NAME: agentName,
|
|
156
|
+
NOKAI_SIGNALING_URL: SIGNALING_URL,
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
}, null, 2).split("\n").map((l) => ` ${l}`).join("\n"));
|
|
161
|
+
}
|
|
162
|
+
async function returningUser() {
|
|
163
|
+
const profileDir = (0, profile_js_1.getProfileDir)();
|
|
164
|
+
const profile = (0, profile_js_1.loadProfile)(profileDir);
|
|
165
|
+
if (!profile) {
|
|
166
|
+
return firstTimeSetup();
|
|
167
|
+
}
|
|
168
|
+
console.log(`\n Welcome back, ${profile.name}! (${profile.nokaiId})\n`);
|
|
169
|
+
const action = await choose("What would you like to do?", [
|
|
170
|
+
"Connect to a teammate",
|
|
171
|
+
"Connect my own projects",
|
|
172
|
+
"Show my NokAI ID",
|
|
173
|
+
"View connections",
|
|
174
|
+
"Reconfigure MCP settings",
|
|
175
|
+
"Exit",
|
|
176
|
+
]);
|
|
177
|
+
switch (action) {
|
|
178
|
+
case "Connect to a teammate": {
|
|
179
|
+
const peerId = await ask("\n Enter teammate's NokAI ID (e.g., NKI-XXXX-XXXX): ");
|
|
180
|
+
if (peerId) {
|
|
181
|
+
console.log(`\n To connect, use this in your AI tool:`);
|
|
182
|
+
console.log(` nokai_connect mode=teammate id=${peerId}\n`);
|
|
183
|
+
}
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
case "Connect my own projects": {
|
|
187
|
+
console.log(`\n To connect your sessions, use this in your AI tool:`);
|
|
188
|
+
console.log(` nokai_connect mode=self\n`);
|
|
189
|
+
console.log(` This will list your active sessions and let you connect them.\n`);
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
case "Show my NokAI ID": {
|
|
193
|
+
console.log(`\n NokAI ID: ${profile.nokaiId}`);
|
|
194
|
+
console.log(` Agent Name: ${profile.name}`);
|
|
195
|
+
console.log(` Device ID: ${profile.deviceId}\n`);
|
|
196
|
+
console.log(` Share your NokAI ID with teammates so they can connect to you.\n`);
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
case "View connections": {
|
|
200
|
+
console.log(`\n To view connections, use nokai_connections in your AI tool.\n`);
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
case "Reconfigure MCP settings": {
|
|
204
|
+
const platforms = getPlatforms();
|
|
205
|
+
const platformNames = platforms.map((p) => p.name);
|
|
206
|
+
const chosen = await choose("Which AI tool?", platformNames);
|
|
207
|
+
const platform = platforms.find((p) => p.name === chosen) || platforms[platforms.length - 1];
|
|
208
|
+
if (platform.configPath) {
|
|
209
|
+
const success = writeMcpConfig(platform, profile.name, SIGNALING_URL);
|
|
210
|
+
if (success) {
|
|
211
|
+
console.log(`\n ✓ MCP configuration updated for ${platform.name}`);
|
|
212
|
+
console.log(` Restart your AI tool to apply changes.\n`);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
console.log(`\n ✗ Failed to write config.`);
|
|
216
|
+
showManualConfig(profile.name);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
showManualConfig(profile.name);
|
|
221
|
+
}
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
case "Exit":
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
rl.close();
|
|
228
|
+
}
|
|
229
|
+
async function runCli() {
|
|
230
|
+
const profileDir = (0, profile_js_1.getProfileDir)();
|
|
231
|
+
const profile = (0, profile_js_1.loadProfile)(profileDir);
|
|
232
|
+
if (!profile) {
|
|
233
|
+
await firstTimeSetup();
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
await returningUser();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
2
|
import type { AgentProfile, PeerMessage, ConnectionRecord } from "./shared/index.js";
|
|
3
3
|
import { type NokaiDB } from "./db.js";
|
|
4
|
+
import type { SharedFile, ProjectContext } from "./shared/index.js";
|
|
4
5
|
export declare class ConnectionManager extends EventEmitter {
|
|
5
6
|
private db;
|
|
6
7
|
private profile;
|
|
7
8
|
private activePeers;
|
|
8
9
|
private incomingHandler;
|
|
9
10
|
private heldQueries;
|
|
10
|
-
|
|
11
|
+
private signalingUrl;
|
|
12
|
+
private pendingBytes;
|
|
13
|
+
private transferReportTimer;
|
|
14
|
+
constructor(db: NokaiDB, profile: AgentProfile, signalingUrl?: string);
|
|
15
|
+
private trackBytes;
|
|
16
|
+
private flushTransferStats;
|
|
11
17
|
registerPeer(connectionId: string, peerName: string, peerPublicKey: string): void;
|
|
12
18
|
setPeerSend(connectionId: string, sendFn: (msg: string) => void): void;
|
|
13
19
|
private findPeerByName;
|
|
@@ -15,6 +21,8 @@ export declare class ConnectionManager extends EventEmitter {
|
|
|
15
21
|
sendResponse(peerName: string, replyTo: string, content: string, sourceFiles?: string[]): PeerMessage;
|
|
16
22
|
sendAction(peerName: string, content: string, context?: string): PeerMessage;
|
|
17
23
|
sendActionResult(peerName: string, replyTo: string, content: string, success: boolean, sourceFiles?: string[]): PeerMessage;
|
|
24
|
+
sendShareFiles(peerName: string, files: SharedFile[]): PeerMessage;
|
|
25
|
+
sendShareContext(peerName: string, context: ProjectContext): PeerMessage;
|
|
18
26
|
handleIncomingMessage(connectionId: string, rawData: string): void;
|
|
19
27
|
onIncomingMessage(handler: (msg: PeerMessage, peerName: string) => void): void;
|
|
20
28
|
getActiveConnections(): Array<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection-manager.d.ts","sourceRoot":"","sources":["../src/connection-manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"connection-manager.d.ts","sourceRoot":"","sources":["../src/connection-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,16 +3,47 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ConnectionManager = void 0;
|
|
4
4
|
const node_events_1 = require("node:events");
|
|
5
5
|
const message_protocol_js_1 = require("./message-protocol.js");
|
|
6
|
+
async function reportStats(signalingUrl, endpoint, body) {
|
|
7
|
+
try {
|
|
8
|
+
const httpUrl = signalingUrl.replace("wss://", "https://").replace("ws://", "http://");
|
|
9
|
+
await fetch(`${httpUrl}/stats/${endpoint}`, {
|
|
10
|
+
method: "POST",
|
|
11
|
+
headers: { "Content-Type": "application/json" },
|
|
12
|
+
body: JSON.stringify(body),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// Stats reporting is best-effort, don't break on failure
|
|
17
|
+
}
|
|
18
|
+
}
|
|
6
19
|
class ConnectionManager extends node_events_1.EventEmitter {
|
|
7
20
|
db;
|
|
8
21
|
profile;
|
|
9
22
|
activePeers = new Map(); // connectionId -> peer
|
|
10
23
|
incomingHandler = null;
|
|
11
24
|
heldQueries = new Map();
|
|
12
|
-
|
|
25
|
+
signalingUrl;
|
|
26
|
+
pendingBytes = 0;
|
|
27
|
+
transferReportTimer = null;
|
|
28
|
+
constructor(db, profile, signalingUrl) {
|
|
13
29
|
super();
|
|
14
30
|
this.db = db;
|
|
15
31
|
this.profile = profile;
|
|
32
|
+
this.signalingUrl = signalingUrl || "";
|
|
33
|
+
// Periodically flush transfer stats (every 60 seconds)
|
|
34
|
+
if (this.signalingUrl) {
|
|
35
|
+
this.transferReportTimer = setInterval(() => this.flushTransferStats(), 60000);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
trackBytes(size) {
|
|
39
|
+
this.pendingBytes += size;
|
|
40
|
+
}
|
|
41
|
+
async flushTransferStats() {
|
|
42
|
+
if (this.pendingBytes > 0 && this.signalingUrl) {
|
|
43
|
+
const bytes = this.pendingBytes;
|
|
44
|
+
this.pendingBytes = 0;
|
|
45
|
+
await reportStats(this.signalingUrl, "transfer", { bytes });
|
|
46
|
+
}
|
|
16
47
|
}
|
|
17
48
|
registerPeer(connectionId, peerName, peerPublicKey) {
|
|
18
49
|
this.activePeers.set(connectionId, {
|
|
@@ -32,6 +63,10 @@ class ConnectionManager extends node_events_1.EventEmitter {
|
|
|
32
63
|
status: "active",
|
|
33
64
|
});
|
|
34
65
|
this.db.logEvent("connection_established", peerName, connectionId, null);
|
|
66
|
+
// Report session to stats
|
|
67
|
+
if (this.signalingUrl) {
|
|
68
|
+
reportStats(this.signalingUrl, "session", {});
|
|
69
|
+
}
|
|
35
70
|
}
|
|
36
71
|
setPeerSend(connectionId, sendFn) {
|
|
37
72
|
const peer = this.activePeers.get(connectionId);
|
|
@@ -57,6 +92,7 @@ class ConnectionManager extends node_events_1.EventEmitter {
|
|
|
57
92
|
const msg = (0, message_protocol_js_1.createQueryMessage)(this.profile.name, content, context);
|
|
58
93
|
const serialized = (0, message_protocol_js_1.serializeMessage)(msg);
|
|
59
94
|
peer.send(serialized);
|
|
95
|
+
this.trackBytes(serialized.length);
|
|
60
96
|
this.db.logEvent("query_sent", peerName, peer.connectionId, content.slice(0, 100));
|
|
61
97
|
this.db.saveMessage({
|
|
62
98
|
id: msg.id,
|
|
@@ -81,6 +117,7 @@ class ConnectionManager extends node_events_1.EventEmitter {
|
|
|
81
117
|
const msg = (0, message_protocol_js_1.createResponseMessage)(this.profile.name, replyTo, content, sourceFiles);
|
|
82
118
|
const serialized = (0, message_protocol_js_1.serializeMessage)(msg);
|
|
83
119
|
peer.send(serialized);
|
|
120
|
+
this.trackBytes(serialized.length);
|
|
84
121
|
this.db.saveMessage({
|
|
85
122
|
id: msg.id,
|
|
86
123
|
connectionId: peer.connectionId,
|
|
@@ -109,6 +146,7 @@ class ConnectionManager extends node_events_1.EventEmitter {
|
|
|
109
146
|
const msg = (0, message_protocol_js_1.createActionMessage)(this.profile.name, content, context);
|
|
110
147
|
const serialized = (0, message_protocol_js_1.serializeMessage)(msg);
|
|
111
148
|
peer.send(serialized);
|
|
149
|
+
this.trackBytes(serialized.length);
|
|
112
150
|
this.db.logEvent("action_sent", peerName, peer.connectionId, content.slice(0, 100));
|
|
113
151
|
this.db.saveMessage({
|
|
114
152
|
id: msg.id,
|
|
@@ -130,6 +168,7 @@ class ConnectionManager extends node_events_1.EventEmitter {
|
|
|
130
168
|
const msg = (0, message_protocol_js_1.createActionResultMessage)(this.profile.name, replyTo, content, success, sourceFiles);
|
|
131
169
|
const serialized = (0, message_protocol_js_1.serializeMessage)(msg);
|
|
132
170
|
peer.send(serialized);
|
|
171
|
+
this.trackBytes(serialized.length);
|
|
133
172
|
this.db.saveMessage({
|
|
134
173
|
id: msg.id,
|
|
135
174
|
connectionId: peer.connectionId,
|
|
@@ -142,7 +181,52 @@ class ConnectionManager extends node_events_1.EventEmitter {
|
|
|
142
181
|
});
|
|
143
182
|
return msg;
|
|
144
183
|
}
|
|
184
|
+
sendShareFiles(peerName, files) {
|
|
185
|
+
const peer = this.findPeerByName(peerName);
|
|
186
|
+
if (!peer || !peer.send) {
|
|
187
|
+
throw new Error(`No active connection with peer: ${peerName}`);
|
|
188
|
+
}
|
|
189
|
+
const msg = (0, message_protocol_js_1.createShareFileMessage)(this.profile.name, files);
|
|
190
|
+
const serialized = (0, message_protocol_js_1.serializeMessage)(msg);
|
|
191
|
+
peer.send(serialized);
|
|
192
|
+
this.trackBytes(serialized.length);
|
|
193
|
+
this.db.logEvent("share_files_sent", peerName, peer.connectionId, `${files.length} file(s)`);
|
|
194
|
+
this.db.saveMessage({
|
|
195
|
+
id: msg.id,
|
|
196
|
+
connectionId: peer.connectionId,
|
|
197
|
+
direction: "sent",
|
|
198
|
+
type: msg.type,
|
|
199
|
+
content: msg.content,
|
|
200
|
+
sourceFiles: JSON.stringify(files.map((f) => f.path)),
|
|
201
|
+
replyTo: null,
|
|
202
|
+
timestamp: msg.timestamp,
|
|
203
|
+
});
|
|
204
|
+
return msg;
|
|
205
|
+
}
|
|
206
|
+
sendShareContext(peerName, context) {
|
|
207
|
+
const peer = this.findPeerByName(peerName);
|
|
208
|
+
if (!peer || !peer.send) {
|
|
209
|
+
throw new Error(`No active connection with peer: ${peerName}`);
|
|
210
|
+
}
|
|
211
|
+
const msg = (0, message_protocol_js_1.createShareContextMessage)(this.profile.name, context);
|
|
212
|
+
const serialized = (0, message_protocol_js_1.serializeMessage)(msg);
|
|
213
|
+
peer.send(serialized);
|
|
214
|
+
this.trackBytes(serialized.length);
|
|
215
|
+
this.db.logEvent("share_context_sent", peerName, peer.connectionId, "project context");
|
|
216
|
+
this.db.saveMessage({
|
|
217
|
+
id: msg.id,
|
|
218
|
+
connectionId: peer.connectionId,
|
|
219
|
+
direction: "sent",
|
|
220
|
+
type: msg.type,
|
|
221
|
+
content: msg.content,
|
|
222
|
+
sourceFiles: null,
|
|
223
|
+
replyTo: null,
|
|
224
|
+
timestamp: msg.timestamp,
|
|
225
|
+
});
|
|
226
|
+
return msg;
|
|
227
|
+
}
|
|
145
228
|
handleIncomingMessage(connectionId, rawData) {
|
|
229
|
+
this.trackBytes(rawData.length);
|
|
146
230
|
const msg = (0, message_protocol_js_1.parseMessage)(rawData);
|
|
147
231
|
if (!msg)
|
|
148
232
|
return;
|