@agimon-ai/doompi-user-feedback 0.0.1-alpha.6 → 0.0.1-alpha.60
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 +96 -35
- package/dist/api-contracts.cjs +1 -0
- package/dist/api-contracts.d.cts +2 -0
- package/dist/api-contracts.d.mts +2 -0
- package/dist/api-contracts.mjs +1 -0
- package/dist/constants/package.cjs +2 -0
- package/dist/constants/package.cjs.map +1 -0
- package/dist/constants/package.mjs +2 -0
- package/dist/constants/package.mjs.map +1 -0
- package/dist/constants/questionnaire.cjs +2 -0
- package/dist/constants/questionnaire.cjs.map +1 -0
- package/dist/constants/questionnaire.mjs +2 -0
- package/dist/constants/questionnaire.mjs.map +1 -0
- package/dist/constants/tool.cjs +2 -0
- package/dist/constants/tool.cjs.map +1 -0
- package/dist/constants/tool.mjs +2 -0
- package/dist/constants/tool.mjs.map +1 -0
- package/dist/extensions/pi.cjs +1 -1
- package/dist/extensions/pi.cjs.map +1 -1
- package/dist/extensions/pi.d.cts +2 -3
- package/dist/extensions/pi.d.cts.map +1 -1
- package/dist/extensions/pi.d.mts +2 -3
- package/dist/extensions/pi.d.mts.map +1 -1
- package/dist/extensions/pi.mjs +1 -1
- package/dist/extensions/pi.mjs.map +1 -1
- package/dist/extensions/server.cjs +2 -0
- package/dist/extensions/server.cjs.map +1 -0
- package/dist/extensions/server.d.cts +5 -0
- package/dist/extensions/server.d.cts.map +1 -0
- package/dist/extensions/server.d.mts +5 -0
- package/dist/extensions/server.d.mts.map +1 -0
- package/dist/extensions/server.mjs +2 -0
- package/dist/extensions/server.mjs.map +1 -0
- package/dist/index.cjs +0 -1
- package/dist/index.d.cts +3 -4
- package/dist/index.d.mts +3 -4
- package/dist/index.mjs +1 -1
- package/dist/schemas/apiContracts.cjs +2 -0
- package/dist/schemas/apiContracts.cjs.map +1 -0
- package/dist/schemas/apiContracts.d.cts +53 -0
- package/dist/schemas/apiContracts.d.cts.map +1 -0
- package/dist/schemas/apiContracts.d.mts +53 -0
- package/dist/schemas/apiContracts.d.mts.map +1 -0
- package/dist/schemas/apiContracts.mjs +2 -0
- package/dist/schemas/apiContracts.mjs.map +1 -0
- package/dist/schemas/questionnaire.cjs +1 -1
- package/dist/schemas/questionnaire.cjs.map +1 -1
- package/dist/schemas/questionnaire.d.cts +2 -3
- package/dist/schemas/questionnaire.d.cts.map +1 -1
- package/dist/schemas/questionnaire.d.mts +2 -3
- package/dist/schemas/questionnaire.d.mts.map +1 -1
- package/dist/schemas/questionnaire.mjs +1 -1
- package/dist/schemas/questionnaire.mjs.map +1 -1
- package/dist/services/answerEnvelope/index.cjs +2 -0
- package/dist/services/answerEnvelope/index.cjs.map +1 -0
- package/dist/services/answerEnvelope/index.mjs +2 -0
- package/dist/services/answerEnvelope/index.mjs.map +1 -0
- package/dist/services/askUserToolGate/index.cjs +2 -0
- package/dist/services/askUserToolGate/index.cjs.map +1 -0
- package/dist/services/askUserToolGate/index.mjs +2 -0
- package/dist/services/askUserToolGate/index.mjs.map +1 -0
- package/dist/services/autonomousVoiceMode/index.cjs +2 -0
- package/dist/services/autonomousVoiceMode/index.cjs.map +1 -0
- package/dist/services/autonomousVoiceMode/index.mjs +2 -0
- package/dist/services/autonomousVoiceMode/index.mjs.map +1 -0
- package/dist/{adapters/config/configAdapter.cjs → services/config/index.cjs} +1 -1
- package/dist/{adapters/config/configAdapter.mjs.map → services/config/index.cjs.map} +1 -1
- package/dist/{adapters/config/configAdapter.mjs → services/config/index.mjs} +1 -1
- package/dist/services/config/index.mjs.map +1 -0
- package/dist/services/questionnaireCoordinator/index.cjs +2 -0
- package/dist/services/questionnaireCoordinator/index.cjs.map +1 -0
- package/dist/services/questionnaireCoordinator/index.mjs +2 -0
- package/dist/services/questionnaireCoordinator/index.mjs.map +1 -0
- package/dist/services/questionnaireService/index.cjs +2 -0
- package/dist/services/questionnaireService/index.cjs.map +1 -0
- package/dist/services/questionnaireService/index.mjs +2 -0
- package/dist/services/questionnaireService/index.mjs.map +1 -0
- package/dist/services/{responseService.cjs → responseService/index.cjs} +1 -1
- package/dist/services/responseService/index.cjs.map +1 -0
- package/dist/services/{responseService.mjs → responseService/index.mjs} +1 -1
- package/dist/services/responseService/index.mjs.map +1 -0
- package/dist/services/rpcQuestionnaire/index.cjs +2 -0
- package/dist/services/rpcQuestionnaire/index.cjs.map +1 -0
- package/dist/services/rpcQuestionnaire/index.mjs +2 -0
- package/dist/services/rpcQuestionnaire/index.mjs.map +1 -0
- package/dist/services/validationService/index.cjs +2 -0
- package/dist/services/validationService/index.cjs.map +1 -0
- package/dist/services/validationService/index.mjs +2 -0
- package/dist/services/validationService/index.mjs.map +1 -0
- package/dist/services/voiceQuestionHandoff/index.cjs +5 -0
- package/dist/services/voiceQuestionHandoff/index.cjs.map +1 -0
- package/dist/services/voiceQuestionHandoff/index.mjs +5 -0
- package/dist/services/voiceQuestionHandoff/index.mjs.map +1 -0
- package/dist/services/voiceQuestionNarration/index.cjs +2 -0
- package/dist/services/voiceQuestionNarration/index.cjs.map +1 -0
- package/dist/services/voiceQuestionNarration/index.mjs +2 -0
- package/dist/services/voiceQuestionNarration/index.mjs.map +1 -0
- package/dist/tools/askUserHeadless.cjs +2 -0
- package/dist/tools/askUserHeadless.cjs.map +1 -0
- package/dist/tools/askUserHeadless.mjs +2 -0
- package/dist/tools/askUserHeadless.mjs.map +1 -0
- package/dist/tools/askUserQuestion.cjs +14 -0
- package/dist/tools/askUserQuestion.cjs.map +1 -0
- package/dist/tools/askUserQuestion.mjs +14 -0
- package/dist/tools/askUserQuestion.mjs.map +1 -0
- package/dist/tui/askUserToolRender.cjs +3 -0
- package/dist/tui/askUserToolRender.cjs.map +1 -0
- package/dist/tui/askUserToolRender.mjs +3 -0
- package/dist/tui/askUserToolRender.mjs.map +1 -0
- package/dist/tui/externalEditor.cjs.map +1 -1
- package/dist/tui/externalEditor.mjs.map +1 -1
- package/dist/tui/questionnaireComponent.cjs +1 -1
- package/dist/tui/questionnaireComponent.cjs.map +1 -1
- package/dist/tui/questionnaireComponent.mjs +1 -1
- package/dist/tui/questionnaireComponent.mjs.map +1 -1
- package/dist/tui/runQuestionnaire.cjs.map +1 -1
- package/dist/tui/runQuestionnaire.mjs.map +1 -1
- package/dist/types/askUserWire.cjs +2 -0
- package/dist/types/askUserWire.cjs.map +1 -0
- package/dist/types/askUserWire.mjs +2 -0
- package/dist/types/askUserWire.mjs.map +1 -0
- package/dist/types/questionnaire.d.cts +7 -6
- package/dist/types/questionnaire.d.cts.map +1 -1
- package/dist/types/questionnaire.d.mts +7 -6
- package/dist/types/questionnaire.d.mts.map +1 -1
- package/package.json +68 -27
- package/src/extensions/web.ts +33 -0
- package/src/types/askUserWire.ts +45 -0
- package/src/types/questionnaire.ts +44 -0
- package/src/web/components/AskUserQuestionToolMessage.tsx +88 -0
- package/src/web/components/QuestionnairePrompt.tsx +371 -0
- package/src/web/lib/askUserText.ts +65 -0
- package/src/web/lib/questionnaireDraft.ts +149 -0
- package/src/web/tsconfig.json +23 -0
- package/dist/adapters/config/configAdapter.cjs.map +0 -1
- package/dist/adapters/doom/voiceQuestionHandoff.cjs +0 -5
- package/dist/adapters/doom/voiceQuestionHandoff.cjs.map +0 -1
- package/dist/adapters/doom/voiceQuestionHandoff.d.cts +0 -32
- package/dist/adapters/doom/voiceQuestionHandoff.d.cts.map +0 -1
- package/dist/adapters/doom/voiceQuestionHandoff.d.mts +0 -32
- package/dist/adapters/doom/voiceQuestionHandoff.d.mts.map +0 -1
- package/dist/adapters/doom/voiceQuestionHandoff.mjs +0 -5
- package/dist/adapters/doom/voiceQuestionHandoff.mjs.map +0 -1
- package/dist/adapters/pi/askUserQuestionAdapter.cjs +0 -15
- package/dist/adapters/pi/askUserQuestionAdapter.cjs.map +0 -1
- package/dist/adapters/pi/askUserQuestionAdapter.mjs +0 -15
- package/dist/adapters/pi/askUserQuestionAdapter.mjs.map +0 -1
- package/dist/adapters/pi/reconcileAdapter.cjs +0 -2
- package/dist/adapters/pi/reconcileAdapter.cjs.map +0 -1
- package/dist/adapters/pi/reconcileAdapter.mjs +0 -2
- package/dist/adapters/pi/reconcileAdapter.mjs.map +0 -1
- package/dist/adapters/pi/rpcQuestionnaireAdapter.cjs +0 -2
- package/dist/adapters/pi/rpcQuestionnaireAdapter.cjs.map +0 -1
- package/dist/adapters/pi/rpcQuestionnaireAdapter.mjs +0 -2
- package/dist/adapters/pi/rpcQuestionnaireAdapter.mjs.map +0 -1
- package/dist/events.cjs +0 -1
- package/dist/events.d.cts +0 -2
- package/dist/events.d.mts +0 -2
- package/dist/events.mjs +0 -1
- package/dist/schemas/events.cjs +0 -1
- package/dist/schemas/events.d.cts +0 -22
- package/dist/schemas/events.d.cts.map +0 -1
- package/dist/schemas/events.d.mts +0 -22
- package/dist/schemas/events.d.mts.map +0 -1
- package/dist/schemas/events.mjs +0 -1
- package/dist/services/questionnaireCoordinator.cjs +0 -2
- package/dist/services/questionnaireCoordinator.cjs.map +0 -1
- package/dist/services/questionnaireCoordinator.mjs +0 -2
- package/dist/services/questionnaireCoordinator.mjs.map +0 -1
- package/dist/services/responseService.cjs.map +0 -1
- package/dist/services/responseService.mjs.map +0 -1
- package/dist/services/validationService.cjs +0 -2
- package/dist/services/validationService.cjs.map +0 -1
- package/dist/services/validationService.mjs +0 -2
- package/dist/services/validationService.mjs.map +0 -1
- package/dist/services/voiceQuestionNarration.cjs +0 -2
- package/dist/services/voiceQuestionNarration.cjs.map +0 -1
- package/dist/services/voiceQuestionNarration.mjs +0 -2
- package/dist/services/voiceQuestionNarration.mjs.map +0 -1
- package/dist/voiceQuestionHandoff.cjs +0 -1
- package/dist/voiceQuestionHandoff.d.cts +0 -4
- package/dist/voiceQuestionHandoff.d.mts +0 -4
- package/dist/voiceQuestionHandoff.mjs +0 -1
package/README.md
CHANGED
|
@@ -1,62 +1,123 @@
|
|
|
1
1
|
# @agimon-ai/doompi-user-feedback
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Ask structured questions in interactive Pi sessions, including sessions using autonomous Voice.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
terminal session it opens a blocking questionnaire and returns the selected answer to the
|
|
7
|
-
agent. The question does not get buried in prose and the turn does not continue on a
|
|
8
|
-
guess.
|
|
5
|
+
Part of the [DoomPi distribution](https://www.npmjs.com/package/@agimon-ai/doompi).
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
plain text, hands them to narration, terminates the turn, and accepts the next spoken reply
|
|
12
|
-
as an ordinary user message.
|
|
7
|
+
The `ask_user_question` tool presents concrete options and waits for a choice or custom-text answer.
|
|
13
8
|
|
|
14
|
-
|
|
15
|
-
packages. It keeps the established `rpiv:ask-user:prompt` and `rpiv:ask-user:blocked`
|
|
16
|
-
channel names so existing Doompi listeners can migrate without being rewritten.
|
|
9
|
+
> **Alpha:** tool and Voice-handoff contracts may change between releases.
|
|
17
10
|
|
|
18
|
-
|
|
19
|
-
`ask-user` layer loads it where structured feedback is wanted.
|
|
11
|
+
## Requirements
|
|
20
12
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npm install @agimon-ai/doompi-user-feedback
|
|
25
|
-
```
|
|
13
|
+
- Node.js 22.19.0 or newer
|
|
14
|
+
- Pi 0.85.0 and Pi TUI 0.85.0
|
|
26
15
|
|
|
27
|
-
##
|
|
16
|
+
## Install
|
|
28
17
|
|
|
29
|
-
|
|
18
|
+
Define a layer in `.doom/modes.yaml`, then include it in a major mode:
|
|
30
19
|
|
|
31
20
|
```yaml
|
|
32
21
|
layers:
|
|
33
|
-
|
|
22
|
+
feedback:
|
|
34
23
|
packages: ['@agimon-ai/doompi-user-feedback']
|
|
35
24
|
|
|
36
25
|
majorMode:
|
|
37
|
-
|
|
38
|
-
description:
|
|
39
|
-
layers: [
|
|
26
|
+
minimal:
|
|
27
|
+
description: Interactive questions without the full default composition.
|
|
28
|
+
layers: [feedback]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
For standalone Pi:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pi install npm:@agimon-ai/doompi-user-feedback
|
|
40
35
|
```
|
|
41
36
|
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
Pi loads the package through `package.json.pi.extensions`. Each factory invocation owns one package
|
|
38
|
+
instance. Session replacement resets its state, and shutdown removes its registrations.
|
|
39
|
+
|
|
40
|
+
## Ask a question
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"questions": [
|
|
45
|
+
{
|
|
46
|
+
"header": "Storage",
|
|
47
|
+
"question": "Where should session results be stored?",
|
|
48
|
+
"options": [
|
|
49
|
+
{
|
|
50
|
+
"label": "Project files",
|
|
51
|
+
"description": "Easy to inspect and commit, but visible in the repository."
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"label": "User state",
|
|
55
|
+
"description": "Keeps generated state outside the repository."
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"multiSelect": false
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
A call accepts 1 to 4 questions. Each question requires 2 to 4 options. Headers are at most 16
|
|
65
|
+
characters; option labels are at most 60 characters. Use `multiSelect: true` when several choices
|
|
66
|
+
are valid. An option can include a Markdown `preview` for meaningful visual comparison.
|
|
67
|
+
|
|
68
|
+
The tool result contains readable answer text plus structured `details.answers`; cancellation sets
|
|
69
|
+
`cancelled: true`. Pressing Escape declines the questionnaire. Do not add an `Other` option because
|
|
70
|
+
the UI supplies a custom-text row.
|
|
44
71
|
|
|
45
|
-
##
|
|
72
|
+
## UI, RPC, and headless behavior
|
|
46
73
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
session ends so subscriptions do not outlive their owner.
|
|
74
|
+
The tool requires an interactive UI. It uses the TUI questionnaire when available and can use Pi's
|
|
75
|
+
dialog or RPC UI bridge. A headless context without either UI returns a structured `no_ui`
|
|
76
|
+
cancellation rather than waiting forever.
|
|
51
77
|
|
|
52
|
-
|
|
53
|
-
|
|
78
|
+
Questionnaires are coordinated one at a time. Cancellation, session replacement, or shutdown
|
|
79
|
+
aborts the active prompt and settles queued work.
|
|
80
|
+
|
|
81
|
+
## Autonomous Voice
|
|
82
|
+
|
|
83
|
+
While autonomous Voice mode is active, `ask_user_question` leaves Pi's active tool set. Voice already
|
|
84
|
+
speaks its own question through `narrate` and then waits for the spoken reply, so keeping a
|
|
85
|
+
questionnaire tool alongside it asks the same thing twice. The agent asks by narrating, and the
|
|
86
|
+
answer arrives as an ordinary user message.
|
|
87
|
+
|
|
88
|
+
The gate tracks its own removal. A tool switched off by the user stays off, no other package's tools
|
|
89
|
+
are touched, and the removal is restored when Voice deactivates, when the Voice services unload, or
|
|
90
|
+
when this runtime shuts down.
|
|
91
|
+
|
|
92
|
+
A call already in flight when Voice activates still hands off: the extension formats the questions as
|
|
93
|
+
plain text, requests narration, and returns `terminate: true`, ending the turn while it waits.
|
|
94
|
+
|
|
95
|
+
Both paths use the shared `doom/minor-mode-catalog` and `doom/narration` Cordis services. If a
|
|
96
|
+
provider unloads, User Feedback restores the tool and falls back to its interactive questionnaire
|
|
97
|
+
without retaining the old provider.
|
|
54
98
|
|
|
55
99
|
## Public API
|
|
56
100
|
|
|
57
|
-
|
|
58
|
-
|
|
101
|
+
Question and result types are available from the package root. Cross-extension ask-user events and
|
|
102
|
+
Voice services come from `@agimon-ai/doompi-core`; consumers should use those Cordis
|
|
103
|
+
contracts. Pi loads the default export of `/extensions/pi` through package metadata, so installation
|
|
104
|
+
does not require a manual registration call.
|
|
105
|
+
|
|
106
|
+
## Development
|
|
107
|
+
|
|
108
|
+
Run from this package directory in the workspace:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
pnpm build
|
|
112
|
+
pnpm typecheck
|
|
113
|
+
pnpm test
|
|
114
|
+
pnpm lint
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Maintained by [Agimon](https://agimon.ai/about).
|
|
59
118
|
|
|
60
119
|
## License
|
|
61
120
|
|
|
62
121
|
MIT
|
|
122
|
+
|
|
123
|
+
The named Pi and server factories live in `src/extensions`. Tools return typed declarations using questionnaire services. TUI renderers are supplied by the Pi entry. Each Pi mount owns optional Voice service subscriptions, a live tool restriction, and awaited questionnaire shutdown through `onDispose`. Public types are exposed through flat `src/exports`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("./schemas/apiContracts.cjs");exports.apiContracts=e.apiContracts,exports.default=e.apiContracts;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{apiContracts as e}from"./schemas/apiContracts.mjs";export{e as apiContracts,e as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package.cjs","names":[],"sources":["../../src/constants/package.ts"],"sourcesContent":["export const PACKAGE_SOURCE = '@agimon-ai/doompi-user-feedback';\n"],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package.mjs","names":[],"sources":["../../src/constants/package.ts"],"sourcesContent":["export const PACKAGE_SOURCE = '@agimon-ai/doompi-user-feedback';\n"],"mappings":"AAAA,MAAa,EAAiB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"questionnaire.cjs","names":[],"sources":["../../src/constants/questionnaire.ts"],"sourcesContent":["export const MAX_QUESTIONS = 4;\nexport const MIN_OPTIONS = 2;\nexport const MAX_OPTIONS = 4;\nexport const MAX_HEADER_LENGTH = 16;\nexport const MAX_LABEL_LENGTH = 60;\n\nexport const RESERVED_LABELS = ['Other', 'Type something.', 'Next'] as const;\n"],"mappings":"AAMA,MAAa,EAAkB,CAAC,QAAS,kBAAmB,MAAM"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"questionnaire.mjs","names":[],"sources":["../../src/constants/questionnaire.ts"],"sourcesContent":["export const MAX_QUESTIONS = 4;\nexport const MIN_OPTIONS = 2;\nexport const MAX_OPTIONS = 4;\nexport const MAX_HEADER_LENGTH = 16;\nexport const MAX_LABEL_LENGTH = 60;\n\nexport const RESERVED_LABELS = ['Other', 'Type something.', 'Next'] as const;\n"],"mappings":"AAMA,MAAa,EAAkB,CAAC,QAAS,kBAAmB,MAAM"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=[`Use ask_user_question whenever the user's request is underspecified and you cannot proceed without concrete decisions, you can ask up to 4 questions per invocation.`,`Each question MUST have 2-4 options. Every option requires a concise label (1-5 words) and a description explaining what the choice means or its trade-offs. The user can additionally 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.`,`Set multiSelect: true when multiple answers are valid. Provide an options[].preview markdown string when an option benefits from richer side-by-side context (mockups, code snippets, diagrams, configs), single-select only. If you recommend a specific option, make that the first option and append "(Recommended)" to its label.`,`Do not stack multiple ask_user_question calls back-to-back, group all clarifying questions into one invocation.`];exports.ASK_USER_QUESTION_TOOL_NAME=`ask_user_question`,exports.DEFAULT_PROMPT_GUIDELINES=e,exports.DEFAULT_PROMPT_SNIPPET=`Ask the user up to 4 structured questions (2-4 options each) when requirements are ambiguous`,exports.ERROR_NO_CUSTOM_UI=`Error: this client cannot render the questionnaire (custom UI is unavailable). The user never saw the questions, do NOT treat this as a decline. Ask the questions as plain chat text instead, without using this tool.`,exports.ERROR_NO_UI=`Error: UI not available (running in non-interactive mode)`,exports.ERROR_SESSION_INACTIVE=`Error: the questionnaire session is no longer active.`,exports.ERROR_SESSION_LOAD_FAILED=`Error: the questionnaire UI failed to load. The user never saw the questions, do NOT treat this as a decline. Ask the questions as plain chat text instead.`;
|
|
2
|
+
//# sourceMappingURL=tool.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.cjs","names":[],"sources":["../../src/constants/tool.ts"],"sourcesContent":["import { MAX_OPTIONS, MAX_QUESTIONS, MIN_OPTIONS } from './questionnaire';\nexport const ASK_USER_QUESTION_TOOL_NAME = 'ask_user_question';\n\nexport const DEFAULT_PROMPT_SNIPPET = `Ask the user up to ${MAX_QUESTIONS} structured questions (${MIN_OPTIONS}-${MAX_OPTIONS} options each) when requirements are ambiguous`;\nexport const DEFAULT_PROMPT_GUIDELINES = [\n `Use ask_user_question whenever the user's request is underspecified and you cannot proceed without concrete decisions, you can ask up to ${MAX_QUESTIONS} questions per invocation.`,\n `Each question MUST have ${MIN_OPTIONS}-${MAX_OPTIONS} options. Every option requires a concise label (1-5 words) and a description explaining what the choice means or its trade-offs. The user can additionally 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 'Set multiSelect: true when multiple answers are valid. Provide an options[].preview markdown string when an option benefits from richer side-by-side context (mockups, code snippets, diagrams, configs), single-select only. If you recommend a specific option, make that the first option and append \"(Recommended)\" to its label.',\n 'Do not stack multiple ask_user_question calls back-to-back, group all clarifying questions into one invocation.',\n];\n\nexport const ERROR_NO_UI = 'Error: UI not available (running in non-interactive mode)';\nexport const ERROR_NO_CUSTOM_UI =\n 'Error: this client cannot render the questionnaire (custom UI is unavailable). The user never saw the questions, do NOT treat this as a decline. Ask the questions as plain chat text instead, without using this tool.';\nexport const ERROR_SESSION_LOAD_FAILED =\n 'Error: the questionnaire UI failed to load. The user never saw the questions, do NOT treat this as a decline. Ask the questions as plain chat text instead.';\nexport const ERROR_SESSION_INACTIVE = 'Error: the questionnaire session is no longer active.';\n"],"mappings":"AACA,MAGa,EAA4B,CACvC,uKACA,saACA,wUACA,iHACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=`ask_user_question`,t=`Ask the user up to 4 structured questions (2-4 options each) when requirements are ambiguous`,n=[`Use ask_user_question whenever the user's request is underspecified and you cannot proceed without concrete decisions, you can ask up to 4 questions per invocation.`,`Each question MUST have 2-4 options. Every option requires a concise label (1-5 words) and a description explaining what the choice means or its trade-offs. The user can additionally 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.`,`Set multiSelect: true when multiple answers are valid. Provide an options[].preview markdown string when an option benefits from richer side-by-side context (mockups, code snippets, diagrams, configs), single-select only. If you recommend a specific option, make that the first option and append "(Recommended)" to its label.`,`Do not stack multiple ask_user_question calls back-to-back, group all clarifying questions into one invocation.`],r=`Error: UI not available (running in non-interactive mode)`,i=`Error: this client cannot render the questionnaire (custom UI is unavailable). The user never saw the questions, do NOT treat this as a decline. Ask the questions as plain chat text instead, without using this tool.`,a=`Error: the questionnaire UI failed to load. The user never saw the questions, do NOT treat this as a decline. Ask the questions as plain chat text instead.`,o=`Error: the questionnaire session is no longer active.`;export{e as ASK_USER_QUESTION_TOOL_NAME,n as DEFAULT_PROMPT_GUIDELINES,t as DEFAULT_PROMPT_SNIPPET,i as ERROR_NO_CUSTOM_UI,r as ERROR_NO_UI,o as ERROR_SESSION_INACTIVE,a as ERROR_SESSION_LOAD_FAILED};
|
|
2
|
+
//# sourceMappingURL=tool.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.mjs","names":[],"sources":["../../src/constants/tool.ts"],"sourcesContent":["import { MAX_OPTIONS, MAX_QUESTIONS, MIN_OPTIONS } from './questionnaire';\nexport const ASK_USER_QUESTION_TOOL_NAME = 'ask_user_question';\n\nexport const DEFAULT_PROMPT_SNIPPET = `Ask the user up to ${MAX_QUESTIONS} structured questions (${MIN_OPTIONS}-${MAX_OPTIONS} options each) when requirements are ambiguous`;\nexport const DEFAULT_PROMPT_GUIDELINES = [\n `Use ask_user_question whenever the user's request is underspecified and you cannot proceed without concrete decisions, you can ask up to ${MAX_QUESTIONS} questions per invocation.`,\n `Each question MUST have ${MIN_OPTIONS}-${MAX_OPTIONS} options. Every option requires a concise label (1-5 words) and a description explaining what the choice means or its trade-offs. The user can additionally 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 'Set multiSelect: true when multiple answers are valid. Provide an options[].preview markdown string when an option benefits from richer side-by-side context (mockups, code snippets, diagrams, configs), single-select only. If you recommend a specific option, make that the first option and append \"(Recommended)\" to its label.',\n 'Do not stack multiple ask_user_question calls back-to-back, group all clarifying questions into one invocation.',\n];\n\nexport const ERROR_NO_UI = 'Error: UI not available (running in non-interactive mode)';\nexport const ERROR_NO_CUSTOM_UI =\n 'Error: this client cannot render the questionnaire (custom UI is unavailable). The user never saw the questions, do NOT treat this as a decline. Ask the questions as plain chat text instead, without using this tool.';\nexport const ERROR_SESSION_LOAD_FAILED =\n 'Error: the questionnaire UI failed to load. The user never saw the questions, do NOT treat this as a decline. Ask the questions as plain chat text instead.';\nexport const ERROR_SESSION_INACTIVE = 'Error: the questionnaire session is no longer active.';\n"],"mappings":"AACA,MAAa,EAA8B,oBAE9B,EAAyB,+FACzB,EAA4B,CACvC,uKACA,saACA,wUACA,iHACF,EAEa,EAAc,4DACd,EACX,0NACW,EACX,8JACW,EAAyB"}
|
package/dist/extensions/pi.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../constants/package.cjs"),t=require("../constants/tool.cjs"),n=require("../services/askUserToolGate/index.cjs"),r=require("../services/autonomousVoiceMode/index.cjs"),i=require("../services/questionnaireCoordinator/index.cjs"),a=require("../services/voiceQuestionHandoff/index.cjs"),o=require("../tools/askUserQuestion.cjs"),s=require("../tui/askUserToolRender.cjs");let c=require("@agimon-ai/doompi-core/narration"),l=require("@agimon-ai/doompi-core/pi-extension"),u=require("@agimon-ai/doompi-minor-mode");function d(){return{answers:[],cancelled:!0}}const f=(0,l.definePiExtension)(e.PACKAGE_SOURCE,({context:f})=>{let p=!0,m=0,h,g=!1,_=new i.QuestionnaireCoordinator,v,y=!1,b=!0,x=new Set,S=()=>n.askUserToolRestriction(t.ASK_USER_QUESTION_TOOL_NAME,b&&!y),C=()=>x.forEach(e=>e()),w=Promise.resolve(),T=new Set,E=e=>(T.add(e),e.then(()=>T.delete(e),()=>T.delete(e)),e),D=(e,t)=>p&&e===m&&t===h,O=(e,t)=>p&&g&&t?.aborted!==!0&&e.sessionManager.getSessionId()===h,k=async()=>{if(!p)return;let e=_;e.shutdown(),p=!1,m+=1,g=!1,h=void 0,await Promise.allSettled(T),await e.waitForIdle()},A={enqueue:(e,t)=>{let n=_,r=m,i=h;return!g||!D(r,i)||t?.aborted?Promise.resolve(d()):n.enqueue(async t=>{if(!g||!D(r,i)||t.signal.aborted)return d();let n=await e({...t,reportProgress:e=>{D(r,i)&&!t.signal.aborted&&t.reportProgress(e)}});return g&&D(r,i)&&!t.signal.aborted?n:d()},t)},isActive:O,runTui:async(e,t,n,r,i)=>{if(!O(e,r))return;let{runTuiQuestionnaire:a}=await Promise.resolve().then(()=>require("../tui/runQuestionnaire.cjs"));if(!O(e,r))return;let o=await a(e,t,n,r,i);return O(e,r)?o:void 0},tryVoice:e=>p&&g?v?.handoff(e):void 0};return{services:[e=>{e.inject([u.DOOM_MINOR_MODE_CATALOG_SERVICE,c.DOOM_NARRATION_SERVICE],e=>{let t=a.createVoiceQuestionHandoff((0,u.requireMinorModeCatalog)(e),(0,c.requireDoomNarrationService)(e));return v=t,()=>{v===t&&(v=void 0)}}),e.inject([u.DOOM_MINOR_MODE_CATALOG_SERVICE],e=>{let t=(0,u.requireMinorModeCatalog)(e),n=()=>{y=r.isAutonomousVoiceActive(t.list()),C()},i=t.subscribe(n);return n(),()=>{i(),y=!1,C()}})}],tools:[(0,l.definePiTool)(o.createAskUserQuestionTool(f,A,s.askUserToolRender))],events:{before_agent_start:(e,t)=>{O(t)&&(b=t.hasUI,C())},session_start:(e,t)=>{if(!p)return;let n=_;n.shutdown();let r=t.sessionManager.getSessionId(),a=++m;_=new i.QuestionnaireCoordinator,h=r,g=!1;let o=async()=>{await n.waitForIdle(),D(a,r)&&(g=!0)},s=w.then(o,o);return w=s.catch(()=>void 0),E(s)}},onDispose:k,toolRestrictions:[{source:e.PACKAGE_SOURCE,get restrict(){return S()},subscribe(e){return x.add(e),()=>{x.delete(e)}}}]}});exports.default=f,exports.userFeedbackExtension=f;
|
|
2
2
|
//# sourceMappingURL=pi.cjs.map
|
|
@@ -1 +1 @@
|
|
|
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
|
+
{"version":3,"file":"pi.cjs","names":["definePiExtension","PACKAGE_SOURCE","QuestionnaireCoordinator","askUserToolRestriction","ASK_USER_QUESTION_TOOL_NAME","DOOM_MINOR_MODE_CATALOG_SERVICE","DOOM_NARRATION_SERVICE","createVoiceQuestionHandoff","requireMinorModeCatalog","requireDoomNarrationService","isAutonomousVoiceActive","definePiTool","createAskUserQuestionTool","askUserToolRender"],"sources":["../../src/extensions/pi.ts"],"sourcesContent":["import { DOOM_NARRATION_SERVICE, requireDoomNarrationService } from '@agimon-ai/doompi-core/narration';\nimport { definePiExtension, definePiTool } from '@agimon-ai/doompi-core/pi-extension';\nimport { type DoomToolRestriction } from '@agimon-ai/doompi-core/tool-surface';\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 { PACKAGE_SOURCE } from '../constants/package';\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 { createAskUserQuestionTool } from '../tools/askUserQuestion';\nimport { askUserToolRender } from '../tui/askUserToolRender';\nimport type { QuestionnaireResult } from '../types/questionnaire';\n\nfunction cancelledResult(): QuestionnaireResult {\n return { answers: [], cancelled: true };\n}\n\nexport const userFeedbackExtension = definePiExtension(PACKAGE_SOURCE, ({ context: cordis }) => {\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 return {\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 tools: [definePiTool(createAskUserQuestionTool(cordis, toolDependencies, askUserToolRender))],\n events: { before_agent_start: beforeAgentStart, session_start: sessionStart },\n onDispose: shutdownRuntime,\n toolRestrictions: [\n {\n source: PACKAGE_SOURCE,\n get restrict() {\n return currentRestriction();\n },\n subscribe(listener) {\n restrictionListeners.add(listener);\n return () => {\n restrictionListeners.delete(listener);\n };\n },\n },\n ],\n };\n});\nexport default userFeedbackExtension;\n"],"mappings":"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"}
|
package/dist/extensions/pi.d.cts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
1
|
//#region src/extensions/pi.d.ts
|
|
3
|
-
declare
|
|
2
|
+
export declare const userFeedbackExtension: import("@agimon-ai/doompi-core/runtime-pi-extension").DefinedPiExtension<undefined>;
|
|
4
3
|
//#endregion
|
|
5
|
-
export {
|
|
4
|
+
export { userFeedbackExtension as default };
|
|
6
5
|
//# sourceMappingURL=pi.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pi.d.cts","names":[],"sources":["../../src/extensions/pi.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"pi.d.cts","names":[],"sources":["../../src/extensions/pi.ts"],"mappings":";qBAqBa,6EAAqB"}
|
package/dist/extensions/pi.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
1
|
//#region src/extensions/pi.d.ts
|
|
3
|
-
declare
|
|
2
|
+
export declare const userFeedbackExtension: import("@agimon-ai/doompi-core/runtime-pi-extension").DefinedPiExtension<undefined>;
|
|
4
3
|
//#endregion
|
|
5
|
-
export {
|
|
4
|
+
export { userFeedbackExtension as default };
|
|
6
5
|
//# sourceMappingURL=pi.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pi.d.mts","names":[],"sources":["../../src/extensions/pi.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"pi.d.mts","names":[],"sources":["../../src/extensions/pi.ts"],"mappings":";qBAqBa,6EAAqB"}
|
package/dist/extensions/pi.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{PACKAGE_SOURCE as e}from"../constants/package.mjs";import{ASK_USER_QUESTION_TOOL_NAME as t}from"../constants/tool.mjs";import{askUserToolRestriction as n}from"../services/askUserToolGate/index.mjs";import{isAutonomousVoiceActive as r}from"../services/autonomousVoiceMode/index.mjs";import{QuestionnaireCoordinator as i}from"../services/questionnaireCoordinator/index.mjs";import{createVoiceQuestionHandoff as a}from"../services/voiceQuestionHandoff/index.mjs";import{createAskUserQuestionTool as o}from"../tools/askUserQuestion.mjs";import{askUserToolRender as s}from"../tui/askUserToolRender.mjs";import{DOOM_NARRATION_SERVICE as c,requireDoomNarrationService as l}from"@agimon-ai/doompi-core/narration";import{definePiExtension as u,definePiTool as d}from"@agimon-ai/doompi-core/pi-extension";import{DOOM_MINOR_MODE_CATALOG_SERVICE as f,requireMinorModeCatalog as p}from"@agimon-ai/doompi-minor-mode";function m(){return{answers:[],cancelled:!0}}const h=u(e,({context:u})=>{let h=!0,g=0,_,v=!1,y=new i,b,x=!1,S=!0,C=new Set,w=()=>n(t,S&&!x),T=()=>C.forEach(e=>e()),E=Promise.resolve(),D=new Set,O=e=>(D.add(e),e.then(()=>D.delete(e),()=>D.delete(e)),e),k=(e,t)=>h&&e===g&&t===_,A=(e,t)=>h&&v&&t?.aborted!==!0&&e.sessionManager.getSessionId()===_;return{services:[e=>{e.inject([f,c],e=>{let t=a(p(e),l(e));return b=t,()=>{b===t&&(b=void 0)}}),e.inject([f],e=>{let t=p(e),n=()=>{x=r(t.list()),T()},i=t.subscribe(n);return n(),()=>{i(),x=!1,T()}})}],tools:[d(o(u,{enqueue:(e,t)=>{let n=y,r=g,i=_;return!v||!k(r,i)||t?.aborted?Promise.resolve(m()):n.enqueue(async t=>{if(!v||!k(r,i)||t.signal.aborted)return m();let n=await e({...t,reportProgress:e=>{k(r,i)&&!t.signal.aborted&&t.reportProgress(e)}});return v&&k(r,i)&&!t.signal.aborted?n:m()},t)},isActive:A,runTui:async(e,t,n,r,i)=>{if(!A(e,r))return;let{runTuiQuestionnaire:a}=await import(`../tui/runQuestionnaire.mjs`);if(!A(e,r))return;let o=await a(e,t,n,r,i);return A(e,r)?o:void 0},tryVoice:e=>h&&v?b?.handoff(e):void 0},s))],events:{before_agent_start:(e,t)=>{A(t)&&(S=t.hasUI,T())},session_start:(e,t)=>{if(!h)return;let n=y;n.shutdown();let r=t.sessionManager.getSessionId(),a=++g;y=new i,_=r,v=!1;let o=async()=>{await n.waitForIdle(),k(a,r)&&(v=!0)},s=E.then(o,o);return E=s.catch(()=>void 0),O(s)}},onDispose:async()=>{if(!h)return;let e=y;e.shutdown(),h=!1,g+=1,v=!1,_=void 0,await Promise.allSettled(D),await e.waitForIdle()},toolRestrictions:[{source:e,get restrict(){return w()},subscribe(e){return C.add(e),()=>{C.delete(e)}}}]}});export{h as default,h as userFeedbackExtension};
|
|
2
2
|
//# sourceMappingURL=pi.mjs.map
|
|
@@ -1 +1 @@
|
|
|
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"}
|
|
1
|
+
{"version":3,"file":"pi.mjs","names":[],"sources":["../../src/extensions/pi.ts"],"sourcesContent":["import { DOOM_NARRATION_SERVICE, requireDoomNarrationService } from '@agimon-ai/doompi-core/narration';\nimport { definePiExtension, definePiTool } from '@agimon-ai/doompi-core/pi-extension';\nimport { type DoomToolRestriction } from '@agimon-ai/doompi-core/tool-surface';\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 { PACKAGE_SOURCE } from '../constants/package';\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 { createAskUserQuestionTool } from '../tools/askUserQuestion';\nimport { askUserToolRender } from '../tui/askUserToolRender';\nimport type { QuestionnaireResult } from '../types/questionnaire';\n\nfunction cancelledResult(): QuestionnaireResult {\n return { answers: [], cancelled: true };\n}\n\nexport const userFeedbackExtension = definePiExtension(PACKAGE_SOURCE, ({ context: cordis }) => {\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 return {\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 tools: [definePiTool(createAskUserQuestionTool(cordis, toolDependencies, askUserToolRender))],\n events: { before_agent_start: beforeAgentStart, session_start: sessionStart },\n onDispose: shutdownRuntime,\n toolRestrictions: [\n {\n source: PACKAGE_SOURCE,\n get restrict() {\n return currentRestriction();\n },\n subscribe(listener) {\n restrictionListeners.add(listener);\n return () => {\n restrictionListeners.delete(listener);\n };\n },\n },\n ],\n };\n});\nexport default userFeedbackExtension;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../constants/package.cjs"),t=require("../services/questionnaireCoordinator/index.cjs"),n=require("../tools/askUserHeadless.cjs"),r=(0,require("@agimon-ai/doompi-core/server-facet").defineServerPlugin)({name:e.PACKAGE_SOURCE,session:()=>{let e=new t.QuestionnaireCoordinator;return{tools:[n.createAskUserHeadlessTool(e)],hooks:[{event:`session_shutdown`,handle:()=>e.shutdown()}],onDispose:()=>e.shutdown()}}});exports.default=r,exports.userFeedbackServerFacet=r;
|
|
2
|
+
//# sourceMappingURL=server.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.cjs","names":["defineServerPlugin","PACKAGE_SOURCE","QuestionnaireCoordinator","createAskUserHeadlessTool"],"sources":["../../src/extensions/server.ts"],"sourcesContent":["import { defineServerPlugin } from '@agimon-ai/doompi-core/server-facet';\n\nimport { PACKAGE_SOURCE } from '../constants/package';\nimport { QuestionnaireCoordinator } from '../services/questionnaireCoordinator';\nimport { createAskUserHeadlessTool } from '../tools/askUserHeadless';\nexport const userFeedbackServerFacet = defineServerPlugin({\n name: PACKAGE_SOURCE,\n session: () => {\n const coordinator = new QuestionnaireCoordinator();\n return {\n tools: [createAskUserHeadlessTool(coordinator)],\n hooks: [{ event: 'session_shutdown', handle: () => coordinator.shutdown() }],\n onDispose: () => coordinator.shutdown(),\n };\n },\n});\nexport default userFeedbackServerFacet;\n"],"mappings":"iPAKa,GAAA,+CAA0BA,CAAAA,CAAAA,mBAAAA,CAAmB,CACxD,KAAMC,EAAAA,eACN,YAAe,CACb,IAAM,EAAc,IAAIC,EAAAA,yBACxB,MAAO,CACL,MAAO,CAACC,EAAAA,0BAA0B,CAAW,CAAC,EAC9C,MAAO,CAAC,CAAE,MAAO,mBAAoB,WAAc,EAAY,SAAS,CAAE,CAAC,EAC3E,cAAiB,EAAY,SAAS,CACxC,CACF,CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.cts","names":[],"sources":["../../src/extensions/server.ts"],"mappings":";qBAKa,uEAAuB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.mts","names":[],"sources":["../../src/extensions/server.ts"],"mappings":";qBAKa,uEAAuB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{PACKAGE_SOURCE as e}from"../constants/package.mjs";import{QuestionnaireCoordinator as t}from"../services/questionnaireCoordinator/index.mjs";import{createAskUserHeadlessTool as n}from"../tools/askUserHeadless.mjs";import{defineServerPlugin as r}from"@agimon-ai/doompi-core/server-facet";const i=r({name:e,session:()=>{let e=new t;return{tools:[n(e)],hooks:[{event:`session_shutdown`,handle:()=>e.shutdown()}],onDispose:()=>e.shutdown()}}});export{i as default,i as userFeedbackServerFacet};
|
|
2
|
+
//# sourceMappingURL=server.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.mjs","names":[],"sources":["../../src/extensions/server.ts"],"sourcesContent":["import { defineServerPlugin } from '@agimon-ai/doompi-core/server-facet';\n\nimport { PACKAGE_SOURCE } from '../constants/package';\nimport { QuestionnaireCoordinator } from '../services/questionnaireCoordinator';\nimport { createAskUserHeadlessTool } from '../tools/askUserHeadless';\nexport const userFeedbackServerFacet = defineServerPlugin({\n name: PACKAGE_SOURCE,\n session: () => {\n const coordinator = new QuestionnaireCoordinator();\n return {\n tools: [createAskUserHeadlessTool(coordinator)],\n hooks: [{ event: 'session_shutdown', handle: () => coordinator.shutdown() }],\n onDispose: () => coordinator.shutdown(),\n };\n },\n});\nexport default userFeedbackServerFacet;\n"],"mappings":"sSAKA,MAAa,EAA0B,EAAmB,CACxD,KAAM,EACN,YAAe,CACb,IAAM,EAAc,IAAI,EACxB,MAAO,CACL,MAAO,CAAC,EAA0B,CAAW,CAAC,EAC9C,MAAO,CAAC,CAAE,MAAO,mBAAoB,WAAc,EAAY,SAAS,CAAE,CAAC,EAC3E,cAAiB,EAAY,SAAS,CACxC,CACF,CACF,CAAC"}
|
package/dist/index.cjs
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("./extensions/pi.cjs");require("./events.cjs");let t=require("@agimon-ai/doompi-extension-contracts");Object.defineProperty(exports,"ASK_USER_BLOCKED_EVENT",{enumerable:!0,get:function(){return t.ASK_USER_BLOCKED_EVENT}}),Object.defineProperty(exports,"ASK_USER_PROMPT_EVENT",{enumerable:!0,get:function(){return t.ASK_USER_PROMPT_EVENT}}),exports.default=e.default,exports.registerUserFeedbackExtension=e.default;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import "./
|
|
3
|
-
|
|
4
|
-
export { ASK_USER_BLOCKED_EVENT, ASK_USER_PROMPT_EVENT, type AskUserBlockedEventPayload, type AskUserPromptEventPayload, type AskUserPromptOption, type AskUserPromptQuestion, registerUserFeedbackExtension as default, registerUserFeedbackExtension };
|
|
1
|
+
import { QuestionParams } from "./schemas/questionnaire.cjs";
|
|
2
|
+
import { QuestionnaireResult, ToolTextResult } from "./types/questionnaire.cjs";
|
|
3
|
+
export type { QuestionParams, QuestionnaireResult, ToolTextResult };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import "./
|
|
3
|
-
|
|
4
|
-
export { ASK_USER_BLOCKED_EVENT, ASK_USER_PROMPT_EVENT, type AskUserBlockedEventPayload, type AskUserPromptEventPayload, type AskUserPromptOption, type AskUserPromptQuestion, registerUserFeedbackExtension as default, registerUserFeedbackExtension };
|
|
1
|
+
import { QuestionParams } from "./schemas/questionnaire.mjs";
|
|
2
|
+
import { QuestionnaireResult, ToolTextResult } from "./types/questionnaire.mjs";
|
|
3
|
+
export type { QuestionParams, QuestionnaireResult, ToolTextResult };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export{};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiContracts.cjs","names":["defineApiContract"],"sources":["../../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract } from '@agimon-ai/doompi-core/api-contracts';\n\n/** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */\nexport const apiContracts = defineApiContract({ version: 1, http: [], sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":"AAGA,MAAa,GAAA,gDAAeA,CAAAA,CAAAA,kBAAAA,CAAkB,CAAE,QAAS,EAAG,KAAM,CAAC,EAAG,QAAS,CAAC,EAAG,QAAS,CAAC,CAAE,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//#region src/schemas/apiContracts.d.ts
|
|
2
|
+
/** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */
|
|
3
|
+
export declare const apiContracts: {
|
|
4
|
+
version: 1;
|
|
5
|
+
protocols?: Record<string, string> | undefined;
|
|
6
|
+
schemas?: Record<string, boolean | object> | undefined;
|
|
7
|
+
http: {
|
|
8
|
+
id: string;
|
|
9
|
+
scope: "global" | "session" | "workspace";
|
|
10
|
+
basePath?: string | undefined;
|
|
11
|
+
path: string;
|
|
12
|
+
method: "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT";
|
|
13
|
+
description: string;
|
|
14
|
+
availability?: string | undefined;
|
|
15
|
+
authentication: "device" | "none" | "owner";
|
|
16
|
+
parameters?: {
|
|
17
|
+
name: string;
|
|
18
|
+
in: "header" | "path" | "query";
|
|
19
|
+
required: boolean;
|
|
20
|
+
schema: boolean | object;
|
|
21
|
+
}[] | undefined;
|
|
22
|
+
body?: {
|
|
23
|
+
contentType: string;
|
|
24
|
+
contentTypes?: string[] | undefined;
|
|
25
|
+
required: boolean;
|
|
26
|
+
schema: boolean | object;
|
|
27
|
+
} | undefined;
|
|
28
|
+
responses: Record<string, {
|
|
29
|
+
description: string;
|
|
30
|
+
contentType?: string | undefined;
|
|
31
|
+
schema?: boolean | object | undefined;
|
|
32
|
+
events?: Record<string, boolean | object> | undefined;
|
|
33
|
+
}>;
|
|
34
|
+
}[];
|
|
35
|
+
sockets: {
|
|
36
|
+
id: string;
|
|
37
|
+
scope: "global" | "session" | "workspace";
|
|
38
|
+
description: string;
|
|
39
|
+
availability?: string | undefined;
|
|
40
|
+
service: string;
|
|
41
|
+
member: string;
|
|
42
|
+
direction: "client-to-server" | "server-to-client";
|
|
43
|
+
kind: "channel" | "method" | "state";
|
|
44
|
+
input: boolean | object;
|
|
45
|
+
output?: boolean | object | undefined;
|
|
46
|
+
errors?: boolean | object | undefined;
|
|
47
|
+
}[];
|
|
48
|
+
dynamic: string[];
|
|
49
|
+
gaps?: string[] | undefined;
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
52
|
+
export { apiContracts as default };
|
|
53
|
+
//# sourceMappingURL=apiContracts.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiContracts.d.cts","names":[],"sources":["../../src/schemas/apiContracts.ts"],"mappings":";;qBAGa"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//#region src/schemas/apiContracts.d.ts
|
|
2
|
+
/** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */
|
|
3
|
+
export declare const apiContracts: {
|
|
4
|
+
version: 1;
|
|
5
|
+
protocols?: Record<string, string> | undefined;
|
|
6
|
+
schemas?: Record<string, boolean | object> | undefined;
|
|
7
|
+
http: {
|
|
8
|
+
id: string;
|
|
9
|
+
scope: "global" | "session" | "workspace";
|
|
10
|
+
basePath?: string | undefined;
|
|
11
|
+
path: string;
|
|
12
|
+
method: "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT";
|
|
13
|
+
description: string;
|
|
14
|
+
availability?: string | undefined;
|
|
15
|
+
authentication: "device" | "none" | "owner";
|
|
16
|
+
parameters?: {
|
|
17
|
+
name: string;
|
|
18
|
+
in: "header" | "path" | "query";
|
|
19
|
+
required: boolean;
|
|
20
|
+
schema: boolean | object;
|
|
21
|
+
}[] | undefined;
|
|
22
|
+
body?: {
|
|
23
|
+
contentType: string;
|
|
24
|
+
contentTypes?: string[] | undefined;
|
|
25
|
+
required: boolean;
|
|
26
|
+
schema: boolean | object;
|
|
27
|
+
} | undefined;
|
|
28
|
+
responses: Record<string, {
|
|
29
|
+
description: string;
|
|
30
|
+
contentType?: string | undefined;
|
|
31
|
+
schema?: boolean | object | undefined;
|
|
32
|
+
events?: Record<string, boolean | object> | undefined;
|
|
33
|
+
}>;
|
|
34
|
+
}[];
|
|
35
|
+
sockets: {
|
|
36
|
+
id: string;
|
|
37
|
+
scope: "global" | "session" | "workspace";
|
|
38
|
+
description: string;
|
|
39
|
+
availability?: string | undefined;
|
|
40
|
+
service: string;
|
|
41
|
+
member: string;
|
|
42
|
+
direction: "client-to-server" | "server-to-client";
|
|
43
|
+
kind: "channel" | "method" | "state";
|
|
44
|
+
input: boolean | object;
|
|
45
|
+
output?: boolean | object | undefined;
|
|
46
|
+
errors?: boolean | object | undefined;
|
|
47
|
+
}[];
|
|
48
|
+
dynamic: string[];
|
|
49
|
+
gaps?: string[] | undefined;
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
52
|
+
export { apiContracts as default };
|
|
53
|
+
//# sourceMappingURL=apiContracts.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiContracts.d.mts","names":[],"sources":["../../src/schemas/apiContracts.ts"],"mappings":";;qBAGa"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiContracts.mjs","names":[],"sources":["../../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract } from '@agimon-ai/doompi-core/api-contracts';\n\n/** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */\nexport const apiContracts = defineApiContract({ version: 1, http: [], sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":"yEAGA,MAAa,EAAe,EAAkB,CAAE,QAAS,EAAG,KAAM,CAAC,EAAG,QAAS,CAAC,EAAG,QAAS,CAAC,CAAE,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
let e=require("typebox");const t=
|
|
1
|
+
let e=require("typebox");const t=e.Type.Object({label:e.Type.String({maxLength:60,description:`MAX 60 CHARACTERS, hard limit. Concise option label shown to the user, ideally 1-5 words.`}),description:e.Type.String({description:`Explanation of what the option means and its important trade-offs.`}),preview:e.Type.Optional(e.Type.String({description:`Optional markdown preview rendered while this option is focused.`}))},{additionalProperties:!1}),n=e.Type.Object({question:e.Type.String({description:`The complete, clear question to ask the user.`}),header:e.Type.String({maxLength:16,description:`MAX 16 CHARACTERS, short label used when navigating several questions.`}),options:e.Type.Array(t,{minItems:2,maxItems:4,description:`The 2-4 choices offered for this question.`}),multiSelect:e.Type.Optional(e.Type.Boolean({description:`Allow more than one option to be selected.`,default:!1}))},{additionalProperties:!1}),r=e.Type.Object({questions:e.Type.Array(n,{minItems:1,maxItems:4,description:`Questions to ask the user (1-4 questions).`})},{additionalProperties:!1});exports.OptionSchema=t,exports.QuestionParamsSchema=r,exports.QuestionSchema=n;
|
|
2
2
|
//# sourceMappingURL=questionnaire.cjs.map
|