@kendoo.agentdesk/agentdesk 0.19.3 → 0.19.5

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/CHANGELOG.md CHANGED
@@ -13,6 +13,16 @@ Internal refactors, infrastructure changes, and architectural notes are not list
13
13
  ### Added
14
14
  - `[UI]` Private-session sharing flow. When someone visits a session URL they don't own, they now see a friendly "Shh… this one's private" page with a one-click "Request access" button instead of a blank error. The session owner sees pending requests in a new header inbox and can grant viewer access for just that session or the whole project. Viewer-granted sessions show up in the teammate's sidebar tagged as a viewer.
15
15
 
16
+ ## [0.19.5] — 2026-04-19
17
+
18
+ ### Changed
19
+ - `[CLI]` `agentdesk bootstrap` now works even when the cloned repo has no committed `.agentdesk.json`. If the project config file is absent, bootstrap fetches the user's project list from the server, tries to auto-match by the git remote (`origin`), and falls back to a numbered picker of the account's projects. Once picked, a minimal `.agentdesk.json` is written locally (prompting the user to commit it so future clones skip the picker) and the rest of the gap-scan continues unchanged. Previous behavior required the file to already be present.
20
+
21
+ ## [0.19.4] — 2026-04-19
22
+
23
+ ### Added
24
+ - `[CLI]` `agentdesk bootstrap` — fresh-machine setup for repos already configured on another machine. Reads the committed `.agentdesk.json` for project identity, tracker type, team/project key, and GitHub repo, then only prompts for the per-machine secrets (Linear API key, Jira email + token, GitHub token) that belong in the local `.env`. Previously the only post-clone path was `agentdesk init`, which walked the full wizard and risked overwriting project-wide settings when the user just wanted to paste in their own tokens. Bootstrap never writes `.agentdesk.json` and never pushes to the server, so the first machine's setup stays untouched. `agentdesk login` now points at both `init` (new project) and `bootstrap` (cloned repo) as next steps.
25
+
16
26
  ## [0.19.3] — 2026-04-19
17
27
 
18
28
  ### Fixed
package/README.md CHANGED
@@ -47,6 +47,8 @@ A guided wizard walks you through it: picks up your project type, asks which tas
47
47
 
48
48
  Re-running `agentdesk init` in a project that already has config offers a "tracker only" shortcut. Use `agentdesk init --quick` to skip the narrative copy for scripted setups.
49
49
 
50
+ **On a second machine** (repo cloned from a teammate's setup): run `agentdesk bootstrap` instead of `init`. It reads the committed `.agentdesk.json` for the project-wide settings (tracker type, team/project key, repo) and only prompts for per-machine secrets (Linear API key, Jira email + token, GitHub token) that end up in `.env`. The other machine's `.env` and the server config are left untouched.
51
+
50
52
  `.agentdesk.json` is kept in sync with the server: every CLI run fetches the authoritative config and rewrites the local file as a credential-free snapshot. Credentials live only on the server, encrypted. If a local edit disagreed with the server's value, a one-line warning lists the overridden fields.
51
53
 
52
54
  ### 4. Run a team session
@@ -72,6 +74,7 @@ Watch the session live at [agentdesk.live](https://agentdesk.live). Each session
72
74
  agentdesk login Sign in to AgentDesk
73
75
  agentdesk logout Sign out and remove credentials
74
76
  agentdesk init Set up project and configure tracker
77
+ agentdesk bootstrap Fill in per-machine tokens on a cloned repo
75
78
  agentdesk team <TASK-ID> Run a team session on an existing task
76
79
  agentdesk team -d "..." Describe what you want — task created automatically
77
80
  agentdesk <agent> -d "..." Run a single agent (jane, dennis, sam, bart, vera, luna, mark, nora)
package/bin/agentdesk.mjs CHANGED
@@ -58,10 +58,16 @@ if (!command || command === "help" || command === "--help") {
58
58
  2. agentdesk init Set up your project (choose tracker, save config)
59
59
  3. agentdesk team TASK-123 Run a team session
60
60
 
61
+ On a freshly cloned repo (already set up on another machine):
62
+ 1. agentdesk login Sign in
63
+ 2. agentdesk bootstrap Fill in per-machine secrets (tokens)
64
+ 3. agentdesk team TASK-123 Run a team session
65
+
61
66
  Commands:
62
67
  agentdesk login Sign in to AgentDesk
63
68
  agentdesk logout Sign out and remove credentials
64
69
  agentdesk init [--quick] Set up project and configure tracker
70
+ agentdesk bootstrap Fill in per-machine tokens on a cloned repo
65
71
  agentdesk team <TASK-ID> Run a team session on an existing task
66
72
  agentdesk team -d "..." Create a task and run a session
67
73
  agentdesk <agent> -d "..." Run a single agent (jane, dennis, sam, bart, vera, luna, mark, nora)
@@ -146,6 +152,11 @@ else if (command === "init") {
146
152
  await runInit(process.cwd(), { quick });
147
153
  }
148
154
 
155
+ else if (command === "bootstrap") {
156
+ const { runBootstrap } = await import("../cli/bootstrap.mjs");
157
+ await runBootstrap(process.cwd());
158
+ }
159
+
149
160
  else if (command === "team") {
150
161
  // Parse options first to find -d, --cwd, --child-strategy
151
162
  let description = "";
@@ -0,0 +1,399 @@
1
+ // `agentdesk bootstrap` — fill in per-machine secrets after cloning a repo
2
+ // that's already been set up on a different machine.
3
+ //
4
+ // Intent: on a fresh clone, `.agentdesk.json` carries the project identity,
5
+ // tracker binding, and GitHub repo — everything that's project-wide. What's
6
+ // missing are the per-machine secrets that live in `.env` (LINEAR_API_KEY,
7
+ // JIRA_EMAIL/JIRA_API_TOKEN, GITHUB_TOKEN). Bootstrap detects which are
8
+ // missing or invalid and prompts only for those.
9
+ //
10
+ // Hard constraints:
11
+ // - Never write `.agentdesk.json` (besides the cached-server-state rewrite
12
+ // that loadConfig already does on every CLI run — we don't add new ones).
13
+ // - Never push to the server. Project-wide config on machine 1 is untouched.
14
+ // - Only writes to `.env`.
15
+ // - Idempotent. Running on a fully-configured machine prints "all set" and
16
+ // exits 0.
17
+
18
+ import { existsSync, readFileSync, writeFileSync } from "fs";
19
+ import { join } from "path";
20
+ import { createInterface } from "readline";
21
+ import { execSync } from "child_process";
22
+ import { loadConfig } from "./config.mjs";
23
+ import { getStoredApiKey } from "./login.mjs";
24
+ import { checkTrackerPermissions, resolveCredentialsFromEnv } from "./tracker-check.mjs";
25
+ import { assertPushable, PreflightError } from "./session-preflight.mjs";
26
+
27
+ const SERVER = process.env.AGENTDESK_SERVER || "https://agentdesk.live";
28
+
29
+ function detectGitRemote(dir) {
30
+ try {
31
+ const url = execSync("git remote get-url origin", { cwd: dir, stdio: ["ignore", "pipe", "ignore"], encoding: "utf-8" }).trim();
32
+ const m = url.match(/github\.com[:/]([^/]+)\/([^/.]+?)(?:\.git)?$/);
33
+ if (m) return `${m[1]}/${m[2]}`;
34
+ } catch {}
35
+ return null;
36
+ }
37
+
38
+ async function fetchProjects(apiKey) {
39
+ try {
40
+ const res = await fetch(`${SERVER}/api/projects`, {
41
+ headers: { "x-api-key": apiKey },
42
+ signal: AbortSignal.timeout(8000),
43
+ });
44
+ if (!res.ok) return null;
45
+ return await res.json();
46
+ } catch { return null; }
47
+ }
48
+
49
+ async function fetchProjectSettings(apiKey, projectId) {
50
+ try {
51
+ const res = await fetch(`${SERVER}/api/projects/${projectId}/settings`, {
52
+ headers: { "x-api-key": apiKey },
53
+ signal: AbortSignal.timeout(5000),
54
+ });
55
+ if (!res.ok) return {};
56
+ return await res.json();
57
+ } catch { return {}; }
58
+ }
59
+
60
+ // Discover the server-side project for this clone when .agentdesk.json is
61
+ // absent. Strategy:
62
+ // 1. Fetch the user's projects list.
63
+ // 2. For each, fetch settings so we can see github.repo.
64
+ // 3. If we can match the local git remote to exactly one project's repo,
65
+ // auto-select (confirmation prompt).
66
+ // 4. Otherwise show a numbered picker of all the user's projects.
67
+ // 5. Write a minimal `.agentdesk.json` locally so loadConfig takes over
68
+ // from here.
69
+ // Returns the chosen projectKey, or null if the user aborts.
70
+ async function discoverProject(rl, cwd, apiKey) {
71
+ const remote = detectGitRemote(cwd);
72
+ if (remote) console.log(` Detected git remote: ${remote}`);
73
+ console.log(" Fetching your projects from the server...");
74
+
75
+ const projects = await fetchProjects(apiKey);
76
+ if (!projects || projects.length === 0) {
77
+ console.log("");
78
+ console.log(" No projects found on your account.");
79
+ console.log(" Run `agentdesk init` on the primary machine first, then retry here.");
80
+ console.log("");
81
+ return null;
82
+ }
83
+
84
+ // Fetch settings in parallel so we can display/match the configured repo.
85
+ const settings = await Promise.all(projects.map(p => fetchProjectSettings(apiKey, p.id)));
86
+ const rows = projects.map((p, i) => {
87
+ const repo = settings[i]?.github?.repo || null;
88
+ const matches = remote && repo && repo.toLowerCase() === remote.toLowerCase();
89
+ return { project: p, settings: settings[i] || {}, repo, matches };
90
+ });
91
+
92
+ const exactMatches = rows.filter(r => r.matches);
93
+ let chosen = null;
94
+
95
+ if (exactMatches.length === 1) {
96
+ const r = exactMatches[0];
97
+ console.log(` ✓ Match: ${r.project.name} (${r.project.id}) — repo ${r.repo}`);
98
+ console.log("");
99
+ const ans = (await askInline(rl, ` Use this project? [Y/n]: `)).trim().toLowerCase();
100
+ if (ans === "" || ans === "y" || ans === "yes") chosen = r;
101
+ }
102
+
103
+ if (!chosen) {
104
+ console.log("");
105
+ console.log(" Pick the project this repo maps to:");
106
+ console.log("");
107
+ rows.forEach((r, i) => {
108
+ const tag = r.matches ? " ← matches git remote" : "";
109
+ const repoStr = r.repo ? ` [${r.repo}]` : "";
110
+ console.log(` ${i + 1}) ${r.project.name} (${r.project.id})${repoStr}${tag}`);
111
+ });
112
+ console.log("");
113
+ while (true) {
114
+ const answer = await askInline(rl, ` Choose (1-${rows.length}, or 'c' to cancel): `);
115
+ const trimmed = answer.trim().toLowerCase();
116
+ if (trimmed === "c" || trimmed === "cancel") return null;
117
+ const num = parseInt(trimmed, 10);
118
+ if (num >= 1 && num <= rows.length) { chosen = rows[num - 1]; break; }
119
+ console.log(` Please enter a number between 1 and ${rows.length}`);
120
+ }
121
+ }
122
+
123
+ // Write a minimal .agentdesk.json — loadConfig will merge server state
124
+ // into it on the next call, producing the full cached view.
125
+ const minimal = { projectKey: chosen.project.id };
126
+ writeFileSync(join(cwd, ".agentdesk.json"), JSON.stringify(minimal, null, 2) + "\n");
127
+ console.log("");
128
+ console.log(` ✓ Wrote .agentdesk.json (projectKey: ${chosen.project.id})`);
129
+ console.log(" (commit this file so future clones skip the picker)");
130
+ return chosen.project.id;
131
+ }
132
+
133
+ function askInline(rl, question) {
134
+ return new Promise(resolve => rl.question(question, resolve));
135
+ }
136
+
137
+ function ask(rl, question) {
138
+ return new Promise(resolve => rl.question(question, resolve));
139
+ }
140
+
141
+ async function promptRequired(rl, label) {
142
+ while (true) {
143
+ const v = (await ask(rl, ` ${label}: `)).trim();
144
+ if (v) return v;
145
+ console.log(` ${label} is required. Ctrl+C to abort.`);
146
+ }
147
+ }
148
+
149
+ function saveEnvVar(dir, key, value) {
150
+ const envPath = join(dir, ".env");
151
+ let content = existsSync(envPath) ? readFileSync(envPath, "utf-8") : "";
152
+ const re = new RegExp(`^${key}=.*$`, "m");
153
+ if (re.test(content)) {
154
+ content = content.replace(re, `${key}=${value}`);
155
+ } else {
156
+ content += `${content && !content.endsWith("\n") ? "\n" : ""}${key}=${value}\n`;
157
+ }
158
+ writeFileSync(envPath, content);
159
+ }
160
+
161
+ function loadDotEnvLocal(dir) {
162
+ const envPath = join(dir, ".env");
163
+ const out = {};
164
+ if (!existsSync(envPath)) return out;
165
+ for (const line of readFileSync(envPath, "utf-8").split("\n")) {
166
+ const trimmed = line.trim();
167
+ if (!trimmed || trimmed.startsWith("#")) continue;
168
+ const eq = trimmed.indexOf("=");
169
+ if (eq !== -1) out[trimmed.slice(0, eq)] = trimmed.slice(eq + 1);
170
+ }
171
+ return out;
172
+ }
173
+
174
+ function readLocalConfig(cwd) {
175
+ const path = join(cwd, ".agentdesk.json");
176
+ if (!existsSync(path)) return null;
177
+ try { return JSON.parse(readFileSync(path, "utf-8")); } catch { return null; }
178
+ }
179
+
180
+ // Compact step list — the init wizard carries the full narrative; bootstrap
181
+ // assumes the user has already seen it on their first machine.
182
+ function printTrackerHint(tracker) {
183
+ if (tracker === "linear") {
184
+ console.log(" (Get a Linear API key at https://linear.app/settings/api)");
185
+ } else if (tracker === "jira") {
186
+ console.log(" (Create a Jira API token at https://id.atlassian.com/manage-profile/security/api-tokens)");
187
+ } else if (tracker === "github") {
188
+ console.log(" (Create a GitHub token at https://github.com/settings/tokens — scope: repo)");
189
+ }
190
+ }
191
+
192
+ // Walk missing tracker credentials and prompt for each. Writes to .env.
193
+ // Returns the merged credentials map so the caller can verify.
194
+ async function promptTrackerCreds(rl, cwd, tracker, existing) {
195
+ const creds = { ...existing };
196
+ if (tracker === "linear") {
197
+ if (!creds.LINEAR_API_KEY) {
198
+ console.log("");
199
+ printTrackerHint("linear");
200
+ const v = await promptRequired(rl, "Linear API key");
201
+ saveEnvVar(cwd, "LINEAR_API_KEY", v);
202
+ creds.LINEAR_API_KEY = v;
203
+ console.log(" ✓ Saved LINEAR_API_KEY to .env");
204
+ }
205
+ } else if (tracker === "jira") {
206
+ if (!creds.JIRA_EMAIL) {
207
+ console.log("");
208
+ printTrackerHint("jira");
209
+ const v = await promptRequired(rl, "Your Atlassian login email");
210
+ saveEnvVar(cwd, "JIRA_EMAIL", v);
211
+ creds.JIRA_EMAIL = v;
212
+ console.log(" ✓ Saved JIRA_EMAIL to .env");
213
+ }
214
+ if (!creds.JIRA_API_TOKEN) {
215
+ if (creds.JIRA_EMAIL) console.log("");
216
+ const v = await promptRequired(rl, "Jira API token");
217
+ saveEnvVar(cwd, "JIRA_API_TOKEN", v);
218
+ creds.JIRA_API_TOKEN = v;
219
+ console.log(" ✓ Saved JIRA_API_TOKEN to .env");
220
+ }
221
+ }
222
+ return creds;
223
+ }
224
+
225
+ async function promptGitHubToken(rl, cwd) {
226
+ console.log("");
227
+ printTrackerHint("github");
228
+ const v = await promptRequired(rl, "GitHub token");
229
+ saveEnvVar(cwd, "GITHUB_TOKEN", v);
230
+ console.log(" ✓ Saved GITHUB_TOKEN to .env");
231
+ return v;
232
+ }
233
+
234
+ async function selectOption(rl, prompt, options) {
235
+ console.log(` ${prompt}`);
236
+ console.log("");
237
+ options.forEach((opt, i) => console.log(` ${i + 1}) ${opt.label}`));
238
+ console.log("");
239
+ while (true) {
240
+ const answer = await ask(rl, ` Choose (1-${options.length}): `);
241
+ const num = parseInt(answer.trim(), 10);
242
+ if (num >= 1 && num <= options.length) return options[num - 1];
243
+ console.log(` Please enter a number between 1 and ${options.length}`);
244
+ }
245
+ }
246
+
247
+ export async function runBootstrap(cwd = process.cwd()) {
248
+ console.log("");
249
+ console.log(" AgentDesk — Bootstrap this machine");
250
+ console.log(" ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
251
+ console.log("");
252
+
253
+ // 1. Must be logged in.
254
+ const apiKey = getStoredApiKey();
255
+ if (!apiKey) {
256
+ console.log(" Not logged in. Run `agentdesk login` first.");
257
+ console.log("");
258
+ process.exit(1);
259
+ }
260
+
261
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
262
+
263
+ // 2. Find the server-side project for this clone. Prefer a committed
264
+ // .agentdesk.json (clean path); fall back to discovering from the
265
+ // user's server-side project list when the file is missing.
266
+ let localConfig = readLocalConfig(cwd);
267
+ let projectKey = localConfig?.projectKey || null;
268
+
269
+ if (!projectKey) {
270
+ if (localConfig) {
271
+ console.log(" .agentdesk.json has no projectKey — discovering project from server.");
272
+ } else {
273
+ console.log(" No .agentdesk.json in this directory — discovering project from server.");
274
+ }
275
+ console.log("");
276
+ projectKey = await discoverProject(rl, cwd, apiKey);
277
+ if (!projectKey) { rl.close(); process.exit(1); }
278
+ localConfig = readLocalConfig(cwd);
279
+ console.log("");
280
+ }
281
+
282
+ // 3. Load merged config (server-authoritative when reachable). This is the
283
+ // same call `agentdesk team` makes, so we see the same view.
284
+ const config = await loadConfig(cwd, { apiKey, serverUrl: SERVER, projectName: projectKey, silent: true });
285
+
286
+ const tracker = config.tracker || null;
287
+ const repo = config.github?.repo || null;
288
+ const login = config.github?.login || null;
289
+
290
+ console.log(` Project: ${projectKey}`);
291
+ console.log(` Tracker: ${tracker || "none"}`);
292
+ if (tracker === "linear" && config.linear?.teamKey) console.log(` Team: ${config.linear.teamKey}`);
293
+ if (tracker === "jira" && config.jira?.project) console.log(` Project: ${config.jira.project}`);
294
+ if (repo) console.log(` Repo: ${repo}${login ? ` (@${login})` : ""}`);
295
+ console.log("");
296
+
297
+ // 4. Gap scan + prompt loop. We retry tracker + github verification up to
298
+ // three times, matching init's retry/skip/cancel UX.
299
+ let creds = resolveCredentialsFromEnv(loadDotEnvLocal(cwd));
300
+ let trackerOk = !tracker; // no tracker → nothing to verify
301
+ let githubOk = false;
302
+ let attempts = 0;
303
+
304
+ while (attempts < 5) {
305
+ attempts += 1;
306
+
307
+ // Tracker
308
+ if (tracker && !trackerOk) {
309
+ const missing =
310
+ (tracker === "linear" && !creds.LINEAR_API_KEY) ||
311
+ (tracker === "jira" && (!creds.JIRA_EMAIL || !creds.JIRA_API_TOKEN));
312
+ if (missing) {
313
+ creds = await promptTrackerCreds(rl, cwd, tracker, creds);
314
+ }
315
+ process.stdout.write(" Verifying tracker access... ");
316
+ const check = await checkTrackerPermissions({ tracker, config, credentials: creds });
317
+ if (check.ok) {
318
+ console.log("✓");
319
+ if (check.identity?.name || check.identity?.email) {
320
+ const label = check.identity.name || check.identity.login || check.identity.email;
321
+ console.log(` ✓ Posting as: ${label}`);
322
+ }
323
+ trackerOk = true;
324
+ } else {
325
+ console.log("failed");
326
+ for (const e of check.errors || []) console.log(` • ${e}`);
327
+ console.log("");
328
+ const next = await selectOption(rl, "What now?", [
329
+ { label: "Re-enter credentials", value: "retry" },
330
+ { label: "Skip tracker (fix later in .env)", value: "skip" },
331
+ { label: "Cancel", value: "cancel" },
332
+ ]);
333
+ console.log("");
334
+ if (next.value === "cancel") { rl.close(); process.exit(1); }
335
+ if (next.value === "skip") { trackerOk = true; break; }
336
+ // retry: clear the tracker-specific creds so the next loop re-prompts
337
+ if (tracker === "linear") delete creds.LINEAR_API_KEY;
338
+ if (tracker === "jira") { delete creds.JIRA_EMAIL; delete creds.JIRA_API_TOKEN; }
339
+ continue;
340
+ }
341
+ }
342
+
343
+ // GitHub — always required (agents push code regardless of tracker)
344
+ if (!githubOk) {
345
+ if (!creds.GITHUB_TOKEN) {
346
+ creds.GITHUB_TOKEN = await promptGitHubToken(rl, cwd);
347
+ }
348
+ try {
349
+ assertPushable({ cwd, creds: { GITHUB_TOKEN: creds.GITHUB_TOKEN }, projectName: projectKey });
350
+ // Best-effort gh API check to confirm the token is valid and matches
351
+ // the configured login. Mirrors init.mjs:495-506.
352
+ try {
353
+ const { execSync } = await import("child_process");
354
+ const env = { ...process.env, GH_TOKEN: creds.GITHUB_TOKEN };
355
+ const who = execSync("gh api user --jq .login", { env, stdio: ["ignore", "pipe", "ignore"], encoding: "utf-8" }).trim();
356
+ if (who && login && who.toLowerCase() !== login.toLowerCase()) {
357
+ console.log(` ⚠ GitHub token authenticates as @${who}, not @${login} (from .agentdesk.json). Agents will post as @${who}.`);
358
+ } else if (who) {
359
+ console.log(` ✓ GitHub verified as @${who}`);
360
+ }
361
+ } catch {
362
+ console.log(" ✓ GITHUB_TOKEN present (couldn't verify via gh — install gh CLI for identity check)");
363
+ }
364
+ githubOk = true;
365
+ } catch (err) {
366
+ if (err instanceof PreflightError) {
367
+ console.log(` ✗ ${err.message}`);
368
+ console.log("");
369
+ const next = await selectOption(rl, "What now?", [
370
+ { label: "Re-enter GITHUB_TOKEN", value: "retry" },
371
+ { label: "Skip (sessions will fail until fixed)", value: "skip" },
372
+ { label: "Cancel", value: "cancel" },
373
+ ]);
374
+ console.log("");
375
+ if (next.value === "cancel") { rl.close(); process.exit(1); }
376
+ if (next.value === "skip") { githubOk = true; break; }
377
+ delete creds.GITHUB_TOKEN;
378
+ continue;
379
+ }
380
+ throw err;
381
+ }
382
+ }
383
+
384
+ if (trackerOk && githubOk) break;
385
+ }
386
+
387
+ rl.close();
388
+
389
+ console.log("");
390
+ if (trackerOk && githubOk) {
391
+ console.log(" Ready. Try:");
392
+ const prefix = config.linear?.teamKey || config.jira?.project || projectKey.toUpperCase();
393
+ console.log(` agentdesk team ${prefix}-123`);
394
+ console.log("");
395
+ } else {
396
+ console.log(" Bootstrap finished with missing pieces — edit .env directly or re-run.");
397
+ console.log("");
398
+ }
399
+ }
package/cli/login.mjs CHANGED
@@ -114,7 +114,8 @@ export async function runLogin() {
114
114
  console.log(` API key saved to ~/.agentdesk/credentials.json`);
115
115
  console.log("");
116
116
  console.log(" Next steps:");
117
- console.log(" agentdesk init");
117
+ console.log(" agentdesk init (new project on this machine)");
118
+ console.log(" agentdesk bootstrap (repo cloned from another machine)");
118
119
  console.log(" agentdesk team TASK-123");
119
120
  console.log("");
120
121
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kendoo.agentdesk/agentdesk",
3
- "version": "0.19.3",
3
+ "version": "0.19.5",
4
4
  "description": "AI team orchestrator for Claude Code — run collaborative agent sessions from your terminal",
5
5
  "type": "module",
6
6
  "bin": {