@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.
Files changed (47) hide show
  1. package/AGENTS.md +14 -10
  2. package/CHANGELOG.md +20 -0
  3. package/README.md +40 -11
  4. package/RELEASE.md +10 -7
  5. package/ROADMAP.md +13 -9
  6. package/bash-mode/completion.ts +39 -6
  7. package/bash-mode/editor.ts +43 -2
  8. package/bash-mode/history.ts +3 -3
  9. package/index.ts +3 -3
  10. package/package.json +6 -2
  11. package/src/config/presets.ts +101 -19
  12. package/src/config/segment-options.ts +11 -0
  13. package/src/config/types.ts +12 -0
  14. package/src/core/frontmatter.ts +43 -0
  15. package/src/extension/{bash-mode-actions.ts → commands/bash-mode-actions.ts} +4 -4
  16. package/src/extension/{commands.ts → commands/commands.ts} +16 -11
  17. package/src/extension/{queue-commands.ts → commands/queue-commands.ts} +4 -4
  18. package/src/extension/{vibe-command.ts → commands/vibe-command.ts} +2 -3
  19. package/src/extension/{constants.ts → core/constants.ts} +2 -5
  20. package/src/extension/{segment-context.ts → core/segment-context.ts} +8 -11
  21. package/src/extension/{state.ts → core/state.ts} +14 -14
  22. package/src/extension/{types.ts → core/types.ts} +9 -9
  23. package/src/extension/{prompt-history.ts → history/prompt-history.ts} +3 -3
  24. package/src/extension/{stash-history.ts → history/stash-history.ts} +6 -6
  25. package/src/extension/{queue-context.ts → queue/queue-context.ts} +1 -1
  26. package/src/extension/{queue-integration.ts → queue/queue-integration.ts} +12 -9
  27. package/src/extension/{activate.ts → session/activate.ts} +7 -7
  28. package/src/extension/{git-invalidation.ts → session/git-invalidation.ts} +3 -3
  29. package/src/extension/{session-lifecycle.ts → session/session-lifecycle.ts} +25 -22
  30. package/src/extension/{settings-io.ts → settings/settings-io.ts} +10 -10
  31. package/src/extension/{shortcuts-config.ts → shortcuts/shortcuts-config.ts} +8 -8
  32. package/src/extension/{shortcuts-router.ts → shortcuts/shortcuts-router.ts} +10 -13
  33. package/src/extension/skills/inline-invocation.ts +150 -128
  34. package/src/extension/skills/skill-manager.ts +242 -0
  35. package/src/extension/{custom-editor.ts → ui/custom-editor.ts} +15 -16
  36. package/src/extension/{layout.ts → ui/layout.ts} +10 -10
  37. package/src/extension/{menu-views.ts → ui/menu-views.ts} +7 -7
  38. package/src/extension/{powerline-widgets.ts → ui/powerline-widgets.ts} +6 -3
  39. package/src/extension/{status-line-renderers.ts → ui/status-line-renderers.ts} +13 -10
  40. package/src/extension/{welcome-control.ts → welcome/welcome-control.ts} +1 -1
  41. package/src/extension/{welcome-integration.ts → welcome/welcome-integration.ts} +10 -8
  42. package/src/git/status.ts +75 -7
  43. package/src/segments/core.ts +31 -2
  44. package/src/segments/custom.ts +7 -1
  45. package/src/segments/system.ts +51 -23
  46. package/src/shell/cd-command.ts +2 -2
  47. /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/` — activation, command handlers, session lifecycle,
20
- custom editor wiring, shortcut routing, settings IO, queue and menu views.
21
- Leaf modules (`types.ts`, `constants.ts`, `queue-context.ts`,
22
- `welcome-control.ts`, `settings-io.ts`, `prompt-history.ts`,
23
- `stash-history.ts`, `shortcuts-config.ts`) keep the dependency graph
24
- acyclic: shared types and constants live in leaves, queue/welcome
25
- callbacks are wired through leaves or `RuntimeState`, and `state.ts` is
26
- the hub that only has inbound edges. Verify with `npx madge --circular
27
- src index.ts bash-mode queue`.
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` | Model, thinking, path (basename), git, context, tokens, cost |
129
- | `minimal` | Just path (basename), git, context |
130
- | `compact` | Model, git, cost, context |
131
- | `full` | Everything including hostname, time, abbreviated path |
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, rolling 1-second window (EMA-free, no spikes); a rocket/bolt icon lights up while generating (override with env `POWERLINE_TPS`)
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 accepts the current ghost suggestion when one exists; otherwise it does nothing
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` · `thinking` · `shell_mode` · `path` · `git` · `subagents` · `token_in` · `token_out` · `token_total` · `cost` · `context_pct` · `context_total` · `time_spent` · `time` · `session` · `hostname` · `cache_read` · `cache_write` · `extension_statuses`
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
- This is the GroepOnline fork of `pi-powerline-footer`. It ships to npm as the
4
- scoped package `@groeponline/pi-wishcraft` and installs locally from the
5
- repo path. This doc records the end-to-end release flow and how to verify it.
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` (fork of `nicobailon/pi-powerline-footer`)
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 `ssh`/OnlineChef key is denied for this org):
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)` / `denied to OnlineChef`.**
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.17.2. Package renamed to `@groeponline/pi-wishcraft` from v0.18.0. Concrete, prioritized. Not commitments — pick what Joep wants.
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.18.0 — pi-wishcraft)
5
+ ## Next release (0.19.0)
6
6
 
7
- - Package renamed from `@groeponline/pi-powerline-footer` to `@groeponline/pi-wishcraft`
8
- - src/ restructure committed (all root-level monofiles moved to `src/<domain>/`)
9
- - Flaky `process.env.USER` test fixed
10
- - `npx madge --circular src index.ts bash-mode queue` added as CI step
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.** Add a `prepublishOnly` that runs `tsc` so a bad type never ships even if CI is skipped.
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
 
@@ -179,8 +179,30 @@ function escapeShellPath(value: string): string {
179
179
  return value.replace(/([\\\s"'`$&|;<>()[\]{}?!*])/g, "\\$1");
180
180
  }
181
181
 
182
- function getPathSuggestions(token: string, cwd: string): ExtendedCompletionItem[] {
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: 0,
200
- endCol: 0,
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
- score: 52,
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(...withRange(getPathSuggestions(ctx.token, cwd), ctx.tokenStart, ctx.tokenEnd));
436
+ items.push(...getPathSuggestions(ctx, cwd));
404
437
 
405
438
  return uniqueByReplacement(items);
406
439
  }
@@ -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.acceptGhostSuggestion();
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
- "[powerline-footer] Failed to resolve bash ghost suggestion:",
473
+ "[wishcraft] Failed to resolve bash ghost suggestion:",
433
474
  error,
434
475
  );
435
476
  });
@@ -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
- `[powerline-footer] Failed to read bash project history from ${filePath}:`,
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
- `[powerline-footer] Failed to persist bash project history to ${filePath}:`,
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
- `[powerline-footer] Failed to read global shell history for ${shellName}:`,
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.17.3",
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": "Nico Bailon",
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",