@itc-steve/pi-ask-complete 0.2.0 → 1.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Changed
6
+
7
+ - Focused the package exclusively on model-guided `ask_user` questions and answers
8
+ - Simplified package metadata and documentation around the single-purpose extension
9
+
10
+ ### Removed
11
+
12
+ - Permission gates for `bash`, `read`, `write`, and `edit`
13
+ - `ask_permission`, `/permissions`, and `/yolo`
14
+ - Command/path policy parsing and `permission.json`
15
+ - `sudo`/`doas` redirection
16
+
3
17
  ## 0.2.0
4
18
 
5
19
  - Path allows now act like directory-scoped YOLO for bash, write, and edit asks
package/README.md CHANGED
@@ -1,104 +1,19 @@
1
1
  # pi-ask-complete
2
2
 
3
- Bottom-panel **ask_user** + **permission gate** (bash / write / edit + path wildcards) for the [Pi coding agent](https://pi.dev).
3
+ Model-guided **ask_user** questions in a bottom panel for the [Pi coding agent](https://pi.dev).
4
4
 
5
- ## Gate
5
+ The extension tells the model to use `ask_user` for decisions, preferences, confirmations, and clarifying questions instead of writing multiple-choice prompts in chat. It does not intercept, approve, deny, or modify other tool calls.
6
6
 
7
- | Tool | Behavior |
8
- | --- | --- |
9
- | `bash` | Every unit (segments, `$(...)`, backticks) is **checked**; path deny args block. **One prompt per tool call** (not per unit). Session/permanent allow applies to each unique base that needed approval |
10
- | `write` / `edit` | Path rules first, then tool rule, else ask |
11
- | `read` | Allowed by default; only auto-**deny** on matching path deny rules — never prompts for normal reads |
7
+ ## Features
12
8
 
13
- ### Default bash allows
14
-
15
- Seeded `permission.json` allows non-destructive **explore / troubleshoot** commands
16
- out of the box (listing, read/print text, search, process/system info, network
17
- diagnostics, checksums, git read-only subcommands). `find`/`awk`/`curl`/`fd` etc are
18
- **ask** (not allow) they are general exec engines.
19
- Path **deny** rules still block secret files even when the binary or project
20
- directory is allowed (`cat .env` deny).
21
-
22
- Still **ask** (not pre-allowed): writers and mutators — `rm`, `mv`, `cp`, `mkdir`,
23
- `touch`, `sed`, `tee`, `chmod`, package managers, `git push` / `commit` / `reset`,
24
- shells (`bash`/`python`/`node`), etc. Catastrophic commands stay **deny**:
25
- `mkfs`, `dd`, `shutdown`, `reboot`, `poweroff`, `halt`.
26
-
27
- Panel options: **Allow this** · **Allow for this session** · **Allow permanently** · **Deny with reason**
28
-
29
- - **Session** — in-memory until the agent session ends (not written to disk).
30
- For a bash pipeline, remembers **every** real base that still needed approval.
31
- - **Permanent** — live immediately + written to `permission.json`
32
- - bash → **primary base only** (`herdr … | python3 … | sed …` → only `herdr`)
33
- - write/edit → **exact file path** in `paths`
34
-
35
- ## Path wildcards
36
-
37
- ```
38
- * any chars except /
39
- ** any chars including /
40
- ? one char except /
41
- ```
42
-
43
- **Deny always wins.** If any matching path rule is `deny`, no `allow` can
44
- override it. Otherwise, a matching directory `allow` acts like path-scoped YOLO:
45
- bash asks running in that directory, plus writes and edits there, are approved
46
- automatically. A command that starts with `cd` into an allowed directory is also
47
- approved when all detected path arguments are allowed. Bash deny rules and path
48
- deny rules still block it.
49
-
50
- Bash commands are decomposed for **policy**: chains (`;` `|` `&&`) and substitutions
51
- each become a unit that must independently pass. Path-like args are checked against
52
- path deny rules — so `ls; rm -rf x` and `cat .env` no longer slip through an allowed
53
- prefix. The user still sees **one** prompt for the whole line; choosing session or
54
- permanent allow covers every base that still needed approval.
55
- (Heuristic, not a full shell parser — `$VAR` expansion isn't resolved.)
56
-
57
- | Path | With example config |
58
- | --- | --- |
59
- | `.env` | deny |
60
- | `prod.env` | deny |
61
- | `.env.example` | **allow** |
62
- | `.ssh/id_rsa` | deny |
63
- | `src/main.ts` | ask (no rule) |
64
-
65
- ## permission.json
66
-
67
- All policy is in JSON — **nothing is hard-blocked in code**.
68
-
69
- `~/.pi/agent/permission.json` (or `$PI_CODING_AGENT_DIR/permission.json`).
70
-
71
- If the file is **missing** (deleted or never created), load seeds it from
72
- `permission.json.example` and re-creates the file on disk so you can edit it.
73
- If the file is **present**, it is obeyed verbatim — even a single rule or an
74
- empty `{}`. Existing files are never merged with, unioned against, or
75
- overwritten by the example defaults.
76
-
77
- `sudo_run` (from pix-sudo) is **not** gated here — its PAM password prompt is the
78
- approve/deny step. Raw `sudo`/`doas` in bash is redirected to `sudo_run`.
79
-
80
- ```json
81
- {
82
- "bash": {
83
- "ls": "allow",
84
- "cat": "allow",
85
- "rg": "allow",
86
- "git status*": "allow",
87
- "dd": "deny"
88
- },
89
- "tools": {
90
- "read": "allow",
91
- "write": "ask"
92
- },
93
- "paths": {
94
- "**/.env.example": "allow",
95
- "**/*.env": "deny",
96
- "/home/you/Projects/**": "allow"
97
- }
98
- }
99
- ```
100
-
101
- Full starter list: `permission.json.example`.
9
+ - Single-select and multi-select questions
10
+ - Free-form answers on every question
11
+ - Optional descriptions and side-by-side previews
12
+ - Multiple questions with tabs and a final review screen
13
+ - Required or skippable questions
14
+ - Bottom-panel UI that keeps the transcript visible
15
+ - Structured JSON answers returned to the model
16
+ - Herdr attention notification when the panel waits in a background pane
102
17
 
103
18
  ## Install
104
19
 
@@ -112,37 +27,37 @@ From a local checkout:
112
27
  pi install /path/to/pi-ask-complete
113
28
  ```
114
29
 
115
- Then `/reload`. `/permissions` shows current allows.
116
-
117
- ## `/yolo`
118
-
119
- Session-scoped mode that auto-approves everything that would otherwise **ask**
120
- (bash / write / edit / unresolved globs — the permission panel stays quiet).
121
-
122
- - **Does:** skip the permission panel for every gate `ask` (including globs/`$VAR`).
123
- - **Does not bypass:** path/bash/tool **deny** rules, or the `sudo`/`doas` → `sudo_run` redirect.
124
- - **Does not touch:** `ask_user` (model questions still prompt you).
125
- - **Dies with the session** memory only; nothing written to `permission.json`. Cleared on `session_start`.
126
-
127
- `/yolo` toggles · `/yolo on` · `/yolo off`. When on, `/permissions` shows the YOLO line.
128
-
129
- ## ask_user
30
+ Run `/reload` after installation.
31
+
32
+ ## Model-facing tool
33
+
34
+ ```ts
35
+ ask_user({
36
+ questions: [
37
+ {
38
+ header: "Which layout?",
39
+ tab: "Layout",
40
+ prompt: "Choose the default page layout.",
41
+ options: [
42
+ { label: "Grid", description: "Dense overview of many items." },
43
+ { label: "List", description: "More detail for each item." }
44
+ ],
45
+ allowSkip: false
46
+ }
47
+ ]
48
+ })
49
+ ```
130
50
 
131
- LLM-callable multi-question bottom panel (`overlay: false` transcript stays visible). Prefer this over plain-text multi-choice.
51
+ Every question also includes a **Type something.** row. The tool returns structured JSON containing the user's selections, custom answers, skipped questions, cancellation state, and optional note.
132
52
 
133
- ## Threat model / limits
53
+ ## Upgrade from 0.x
134
54
 
135
- This is a **heuristic agent gate**, not a sandbox or seccomp profile. The model is still the adversary; the gate reduces accidents and casual exfil, it does not stop a determined local process.
55
+ Version 1.0 removes the permission system entirely:
136
56
 
137
- | Covered | Not a full guarantee |
138
- | --- | --- |
139
- | Chain / pipe / `&&` units each checked | Full shell AST / exotic quoting |
140
- | `$(…)`, backticks, process subs as units | Nested quote mazes |
141
- | Path deny on args, redirects, `if=`, `@file`, git `rev:path` | Paths only after real `$VAR` expansion |
142
- | Glued operators (`cat .env;true`) cleaned | Every future shell metacharacter |
143
- | Unresolved globs / braces / `$''` → **ask** | Interpreter `-c` payloads (permanent-allow `python3`/`bash` is high blast radius) |
144
- | Any unit starting with `sudo`/`doas` → redirect | Root via other helpers |
145
- | Corrupt / non-object `permission.json` keeps last good rules | First load of a corrupt file (everything asks) |
146
- | Missing `permission.json` re-seeds from example (fail closed) | Broken install with no example (path deny-all via noPolicy) |
57
+ - No automatic gate for `bash`, `read`, `write`, or `edit`
58
+ - No `ask_permission` tool
59
+ - No `/permissions` or `/yolo` commands
60
+ - No `permission.json` or path/command rules
61
+ - No `sudo`/`doas` redirection
147
62
 
148
- **Allow permanently** stores a **binary base** (e.g. all `cat`) or an **exact file path** for write/edit. Prefer session allow for interpreters.
63
+ Delete `~/.pi/agent/permission.json` if no other extension uses it. Pi and other installed extensions remain responsible for tool permissions.
package/index.ts CHANGED
@@ -1,34 +1,22 @@
1
1
  /**
2
2
  * pi-ask-complete
3
3
  *
4
- * Bottom-panel ask_user (transcript stays visible) + bash permission gate
5
- * that reuses the same panel for Allow / Allow permanently / Deny with reason.
4
+ * Bottom-panel ask_user with model guidance and a visible transcript.
6
5
  */
7
6
 
8
7
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
9
8
  import { registerAskUser } from "./src/ask-user.ts";
10
9
  import { bindHerdrAttention } from "./src/herdr-attention.ts";
11
- import { registerPermission } from "./src/permission.ts";
12
- import { PermissionStore } from "./src/permission-store.ts";
13
10
 
14
11
  export default function piCompleteAsk(pi: ExtensionAPI) {
15
- const store = new PermissionStore();
16
-
17
12
  // Herdr dings only when this pane is backgrounded (see herdr-attention.ts).
18
13
  bindHerdrAttention(pi.events);
19
14
  registerAskUser(pi);
20
- registerPermission(pi, store);
21
15
 
22
- // Nudge the model to use ask_user / sudo_run correctly.
23
- pi.on("before_agent_start", async (event) => {
24
- const tip =
16
+ pi.on("before_agent_start", async (event) => ({
17
+ systemPrompt:
18
+ (event.systemPrompt ?? "") +
25
19
  "\n\n# User interaction tools\n" +
26
- "- Use `ask_user` whenever you need the user to choose between options, confirm a decision, or answer a clarifying question. Do not present multi-choice questions as plain text when `ask_user` is available.\n" +
27
- "- System shell commands are gated automatically; you do not need to call `ask_permission` for normal bash — the user will be prompted.\n" +
28
- "- Never run `sudo`/`doas` via bash. Use `sudo_run` with the command (no sudo prefix) and a short reason; the user will approve and enter their password.\n";
29
-
30
- return {
31
- systemPrompt: (event.systemPrompt ?? "") + tip,
32
- };
33
- });
20
+ "- Use `ask_user` whenever you need the user to choose between options, confirm a decision, or answer a clarifying question. Do not present multiple-choice questions as plain text when `ask_user` is available.\n",
21
+ }));
34
22
  }
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@itc-steve/pi-ask-complete",
3
- "version": "0.2.0",
4
- "description": "Pi extension: bottom-panel ask_user + bash permission gate (Allow / Allow permanently / Deny with reason) writing ~/.pi/agent/permission.json",
3
+ "version": "1.0.0",
4
+ "description": "Pi extension: model-guided ask_user questions in a bottom panel with the transcript kept visible",
5
5
  "keywords": [
6
6
  "pi-package",
7
7
  "pi",
8
8
  "pi-extension",
9
9
  "pi-coding-agent",
10
10
  "ask-user",
11
- "permissions",
12
- "yolo"
11
+ "questions",
12
+ "tui"
13
13
  ],
14
14
  "author": {
15
15
  "name": "itc-steve",
@@ -35,7 +35,6 @@
35
35
  "files": [
36
36
  "index.ts",
37
37
  "src",
38
- "permission.json.example",
39
38
  "README.md",
40
39
  "CHANGELOG.md",
41
40
  "LICENSE"
@@ -1236,7 +1236,7 @@ export class AskUserResultView implements Component {
1236
1236
  }
1237
1237
 
1238
1238
  // ────────────────────────────────────────────────────────────────────────────
1239
- // Shared runners — used by ask_user tool and the permission gate
1239
+ // ask_user runner and result serialization
1240
1240
  // ────────────────────────────────────────────────────────────────────────────
1241
1241
 
1242
1242
  export function sanitizeQuestions(
@@ -1,299 +0,0 @@
1
- {
2
- "bash": {
3
- "ls": "allow",
4
- "dir": "allow",
5
- "vdir": "allow",
6
- "tree": "allow",
7
- "eza": "allow",
8
- "exa": "allow",
9
- "lsd": "allow",
10
- "pwd": "allow",
11
- "cd": "allow",
12
- "pushd": "allow",
13
- "popd": "allow",
14
- "dirs": "allow",
15
- "locate": "allow",
16
- "which": "allow",
17
- "type": "allow",
18
- "whereis": "allow",
19
- "file": "allow",
20
- "stat": "allow",
21
- "namei": "allow",
22
- "readlink": "allow",
23
- "realpath": "allow",
24
- "basename": "allow",
25
- "dirname": "allow",
26
- "pathchk": "allow",
27
- "du": "allow",
28
- "df": "allow",
29
- "dust": "allow",
30
- "duf": "allow",
31
- "free": "allow",
32
- "lsblk": "allow",
33
- "blkid": "allow",
34
- "lsattr": "allow",
35
- "getfacl": "allow",
36
- "findmnt": "allow",
37
- "lscpu": "allow",
38
- "lsmem": "allow",
39
- "lsipc": "allow",
40
- "lslogins": "allow",
41
- "lspci": "allow",
42
- "lsusb": "allow",
43
- "lshw": "allow",
44
- "ps": "allow",
45
- "procs": "allow",
46
- "pgrep": "allow",
47
- "pidof": "allow",
48
- "top": "allow",
49
- "htop": "allow",
50
- "btop": "allow",
51
- "pstree": "allow",
52
- "lsof": "allow",
53
- "fuser": "allow",
54
- "uname": "allow",
55
- "hostname": "allow",
56
- "arch": "allow",
57
- "nproc": "allow",
58
- "id": "allow",
59
- "whoami": "allow",
60
- "groups": "allow",
61
- "who": "allow",
62
- "w": "allow",
63
- "last": "allow",
64
- "lastlog": "allow",
65
- "uptime": "allow",
66
- "date": "allow",
67
- "cal": "allow",
68
- "vmstat": "allow",
69
- "iostat": "allow",
70
- "mpstat": "allow",
71
- "sar": "allow",
72
- "dmesg": "allow",
73
- "journalctl": "allow",
74
- "getconf": "allow",
75
- "getent": "allow",
76
- "locale": "allow",
77
- "ss": "allow",
78
- "netstat": "allow",
79
- "ping": "allow",
80
- "ping6": "allow",
81
- "traceroute": "allow",
82
- "traceroute6": "allow",
83
- "tracepath": "allow",
84
- "mtr": "allow",
85
- "dig": "allow",
86
- "nslookup": "allow",
87
- "host": "allow",
88
- "ip": "allow",
89
- "cat": "allow",
90
- "tac": "allow",
91
- "head": "allow",
92
- "tail": "allow",
93
- "less": "allow",
94
- "more": "allow",
95
- "bat": "allow",
96
- "batcat": "allow",
97
- "wc": "allow",
98
- "nl": "allow",
99
- "od": "allow",
100
- "hexdump": "allow",
101
- "xxd": "allow",
102
- "strings": "allow",
103
- "grep": "allow",
104
- "egrep": "allow",
105
- "fgrep": "allow",
106
- "rg": "allow",
107
- "ag": "allow",
108
- "ack": "allow",
109
- "cut": "allow",
110
- "sort": "allow",
111
- "uniq": "allow",
112
- "tr": "allow",
113
- "column": "allow",
114
- "paste": "allow",
115
- "join": "allow",
116
- "comm": "allow",
117
- "diff": "allow",
118
- "diff3": "allow",
119
- "sdiff": "allow",
120
- "cmp": "allow",
121
- "colordiff": "allow",
122
- "jq": "allow",
123
- "yq": "allow",
124
- "fold": "allow",
125
- "fmt": "allow",
126
- "expand": "allow",
127
- "unexpand": "allow",
128
- "rev": "allow",
129
- "tput": "allow",
130
- "printf": "allow",
131
- "echo": "allow",
132
- "true": "allow",
133
- "false": "allow",
134
- "test": "allow",
135
- "expr": "allow",
136
- "seq": "allow",
137
- "md5sum": "allow",
138
- "sha1sum": "allow",
139
- "sha224sum": "allow",
140
- "sha256sum": "allow",
141
- "sha384sum": "allow",
142
- "sha512sum": "allow",
143
- "cksum": "allow",
144
- "sum": "allow",
145
- "b2sum": "allow",
146
- "crc32": "allow",
147
- "zcat": "allow",
148
- "zless": "allow",
149
- "zgrep": "allow",
150
- "bzcat": "allow",
151
- "bzgrep": "allow",
152
- "xzcat": "allow",
153
- "xzgrep": "allow",
154
- "lzcat": "allow",
155
- "zstdcat": "allow",
156
- "zstdless": "allow",
157
- "tar -t*": "allow",
158
- "tar --list*": "allow",
159
- "unzip -l*": "allow",
160
- "gzip -l*": "allow",
161
- "env": "allow",
162
- "printenv": "allow",
163
- "export": "allow",
164
- "set": "allow",
165
- "declare": "allow",
166
- "alias": "allow",
167
- "history": "allow",
168
- "help": "allow",
169
- "man": "allow",
170
- "info": "allow",
171
- "whatis": "allow",
172
- "apropos": "allow",
173
- "compgen": "allow",
174
- "strace": "allow",
175
- "ltrace": "allow",
176
- "nm": "allow",
177
- "objdump": "allow",
178
- "readelf": "allow",
179
- "ldd": "allow",
180
- "git status*": "allow",
181
- "git log*": "allow",
182
- "git diff*": "allow",
183
- "git show*": "allow",
184
- "git rev-parse*": "allow",
185
- "git rev-list*": "allow",
186
- "git ls-files*": "allow",
187
- "git ls-tree*": "allow",
188
- "git ls-remote*": "allow",
189
- "git blame*": "allow",
190
- "git describe*": "allow",
191
- "git remote -v": "allow",
192
- "git remote show*": "allow",
193
- "git branch": "allow",
194
- "git branch -a": "allow",
195
- "git branch -v*": "allow",
196
- "git branch --show-current": "allow",
197
- "git stash list*": "allow",
198
- "git config --get*": "allow",
199
- "git config --list*": "allow",
200
- "git config -l*": "allow",
201
- "git tag": "allow",
202
- "git tag -l*": "allow",
203
- "git shortlog*": "allow",
204
- "git reflog*": "allow",
205
- "git cat-file*": "allow",
206
- "git name-rev*": "allow",
207
- "git symbolic-ref*": "allow",
208
- "git check-ignore*": "allow",
209
- "mkfs": "deny",
210
- "mkfs.fat": "deny",
211
- "mkfs.vfat": "deny",
212
- "mkfs.exfat": "deny",
213
- "mkfs.ext2": "deny",
214
- "mkfs.ext3": "deny",
215
- "mkfs.ext4": "deny",
216
- "mkfs.xfs": "deny",
217
- "mkfs.btrfs": "deny",
218
- "mkfs.ntfs": "deny",
219
- "mkfs.f2fs": "deny",
220
- "mkfs.minix": "deny",
221
- "dd": "deny",
222
- "shutdown": "deny",
223
- "reboot": "deny",
224
- "poweroff": "deny",
225
- "halt": "deny",
226
- "fdisk": "deny",
227
- "parted": "deny",
228
- "sgdisk": "deny",
229
- "wipefs": "deny",
230
- "shred": "deny",
231
- "mkswap": "deny",
232
- "blkdiscard": "deny"
233
- },
234
- "tools": {
235
- "read": "allow",
236
- "write": "ask",
237
- "edit": "ask"
238
- },
239
- "paths": {
240
- "**/.env.example": "allow",
241
- "**/*.env.example": "allow",
242
- "**/.env.sample": "allow",
243
- "**/.env.template": "allow",
244
- "**/.env.sample.*": "allow",
245
- "**/env.example": "allow",
246
- "**/id_rsa.pub": "allow",
247
- "**/id_ed25519.pub": "allow",
248
- "**/id_ecdsa.pub": "allow",
249
- "**/id_dsa.pub": "allow",
250
- "**/.env": "deny",
251
- "**/*.env": "deny",
252
- "**/.env.local": "deny",
253
- "**/.env.development": "deny",
254
- "**/.env.production": "deny",
255
- "**/.env.staging": "deny",
256
- "**/.env.test": "deny",
257
- "**/.env.rc": "deny",
258
- "**/.env.*.local": "deny",
259
- "**/*.pem": "deny",
260
- "**/*.key": "deny",
261
- "**/*.p12": "deny",
262
- "**/*.pfx": "deny",
263
- "**/*.jks": "deny",
264
- "**/id_rsa": "deny",
265
- "**/id_ed25519": "deny",
266
- "**/id_ecdsa": "deny",
267
- "**/id_dsa": "deny",
268
- "**/.ssh/**": "deny",
269
- "**/.aws/**": "deny",
270
- "**/.gnupg/**": "deny",
271
- "**/.netrc": "deny",
272
- "**/.npmrc": "deny",
273
- "**/.pypirc": "deny",
274
- "**/credentials.json": "deny",
275
- "**/credentials.yml": "deny",
276
- "**/credentials.yaml": "deny",
277
- "**/service-account*.json": "deny",
278
- "**/secrets.json": "deny",
279
- "**/secrets.yml": "deny",
280
- "**/secrets.yaml": "deny",
281
- "**/*-credentials.json": "deny",
282
- "/etc/shadow": "deny",
283
- "/etc/gshadow": "deny",
284
- "/etc/sudoers": "deny",
285
- "/etc/sudoers.d/**": "deny",
286
- "/etc/ssh/ssh_host_*_key": "deny",
287
- "**/.docker/config.json": "deny",
288
- "**/kubeconfig": "deny",
289
- "**/.kube/config": "deny",
290
- "**/*.tfstate": "deny",
291
- "**/.git-credentials": "deny",
292
- "**/.config/gh/hosts.yml": "deny",
293
- "**/.bash_history": "deny",
294
- "**/.zsh_history": "deny",
295
- "**/.mysql_history": "deny",
296
- "**/.psql_history": "deny",
297
- "**/.python_history": "deny"
298
- }
299
- }