@groeponline/pi-wishcraft 0.17.3 → 0.18.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/AGENTS.md +14 -10
- package/CHANGELOG.md +20 -0
- package/README.md +40 -11
- package/RELEASE.md +10 -7
- package/ROADMAP.md +13 -9
- package/bash-mode/completion.ts +39 -6
- package/bash-mode/editor.ts +43 -2
- package/bash-mode/history.ts +3 -3
- package/index.ts +3 -3
- package/package.json +6 -2
- package/src/config/presets.ts +101 -19
- package/src/config/segment-options.ts +11 -0
- package/src/config/types.ts +12 -0
- package/src/core/frontmatter.ts +43 -0
- package/src/extension/{bash-mode-actions.ts → commands/bash-mode-actions.ts} +4 -4
- package/src/extension/{commands.ts → commands/commands.ts} +16 -11
- package/src/extension/{queue-commands.ts → commands/queue-commands.ts} +4 -4
- package/src/extension/{vibe-command.ts → commands/vibe-command.ts} +2 -3
- package/src/extension/{constants.ts → core/constants.ts} +2 -5
- package/src/extension/{segment-context.ts → core/segment-context.ts} +8 -11
- package/src/extension/{state.ts → core/state.ts} +14 -14
- package/src/extension/{types.ts → core/types.ts} +9 -9
- package/src/extension/{prompt-history.ts → history/prompt-history.ts} +3 -3
- package/src/extension/{stash-history.ts → history/stash-history.ts} +6 -6
- package/src/extension/{queue-context.ts → queue/queue-context.ts} +1 -1
- package/src/extension/{queue-integration.ts → queue/queue-integration.ts} +12 -9
- package/src/extension/{activate.ts → session/activate.ts} +7 -7
- package/src/extension/{git-invalidation.ts → session/git-invalidation.ts} +3 -3
- package/src/extension/{session-lifecycle.ts → session/session-lifecycle.ts} +25 -22
- package/src/extension/{settings-io.ts → settings/settings-io.ts} +10 -10
- package/src/extension/{shortcuts-config.ts → shortcuts/shortcuts-config.ts} +8 -8
- package/src/extension/{shortcuts-router.ts → shortcuts/shortcuts-router.ts} +10 -13
- package/src/extension/skills/inline-invocation.ts +150 -128
- package/src/extension/skills/skill-manager.ts +242 -0
- package/src/extension/{custom-editor.ts → ui/custom-editor.ts} +15 -16
- package/src/extension/{layout.ts → ui/layout.ts} +10 -10
- package/src/extension/{menu-views.ts → ui/menu-views.ts} +7 -7
- package/src/extension/{powerline-widgets.ts → ui/powerline-widgets.ts} +6 -3
- package/src/extension/{status-line-renderers.ts → ui/status-line-renderers.ts} +13 -10
- package/src/extension/{welcome-control.ts → welcome/welcome-control.ts} +1 -1
- package/src/extension/{welcome-integration.ts → welcome/welcome-integration.ts} +10 -8
- package/src/git/status.ts +75 -7
- package/src/segments/core.ts +31 -2
- package/src/segments/custom.ts +7 -1
- package/src/segments/system.ts +51 -23
- package/src/shell/cd-command.ts +2 -2
- /package/src/extension/{stale-context.ts → session/stale-context.ts} +0 -0
package/AGENTS.md
CHANGED
|
@@ -16,15 +16,19 @@ user customization.
|
|
|
16
16
|
`parseBashModeSettings`, `PowerlineShortcuts`). Keep it a barrel; no
|
|
17
17
|
implementation lives here.
|
|
18
18
|
- `src/` — the proxy-free extension runtime, organized by domain:
|
|
19
|
-
- `src/extension/` —
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
`
|
|
23
|
-
`
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
- `src/extension/` — the extension runtime, organized into domain subfolders:
|
|
20
|
+
`core/` (constants, types, `state.ts` hub, segment-context), `commands/`
|
|
21
|
+
(slash commands, queue commands, bash-mode actions, vibe command),
|
|
22
|
+
`session/` (activation, session lifecycle, git invalidation, stale-context),
|
|
23
|
+
`ui/` (custom editor, layout, menu views, powerline widgets, status-line
|
|
24
|
+
renderers), `history/` (prompt + stash history), `queue/` (queue context +
|
|
25
|
+
integration), `settings/` (settings IO), `shortcuts/` (shortcut config +
|
|
26
|
+
router), `welcome/` (welcome control + integration), `skills/` (inline
|
|
27
|
+
invocation). Leaf modules keep the dependency graph acyclic: shared types
|
|
28
|
+
and constants live in `core/`, queue/welcome callbacks are wired through
|
|
29
|
+
leaves or `RuntimeState`, and `core/state.ts` is the hub that only has
|
|
30
|
+
inbound edges. Verify with `npx madge --circular src index.ts bash-mode
|
|
31
|
+
queue`.
|
|
28
32
|
- `src/config/` — powerline config parsing, presets, types, segment ids/options.
|
|
29
33
|
- `src/segments/` — segment registry and the segment renderers.
|
|
30
34
|
- `src/theme/` — colors, icons, separators, theme loading.
|
|
@@ -48,7 +52,7 @@ user customization.
|
|
|
48
52
|
boundaries (e.g. command handlers out of `commands.ts`, git invalidation
|
|
49
53
|
out of `session-lifecycle.ts`). Prefer many cohesive small modules.
|
|
50
54
|
- **No circular imports.** Domain modules must not import back into
|
|
51
|
-
`src/extension/state.ts` for callbacks; move the callback into a leaf module
|
|
55
|
+
`src/extension/core/state.ts` for callbacks; move the callback into a leaf module
|
|
52
56
|
(e.g. `welcome-control.ts`) or wire it through `RuntimeState`.
|
|
53
57
|
- **Bun/Node-native TS:** `import` paths carry `.ts` extensions
|
|
54
58
|
(`allowImportingTsExtensions`), `node:`-prefixed builtins, `node --test`
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [0.18.0] - 2026-08-16
|
|
6
|
+
|
|
7
|
+
Wishcraft v2 (#7).
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **Tab token completion** — bash-mode tab completion for stored tokens/shortcuts.
|
|
11
|
+
- **Preset rework** — own-property preset handling plus reworked presets.
|
|
12
|
+
- **Git commit/ahead-behind extras** — commit count and ahead/behind in the git segment; ANSI/control chars in git commit metadata sanitized.
|
|
13
|
+
- **TPS in/out** — separate tokens-in/tokens-out throughput.
|
|
14
|
+
- **Interactive skill-manager TUI** (`/skills`) — browse, inspect, and manage discovered skills.
|
|
15
|
+
- **Full git polling for compact extras** — reliable commit/ahead-behind data.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- **Extension refactor** — `src/extension` split into domain subfolders (core, commands, session, ui, history, queue, settings, shortcuts, welcome).
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- **Ghost suggestions revalidated after partial completion** — and scheduleGhostUpdate stubbed in tab token-step tests.
|
|
22
|
+
|
|
3
23
|
## [0.17.3] - 2026-08-10
|
|
4
24
|
|
|
5
25
|
### Added
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ This extension translates that philosophy to the [pi](https://github.com/badlogi
|
|
|
13
13
|
4. **Stash & Pivot (Alt+S)**: Park a prompt draft, ask a quick question, pop it back automatically.
|
|
14
14
|
5. **Sticky Shell (`!cmd`)**: A persistent bash runtime under your fingertips.
|
|
15
15
|
|
|
16
|
-
Inspired by [Powerlevel10k](https://github.com/romkatv/powerlevel10k) and [oh-my-pi](https://github.com/can1357/oh-my-pi).
|
|
16
|
+
Inspired by [Powerlevel10k](https://github.com/romkatv/powerlevel10k) and [oh-my-pi](https://github.com/can1357/oh-my-pi). Forked from [`nicobailon/pi-powerline-footer`](https://github.com/nicobailon/pi-powerline-footer), maintained by [GroepOnline](https://github.com/GroepOnline).
|
|
17
17
|
|
|
18
18
|
<img width="1261" height="817" alt="Example powerline UI" src="https://github.com/user-attachments/assets/4cc43320-3fb8-4503-b857-69dffa7028f2" />
|
|
19
19
|
|
|
@@ -125,13 +125,13 @@ You can also set it in the agent settings file (`~/.pi/agent/settings.json` by d
|
|
|
125
125
|
|
|
126
126
|
| Preset | Description |
|
|
127
127
|
|--------|-------------|
|
|
128
|
-
| `default` |
|
|
129
|
-
| `minimal` | Just path (basename), git
|
|
130
|
-
| `compact` | Model, git, cost, context |
|
|
131
|
-
| `full` | Everything
|
|
132
|
-
| `nerd` | Maximum detail for Nerd Font users |
|
|
133
|
-
| `ascii` | Safe for any terminal |
|
|
134
|
-
| `chef` | Fork default: muted colors, slash separators, TPS + open-ports segments |
|
|
128
|
+
| `default` | Balanced daily driver: model, thinking, path (basename), git (branch + dirty + latest commit + ↑/↓ ahead-behind + host icon), session, queue, subagent cost, tokens in/out, cache-hit%, cost, context |
|
|
129
|
+
| `minimal` | Just path (basename), git branch and context% (branch-only polling, no indicators/commit) |
|
|
130
|
+
| `compact` | Model, git (short commit + ahead/behind), queue, cost, context%, session id |
|
|
131
|
+
| `full` | Everything: hostname, model, path (abbreviated), full git incl commit + ↑/↓, totals, context total, elapsed + clock |
|
|
132
|
+
| `nerd` | Maximum detail for Nerd Font users: qualified model, full tokens + cache, commit, totals, seconds clock |
|
|
133
|
+
| `ascii` | Safe for any terminal: branch + short commit + ↑/↓, tokens, cost, context% (no Nerd glyphs) |
|
|
134
|
+
| `chef` | Fork default: muted colors, slash separators, live TPS in/out + open-ports + subagent-cost segments |
|
|
135
135
|
|
|
136
136
|
**Environment:** `POWERLINE_NERD_FONTS=1` to force Nerd Fonts, `=0` for ASCII.
|
|
137
137
|
|
|
@@ -238,7 +238,7 @@ Define your own preset in settings; it merges over built-ins and is selectable v
|
|
|
238
238
|
|
|
239
239
|
`preset: "chef"` is the GroepOnline fork's default look: muted colors (no rainbow), slash separators, and two extra right-side segments:
|
|
240
240
|
|
|
241
|
-
- `tps`: live tokens/sec
|
|
241
|
+
- `tps`: live tokens/sec over a rolling 1-second window (EMA-free, no spikes), now reporting **output and input** rates separately (`⇡out ⇣in`) so you can see generation speed and incoming prompt tokens at a glance. A rocket/bolt icon lights up while streaming (override with env `POWERLINE_TPS`).
|
|
242
242
|
- `open_ports`: count of unique **TCP** listening ports (`ss` → `netstat` → `/proc/net` fallback, dedupes IPv4/IPv6). Set `segmentOptions.openPorts.includeUdp: true` to include noisy UDP (mDNS/DHCP/ephemeral).
|
|
243
243
|
|
|
244
244
|
Interactivity (Pi core renders the footer as static text, so live click is not possible; actions live in commands and a navigable overlay):
|
|
@@ -378,7 +378,7 @@ While bash mode is active:
|
|
|
378
378
|
|
|
379
379
|
- Enter runs the current shell command
|
|
380
380
|
- Right Arrow accepts ghost text into the editor without running it
|
|
381
|
-
- Tab
|
|
381
|
+
- Tab completes the ghost suggestion one token/segment at a time (repeat Tab to step through each further token); once the full suggestion is inserted it clears, otherwise Tab does nothing
|
|
382
382
|
- Up and Down browse matching shell history
|
|
383
383
|
- `escape` exits bash mode and returns to normal prompt mode
|
|
384
384
|
- `ctrl+c` interrupts the active shell job before falling back to normal pi behavior
|
|
@@ -462,6 +462,14 @@ After changing bindings, run `/reload`. Invalid bindings, reserved key conflicts
|
|
|
462
462
|
|
|
463
463
|
Powerline wraps Pi's autocomplete provider so bash mode can add shell-aware suggestions. When another editor extension was already installed, powerline now passes Pi's provider through that previous editor's `setAutocompleteProvider()` first and then wraps the resulting provider. This preserves prior autocomplete-provider wrappers where possible, but it is not full render/input composition between custom editors.
|
|
464
464
|
|
|
465
|
+
## Skill manager
|
|
466
|
+
|
|
467
|
+
Browse and insert your installed skills (`SKILL.md` files and `*.md`/`*.txt` prompts) from an interactive TUI overlay:
|
|
468
|
+
|
|
469
|
+
- **`/skills`** — open the skill manager. Filter with plain typing, `↑↓` to move, `enter` to open a skill's detail body, `↑↓` in the detail to scroll, `enter`/`tab` to insert the skill content into your prompt, `esc` to go back/close.
|
|
470
|
+
|
|
471
|
+
The manager reuses the same skill discovery as inline `/command`/`$skill` triggers, so anything you can inline you can also browse and insert manually.
|
|
472
|
+
|
|
465
473
|
## Working Vibes
|
|
466
474
|
|
|
467
475
|
Transform boring "Working..." messages into themed phrases that match your style:
|
|
@@ -583,9 +591,27 @@ Set `git.hostIcon` to replace the branch icon with the origin remote's host logo
|
|
|
583
591
|
|
|
584
592
|
The origin remote is detected (SSH or HTTPS) and mapped to an icon: GitHub (`nf-fa-github`), GitLab (`nf-fa-gitlab`), Bitbucket (`nf-fa-bitbucket`), or a generic git logo (`nf-fa-git`) for any other remote (self-hosted, Gitea, Codeberg, …). Repositories without an origin remote keep the plain branch icon (`nf-fa-code_fork`), as do ASCII (non–Nerd Font) setups. The remote is read once and cached, so this adds no per-render cost. Default is `false` (branch icon unchanged).
|
|
585
593
|
|
|
594
|
+
## Git status extras (commits, ahead/behind)
|
|
595
|
+
|
|
596
|
+
The git segment can also show the last commit on `HEAD` (short hash + subject) and the upstream ahead/behind counts — handy for a quick "where am I relative to main" GitHub signal:
|
|
597
|
+
|
|
598
|
+
- `git.showCommit` (`true` by default) — appends `#<hash> <subject>` for the latest commit.
|
|
599
|
+
- `git.maxCommitSubjectLength` (`24`) — truncates the commit subject shown.
|
|
600
|
+
- `git.showAheadBehind` (`true` by default) — appends `↑<n> ↓<n>` for commits ahead/behind the configured upstream (hidden when there is no upstream).
|
|
601
|
+
|
|
602
|
+
```json
|
|
603
|
+
{
|
|
604
|
+
"powerline": {
|
|
605
|
+
"git": { "showCommit": true, "showAheadBehind": true, "maxCommitSubjectLength": 24 }
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
The `minimal` and `compact` presets keep these off to stay lean; set `showCommit: true`/`showAheadBehind: true` to enable them.
|
|
611
|
+
|
|
586
612
|
## Segments
|
|
587
613
|
|
|
588
|
-
`model` · `
|
|
614
|
+
`model` · `shell_mode` · `path` · `git` · `subagents` · `queue` · `token_in` · `token_out` · `token_total` · `cost` · `context_pct` · `context_total` · `time_spent` · `time` · `session` · `hostname` · `cache_read` · `cache_write` · `thinking` · `tps` · `open_ports` · `extension_statuses`
|
|
589
615
|
|
|
590
616
|
## Separators
|
|
591
617
|
|
|
@@ -613,6 +639,9 @@ Colors are configurable via pi's theme system. Each preset defines its own color
|
|
|
613
639
|
| `contextError` | `error` | Context usage >90% |
|
|
614
640
|
| `cost` | `text` | Cost display |
|
|
615
641
|
| `tokens` | `muted` | Token counts |
|
|
642
|
+
| `queue` | `accent` | Queue / ideas / blocked counts |
|
|
643
|
+
| `separator` | `dim` | Segment separators and ahead/behind counts |
|
|
644
|
+
| `border` | `borderMuted` | Panel/border chrome |
|
|
616
645
|
|
|
617
646
|
### Custom Theme Override
|
|
618
647
|
|
package/RELEASE.md
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
# Releasing `@groeponline/pi-wishcraft`
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
`@groeponline/pi-wishcraft` is GroepOnline's powerline status bar and
|
|
4
|
+
interaction layer for the pi coding agent (forked from
|
|
5
|
+
`nicobailon/pi-powerline-footer`, now independently maintained). It ships to
|
|
6
|
+
npm as the scoped package `@groeponline/pi-wishcraft` and installs locally
|
|
7
|
+
from the repo path. This doc records the end-to-end release flow and how to
|
|
8
|
+
verify it.
|
|
6
9
|
|
|
7
10
|
## Identity
|
|
8
11
|
|
|
9
|
-
- **GitHub repo:** `GroepOnline/pi-wishcraft` (
|
|
12
|
+
- **GitHub repo:** `GroepOnline/pi-wishcraft` (forked from `nicobailon/pi-powerline-footer`, independently maintained)
|
|
10
13
|
- **npm package:** `@groeponline/pi-wishcraft` (scoped, `--access public`)
|
|
11
14
|
- **Default branch:** `main`
|
|
12
15
|
- **Local checkout:** `/home/joep/pi-wishcraft`
|
|
@@ -35,7 +38,7 @@ npm run release minor # = node scripts/release.mjs minor
|
|
|
35
38
|
5. `git tag -a v<version> -m "Release <version>"`
|
|
36
39
|
|
|
37
40
|
It does **not** push — it prints the push command. Push with the GroepOnline SSH
|
|
38
|
-
identity (the laptop default
|
|
41
|
+
identity (the laptop default SSH key is denied for this org):
|
|
39
42
|
|
|
40
43
|
```bash
|
|
41
44
|
GIT_SSH_COMMAND='ssh -F ~/.ssh/config-groeponline -o IdentityFile=~/.ssh/sheesh' \
|
|
@@ -97,8 +100,8 @@ A release is "done" when all four hold: local green, tag on origin, CI
|
|
|
97
100
|
publish succeeded. The CI log line `+ @groeponline/pi-wishcraft@<v>`
|
|
98
101
|
and HTTP `200` from `https://registry.npmjs.org/@groeponline%2fpi-wishcraft`
|
|
99
102
|
are the real success signals; retry `npm view` if you see an early 404.
|
|
100
|
-
- **Wrong SSH key = `Permission denied (publickey)
|
|
101
|
-
Always push with `GIT_SSH_COMMAND='ssh -F ~/.ssh/config-groeponline -o IdentityFile=~/.ssh/sheesh'
|
|
103
|
+
- **Wrong SSH key = `Permission denied (publickey)`.**
|
|
104
|
+
Always push with `GIT_SSH_COMMAND='ssh -F ~/.ssh/config-groeponline -o IdentityFile=~/.ssh/sheesh'` (chefadmin-netizen / `~/.ssh/sheesh`).
|
|
102
105
|
- **TPS used to show absurd values** (e.g. `tps:12775`) because `sessionStartTime`
|
|
103
106
|
resets on extension reload while output is cumulative. Fixed in 0.15.0 with a
|
|
104
107
|
rolling token-rate. If TPS ever looks wrong again, check that `tpsSegment` still
|
package/ROADMAP.md
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
# Roadmap — what to improve & how to integrate better
|
|
2
2
|
|
|
3
|
-
Status after 0.
|
|
3
|
+
Status after 0.18.0. Package is `@groeponline/pi-wishcraft` (renamed from `@groeponline/pi-powerline-footer` in 0.17.x; `src/` restructured by domain; `madge --circular` runs in CI). Concrete, prioritized. Not commitments — pick what Joep wants.
|
|
4
4
|
|
|
5
|
-
## Next release (0.
|
|
5
|
+
## Next release (0.19.0)
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
7
|
+
- `npm deprecate @groeponline/pi-powerline-footer "Renamed to @groeponline/pi-wishcraft"` — the old package name still resolves on npm at 0.17.2 and is not deprecated yet. Needs the `@groeponline` scope owner's npm login (no publish auth on the laptop).
|
|
8
|
+
- Generalize `segmentLabels` to every segment (today only tps/open_ports honor it; apply in `renderSegment`).
|
|
9
|
+
- Per-segment `format`/`template` override (`segmentOptions.tps.template: "{value} tok/s"`).
|
|
10
|
+
- Visibility toggle per segment from the `alt+p` menu (writes `powerline.disabledSegments` live).
|
|
11
|
+
- `segmentOptions.tps.windowMs` — expose the 1s window length for fast models (Groq).
|
|
12
|
+
|
|
13
|
+
## Already shipped
|
|
14
|
+
|
|
15
|
+
- 0.18.0 (wishcraft v2, #7): tab token completion, preset rework, git commit/ahead-behind extras, TPS in/out, `/skills` TUI, `src/extension` split into domain subfolders.
|
|
16
|
+
- 0.17.x: package renamed to `@groeponline/pi-wishcraft`; `src/` restructure committed; `madge --circular` is a CI step in `test.yml`; inline skill/command invocation (`/` skills, `$` commands) landed in 0.17.3.
|
|
11
17
|
|
|
12
18
|
## Correctness (done, keep honest)
|
|
13
19
|
|
|
@@ -41,9 +47,7 @@ Status after 0.17.2. Package renamed to `@groeponline/pi-wishcraft` from v0.18.0
|
|
|
41
47
|
|
|
42
48
|
1. **Dependabot vulns** — GitHub flagged 7 (3 high, 4 moderate) on default branch. Triage; most are devDep transitive. Add `npm audit` to CI as non-blocking info, or pin.
|
|
43
49
|
2. **Test the menu.** The overlay/menu functions aren't unit-tested (hard to test `ctx.ui.custom` headless). Add a thin `SelectList`-based pure function for "build segment items" and test that, leaving the overlay shell untested.
|
|
44
|
-
3. **Typecheck in pre-push.**
|
|
45
|
-
4. `npm deprecate @groeponline/pi-powerline-footer "Renamed to @groeponline/pi-wishcraft"` after first successful publish under new name
|
|
46
|
-
5. `prepublishOnly` script with `tsc` to prevent bad types from shipping
|
|
50
|
+
3. **Typecheck in pre-push.** `prepublishOnly` already runs `tsc` so a bad type never ships even if CI is skipped.
|
|
47
51
|
|
|
48
52
|
## Not doing (YAGNI)
|
|
49
53
|
|
package/bash-mode/completion.ts
CHANGED
|
@@ -179,8 +179,30 @@ function escapeShellPath(value: string): string {
|
|
|
179
179
|
return value.replace(/([\\\s"'`$&|;<>()[\]{}?!*])/g, "\\$1");
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
function getPathSuggestions(
|
|
182
|
+
function getPathSuggestions(
|
|
183
|
+
ctx: TokenContext,
|
|
184
|
+
cwd: string,
|
|
185
|
+
): ExtendedCompletionItem[] {
|
|
186
|
+
const token = ctx.token;
|
|
183
187
|
if (!token) return [];
|
|
188
|
+
const tokenStart = ctx.tokenStart;
|
|
189
|
+
const tokenEnd = ctx.tokenEnd;
|
|
190
|
+
|
|
191
|
+
// `~`, `.`, and `..` are directory shorthand, not filenames to match.
|
|
192
|
+
if (token === "~" || token === "." || token === "..") {
|
|
193
|
+
return [
|
|
194
|
+
{
|
|
195
|
+
value: `${token}/`,
|
|
196
|
+
label: `${token}/`,
|
|
197
|
+
replacement: `${token}/`,
|
|
198
|
+
startCol: tokenStart,
|
|
199
|
+
endCol: tokenEnd,
|
|
200
|
+
source: "path",
|
|
201
|
+
score: 50,
|
|
202
|
+
} satisfies ExtendedCompletionItem,
|
|
203
|
+
];
|
|
204
|
+
}
|
|
205
|
+
|
|
184
206
|
const { dir, prefix, displayPrefix } = pathBase(token, cwd);
|
|
185
207
|
|
|
186
208
|
try {
|
|
@@ -188,16 +210,26 @@ function getPathSuggestions(token: string, cwd: string): ExtendedCompletionItem[
|
|
|
188
210
|
.filter((entry) => prefix.length === 0 || entry.name.startsWith(prefix))
|
|
189
211
|
.slice(0, 100);
|
|
190
212
|
|
|
213
|
+
// Complete only the basename part of the token and skip re-emitting the
|
|
214
|
+
// directory prefix the user already typed. For a fully-typed dir (trailing
|
|
215
|
+
// "/") replace the whole token so the new entry is appended correctly.
|
|
216
|
+
const isFullDir = token.endsWith("/");
|
|
217
|
+
const startCol = isFullDir
|
|
218
|
+
? tokenStart
|
|
219
|
+
: displayPrefix.length === 0
|
|
220
|
+
? tokenStart
|
|
221
|
+
: tokenStart + displayPrefix.length;
|
|
222
|
+
|
|
191
223
|
return entries.map((entry) => {
|
|
192
224
|
const suffix = entry.isDirectory() ? "/" : "";
|
|
193
225
|
const label = `${displayPrefix}${entry.name}${suffix}`;
|
|
194
|
-
const replacement = `${displayPrefix}${escapeShellPath(entry.name)}${suffix}`;
|
|
226
|
+
const replacement = `${isFullDir ? displayPrefix : ""}${escapeShellPath(entry.name)}${suffix}`;
|
|
195
227
|
return {
|
|
196
228
|
value: replacement,
|
|
197
229
|
label,
|
|
198
230
|
replacement,
|
|
199
|
-
startCol
|
|
200
|
-
endCol:
|
|
231
|
+
startCol,
|
|
232
|
+
endCol: tokenEnd,
|
|
201
233
|
source: "path",
|
|
202
234
|
score: 40 + (entry.isDirectory() ? 4 : 0),
|
|
203
235
|
} satisfies ExtendedCompletionItem;
|
|
@@ -237,7 +269,8 @@ function getGitSuggestions(ctx: TokenContext, cwd: string): ExtendedCompletionIt
|
|
|
237
269
|
startCol: 0,
|
|
238
270
|
endCol: 0,
|
|
239
271
|
source: "git",
|
|
240
|
-
|
|
272
|
+
// Exact subcommand matches outrank mere prefixes (e.g. `git sta` → status).
|
|
273
|
+
score: command === ctx.token ? 62 : 52,
|
|
241
274
|
}));
|
|
242
275
|
}
|
|
243
276
|
|
|
@@ -400,7 +433,7 @@ export class BashCompletionEngine {
|
|
|
400
433
|
private getDeterministicInlineSuggestions(ctx: TokenContext, cwd: string): ExtendedCompletionItem[] {
|
|
401
434
|
const items: ExtendedCompletionItem[] = [];
|
|
402
435
|
items.push(...withRange(getGitSuggestions(ctx, cwd), ctx.tokenStart, ctx.tokenEnd));
|
|
403
|
-
items.push(...
|
|
436
|
+
items.push(...getPathSuggestions(ctx, cwd));
|
|
404
437
|
|
|
405
438
|
return uniqueByReplacement(items);
|
|
406
439
|
}
|
package/bash-mode/editor.ts
CHANGED
|
@@ -175,7 +175,7 @@ export class BashModeEditor extends CustomEditor {
|
|
|
175
175
|
(bashMode || oneOffBashCommand) &&
|
|
176
176
|
this.keybindingsRef.matches(data, "tui.input.tab")
|
|
177
177
|
) {
|
|
178
|
-
this.
|
|
178
|
+
this.completeGhostSuggestionOneToken();
|
|
179
179
|
return;
|
|
180
180
|
}
|
|
181
181
|
|
|
@@ -349,6 +349,47 @@ export class BashModeEditor extends CustomEditor {
|
|
|
349
349
|
return true;
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
+
/**
|
|
353
|
+
* Advance the buffer by exactly one token/segment toward the active ghost
|
|
354
|
+
* suggestion (the next whitespace-delimited chunk). Repeated Tabs step
|
|
355
|
+
* through the rest of the suggestion one token at a time instead of
|
|
356
|
+
* inserting the whole line at once. The ghost stays live after a partial
|
|
357
|
+
* step so the next Tab continues from where it left off, and it is only
|
|
358
|
+
* cleared once the full suggestion has been inserted.
|
|
359
|
+
*/
|
|
360
|
+
private completeGhostSuggestionOneToken(): boolean {
|
|
361
|
+
if (!this.ghost) return false;
|
|
362
|
+
const text = this.getExpandedText();
|
|
363
|
+
if (text.includes("\n")) return false;
|
|
364
|
+
|
|
365
|
+
const cursor = this.getCursor();
|
|
366
|
+
if (cursor.line !== 0 || cursor.col !== text.length) return false;
|
|
367
|
+
|
|
368
|
+
const value = this.ghost.value;
|
|
369
|
+
if (!value.startsWith(text) || value === text) return false;
|
|
370
|
+
|
|
371
|
+
// Next chunk = leading whitespace (when the current token is complete)
|
|
372
|
+
// plus the next whitespace-delimited token from the projected ghost value.
|
|
373
|
+
const rest = value.slice(text.length);
|
|
374
|
+
const nextChunk = rest.match(/^\s*\S*/)?.[0];
|
|
375
|
+
if (!nextChunk) return false;
|
|
376
|
+
|
|
377
|
+
const next = text + nextChunk;
|
|
378
|
+
this.setText(next);
|
|
379
|
+
|
|
380
|
+
if (value === next) {
|
|
381
|
+
// The full ghost suggestion is now in the buffer; nothing is left to
|
|
382
|
+
// step through.
|
|
383
|
+
this.clearGhostSuggestion();
|
|
384
|
+
} else if (value.startsWith(next)) {
|
|
385
|
+
// Re-resolve against the updated buffer rather than reusing a stale ghost.
|
|
386
|
+
this.scheduleGhostUpdate();
|
|
387
|
+
} else {
|
|
388
|
+
this.clearGhostSuggestion();
|
|
389
|
+
}
|
|
390
|
+
return true;
|
|
391
|
+
}
|
|
392
|
+
|
|
352
393
|
private isPromptHistoryRecallPosition(): boolean {
|
|
353
394
|
if (this.isShowingAutocomplete()) return false;
|
|
354
395
|
|
|
@@ -429,7 +470,7 @@ export class BashModeEditor extends CustomEditor {
|
|
|
429
470
|
.catch((error) => {
|
|
430
471
|
if (error instanceof Error && error.message === "aborted") return;
|
|
431
472
|
console.debug(
|
|
432
|
-
"[
|
|
473
|
+
"[wishcraft] Failed to resolve bash ghost suggestion:",
|
|
433
474
|
error,
|
|
434
475
|
);
|
|
435
476
|
});
|
package/bash-mode/history.ts
CHANGED
|
@@ -109,7 +109,7 @@ export function readProjectHistory(cwd: string): PersistedHistoryEntry[] {
|
|
|
109
109
|
// Project history is a best-effort cache. If it is unreadable or malformed,
|
|
110
110
|
// bash mode should keep working instead of failing command entry entirely.
|
|
111
111
|
console.debug(
|
|
112
|
-
`[
|
|
112
|
+
`[wishcraft] Failed to read bash project history from ${filePath}:`,
|
|
113
113
|
error,
|
|
114
114
|
);
|
|
115
115
|
return [];
|
|
@@ -151,7 +151,7 @@ export function appendProjectHistory(
|
|
|
151
151
|
} catch (error) {
|
|
152
152
|
// History persistence should never block a successful shell command from completing.
|
|
153
153
|
console.debug(
|
|
154
|
-
`[
|
|
154
|
+
`[wishcraft] Failed to persist bash project history to ${filePath}:`,
|
|
155
155
|
error,
|
|
156
156
|
);
|
|
157
157
|
}
|
|
@@ -234,7 +234,7 @@ export function readGlobalShellHistory(shellPath: string): string[] {
|
|
|
234
234
|
globalHistoryCache.set(cacheKey, { ...stat, entries: [] });
|
|
235
235
|
}
|
|
236
236
|
console.debug(
|
|
237
|
-
`[
|
|
237
|
+
`[wishcraft] Failed to read global shell history for ${shellName}:`,
|
|
238
238
|
error,
|
|
239
239
|
);
|
|
240
240
|
return [];
|
package/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { default } from "./src/extension/activate.ts";
|
|
1
|
+
export { default } from "./src/extension/session/activate.ts";
|
|
2
2
|
export {
|
|
3
3
|
parseBashModeSettings,
|
|
4
4
|
resolveShortcutConfig,
|
|
5
|
-
} from "./src/extension/shortcuts-config.ts";
|
|
6
|
-
export type { PowerlineShortcuts } from "./src/extension/types.ts";
|
|
5
|
+
} from "./src/extension/shortcuts/shortcuts-config.ts";
|
|
6
|
+
export type { PowerlineShortcuts } from "./src/extension/core/types.ts";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@groeponline/pi-wishcraft",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Wishcraft status bar & interaction layer for the pi coding agent — powerline segments, vibes, queue, bash mode, and full customization.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -21,12 +21,16 @@
|
|
|
21
21
|
"status-bar",
|
|
22
22
|
"extension"
|
|
23
23
|
],
|
|
24
|
-
"author": "
|
|
24
|
+
"author": "GroepOnline",
|
|
25
25
|
"license": "MIT",
|
|
26
|
+
"homepage": "https://github.com/GroepOnline/pi-wishcraft#readme",
|
|
26
27
|
"repository": {
|
|
27
28
|
"type": "git",
|
|
28
29
|
"url": "git+https://github.com/GroepOnline/pi-wishcraft.git"
|
|
29
30
|
},
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/GroepOnline/pi-wishcraft/issues"
|
|
33
|
+
},
|
|
30
34
|
"scripts": {
|
|
31
35
|
"typecheck": "tsc --noEmit",
|
|
32
36
|
"test": "node --experimental-strip-types --test tests/**/*.test.ts",
|