Skip to content

guardedCommands: emit an event before ctx.ui.confirm so notification extensions can react #394

Description

@martinmadisor-cyber

Problem

extensions/gentle-ai.ts blocks the agent on ctx.ui.confirm("Allow guarded command?", preview) (currently around line 1109, inside
confirmCommand) without emitting any event on the extension bus.

As a result, notification extensions like pi-smart-voice-notify (which listens on the pi-permission-system:permission-request channel)
never learn that the user is being blocked on a decision, and no sound / desktop notification / TTS fires.

In practice: if I Alt+Tab away from the terminal while the agent runs, and it hits a guarded git push / rm -rf / etc., Pi sits
silently forever waiting for me. There is no audible or visual cue that human attention is required.

Subagent permission requests DO fire notifications, because pi-smart-voice-notify's PermissionForwardingWatcher sees the forwarded
permission JSON file on disk. The parent's own guarded confirms are invisible to notification extensions.

Repro

  1. Install gentle-pi and pi-smart-voice-notify (with enablePermissionNotification: true).
  2. Ask the agent to run any guarded command in the parent session (e.g. git push origin HEAD).
  3. When the "Allow guarded command?" confirm appears → no notification, no sound.

Root cause

ctx.ui.confirm is a blocking UI primitive. It does not publish to the pi-permission-system:permission-request event channel that
notification extensions monitor.

Suggested fix

Before await ctx.ui.confirm(...) in confirmCommand, publish a waiting event, and after it resolves publish a matching approved /
denied event with the same requestId. Something like:

const requestId = crypto.randomUUID();
pi.events.emit("pi-permission-system:permission-request", {
  requestId,
  state: "waiting",
  source: "tool_call",
  message: `Guarded command awaiting confirmation: ${preview}`,
  toolName: "bash",
});

const approved = await ctx.ui.confirm("Allow guarded command?", preview);

pi.events.emit("pi-permission-system:permission-request", {
  requestId,
  state: approved ? "approved" : "denied",
  source: "tool_call",
  message: `Guarded command ${approved ? "approved" : "denied"}: ${preview}`,
  toolName: "bash",
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions