@kendoo.agentdesk/agentdesk 0.3.1 → 0.4.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/README.md CHANGED
@@ -42,17 +42,17 @@ This detects your project, asks which task tracker you use (Linear, Jira, GitHub
42
42
 
43
43
  ### 4. Run a team session
44
44
 
45
- With a task tracker:
45
+ Work on an existing task:
46
46
 
47
47
  ```bash
48
48
  agentdesk team KEN-517
49
- agentdesk team BUG-42 -d "Fix the checkout total calculation"
50
49
  ```
51
50
 
52
- Without a trackerpass requirements directly:
51
+ Or just describe what you want a task is created automatically:
53
52
 
54
53
  ```bash
55
- agentdesk team add-auth -d "Add Google OAuth to the login page"
54
+ agentdesk team -d "Fix the checkout total calculation"
55
+ agentdesk team -d "Add Google OAuth to the login page"
56
56
  ```
57
57
 
58
58
  Open [agentdesk.live](https://agentdesk.live) to watch the session live.
@@ -102,8 +102,8 @@ AgentDesk also auto-discovers agents from `.claude/agents/`, `.claude/commands/`
102
102
  agentdesk login Sign in to AgentDesk
103
103
  agentdesk logout Sign out and remove credentials
104
104
  agentdesk init Set up project and configure tracker
105
- agentdesk team <TASK-ID> Run a team session on a task
106
- agentdesk team <TASK-ID> -d "..." Run with a task description
105
+ agentdesk team <TASK-ID> Run a team session on an existing task
106
+ agentdesk team -d "..." Describe what you want — task created automatically
107
107
  ```
108
108
 
109
109
  ### Options
package/bin/agentdesk.mjs CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  // AgentDesk CLI — AI team orchestrator
4
4
 
5
+ import { readFileSync } from "fs";
6
+ import { fileURLToPath } from "url";
7
+ import { dirname, join } from "path";
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = dirname(__filename);
11
+ const pkg = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8"));
12
+
13
+ // Non-blocking update check — runs in background, never delays startup
14
+ (async () => {
15
+ try {
16
+ const res = await fetch(`https://registry.npmjs.org/${pkg.name}/latest`, { signal: AbortSignal.timeout(3000) });
17
+ if (!res.ok) return;
18
+ const { version } = await res.json();
19
+ if (version !== pkg.version) {
20
+ console.log(`\n Update available: ${pkg.version} → ${version}`);
21
+ console.log(` Run: npm i -g ${pkg.name}\n`);
22
+ }
23
+ } catch {}
24
+ })();
25
+
5
26
  const args = process.argv.slice(2);
6
27
  const command = args[0];
7
28
 
@@ -18,22 +39,25 @@ if (!command || command === "help" || command === "--help") {
18
39
  agentdesk login Sign in to AgentDesk
19
40
  agentdesk logout Sign out and remove credentials
20
41
  agentdesk init Set up project and configure tracker
21
- agentdesk team <TASK-ID> Run a team session on a task
22
- agentdesk team <TASK-ID> -d "..." Run with a task description
42
+ agentdesk team <TASK-ID> Run a team session on an existing task
43
+ agentdesk team -d "..." Create a task and run a session
23
44
 
24
45
  Options:
25
46
  --description, -d Task description or requirements
26
47
  --cwd Working directory (defaults to current)
27
48
 
28
- Task trackers:
29
- agentdesk init configures your tracker (Linear, Jira, GitHub Issues).
30
- Without a tracker, pass requirements directly:
31
- agentdesk team my-feature -d "Add dark mode support"
49
+ How it works:
50
+ With a tracker (Linear, Jira, GitHub Issues):
51
+ agentdesk team KEN-517 Work on an existing task
52
+ agentdesk team -d "Fix login bug" Create a new task, then work on it
53
+
54
+ Without a tracker:
55
+ agentdesk team -d "Add dark mode" Describe what you want
32
56
 
33
57
  Examples:
34
58
  agentdesk team KEN-517
35
- agentdesk team BUG-42 -d "Fix the checkout total calculation"
36
- agentdesk team add-auth -d "Add Google OAuth to the login page"
59
+ agentdesk team -d "Fix the checkout total calculation"
60
+ agentdesk team -d "Add Google OAuth to the login page"
37
61
 
38
62
  Dashboard: https://agentdesk.live
39
63
  `);
@@ -56,23 +80,28 @@ else if (command === "init") {
56
80
  }
57
81
 
58
82
  else if (command === "team") {
59
- const taskId = args[1];
60
- if (!taskId) {
61
- console.error("Usage: agentdesk team <TASK-ID>");
62
- process.exit(1);
63
- }
64
-
65
- // Parse options
83
+ // Parse options first to find -d and --cwd
66
84
  let description = "";
67
85
  let cwd = process.cwd();
68
- for (let i = 2; i < args.length; i++) {
69
- if ((args[i] === "--description" || args[i] === "-d") && args[i + 1]) {
70
- description = args[++i];
71
- } else if (args[i] === "--cwd" && args[i + 1]) {
72
- cwd = args[++i];
86
+ let taskId = null;
87
+ const remaining = args.slice(1);
88
+
89
+ for (let i = 0; i < remaining.length; i++) {
90
+ if ((remaining[i] === "--description" || remaining[i] === "-d") && remaining[i + 1]) {
91
+ description = remaining[++i];
92
+ } else if (remaining[i] === "--cwd" && remaining[i + 1]) {
93
+ cwd = remaining[++i];
94
+ } else if (!taskId && !remaining[i].startsWith("-")) {
95
+ taskId = remaining[i];
73
96
  }
74
97
  }
75
98
 
99
+ if (!taskId && !description) {
100
+ console.error("Usage: agentdesk team <TASK-ID>");
101
+ console.error(" or: agentdesk team -d \"description\"");
102
+ process.exit(1);
103
+ }
104
+
76
105
  const { runTeam } = await import("../cli/team.mjs");
77
106
  const code = await runTeam(taskId, { description, cwd });
78
107
  process.exit(code);
package/cli/team.mjs CHANGED
@@ -36,19 +36,44 @@ export async function runTeam(taskId, opts = {}) {
36
36
  // Detect project and load config
37
37
  const project = detectProject(cwd);
38
38
  const config = loadConfig(cwd);
39
- console.log(`Project: ${project.name || "unknown"} (${project.label})`);
40
- console.log(`Task: ${taskId}`);
41
-
42
- // Determine tracker and build task link
43
39
  const tracker = config.tracker || (project.hasLinear ? "linear" : null);
40
+
41
+ // If no task ID, handle based on tracker
42
+ let createTask = false;
43
+ if (!taskId) {
44
+ if (tracker) {
45
+ // Tracker configured but no task ID — agents will create a task
46
+ createTask = true;
47
+ taskId = `new-${Date.now().toString(36)}`;
48
+ console.log(`Project: ${project.name || "unknown"} (${project.label})`);
49
+ console.log(`Mode: Create new ${tracker} task from description`);
50
+ } else {
51
+ // No tracker — generate a label from description
52
+ taskId = description
53
+ .toLowerCase()
54
+ .replace(/[^a-z0-9\s-]/g, "")
55
+ .trim()
56
+ .replace(/\s+/g, "-")
57
+ .slice(0, 40) || `task-${Date.now().toString(36)}`;
58
+ console.log(`Project: ${project.name || "unknown"} (${project.label})`);
59
+ console.log(`Task: ${taskId}`);
60
+ }
61
+ } else {
62
+ console.log(`Project: ${project.name || "unknown"} (${project.label})`);
63
+ console.log(`Task: ${taskId}`);
64
+ }
65
+
66
+ // Build task link (only for existing tasks with a tracker)
44
67
  let taskLink = null;
45
- if (tracker === "linear" && config.linear?.workspace) {
46
- taskLink = `https://linear.app/${config.linear.workspace}/issue/${taskId}`;
47
- } else if (tracker === "jira" && config.jira?.baseUrl) {
48
- taskLink = `${config.jira.baseUrl}/browse/${taskId}`;
49
- } else if (tracker === "github") {
50
- const repo = config.github?.repo || "";
51
- if (repo) taskLink = `https://github.com/${repo}/issues/${taskId}`;
68
+ if (!createTask) {
69
+ if (tracker === "linear" && config.linear?.workspace) {
70
+ taskLink = `https://linear.app/${config.linear.workspace}/issue/${taskId}`;
71
+ } else if (tracker === "jira" && config.jira?.baseUrl) {
72
+ taskLink = `${config.jira.baseUrl}/browse/${taskId}`;
73
+ } else if (tracker === "github") {
74
+ const repo = config.github?.repo || "";
75
+ if (repo) taskLink = `https://github.com/${repo}/issues/${taskId}`;
76
+ }
52
77
  }
53
78
  if (tracker) console.log(`Tracker: ${tracker}`);
54
79
  if (taskLink) console.log(`Task: ${taskLink}`);
@@ -68,6 +93,20 @@ export async function runTeam(taskId, opts = {}) {
68
93
  prompt = prompt.replace(/\{\{#TASK_DESCRIPTION\}\}[\s\S]*?\{\{\/TASK_DESCRIPTION\}\}/g, "");
69
94
  }
70
95
 
96
+ // Create task instruction — when -d is used without a task ID and a tracker is configured
97
+ if (createTask && description) {
98
+ let createInstr = "\n\n## CREATE TASK\n\nNo task ID was provided. Before starting work, Jane MUST create a new task in the tracker:\n\n";
99
+ if (tracker === "linear") {
100
+ createInstr += `Create a Linear issue using the GraphQL API:\n- Endpoint: https://api.linear.app/graphql\n- Auth: Authorization: $LINEAR_API_KEY\n- Set the title based on the description below\n- After creation, use the returned identifier (e.g., KEN-530) as the task ID for the rest of the session\n`;
101
+ } else if (tracker === "jira") {
102
+ createInstr += `Create a Jira issue:\n- Endpoint: ${config.jira?.baseUrl || ""}/rest/api/3/issue\n- Auth: Basic auth with $JIRA_EMAIL and $JIRA_API_TOKEN\n- Set the summary based on the description below\n- After creation, use the returned key (e.g., PROJ-42) as the task ID for the rest of the session\n`;
103
+ } else if (tracker === "github") {
104
+ createInstr += `Create a GitHub issue:\n- Run: gh issue create --title "..." --body "..."\n- After creation, use the returned issue number as the task ID for the rest of the session\n`;
105
+ }
106
+ createInstr += `\nTask description: ${description}\n`;
107
+ prompt += createInstr;
108
+ }
109
+
71
110
  // Tracker integration — enable the matching section, strip the rest
72
111
  const trackers = ["LINEAR", "JIRA", "GITHUB"];
73
112
  for (const t of trackers) {
@@ -100,8 +139,7 @@ export async function runTeam(taskId, opts = {}) {
100
139
  const projectEnv = loadDotEnv(cwd);
101
140
  const apiKey = projectEnv.AGENTDESK_API_KEY || process.env.AGENTDESK_API_KEY || getStoredApiKey() || null;
102
141
  const agentdeskServer = process.env.AGENTDESK_SERVER || "https://agentdesk.live";
103
- const baseUrl = process.env.AGENTDESK_URL || "wss://agentdesk.live/ws/agent";
104
- const AGENTDESK_URL = apiKey ? `${baseUrl}?api_key=${apiKey}` : baseUrl;
142
+ const AGENTDESK_URL = process.env.AGENTDESK_URL || "wss://agentdesk.live/ws/agent";
105
143
  const sessionId = `${taskId}-${randomUUID().slice(0, 8)}`;
106
144
  const inboxUrl = `${agentdeskServer}/api/sessions/${sessionId}/inbox`;
107
145
 
@@ -138,33 +176,40 @@ export async function runTeam(taskId, opts = {}) {
138
176
  try {
139
177
  vizWs = new WebSocket(AGENTDESK_URL);
140
178
  vizWs.on("open", () => {
141
- vizConnected = true;
142
- console.log("AgentDesk: connected");
143
- vizSend({
144
- type: "session:start",
145
- taskId,
146
- taskLink,
147
- title: description || taskId,
148
- project: project.name || null,
149
- sessionNumber: 1,
150
- agents: ["Jane", "Dennis", "Bart", "Vera", "Sam", "Luna", "Mark"],
151
- });
152
- while (vizQueue.length > 0 && vizWs.readyState === WebSocket.OPEN) {
153
- vizWs.send(vizQueue.shift());
179
+ // Authenticate via first message (proxy-safe — query params can be stripped)
180
+ if (apiKey) {
181
+ vizWs.send(JSON.stringify({ type: "auth", apiKey }));
182
+ }
183
+ });
184
+ vizWs.on("message", (raw) => {
185
+ let msg;
186
+ try { msg = JSON.parse(raw.toString()); } catch { return; }
187
+ if (msg.type === "auth:ok") {
188
+ vizConnected = true;
189
+ console.log("AgentDesk: connected");
190
+ vizSend({
191
+ type: "session:start",
192
+ taskId,
193
+ taskLink,
194
+ title: description || taskId,
195
+ project: project.name || null,
196
+ sessionNumber: 1,
197
+ agents: ["Jane", "Dennis", "Bart", "Vera", "Sam", "Luna", "Mark"],
198
+ });
199
+ while (vizQueue.length > 0 && vizWs.readyState === WebSocket.OPEN) {
200
+ vizWs.send(vizQueue.shift());
201
+ }
202
+ } else if (msg.type === "auth:error") {
203
+ console.log("AgentDesk: authentication failed — run 'agentdesk login'");
204
+ vizConnected = false;
154
205
  }
155
206
  });
156
207
  vizWs.on("error", () => { vizConnected = false; });
157
208
  vizWs.on("close", (code) => {
158
209
  vizConnected = false;
159
- if (code === 1006 && !vizConnected) {
160
- console.log("AgentDesk: not connected — run 'agentdesk login' to authenticate");
161
- }
162
- });
163
- vizWs.on("unexpected-response", (_req, res) => {
164
- if (res.statusCode === 401) {
210
+ if (code === 4001) {
165
211
  console.log("AgentDesk: authentication required — run 'agentdesk login'");
166
212
  }
167
- vizConnected = false;
168
213
  });
169
214
  } catch {
170
215
  // AgentDesk not running
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kendoo.agentdesk/agentdesk",
3
- "version": "0.3.1",
3
+ "version": "0.4.2",
4
4
  "description": "AI team orchestrator for Claude Code — run collaborative agent sessions from your terminal",
5
5
  "type": "module",
6
6
  "bin": {