@agimon-ai/doompi-user-feedback 0.0.1-alpha.1 → 0.0.1-alpha.11

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/README.md CHANGED
@@ -1,10 +1,95 @@
1
1
  # @agimon-ai/doompi-user-feedback
2
2
 
3
- An independent DoomPi extension for structured `ask_user_question` interactions.
3
+ Structured, blocking user questions for Pi, with an autonomous-Voice handoff.
4
4
 
5
- The implementation is written from scratch for Pi 0.84.1. It retains the established `rpiv:ask-user:prompt` and `rpiv:ask-user:blocked` channel names so existing DoomPi consumers can migrate without changing their listeners. It has no dependency on `@juicesharp/rpiv-ask-user-question`, `@juicesharp/rpiv-i18n`, or other Juicesharp packages.
5
+ The `ask_user_question` tool presents concrete options instead of asking the model to continue on a guess.
6
6
 
7
- When DoomPi autonomous voice mode is active, the extension narrates the questions without opening a modal questionnaire. The spoken response returns through Doom Voice as the next user message.
7
+ > **Alpha:** tool and Voice-handoff contracts may change between releases.
8
+
9
+ ## Requirements
10
+
11
+ - Node.js 22.19.0 or newer
12
+ - Pi 0.84.2 and Pi TUI 0.84.2
13
+
14
+ ## Install
15
+
16
+ Add the package to a DoomPi layer:
17
+
18
+ ```yaml
19
+ layers:
20
+ feedback:
21
+ packages: ['@agimon-ai/doompi-user-feedback']
22
+ ```
23
+
24
+ For standalone Pi:
25
+
26
+ ```bash
27
+ pi install npm:@agimon-ai/doompi-user-feedback
28
+ ```
29
+
30
+ ## Ask a question
31
+
32
+ ```json
33
+ {
34
+ "questions": [
35
+ {
36
+ "header": "Storage",
37
+ "question": "Where should session results be stored?",
38
+ "options": [
39
+ {
40
+ "label": "Project files",
41
+ "description": "Easy to inspect and commit, but visible in the repository."
42
+ },
43
+ {
44
+ "label": "User state",
45
+ "description": "Keeps generated state outside the repository."
46
+ }
47
+ ],
48
+ "multiSelect": false
49
+ }
50
+ ]
51
+ }
52
+ ```
53
+
54
+ A call accepts 1–4 questions. Each question requires 2–4 options. Headers are at most 16 characters; option labels are at most 60 characters. Use `multiSelect: true` when several choices are valid. An option can include a Markdown `preview` for meaningful visual comparison.
55
+
56
+ The tool result contains readable answer text plus structured `details.answers`; cancellation sets `cancelled: true`. Pressing Escape declines the questionnaire. Do not add an `Other` option because the UI supplies a custom-text row.
57
+
58
+ ## UI, RPC, and headless behavior
59
+
60
+ The tool requires an interactive UI. It uses the TUI questionnaire when available and can use Pi's dialog/RPC UI bridge. A truly headless context returns a structured `no_ui` cancellation rather than waiting forever.
61
+
62
+ Questionnaires are coordinated one at a time. Cancellation, session replacement, or shutdown aborts the active prompt and settles queued work.
63
+
64
+ ## Autonomous Voice handoff
65
+
66
+ When autonomous Voice mode is active, the extension formats the questions as plain text, requests narration, and returns `terminate: true`. The current turn ends while waiting; the next spoken answer arrives as a normal user message rather than a synthetic questionnaire selection.
67
+
68
+ Reusable integrations can create a session-scoped handoff:
69
+
70
+ ```ts
71
+ import { createVoiceQuestionHandoff } from '@agimon-ai/doompi-user-feedback/voice-question-handoff';
72
+ import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
73
+
74
+ export function installVoiceHandoff(pi: ExtensionAPI, sessionId: string): () => void {
75
+ const handoff = createVoiceQuestionHandoff({
76
+ bus: pi.events,
77
+ source: '@example/review-extension',
78
+ sessionId,
79
+ });
80
+ return () => handoff.dispose();
81
+ }
82
+ ```
83
+
84
+ Always dispose the handle during shutdown.
85
+
86
+ ## Public API
87
+
88
+ ```ts
89
+ import { registerUserFeedbackExtension } from '@agimon-ai/doompi-user-feedback';
90
+ ```
91
+
92
+ Event constants are available through `/events`; the Pi adapter is `/extensions/pi`.
8
93
 
9
94
  ## Development
10
95
 
@@ -15,4 +100,6 @@ pnpm test
15
100
  pnpm lint
16
101
  ```
17
102
 
18
- The Pi extension entrypoint is `@agimon-ai/doompi-user-feedback/extensions/pi`.
103
+ ## License
104
+
105
+ MIT
@@ -1,5 +1,5 @@
1
- const e=`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.`;function t(e){return e.source===`@agimon-ai/doompi-voice`&&e.id===`voice-auto`}function n(e){let t=e.questions.length>1;return e.questions.map((e,n)=>[`${t?`${n+1}. `:``}${e.question}${e.multiSelect?` (Select all that apply.)`:``}`,...e.options.map((e,t)=>` ${t+1}. ${e.label}`),` Type something.`].join(`
1
+ const e=require("../../services/voiceQuestionNarration.cjs");let t=require("@agimon-ai/doompi-extension-contracts/mode"),n=require("@agimon-ai/doompi-extension-contracts/narration"),r=require("@agimon-ai/doompi-extension-contracts/protocol");const i=`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.`;function a(e){return e.descriptor.source===`@agimon-ai/doompi-voice`&&e.descriptor.id===`voice-auto`&&e.state.activation===`active`}function o(e){let t=e.questions.length>1;return e.questions.map((e,n)=>[`${t?`${n+1}. `:``}${e.question}${e.multiSelect?` (Select all that apply.)`:``}`,...e.options.map((e,t)=>` ${t+1}. ${e.label}`),` Type something.`].join(`
2
2
  `)).join(`
3
3
 
4
- `)}var r=class{modes;narration;buildNarration;constructor(e,t,n){this.modes=e,this.narration=t,this.buildNarration=n}handoff(e){if(this.modes.getStatuses().some(t))return this.narration.narrate(this.buildNarration(e)),{answers:[],cancelled:!1,delivery:`voice`,awaitingResponse:!0,voicePrompt:n(e)}}};function i(t){return{content:[{type:`text`,text:e}],details:t,terminate:!0}}exports.DOOM_VOICE_AUTO_MODE_ID=`voice-auto`,exports.DOOM_VOICE_SOURCE=`@agimon-ai/doompi-voice`,exports.VOICE_WAIT_MESSAGE=e,exports.VoiceQuestionHandoff=r,exports.buildVoiceToolResult=i,exports.formatVoiceQuestionPrompt=n;
4
+ `)}var s=class{modes;narration;buildNarration;constructor(e,t,n){this.modes=e,this.narration=t,this.buildNarration=n}handoff(e){if(this.modes.list().some(a))return this.narration.narrate(this.buildNarration(e)),{answers:[],cancelled:!1,delivery:`voice`,awaitingResponse:!0,voicePrompt:o(e)}}};function c(i){let a=(0,t.createMinorModeCatalogClient)(),o=a.bind((0,r.createProtocolRuntime)(i)),c=new s(a,(0,n.createNarrationRequester)(i),e.buildVoiceQuestionNarration),l=!1;return{handoff(e){return l?void 0:c.handoff(e)},dispose(){l||(l=!0,o(),a.dispose())}}}function l(e){let t=e.voicePrompt?.trim();return{content:[{type:`text`,text:t?`${t}\n\n${i}`:i}],details:e,terminate:!0}}exports.DOOM_VOICE_AUTO_MODE_ID=`voice-auto`,exports.DOOM_VOICE_SOURCE=`@agimon-ai/doompi-voice`,exports.VOICE_WAIT_MESSAGE=i,exports.VoiceQuestionHandoff=s,exports.buildVoiceToolResult=l,exports.createVoiceQuestionHandoff=c,exports.formatVoiceQuestionPrompt=o;
5
5
  //# sourceMappingURL=voiceQuestionHandoff.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"voiceQuestionHandoff.cjs","names":[],"sources":["../../../src/adapters/doom/voiceQuestionHandoff.ts"],"sourcesContent":["import type { DoomModeStatusRegistry, DoomModeStatus } from '@agimon-ai/doompi-extension-contracts/mode';\nimport type { NarrationRequester } from '@agimon-ai/doompi-extension-contracts/narration';\nimport type { QuestionParams } from '../../schemas/questionnaire.js';\nimport type { QuestionnaireResult, ToolTextResult } from '../../types/questionnaire.js';\n\nexport const DOOM_VOICE_SOURCE = '@agimon-ai/doompi-voice';\nexport const DOOM_VOICE_AUTO_MODE_ID = 'voice-auto';\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\nfunction isAutonomousVoice(status: DoomModeStatus): boolean {\n return status.source === DOOM_VOICE_SOURCE && status.id === DOOM_VOICE_AUTO_MODE_ID;\n}\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<DoomModeStatusRegistry, 'getStatuses'>,\n private readonly narration: NarrationRequester,\n private readonly buildNarration: (params: QuestionParams) => string,\n ) {}\n\n handoff(params: QuestionParams): QuestionnaireResult | undefined {\n if (!this.modes.getStatuses().some(isAutonomousVoice)) return undefined;\n this.narration.narrate(this.buildNarration(params));\n return {\n answers: [],\n cancelled: false,\n delivery: 'voice',\n awaitingResponse: true,\n voicePrompt: formatVoiceQuestionPrompt(params),\n };\n }\n}\n\nexport function buildVoiceToolResult(details: QuestionnaireResult): ToolTextResult {\n return {\n content: [{ type: 'text', text: VOICE_WAIT_MESSAGE }],\n details,\n terminate: true,\n };\n}\n"],"mappings":"AAKA,MAEa,EACX,iJAEF,SAAS,EAAkB,EAAiC,CAC1D,OAAO,EAAO,SAAA,2BAAgC,EAAO,KAAA,YACvD,CAEA,SAAgB,EAA0B,EAAgC,CACxE,IAAM,EAAkB,EAAO,UAAU,OAAS,EAClD,OAAO,EAAO,UACX,KAAK,EAAU,IAGP,CAAC,GAFW,EAAkB,GAAG,EAAgB,EAAE,IAAM,KAAK,EAAS,WAAW,EAAS,YAAc,4BAA8B,KAE7H,GADD,EAAS,QAAQ,KAAK,EAAQ,IAAgB,KAAK,EAAc,EAAE,IAAI,EAAO,OACpE,EAAG,mBAAmB,CAAC,CAAC,KAAK;CAAI,CAC5D,CAAC,CACD,KAAK;;CAAM,CAChB,CAEA,IAAa,EAAb,KAAkC,CAEb,MACA,UACA,eAHnB,YACE,EACA,EACA,EACA,CAHiB,KAAA,MAAA,EACA,KAAA,UAAA,EACA,KAAA,eAAA,CAChB,CAEH,QAAQ,EAAyD,CAC1D,QAAK,MAAM,YAAY,CAAC,CAAC,KAAK,CAAiB,EAEpD,OADA,KAAK,UAAU,QAAQ,KAAK,eAAe,CAAM,CAAC,EAC3C,CACL,QAAS,CAAC,EACV,UAAW,GACX,SAAU,QACV,iBAAkB,GAClB,YAAa,EAA0B,CAAM,CAC/C,CACF,CACF,EAEA,SAAgB,EAAqB,EAA8C,CACjF,MAAO,CACL,QAAS,CAAC,CAAE,KAAM,OAAQ,KAAM,CAAmB,CAAC,EACpD,UACA,UAAW,EACb,CACF"}
1
+ {"version":3,"file":"voiceQuestionHandoff.cjs","names":["createMinorModeCatalogClient","createProtocolRuntime","createNarrationRequester","buildVoiceQuestionNarration"],"sources":["../../../src/adapters/doom/voiceQuestionHandoff.ts"],"sourcesContent":["import {\n createMinorModeCatalogClient,\n type MinorModeCatalogClient,\n type MinorModeRecord,\n} from '@agimon-ai/doompi-extension-contracts/mode';\nimport { createNarrationRequester, type NarrationRequester } from '@agimon-ai/doompi-extension-contracts/narration';\nimport { createProtocolRuntime, type ProtocolRuntimeOptions } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport type { QuestionParams } from '../../schemas/questionnaire.js';\nimport { buildVoiceQuestionNarration } from '../../services/voiceQuestionNarration.js';\nimport type { QuestionnaireResult, ToolTextResult } from '../../types/questionnaire.js';\n\nexport const DOOM_VOICE_SOURCE = '@agimon-ai/doompi-voice';\nexport const DOOM_VOICE_AUTO_MODE_ID = 'voice-auto';\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\nfunction isAutonomousVoice(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 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<MinorModeCatalogClient, 'list'>,\n private readonly narration: NarrationRequester,\n private readonly buildNarration: (params: QuestionParams) => string,\n ) {}\n\n handoff(params: QuestionParams): QuestionnaireResult | undefined {\n if (!this.modes.list().some(isAutonomousVoice)) return undefined;\n this.narration.narrate(this.buildNarration(params));\n return {\n answers: [],\n cancelled: false,\n delivery: 'voice',\n awaitingResponse: true,\n voicePrompt: formatVoiceQuestionPrompt(params),\n };\n }\n}\n\nexport interface VoiceQuestionHandoffHandle {\n handoff(params: QuestionParams): QuestionnaireResult | undefined;\n dispose(): void;\n}\n\n/**\n * Bind one session-scoped autonomous-voice handoff.\n *\n * The returned handle owns the external catalog subscription and must be\n * disposed when its session is replaced or shut down.\n */\nexport function createVoiceQuestionHandoff(options: ProtocolRuntimeOptions): VoiceQuestionHandoffHandle {\n const modes = createMinorModeCatalogClient();\n const disposeBinding = modes.bind(createProtocolRuntime(options));\n const handoff = new VoiceQuestionHandoff(modes, createNarrationRequester(options), buildVoiceQuestionNarration);\n let disposed = false;\n\n return {\n handoff(params) {\n return disposed ? undefined : handoff.handoff(params);\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n disposeBinding();\n modes.dispose();\n },\n };\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"],"mappings":"kPAWA,MAEa,EACX,iJAEF,SAAS,EAAkB,EAAkC,CAC3D,OACE,EAAO,WAAW,SAAA,2BAClB,EAAO,WAAW,KAAA,cAClB,EAAO,MAAM,aAAe,QAEhC,CAEA,SAAgB,EAA0B,EAAgC,CACxE,IAAM,EAAkB,EAAO,UAAU,OAAS,EAClD,OAAO,EAAO,UACX,KAAK,EAAU,IAGP,CAAC,GAFW,EAAkB,GAAG,EAAgB,EAAE,IAAM,KAAK,EAAS,WAAW,EAAS,YAAc,4BAA8B,KAE7H,GADD,EAAS,QAAQ,KAAK,EAAQ,IAAgB,KAAK,EAAc,EAAE,IAAI,EAAO,OACpE,EAAG,mBAAmB,CAAC,CAAC,KAAK;CAAI,CAC5D,CAAC,CACD,KAAK;;CAAM,CAChB,CAEA,IAAa,EAAb,KAAkC,CAEb,MACA,UACA,eAHnB,YACE,EACA,EACA,EACA,CAHiB,KAAA,MAAA,EACA,KAAA,UAAA,EACA,KAAA,eAAA,CAChB,CAEH,QAAQ,EAAyD,CAC1D,QAAK,MAAM,KAAK,CAAC,CAAC,KAAK,CAAiB,EAE7C,OADA,KAAK,UAAU,QAAQ,KAAK,eAAe,CAAM,CAAC,EAC3C,CACL,QAAS,CAAC,EACV,UAAW,GACX,SAAU,QACV,iBAAkB,GAClB,YAAa,EAA0B,CAAM,CAC/C,CACF,CACF,EAaA,SAAgB,EAA2B,EAA6D,CACtG,IAAM,GAAA,EAAQA,EAAAA,6BAAAA,CAA6B,EACrC,EAAiB,EAAM,MAAA,EAAKC,EAAAA,sBAAAA,CAAsB,CAAO,CAAC,EAC1D,EAAU,IAAI,EAAqB,GAAA,EAAOC,EAAAA,yBAAAA,CAAyB,CAAO,EAAGC,EAAAA,2BAA2B,EAC1G,EAAW,GAEf,MAAO,CACL,QAAQ,EAAQ,CACd,OAAO,EAAW,IAAA,GAAY,EAAQ,QAAQ,CAAM,CACtD,EACA,SAAU,CACJ,IACJ,EAAW,GACX,EAAe,EACf,EAAM,QAAQ,EAChB,CACF,CACF,CAEA,SAAgB,EAAqB,EAA8C,CACjF,IAAM,EAAS,EAAQ,aAAa,KAAK,EACzC,MAAO,CACL,QAAS,CAAC,CAAE,KAAM,OAAQ,KAAM,EAAS,GAAG,EAAO,MAAM,IAAuB,CAAmB,CAAC,EACpG,UACA,UAAW,EACb,CACF"}
@@ -0,0 +1,32 @@
1
+ import { QuestionParams } from "../../schemas/questionnaire.cjs";
2
+ import { QuestionnaireResult, ToolTextResult } from "../../types/questionnaire.cjs";
3
+ import { MinorModeCatalogClient } from "@agimon-ai/doompi-extension-contracts/mode";
4
+ import { NarrationRequester } from "@agimon-ai/doompi-extension-contracts/narration";
5
+ import { ProtocolRuntimeOptions } from "@agimon-ai/doompi-extension-contracts/protocol";
6
+ //#region src/adapters/doom/voiceQuestionHandoff.d.ts
7
+ declare const DOOM_VOICE_SOURCE = "@agimon-ai/doompi-voice";
8
+ declare const DOOM_VOICE_AUTO_MODE_ID = "voice-auto";
9
+ declare const VOICE_WAIT_MESSAGE = "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.";
10
+ declare function formatVoiceQuestionPrompt(params: QuestionParams): string;
11
+ declare class VoiceQuestionHandoff {
12
+ private readonly modes;
13
+ private readonly narration;
14
+ private readonly buildNarration;
15
+ constructor(modes: Pick<MinorModeCatalogClient, 'list'>, narration: NarrationRequester, buildNarration: (params: QuestionParams) => string);
16
+ handoff(params: QuestionParams): QuestionnaireResult | undefined;
17
+ }
18
+ interface VoiceQuestionHandoffHandle {
19
+ handoff(params: QuestionParams): QuestionnaireResult | undefined;
20
+ dispose(): void;
21
+ }
22
+ /**
23
+ * Bind one session-scoped autonomous-voice handoff.
24
+ *
25
+ * The returned handle owns the external catalog subscription and must be
26
+ * disposed when its session is replaced or shut down.
27
+ */
28
+ declare function createVoiceQuestionHandoff(options: ProtocolRuntimeOptions): VoiceQuestionHandoffHandle;
29
+ declare function buildVoiceToolResult(details: QuestionnaireResult): ToolTextResult;
30
+ //#endregion
31
+ export { DOOM_VOICE_AUTO_MODE_ID, DOOM_VOICE_SOURCE, VOICE_WAIT_MESSAGE, VoiceQuestionHandoff, VoiceQuestionHandoffHandle, buildVoiceToolResult, createVoiceQuestionHandoff, formatVoiceQuestionPrompt };
32
+ //# sourceMappingURL=voiceQuestionHandoff.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voiceQuestionHandoff.d.cts","names":[],"sources":["../../../src/adapters/doom/voiceQuestionHandoff.ts"],"mappings":";;;;;;cAWa;cACA;cACA;iBAWG,0BAA0B,QAAQ;cAWrC;mBAEQ;mBACA;mBACA;EAFA,YAAA,OAAO,KAAK,iCACZ,WAAW,oBACX,iBAAiB,QAAQ;EAG5C,QAAQ,QAAQ,iBAAiB;;UAalB;EACf,QAAQ,QAAQ,iBAAiB;EACjC;;;;;;;;iBASc,2BAA2B,SAAS,yBAAyB;iBAmB7D,qBAAqB,SAAS,sBAAsB"}
@@ -0,0 +1,32 @@
1
+ import { QuestionParams } from "../../schemas/questionnaire.mjs";
2
+ import { QuestionnaireResult, ToolTextResult } from "../../types/questionnaire.mjs";
3
+ import { MinorModeCatalogClient } from "@agimon-ai/doompi-extension-contracts/mode";
4
+ import { NarrationRequester } from "@agimon-ai/doompi-extension-contracts/narration";
5
+ import { ProtocolRuntimeOptions } from "@agimon-ai/doompi-extension-contracts/protocol";
6
+ //#region src/adapters/doom/voiceQuestionHandoff.d.ts
7
+ declare const DOOM_VOICE_SOURCE = "@agimon-ai/doompi-voice";
8
+ declare const DOOM_VOICE_AUTO_MODE_ID = "voice-auto";
9
+ declare const VOICE_WAIT_MESSAGE = "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.";
10
+ declare function formatVoiceQuestionPrompt(params: QuestionParams): string;
11
+ declare class VoiceQuestionHandoff {
12
+ private readonly modes;
13
+ private readonly narration;
14
+ private readonly buildNarration;
15
+ constructor(modes: Pick<MinorModeCatalogClient, 'list'>, narration: NarrationRequester, buildNarration: (params: QuestionParams) => string);
16
+ handoff(params: QuestionParams): QuestionnaireResult | undefined;
17
+ }
18
+ interface VoiceQuestionHandoffHandle {
19
+ handoff(params: QuestionParams): QuestionnaireResult | undefined;
20
+ dispose(): void;
21
+ }
22
+ /**
23
+ * Bind one session-scoped autonomous-voice handoff.
24
+ *
25
+ * The returned handle owns the external catalog subscription and must be
26
+ * disposed when its session is replaced or shut down.
27
+ */
28
+ declare function createVoiceQuestionHandoff(options: ProtocolRuntimeOptions): VoiceQuestionHandoffHandle;
29
+ declare function buildVoiceToolResult(details: QuestionnaireResult): ToolTextResult;
30
+ //#endregion
31
+ export { DOOM_VOICE_AUTO_MODE_ID, DOOM_VOICE_SOURCE, VOICE_WAIT_MESSAGE, VoiceQuestionHandoff, VoiceQuestionHandoffHandle, buildVoiceToolResult, createVoiceQuestionHandoff, formatVoiceQuestionPrompt };
32
+ //# sourceMappingURL=voiceQuestionHandoff.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voiceQuestionHandoff.d.mts","names":[],"sources":["../../../src/adapters/doom/voiceQuestionHandoff.ts"],"mappings":";;;;;;cAWa;cACA;cACA;iBAWG,0BAA0B,QAAQ;cAWrC;mBAEQ;mBACA;mBACA;EAFA,YAAA,OAAO,KAAK,iCACZ,WAAW,oBACX,iBAAiB,QAAQ;EAG5C,QAAQ,QAAQ,iBAAiB;;UAalB;EACf,QAAQ,QAAQ,iBAAiB;EACjC;;;;;;;;iBASc,2BAA2B,SAAS,yBAAyB;iBAmB7D,qBAAqB,SAAS,sBAAsB"}
@@ -1,5 +1,5 @@
1
- const e=`@agimon-ai/doompi-voice`,t=`voice-auto`,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.`;function r(e){return e.source===`@agimon-ai/doompi-voice`&&e.id===`voice-auto`}function i(e){let t=e.questions.length>1;return e.questions.map((e,n)=>[`${t?`${n+1}. `:``}${e.question}${e.multiSelect?` (Select all that apply.)`:``}`,...e.options.map((e,t)=>` ${t+1}. ${e.label}`),` Type something.`].join(`
1
+ import{buildVoiceQuestionNarration as e}from"../../services/voiceQuestionNarration.mjs";import{createMinorModeCatalogClient as t}from"@agimon-ai/doompi-extension-contracts/mode";import{createNarrationRequester as n}from"@agimon-ai/doompi-extension-contracts/narration";import{createProtocolRuntime as r}from"@agimon-ai/doompi-extension-contracts/protocol";const i=`@agimon-ai/doompi-voice`,a=`voice-auto`,o=`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.`;function s(e){return e.descriptor.source===`@agimon-ai/doompi-voice`&&e.descriptor.id===`voice-auto`&&e.state.activation===`active`}function c(e){let t=e.questions.length>1;return e.questions.map((e,n)=>[`${t?`${n+1}. `:``}${e.question}${e.multiSelect?` (Select all that apply.)`:``}`,...e.options.map((e,t)=>` ${t+1}. ${e.label}`),` Type something.`].join(`
2
2
  `)).join(`
3
3
 
4
- `)}var a=class{modes;narration;buildNarration;constructor(e,t,n){this.modes=e,this.narration=t,this.buildNarration=n}handoff(e){if(this.modes.getStatuses().some(r))return this.narration.narrate(this.buildNarration(e)),{answers:[],cancelled:!1,delivery:`voice`,awaitingResponse:!0,voicePrompt:i(e)}}};function o(e){return{content:[{type:`text`,text:n}],details:e,terminate:!0}}export{t as DOOM_VOICE_AUTO_MODE_ID,e as DOOM_VOICE_SOURCE,n as VOICE_WAIT_MESSAGE,a as VoiceQuestionHandoff,o as buildVoiceToolResult,i as formatVoiceQuestionPrompt};
4
+ `)}var l=class{modes;narration;buildNarration;constructor(e,t,n){this.modes=e,this.narration=t,this.buildNarration=n}handoff(e){if(this.modes.list().some(s))return this.narration.narrate(this.buildNarration(e)),{answers:[],cancelled:!1,delivery:`voice`,awaitingResponse:!0,voicePrompt:c(e)}}};function u(i){let a=t(),o=a.bind(r(i)),s=new l(a,n(i),e),c=!1;return{handoff(e){return c?void 0:s.handoff(e)},dispose(){c||(c=!0,o(),a.dispose())}}}function d(e){let t=e.voicePrompt?.trim();return{content:[{type:`text`,text:t?`${t}\n\n${o}`:o}],details:e,terminate:!0}}export{a as DOOM_VOICE_AUTO_MODE_ID,i as DOOM_VOICE_SOURCE,o as VOICE_WAIT_MESSAGE,l as VoiceQuestionHandoff,d as buildVoiceToolResult,u as createVoiceQuestionHandoff,c as formatVoiceQuestionPrompt};
5
5
  //# sourceMappingURL=voiceQuestionHandoff.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"voiceQuestionHandoff.mjs","names":[],"sources":["../../../src/adapters/doom/voiceQuestionHandoff.ts"],"sourcesContent":["import type { DoomModeStatusRegistry, DoomModeStatus } from '@agimon-ai/doompi-extension-contracts/mode';\nimport type { NarrationRequester } from '@agimon-ai/doompi-extension-contracts/narration';\nimport type { QuestionParams } from '../../schemas/questionnaire.js';\nimport type { QuestionnaireResult, ToolTextResult } from '../../types/questionnaire.js';\n\nexport const DOOM_VOICE_SOURCE = '@agimon-ai/doompi-voice';\nexport const DOOM_VOICE_AUTO_MODE_ID = 'voice-auto';\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\nfunction isAutonomousVoice(status: DoomModeStatus): boolean {\n return status.source === DOOM_VOICE_SOURCE && status.id === DOOM_VOICE_AUTO_MODE_ID;\n}\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<DoomModeStatusRegistry, 'getStatuses'>,\n private readonly narration: NarrationRequester,\n private readonly buildNarration: (params: QuestionParams) => string,\n ) {}\n\n handoff(params: QuestionParams): QuestionnaireResult | undefined {\n if (!this.modes.getStatuses().some(isAutonomousVoice)) return undefined;\n this.narration.narrate(this.buildNarration(params));\n return {\n answers: [],\n cancelled: false,\n delivery: 'voice',\n awaitingResponse: true,\n voicePrompt: formatVoiceQuestionPrompt(params),\n };\n }\n}\n\nexport function buildVoiceToolResult(details: QuestionnaireResult): ToolTextResult {\n return {\n content: [{ type: 'text', text: VOICE_WAIT_MESSAGE }],\n details,\n terminate: true,\n };\n}\n"],"mappings":"AAKA,MAAa,EAAoB,0BACpB,EAA0B,aAC1B,EACX,iJAEF,SAAS,EAAkB,EAAiC,CAC1D,OAAO,EAAO,SAAA,2BAAgC,EAAO,KAAA,YACvD,CAEA,SAAgB,EAA0B,EAAgC,CACxE,IAAM,EAAkB,EAAO,UAAU,OAAS,EAClD,OAAO,EAAO,UACX,KAAK,EAAU,IAGP,CAAC,GAFW,EAAkB,GAAG,EAAgB,EAAE,IAAM,KAAK,EAAS,WAAW,EAAS,YAAc,4BAA8B,KAE7H,GADD,EAAS,QAAQ,KAAK,EAAQ,IAAgB,KAAK,EAAc,EAAE,IAAI,EAAO,OACpE,EAAG,mBAAmB,CAAC,CAAC,KAAK;CAAI,CAC5D,CAAC,CACD,KAAK;;CAAM,CAChB,CAEA,IAAa,EAAb,KAAkC,CAEb,MACA,UACA,eAHnB,YACE,EACA,EACA,EACA,CAHiB,KAAA,MAAA,EACA,KAAA,UAAA,EACA,KAAA,eAAA,CAChB,CAEH,QAAQ,EAAyD,CAC1D,QAAK,MAAM,YAAY,CAAC,CAAC,KAAK,CAAiB,EAEpD,OADA,KAAK,UAAU,QAAQ,KAAK,eAAe,CAAM,CAAC,EAC3C,CACL,QAAS,CAAC,EACV,UAAW,GACX,SAAU,QACV,iBAAkB,GAClB,YAAa,EAA0B,CAAM,CAC/C,CACF,CACF,EAEA,SAAgB,EAAqB,EAA8C,CACjF,MAAO,CACL,QAAS,CAAC,CAAE,KAAM,OAAQ,KAAM,CAAmB,CAAC,EACpD,UACA,UAAW,EACb,CACF"}
1
+ {"version":3,"file":"voiceQuestionHandoff.mjs","names":[],"sources":["../../../src/adapters/doom/voiceQuestionHandoff.ts"],"sourcesContent":["import {\n createMinorModeCatalogClient,\n type MinorModeCatalogClient,\n type MinorModeRecord,\n} from '@agimon-ai/doompi-extension-contracts/mode';\nimport { createNarrationRequester, type NarrationRequester } from '@agimon-ai/doompi-extension-contracts/narration';\nimport { createProtocolRuntime, type ProtocolRuntimeOptions } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport type { QuestionParams } from '../../schemas/questionnaire.js';\nimport { buildVoiceQuestionNarration } from '../../services/voiceQuestionNarration.js';\nimport type { QuestionnaireResult, ToolTextResult } from '../../types/questionnaire.js';\n\nexport const DOOM_VOICE_SOURCE = '@agimon-ai/doompi-voice';\nexport const DOOM_VOICE_AUTO_MODE_ID = 'voice-auto';\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\nfunction isAutonomousVoice(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 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<MinorModeCatalogClient, 'list'>,\n private readonly narration: NarrationRequester,\n private readonly buildNarration: (params: QuestionParams) => string,\n ) {}\n\n handoff(params: QuestionParams): QuestionnaireResult | undefined {\n if (!this.modes.list().some(isAutonomousVoice)) return undefined;\n this.narration.narrate(this.buildNarration(params));\n return {\n answers: [],\n cancelled: false,\n delivery: 'voice',\n awaitingResponse: true,\n voicePrompt: formatVoiceQuestionPrompt(params),\n };\n }\n}\n\nexport interface VoiceQuestionHandoffHandle {\n handoff(params: QuestionParams): QuestionnaireResult | undefined;\n dispose(): void;\n}\n\n/**\n * Bind one session-scoped autonomous-voice handoff.\n *\n * The returned handle owns the external catalog subscription and must be\n * disposed when its session is replaced or shut down.\n */\nexport function createVoiceQuestionHandoff(options: ProtocolRuntimeOptions): VoiceQuestionHandoffHandle {\n const modes = createMinorModeCatalogClient();\n const disposeBinding = modes.bind(createProtocolRuntime(options));\n const handoff = new VoiceQuestionHandoff(modes, createNarrationRequester(options), buildVoiceQuestionNarration);\n let disposed = false;\n\n return {\n handoff(params) {\n return disposed ? undefined : handoff.handoff(params);\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n disposeBinding();\n modes.dispose();\n },\n };\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"],"mappings":"oWAWA,MAAa,EAAoB,0BACpB,EAA0B,aAC1B,EACX,iJAEF,SAAS,EAAkB,EAAkC,CAC3D,OACE,EAAO,WAAW,SAAA,2BAClB,EAAO,WAAW,KAAA,cAClB,EAAO,MAAM,aAAe,QAEhC,CAEA,SAAgB,EAA0B,EAAgC,CACxE,IAAM,EAAkB,EAAO,UAAU,OAAS,EAClD,OAAO,EAAO,UACX,KAAK,EAAU,IAGP,CAAC,GAFW,EAAkB,GAAG,EAAgB,EAAE,IAAM,KAAK,EAAS,WAAW,EAAS,YAAc,4BAA8B,KAE7H,GADD,EAAS,QAAQ,KAAK,EAAQ,IAAgB,KAAK,EAAc,EAAE,IAAI,EAAO,OACpE,EAAG,mBAAmB,CAAC,CAAC,KAAK;CAAI,CAC5D,CAAC,CACD,KAAK;;CAAM,CAChB,CAEA,IAAa,EAAb,KAAkC,CAEb,MACA,UACA,eAHnB,YACE,EACA,EACA,EACA,CAHiB,KAAA,MAAA,EACA,KAAA,UAAA,EACA,KAAA,eAAA,CAChB,CAEH,QAAQ,EAAyD,CAC1D,QAAK,MAAM,KAAK,CAAC,CAAC,KAAK,CAAiB,EAE7C,OADA,KAAK,UAAU,QAAQ,KAAK,eAAe,CAAM,CAAC,EAC3C,CACL,QAAS,CAAC,EACV,UAAW,GACX,SAAU,QACV,iBAAkB,GAClB,YAAa,EAA0B,CAAM,CAC/C,CACF,CACF,EAaA,SAAgB,EAA2B,EAA6D,CACtG,IAAM,EAAQ,EAA6B,EACrC,EAAiB,EAAM,KAAK,EAAsB,CAAO,CAAC,EAC1D,EAAU,IAAI,EAAqB,EAAO,EAAyB,CAAO,EAAG,CAA2B,EAC1G,EAAW,GAEf,MAAO,CACL,QAAQ,EAAQ,CACd,OAAO,EAAW,IAAA,GAAY,EAAQ,QAAQ,CAAM,CACtD,EACA,SAAU,CACJ,IACJ,EAAW,GACX,EAAe,EACf,EAAM,QAAQ,EAChB,CACF,CACF,CAEA,SAAgB,EAAqB,EAA8C,CACjF,IAAM,EAAS,EAAQ,aAAa,KAAK,EACzC,MAAO,CACL,QAAS,CAAC,CAAE,KAAM,OAAQ,KAAM,EAAS,GAAG,EAAO,MAAM,IAAuB,CAAmB,CAAC,EACpG,UACA,UAAW,EACb,CACF"}
@@ -1,2 +1,2 @@
1
- Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../adapters/doom/voiceQuestionHandoff.cjs"),t=require("../adapters/pi/askUserQuestionAdapter.cjs"),n=require("../adapters/pi/reconcileAdapter.cjs"),r=require("../services/questionnaireCoordinator.cjs"),i=require("../services/voiceQuestionNarration.cjs");let a=require("@agimon-ai/doompi-extension-contracts/mode"),o=require("@agimon-ai/doompi-extension-contracts/narration"),s=require("@agimon-ai/doompi-extension-contracts/protocol");const c=`@agimon-ai/doompi-user-feedback`,l=Symbol.for(`${c}/installed-hosts`);function u(e){let t=globalThis,n=t[l]??new WeakSet;return t[l]=n,!n.has(e)&&(n.add(e),!0)}function d(l){if(!u(l))return;let d=new r.QuestionnaireCoordinator,f,p,m,h=()=>{p?.(),p=void 0,f?.reset(),f=void 0,m=void 0};t.registerAskUserQuestionTool(l,{enqueue:(e,t)=>d.enqueue(e,t),runTui:async(...e)=>{let{runTuiQuestionnaire:t}=await Promise.resolve().then(()=>require("../tui/runQuestionnaire.cjs"));return t(...e)},tryVoice:e=>m?.handoff(e)}),n.registerAskUserQuestionReconciler(l),l.on(`session_start`,(t,n)=>{d.shutdown(),d=new r.QuestionnaireCoordinator,h();let u=n.sessionManager.getSessionId(),g=new a.DoomModeStatusRegistry,_=(0,s.createProtocolRuntime)({bus:l.events,source:c,sessionId:u});f=g,p=g.bind(_),m=new e.VoiceQuestionHandoff(g,(0,o.createNarrationRequester)({bus:l.events,source:c,sessionId:u}),i.buildVoiceQuestionNarration)}),l.on(`session_shutdown`,()=>{d.shutdown(),h()})}exports.default=d,exports.registerUserFeedbackExtension=d;
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../adapters/doom/voiceQuestionHandoff.cjs"),t=require("../adapters/pi/askUserQuestionAdapter.cjs"),n=require("../adapters/pi/reconcileAdapter.cjs"),r=require("../services/questionnaireCoordinator.cjs"),i=`@agimon-ai/doompi-user-feedback`,a=Symbol.for(`${i}/installed-hosts`);function o(e){let t=globalThis,n=t[a]??new WeakSet;return t[a]=n,!n.has(e)&&(n.add(e),!0)}function s(a){if(!o(a))return;let s=new r.QuestionnaireCoordinator,c,l=()=>{c?.dispose(),c=void 0};t.registerAskUserQuestionTool(a,{enqueue:(e,t)=>s.enqueue(e,t),runTui:async(...e)=>{let{runTuiQuestionnaire:t}=await Promise.resolve().then(()=>require("../tui/runQuestionnaire.cjs"));return t(...e)},tryVoice:e=>c?.handoff(e)}),n.registerAskUserQuestionReconciler(a),a.on(`session_start`,(t,n)=>{s.shutdown(),s=new r.QuestionnaireCoordinator,l(),c=e.createVoiceQuestionHandoff({bus:a.events,source:i,sessionId:n.sessionManager.getSessionId()})}),a.on(`session_shutdown`,()=>{s.shutdown(),l()})}exports.default=s,exports.registerUserFeedbackExtension=s;
2
2
  //# sourceMappingURL=pi.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"pi.cjs","names":["QuestionnaireCoordinator","DoomModeStatusRegistry","createProtocolRuntime","VoiceQuestionHandoff","createNarrationRequester","buildVoiceQuestionNarration"],"sources":["../../src/extensions/pi.ts"],"sourcesContent":["import { DoomModeStatusRegistry } from '@agimon-ai/doompi-extension-contracts/mode';\nimport { createNarrationRequester } from '@agimon-ai/doompi-extension-contracts/narration';\nimport { createProtocolRuntime } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { VoiceQuestionHandoff } from '../adapters/doom/voiceQuestionHandoff.js';\nimport { registerAskUserQuestionTool } from '../adapters/pi/askUserQuestionAdapter.js';\nimport { registerAskUserQuestionReconciler } from '../adapters/pi/reconcileAdapter.js';\nimport { QuestionnaireCoordinator } from '../services/questionnaireCoordinator.js';\nimport { buildVoiceQuestionNarration } from '../services/voiceQuestionNarration.js';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-user-feedback';\nconst INSTALLATIONS_KEY = Symbol.for(`${PACKAGE_SOURCE}/installed-hosts`);\n\ntype InstallationRegistry = typeof globalThis & {\n [INSTALLATIONS_KEY]?: WeakSet<object>;\n};\n\nfunction claimHostInstallation(pi: ExtensionAPI): boolean {\n const registry = globalThis as InstallationRegistry;\n const installedHosts = registry[INSTALLATIONS_KEY] ?? new WeakSet<object>();\n registry[INSTALLATIONS_KEY] = installedHosts;\n if (installedHosts.has(pi)) return false;\n installedHosts.add(pi);\n return true;\n}\n\nexport function registerUserFeedbackExtension(pi: ExtensionAPI): void {\n if (!claimHostInstallation(pi)) return;\n\n let coordinator = new QuestionnaireCoordinator();\n let modes: DoomModeStatusRegistry | undefined;\n let disposeModes: (() => void) | undefined;\n let voiceHandoff: VoiceQuestionHandoff | undefined;\n const resetVoiceHandoff = (): void => {\n disposeModes?.();\n disposeModes = undefined;\n modes?.reset();\n modes = undefined;\n voiceHandoff = undefined;\n };\n\n registerAskUserQuestionTool(pi, {\n enqueue: (runner, signal) => coordinator.enqueue(runner, signal),\n runTui: async (...args) => {\n const { runTuiQuestionnaire } = await import('../tui/runQuestionnaire.js');\n return runTuiQuestionnaire(...args);\n },\n tryVoice: (params) => voiceHandoff?.handoff(params),\n });\n registerAskUserQuestionReconciler(pi);\n\n pi.on('session_start', (_event, context) => {\n coordinator.shutdown();\n coordinator = new QuestionnaireCoordinator();\n resetVoiceHandoff();\n\n const sessionId = context.sessionManager.getSessionId();\n const registry = new DoomModeStatusRegistry();\n const runtime = createProtocolRuntime({\n bus: pi.events,\n source: PACKAGE_SOURCE,\n sessionId,\n });\n modes = registry;\n disposeModes = registry.bind(runtime);\n voiceHandoff = new VoiceQuestionHandoff(\n registry,\n createNarrationRequester({ bus: pi.events, source: PACKAGE_SOURCE, sessionId }),\n buildVoiceQuestionNarration,\n );\n });\n pi.on('session_shutdown', () => {\n coordinator.shutdown();\n resetVoiceHandoff();\n });\n}\n\nexport { registerUserFeedbackExtension as default };\n"],"mappings":"miBAUA,MAAM,EAAiB,kCACjB,EAAoB,OAAO,IAAI,GAAG,EAAe,iBAAiB,EAMxE,SAAS,EAAsB,EAA2B,CACxD,IAAM,EAAW,WACX,EAAiB,EAAS,IAAsB,IAAI,QAI1D,MAHA,GAAS,GAAqB,EAC9B,CAAI,EAAe,IAAI,CAAE,IACzB,EAAe,IAAI,CAAE,EACd,GACT,CAEA,SAAgB,EAA8B,EAAwB,CACpE,GAAI,CAAC,EAAsB,CAAE,EAAG,OAEhC,IAAI,EAAc,IAAIA,EAAAA,yBAClB,EACA,EACA,EACE,MAAgC,CACpC,IAAe,EACf,EAAe,IAAA,GACf,GAAO,MAAM,EACb,EAAQ,IAAA,GACR,EAAe,IAAA,EACjB,EAEA,EAAA,4BAA4B,EAAI,CAC9B,SAAU,EAAQ,IAAW,EAAY,QAAQ,EAAQ,CAAM,EAC/D,OAAQ,MAAO,GAAG,IAAS,CACzB,GAAM,CAAE,uBAAwB,MAAA,QAAA,QAAA,CAAA,CAAA,SAAA,QAAM,6BAAA,CAAA,EACtC,OAAO,EAAoB,GAAG,CAAI,CACpC,EACA,SAAW,GAAW,GAAc,QAAQ,CAAM,CACpD,CAAC,EACD,EAAA,kCAAkC,CAAE,EAEpC,EAAG,GAAG,iBAAkB,EAAQ,IAAY,CAC1C,EAAY,SAAS,EACrB,EAAc,IAAIA,EAAAA,yBAClB,EAAkB,EAElB,IAAM,EAAY,EAAQ,eAAe,aAAa,EAChD,EAAW,IAAIC,EAAAA,uBACf,GAAA,EAAUC,EAAAA,sBAAAA,CAAsB,CACpC,IAAK,EAAG,OACR,OAAQ,EACR,WACF,CAAC,EACD,EAAQ,EACR,EAAe,EAAS,KAAK,CAAO,EACpC,EAAe,IAAIC,EAAAA,qBACjB,GAAA,EACAC,EAAAA,yBAAAA,CAAyB,CAAE,IAAK,EAAG,OAAQ,OAAQ,EAAgB,WAAU,CAAC,EAC9EC,EAAAA,2BACF,CACF,CAAC,EACD,EAAG,GAAG,uBAA0B,CAC9B,EAAY,SAAS,EACrB,EAAkB,CACpB,CAAC,CACH"}
1
+ {"version":3,"file":"pi.cjs","names":["QuestionnaireCoordinator","createVoiceQuestionHandoff"],"sources":["../../src/extensions/pi.ts"],"sourcesContent":["import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { createVoiceQuestionHandoff, type VoiceQuestionHandoffHandle } from '../adapters/doom/voiceQuestionHandoff.js';\nimport { registerAskUserQuestionTool } from '../adapters/pi/askUserQuestionAdapter.js';\nimport { registerAskUserQuestionReconciler } from '../adapters/pi/reconcileAdapter.js';\nimport { QuestionnaireCoordinator } from '../services/questionnaireCoordinator.js';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-user-feedback';\nconst INSTALLATIONS_KEY = Symbol.for(`${PACKAGE_SOURCE}/installed-hosts`);\n\ntype InstallationRegistry = typeof globalThis & {\n [INSTALLATIONS_KEY]?: WeakSet<object>;\n};\n\nfunction claimHostInstallation(pi: ExtensionAPI): boolean {\n const registry = globalThis as InstallationRegistry;\n const installedHosts = registry[INSTALLATIONS_KEY] ?? new WeakSet<object>();\n registry[INSTALLATIONS_KEY] = installedHosts;\n if (installedHosts.has(pi)) return false;\n installedHosts.add(pi);\n return true;\n}\n\nexport function registerUserFeedbackExtension(pi: ExtensionAPI): void {\n if (!claimHostInstallation(pi)) return;\n\n let coordinator = new QuestionnaireCoordinator();\n let voiceHandoff: VoiceQuestionHandoffHandle | undefined;\n const resetVoiceHandoff = (): void => {\n voiceHandoff?.dispose();\n voiceHandoff = undefined;\n };\n\n registerAskUserQuestionTool(pi, {\n enqueue: (runner, signal) => coordinator.enqueue(runner, signal),\n runTui: async (...args) => {\n const { runTuiQuestionnaire } = await import('../tui/runQuestionnaire.js');\n return runTuiQuestionnaire(...args);\n },\n tryVoice: (params) => voiceHandoff?.handoff(params),\n });\n registerAskUserQuestionReconciler(pi);\n\n pi.on('session_start', (_event, context) => {\n coordinator.shutdown();\n coordinator = new QuestionnaireCoordinator();\n resetVoiceHandoff();\n\n voiceHandoff = createVoiceQuestionHandoff({\n bus: pi.events,\n source: PACKAGE_SOURCE,\n sessionId: context.sessionManager.getSessionId(),\n });\n });\n pi.on('session_shutdown', () => {\n coordinator.shutdown();\n resetVoiceHandoff();\n });\n}\n\nexport { registerUserFeedbackExtension as default };\n"],"mappings":"0TAMM,EAAiB,kCACjB,EAAoB,OAAO,IAAI,GAAG,EAAe,iBAAiB,EAMxE,SAAS,EAAsB,EAA2B,CACxD,IAAM,EAAW,WACX,EAAiB,EAAS,IAAsB,IAAI,QAI1D,MAHA,GAAS,GAAqB,EAC9B,CAAI,EAAe,IAAI,CAAE,IACzB,EAAe,IAAI,CAAE,EACd,GACT,CAEA,SAAgB,EAA8B,EAAwB,CACpE,GAAI,CAAC,EAAsB,CAAE,EAAG,OAEhC,IAAI,EAAc,IAAIA,EAAAA,yBAClB,EACE,MAAgC,CACpC,GAAc,QAAQ,EACtB,EAAe,IAAA,EACjB,EAEA,EAAA,4BAA4B,EAAI,CAC9B,SAAU,EAAQ,IAAW,EAAY,QAAQ,EAAQ,CAAM,EAC/D,OAAQ,MAAO,GAAG,IAAS,CACzB,GAAM,CAAE,uBAAwB,MAAA,QAAA,QAAA,CAAA,CAAA,SAAA,QAAM,6BAAA,CAAA,EACtC,OAAO,EAAoB,GAAG,CAAI,CACpC,EACA,SAAW,GAAW,GAAc,QAAQ,CAAM,CACpD,CAAC,EACD,EAAA,kCAAkC,CAAE,EAEpC,EAAG,GAAG,iBAAkB,EAAQ,IAAY,CAC1C,EAAY,SAAS,EACrB,EAAc,IAAIA,EAAAA,yBAClB,EAAkB,EAElB,EAAeC,EAAAA,2BAA2B,CACxC,IAAK,EAAG,OACR,OAAQ,EACR,UAAW,EAAQ,eAAe,aAAa,CACjD,CAAC,CACH,CAAC,EACD,EAAG,GAAG,uBAA0B,CAC9B,EAAY,SAAS,EACrB,EAAkB,CACpB,CAAC,CACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"pi.d.cts","names":[],"sources":["../../src/extensions/pi.ts"],"mappings":";;iBA0BgB,8BAA8B,IAAI"}
1
+ {"version":3,"file":"pi.d.cts","names":[],"sources":["../../src/extensions/pi.ts"],"mappings":";;iBAsBgB,8BAA8B,IAAI"}
@@ -1 +1 @@
1
- {"version":3,"file":"pi.d.mts","names":[],"sources":["../../src/extensions/pi.ts"],"mappings":";;iBA0BgB,8BAA8B,IAAI"}
1
+ {"version":3,"file":"pi.d.mts","names":[],"sources":["../../src/extensions/pi.ts"],"mappings":";;iBAsBgB,8BAA8B,IAAI"}
@@ -1,2 +1,2 @@
1
- import{VoiceQuestionHandoff as e}from"../adapters/doom/voiceQuestionHandoff.mjs";import{registerAskUserQuestionTool as t}from"../adapters/pi/askUserQuestionAdapter.mjs";import{registerAskUserQuestionReconciler as n}from"../adapters/pi/reconcileAdapter.mjs";import{QuestionnaireCoordinator as r}from"../services/questionnaireCoordinator.mjs";import{buildVoiceQuestionNarration as i}from"../services/voiceQuestionNarration.mjs";import{DoomModeStatusRegistry as a}from"@agimon-ai/doompi-extension-contracts/mode";import{createNarrationRequester as o}from"@agimon-ai/doompi-extension-contracts/narration";import{createProtocolRuntime as s}from"@agimon-ai/doompi-extension-contracts/protocol";const c=`@agimon-ai/doompi-user-feedback`,l=Symbol.for(`${c}/installed-hosts`);function u(e){let t=globalThis,n=t[l]??new WeakSet;return t[l]=n,!n.has(e)&&(n.add(e),!0)}function d(l){if(!u(l))return;let d=new r,f,p,m,h=()=>{p?.(),p=void 0,f?.reset(),f=void 0,m=void 0};t(l,{enqueue:(e,t)=>d.enqueue(e,t),runTui:async(...e)=>{let{runTuiQuestionnaire:t}=await import(`../tui/runQuestionnaire.mjs`);return t(...e)},tryVoice:e=>m?.handoff(e)}),n(l),l.on(`session_start`,(t,n)=>{d.shutdown(),d=new r,h();let u=n.sessionManager.getSessionId(),g=new a,_=s({bus:l.events,source:c,sessionId:u});f=g,p=g.bind(_),m=new e(g,o({bus:l.events,source:c,sessionId:u}),i)}),l.on(`session_shutdown`,()=>{d.shutdown(),h()})}export{d as default,d as registerUserFeedbackExtension};
1
+ import{createVoiceQuestionHandoff as e}from"../adapters/doom/voiceQuestionHandoff.mjs";import{registerAskUserQuestionTool as t}from"../adapters/pi/askUserQuestionAdapter.mjs";import{registerAskUserQuestionReconciler as n}from"../adapters/pi/reconcileAdapter.mjs";import{QuestionnaireCoordinator as r}from"../services/questionnaireCoordinator.mjs";const i=`@agimon-ai/doompi-user-feedback`,a=Symbol.for(`${i}/installed-hosts`);function o(e){let t=globalThis,n=t[a]??new WeakSet;return t[a]=n,!n.has(e)&&(n.add(e),!0)}function s(a){if(!o(a))return;let s=new r,c,l=()=>{c?.dispose(),c=void 0};t(a,{enqueue:(e,t)=>s.enqueue(e,t),runTui:async(...e)=>{let{runTuiQuestionnaire:t}=await import(`../tui/runQuestionnaire.mjs`);return t(...e)},tryVoice:e=>c?.handoff(e)}),n(a),a.on(`session_start`,(t,n)=>{s.shutdown(),s=new r,l(),c=e({bus:a.events,source:i,sessionId:n.sessionManager.getSessionId()})}),a.on(`session_shutdown`,()=>{s.shutdown(),l()})}export{s as default,s as registerUserFeedbackExtension};
2
2
  //# sourceMappingURL=pi.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"pi.mjs","names":[],"sources":["../../src/extensions/pi.ts"],"sourcesContent":["import { DoomModeStatusRegistry } from '@agimon-ai/doompi-extension-contracts/mode';\nimport { createNarrationRequester } from '@agimon-ai/doompi-extension-contracts/narration';\nimport { createProtocolRuntime } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { VoiceQuestionHandoff } from '../adapters/doom/voiceQuestionHandoff.js';\nimport { registerAskUserQuestionTool } from '../adapters/pi/askUserQuestionAdapter.js';\nimport { registerAskUserQuestionReconciler } from '../adapters/pi/reconcileAdapter.js';\nimport { QuestionnaireCoordinator } from '../services/questionnaireCoordinator.js';\nimport { buildVoiceQuestionNarration } from '../services/voiceQuestionNarration.js';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-user-feedback';\nconst INSTALLATIONS_KEY = Symbol.for(`${PACKAGE_SOURCE}/installed-hosts`);\n\ntype InstallationRegistry = typeof globalThis & {\n [INSTALLATIONS_KEY]?: WeakSet<object>;\n};\n\nfunction claimHostInstallation(pi: ExtensionAPI): boolean {\n const registry = globalThis as InstallationRegistry;\n const installedHosts = registry[INSTALLATIONS_KEY] ?? new WeakSet<object>();\n registry[INSTALLATIONS_KEY] = installedHosts;\n if (installedHosts.has(pi)) return false;\n installedHosts.add(pi);\n return true;\n}\n\nexport function registerUserFeedbackExtension(pi: ExtensionAPI): void {\n if (!claimHostInstallation(pi)) return;\n\n let coordinator = new QuestionnaireCoordinator();\n let modes: DoomModeStatusRegistry | undefined;\n let disposeModes: (() => void) | undefined;\n let voiceHandoff: VoiceQuestionHandoff | undefined;\n const resetVoiceHandoff = (): void => {\n disposeModes?.();\n disposeModes = undefined;\n modes?.reset();\n modes = undefined;\n voiceHandoff = undefined;\n };\n\n registerAskUserQuestionTool(pi, {\n enqueue: (runner, signal) => coordinator.enqueue(runner, signal),\n runTui: async (...args) => {\n const { runTuiQuestionnaire } = await import('../tui/runQuestionnaire.js');\n return runTuiQuestionnaire(...args);\n },\n tryVoice: (params) => voiceHandoff?.handoff(params),\n });\n registerAskUserQuestionReconciler(pi);\n\n pi.on('session_start', (_event, context) => {\n coordinator.shutdown();\n coordinator = new QuestionnaireCoordinator();\n resetVoiceHandoff();\n\n const sessionId = context.sessionManager.getSessionId();\n const registry = new DoomModeStatusRegistry();\n const runtime = createProtocolRuntime({\n bus: pi.events,\n source: PACKAGE_SOURCE,\n sessionId,\n });\n modes = registry;\n disposeModes = registry.bind(runtime);\n voiceHandoff = new VoiceQuestionHandoff(\n registry,\n createNarrationRequester({ bus: pi.events, source: PACKAGE_SOURCE, sessionId }),\n buildVoiceQuestionNarration,\n );\n });\n pi.on('session_shutdown', () => {\n coordinator.shutdown();\n resetVoiceHandoff();\n });\n}\n\nexport { registerUserFeedbackExtension as default };\n"],"mappings":"grBAUA,MAAM,EAAiB,kCACjB,EAAoB,OAAO,IAAI,GAAG,EAAe,iBAAiB,EAMxE,SAAS,EAAsB,EAA2B,CACxD,IAAM,EAAW,WACX,EAAiB,EAAS,IAAsB,IAAI,QAI1D,MAHA,GAAS,GAAqB,EAC9B,CAAI,EAAe,IAAI,CAAE,IACzB,EAAe,IAAI,CAAE,EACd,GACT,CAEA,SAAgB,EAA8B,EAAwB,CACpE,GAAI,CAAC,EAAsB,CAAE,EAAG,OAEhC,IAAI,EAAc,IAAI,EAClB,EACA,EACA,EACE,MAAgC,CACpC,IAAe,EACf,EAAe,IAAA,GACf,GAAO,MAAM,EACb,EAAQ,IAAA,GACR,EAAe,IAAA,EACjB,EAEA,EAA4B,EAAI,CAC9B,SAAU,EAAQ,IAAW,EAAY,QAAQ,EAAQ,CAAM,EAC/D,OAAQ,MAAO,GAAG,IAAS,CACzB,GAAM,CAAE,uBAAwB,MAAM,OAAO,+BAC7C,OAAO,EAAoB,GAAG,CAAI,CACpC,EACA,SAAW,GAAW,GAAc,QAAQ,CAAM,CACpD,CAAC,EACD,EAAkC,CAAE,EAEpC,EAAG,GAAG,iBAAkB,EAAQ,IAAY,CAC1C,EAAY,SAAS,EACrB,EAAc,IAAI,EAClB,EAAkB,EAElB,IAAM,EAAY,EAAQ,eAAe,aAAa,EAChD,EAAW,IAAI,EACf,EAAU,EAAsB,CACpC,IAAK,EAAG,OACR,OAAQ,EACR,WACF,CAAC,EACD,EAAQ,EACR,EAAe,EAAS,KAAK,CAAO,EACpC,EAAe,IAAI,EACjB,EACA,EAAyB,CAAE,IAAK,EAAG,OAAQ,OAAQ,EAAgB,WAAU,CAAC,EAC9E,CACF,CACF,CAAC,EACD,EAAG,GAAG,uBAA0B,CAC9B,EAAY,SAAS,EACrB,EAAkB,CACpB,CAAC,CACH"}
1
+ {"version":3,"file":"pi.mjs","names":[],"sources":["../../src/extensions/pi.ts"],"sourcesContent":["import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { createVoiceQuestionHandoff, type VoiceQuestionHandoffHandle } from '../adapters/doom/voiceQuestionHandoff.js';\nimport { registerAskUserQuestionTool } from '../adapters/pi/askUserQuestionAdapter.js';\nimport { registerAskUserQuestionReconciler } from '../adapters/pi/reconcileAdapter.js';\nimport { QuestionnaireCoordinator } from '../services/questionnaireCoordinator.js';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-user-feedback';\nconst INSTALLATIONS_KEY = Symbol.for(`${PACKAGE_SOURCE}/installed-hosts`);\n\ntype InstallationRegistry = typeof globalThis & {\n [INSTALLATIONS_KEY]?: WeakSet<object>;\n};\n\nfunction claimHostInstallation(pi: ExtensionAPI): boolean {\n const registry = globalThis as InstallationRegistry;\n const installedHosts = registry[INSTALLATIONS_KEY] ?? new WeakSet<object>();\n registry[INSTALLATIONS_KEY] = installedHosts;\n if (installedHosts.has(pi)) return false;\n installedHosts.add(pi);\n return true;\n}\n\nexport function registerUserFeedbackExtension(pi: ExtensionAPI): void {\n if (!claimHostInstallation(pi)) return;\n\n let coordinator = new QuestionnaireCoordinator();\n let voiceHandoff: VoiceQuestionHandoffHandle | undefined;\n const resetVoiceHandoff = (): void => {\n voiceHandoff?.dispose();\n voiceHandoff = undefined;\n };\n\n registerAskUserQuestionTool(pi, {\n enqueue: (runner, signal) => coordinator.enqueue(runner, signal),\n runTui: async (...args) => {\n const { runTuiQuestionnaire } = await import('../tui/runQuestionnaire.js');\n return runTuiQuestionnaire(...args);\n },\n tryVoice: (params) => voiceHandoff?.handoff(params),\n });\n registerAskUserQuestionReconciler(pi);\n\n pi.on('session_start', (_event, context) => {\n coordinator.shutdown();\n coordinator = new QuestionnaireCoordinator();\n resetVoiceHandoff();\n\n voiceHandoff = createVoiceQuestionHandoff({\n bus: pi.events,\n source: PACKAGE_SOURCE,\n sessionId: context.sessionManager.getSessionId(),\n });\n });\n pi.on('session_shutdown', () => {\n coordinator.shutdown();\n resetVoiceHandoff();\n });\n}\n\nexport { registerUserFeedbackExtension as default };\n"],"mappings":"2VAMA,MAAM,EAAiB,kCACjB,EAAoB,OAAO,IAAI,GAAG,EAAe,iBAAiB,EAMxE,SAAS,EAAsB,EAA2B,CACxD,IAAM,EAAW,WACX,EAAiB,EAAS,IAAsB,IAAI,QAI1D,MAHA,GAAS,GAAqB,EAC9B,CAAI,EAAe,IAAI,CAAE,IACzB,EAAe,IAAI,CAAE,EACd,GACT,CAEA,SAAgB,EAA8B,EAAwB,CACpE,GAAI,CAAC,EAAsB,CAAE,EAAG,OAEhC,IAAI,EAAc,IAAI,EAClB,EACE,MAAgC,CACpC,GAAc,QAAQ,EACtB,EAAe,IAAA,EACjB,EAEA,EAA4B,EAAI,CAC9B,SAAU,EAAQ,IAAW,EAAY,QAAQ,EAAQ,CAAM,EAC/D,OAAQ,MAAO,GAAG,IAAS,CACzB,GAAM,CAAE,uBAAwB,MAAM,OAAO,+BAC7C,OAAO,EAAoB,GAAG,CAAI,CACpC,EACA,SAAW,GAAW,GAAc,QAAQ,CAAM,CACpD,CAAC,EACD,EAAkC,CAAE,EAEpC,EAAG,GAAG,iBAAkB,EAAQ,IAAY,CAC1C,EAAY,SAAS,EACrB,EAAc,IAAI,EAClB,EAAkB,EAElB,EAAe,EAA2B,CACxC,IAAK,EAAG,OACR,OAAQ,EACR,UAAW,EAAQ,eAAe,aAAa,CACjD,CAAC,CACH,CAAC,EACD,EAAG,GAAG,uBAA0B,CAC9B,EAAY,SAAS,EACrB,EAAkB,CACpB,CAAC,CACH"}
@@ -0,0 +1,18 @@
1
+ import { Static, Type } from "typebox";
2
+ //#region src/schemas/questionnaire.d.ts
3
+ declare const QuestionParamsSchema: Type.TObject<{
4
+ questions: Type.TArray<Type.TObject<{
5
+ question: Type.TString;
6
+ header: Type.TString;
7
+ options: Type.TArray<Type.TObject<{
8
+ label: Type.TString;
9
+ description: Type.TString;
10
+ preview: Type.TOptional<Type.TString>;
11
+ }>>;
12
+ multiSelect: Type.TOptional<Type.TBoolean>;
13
+ }>>;
14
+ }>;
15
+ type QuestionParams = Static<typeof QuestionParamsSchema>;
16
+ //#endregion
17
+ export { QuestionParams, QuestionParamsSchema };
18
+ //# sourceMappingURL=questionnaire.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"questionnaire.d.cts","names":[],"sources":["../../src/schemas/questionnaire.ts"],"mappings":";;cA6Ca,sBAAoB,KAAA;;;;;;;;;;;;KAarB,iBAAiB,cAAc"}
@@ -0,0 +1,18 @@
1
+ import { Static, Type } from "typebox";
2
+ //#region src/schemas/questionnaire.d.ts
3
+ declare const QuestionParamsSchema: Type.TObject<{
4
+ questions: Type.TArray<Type.TObject<{
5
+ question: Type.TString;
6
+ header: Type.TString;
7
+ options: Type.TArray<Type.TObject<{
8
+ label: Type.TString;
9
+ description: Type.TString;
10
+ preview: Type.TOptional<Type.TString>;
11
+ }>>;
12
+ multiSelect: Type.TOptional<Type.TBoolean>;
13
+ }>>;
14
+ }>;
15
+ type QuestionParams = Static<typeof QuestionParamsSchema>;
16
+ //#endregion
17
+ export { QuestionParams, QuestionParamsSchema };
18
+ //# sourceMappingURL=questionnaire.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"questionnaire.d.mts","names":[],"sources":["../../src/schemas/questionnaire.ts"],"mappings":";;cA6Ca,sBAAoB,KAAA;;;;;;;;;;;;KAarB,iBAAiB,cAAc"}
@@ -0,0 +1,31 @@
1
+ //#region src/types/questionnaire.d.ts
2
+ type AnswerKind = 'option' | 'custom' | 'multi';
3
+ interface QuestionAnswer {
4
+ questionIndex: number;
5
+ question: string;
6
+ kind: AnswerKind;
7
+ answer: string | null;
8
+ selected?: string[];
9
+ notes?: string;
10
+ preview?: string;
11
+ }
12
+ type QuestionnaireError = 'no_ui' | 'no_custom_ui' | 'no_questions' | 'empty_options' | 'too_many_questions' | 'duplicate_question' | 'duplicate_option_label' | 'reserved_label' | 'session_load_failed' | 'stale_module_cache';
13
+ interface QuestionnaireResult {
14
+ answers: QuestionAnswer[];
15
+ cancelled: boolean;
16
+ error?: QuestionnaireError;
17
+ delivery?: 'voice';
18
+ awaitingResponse?: boolean;
19
+ voicePrompt?: string;
20
+ }
21
+ interface ToolTextResult {
22
+ content: Array<{
23
+ type: 'text';
24
+ text: string;
25
+ }>;
26
+ details: QuestionnaireResult;
27
+ terminate?: boolean;
28
+ }
29
+ //#endregion
30
+ export { AnswerKind, QuestionAnswer, QuestionnaireError, QuestionnaireResult, ToolTextResult };
31
+ //# sourceMappingURL=questionnaire.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"questionnaire.d.cts","names":[],"sources":["../../src/types/questionnaire.ts"],"mappings":";KAAY;UAEK;EACf;EACA;EACA,MAAM;EACN;EACA;EACA;EACA;;KAGU;UAgBK;EACf,SAAS;EACT;EACA,QAAQ;EACR;EACA;EACA;;UAGe;EACf,SAAS;IAAQ;IAAc;;EAC/B,SAAS;EACT"}
@@ -0,0 +1,31 @@
1
+ //#region src/types/questionnaire.d.ts
2
+ type AnswerKind = 'option' | 'custom' | 'multi';
3
+ interface QuestionAnswer {
4
+ questionIndex: number;
5
+ question: string;
6
+ kind: AnswerKind;
7
+ answer: string | null;
8
+ selected?: string[];
9
+ notes?: string;
10
+ preview?: string;
11
+ }
12
+ type QuestionnaireError = 'no_ui' | 'no_custom_ui' | 'no_questions' | 'empty_options' | 'too_many_questions' | 'duplicate_question' | 'duplicate_option_label' | 'reserved_label' | 'session_load_failed' | 'stale_module_cache';
13
+ interface QuestionnaireResult {
14
+ answers: QuestionAnswer[];
15
+ cancelled: boolean;
16
+ error?: QuestionnaireError;
17
+ delivery?: 'voice';
18
+ awaitingResponse?: boolean;
19
+ voicePrompt?: string;
20
+ }
21
+ interface ToolTextResult {
22
+ content: Array<{
23
+ type: 'text';
24
+ text: string;
25
+ }>;
26
+ details: QuestionnaireResult;
27
+ terminate?: boolean;
28
+ }
29
+ //#endregion
30
+ export { AnswerKind, QuestionAnswer, QuestionnaireError, QuestionnaireResult, ToolTextResult };
31
+ //# sourceMappingURL=questionnaire.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"questionnaire.d.mts","names":[],"sources":["../../src/types/questionnaire.ts"],"mappings":";KAAY;UAEK;EACf;EACA;EACA,MAAM;EACN;EACA;EACA;EACA;;KAGU;UAgBK;EACf,SAAS;EACT;EACA,QAAQ;EACR;EACA;EACA;;UAGe;EACf,SAAS;IAAQ;IAAc;;EAC/B,SAAS;EACT"}
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./adapters/doom/voiceQuestionHandoff.cjs");exports.DOOM_VOICE_AUTO_MODE_ID=e.DOOM_VOICE_AUTO_MODE_ID,exports.DOOM_VOICE_SOURCE=e.DOOM_VOICE_SOURCE,exports.VOICE_WAIT_MESSAGE=e.VOICE_WAIT_MESSAGE,exports.VoiceQuestionHandoff=e.VoiceQuestionHandoff,exports.buildVoiceToolResult=e.buildVoiceToolResult,exports.createVoiceQuestionHandoff=e.createVoiceQuestionHandoff,exports.formatVoiceQuestionPrompt=e.formatVoiceQuestionPrompt;
@@ -0,0 +1,4 @@
1
+ import { QuestionParams } from "./schemas/questionnaire.cjs";
2
+ import { QuestionnaireResult, ToolTextResult } from "./types/questionnaire.cjs";
3
+ import { DOOM_VOICE_AUTO_MODE_ID, DOOM_VOICE_SOURCE, VOICE_WAIT_MESSAGE, VoiceQuestionHandoff, VoiceQuestionHandoffHandle, buildVoiceToolResult, createVoiceQuestionHandoff, formatVoiceQuestionPrompt } from "./adapters/doom/voiceQuestionHandoff.cjs";
4
+ export { DOOM_VOICE_AUTO_MODE_ID, DOOM_VOICE_SOURCE, type QuestionParams, type QuestionnaireResult, type ToolTextResult, VOICE_WAIT_MESSAGE, VoiceQuestionHandoff, type VoiceQuestionHandoffHandle, buildVoiceToolResult, createVoiceQuestionHandoff, formatVoiceQuestionPrompt };
@@ -0,0 +1,4 @@
1
+ import { QuestionParams } from "./schemas/questionnaire.mjs";
2
+ import { QuestionnaireResult, ToolTextResult } from "./types/questionnaire.mjs";
3
+ import { DOOM_VOICE_AUTO_MODE_ID, DOOM_VOICE_SOURCE, VOICE_WAIT_MESSAGE, VoiceQuestionHandoff, VoiceQuestionHandoffHandle, buildVoiceToolResult, createVoiceQuestionHandoff, formatVoiceQuestionPrompt } from "./adapters/doom/voiceQuestionHandoff.mjs";
4
+ export { DOOM_VOICE_AUTO_MODE_ID, DOOM_VOICE_SOURCE, type QuestionParams, type QuestionnaireResult, type ToolTextResult, VOICE_WAIT_MESSAGE, VoiceQuestionHandoff, type VoiceQuestionHandoffHandle, buildVoiceToolResult, createVoiceQuestionHandoff, formatVoiceQuestionPrompt };
@@ -0,0 +1 @@
1
+ import{DOOM_VOICE_AUTO_MODE_ID as e,DOOM_VOICE_SOURCE as t,VOICE_WAIT_MESSAGE as n,VoiceQuestionHandoff as r,buildVoiceToolResult as i,createVoiceQuestionHandoff as a,formatVoiceQuestionPrompt as o}from"./adapters/doom/voiceQuestionHandoff.mjs";export{e as DOOM_VOICE_AUTO_MODE_ID,t as DOOM_VOICE_SOURCE,n as VOICE_WAIT_MESSAGE,r as VoiceQuestionHandoff,i as buildVoiceToolResult,a as createVoiceQuestionHandoff,o as formatVoiceQuestionPrompt};
package/package.json CHANGED
@@ -1,7 +1,14 @@
1
1
  {
2
2
  "name": "@agimon-ai/doompi-user-feedback",
3
- "version": "0.0.1-alpha.1",
3
+ "version": "0.0.1-alpha.11",
4
4
  "description": "Structured user feedback for DoomPi agents",
5
+ "keywords": [
6
+ "ai",
7
+ "coding-agent",
8
+ "developer-tools",
9
+ "doompi",
10
+ "pi-package"
11
+ ],
5
12
  "homepage": "https://agimon.ai",
6
13
  "license": "MIT",
7
14
  "author": "Vuong Ngo",
@@ -26,6 +33,11 @@
26
33
  "import": "./dist/events.mjs",
27
34
  "require": "./dist/events.cjs"
28
35
  },
36
+ "./voice-question-handoff": {
37
+ "types": "./dist/voiceQuestionHandoff.d.mts",
38
+ "import": "./dist/voiceQuestionHandoff.mjs",
39
+ "require": "./dist/voiceQuestionHandoff.cjs"
40
+ },
29
41
  "./extensions/pi": {
30
42
  "types": "./dist/extensions/pi.d.mts",
31
43
  "import": "./dist/extensions/pi.mjs",
@@ -38,12 +50,12 @@
38
50
  },
39
51
  "dependencies": {
40
52
  "typebox": "1.1.38",
41
- "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.12",
42
- "@agimon-ai/doompi-ui": "0.0.1-alpha.12"
53
+ "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.22",
54
+ "@agimon-ai/doompi-ui": "0.0.1-alpha.22"
43
55
  },
44
56
  "devDependencies": {
45
- "@earendil-works/pi-coding-agent": "0.84.1",
46
- "@earendil-works/pi-tui": "0.84.1",
57
+ "@earendil-works/pi-coding-agent": "0.84.2",
58
+ "@earendil-works/pi-tui": "0.84.2",
47
59
  "@types/node": "26.1.1",
48
60
  "@vitest/coverage-v8": "4.1.10",
49
61
  "tsdown": "0.22.14",
@@ -51,8 +63,8 @@
51
63
  "vitest": "4.1.10"
52
64
  },
53
65
  "peerDependencies": {
54
- "@earendil-works/pi-coding-agent": "0.84.1",
55
- "@earendil-works/pi-tui": "0.84.1"
66
+ "@earendil-works/pi-coding-agent": "0.84.2",
67
+ "@earendil-works/pi-tui": "0.84.2"
56
68
  },
57
69
  "peerDependenciesMeta": {
58
70
  "@earendil-works/pi-coding-agent": {