@mrclrchtr/supi-ask-user 1.3.1 → 1.5.0
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 +163 -67
- package/node_modules/@mrclrchtr/supi-core/README.md +52 -41
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/api.ts +15 -13
- package/node_modules/@mrclrchtr/supi-core/src/{config-settings.ts → config/config-settings.ts} +2 -2
- package/node_modules/@mrclrchtr/supi-core/src/{context-provider-registry.ts → context/context-provider-registry.ts} +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/extension.ts +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/index.ts +15 -13
- package/node_modules/@mrclrchtr/supi-core/src/path-utils.ts +40 -0
- package/node_modules/@mrclrchtr/supi-core/src/registry-utils.ts +42 -10
- package/node_modules/@mrclrchtr/supi-core/src/{settings-registry.ts → settings/settings-registry.ts} +1 -1
- package/package.json +2 -2
- package/src/api.ts +19 -0
- package/src/ask-user.ts +71 -131
- package/src/index.ts +23 -1
- package/src/normalize.ts +153 -142
- package/src/render/result.ts +102 -0
- package/src/render/transcript.ts +65 -0
- package/src/render/tree-summary.ts +10 -0
- package/src/schema.ts +41 -38
- package/src/session/controller.ts +281 -0
- package/src/session/lock.ts +19 -0
- package/src/tool/guidance.ts +15 -0
- package/src/types.ts +56 -55
- package/src/ui/choose-renderer.ts +11 -0
- package/src/ui/overlay-actions.ts +42 -0
- package/src/ui/overlay-component.ts +400 -0
- package/src/ui/overlay-render.ts +219 -0
- package/src/ui/overlay-view.ts +313 -0
- package/src/ui/overlay.ts +28 -0
- package/src/ui/types.ts +38 -0
- package/src/flow.ts +0 -224
- package/src/format.ts +0 -66
- package/src/render/ui-rich-render-editor.ts +0 -51
- package/src/render/ui-rich-render-env.ts +0 -15
- package/src/render/ui-rich-render-footer.ts +0 -55
- package/src/render/ui-rich-render-markdown.ts +0 -33
- package/src/render/ui-rich-render-notes.ts +0 -80
- package/src/render/ui-rich-render-types.ts +0 -17
- package/src/render/ui-rich-render.ts +0 -323
- package/src/render.ts +0 -95
- package/src/result.ts +0 -90
- package/src/ui/ui-rich-handlers.ts +0 -369
- package/src/ui/ui-rich-inline.ts +0 -77
- package/src/ui/ui-rich-state.ts +0 -179
- package/src/ui/ui-rich.ts +0 -144
- /package/node_modules/@mrclrchtr/supi-core/src/{config.ts → config/config.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-core/src/{context-messages.ts → context/context-messages.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-core/src/{context-tag.ts → context/context-tag.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-core/src/{settings-command.ts → settings/settings-command.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-core/src/{settings-ui.ts → settings/settings-ui.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @mrclrchtr/supi-ask-user
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Adds a redesigned `ask_user` tool to the [pi coding agent](https://github.com/earendil-works/pi). It lets the model pause and request a small decision form when explicit human input is required.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -14,34 +14,153 @@ For local development:
|
|
|
14
14
|
pi install ./packages/supi-ask-user
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
After editing the source, run `/reload
|
|
17
|
+
After editing the source, run `/reload`.
|
|
18
18
|
|
|
19
|
-
## What
|
|
19
|
+
## What you get
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
After install, pi gets one new tool:
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
- **`ask_user`** — open a blocking decision form during a run
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|------|-----|
|
|
27
|
-
| `choice` | Pick one option (default) or multiple options (`multi: true`) from a list |
|
|
28
|
-
| `text` | Freeform text input |
|
|
25
|
+
The tool presents a structured questionnaire in the TUI overlay and blocks the agent turn until the user responds. It is designed for focused decisions, **not** long surveys or open-ended discovery.
|
|
29
26
|
|
|
30
|
-
|
|
27
|
+
Typical use cases:
|
|
31
28
|
|
|
32
|
-
|
|
29
|
+
- Clarify a narrow implementation choice
|
|
30
|
+
- Confirm a risky or destructive action
|
|
31
|
+
- Ask for a preference the repo cannot answer
|
|
32
|
+
- Gather one short cluster of related decisions before proceeding
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
- Only one questionnaire runs at a time — concurrent `ask_user` calls return an error.
|
|
36
|
-
- Cancelling or closing the overlay aborts the current agent turn.
|
|
37
|
-
- Completed answers appear as a readable summary entry in the `/tree` view.
|
|
34
|
+
## Package surfaces
|
|
38
35
|
|
|
39
|
-
|
|
36
|
+
- `@mrclrchtr/supi-ask-user/extension` — pi extension entrypoint, registers the `ask_user` tool
|
|
37
|
+
- `@mrclrchtr/supi-ask-user/api` — reusable types and utilities
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
Example:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { normalizeQuestionnaire, AskUserController } from "@mrclrchtr/supi-ask-user/api";
|
|
43
|
+
|
|
44
|
+
const questionnaire = normalizeQuestionnaire(params);
|
|
45
|
+
const controller = new AskUserController(questionnaire);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Request shape
|
|
49
|
+
|
|
50
|
+
`ask_user` accepts a small form with optional framing text:
|
|
51
|
+
|
|
52
|
+
| Field | Type | Description |
|
|
53
|
+
|-------|------|-------------|
|
|
54
|
+
| `title` | string (optional) | Short overall title for the form |
|
|
55
|
+
| `intro` | string (optional) | Why the agent is asking |
|
|
56
|
+
| `questions` | array (1–4) | Choice or text questions |
|
|
57
|
+
| `allowPartialSubmit` | boolean (optional) | Let the user submit partial progress |
|
|
58
|
+
| `allowDiscuss` | boolean (optional) | Let the user switch back into discussion instead of giving a final decision |
|
|
59
|
+
|
|
60
|
+
## Questions
|
|
61
|
+
|
|
62
|
+
Each question has a `type`, `id`, `header`, and `prompt`. Two question types are supported:
|
|
63
|
+
|
|
64
|
+
### `choice` — fixed options
|
|
65
|
+
|
|
66
|
+
| Field | Type | Description |
|
|
67
|
+
|-------|------|-------------|
|
|
68
|
+
| `options` | array (2–12) | Allowed answers with `value`, `label`, and optional `description`/`preview` |
|
|
69
|
+
| `required` | boolean (default: `true`) | Whether this question must be answered |
|
|
70
|
+
| `multi` | boolean (default: `false`) | Allow selecting multiple options |
|
|
71
|
+
| `allowOther` | boolean | Allow a freeform answer instead of listed options. Single-select only. |
|
|
72
|
+
| `recommendation` | string \| string[] | Recommended option value(s) |
|
|
73
|
+
| `initial` | string \| string[] | Initially selected option value(s) |
|
|
74
|
+
|
|
75
|
+
Model yes/no questions as a `choice` with `{ value: "yes", label: "Yes" }` and `{ value: "no", label: "No" }`.
|
|
76
|
+
|
|
77
|
+
### `text` — freeform input
|
|
78
|
+
|
|
79
|
+
| Field | Type | Description |
|
|
80
|
+
|-------|------|-------------|
|
|
81
|
+
| `required` | boolean (default: `true`) | Whether this question must be answered |
|
|
82
|
+
| `initial` | string | Initial value shown in the editor |
|
|
83
|
+
| `placeholder` | string | Placeholder shown before the user types |
|
|
84
|
+
|
|
85
|
+
## Result
|
|
86
|
+
|
|
87
|
+
A completed form returns a result with `details.status` set to one of:
|
|
88
|
+
|
|
89
|
+
| Status | Meaning |
|
|
90
|
+
|--------|---------|
|
|
91
|
+
| `submitted` | Full submit, all required questions answered |
|
|
92
|
+
| `partial` | Partial submit with some required questions unanswered |
|
|
93
|
+
| `discuss` | User wants to continue the conversation instead of deciding |
|
|
94
|
+
| `cancelled` | User explicitly cancelled (aborts the current agent turn) |
|
|
95
|
+
| `aborted` | The interaction was aborted externally (aborts the current agent turn) |
|
|
96
|
+
|
|
97
|
+
`details.answersById` maps question IDs to their answers. Each answer has a `kind` and type-specific data:
|
|
98
|
+
|
|
99
|
+
- `{ kind: "choice", selections: [{ value, label, note? }] }` — single or multi-select choice, with optional per-option user notes
|
|
100
|
+
- `{ kind: "custom", value: "..." }` — freeform `allowOther` answer
|
|
101
|
+
- `{ kind: "text", value: "..." }` — freeform text answer
|
|
102
|
+
|
|
103
|
+
`details.missingQuestionIds` lists any required questions that were left unanswered on a partial submit.
|
|
104
|
+
|
|
105
|
+
## Behavior
|
|
106
|
+
|
|
107
|
+
- Requires pi in interactive (TUI) mode with custom overlay support — no degraded fallback
|
|
108
|
+
- Only one `ask_user` form may be active at a time; calling `ask_user` while another form is in flight returns an error
|
|
109
|
+
- Cancellation or abort stops the current agent turn
|
|
110
|
+
- Completed forms are summarized in the session tree
|
|
111
|
+
- Do not use `ask_user` for open-ended interviews or repo facts the agent can discover on its own
|
|
112
|
+
|
|
113
|
+
## Tool guidance
|
|
114
|
+
|
|
115
|
+
The tool registers the following prompt guidance that the model sees:
|
|
116
|
+
|
|
117
|
+
- Use ask_user only when explicit user input is required to proceed safely; do not use ask_user for open-ended interviews or repo facts.
|
|
118
|
+
- Use ask_user with 1-4 related questions; prefer one when possible.
|
|
119
|
+
- Use ask_user `choice` for fixed options and ask_user `text` for freeform input; model yes/no as `choice` with `{ value: "yes", label: "Yes" }` and `{ value: "no", label: "No" }`.
|
|
120
|
+
- Use ask_user `allowOther` only on single-select `choice` questions.
|
|
121
|
+
- Use ask_user `allowDiscuss` or `allowPartialSubmit` only when that outcome is actionable.
|
|
122
|
+
- Do not call ask_user while another ask_user form is already in flight.
|
|
123
|
+
|
|
124
|
+
## UI controls
|
|
125
|
+
|
|
126
|
+
### Choice questions
|
|
127
|
+
|
|
128
|
+
- `↑↓` — move between options
|
|
129
|
+
- `Space` — select the focused option (single-select) or toggle (multi-select)
|
|
130
|
+
- `Enter` — submit the current answer
|
|
131
|
+
- `n` — edit a note for the focused choice option
|
|
132
|
+
- `←` — go back to the previous question
|
|
133
|
+
- `Esc` — cancel the whole form (or close the note editor if one is open)
|
|
134
|
+
|
|
135
|
+
On wide terminals, option previews render side-by-side with the option list. On narrow terminals, previews stack below.
|
|
136
|
+
|
|
137
|
+
Notes are available only for real `choice` options. They do not apply to `text` questions, `Other…` freeform answers, or other exceptional action rows. Saving a non-empty note selects the option if needed; clearing a note leaves the current selection alone; deselecting a multi-select option removes its note with the selection.
|
|
138
|
+
|
|
139
|
+
Only exceptional action rows are visible:
|
|
140
|
+
|
|
141
|
+
- `Other…` — when `allowOther` is enabled
|
|
142
|
+
- `Discuss instead…` — when `allowDiscuss` is enabled
|
|
143
|
+
- `Submit partial answers` — when `allowPartialSubmit` is enabled
|
|
144
|
+
- `Skip question` — for optional questions
|
|
145
|
+
|
|
146
|
+
Back and cancel are keyboard-only (`←`, `Esc`) — no visible rows.
|
|
147
|
+
|
|
148
|
+
### Text questions
|
|
149
|
+
|
|
150
|
+
- The editor is visible immediately (no separate entry row)
|
|
151
|
+
- `Enter` — submit the current text
|
|
152
|
+
- `↓` — move from the editor into visible exceptional action rows
|
|
153
|
+
- `↑` — from the first action row, return focus to the editor
|
|
154
|
+
- `Esc` — cancel the whole form
|
|
155
|
+
|
|
156
|
+
Exceptional action rows (`Discuss instead…`, `Submit partial answers`) may appear below the editor when those paths are enabled.
|
|
157
|
+
|
|
158
|
+
## Example
|
|
42
159
|
|
|
43
160
|
```json
|
|
44
161
|
{
|
|
162
|
+
"title": "Formatter decision",
|
|
163
|
+
"intro": "I need one explicit choice before I update the repo config.",
|
|
45
164
|
"questions": [
|
|
46
165
|
{
|
|
47
166
|
"type": "choice",
|
|
@@ -53,63 +172,40 @@ The agent decides when to call `ask_user`. You control how it's used through the
|
|
|
53
172
|
{ "value": "prettier", "label": "Prettier" }
|
|
54
173
|
],
|
|
55
174
|
"recommendation": "biome",
|
|
56
|
-
"
|
|
175
|
+
"initial": "biome"
|
|
57
176
|
},
|
|
58
177
|
{
|
|
59
178
|
"type": "text",
|
|
60
179
|
"id": "reason",
|
|
61
180
|
"header": "Reason",
|
|
62
|
-
"prompt": "
|
|
63
|
-
"
|
|
181
|
+
"prompt": "Anything I should optimize for?",
|
|
182
|
+
"required": false,
|
|
183
|
+
"placeholder": "optional"
|
|
64
184
|
}
|
|
65
|
-
]
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
**Multi-select example:**
|
|
70
|
-
|
|
71
|
-
```json
|
|
72
|
-
{
|
|
73
|
-
"type": "choice",
|
|
74
|
-
"multi": true,
|
|
75
|
-
"id": "features",
|
|
76
|
-
"header": "Features",
|
|
77
|
-
"prompt": "Which features to include?",
|
|
78
|
-
"options": [
|
|
79
|
-
{ "value": "auth", "label": "Authentication" },
|
|
80
|
-
{ "value": "caching", "label": "Caching" },
|
|
81
|
-
{ "value": "logging", "label": "Logging" }
|
|
82
185
|
],
|
|
83
|
-
"
|
|
186
|
+
"allowDiscuss": true
|
|
84
187
|
}
|
|
85
188
|
```
|
|
86
189
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
- `
|
|
90
|
-
- `
|
|
91
|
-
- `
|
|
92
|
-
- `
|
|
93
|
-
- `
|
|
94
|
-
- `
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
- `
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
- `@earendil-works/pi-coding-agent`
|
|
110
|
-
- `@earendil-works/pi-tui`
|
|
111
|
-
- `typebox`
|
|
112
|
-
|
|
113
|
-
## Source
|
|
114
|
-
|
|
115
|
-
Entrypoint: `src/ask-user.ts` — registers the `ask_user` tool, drives the questionnaire overlay, and manages the concurrency lock.
|
|
190
|
+
## Source layout
|
|
191
|
+
|
|
192
|
+
- `src/extension.ts` — pi extension entrypoint
|
|
193
|
+
- `src/api.ts` — reusable public surface
|
|
194
|
+
- `src/index.ts` — package barrel
|
|
195
|
+
- `src/ask-user.ts` — tool registration and execution boundary
|
|
196
|
+
- `src/schema.ts` — tool-call parameter schema (TypeBox)
|
|
197
|
+
- `src/types.ts` — internal normalized types and answer shapes
|
|
198
|
+
- `src/normalize.ts` — validation and lowering into internal types
|
|
199
|
+
- `src/tool/guidance.ts` — prompt guidance and tool description
|
|
200
|
+
- `src/session/controller.ts` — headless decision-form state machine
|
|
201
|
+
- `src/session/lock.ts` — session-scoped concurrency lock
|
|
202
|
+
- `src/ui/choose-renderer.ts` — custom-overlay capability gate
|
|
203
|
+
- `src/ui/overlay.ts` — overlay runner that creates the custom interaction session
|
|
204
|
+
- `src/ui/overlay-component.ts` — rich custom interaction state and input orchestration
|
|
205
|
+
- `src/ui/overlay-view.ts` — choice/action row modeling and split-layout helpers
|
|
206
|
+
- `src/ui/overlay-render.ts` — rich overlay rendering built on `Markdown`, `Editor`, and `SelectList`
|
|
207
|
+
- `src/ui/overlay-actions.ts` — exceptional-action list wiring for text questions
|
|
208
|
+
- `src/ui/types.ts` — shared UI runner types
|
|
209
|
+
- `src/render/result.ts` — tool result shaping
|
|
210
|
+
- `src/render/transcript.ts` — transcript rendering
|
|
211
|
+
- `src/render/tree-summary.ts` — session-tree summary labels
|
|
@@ -1,65 +1,78 @@
|
|
|
1
1
|
# @mrclrchtr/supi-core
|
|
2
2
|
|
|
3
|
-
Shared infrastructure for SuPi
|
|
3
|
+
Shared infrastructure for SuPi extensions.
|
|
4
|
+
|
|
5
|
+
This package is mainly for extension authors. It gives you a common config system, settings plumbing, context helpers, registries, and a small extension surface that registers `/supi-settings`.
|
|
4
6
|
|
|
5
7
|
## Install
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
### As a dependency for another extension
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
12
|
pnpm add @mrclrchtr/supi-core
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
`@mrclrchtr/supi-core` now has two explicit surfaces:
|
|
15
|
+
### As a pi package
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
`pi.extensions` still points at the real file path `./src/extension.ts` inside the package. The `/api` and `/extension` paths are consumer-facing package exports, not manifest aliases.
|
|
17
|
+
```bash
|
|
18
|
+
pi install npm:@mrclrchtr/supi-core
|
|
19
|
+
```
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
Installing it as a pi package adds the minimal `/supi-settings` extension surface.
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
## Package surfaces
|
|
25
24
|
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
- the shared settings registry, overlay UI, and `registerSettingsCommand()` helper
|
|
29
|
-
- XML `<extension-context>` wrapping plus context-message utilities
|
|
30
|
-
- context-provider and debug-event registries reused across SuPi packages
|
|
31
|
-
- project root and path helpers reused by packages such as `supi-lsp`
|
|
25
|
+
- `@mrclrchtr/supi-core/api` — reusable helpers for other packages and extensions
|
|
26
|
+
- `@mrclrchtr/supi-core/extension` — minimal pi extension that registers `/supi-settings`
|
|
32
27
|
|
|
33
|
-
##
|
|
28
|
+
## What you get from the API
|
|
34
29
|
|
|
35
|
-
Config
|
|
30
|
+
### Config helpers
|
|
36
31
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
- `loadSupiConfig()` — merged config with resolution order `defaults <- global <- project`
|
|
33
|
+
- `loadSupiConfigForScope()` — load one scope at a time for settings UIs
|
|
34
|
+
- `writeSupiConfig()` — persist values
|
|
35
|
+
- `removeSupiConfigKey()` — remove a key or override
|
|
40
36
|
|
|
41
37
|
Config file locations:
|
|
42
38
|
|
|
43
39
|
- global: `~/.pi/agent/supi/config.json`
|
|
44
40
|
- project: `.pi/supi/config.json`
|
|
45
41
|
|
|
46
|
-
|
|
42
|
+
### Settings helpers
|
|
43
|
+
|
|
44
|
+
- `registerSettings()` — register an arbitrary settings section
|
|
45
|
+
- `registerConfigSettings()` — register a config-backed settings section with scoped persistence helpers
|
|
46
|
+
- `registerSettingsCommand()` — register `/supi-settings`
|
|
47
|
+
- `openSettingsOverlay()` — open the shared settings UI directly
|
|
48
|
+
- `createInputSubmenu()` — helper for simple text-entry submenus
|
|
49
|
+
|
|
50
|
+
The built-in settings UI supports:
|
|
47
51
|
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
- `removeSupiConfigKey()`
|
|
52
|
-
- `registerConfigSettings()`
|
|
52
|
+
- project/global scope toggle
|
|
53
|
+
- grouped extension sections
|
|
54
|
+
- searchable setting lists
|
|
53
55
|
|
|
54
|
-
|
|
56
|
+
### Context helpers
|
|
55
57
|
|
|
56
|
-
- `wrapExtensionContext()`
|
|
58
|
+
- `wrapExtensionContext()` — wrap injected text in SuPi's `<extension-context>` tag
|
|
57
59
|
- `findLastUserMessageIndex()`
|
|
58
60
|
- `getContextToken()`
|
|
61
|
+
- `getPromptContent()`
|
|
59
62
|
- `pruneAndReorderContextMessages()`
|
|
60
|
-
- `
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
- `restorePromptContent()`
|
|
64
|
+
|
|
65
|
+
### Shared registries
|
|
66
|
+
|
|
67
|
+
- context-provider registry for `/supi-context`
|
|
68
|
+
- debug-event registry for producers that want shared debug capture
|
|
69
|
+
- settings registry used by `/supi-settings`
|
|
70
|
+
|
|
71
|
+
### Project and session helpers
|
|
72
|
+
|
|
73
|
+
- project-root detection and directory walking helpers such as `findProjectRoot()` and `walkProject()`
|
|
74
|
+
- active-branch session helper: `getActiveBranchEntries()`
|
|
75
|
+
- terminal helpers such as `formatTitle()`, `signalWaiting()`, and `signalDone()`
|
|
63
76
|
|
|
64
77
|
## Example
|
|
65
78
|
|
|
@@ -80,17 +93,15 @@ registerConfigSettings({
|
|
|
80
93
|
});
|
|
81
94
|
|
|
82
95
|
const message = wrapExtensionContext("my-extension", "hello", {
|
|
83
|
-
turn: 1,
|
|
84
96
|
file: "CLAUDE.md",
|
|
97
|
+
turn: 1,
|
|
85
98
|
});
|
|
86
99
|
```
|
|
87
100
|
|
|
88
|
-
## Requirements
|
|
89
|
-
|
|
90
|
-
- `@earendil-works/pi-coding-agent`
|
|
91
|
-
- `@earendil-works/pi-tui`
|
|
92
|
-
|
|
93
101
|
## Source
|
|
94
102
|
|
|
95
|
-
-
|
|
96
|
-
-
|
|
103
|
+
- `src/api.ts` — exported library surface
|
|
104
|
+
- `src/extension.ts` — minimal `/supi-settings` entrypoint
|
|
105
|
+
- `src/config.ts` — shared config loading and writing
|
|
106
|
+
- `src/config-settings.ts` — config-backed settings registration helper
|
|
107
|
+
- `src/settings-ui.ts` — shared settings overlay
|
|
@@ -2,30 +2,30 @@
|
|
|
2
2
|
// Provides XML context tag wrapping, unified config system, context-message utilities,
|
|
3
3
|
// and settings registry for supi-wide TUI settings.
|
|
4
4
|
|
|
5
|
-
export type { SupiConfigLocation, SupiConfigOptions } from "./config.ts";
|
|
5
|
+
export type { SupiConfigLocation, SupiConfigOptions } from "./config/config.ts";
|
|
6
6
|
export {
|
|
7
7
|
loadSupiConfig,
|
|
8
8
|
loadSupiConfigForScope,
|
|
9
9
|
removeSupiConfigKey,
|
|
10
10
|
writeSupiConfig,
|
|
11
|
-
} from "./config.ts";
|
|
12
|
-
export type { ConfigSettingsHelpers, ConfigSettingsOptions } from "./config-settings.ts";
|
|
13
|
-
export { registerConfigSettings } from "./config-settings.ts";
|
|
14
|
-
export type { ContextMessageLike } from "./context-messages.ts";
|
|
11
|
+
} from "./config/config.ts";
|
|
12
|
+
export type { ConfigSettingsHelpers, ConfigSettingsOptions } from "./config/config-settings.ts";
|
|
13
|
+
export { registerConfigSettings } from "./config/config-settings.ts";
|
|
14
|
+
export type { ContextMessageLike } from "./context/context-messages.ts";
|
|
15
15
|
export {
|
|
16
16
|
findLastUserMessageIndex,
|
|
17
17
|
getContextToken,
|
|
18
18
|
getPromptContent,
|
|
19
19
|
pruneAndReorderContextMessages,
|
|
20
20
|
restorePromptContent,
|
|
21
|
-
} from "./context-messages.ts";
|
|
22
|
-
export type { ContextProvider } from "./context-provider-registry.ts";
|
|
21
|
+
} from "./context/context-messages.ts";
|
|
22
|
+
export type { ContextProvider } from "./context/context-provider-registry.ts";
|
|
23
23
|
export {
|
|
24
24
|
clearRegisteredContextProviders,
|
|
25
25
|
getRegisteredContextProviders,
|
|
26
26
|
registerContextProvider,
|
|
27
|
-
} from "./context-provider-registry.ts";
|
|
28
|
-
export { wrapExtensionContext } from "./context-tag.ts";
|
|
27
|
+
} from "./context/context-provider-registry.ts";
|
|
28
|
+
export { wrapExtensionContext } from "./context/context-tag.ts";
|
|
29
29
|
export type {
|
|
30
30
|
DebugAgentAccess,
|
|
31
31
|
DebugEvent,
|
|
@@ -49,6 +49,7 @@ export {
|
|
|
49
49
|
redactDebugData,
|
|
50
50
|
resetDebugRegistry,
|
|
51
51
|
} from "./debug-registry.ts";
|
|
52
|
+
export { fileToUri, resolveToolPath, stripToolPathPrefix, uriToFile } from "./path-utils.ts";
|
|
52
53
|
export type { KnownRootEntry } from "./project-roots.ts";
|
|
53
54
|
export {
|
|
54
55
|
buildKnownRootsMap,
|
|
@@ -63,15 +64,16 @@ export {
|
|
|
63
64
|
sortRootsBySpecificity,
|
|
64
65
|
walkProject,
|
|
65
66
|
} from "./project-roots.ts";
|
|
67
|
+
export { createRegistry, createSessionStateRegistry } from "./registry-utils.ts";
|
|
66
68
|
export { getActiveBranchEntries } from "./session-utils.ts";
|
|
67
|
-
export { registerSettingsCommand } from "./settings-command.ts";
|
|
68
|
-
export type { SettingsScope, SettingsSection } from "./settings-registry.ts";
|
|
69
|
+
export { registerSettingsCommand } from "./settings/settings-command.ts";
|
|
70
|
+
export type { SettingsScope, SettingsSection } from "./settings/settings-registry.ts";
|
|
69
71
|
export {
|
|
70
72
|
clearRegisteredSettings,
|
|
71
73
|
getRegisteredSettings,
|
|
72
74
|
registerSettings,
|
|
73
|
-
} from "./settings-registry.ts";
|
|
74
|
-
export { createInputSubmenu, openSettingsOverlay } from "./settings-ui.ts";
|
|
75
|
+
} from "./settings/settings-registry.ts";
|
|
76
|
+
export { createInputSubmenu, openSettingsOverlay } from "./settings/settings-ui.ts";
|
|
75
77
|
export type { TitleTarget } from "./terminal.ts";
|
|
76
78
|
export {
|
|
77
79
|
DONE_SYMBOL,
|
package/node_modules/@mrclrchtr/supi-core/src/{config-settings.ts → config/config-settings.ts}
RENAMED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// Wraps registerSettings() and centralizes selected-scope loading + scoped persistence.
|
|
3
3
|
|
|
4
4
|
import type { SettingItem } from "@earendil-works/pi-tui";
|
|
5
|
+
import type { SettingsScope } from "../settings/settings-registry.ts";
|
|
6
|
+
import { registerSettings } from "../settings/settings-registry.ts";
|
|
5
7
|
import { loadSupiConfigForScope, removeSupiConfigKey, writeSupiConfig } from "./config.ts";
|
|
6
|
-
import type { SettingsScope } from "./settings-registry.ts";
|
|
7
|
-
import { registerSettings } from "./settings-registry.ts";
|
|
8
8
|
|
|
9
9
|
export interface ConfigSettingsHelpers {
|
|
10
10
|
/** Write a key to the selected scope's config section. */
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Extensions declare context data providers via `registerContextProvider()` during their
|
|
4
4
|
// factory function. The `/supi-context` command reads them via `getRegisteredContextProviders()`.
|
|
5
5
|
|
|
6
|
-
import { createRegistry } from "
|
|
6
|
+
import { createRegistry } from "../registry-utils.ts";
|
|
7
7
|
|
|
8
8
|
export interface ContextProvider {
|
|
9
9
|
/** Unique identifier — e.g. "rtk" */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { registerSettingsCommand as default } from "./settings-command.ts";
|
|
1
|
+
export { registerSettingsCommand as default } from "./settings/settings-command.ts";
|
|
@@ -2,30 +2,30 @@
|
|
|
2
2
|
// Provides XML context tag wrapping, unified config system, context-message utilities,
|
|
3
3
|
// and settings registry for supi-wide TUI settings.
|
|
4
4
|
|
|
5
|
-
export type { SupiConfigLocation, SupiConfigOptions } from "./config.ts";
|
|
5
|
+
export type { SupiConfigLocation, SupiConfigOptions } from "./config/config.ts";
|
|
6
6
|
export {
|
|
7
7
|
loadSupiConfig,
|
|
8
8
|
loadSupiConfigForScope,
|
|
9
9
|
removeSupiConfigKey,
|
|
10
10
|
writeSupiConfig,
|
|
11
|
-
} from "./config.ts";
|
|
12
|
-
export type { ConfigSettingsHelpers, ConfigSettingsOptions } from "./config-settings.ts";
|
|
13
|
-
export { registerConfigSettings } from "./config-settings.ts";
|
|
14
|
-
export type { ContextMessageLike } from "./context-messages.ts";
|
|
11
|
+
} from "./config/config.ts";
|
|
12
|
+
export type { ConfigSettingsHelpers, ConfigSettingsOptions } from "./config/config-settings.ts";
|
|
13
|
+
export { registerConfigSettings } from "./config/config-settings.ts";
|
|
14
|
+
export type { ContextMessageLike } from "./context/context-messages.ts";
|
|
15
15
|
export {
|
|
16
16
|
findLastUserMessageIndex,
|
|
17
17
|
getContextToken,
|
|
18
18
|
getPromptContent,
|
|
19
19
|
pruneAndReorderContextMessages,
|
|
20
20
|
restorePromptContent,
|
|
21
|
-
} from "./context-messages.ts";
|
|
22
|
-
export type { ContextProvider } from "./context-provider-registry.ts";
|
|
21
|
+
} from "./context/context-messages.ts";
|
|
22
|
+
export type { ContextProvider } from "./context/context-provider-registry.ts";
|
|
23
23
|
export {
|
|
24
24
|
clearRegisteredContextProviders,
|
|
25
25
|
getRegisteredContextProviders,
|
|
26
26
|
registerContextProvider,
|
|
27
|
-
} from "./context-provider-registry.ts";
|
|
28
|
-
export { wrapExtensionContext } from "./context-tag.ts";
|
|
27
|
+
} from "./context/context-provider-registry.ts";
|
|
28
|
+
export { wrapExtensionContext } from "./context/context-tag.ts";
|
|
29
29
|
export type {
|
|
30
30
|
DebugAgentAccess,
|
|
31
31
|
DebugEvent,
|
|
@@ -49,6 +49,7 @@ export {
|
|
|
49
49
|
redactDebugData,
|
|
50
50
|
resetDebugRegistry,
|
|
51
51
|
} from "./debug-registry.ts";
|
|
52
|
+
export { fileToUri, resolveToolPath, stripToolPathPrefix, uriToFile } from "./path-utils.ts";
|
|
52
53
|
export type { KnownRootEntry } from "./project-roots.ts";
|
|
53
54
|
export {
|
|
54
55
|
buildKnownRootsMap,
|
|
@@ -63,15 +64,16 @@ export {
|
|
|
63
64
|
sortRootsBySpecificity,
|
|
64
65
|
walkProject,
|
|
65
66
|
} from "./project-roots.ts";
|
|
67
|
+
export { createRegistry, createSessionStateRegistry } from "./registry-utils.ts";
|
|
66
68
|
export { getActiveBranchEntries } from "./session-utils.ts";
|
|
67
|
-
export { registerSettingsCommand } from "./settings-command.ts";
|
|
68
|
-
export type { SettingsScope, SettingsSection } from "./settings-registry.ts";
|
|
69
|
+
export { registerSettingsCommand } from "./settings/settings-command.ts";
|
|
70
|
+
export type { SettingsScope, SettingsSection } from "./settings/settings-registry.ts";
|
|
69
71
|
export {
|
|
70
72
|
clearRegisteredSettings,
|
|
71
73
|
getRegisteredSettings,
|
|
72
74
|
registerSettings,
|
|
73
|
-
} from "./settings-registry.ts";
|
|
74
|
-
export { createInputSubmenu, openSettingsOverlay } from "./settings-ui.ts";
|
|
75
|
+
} from "./settings/settings-registry.ts";
|
|
76
|
+
export { createInputSubmenu, openSettingsOverlay } from "./settings/settings-ui.ts";
|
|
75
77
|
export type { TitleTarget } from "./terminal.ts";
|
|
76
78
|
export {
|
|
77
79
|
DONE_SYMBOL,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
|
|
3
|
+
/** Strip pi's optional leading `@` file-path prefix from a tool input. */
|
|
4
|
+
export function stripToolPathPrefix(target: string): string {
|
|
5
|
+
return target.startsWith("@") ? target.slice(1) : target;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Resolve a tool-style file path from a session cwd.
|
|
10
|
+
*
|
|
11
|
+
* Built-in pi file tools accept a leading `@` prefix in path arguments, so
|
|
12
|
+
* shared SuPi path helpers normalize that prefix before resolving relative
|
|
13
|
+
* paths.
|
|
14
|
+
*/
|
|
15
|
+
export function resolveToolPath(cwd: string, target: string): string {
|
|
16
|
+
return path.resolve(cwd, stripToolPathPrefix(target));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Convert a file path to a file:// URI. */
|
|
20
|
+
export function fileToUri(filePath: string): string {
|
|
21
|
+
const resolved = path.resolve(filePath);
|
|
22
|
+
if (process.platform === "win32") {
|
|
23
|
+
return `file:///${resolved.replace(/\\/g, "/")}`;
|
|
24
|
+
}
|
|
25
|
+
return `file://${resolved}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Convert a file:// URI to a file path. */
|
|
29
|
+
export function uriToFile(uri: string): string {
|
|
30
|
+
if (!uri.startsWith("file://")) return uri;
|
|
31
|
+
let filePath = decodeURIComponent(uri.slice(7));
|
|
32
|
+
if (
|
|
33
|
+
process.platform === "win32" &&
|
|
34
|
+
filePath.startsWith("/") &&
|
|
35
|
+
/^[A-Za-z]:/.test(filePath.slice(1))
|
|
36
|
+
) {
|
|
37
|
+
filePath = filePath.slice(1);
|
|
38
|
+
}
|
|
39
|
+
return filePath;
|
|
40
|
+
}
|