@kendoo.agentdesk/agentdesk 0.1.0 → 0.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 +119 -0
- package/bin/agentdesk.mjs +17 -5
- package/cli/init.mjs +3 -2
- package/cli/login.mjs +129 -0
- package/cli/team.mjs +2 -1
- package/package.json +3 -2
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# AgentDesk
|
|
2
|
+
|
|
3
|
+
AI team orchestrator for [Claude Code](https://claude.ai/claude-code). Run collaborative agent sessions from your terminal and watch them live on [agentdesk.live](https://agentdesk.live).
|
|
4
|
+
|
|
5
|
+
AgentDesk spawns a team of 7 specialized AI agents that collaborate on your tasks:
|
|
6
|
+
|
|
7
|
+
| Agent | Role |
|
|
8
|
+
|-------|------|
|
|
9
|
+
| Jane | Product Lead — facilitates, clarifies requirements, coordinates the team |
|
|
10
|
+
| Luna | UX/UI Designer — visual consistency, accessibility, interaction patterns |
|
|
11
|
+
| Mark | Content Writer — copy, tone, user-facing text |
|
|
12
|
+
| Sam | Architecture Auditor — code structure, separation of concerns |
|
|
13
|
+
| Dennis | Senior Developer — implements the solution |
|
|
14
|
+
| Bart | QA Engineer — edge cases, risks, acceptance criteria |
|
|
15
|
+
| Vera | Test Engineer — unit tests, regression coverage |
|
|
16
|
+
|
|
17
|
+
## Getting Started
|
|
18
|
+
|
|
19
|
+
### 1. Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm i -g @kendoo.agentdesk/agentdesk
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Requires [Node.js](https://nodejs.org/) 18+ and [Claude Code](https://claude.ai/claude-code) installed.
|
|
26
|
+
|
|
27
|
+
### 2. Log in
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
agentdesk login
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This opens your browser to [agentdesk.live](https://agentdesk.live) where you sign up or log in. Your API key is saved automatically to `~/.agentdesk/credentials.json`.
|
|
34
|
+
|
|
35
|
+
### 3. Set up your project
|
|
36
|
+
|
|
37
|
+
Navigate to your project and run init:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
agentdesk init
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 4. Run a team session
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
agentdesk team KEN-517
|
|
47
|
+
agentdesk team BUG-42 -d "Fix the checkout total calculation"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Open [agentdesk.live](https://agentdesk.live) to watch the session live.
|
|
51
|
+
|
|
52
|
+
## Configuration
|
|
53
|
+
|
|
54
|
+
Create `.agentdesk.json` in your project root to customize behavior:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"tracker": "linear",
|
|
59
|
+
"linear": { "workspace": "your-workspace" }
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Task trackers
|
|
64
|
+
|
|
65
|
+
| Tracker | Config |
|
|
66
|
+
|---------|--------|
|
|
67
|
+
| Linear | `{ "tracker": "linear", "linear": { "workspace": "..." } }` |
|
|
68
|
+
| Jira | `{ "tracker": "jira", "jira": { "baseUrl": "https://yourcompany.atlassian.net" } }` |
|
|
69
|
+
| GitHub Issues | `{ "tracker": "github", "github": { "repo": "owner/repo" } }` |
|
|
70
|
+
|
|
71
|
+
### Declaring project agents
|
|
72
|
+
|
|
73
|
+
If your project has existing AI agents, bots, or automation, declare them so the team knows about them:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"projectAgents": [
|
|
78
|
+
{
|
|
79
|
+
"name": "ReviewBot",
|
|
80
|
+
"role": "Auto-reviews PRs for security issues",
|
|
81
|
+
"when": "Triggers on every PR creation",
|
|
82
|
+
"how": "Comment /review on a PR to re-trigger"
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
AgentDesk also auto-discovers agents from `.claude/agents/`, `.claude/commands/`, `.mcp.json`, GitHub Actions workflows, Dependabot, and Renovate configs.
|
|
89
|
+
|
|
90
|
+
## Usage
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
agentdesk login Log in to AgentDesk
|
|
94
|
+
agentdesk logout Log out and remove credentials
|
|
95
|
+
agentdesk init Detect project and show setup info
|
|
96
|
+
agentdesk team <TASK-ID> Run a team session on a task
|
|
97
|
+
agentdesk team <TASK-ID> -d "..." Run with a task description
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Options
|
|
101
|
+
|
|
102
|
+
| Flag | Description |
|
|
103
|
+
|------|-------------|
|
|
104
|
+
| `--description`, `-d` | Task description (for projects without a task tracker) |
|
|
105
|
+
| `--cwd` | Working directory (defaults to current) |
|
|
106
|
+
|
|
107
|
+
## How It Works
|
|
108
|
+
|
|
109
|
+
1. You run `agentdesk team TASK-ID` in your project directory
|
|
110
|
+
2. AgentDesk detects your project type, reads `CLAUDE.md`, and discovers existing agents
|
|
111
|
+
3. A Claude Code session starts with all 7 agents collaborating on your task
|
|
112
|
+
4. The team goes through structured phases: **Brainstorm** > **Planning** > **Execution** > **Review**
|
|
113
|
+
5. The session streams live to [agentdesk.live](https://agentdesk.live) where you can watch and send messages to the team
|
|
114
|
+
|
|
115
|
+
## Requirements
|
|
116
|
+
|
|
117
|
+
- [Node.js](https://nodejs.org/) 18+
|
|
118
|
+
- [Claude Code](https://claude.ai/claude-code) CLI installed and authenticated
|
|
119
|
+
- An AgentDesk account at [agentdesk.live](https://agentdesk.live)
|
package/bin/agentdesk.mjs
CHANGED
|
@@ -10,12 +10,13 @@ if (!command || command === "help" || command === "--help") {
|
|
|
10
10
|
AgentDesk — AI team orchestrator for Claude Code
|
|
11
11
|
|
|
12
12
|
Getting started:
|
|
13
|
-
1.
|
|
14
|
-
2.
|
|
15
|
-
3. Run: agentdesk
|
|
16
|
-
4. Run: agentdesk team <TASK-ID>
|
|
13
|
+
1. Run: agentdesk login
|
|
14
|
+
2. Run: agentdesk init
|
|
15
|
+
3. Run: agentdesk team <TASK-ID>
|
|
17
16
|
|
|
18
17
|
Usage:
|
|
18
|
+
agentdesk login Log in to AgentDesk
|
|
19
|
+
agentdesk logout Log out and remove credentials
|
|
19
20
|
agentdesk init Detect project and show setup info
|
|
20
21
|
agentdesk team <TASK-ID> Run a team session on a task
|
|
21
22
|
agentdesk team <TASK-ID> -d "..." Run with a task description
|
|
@@ -32,6 +33,7 @@ if (!command || command === "help" || command === "--help") {
|
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
Examples:
|
|
36
|
+
agentdesk login
|
|
35
37
|
agentdesk init
|
|
36
38
|
agentdesk team KEN-517
|
|
37
39
|
agentdesk team BUG-42 -d "Fix the checkout total calculation"
|
|
@@ -41,7 +43,17 @@ if (!command || command === "help" || command === "--help") {
|
|
|
41
43
|
process.exit(0);
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
if (command === "
|
|
46
|
+
if (command === "login") {
|
|
47
|
+
const { runLogin } = await import("../cli/login.mjs");
|
|
48
|
+
await runLogin();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
else if (command === "logout") {
|
|
52
|
+
const { runLogout } = await import("../cli/login.mjs");
|
|
53
|
+
await runLogout();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
else if (command === "init") {
|
|
45
57
|
const { runInit } = await import("../cli/init.mjs");
|
|
46
58
|
await runInit(process.cwd());
|
|
47
59
|
}
|
package/cli/init.mjs
CHANGED
|
@@ -4,14 +4,15 @@ import { existsSync, readFileSync } from "fs";
|
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
import { detectProject } from "./detect.mjs";
|
|
6
6
|
import { loadConfig } from "./config.mjs";
|
|
7
|
+
import { getStoredApiKey } from "./login.mjs";
|
|
7
8
|
|
|
8
9
|
const SERVER = process.env.AGENTDESK_SERVER || "https://agentdesk.live";
|
|
9
10
|
|
|
10
11
|
function loadApiKey(dir) {
|
|
11
12
|
const envPath = join(dir, ".env");
|
|
12
|
-
if (!existsSync(envPath)) return
|
|
13
|
+
if (!existsSync(envPath)) return getStoredApiKey();
|
|
13
14
|
const match = readFileSync(envPath, "utf-8").match(/AGENTDESK_API_KEY=(.+)/);
|
|
14
|
-
return match?.[1]?.trim() ||
|
|
15
|
+
return match?.[1]?.trim() || getStoredApiKey();
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export async function runInit(cwd) {
|
package/cli/login.mjs
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// `agentdesk login` — authenticate with AgentDesk and save API key
|
|
2
|
+
|
|
3
|
+
import { createServer } from "http";
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
import { randomUUID } from "crypto";
|
|
7
|
+
|
|
8
|
+
const AGENTDESK_SERVER = process.env.AGENTDESK_SERVER || "https://agentdesk.live";
|
|
9
|
+
const CONFIG_DIR = join(process.env.HOME || process.env.USERPROFILE, ".agentdesk");
|
|
10
|
+
const CREDENTIALS_PATH = join(CONFIG_DIR, "credentials.json");
|
|
11
|
+
|
|
12
|
+
export function getStoredApiKey() {
|
|
13
|
+
if (!existsSync(CREDENTIALS_PATH)) return null;
|
|
14
|
+
try {
|
|
15
|
+
const creds = JSON.parse(readFileSync(CREDENTIALS_PATH, "utf-8"));
|
|
16
|
+
return creds.apiKey || null;
|
|
17
|
+
} catch { return null; }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function runLogin() {
|
|
21
|
+
console.log("");
|
|
22
|
+
console.log(" AgentDesk — Login");
|
|
23
|
+
console.log(" ━━━━━━━━━━━━━━━━");
|
|
24
|
+
console.log("");
|
|
25
|
+
|
|
26
|
+
// Check if already logged in
|
|
27
|
+
const existing = getStoredApiKey();
|
|
28
|
+
if (existing) {
|
|
29
|
+
console.log(` Already logged in (key: ${existing.slice(0, 8)}...)`);
|
|
30
|
+
console.log("");
|
|
31
|
+
console.log(" To re-authenticate, run: agentdesk logout");
|
|
32
|
+
console.log("");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const state = randomUUID();
|
|
37
|
+
|
|
38
|
+
// Start a local server to receive the API key callback
|
|
39
|
+
const server = createServer((req, res) => {
|
|
40
|
+
// Allow CORS from agentdesk.live
|
|
41
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
42
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
43
|
+
if (req.method === "OPTIONS") { res.writeHead(200); res.end(); return; }
|
|
44
|
+
|
|
45
|
+
const url = new URL(req.url, `http://localhost`);
|
|
46
|
+
|
|
47
|
+
if (url.pathname === "/callback") {
|
|
48
|
+
const apiKey = url.searchParams.get("api_key");
|
|
49
|
+
const name = url.searchParams.get("name");
|
|
50
|
+
const returnedState = url.searchParams.get("state");
|
|
51
|
+
|
|
52
|
+
// CSRF check
|
|
53
|
+
if (returnedState !== state) {
|
|
54
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
55
|
+
res.end("<html><body><h2>Invalid state. Please try again.</h2></body></html>");
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (apiKey) {
|
|
60
|
+
// Save credentials
|
|
61
|
+
if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true });
|
|
62
|
+
writeFileSync(CREDENTIALS_PATH, JSON.stringify({ apiKey, name, savedAt: Date.now() }, null, 2));
|
|
63
|
+
|
|
64
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
65
|
+
res.end(`<html><body style="background:#0f172a;color:#e2e8f0;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0"><div style="text-align:center"><h2 style="color:#2dd4bf">Logged in to AgentDesk</h2><p>You can close this tab and return to your terminal.</p></div></body></html>`);
|
|
66
|
+
|
|
67
|
+
console.log(` Logged in as ${name || "user"}`);
|
|
68
|
+
console.log(` API key saved to ~/.agentdesk/credentials.json`);
|
|
69
|
+
console.log("");
|
|
70
|
+
console.log(" Next steps:");
|
|
71
|
+
console.log(" agentdesk init");
|
|
72
|
+
console.log(" agentdesk team TASK-123");
|
|
73
|
+
console.log("");
|
|
74
|
+
|
|
75
|
+
setTimeout(() => { server.close(); process.exit(0); }, 500);
|
|
76
|
+
} else {
|
|
77
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
78
|
+
res.end("<html><body><h2>Login failed. No API key received.</h2></body></html>");
|
|
79
|
+
}
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
res.writeHead(404);
|
|
84
|
+
res.end();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Find an available port
|
|
88
|
+
await new Promise((resolve) => {
|
|
89
|
+
server.listen(0, "127.0.0.1", resolve);
|
|
90
|
+
});
|
|
91
|
+
const port = server.address().port;
|
|
92
|
+
|
|
93
|
+
const loginUrl = `${AGENTDESK_SERVER}/cli-auth?port=${port}&state=${state}`;
|
|
94
|
+
|
|
95
|
+
console.log(` Opening browser to log in...`);
|
|
96
|
+
console.log("");
|
|
97
|
+
console.log(` If the browser doesn't open, visit:`);
|
|
98
|
+
console.log(` ${loginUrl}`);
|
|
99
|
+
console.log("");
|
|
100
|
+
console.log(" Waiting for authentication...");
|
|
101
|
+
|
|
102
|
+
// Open browser
|
|
103
|
+
const { exec } = await import("child_process");
|
|
104
|
+
const platform = process.platform;
|
|
105
|
+
const cmd = platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open";
|
|
106
|
+
exec(`${cmd} "${loginUrl}"`);
|
|
107
|
+
|
|
108
|
+
// Timeout after 5 minutes
|
|
109
|
+
setTimeout(() => {
|
|
110
|
+
console.log("");
|
|
111
|
+
console.log(" Login timed out. Please try again.");
|
|
112
|
+
server.close();
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}, 5 * 60 * 1000);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export async function runLogout() {
|
|
118
|
+
if (existsSync(CREDENTIALS_PATH)) {
|
|
119
|
+
const { unlinkSync } = await import("fs");
|
|
120
|
+
unlinkSync(CREDENTIALS_PATH);
|
|
121
|
+
console.log("");
|
|
122
|
+
console.log(" Logged out. Credentials removed.");
|
|
123
|
+
console.log("");
|
|
124
|
+
} else {
|
|
125
|
+
console.log("");
|
|
126
|
+
console.log(" Not logged in.");
|
|
127
|
+
console.log("");
|
|
128
|
+
}
|
|
129
|
+
}
|
package/cli/team.mjs
CHANGED
|
@@ -9,6 +9,7 @@ import { randomUUID } from "crypto";
|
|
|
9
9
|
import WebSocket from "ws";
|
|
10
10
|
import { detectProject, generateContext } from "./detect.mjs";
|
|
11
11
|
import { loadConfig } from "./config.mjs";
|
|
12
|
+
import { getStoredApiKey } from "./login.mjs";
|
|
12
13
|
|
|
13
14
|
function loadDotEnv(dir) {
|
|
14
15
|
const envPath = join(dir, ".env");
|
|
@@ -96,7 +97,7 @@ export async function runTeam(taskId, opts = {}) {
|
|
|
96
97
|
|
|
97
98
|
// --- AgentDesk config ---
|
|
98
99
|
const projectEnv = loadDotEnv(cwd);
|
|
99
|
-
const apiKey = projectEnv.AGENTDESK_API_KEY || process.env.AGENTDESK_API_KEY || null;
|
|
100
|
+
const apiKey = projectEnv.AGENTDESK_API_KEY || process.env.AGENTDESK_API_KEY || getStoredApiKey() || null;
|
|
100
101
|
const agentdeskServer = process.env.AGENTDESK_SERVER || "https://agentdesk.live";
|
|
101
102
|
const baseUrl = process.env.AGENTDESK_URL || "wss://agentdesk.live/ws/agent";
|
|
102
103
|
const AGENTDESK_URL = apiKey ? `${baseUrl}?api_key=${apiKey}` : baseUrl;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kendoo.agentdesk/agentdesk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "AI team orchestrator for Claude Code — run collaborative agent sessions from your terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"bin/",
|
|
11
11
|
"cli/",
|
|
12
|
-
"prompts/"
|
|
12
|
+
"prompts/",
|
|
13
|
+
"README.md"
|
|
13
14
|
],
|
|
14
15
|
"engines": {
|
|
15
16
|
"node": ">=18"
|