@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.
- package/cli/daemon.mjs +36 -0
- 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}`);
|