@groeponline/pi-wishcraft 1.4.8 → 1.4.10
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 +4 -0
- package/bash-mode/editor.ts +21 -4
- package/bash-mode/pty-session.ts +19 -13
- package/docs/bash-mode.md +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/bash-mode/editor.ts
CHANGED
|
@@ -279,17 +279,34 @@ export class BashModeEditor extends CustomEditor {
|
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
if (
|
|
282
|
-
bashMode &&
|
|
282
|
+
(bashMode || oneOffBashCommand) &&
|
|
283
283
|
this.keybindingsRef.matches(data, "tui.input.submit") &&
|
|
284
284
|
!this.keybindingsRef.matches(data, "tui.input.newLine")
|
|
285
285
|
) {
|
|
286
|
+
// One-off bang prompts run the text after the prefix (mirrors pi's
|
|
287
|
+
// own !/!! handling in interactive-mode.js); anything else submits
|
|
288
|
+
// verbatim. Without the strip the bang would hit bash history
|
|
289
|
+
// expansion (`!cmd` = replay a previous command) instead of `cmd`.
|
|
290
|
+
const raw = this.getExpandedText().trim();
|
|
291
|
+
const oneOff = getOneOffBashCommandContext(raw);
|
|
292
|
+
const command = oneOff ? oneOff.command.trim() : raw;
|
|
293
|
+
if (!command) {
|
|
294
|
+
// Bash-off bare `!`: fall back to pi's own submit handling, whose
|
|
295
|
+
// `if (command)` guard turns an empty command into a normal prompt
|
|
296
|
+
// (pre-interception behavior). Full bash mode keeps the return.
|
|
297
|
+
// This must run before the shell-running guard: a bare `!` while a
|
|
298
|
+
// managed shell job runs should still delegate to pi, not be
|
|
299
|
+
// swallowed by the "already running" warning.
|
|
300
|
+
if (!bashMode) {
|
|
301
|
+
super.handleInput(data);
|
|
302
|
+
}
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
|
|
286
306
|
if (this.optionsRef.isShellRunning()) {
|
|
287
307
|
this.optionsRef.onNotify("Shell command already running", "warning");
|
|
288
308
|
return;
|
|
289
309
|
}
|
|
290
|
-
|
|
291
|
-
const command = this.getExpandedText().trim();
|
|
292
|
-
if (!command) return;
|
|
293
310
|
this.clearGhostSuggestion();
|
|
294
311
|
resetShellHistoryBrowse(this);
|
|
295
312
|
this.optionsRef.onEditorSubmit?.();
|
package/bash-mode/pty-session.ts
CHANGED
|
@@ -119,6 +119,8 @@ interface RunningCommand {
|
|
|
119
119
|
buffer: string;
|
|
120
120
|
/** Trailing partial escape sequence carried across chunks. */
|
|
121
121
|
escapeTail: string;
|
|
122
|
+
/** Wrapper result observed on stdout; publication waits for child close. */
|
|
123
|
+
pendingResult: PtyRunResult | null;
|
|
122
124
|
resolve: (result: PtyRunResult) => void;
|
|
123
125
|
settled: boolean;
|
|
124
126
|
}
|
|
@@ -179,6 +181,7 @@ export class PtyShellSession {
|
|
|
179
181
|
done,
|
|
180
182
|
buffer: "",
|
|
181
183
|
escapeTail: "",
|
|
184
|
+
pendingResult: null,
|
|
182
185
|
resolve: (result) => {
|
|
183
186
|
if (running.settled) return;
|
|
184
187
|
running.settled = true;
|
|
@@ -224,9 +227,8 @@ export class PtyShellSession {
|
|
|
224
227
|
child.stderr.on("data", (chunk: string) => this.handleChunk(String(chunk)));
|
|
225
228
|
child.on("error", (error) => {
|
|
226
229
|
// spawn itself failed (script removed between probe and spawn, dead
|
|
227
|
-
// SHELL path): surface the reason,
|
|
228
|
-
//
|
|
229
|
-
// next command degrades to pipes instead of silently failing again.
|
|
230
|
+
// SHELL path): surface the reason, but do not publish completion until
|
|
231
|
+
// the matching child emits close. That preserves strict child ownership.
|
|
230
232
|
console.warn(
|
|
231
233
|
"[wishcraft] spawn failed:",
|
|
232
234
|
error instanceof Error ? error.message : String(error),
|
|
@@ -234,20 +236,24 @@ export class PtyShellSession {
|
|
|
234
236
|
if (usePty) {
|
|
235
237
|
_resetScriptAvailableForTests();
|
|
236
238
|
}
|
|
237
|
-
running.
|
|
239
|
+
running.pendingResult = { exitCode: 1, cwd: this.state.cwd };
|
|
238
240
|
});
|
|
239
241
|
child.on("close", (code, signal) => {
|
|
240
|
-
this.child
|
|
241
|
-
|
|
242
|
-
|
|
242
|
+
if (this.child === child) {
|
|
243
|
+
this.child = null;
|
|
244
|
+
}
|
|
245
|
+
// Completion is published only after this exact child closes, so a
|
|
246
|
+
// later run cannot have its child reference cleared by this callback.
|
|
243
247
|
if (this.interrupted) {
|
|
244
248
|
running.resolve({ exitCode: 130, cwd: this.state.cwd });
|
|
245
249
|
return;
|
|
246
250
|
}
|
|
247
|
-
running.resolve(
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
+
running.resolve(
|
|
252
|
+
running.pendingResult ?? {
|
|
253
|
+
exitCode: getCloseExitCode(code, signal),
|
|
254
|
+
cwd: this.state.cwd,
|
|
255
|
+
},
|
|
256
|
+
);
|
|
251
257
|
});
|
|
252
258
|
});
|
|
253
259
|
}
|
|
@@ -322,10 +328,10 @@ export class PtyShellSession {
|
|
|
322
328
|
if (firstColon !== -1) {
|
|
323
329
|
const exitCode = Number.parseInt(rest.slice(0, firstColon), 10);
|
|
324
330
|
const cwd = rest.slice(firstColon + 1);
|
|
325
|
-
running.
|
|
331
|
+
running.pendingResult = {
|
|
326
332
|
exitCode: Number.isFinite(exitCode) ? exitCode : 1,
|
|
327
333
|
cwd: cwd || this.state.cwd,
|
|
328
|
-
}
|
|
334
|
+
};
|
|
329
335
|
return;
|
|
330
336
|
}
|
|
331
337
|
continue;
|
package/docs/bash-mode.md
CHANGED
|
@@ -32,6 +32,8 @@ At command position, short stems first resolve from the newest successful local
|
|
|
32
32
|
|
|
33
33
|
If the bash prompt is empty, bash mode shows the newest successful project-history ghost suggestion immediately when one exists, including right after mode entry or after the prompt is cleared again. One-off `!command` and `!!command` prompts reuse the same shell prediction pipeline, including ghost text. Right Arrow or Tab accepts ghost text into the editor, and Enter runs the current shell command. Mode entry stays quiet: there is no automatic or manual dropdown completion surface, and ghost suggestions do not run shell-native completion probes.
|
|
34
34
|
|
|
35
|
+
One-off `!command` and `!!command` prompts also work when bash mode is off: Enter routes them through the managed shell with the prefix stripped, so `!cmd` runs `cmd` (in a real PTY) instead of a headless shell failing on TUI programs or hitting bash history expansion. Output lands in the transcript below the editor, not in the model conversation — pi's own `!`-prefix bash (headless, context-injected) is superseded while this extension's editor is active. Full bash mode (`ctrl+shift+b`) is only needed for running plain commands or keeping the shell session visible in the footer.
|
|
36
|
+
|
|
35
37
|
## Configuration
|
|
36
38
|
|
|
37
39
|
In `~/.pi/agent/settings.json` (or under `PI_CODING_AGENT_DIR` when that environment variable is set):
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@groeponline/pi-wishcraft",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.10",
|
|
4
4
|
"description": "Operator cockpit for Pi: live powerline status, searchable skills, idea queue, sticky Bash, hooks, policy controls, and session UX.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|