{"version":3,"file":"pi.mjs","names":["contribution","contribution","contribution","contribution","rootSession","hookBeforeAgentStart","hookSessionStart","resourceDoompiUseUserFeedback","toolRestrictionAskUserQuestion","toolAskUserQuestion"],"sources":["../../src/services/askUserToolGate/index.ts","../../src/services/autonomousVoiceMode/index.ts","../../src/services/voiceQuestionNarration/index.ts","../../src/services/voiceQuestionHandoff/index.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/root.cli.ts","../../src/extensions/workspaces/sessions/(backend)/root.cli.ts","../../src/extensions/workspaces/sessions/(backend)/hook/_lib/before-agent-start.cli.ts","../../src/extensions/workspaces/sessions/(backend)/hook/before-agent-start.cli.ts","../../src/extensions/workspaces/sessions/(backend)/hook/_lib/session-start.cli.ts","../../src/extensions/workspaces/sessions/(backend)/hook/session-start.cli.ts","../../src/extensions/workspaces/sessions/(backend)/resource/_lib/doompi-use-user-feedback.cli.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompi-use-user-feedback.cli.ts","../../src/extensions/workspaces/sessions/(backend)/tool-restriction/_lib/ask-user-question.cli.ts","../../src/extensions/workspaces/sessions/(backend)/tool-restriction/ask-user-question.cli.ts","../../src/tui/askUserToolRender.ts","../../src/services/config/index.ts","../../src/services/rpcQuestionnaire/index.ts","../../src/extensions/workspaces/sessions/(backend)/_tools/askUserQuestion.ts","../../src/extensions/workspaces/sessions/(backend)/tool/askUserQuestion.cli.ts","../../generated/pi.ts"],"sourcesContent":["import type { DoomToolRestriction } from '@agimon-ai/doompi-core/toolSurface';\n\n/**\n * Hides the questionnaire tool while nobody can answer it.\n *\n * Autonomous Voice narrates its own question and then waits for the spoken reply, so a\n * questionnaire tool alongside it asks the same thing twice. A run without UI cannot render\n * the questionnaire at all. Both cases only ever remove the name: the tool surface recomputes\n * from every registered tool, so a visible gate restores it without tracking what it hid.\n */\nexport function askUserToolRestriction(toolName: string, visible: boolean): DoomToolRestriction {\n  return (incoming) => (visible ? incoming : incoming.filter((name) => name !== toolName));\n}\n","import { DOOM_VOICE_AUTO_MODE_ID, DOOM_VOICE_SOURCE } from '@agimon-ai/doompi-core/voiceTools';\nimport type { MinorModeRecord } from '@agimon-ai/doompi-minor-mode';\n/**\n * Matches only the Voice package's own autonomous mode, and only while it reports active.\n *\n * Both the source and the mode id are checked because another package may register a mode\n * under the same id, and a transitional `activating` or `deactivating` record is not yet\n * (or no longer) speaking.\n */\nexport function isAutonomousVoiceRecord(record: MinorModeRecord): boolean {\n  return (\n    record.descriptor.source === DOOM_VOICE_SOURCE &&\n    record.descriptor.id === DOOM_VOICE_AUTO_MODE_ID &&\n    record.state.activation === 'active'\n  );\n}\n\nexport function isAutonomousVoiceActive(records: readonly MinorModeRecord[]): boolean {\n  return records.some((record) => isAutonomousVoiceRecord(record));\n}\n","import { MAX_NARRATION_TEXT_CHARACTERS } from '@agimon-ai/doompi-core/narration';\n\nimport type { QuestionParams } from '../../schemas/questionnaire';\n\nconst MAX_QUESTION_CHARACTERS = 240;\nconst MAX_OPTION_CHARACTERS = 80;\nconst PATH_PATTERN = /\\/(?:Users|home|private|tmp|var)\\/[^\\s,;:]+/gu;\nconst TOKEN_PATTERN = /\\b(?:sk|api|token|key)[-_][A-Za-z0-9_-]{12,}\\b/giu;\nconst CODE_PATTERN = /`[^`]*`|<\\/?[A-Za-z][^>]*>|\\$\\([^)]*\\)|\\{[^}]*\\}/gu;\nconst SAFE_FALLBACK = 'I need your answer to the questions shown in the conversation.';\n\nfunction takeCharacters(text: string, maximum: number): string {\n  return Array.from(text).slice(0, maximum).join('').trim();\n}\n\nexport function sanitizeVoiceQuestionText(text: string, maximum: number): string {\n  const withoutControls = Array.from(text, (character) => {\n    const codePoint = character.codePointAt(0) ?? 0;\n    return codePoint < 32 || codePoint === 127 ? ' ' : character;\n  }).join('');\n  return takeCharacters(\n    withoutControls\n      .replace(PATH_PATTERN, ' ')\n      .replace(TOKEN_PATTERN, ' ')\n      .replace(CODE_PATTERN, ' ')\n      .replace(/\\s+/gu, ' ')\n      .trim(),\n    maximum,\n  );\n}\n\nfunction spokenQuestion(params: QuestionParams, questionIndex: number): string {\n  const question = params.questions[questionIndex];\n  if (!question) return '';\n  const position = questionIndex + 1;\n  const prompt =\n    sanitizeVoiceQuestionText(question.question, MAX_QUESTION_CHARACTERS) || `Question ${position} needs your choice`;\n  const labels = question.options.map((option, optionIndex) => {\n    const label = sanitizeVoiceQuestionText(option.label, MAX_OPTION_CHARACTERS);\n    return `${optionIndex + 1}, ${label || `option ${optionIndex + 1}`}`;\n  });\n  const selection = question.multiSelect ? 'You may choose more than one option.' : 'Please choose one option.';\n  return `Question ${position}: ${prompt}. Options: ${labels.join('; ')}. ${selection} You may also answer in your own words.`;\n}\n\nexport function buildVoiceQuestionNarration(params: QuestionParams): string {\n  const questions = params.questions.map((_question, index) => spokenQuestion(params, index));\n  const combined = sanitizeVoiceQuestionText(questions.join(' '), MAX_NARRATION_TEXT_CHARACTERS);\n  return combined || SAFE_FALLBACK;\n}\n","import { createNarrationRequest, type DoomNarrationService } from '@agimon-ai/doompi-core/narration';\nimport type { MinorModeCatalogService } from '@agimon-ai/doompi-minor-mode';\n\nimport type { QuestionParams } from '../../schemas/questionnaire';\nimport type { QuestionnaireResult, ToolTextResult } from '../../types/questionnaire';\nimport { isAutonomousVoiceRecord } from '../autonomousVoiceMode';\nimport { buildVoiceQuestionNarration } from '../voiceQuestionNarration';\n\nexport const VOICE_WAIT_MESSAGE =\n  \"The questions were spoken through autonomous voice. Stop now and wait for the user's next message; it will arrive as an ordinary user message.\";\n\nexport function formatVoiceQuestionPrompt(params: QuestionParams): string {\n  const numberQuestions = params.questions.length > 1;\n  return params.questions\n    .map((question, questionIndex) => {\n      const heading = `${numberQuestions ? `${questionIndex + 1}. ` : ''}${question.question}${question.multiSelect ? ' (Select all that apply.)' : ''}`;\n      const options = question.options.map((option, optionIndex) => `  ${optionIndex + 1}. ${option.label}`);\n      return [heading, ...options, '  Type something.'].join('\\n');\n    })\n    .join('\\n\\n');\n}\n\nexport class VoiceQuestionHandoff {\n  constructor(\n    private readonly modes: Pick<MinorModeCatalogService, 'list'>,\n    private readonly narration: Pick<DoomNarrationService, 'request'>,\n    private readonly buildNarration: (params: QuestionParams) => string = buildVoiceQuestionNarration,\n  ) {}\n\n  async handoff(params: QuestionParams): Promise<QuestionnaireResult | undefined> {\n    if (!this.modes.list().some((record) => isAutonomousVoiceRecord(record))) return undefined;\n    const narration = createNarrationRequest(this.buildNarration(params));\n    if (!narration) return undefined;\n    await this.narration.request(narration);\n    return {\n      answers: [],\n      cancelled: false,\n      delivery: 'voice',\n      awaitingResponse: true,\n      voicePrompt: formatVoiceQuestionPrompt(params),\n    };\n  }\n}\n\n/** Create a handoff from services whose lifecycle is owned by a Cordis injection. */\nexport function createVoiceQuestionHandoff(\n  modes: Pick<MinorModeCatalogService, 'list'>,\n  narration: Pick<DoomNarrationService, 'request'>,\n): VoiceQuestionHandoff {\n  return new VoiceQuestionHandoff(modes, narration);\n}\n\nexport function buildVoiceToolResult(details: QuestionnaireResult): ToolTextResult {\n  const prompt = details.voicePrompt?.trim();\n  return {\n    content: [{ type: 'text', text: prompt ? `${prompt}\\n\\n${VOICE_WAIT_MESSAGE}` : VOICE_WAIT_MESSAGE }],\n    details,\n    terminate: true,\n  };\n}\n","import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport { DOOM_NARRATION_SERVICE, requireDoomNarrationService } from '@agimon-ai/doompi-core/narration';\nimport type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\nimport type { DoomToolRestriction } from '@agimon-ai/doompi-core/toolSurface';\nimport { DOOM_MINOR_MODE_CATALOG_SERVICE, requireMinorModeCatalog } from '@agimon-ai/doompi-minor-mode';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nimport { ASK_USER_QUESTION_TOOL_NAME } from '../../../../../constants/tool';\nimport { askUserToolRestriction } from '../../../../../services/askUserToolGate';\nimport { isAutonomousVoiceActive } from '../../../../../services/autonomousVoiceMode';\nimport { QuestionnaireCoordinator, type QuestionnaireRunner } from '../../../../../services/questionnaireCoordinator';\nimport { createVoiceQuestionHandoff, type VoiceQuestionHandoff } from '../../../../../services/voiceQuestionHandoff';\nimport type { QuestionnaireResult } from '../../../../../types/questionnaire';\nimport { createAskUserQuestionTool } from '.././_tools/askUserQuestion';\n\nfunction cancelledResult(): QuestionnaireResult {\n  return { answers: [], cancelled: true };\n}\n\nconst root = defineRoot((_context: PiPluginContext) => {\n  let active = true;\n  let sessionGeneration = 0;\n  let sessionId: string | undefined;\n  let sessionReady = false;\n  let coordinator = new QuestionnaireCoordinator();\n  let voiceHandoff: VoiceQuestionHandoff | undefined;\n  let voiceActive = false;\n  let hasUI = true;\n  const restrictionListeners = new Set<() => void>();\n  const currentRestriction = (): DoomToolRestriction =>\n    askUserToolRestriction(ASK_USER_QUESTION_TOOL_NAME, hasUI && !voiceActive);\n  const syncToolRestriction = (): void => restrictionListeners.forEach((listener) => listener());\n  let lifecycleQueue: Promise<void> = Promise.resolve();\n  const pendingOperations = new Set<Promise<unknown>>();\n\n  const trackOperation = <T>(operation: Promise<T>): Promise<T> => {\n    pendingOperations.add(operation);\n    void operation.then(\n      () => pendingOperations.delete(operation),\n      () => pendingOperations.delete(operation),\n    );\n    return operation;\n  };\n  const ownsGeneration = (generation: number, expectedSessionId: string | undefined): boolean =>\n    active && generation === sessionGeneration && expectedSessionId === sessionId;\n  const isContextActive = (context: ExtensionContext, signal?: AbortSignal): boolean =>\n    active && sessionReady && signal?.aborted !== true && context.sessionManager.getSessionId() === sessionId;\n\n  const shutdownRuntime = async (): Promise<void> => {\n    if (!active) return;\n    const ownedCoordinator = coordinator;\n    ownedCoordinator.shutdown();\n    active = false;\n    sessionGeneration += 1;\n    sessionReady = false;\n    sessionId = undefined;\n    await Promise.allSettled(pendingOperations);\n    await ownedCoordinator.waitForIdle();\n  };\n\n  const toolDependencies: Parameters<typeof createAskUserQuestionTool>[1] = {\n    enqueue: (runner: QuestionnaireRunner, signal?: AbortSignal) => {\n      const ownedCoordinator = coordinator;\n      const generation = sessionGeneration;\n      const expectedSessionId = sessionId;\n      if (!sessionReady || !ownsGeneration(generation, expectedSessionId) || signal?.aborted) {\n        return Promise.resolve(cancelledResult());\n      }\n      return ownedCoordinator.enqueue(async (context) => {\n        if (!sessionReady || !ownsGeneration(generation, expectedSessionId) || context.signal.aborted) {\n          return cancelledResult();\n        }\n        const result = await runner({\n          ...context,\n          reportProgress: (progress) => {\n            if (ownsGeneration(generation, expectedSessionId) && !context.signal.aborted) {\n              context.reportProgress(progress);\n            }\n          },\n        });\n        return sessionReady && ownsGeneration(generation, expectedSessionId) && !context.signal.aborted\n          ? result\n          : cancelledResult();\n      }, signal);\n    },\n    isActive: isContextActive,\n    runTui: async (context, params, collapseKey, signal, reportProgress) => {\n      if (!isContextActive(context, signal)) return undefined;\n      const { runTuiQuestionnaire } = await import('../../../../../tui/runQuestionnaire');\n      if (!isContextActive(context, signal)) return undefined;\n      const result = await runTuiQuestionnaire(context, params, collapseKey, signal, reportProgress);\n      return isContextActive(context, signal) ? result : undefined;\n    },\n    tryVoice: (params) => (active && sessionReady ? voiceHandoff?.handoff(params) : undefined),\n  };\n\n  const beforeAgentStart = (_event: unknown, context: ExtensionContext) => {\n    if (!isContextActive(context)) return;\n    hasUI = context.hasUI;\n    syncToolRestriction();\n  };\n\n  const sessionStart = (_event: unknown, context: ExtensionContext) => {\n    if (!active) return;\n    const previousCoordinator = coordinator;\n    previousCoordinator.shutdown();\n    const activeSessionId = context.sessionManager.getSessionId();\n    const generation = ++sessionGeneration;\n    const nextCoordinator = new QuestionnaireCoordinator();\n    coordinator = nextCoordinator;\n    sessionId = activeSessionId;\n    sessionReady = false;\n\n    const initializeSession = async (): Promise<void> => {\n      await previousCoordinator.waitForIdle();\n      if (!ownsGeneration(generation, activeSessionId)) return;\n      sessionReady = true;\n      // The surface is re-registered per session from the gate state in force, so a session\n      // that starts with Voice already active needs nothing extra here.\n    };\n\n    const operation = lifecycleQueue.then(initializeSession, initializeSession);\n    lifecycleQueue = operation.catch(() => undefined);\n    return trackOperation(operation);\n  };\n  const toolRestriction = {\n    source: '@agimon-ai/doompi-user-feedback',\n    get restrict() {\n      return currentRestriction();\n    },\n    subscribe(listener: () => void) {\n      restrictionListeners.add(listener);\n      return () => {\n        restrictionListeners.delete(listener);\n      };\n    },\n  };\n\n  return {\n    value: {\n      toolDependencies,\n      beforeAgentStart,\n      sessionStart,\n      toolRestriction,\n    },\n    services: [\n      (serviceContextOwner: Context) => {\n        serviceContextOwner.inject([DOOM_MINOR_MODE_CATALOG_SERVICE, DOOM_NARRATION_SERVICE], (serviceContext) => {\n          const handoff = createVoiceQuestionHandoff(\n            requireMinorModeCatalog(serviceContext),\n            requireDoomNarrationService(serviceContext),\n          );\n          voiceHandoff = handoff;\n          return () => {\n            if (voiceHandoff === handoff) voiceHandoff = undefined;\n          };\n        });\n\n        // Separate from the handoff binding above: the gate needs only the mode catalog, so it\n        // still applies to a Voice build that publishes modes without providing narration.\n        serviceContextOwner.inject([DOOM_MINOR_MODE_CATALOG_SERVICE], (modeContext) => {\n          const modes = requireMinorModeCatalog(modeContext);\n          const apply = (): void => {\n            voiceActive = isAutonomousVoiceActive(modes.list());\n            syncToolRestriction();\n          };\n          const unsubscribe = modes.subscribe(apply);\n          apply();\n          return () => {\n            unsubscribe();\n            voiceActive = false;\n            syncToolRestriction();\n          };\n        });\n      },\n    ],\n    onDispose: shutdownRuntime,\n  };\n});\n\nexport type UserFeedbackPiScope = Awaited<ReturnType<typeof root>>['value'];\nexport default root;\n","import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/root.cli';\n\nexport default defineRoot(contribution);\n","import type { WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport type { UserFeedbackPiScope } from '../../_lib/root.cli';\n\nexport default (context: WithRoot<PiPluginContext, UserFeedbackPiScope>) => context.root.beforeAgentStart;\n","import { defineCliHook } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/before-agent-start.cli';\n\nexport default defineCliHook(contribution);\n","import type { WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport type { UserFeedbackPiScope } from '../../_lib/root.cli';\n\nexport default (context: WithRoot<PiPluginContext, UserFeedbackPiScope>) => context.root.sessionStart;\n","import { defineCliHook } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/session-start.cli';\n\nexport default defineCliHook(contribution);\n","export function createDoompiUseUserFeedbackResource(moduleUrl: string) {\n  return {\n    source: '@agimon-ai/doompi-user-feedback',\n    moduleUrl,\n    skills: [\n      {\n        name: 'doompi-use-user-feedback',\n        description:\n          'Use @agimon-ai/doompi-user-feedback: Structured user questions with interactive and autonomous Voice handoff for Pi agents.',\n      },\n    ],\n  };\n}\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { createDoompiUseUserFeedbackResource } from './_lib/doompi-use-user-feedback.cli';\n\nexport default defineResource(createDoompiUseUserFeedbackResource(import.meta.url));\n","import type { WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport type { UserFeedbackPiScope } from '../../_lib/root.cli';\n\nexport default (context: WithRoot<PiPluginContext, UserFeedbackPiScope>) => context.root.toolRestriction;\n","import { defineToolRestriction } from '@agimon-ai/doompi-core/extensionFile';\n\nimport contribution from './_lib/ask-user-question.cli';\n\nexport default defineToolRestriction(contribution);\n","import { DoomToolCall, DoomToolResult, renderToolHeading } from '@agimon-ai/doompi-ui/toolChrome';\nimport type { ToolDefinition } from '@earendil-works/pi-coding-agent';\n\nimport type { QuestionParams, QuestionParamsSchema } from '../schemas/questionnaire';\nimport type { QuestionnaireResult } from '../types/questionnaire';\nexport const askUserToolRender: Pick<\n  ToolDefinition<typeof QuestionParamsSchema, QuestionnaireResult>,\n  'renderCall' | 'renderResult'\n> = {\n  renderCall(args, theme) {\n    const params = args as QuestionParams;\n    const headers = params.questions.map((question) => question.header).join(', ');\n    const count = `${params.questions.length} question${params.questions.length === 1 ? '' : 's'}`;\n    const heading = renderToolHeading('ask', count, theme);\n    return new DoomToolCall(headers ? `${heading} ${theme.fg('dim', `(${headers})`)}` : heading);\n  },\n\n  renderResult(result, _options, theme, context) {\n    const details = result.details as QuestionnaireResult | undefined;\n    if (!details) {\n      const raw = result.content\n        .filter((block) => block.type === 'text')\n        .map((block) => block.text)\n        .join('\\n');\n      const color = context.isError ? 'error' : 'toolOutput';\n      const fallback = context.isError ? '✗ failed' : '✓ submitted';\n      return new DoomToolResult([theme.fg(color, raw || fallback)], theme, { wrap: true });\n    }\n    if (details.cancelled) {\n      return new DoomToolResult([theme.fg('warning', '◐') + theme.fg('dim', ' cancelled')], theme);\n    }\n    if (details.delivery === 'voice' && details.voicePrompt) {\n      return new DoomToolResult([theme.fg('toolOutput', details.voicePrompt)], theme, { wrap: true });\n    }\n    const lines = details.answers.map((answer) => {\n      const scalar = answer.kind === 'multi' ? (answer.selected ?? []).join(', ') : answer.answer;\n      return `${theme.fg('success', '✓')} ${theme.fg('accent', answer.question)}: ${theme.fg(\n        'toolOutput',\n        scalar ?? '',\n      )}`;\n    });\n    if (lines.length === 0) lines.push(theme.fg('success', '✓') + theme.fg('dim', ' submitted'));\n    return new DoomToolResult(lines, theme, { wrap: true });\n  },\n};\n","import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nexport const DEFAULT_COLLAPSE_KEY = 'ctrl+]';\nexport const COLLAPSE_KEY_OFF = 'off';\n\nexport interface GuidanceConfig {\n  promptSnippet?: string;\n  promptGuidelines?: string[];\n}\n\nexport interface UserFeedbackConfig {\n  collapseKey?: string;\n  guidance?: GuidanceConfig;\n}\n\nfunction legacyConfigPath(environment: NodeJS.ProcessEnv): string {\n  const configRoot = environment.XDG_CONFIG_HOME?.trim() || path.join(os.homedir(), '.config');\n  return path.join(configRoot, 'rpiv-ask-user-question', 'config.json');\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function loadUserFeedbackConfig(environment: NodeJS.ProcessEnv = process.env): UserFeedbackConfig {\n  const filePath = legacyConfigPath(environment);\n  if (!fs.existsSync(filePath)) return {};\n  try {\n    const parsed: unknown = JSON.parse(fs.readFileSync(filePath, 'utf8'));\n    if (!isRecord(parsed)) return {};\n    const rawGuidance = isRecord(parsed.guidance) ? parsed.guidance : undefined;\n    const guidance = rawGuidance\n      ? {\n          ...(typeof rawGuidance.promptSnippet === 'string' ? { promptSnippet: rawGuidance.promptSnippet } : {}),\n          ...(Array.isArray(rawGuidance.promptGuidelines) &&\n          rawGuidance.promptGuidelines.every((item) => typeof item === 'string')\n            ? { promptGuidelines: rawGuidance.promptGuidelines as string[] }\n            : {}),\n        }\n      : undefined;\n    return {\n      ...(typeof parsed.collapseKey === 'string' ? { collapseKey: parsed.collapseKey } : {}),\n      ...(guidance ? { guidance } : {}),\n    };\n  } catch {\n    return {};\n  }\n}\n\nexport function resolveCollapseKey(config: UserFeedbackConfig): string {\n  const value = config.collapseKey?.trim().toLowerCase();\n  if (!value) return DEFAULT_COLLAPSE_KEY;\n  if (value === COLLAPSE_KEY_OFF) return COLLAPSE_KEY_OFF;\n  return /^[a-z0-9_+\\-\\]{}]+$/u.test(value) ? value : DEFAULT_COLLAPSE_KEY;\n}\n","import type { ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nimport type { QuestionParams } from '../../schemas/questionnaire';\nimport type { QuestionnaireResult } from '../../types/questionnaire';\nimport { runQuestionnaire, type QuestionnaireInteraction } from '../questionnaireService';\n\nexport async function runRpcQuestionnaire(\n  context: ExtensionContext,\n  params: QuestionParams,\n  signal?: AbortSignal,\n  reportProgress?: (result: QuestionnaireResult) => void,\n): Promise<QuestionnaireResult> {\n  const interaction: QuestionnaireInteraction = {\n    select: (title, options, interactionSignal) =>\n      context.ui.select(title, [...options], { signal: interactionSignal }),\n    input: (title, placeholder, interactionSignal) =>\n      context.ui.input(title, placeholder, { signal: interactionSignal }),\n  };\n  return runQuestionnaire(interaction, params, signal, reportProgress);\n}\n","import {\n  type AskUserBlockedEvent,\n  type AskUserPromptEvent,\n  DOOM_ASK_USER_BLOCKED_EVENT,\n  DOOM_ASK_USER_PROMPT_EVENT,\n} from '@agimon-ai/doompi-core/askUser';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ToolDefinition, ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nimport {\n  ASK_USER_QUESTION_TOOL_NAME,\n  DEFAULT_PROMPT_SNIPPET,\n  DEFAULT_PROMPT_GUIDELINES,\n  ERROR_NO_UI,\n  ERROR_NO_CUSTOM_UI,\n  ERROR_SESSION_LOAD_FAILED,\n  ERROR_SESSION_INACTIVE,\n} from '../../../../../constants/tool';\nimport { type QuestionParams, QuestionParamsSchema } from '../../../../../schemas/questionnaire';\nimport { loadUserFeedbackConfig, resolveCollapseKey } from '../../../../../services/config';\nimport type { QuestionnaireRunner } from '../../../../../services/questionnaireCoordinator';\nimport { buildQuestionnaireResponse, buildToolResult } from '../../../../../services/responseService';\nimport { runRpcQuestionnaire } from '../../../../../services/rpcQuestionnaire';\nimport { validateQuestionnaire } from '../../../../../services/validationService';\nimport { buildVoiceToolResult } from '../../../../../services/voiceQuestionHandoff';\nimport type { QuestionnaireResult } from '../../../../../types/questionnaire';\nexport interface AskUserQuestionToolDependencies {\n  enqueue: (runner: QuestionnaireRunner, signal?: AbortSignal) => Promise<QuestionnaireResult>;\n  isActive?: (context: ExtensionContext, signal?: AbortSignal) => boolean;\n  tryVoice?: (params: QuestionParams) => QuestionnaireResult | undefined | Promise<QuestionnaireResult | undefined>;\n  runTui: (\n    context: ExtensionContext,\n    params: QuestionParams,\n    collapseKey: string,\n    signal?: AbortSignal,\n    reportProgress?: (result: QuestionnaireResult) => void,\n  ) => Promise<QuestionnaireResult | undefined>;\n}\n\nfunction emitPrompt(cordis: Context, params: QuestionParams): void {\n  const payload: AskUserPromptEvent = {\n    questions: params.questions.map((question) => ({\n      question: question.question,\n      header: question.header,\n      multiSelect: question.multiSelect ?? false,\n      options: question.options.map((option) => ({\n        label: option.label,\n        description: option.description,\n        hasPreview: Boolean(option.preview),\n      })),\n    })),\n  };\n  cordis.emit(DOOM_ASK_USER_PROMPT_EVENT, payload);\n}\n\nfunction emitBlocked(cordis: Context, active: boolean): void {\n  const payload: AskUserBlockedEvent = { active };\n  cordis.emit(DOOM_ASK_USER_BLOCKED_EVENT, payload);\n}\n\nfunction hasDialogUI(context: ExtensionContext): boolean {\n  const ui = context.ui as unknown as { select?: unknown; input?: unknown };\n  return typeof ui.select === 'function' && typeof ui.input === 'function';\n}\n\nexport function createAskUserQuestionTool(\n  cordis: Context,\n  dependencies: AskUserQuestionToolDependencies,\n  renderers: Pick<ToolDefinition<typeof QuestionParamsSchema, QuestionnaireResult>, 'renderCall' | 'renderResult'> = {},\n): ToolDefinition<typeof QuestionParamsSchema, QuestionnaireResult> {\n  const configuredGuidance = loadUserFeedbackConfig().guidance;\n  return {\n    name: ASK_USER_QUESTION_TOOL_NAME,\n    label: 'Ask User Question',\n    renderShell: 'self',\n    description: `Ask the user one or more structured questions during execution. Use when you need to:\n1. Gather user preferences or requirements\n2. Clarify ambiguous instructions\n3. Get decisions on implementation choices as you work\n4. Offer choices to the user about what direction to take\n\nUsage notes:\n- Users can type a custom answer via the automatically appended \"Type something.\" row on every question or press Esc to abandon the questionnaire. Do NOT author \"Other\" or \"Type something.\" labels yourself, reserved labels are rejected at runtime.\n- Use multiSelect: true when multiple answers are valid.\n- If you recommend a specific option, make that the first option and add \"(Recommended)\" at the end of the label.\n\nPreview feature:\nUse the optional preview field for ASCII mockups, code snippets, diagrams, or configuration examples that users should compare visually. Do not use previews for simple preference questions.`,\n    promptSnippet: configuredGuidance?.promptSnippet ?? DEFAULT_PROMPT_SNIPPET,\n    promptGuidelines: configuredGuidance?.promptGuidelines ?? DEFAULT_PROMPT_GUIDELINES,\n    parameters: QuestionParamsSchema,\n    executionMode: 'sequential',\n\n    async execute(_toolCallId, params, signal, _onUpdate, context) {\n      const typed = params as QuestionParams;\n      const isActive = (activeSignal?: AbortSignal): boolean => dependencies.isActive?.(context, activeSignal) ?? true;\n      const cancelled = (): QuestionnaireResult => ({ answers: [], cancelled: true });\n      if (!isActive(signal)) return buildToolResult(ERROR_SESSION_INACTIVE, cancelled());\n      if (!context.hasUI) {\n        return buildToolResult(ERROR_NO_UI, { answers: [], cancelled: true, error: 'no_ui' });\n      }\n\n      const validation = validateQuestionnaire(typed);\n      if (!validation.ok) {\n        return buildToolResult(validation.message, {\n          answers: [],\n          cancelled: true,\n          error: validation.error,\n        });\n      }\n\n      try {\n        const result = await dependencies.enqueue(async ({ signal: activeSignal, reportProgress }) => {\n          if (!isActive(activeSignal)) return cancelled();\n          emitPrompt(cordis, typed);\n          const voiceResult = await dependencies.tryVoice?.(typed);\n          if (voiceResult) return voiceResult;\n\n          let blocked = true;\n          const clearBlocked = (): void => {\n            if (!blocked) return;\n            blocked = false;\n            if (isActive()) emitBlocked(cordis, false);\n          };\n          activeSignal.addEventListener('abort', clearBlocked, { once: true });\n          emitBlocked(cordis, true);\n          try {\n            if (!isActive(activeSignal)) return cancelled();\n            if (context.mode === 'rpc' && hasDialogUI(context)) {\n              const rpcResult = await runRpcQuestionnaire(context, typed, activeSignal, reportProgress);\n              return isActive(activeSignal) ? rpcResult : cancelled();\n            }\n\n            const tuiResult = await dependencies.runTui(\n              context,\n              typed,\n              resolveCollapseKey(loadUserFeedbackConfig()),\n              activeSignal,\n              reportProgress,\n            );\n            if (!isActive(activeSignal)) return cancelled();\n            if (tuiResult !== undefined) return tuiResult;\n            if (hasDialogUI(context)) {\n              const rpcResult = await runRpcQuestionnaire(context, typed, activeSignal, reportProgress);\n              return isActive(activeSignal) ? rpcResult : cancelled();\n            }\n            return { answers: [], cancelled: true, error: 'no_custom_ui' };\n          } finally {\n            activeSignal.removeEventListener('abort', clearBlocked);\n            clearBlocked();\n          }\n        }, signal);\n\n        if (result.delivery === 'voice') return buildVoiceToolResult(result);\n        if (result.error === 'no_custom_ui') return buildToolResult(ERROR_NO_CUSTOM_UI, result);\n        return buildQuestionnaireResponse(result, typed);\n      } catch (error) {\n        const cause = error instanceof Error ? error.message : String(error);\n        return buildToolResult(`${ERROR_SESSION_LOAD_FAILED} (cause: ${cause})`, {\n          answers: [],\n          cancelled: true,\n          error: 'session_load_failed',\n        });\n      }\n    },\n\n    ...renderers,\n  };\n}\n","import { defineCliTool, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport { definePiTool, type PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport { askUserToolRender } from '../../../../../tui/askUserToolRender';\nimport type { UserFeedbackPiScope } from '../_lib/root.cli';\nimport { createAskUserQuestionTool } from '../_tools/askUserQuestion';\n\nexport default defineCliTool((context: WithRoot<PiPluginContext, UserFeedbackPiScope>) =>\n  definePiTool(createAskUserQuestionTool(context.context, context.root.toolDependencies, askUserToolRender)),\n);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { definePiExtension, piToolContributions, type PiPluginContext, type PiPluginContributions } from '@agimon-ai/doompi-core/piExtension';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.cli';\nimport hookBeforeAgentStart from '../src/extensions/workspaces/sessions/(backend)/hook/before-agent-start.cli';\nimport hookSessionStart from '../src/extensions/workspaces/sessions/(backend)/hook/session-start.cli';\nimport resourceDoompiUseUserFeedback from '../src/extensions/workspaces/sessions/(backend)/resource/doompi-use-user-feedback.cli';\nimport toolRestrictionAskUserQuestion from '../src/extensions/workspaces/sessions/(backend)/tool-restriction/ask-user-question.cli';\nimport toolAskUserQuestion from '../src/extensions/workspaces/sessions/(backend)/tool/askUserQuestion.cli';\n\ntype OptionsOf<T> = T extends (context: PiPluginContext<infer Options>) => unknown ? Options : never;\ntype InferredOptions = Exclude<OptionsOf<typeof rootSession> | OptionsOf<typeof hookBeforeAgentStart> | OptionsOf<typeof hookSessionStart> | OptionsOf<typeof resourceDoompiUseUserFeedback> | OptionsOf<typeof toolRestrictionAskUserQuestion> | OptionsOf<typeof toolAskUserQuestion>, undefined>;\ntype Intersect<Union> =\n  (Union extends unknown ? (value: Union) => void : never) extends (value: infer Value) => void ? Value : never;\ntype ExtensionOptions = [InferredOptions] extends [never] ? undefined : Intersect<InferredOptions>;\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n  typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n  (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const extension = definePiExtension<ExtensionOptions>('@agimon-ai/doompi-user-feedback', async (context) => {\n  const scopeSession = await rootSession(context);\n  const contextSession = { ...context, root: scopeSession.value };\n  return {\n    ...composeRootHooks(scopeSession),\n    events: {\n      before_agent_start: at(hookBeforeAgentStart, contextSession) as NonNullable<PiPluginContributions['events']>['before_agent_start'],\n      session_start: at(hookSessionStart, contextSession) as NonNullable<PiPluginContributions['events']>['session_start'],\n    },\n    get resources(): PiPluginContributions['resources'] { return [at(resourceDoompiUseUserFeedback, contextSession)]; },\n    get toolRestrictions(): PiPluginContributions['toolRestrictions'] { return [at(toolRestrictionAskUserQuestion, contextSession)]; },\n    ...piToolContributions('@agimon-ai/doompi-user-feedback', [via({ name: 'ask_user_question' }, at(toolAskUserQuestion, contextSession))]),\n    services: [...(scopeSession.services ?? [])],\n  };\n});\n\nexport default extension;\n"],"mappings":"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"}