@kendoo.agentdesk/agentdesk 0.24.0 → 0.25.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.
Files changed (2) hide show
  1. package/cli/daemon.mjs +36 -0
  2. package/package.json +1 -1
package/cli/daemon.mjs CHANGED
@@ -318,6 +318,27 @@ export async function runDaemon() {
318
318
  }
319
319
  }
320
320
 
321
+ // AD-34 confirmation helper. Prints session details and asks y/N at the local
322
+ // terminal. Returns true if the user accepts. If stdin isn't a TTY (running
323
+ // headless / no terminal), refuse — the safer default. Set
324
+ // AGENTDESK_DAEMON_AUTO_ACCEPT=1 to skip this prompt for trusted automation.
325
+ async function confirmIncomingSession({ project, taskId, prompt }) {
326
+ if (!process.stdin.isTTY) {
327
+ console.log(" Refusing server-pushed session: no terminal to confirm at. Set AGENTDESK_DAEMON_AUTO_ACCEPT=1 to allow.");
328
+ return false;
329
+ }
330
+ const promptPreview = String(prompt || "(no prompt)").trim().slice(0, 240).replace(/\s+/g, " ");
331
+ console.log("");
332
+ console.log(` Incoming session for project: ${project.name}`);
333
+ if (taskId) console.log(` Task: ${taskId}`);
334
+ console.log(` Prompt: ${promptPreview}${String(prompt || "").length > 240 ? "..." : ""}`);
335
+ console.log("");
336
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
337
+ const answer = await new Promise(resolve => rl.question(" Approve this session? [y/N] ", resolve));
338
+ rl.close();
339
+ return /^y(es)?$/i.test(String(answer).trim());
340
+ }
341
+
321
342
  // 4. Session handling
322
343
 
323
344
  async function handleStartSession({ sessionId, projectId, taskId: remoteTaskId, prompt, phased, screenshots: screenshotsOverride }) {
@@ -329,6 +350,21 @@ export async function runDaemon() {
329
350
  return;
330
351
  }
331
352
 
353
+ // AD-34: server-pushed sessions get a human confirmation prompt at the
354
+ // local terminal before any code runs. If an attacker steals the user's
355
+ // api_key, they can POST to /api/daemon/sessions, but cannot push a
356
+ // command through to the victim machine without someone at the keyboard
357
+ // saying yes. Opt out via AGENTDESK_DAEMON_AUTO_ACCEPT=1 for trusted
358
+ // automation environments.
359
+ if (process.env.AGENTDESK_DAEMON_AUTO_ACCEPT !== "1") {
360
+ const accepted = await confirmIncomingSession({ project, taskId: remoteTaskId, prompt });
361
+ if (!accepted) {
362
+ console.log(` ${yellow}Rejected by user:${reset} ${dim}${sessionId}${reset}`);
363
+ send({ type: "daemon:error", sessionId, error: "Session declined by daemon owner" });
364
+ return;
365
+ }
366
+ }
367
+
332
368
  // Enforce max 1 concurrent session — set flag BEFORE any async work to prevent race
333
369
  if (activeSession) {
334
370
  console.log(` ${red}Rejected:${reset} session already running ${dim}(${activeSession.sessionId})${reset}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kendoo.agentdesk/agentdesk",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "description": "AI team orchestrator for Claude Code — run collaborative agent sessions from your terminal",
5
5
  "type": "module",
6
6
  "bin": {