pi-ask-user-x 0.0.0-stage → 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dogalyir contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,168 @@
1
- # Temporary Holding Version
1
+ # pi-ask-user-x
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Bilingual structured questionnaire extension for the Pi coding agent (`@earendil-works/pi-coding-agent`).
4
+
5
+ ## Overview & Architecture
6
+
7
+ `pi-ask-user-x` provides the `ask_user` tool for interactive user questionnaires, preference elicitation, and architectural decision trees.
8
+
9
+ - **Non-Interception & Tool Separation**: The separate `ask_user_question` plugin is **not intercepted**, patched, or monkey-patched. Models invoke `ask_user` directly to ask structured questions with single or multiple choices, or open freeform input, without global state mutations.
10
+ - **Dual Execution Modes**:
11
+ - **Co-operative with `pi-translate-x`**: When `pi-translate-x` (>=0.1.3) is active and enabled, question headers, prompts, descriptions, and predefined options are dynamically translated into the user's target language via the versioned translation service (`TranslationService`, protocol v1 over `pi.events`). Custom user prose and notes are reverse-translated back to English for the LLM. Translation is a presentation implementation detail—the model tool name, label, and description remain clean and neutral.
12
+ - **Standalone Mode**: When `pi-translate-x` is absent or disabled at launch, `pi-ask-user-x` operates standalone in canonical English without failure. When an active translation service is detected but incompatible, malformed, or fails rediscovery/retry, users are presented with an explicit recovery choice (Retry discovery, Continue in English, or Cancel questionnaire) rather than silently degrading. Once an enabled service is discovered, answer translation obligation is pinned: custom user prose and notes are never submitted raw to the LLM without translation or explicit user recovery choice.
13
+ - **English-Canonical Contract & Stable IDs**: Predefined choices resolve strictly by stable, immutable string identifiers (`id`), completely independent of translated display text or duplicate localized labels. Predefined option choices are never back-translated. The model-facing tool arguments and return results remain strictly canonical English.
14
+ - **Submit-Only Privacy & Persistence**: Only confirmed, submitted questionnaire answers and their durable bilingual display snapshot are persisted to the session transcript (as context-excluded custom entries of type `pi-ask-user-x:questionnaire`). In-progress drafts, uncommitted answers, and cancelled questionnaire sessions are discarded from memory and never written to transcript storage. Persisted records are static; changing translator settings later does not re-translate or mutate session history. Durable transcript records are rendered visually for the human user but excluded from LLM context injection.
15
+
16
+ ## Question Types and Configuration
17
+
18
+ The `ask_user` tool supports 1 to 8 structured questions per invocation:
19
+
20
+ | Question Type | Behavior & Fields |
21
+ |---|---|
22
+ | `single` (default) | Single-select radio choices. Pressing `Enter` selects the option and advances. Allows custom supplemental text alongside selection when `allowCustom: true`. |
23
+ | `multi` | Multi-select checkbox choices. Toggled with `Space`. Enforces optional `minSelections` and `maxSelections` constraints. Allows custom supplemental text when `allowCustom: true`. |
24
+ | `text` | Pure free-form text input. Options are omitted; uses `textPlaceholder`, `textMinLength`, and `textMaxLength`. |
25
+
26
+ - **Options**: Each option defines a unique `id` (e.g. `'postgres'`), display `label`, optional `description`, and optional Markdown `preview`.
27
+ - **Supplemental Custom Input**: When `allowCustom: true` (default for `single` and `multi`), users can press `c` to enter custom text. For single-select questions, custom text is preserved as supplemental qualification alongside the selected choice, rather than a conflicting radio indicator.
28
+ - **Notes**: Supports per-question notes (press `n` on any question row) and global questionnaire notes (edited in the Review tab).
29
+ - **Validation**: Enforces mandatory fields (`required: true`), selection count bounds (`minSelections`, `maxSelections`), and text lengths. Attempted submissions with invalid fields announce warnings and automatically jump focus to the first invalid row.
30
+ - **Explicit Mark-Empty**: Optional questions support explicit blank confirmation (`e` shortcut) to distinguish conscious skips from unvisited rows.
31
+
32
+ ## Terminal UI (TUI) & Layout Responsiveness
33
+
34
+ The TUI component (`QuestionnaireTUIComponent`) provides an accessible, fully responsive terminal interface:
35
+ - **Screen Layouts**: Responsive side-by-side (>= 80 columns), stacked preview (60–80 columns), and compact (< 60 columns) modes.
36
+ - **Height-Bounded Viewport**: Computes `termRows` before checking cached renders, caching terminal height alongside width. Terminal height resizes (e.g. 24 -> 8 -> 4 rows) at the same width reflow immediately without requiring manual `invalidate()`.
37
+ - **Markdown Previews**: Syntax-highlighted code blocks in previews (via public `Markdown` and `getMarkdownTheme()`). Focusable with `p`, scrollable with Up/Down/PageUp/PageDown without clipping.
38
+ - **Review Tab**: Accessible via `Tab`/`Shift-Tab`, listing all question statuses, answers, validation errors, global notes, and submit trigger. Pressing `Enter` on any row jumps directly to edit that question.
39
+ - **Confirmations**:
40
+ - Full submit confirmation (`confirm_submit_full`).
41
+ - Conscious partial submit confirmation (`confirm_submit_partial`), explicitly listing headers and IDs of unanswered questions.
42
+ - Cancellation confirmation (`confirm_cancel`), confirming before discarding draft responses.
43
+ - **Error Recovery**:
44
+ - Display translation failure: `[r]` Retry translation, `[e/Enter]` Continue in English, `[c/Esc]` Cancel questionnaire.
45
+ - Answer translation failure: `[r]` Retry translation, `[e/Enter]` Return to edit drafts, `[c/Esc]` Cancel questionnaire.
46
+ - **Compact Small-Viewport Dialogs**: Early error and confirmation dialogs adapt dynamically to constrained heights (down to height 1) and narrow widths (1, 3, 4, 6, 12 columns). All action choices (`[r]`, `[e/Enter]`, `[c/Esc]` or `[y/Enter]`, `[n/Esc]`) are preserved in discoverable short hints without slicing action lines. Detail messages scroll vertically via Up/Down navigation when viewports are constrained. Truncation uses ANSI-safe width calculations.
47
+
48
+ ## RPC Mode Degradation
49
+
50
+ When running headless or via RPC (`ctx.mode === "rpc"`), interactive terminal components degrade gracefully to standard dialog methods (`ui.select`, `ui.input`, `ui.confirm`). Rich Markdown previews degrade to text label and description hints.
51
+
52
+ ## Installation & Usage
53
+
54
+ ### Installing Published Packages
55
+
56
+ Install the companion questionnaire package directly from npm:
57
+ ```sh
58
+ pi install npm:pi-ask-user-x
59
+ ```
60
+
61
+ When using alongside `pi-translate-x` for bilingual translation support, ensure `pi-translate-x` is at least version `0.1.3`:
62
+ ```sh
63
+ pi install npm:pi-translate-x
64
+ ```
65
+
66
+ ### Source Checkout, Migration, and Release Status
67
+
68
+ - **Tool Name Migration**:
69
+ - In `pi-ask-user-x@0.1.0` (published on npm): The tool was named `bilingual_questionnaire`.
70
+ - In `pi-ask-user-x@0.1.1` (prepared in checkout): The tool is renamed to `ask_user` with label `Ask User` and a neutral model description (`structured questions / choices / freeform`).
71
+ - **Published Tarball vs Source**: Version `0.1.0` of `pi-ask-user-x` is verified public latest on npm (integrity `sha512-MYTZ9F1Ll7DKmyeUtq5iAzBF/r6vwomizfeR2WUjr25KK+si36iHINRgMon5WzUcNkxzjnc/mGeWtnG/d1Mdiw==`, owner `carmelocampos`). Because npm enforces package immutability, version 0.1.0 cannot and will not be republished. Version `0.1.1` is prepared in this repository workspace.
72
+ - **Future Automated Releases**: Subsequent releases will be automated via GitHub Actions workflow `.github/workflows/publish-ask-user.yml` triggered exclusively by published GitHub Releases (`GHrelease.published`) with tag `pi-ask-user-x-v<packageversion>`.
73
+ - **npm Trusted Publisher Configuration**:
74
+ - GitHub repository: `dogalyir/pi-translate-x`
75
+ - Workflow name: `publish-ask-user.yml`
76
+ - Environment name: `npm`
77
+ *(Do not configure the trusted publisher in the npm owner UI until confirmed.)*
78
+
79
+ ### Local Development from Checkout
80
+
81
+ To run or test both extensions locally from this checkout without loading duplicate extensions:
82
+ ```sh
83
+ pi --no-extensions --extension ./src/index.ts --extension ./packages/ask-user/src/index.ts
84
+ ```
85
+
86
+ ## Runnable Schema Example
87
+
88
+ Below is a complete, runnable invocation of `ask_user` demonstrating `single`, `multi`, and `text` question types, markdown previews, supplemental custom text, notes, and selection bounds:
89
+
90
+ ```json
91
+ {
92
+ "title": "System Architecture Decisions",
93
+ "description": "Please specify preferences for storage, caching, and custom deployment requirements.",
94
+ "notes": "Decisions will be recorded in ADR-004.",
95
+ "questions": [
96
+ {
97
+ "id": "database_engine",
98
+ "header": "Database",
99
+ "prompt": "Which primary database engine should the microservices utilize?",
100
+ "description": "Consider ACID guarantees, relational consistency, and read/write access patterns.",
101
+ "type": "single",
102
+ "required": true,
103
+ "allowCustom": true,
104
+ "options": [
105
+ {
106
+ "id": "postgresql",
107
+ "label": "PostgreSQL",
108
+ "description": "Relational database with JSONB support, strict ACID compliance, and robust extension ecosystem.",
109
+ "preview": "```sql\nCREATE TABLE tenants (\n id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n name TEXT NOT NULL,\n created_at TIMESTAMPTZ DEFAULT now()\n);\n```"
110
+ },
111
+ {
112
+ "id": "mongodb",
113
+ "label": "MongoDB",
114
+ "description": "Document-oriented database optimized for flexible schemas and horizontal sharding.",
115
+ "preview": "```javascript\ndb.tenants.insertOne({\n name: 'Acme Corp',\n createdAt: new Date()\n});\n```"
116
+ }
117
+ ]
118
+ },
119
+ {
120
+ "id": "caching_layer",
121
+ "header": "Cache",
122
+ "prompt": "Select caching technologies to support high-throughput read operations:",
123
+ "type": "multi",
124
+ "required": false,
125
+ "minSelections": 1,
126
+ "maxSelections": 2,
127
+ "allowCustom": true,
128
+ "options": [
129
+ {
130
+ "id": "redis",
131
+ "label": "Redis",
132
+ "description": "In-memory data store supporting pub/sub, clustering, and rich data structures."
133
+ },
134
+ {
135
+ "id": "memcached",
136
+ "label": "Memcached",
137
+ "description": "Simple multithreaded key-value cache."
138
+ }
139
+ ]
140
+ },
141
+ {
142
+ "id": "compliance_notes",
143
+ "header": "Compliance",
144
+ "prompt": "Specify any regulatory or data residency constraints (e.g. GDPR, HIPAA, FedRAMP):",
145
+ "type": "text",
146
+ "required": false,
147
+ "textPlaceholder": "e.g. EU data residency required; logs retained for 90 days max.",
148
+ "textMaxLength": 1000
149
+ }
150
+ ]
151
+ }
152
+ ```
153
+
154
+ ## Testing & Verification Limits
155
+
156
+ Automated test suites pass deterministically using headless Vitest assertions, mock terminal renderers, and simulated event busses. **No manual assistive technology (AT), hardware cursor, screen-reader, or live terminal/provider verification is claimed.** Manual terminal inspection remains required for physical terminal emulator quirks.
157
+
158
+ ## Documentation & Monorepo Links
159
+
160
+ For additional architectural details and guides, see the repository documentation:
161
+ - [Questionnaire Guide](https://github.com/dogalyir/pi-translate-x/blob/main/docs/questionnaire.md)
162
+ - [Translation Pipeline Guide](https://github.com/dogalyir/pi-translate-x/blob/main/docs/translation.md)
163
+ - [Release Operations & Verification](https://github.com/dogalyir/pi-translate-x/blob/main/docs/releases.md)
164
+ - [Monorepo Documentation Index](https://github.com/dogalyir/pi-translate-x/blob/main/docs/index.md)
165
+
166
+ ## License
167
+
168
+ MIT
package/package.json CHANGED
@@ -1,6 +1,53 @@
1
1
  {
2
2
  "name": "pi-ask-user-x",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "Bilingual structured questionnaire extension for Pi coding agent",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/dogalyir/pi-translate-x.git",
9
+ "directory": "packages/ask-user"
10
+ },
11
+ "publishConfig": {
12
+ "access": "public",
13
+ "provenance": true
14
+ },
15
+ "keywords": [
16
+ "pi-package",
17
+ "pi-extension"
18
+ ],
19
+ "type": "module",
20
+ "files": [
21
+ "src",
22
+ "README.md",
23
+ "LICENSE"
24
+ ],
25
+ "pi": {
26
+ "extensions": [
27
+ "./src/index.ts"
28
+ ]
29
+ },
30
+ "scripts": {
31
+ "test": "vitest run",
32
+ "typecheck": "tsc --noEmit",
33
+ "check": "npm run typecheck && npm test",
34
+ "pack:dry": "npm pack --dry-run"
35
+ },
36
+ "peerDependencies": {
37
+ "@earendil-works/pi-ai": "*",
38
+ "@earendil-works/pi-agent-core": "*",
39
+ "@earendil-works/pi-coding-agent": "*",
40
+ "@earendil-works/pi-tui": "*",
41
+ "typebox": "*"
42
+ },
43
+ "devDependencies": {
44
+ "@earendil-works/pi-ai": "1.4.0",
45
+ "@earendil-works/pi-agent-core": "1.4.0",
46
+ "@earendil-works/pi-coding-agent": "1.4.0",
47
+ "@earendil-works/pi-tui": "1.4.0",
48
+ "@types/node": "22.15.30",
49
+ "typescript": "5.8.3",
50
+ "vitest": "5.0.5",
51
+ "typebox": "1.3.27"
52
+ }
53
+ }
@@ -0,0 +1,109 @@
1
+ export interface UIChromeStrings {
2
+ readonly reviewAndSubmit: string;
3
+ readonly reviewTitle: string;
4
+ readonly reviewHint: string;
5
+ readonly answeredBadge: string;
6
+ readonly missingRequiredBadge: string;
7
+ readonly skippedOptionalBadge: string;
8
+ readonly globalNotesLabel: string;
9
+ readonly customLabel: string;
10
+ readonly noteLabel: string;
11
+ readonly submitAnswers: string;
12
+ readonly submitIncomplete: string;
13
+ readonly submitPartial: string;
14
+ readonly confirmCancelTitle: string;
15
+ readonly confirmCancelPrompt: string;
16
+ readonly confirmCancelYes: string;
17
+ readonly confirmCancelNo: string;
18
+ readonly confirmSubmitTitle: string;
19
+ readonly confirmSubmitPrompt: string;
20
+ readonly confirmSubmitYes: string;
21
+ readonly confirmSubmitNo: string;
22
+ readonly retryTranslation: string;
23
+ readonly continueInEnglish: string;
24
+ readonly cancelQuestionnaire: string;
25
+ readonly retryAnswers: string;
26
+ readonly returnToEdit: string;
27
+ readonly previewHeader: string;
28
+ readonly noPreview: string;
29
+ readonly addGlobalNotesPrompt: string;
30
+ readonly addQuestionNotesPrompt: string;
31
+ readonly typeCustomPlaceholder: string;
32
+ readonly footerNav: string;
33
+ readonly footerEdit: string;
34
+ readonly emptySelectionConfirm: string;
35
+ readonly skipQuestion: string;
36
+ readonly doneSelections: string;
37
+ readonly backQuestion: string;
38
+ readonly confirmPartialTitle: string;
39
+ readonly submitAnyway: string;
40
+ readonly validationFailed: string;
41
+ readonly requiredBadge: string;
42
+ readonly optionalBadge: string;
43
+ readonly markEmpty: string;
44
+ readonly clearNote: string;
45
+ readonly clearCustom: string;
46
+ readonly togglePreview: string;
47
+ readonly toggleOptions: string;
48
+ readonly submitConfirmTitle: string;
49
+ readonly scrollUpMore: string;
50
+ readonly scrollDownMore: string;
51
+ readonly previewFocusHint: string;
52
+ readonly previewScrollHint: string;
53
+ readonly previewCollapseHint: string;
54
+ }
55
+
56
+ export const DEFAULT_EN_CHROME: UIChromeStrings = {
57
+ reviewAndSubmit: "Review & Submit",
58
+ reviewTitle: "Review & Submit Answers",
59
+ reviewHint: "Press [Enter] on any question row to jump back and edit it.",
60
+ answeredBadge: "✓ Answered",
61
+ missingRequiredBadge: "* Missing - Required",
62
+ skippedOptionalBadge: "○ Skipped - Optional",
63
+ globalNotesLabel: "Global Notes",
64
+ customLabel: "Custom",
65
+ noteLabel: "Note",
66
+ submitAnswers: "Submit Answers",
67
+ submitIncomplete: "Incomplete - Fix Required Questions Above",
68
+ submitPartial: "Submit Partial Answers (Unanswered Remain)",
69
+ confirmCancelTitle: "Are you sure you want to cancel?",
70
+ confirmCancelPrompt: "All entered answers and drafts will be discarded.",
71
+ confirmCancelYes: "Confirm cancel",
72
+ confirmCancelNo: "Keep editing",
73
+ confirmSubmitTitle: "Ready to Submit Questionnaire",
74
+ confirmSubmitPrompt: "All required questions have been answered. Confirm submission?",
75
+ confirmSubmitYes: "Submit answers",
76
+ confirmSubmitNo: "Keep editing",
77
+ retryTranslation: "Retry translation",
78
+ continueInEnglish: "Continue in English",
79
+ cancelQuestionnaire: "Cancel questionnaire",
80
+ retryAnswers: "Retry translating answers",
81
+ returnToEdit: "Return to edit drafts",
82
+ previewHeader: "Preview",
83
+ noPreview: "(No preview available)",
84
+ addGlobalNotesPrompt: "(Press Enter to add overall questionnaire notes...)",
85
+ addQuestionNotesPrompt: "(Add a note for this question...)",
86
+ typeCustomPlaceholder: "(Type custom answer...)",
87
+ footerNav: "[Tab/Shift-Tab] Switch Question [↑/↓] Navigate [PgUp/PgDn] Page [p] Preview [Space] Select [Enter] Action [Esc] Cancel",
88
+ footerEdit: "[Enter] Confirm input [Esc] Revert/cancel input",
89
+ emptySelectionConfirm: "[Empty] Confirm empty selection",
90
+ skipQuestion: "⏭ Skip this question",
91
+ doneSelections: "✔ Done (confirm selections)",
92
+ backQuestion: "← Back to previous question",
93
+ confirmPartialTitle: "Confirm partial submission?",
94
+ submitAnyway: "Submit anyway?",
95
+ validationFailed: "Validation failed: fix invalid fields",
96
+ requiredBadge: "*required",
97
+ optionalBadge: "optional",
98
+ markEmpty: "Explicit empty selection (mark blank)",
99
+ clearNote: "Clear note",
100
+ clearCustom: "Clear custom text",
101
+ togglePreview: "Toggle preview",
102
+ toggleOptions: "Toggle options",
103
+ submitConfirmTitle: "Submit questionnaire answers?",
104
+ scrollUpMore: "▲ (scroll up for more)",
105
+ scrollDownMore: "▼ (scroll down for more)",
106
+ previewFocusHint: "Press [p] to focus preview",
107
+ previewScrollHint: "[↑/↓/PgUp/PgDn] Scroll preview [Esc/p] Return to controls",
108
+ previewCollapseHint: "Press [p] to collapse preview",
109
+ };