@kendoo.agentdesk/agentdesk 0.2.1 → 0.3.1

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
@@ -1,6 +1,6 @@
1
1
  # AgentDesk
2
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).
3
+ AI team orchestrator. Run collaborative agent sessions from your terminal and watch them live on [agentdesk.live](https://agentdesk.live).
4
4
 
5
5
  AgentDesk spawns a team of 7 specialized AI agents that collaborate on your tasks:
6
6
 
@@ -22,36 +22,44 @@ AgentDesk spawns a team of 7 specialized AI agents that collaborate on your task
22
22
  npm i -g @kendoo.agentdesk/agentdesk
23
23
  ```
24
24
 
25
- Requires [Node.js](https://nodejs.org/) 18+ and [Claude Code](https://claude.ai/claude-code) installed.
25
+ Requires [Node.js](https://nodejs.org/) 18+.
26
26
 
27
- ### 2. Log in
27
+ ### 2. Sign in
28
28
 
29
29
  ```bash
30
30
  agentdesk login
31
31
  ```
32
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`.
33
+ Opens your browser to [agentdesk.live](https://agentdesk.live) where you sign up or log in (email/password or Google). Your API key is saved automatically.
34
34
 
35
35
  ### 3. Set up your project
36
36
 
37
- Navigate to your project and run init:
38
-
39
37
  ```bash
40
38
  agentdesk init
41
39
  ```
42
40
 
41
+ This detects your project, asks which task tracker you use (Linear, Jira, GitHub Issues, or none), and saves the config to `.agentdesk.json`.
42
+
43
43
  ### 4. Run a team session
44
44
 
45
+ With a task tracker:
46
+
45
47
  ```bash
46
48
  agentdesk team KEN-517
47
49
  agentdesk team BUG-42 -d "Fix the checkout total calculation"
48
50
  ```
49
51
 
52
+ Without a tracker — pass requirements directly:
53
+
54
+ ```bash
55
+ agentdesk team add-auth -d "Add Google OAuth to the login page"
56
+ ```
57
+
50
58
  Open [agentdesk.live](https://agentdesk.live) to watch the session live.
51
59
 
52
60
  ## Configuration
53
61
 
54
- Create `.agentdesk.json` in your project root to customize behavior:
62
+ `agentdesk init` creates `.agentdesk.json` in your project root. You can also edit it manually:
55
63
 
56
64
  ```json
57
65
  {
@@ -65,8 +73,9 @@ Create `.agentdesk.json` in your project root to customize behavior:
65
73
  | Tracker | Config |
66
74
  |---------|--------|
67
75
  | Linear | `{ "tracker": "linear", "linear": { "workspace": "..." } }` |
68
- | Jira | `{ "tracker": "jira", "jira": { "baseUrl": "https://yourcompany.atlassian.net" } }` |
76
+ | Jira | `{ "tracker": "jira", "jira": { "baseUrl": "https://company.atlassian.net" } }` |
69
77
  | GitHub Issues | `{ "tracker": "github", "github": { "repo": "owner/repo" } }` |
78
+ | None | No config needed — pass `-d "description"` when running a session |
70
79
 
71
80
  ### Declaring project agents
72
81
 
@@ -87,12 +96,12 @@ If your project has existing AI agents, bots, or automation, declare them so the
87
96
 
88
97
  AgentDesk also auto-discovers agents from `.claude/agents/`, `.claude/commands/`, `.mcp.json`, GitHub Actions workflows, Dependabot, and Renovate configs.
89
98
 
90
- ## Usage
99
+ ## Commands
91
100
 
92
101
  ```
93
- agentdesk login Log in to AgentDesk
94
- agentdesk logout Log out and remove credentials
95
- agentdesk init Detect project and show setup info
102
+ agentdesk login Sign in to AgentDesk
103
+ agentdesk logout Sign out and remove credentials
104
+ agentdesk init Set up project and configure tracker
96
105
  agentdesk team <TASK-ID> Run a team session on a task
97
106
  agentdesk team <TASK-ID> -d "..." Run with a task description
98
107
  ```
@@ -101,19 +110,17 @@ agentdesk team <TASK-ID> -d "..." Run with a task description
101
110
 
102
111
  | Flag | Description |
103
112
  |------|-------------|
104
- | `--description`, `-d` | Task description (for projects without a task tracker) |
113
+ | `--description`, `-d` | Task description or requirements |
105
114
  | `--cwd` | Working directory (defaults to current) |
106
115
 
107
116
  ## How It Works
108
117
 
109
118
  1. You run `agentdesk team TASK-ID` in your project directory
110
119
  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
120
+ 3. 7 AI agents collaborate on your task in structured phases: **Brainstorm** > **Planning** > **Execution** > **Review**
121
+ 4. The session streams live to [agentdesk.live](https://agentdesk.live) where you can watch and send messages to the team
114
122
 
115
123
  ## Requirements
116
124
 
117
125
  - [Node.js](https://nodejs.org/) 18+
118
- - [Claude Code](https://claude.ai/claude-code) CLI installed and authenticated
119
126
  - An AgentDesk account at [agentdesk.live](https://agentdesk.live)
package/bin/agentdesk.mjs CHANGED
@@ -1,42 +1,39 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // AgentDesk CLI — AI team orchestrator for Claude Code
3
+ // AgentDesk CLI — AI team orchestrator
4
4
 
5
5
  const args = process.argv.slice(2);
6
6
  const command = args[0];
7
7
 
8
8
  if (!command || command === "help" || command === "--help") {
9
9
  console.log(`
10
- AgentDesk — AI team orchestrator for Claude Code
10
+ AgentDesk — AI team orchestrator
11
11
 
12
12
  Getting started:
13
- 1. Run: agentdesk login
14
- 2. Run: agentdesk init
15
- 3. Run: agentdesk team <TASK-ID>
16
-
17
- Usage:
18
- agentdesk login Log in to AgentDesk
19
- agentdesk logout Log out and remove credentials
20
- agentdesk init Detect project and show setup info
13
+ 1. agentdesk login Sign in to your account
14
+ 2. agentdesk init Set up your project (choose tracker, save config)
15
+ 3. agentdesk team TASK-123 Run a team session
16
+
17
+ Commands:
18
+ agentdesk login Sign in to AgentDesk
19
+ agentdesk logout Sign out and remove credentials
20
+ agentdesk init Set up project and configure tracker
21
21
  agentdesk team <TASK-ID> Run a team session on a task
22
22
  agentdesk team <TASK-ID> -d "..." Run with a task description
23
23
 
24
24
  Options:
25
- --description, -d Task description (for projects without a task tracker)
25
+ --description, -d Task description or requirements
26
26
  --cwd Working directory (defaults to current)
27
27
 
28
- Configuration:
29
- Create .agentdesk.json in your project root:
30
- {
31
- "tracker": "linear", // "linear" | "jira" | "github"
32
- "linear": { "workspace": "..." } // for task links in the dashboard
33
- }
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"
34
32
 
35
33
  Examples:
36
- agentdesk login
37
- agentdesk init
38
34
  agentdesk team KEN-517
39
35
  agentdesk team BUG-42 -d "Fix the checkout total calculation"
36
+ agentdesk team add-auth -d "Add Google OAuth to the login page"
40
37
 
41
38
  Dashboard: https://agentdesk.live
42
39
  `);
package/cli/agents.mjs ADDED
@@ -0,0 +1,267 @@
1
+ // Agent registry — defines all built-in agents and generates prompt sections
2
+
3
+ export const BUILT_IN_AGENTS = {
4
+ Jane: {
5
+ badge: "●● JANE ●●",
6
+ role: "Product Analyst / Team Lead",
7
+ description: "facilitates discussion, clarifies requirements, keeps the team focused, evaluates team performance at the end",
8
+ groundRules: "Jane resolves disagreements and keeps the discussion productive. She NEVER reads code, runs tools, or inspects files — that's the developer and auditor's job. She focuses on requirements, user impact, scope, and coordination.",
9
+ brainstorm: { tag: "SAY", focus: "facilitation, question, or summary" },
10
+ planning: "Requirements Summary (what we're building, acceptance criteria, scope boundaries)",
11
+ execution: {
12
+ step: "Jane wraps up",
13
+ tasks: [
14
+ "Review the PR description. Ensure it explains what changed and why.",
15
+ "Summarize the session.",
16
+ ],
17
+ order: 99, // last
18
+ },
19
+ },
20
+ Dennis: {
21
+ badge: "■■ DENNIS ■■",
22
+ role: "Senior Developer",
23
+ description: "assesses technical feasibility, proposes architecture, implements the solution",
24
+ groundRules: "Dennis must verify at least 1 assumption about the codebase before agreeing to any approach.",
25
+ codePrinciple: "Never write logic inline inside components or UI templates. Extract all conditionals, transformations, calculations, and API calls into dedicated functions, hooks, or services.",
26
+ brainstorm: { tag: "THINK", focus: "technical feasibility, existing patterns" },
27
+ planning: "Implementation Plan (files to modify, approach, complexity S/M/L)",
28
+ execution: {
29
+ step: "Dennis implements",
30
+ tasks: [
31
+ "Create a branch following project conventions.",
32
+ "Implement the changes according to the agreed plan.",
33
+ "Run linter and build to verify.",
34
+ "Commit the implementation.",
35
+ ],
36
+ order: 1,
37
+ },
38
+ },
39
+ Sam: {
40
+ badge: "◆◆ SAM ◆◆",
41
+ role: "Architecture Auditor",
42
+ description: "scans for separation-of-concerns violations, guards code architecture",
43
+ groundRules: "Sam must verify that the proposed approach does not introduce architecture violations. He always backs claims with a file reference or line number.",
44
+ codePrinciple: "Actively guards separation of concerns throughout the session. Always cites file and line number.",
45
+ brainstorm: { tag: "THINK", focus: "codebase patterns, architecture risks" },
46
+ planning: "Architecture Review (existing violations, whether approach is clean)",
47
+ execution: {
48
+ step: "Sam scans for violations",
49
+ tasks: [
50
+ "Read all files the developer changed.",
51
+ "Check for architecture violations.",
52
+ "If violations found, the developer fixes them before proceeding.",
53
+ ],
54
+ order: 2,
55
+ },
56
+ },
57
+ Bart: {
58
+ badge: "▲▲ BART ▲▲",
59
+ role: "QA Engineer",
60
+ description: "identifies edge cases, test plans, acceptance criteria, quality risks",
61
+ groundRules: "Bart must identify at least 2 risks or edge cases before agreeing to any plan.",
62
+ codePrinciple: "Flag any logic written directly inside a component or UI template.",
63
+ brainstorm: { tag: "SAY", focus: "risks, edge cases, \"what happens when...\"" },
64
+ planning: "Test Plan (acceptance criteria, key test cases, edge cases)",
65
+ execution: {
66
+ step: "Bart reviews",
67
+ tasks: [
68
+ "Read EVERY file the developer changed.",
69
+ "Check calculations, edge cases, error handling.",
70
+ "Run linter and build.",
71
+ "If ALL criteria pass, push and create PR: `gh pr create --title \"...\" --body \"...\"`",
72
+ "Approve the PR if clean.",
73
+ ],
74
+ order: 4,
75
+ },
76
+ },
77
+ Vera: {
78
+ badge: "◈◈ VERA ◈◈",
79
+ role: "Test Engineer",
80
+ description: "writes unit and regression tests for changed code, ensures test coverage",
81
+ groundRules: "Vera must identify which functions need unit test coverage before agreeing to any plan.",
82
+ codePrinciple: "Never mount or render UI to test a logic outcome. Test files must mirror the service/utility structure.",
83
+ brainstorm: { tag: "SAY", focus: "test coverage gaps, which functions need tests" },
84
+ planning: "Test Plan (which functions need tests, regression tests)",
85
+ execution: {
86
+ step: "Vera writes tests",
87
+ tasks: [
88
+ "Read every file the developer changed. Identify testable functions.",
89
+ "Write unit tests following existing test patterns.",
90
+ "Run tests to verify they pass.",
91
+ "Commit test files.",
92
+ ],
93
+ order: 3,
94
+ },
95
+ },
96
+ Luna: {
97
+ badge: "☾☾ LUNA ☾☾",
98
+ role: "UX/UI Designer",
99
+ description: "designs pixel-perfect interfaces, champions user experience, applies psychology of user behavior, ensures visual consistency, accessibility, and intuitive interaction patterns",
100
+ groundRules: "Luna must review any UI changes for visual consistency, spacing, color harmony, accessibility (contrast, focus states), and intuitive interaction flow. She references specific components, screenshots, or design patterns.",
101
+ codePrinciple: "Reviews all UI changes for visual hierarchy, whitespace balance, color consistency, typography, responsive behavior, and accessibility (WCAG). Pushes back on cluttered layouts, inconsistent spacing, poor contrast, or confusing interaction flows. Proposes specific CSS/styling improvements with exact values.",
102
+ brainstorm: { tag: "THINK", focus: "UX/UI impact, visual consistency, interaction patterns, accessibility" },
103
+ planning: "UX Review (visual impact, layout concerns, accessibility checklist, interaction improvements)",
104
+ execution: {
105
+ step: "Luna reviews UI changes (if applicable)",
106
+ tasks: [
107
+ "Read any changed component, page, or style files.",
108
+ "Check visual hierarchy, spacing consistency, color harmony, typography.",
109
+ "Verify accessibility: contrast ratios, focus states, keyboard navigation, screen reader labels.",
110
+ "Check responsive behavior and interaction flow.",
111
+ "If issues found, propose specific fixes (exact CSS values, spacing, colors). The developer implements them before proceeding.",
112
+ "Skip this step if the task has no UI impact.",
113
+ ],
114
+ order: 2.1,
115
+ },
116
+ },
117
+ Mark: {
118
+ badge: "✦✦ MARK ✦✦",
119
+ role: "Content Writer",
120
+ description: "crafts precise, engaging copy for UI text, error messages, tooltips, onboarding flows, and documentation. Simplifies technical language into friendly, clear wording. Ensures consistent tone and voice across the product",
121
+ groundRules: "Mark must review all user-facing text — labels, buttons, headings, error messages, tooltips, empty states, confirmation dialogs. He ensures the tone is friendly and consistent, wording is concise, and technical jargon is avoided unless the audience is technical.",
122
+ codePrinciple: "Reviews all user-facing strings in changed files. Rewrites vague, wordy, or technical copy into clear, concise, human-friendly language. Ensures consistent voice — no mixing formal and casual tone. Checks empty states, error messages, and confirmation dialogs for helpfulness.",
123
+ brainstorm: { tag: "THINK", focus: "copy clarity, tone, user-facing text quality" },
124
+ planning: "Content Review (user-facing text audit, tone, clarity, empty states, error messages)",
125
+ execution: {
126
+ step: "Mark reviews content (if applicable)",
127
+ tasks: [
128
+ "Read all changed files that contain user-facing text (components, templates, error handlers).",
129
+ "Check every label, button, heading, tooltip, error message, empty state, and confirmation dialog.",
130
+ "Rewrite anything vague, wordy, jargon-heavy, or inconsistent in tone.",
131
+ "Propose exact replacement strings. The developer implements them.",
132
+ "Skip this step if the task has no user-facing text changes.",
133
+ ],
134
+ order: 2.2,
135
+ },
136
+ },
137
+ };
138
+
139
+ /**
140
+ * Resolve the team from config.
141
+ * - If config.team is an array of names, use those built-in agents in that order.
142
+ * - If config.team contains objects, treat as custom agents.
143
+ * - Jane is always included (she's the lead).
144
+ * - Dennis is always included (someone has to implement).
145
+ */
146
+ export function resolveTeam(config) {
147
+ const teamConfig = config.team || null;
148
+
149
+ // Default: all 7 agents
150
+ if (!teamConfig) {
151
+ return Object.entries(BUILT_IN_AGENTS).map(([name, agent]) => ({ name, ...agent }));
152
+ }
153
+
154
+ const team = [];
155
+ for (const entry of teamConfig) {
156
+ if (typeof entry === "string") {
157
+ // Built-in agent by name
158
+ const agent = BUILT_IN_AGENTS[entry];
159
+ if (agent) {
160
+ team.push({ name: entry, ...agent });
161
+ } else {
162
+ console.warn(`Warning: Unknown agent "${entry}" — skipping`);
163
+ }
164
+ } else if (typeof entry === "object" && entry.name) {
165
+ // Custom agent
166
+ const builtin = BUILT_IN_AGENTS[entry.name];
167
+ if (builtin) {
168
+ // Override a built-in agent's role
169
+ team.push({ ...builtin, name: entry.name, ...entry, badge: builtin.badge });
170
+ } else {
171
+ // Fully custom agent
172
+ team.push({
173
+ name: entry.name,
174
+ badge: entry.badge || `** ${entry.name.toUpperCase()} **`,
175
+ role: entry.role || "Team Member",
176
+ description: entry.description || entry.role || "Custom team member",
177
+ groundRules: entry.groundRules || "",
178
+ brainstorm: entry.brainstorm || { tag: "SAY", focus: entry.role || "general input" },
179
+ planning: entry.planning || `${entry.role || entry.name} Review`,
180
+ execution: entry.execution || null,
181
+ });
182
+ }
183
+ }
184
+ }
185
+
186
+ // Ensure Jane and Dennis are always present
187
+ if (!team.find(a => a.name === "Jane")) {
188
+ team.unshift({ name: "Jane", ...BUILT_IN_AGENTS.Jane });
189
+ }
190
+ if (!team.find(a => a.name === "Dennis")) {
191
+ const jane = team.findIndex(a => a.name === "Jane");
192
+ team.splice(jane + 1, 0, { name: "Dennis", ...BUILT_IN_AGENTS.Dennis });
193
+ }
194
+
195
+ return team;
196
+ }
197
+
198
+ /**
199
+ * Generate the dynamic parts of the prompt from the team.
200
+ */
201
+ export function generateTeamPrompt(team) {
202
+ const count = team.length;
203
+ const agentWord = count === 1 ? "one AI agent" : `${count} AI agents`;
204
+
205
+ const sections = {};
206
+
207
+ // Agent list
208
+ sections.agentList = team.map(a =>
209
+ `- ${a.name} (${a.role}) — ${a.description}`
210
+ ).join("\n");
211
+
212
+ // Speaking order
213
+ sections.speakingOrder = team.map((a, i) =>
214
+ `${i + 1}. ${a.badge}`
215
+ ).join("\n");
216
+
217
+ // Ground rules
218
+ const rules = [];
219
+ rules.push(`1. Each agent speaks in turn, prefixed with their badge (e.g., "${team[0].badge} Starting.").`);
220
+ rules.push(`2. ALL text output MUST be prefixed with the acting agent's badge. Never output unprefixed text.`);
221
+ rules.push(`3. Agents should DISAGREE when they see problems — don't rubber-stamp each other.`);
222
+ let ruleNum = 4;
223
+ for (const a of team) {
224
+ if (a.groundRules) {
225
+ rules.push(`${ruleNum}. ${a.groundRules}`);
226
+ ruleNum++;
227
+ }
228
+ }
229
+ rules.push(`${ruleNum}. Every statement should add value — no filler, no repeating what someone else already said.`);
230
+ sections.groundRules = rules.join("\n");
231
+
232
+ // Code principles
233
+ const principles = team
234
+ .filter(a => a.codePrinciple)
235
+ .map(a => `- ${a.name}: ${a.codePrinciple}`);
236
+ sections.codePrinciples = principles.length > 0 ? principles.join("\n") : "";
237
+
238
+ // Brainstorm order
239
+ sections.brainstormOrder = team.map((a, i) =>
240
+ `${i + 1}. ${a.badge} [${a.brainstorm.tag}] ${a.brainstorm.focus}`
241
+ ).join("\n");
242
+
243
+ // Planning presentations
244
+ sections.planningOrder = team.map(a =>
245
+ `${a.badge} ${a.planning}`
246
+ ).join("\n");
247
+
248
+ // Execution steps
249
+ const execAgents = team
250
+ .filter(a => a.execution)
251
+ .sort((a, b) => a.execution.order - b.execution.order);
252
+ let stepNum = 1;
253
+ const execSteps = [];
254
+ for (const a of execAgents) {
255
+ const tasks = a.execution.tasks.map((t, i) => `${i + 1}. ${t}`).join("\n");
256
+ execSteps.push(`### Step ${stepNum} — ${a.name} ${a.execution.step.replace(/^[A-Za-z]+ /, "")}:\n${tasks}`);
257
+ stepNum++;
258
+ }
259
+ sections.executionSteps = execSteps.join("\n\n");
260
+
261
+ // Count and phrasing
262
+ sections.count = count;
263
+ sections.agentWord = agentWord;
264
+ sections.names = team.map(a => a.name);
265
+
266
+ return sections;
267
+ }
package/cli/config.mjs CHANGED
@@ -21,14 +21,12 @@ const DEFAULTS = {
21
21
  repo: null, // e.g., "owner/repo" — auto-detected from git if null
22
22
  },
23
23
 
24
- // Agent customization
25
- agents: {
26
- Jane: { role: "Product Analyst / Team Lead" },
27
- Dennis: { role: "Senior Developer" },
28
- Bart: { role: "QA Engineer" },
29
- Vera: { role: "Test Engineer" },
30
- Sam: { role: "Architecture Auditor" },
31
- },
24
+ // Team composition — array of agent names or custom agent objects
25
+ // Default: all 7 agents. To customize:
26
+ // "team": ["Jane", "Dennis", "Sam", "Bart"] — 4-agent team (no Luna, Mark, Vera)
27
+ // "team": ["Jane", "Dennis", "Sam", {"name": "Alex", "role": "DevOps Engineer", "description": "..."}]
28
+ // Jane and Dennis are always included even if omitted.
29
+ team: null,
32
30
 
33
31
  // Commands — auto-detected if null
34
32
  commands: {
package/cli/init.mjs CHANGED
@@ -1,7 +1,8 @@
1
- // `agentdesk init` — detect project and register with AgentDesk server
1
+ // `agentdesk init` — interactive project setup with tracker configuration
2
2
 
3
- import { existsSync, readFileSync } from "fs";
3
+ import { existsSync, readFileSync, writeFileSync } from "fs";
4
4
  import { join } from "path";
5
+ import { createInterface } from "readline";
5
6
  import { detectProject } from "./detect.mjs";
6
7
  import { loadConfig } from "./config.mjs";
7
8
  import { getStoredApiKey } from "./login.mjs";
@@ -15,11 +16,34 @@ function loadApiKey(dir) {
15
16
  return match?.[1]?.trim() || getStoredApiKey();
16
17
  }
17
18
 
19
+ function ask(rl, question) {
20
+ return new Promise(resolve => rl.question(question, resolve));
21
+ }
22
+
23
+ async function selectOption(rl, prompt, options) {
24
+ console.log(` ${prompt}`);
25
+ console.log("");
26
+ options.forEach((opt, i) => {
27
+ console.log(` ${i + 1}) ${opt.label}`);
28
+ });
29
+ console.log("");
30
+
31
+ while (true) {
32
+ const answer = await ask(rl, ` Choose (1-${options.length}): `);
33
+ const num = parseInt(answer.trim(), 10);
34
+ if (num >= 1 && num <= options.length) return options[num - 1];
35
+ console.log(` Please enter a number between 1 and ${options.length}`);
36
+ }
37
+ }
38
+
18
39
  export async function runInit(cwd) {
19
40
  const project = detectProject(cwd);
20
- const config = loadConfig(cwd);
21
- const tracker = config.tracker || (project.hasLinear ? "linear" : null);
41
+ const existingConfig = loadConfig(cwd);
22
42
  const projectId = project.name || cwd.split("/").pop();
43
+ const configPath = join(cwd, ".agentdesk.json");
44
+ const hasConfig = existsSync(configPath);
45
+
46
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
23
47
 
24
48
  console.log("");
25
49
  console.log(" AgentDesk — Project Setup");
@@ -28,9 +52,8 @@ export async function runInit(cwd) {
28
52
  console.log(` Project: ${project.name || "unknown"}`);
29
53
  console.log(` Type: ${project.label}`);
30
54
  console.log(` Directory: ${project.dir}`);
31
- console.log(` Git: ${project.hasGit ? "" : ""}`);
32
- console.log(` CLAUDE.md: ${project.hasClaudeMd ? "" : " (recommended — run 'claude' to generate one)"}`);
33
- console.log(` Tracker: ${tracker || "— (none)"}`);
55
+ console.log(` Git: ${project.hasGit ? "yes" : "no"}`);
56
+ console.log(` CLAUDE.md: ${project.hasClaudeMd ? "yes" : "no (recommended)"}`);
34
57
  console.log("");
35
58
 
36
59
  if (project.testCommand) console.log(` Test: ${project.testCommand}`);
@@ -38,7 +61,68 @@ export async function runInit(cwd) {
38
61
  if (project.lintCommand) console.log(` Lint: ${project.lintCommand}`);
39
62
  if (project.testCommand || project.buildCommand || project.lintCommand) console.log("");
40
63
 
41
- // Register with AgentDesk server
64
+ // --- Tracker selection ---
65
+ const trackerOptions = [
66
+ { label: "Linear", value: "linear" },
67
+ { label: "Jira", value: "jira" },
68
+ { label: "GitHub Issues", value: "github" },
69
+ { label: "None (use descriptions only)", value: null },
70
+ ];
71
+
72
+ const selected = await selectOption(rl, "Task tracker:", trackerOptions);
73
+ const tracker = selected.value;
74
+ console.log("");
75
+
76
+ // Build config
77
+ const config = {};
78
+ if (tracker) config.tracker = tracker;
79
+
80
+ if (tracker === "linear") {
81
+ const current = existingConfig.linear?.workspace || "";
82
+ const answer = await ask(rl, ` Linear workspace slug${current ? ` (${current})` : ""}: `);
83
+ const ws = answer.trim() || current;
84
+ if (ws) config.linear = { workspace: ws };
85
+ console.log("");
86
+ }
87
+
88
+ if (tracker === "jira") {
89
+ const current = existingConfig.jira?.baseUrl || "";
90
+ const answer = await ask(rl, ` Jira base URL${current ? ` (${current})` : ""}: `);
91
+ const url = answer.trim() || current;
92
+ if (url) config.jira = { baseUrl: url };
93
+ console.log("");
94
+ }
95
+
96
+ if (tracker === "github") {
97
+ const current = existingConfig.github?.repo || "";
98
+ const answer = await ask(rl, ` GitHub repo${current ? ` (${current})` : ""} (owner/repo): `);
99
+ const r = answer.trim() || current;
100
+ if (r) config.github = { repo: r };
101
+ console.log("");
102
+ }
103
+
104
+ // --- Save .agentdesk.json ---
105
+ let merged = {};
106
+ if (hasConfig) {
107
+ try { merged = JSON.parse(readFileSync(configPath, "utf-8")); } catch {}
108
+ }
109
+
110
+ if (tracker) {
111
+ merged.tracker = tracker;
112
+ if (config.linear) merged.linear = config.linear;
113
+ if (config.jira) merged.jira = config.jira;
114
+ if (config.github) merged.github = config.github;
115
+ } else {
116
+ delete merged.tracker;
117
+ delete merged.linear;
118
+ delete merged.jira;
119
+ delete merged.github;
120
+ }
121
+
122
+ writeFileSync(configPath, JSON.stringify(merged, null, 2) + "\n");
123
+ console.log(` Saved .agentdesk.json`);
124
+
125
+ // --- Register with server ---
42
126
  try {
43
127
  const res = await fetch(`${SERVER}/api/projects`, {
44
128
  method: "POST",
@@ -55,24 +139,27 @@ export async function runInit(cwd) {
55
139
  }),
56
140
  });
57
141
  if (res.ok) {
58
- console.log(" Registered with AgentDesk server");
59
- } else {
60
- console.log(" ⚠ AgentDesk server not available — project will register on first session");
142
+ console.log(" Registered with agentdesk.live");
61
143
  }
62
144
  } catch {
63
- console.log(" ⚠ AgentDesk server not running — start it with: agentdesk server");
145
+ // Server not available
64
146
  }
65
147
 
66
148
  console.log("");
67
- console.log(" Ready. Run a team session with:");
149
+ console.log(" Ready! Run a team session:");
68
150
  console.log("");
69
- console.log(` agentdesk team TASK-123`);
70
- console.log(` agentdesk team TASK-123 --description "Fix the login bug"`);
151
+ if (tracker) {
152
+ console.log(` agentdesk team TASK-123`);
153
+ console.log(` agentdesk team TASK-123 -d "Optional extra context"`);
154
+ } else {
155
+ console.log(` agentdesk team my-feature -d "Add dark mode support"`);
156
+ }
71
157
  console.log("");
72
158
 
73
159
  if (!project.hasClaudeMd) {
74
- console.log(" Tip: Create a CLAUDE.md in your project root to help the agents");
75
- console.log(" understand your codebase conventions, architecture, and commands.");
160
+ console.log(" Tip: Create a CLAUDE.md to help the agents understand your codebase.");
76
161
  console.log("");
77
162
  }
163
+
164
+ rl.close();
78
165
  }
package/cli/team.mjs CHANGED
@@ -10,6 +10,7 @@ import WebSocket from "ws";
10
10
  import { detectProject, generateContext } from "./detect.mjs";
11
11
  import { loadConfig } from "./config.mjs";
12
12
  import { getStoredApiKey } from "./login.mjs";
13
+ import { resolveTeam, generateTeamPrompt } from "./agents.mjs";
13
14
 
14
15
  function loadDotEnv(dir) {
15
16
  const envPath = join(dir, ".env");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kendoo.agentdesk/agentdesk",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "AI team orchestrator for Claude Code — run collaborative agent sessions from your terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -24,25 +24,22 @@
24
24
  "test": "node --test tests/server.test.mjs"
25
25
  },
26
26
  "dependencies": {
27
+ "bcryptjs": "^3.0.3",
28
+ "express": "^5.1.0",
29
+ "jsonwebtoken": "^9.0.3",
30
+ "sql.js": "^1.14.1",
27
31
  "ws": "^8.18.0"
28
32
  },
29
33
  "devDependencies": {
30
- "@logto/react": "^4.0.13",
31
34
  "@vitejs/plugin-react": "^4.5.2",
32
35
  "autoprefixer": "^10.4.21",
33
- "bcryptjs": "^3.0.3",
34
36
  "concurrently": "^9.2.0",
35
- "express": "^5.1.0",
36
- "jose": "^6.2.2",
37
- "jsonwebtoken": "^9.0.3",
38
37
  "lucide-react": "^0.577.0",
39
38
  "postcss": "^8.5.4",
40
39
  "react": "^19.1.0",
41
40
  "react-dom": "^19.1.0",
42
- "sql.js": "^1.14.1",
43
41
  "tailwindcss": "^3.4.17",
44
- "vite": "^6.3.5",
45
- "ws": "^8.18.0"
42
+ "vite": "^6.3.5"
46
43
  },
47
44
  "keywords": [
48
45
  "ai",