@groeponline/pi-wishcraft 0.17.3

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 (106) hide show
  1. package/AGENTS.md +68 -0
  2. package/CHANGELOG.md +724 -0
  3. package/CONTRIBUTING.md +37 -0
  4. package/README.md +648 -0
  5. package/RELEASE.md +117 -0
  6. package/ROADMAP.md +52 -0
  7. package/bash-mode/completion-providers.ts +269 -0
  8. package/bash-mode/completion.ts +416 -0
  9. package/bash-mode/editor-ghost.ts +40 -0
  10. package/bash-mode/editor-input.ts +80 -0
  11. package/bash-mode/editor.ts +437 -0
  12. package/bash-mode/history.ts +263 -0
  13. package/bash-mode/shell-session.ts +286 -0
  14. package/bash-mode/transcript.ts +108 -0
  15. package/bash-mode/types.ts +80 -0
  16. package/index.ts +6 -0
  17. package/package.json +55 -0
  18. package/queue/store.ts +443 -0
  19. package/queue/types.ts +54 -0
  20. package/src/config/custom-items.ts +182 -0
  21. package/src/config/extension-statuses.ts +51 -0
  22. package/src/config/layout.ts +60 -0
  23. package/src/config/parse.ts +127 -0
  24. package/src/config/powerline-config.ts +18 -0
  25. package/src/config/presets.ts +245 -0
  26. package/src/config/primitives.ts +117 -0
  27. package/src/config/segment-ids.ts +114 -0
  28. package/src/config/segment-options.ts +128 -0
  29. package/src/config/settings-patch.ts +26 -0
  30. package/src/config/types.ts +277 -0
  31. package/src/core/frontmatter.ts +40 -0
  32. package/src/editor/autocomplete-chain.ts +41 -0
  33. package/src/extension/activate.ts +28 -0
  34. package/src/extension/bash-mode-actions.ts +104 -0
  35. package/src/extension/commands.ts +268 -0
  36. package/src/extension/constants.ts +46 -0
  37. package/src/extension/custom-editor.ts +406 -0
  38. package/src/extension/git-invalidation.ts +40 -0
  39. package/src/extension/layout.ts +160 -0
  40. package/src/extension/menu-views.ts +393 -0
  41. package/src/extension/powerline-widgets.ts +95 -0
  42. package/src/extension/prompt-history.ts +219 -0
  43. package/src/extension/queue-commands.ts +245 -0
  44. package/src/extension/queue-context.ts +12 -0
  45. package/src/extension/queue-integration.ts +434 -0
  46. package/src/extension/segment-context.ts +212 -0
  47. package/src/extension/session-lifecycle.ts +373 -0
  48. package/src/extension/settings-io.ts +202 -0
  49. package/src/extension/shortcuts-config.ts +357 -0
  50. package/src/extension/shortcuts-router.ts +383 -0
  51. package/src/extension/skills/inline-invocation.ts +174 -0
  52. package/src/extension/skills/ook.md +6 -0
  53. package/src/extension/skills/test.md +6 -0
  54. package/src/extension/stale-context.ts +10 -0
  55. package/src/extension/stash-history.ts +103 -0
  56. package/src/extension/state.ts +159 -0
  57. package/src/extension/status-line-renderers.ts +222 -0
  58. package/src/extension/types.ts +97 -0
  59. package/src/extension/vibe-command.ts +160 -0
  60. package/src/extension/welcome-control.ts +27 -0
  61. package/src/extension/welcome-integration.ts +153 -0
  62. package/src/git/status.ts +332 -0
  63. package/src/paths/agent-dirs.ts +67 -0
  64. package/src/render/timer.ts +46 -0
  65. package/src/segments/core.ts +256 -0
  66. package/src/segments/custom.ts +114 -0
  67. package/src/segments/index.ts +3 -0
  68. package/src/segments/registry.ts +87 -0
  69. package/src/segments/shared.ts +36 -0
  70. package/src/segments/system.ts +235 -0
  71. package/src/segments/usage.ts +178 -0
  72. package/src/shell/cd-command.ts +190 -0
  73. package/src/shortcuts/matching.ts +61 -0
  74. package/src/theme/colors.ts +60 -0
  75. package/src/theme/icons.ts +175 -0
  76. package/src/theme/separators.ts +41 -0
  77. package/src/theme/theme.ts +211 -0
  78. package/src/tools/graph.ts +75 -0
  79. package/src/tools/patch.ts +179 -0
  80. package/src/tools/ripgrep.ts +104 -0
  81. package/src/usage/context.ts +97 -0
  82. package/src/usage/ledger.ts +293 -0
  83. package/src/usage/rates.ts +155 -0
  84. package/src/welcome/auto-dismiss.ts +43 -0
  85. package/src/welcome/banner.ts +68 -0
  86. package/src/welcome/discover.ts +234 -0
  87. package/src/welcome/format.ts +18 -0
  88. package/src/welcome/index.ts +5 -0
  89. package/src/welcome/layout.ts +36 -0
  90. package/src/welcome/overlay.ts +80 -0
  91. package/src/welcome/renderer.ts +157 -0
  92. package/src/welcome/sessions.ts +107 -0
  93. package/src/welcome/types.ts +41 -0
  94. package/src/welcome/widgets/graph-widget.ts +25 -0
  95. package/src/welcome/widgets/index.ts +20 -0
  96. package/src/welcome/widgets/queue-widget.ts +26 -0
  97. package/src/welcome/widgets/sessions-widget.ts +23 -0
  98. package/src/welcome/widgets/shortcuts-widget.ts +17 -0
  99. package/src/welcome/widgets/system-widget.ts +29 -0
  100. package/src/working-vibes/generate.ts +144 -0
  101. package/src/working-vibes/index.ts +24 -0
  102. package/src/working-vibes/manager.ts +198 -0
  103. package/src/working-vibes/provider.ts +163 -0
  104. package/src/working-vibes/storage.ts +357 -0
  105. package/theme.example.json +24 -0
  106. package/tsconfig.json +13 -0
@@ -0,0 +1,104 @@
1
+ import {
2
+ appendProjectHistory,
3
+ matchHistoryEntries,
4
+ readGlobalShellHistory,
5
+ readProjectHistory,
6
+ } from "../../bash-mode/history.ts";
7
+ import { ManagedShellSession } from "../../bash-mode/shell-session.ts";
8
+ import { requestStatusRender } from "./segment-context.ts";
9
+ import type { RuntimeState } from "./types.ts";
10
+
11
+ export const getShellPath = () => process.env.SHELL || "/bin/sh";
12
+
13
+ export const getShellCwd = (rt: RuntimeState) =>
14
+ rt.shellSession?.state.cwd ?? rt.currentCtx?.cwd ?? process.cwd();
15
+
16
+ export const getShellHistoryEntries = (
17
+ rt: RuntimeState,
18
+ prefix: string,
19
+ ): string[] => {
20
+ const project = matchHistoryEntries(
21
+ readProjectHistory(rt.currentCtx?.cwd ?? process.cwd()).map(
22
+ (entry) => entry.command,
23
+ ),
24
+ prefix,
25
+ 50,
26
+ );
27
+ const global = matchHistoryEntries(
28
+ readGlobalShellHistory(getShellPath()),
29
+ prefix,
30
+ 50,
31
+ );
32
+ return [...new Set([...project, ...global])];
33
+ };
34
+
35
+ export const ensureShellSession = async (
36
+ rt: RuntimeState,
37
+ ): Promise<ManagedShellSession> => {
38
+ if (!rt.shellSession) {
39
+ rt.shellSession = new ManagedShellSession(
40
+ getShellPath(),
41
+ rt.currentCtx?.cwd ?? process.cwd(),
42
+ rt.bashTranscript,
43
+ () => requestStatusRender(rt),
44
+ (command, cwd) =>
45
+ appendProjectHistory(rt.currentCtx?.cwd ?? process.cwd(), command, cwd),
46
+ );
47
+ }
48
+ await rt.shellSession.ensureReady();
49
+ return rt.shellSession;
50
+ };
51
+
52
+ export const runShellCommand = async (
53
+ rt: RuntimeState,
54
+ command: string,
55
+ ctx: any,
56
+ ): Promise<void> => {
57
+ try {
58
+ const session = await ensureShellSession(rt);
59
+ await session.runCommand(command);
60
+ requestStatusRender(rt);
61
+ } catch (error) {
62
+ const message = error instanceof Error ? error.message : String(error);
63
+ ctx.ui.notify(`Failed to run shell command: ${message}`, "error");
64
+ }
65
+ };
66
+
67
+ export const setBashModeActive = async (
68
+ rt: RuntimeState,
69
+ value: boolean,
70
+ ctx: any,
71
+ ): Promise<void> => {
72
+ if (value === rt.bashModeActive) return;
73
+ if (!value && rt.shellSession?.state.running) {
74
+ ctx.ui.notify(
75
+ "Wait for the current shell command to finish before leaving bash mode",
76
+ "warning",
77
+ );
78
+ return;
79
+ }
80
+
81
+ if (value) {
82
+ try {
83
+ const session = await ensureShellSession(rt);
84
+ rt.bashModeActive = true;
85
+ rt.currentEditor?.dismissBashModeUi?.();
86
+ rt.currentEditor?.refreshGhostSuggestion?.();
87
+ requestStatusRender(rt);
88
+ ctx.ui.notify(`Bash mode enabled (${session.state.shellName})`, "info");
89
+ } catch (error) {
90
+ rt.shellSession?.dispose();
91
+ rt.shellSession = null;
92
+ rt.bashModeActive = false;
93
+ requestStatusRender(rt);
94
+ const message = error instanceof Error ? error.message : String(error);
95
+ ctx.ui.notify(`Failed to start shell session: ${message}`, "error");
96
+ }
97
+ return;
98
+ }
99
+
100
+ rt.bashModeActive = value;
101
+ rt.currentEditor?.dismissBashModeUi?.();
102
+ requestStatusRender(rt);
103
+ ctx.ui.notify("Bash mode disabled", "info");
104
+ };
@@ -0,0 +1,268 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { type KeyId, type SelectItem } from "@earendil-works/pi-tui";
3
+ import { execSync } from "node:child_process";
4
+
5
+ import type { StatusLinePreset } from "../config/types.ts";
6
+ import { PRESETS } from "../config/presets.ts";
7
+ import { registerCdCommand } from "../shell/cd-command.ts";
8
+ import { registerVibeCommand } from "./vibe-command.ts";
9
+ import { registerQueueCommands } from "./queue-commands.ts";
10
+ import {
11
+ writePowerlineOptionSetting,
12
+ writePowerlinePresetSetting,
13
+ } from "./settings-io.ts";
14
+ import {
15
+ showOpenPortsList,
16
+ showPowerlineMainMenu,
17
+ showSelectOverlay,
18
+ } from "./menu-views.ts";
19
+ import { openStashHistory } from "./shortcuts-router.ts";
20
+ import { ensureShellSession, setBashModeActive } from "./bash-mode-actions.ts";
21
+ import { setupCustomEditor } from "./custom-editor.ts";
22
+ import { getPromptHistoryState } from "./prompt-history.ts";
23
+ import { requestStatusRender, resetLayoutCache } from "./segment-context.ts";
24
+ import { config, normalizePreset } from "./state.ts";
25
+ import type { RuntimeState } from "./types.ts";
26
+
27
+ export function registerCommands(pi: ExtensionAPI, rt: RuntimeState): void {
28
+ registerCdCommand(pi, () => rt.currentCtx?.cwd ?? process.cwd());
29
+ registerVibeCommand(pi);
30
+ registerQueueCommands(pi, rt);
31
+
32
+ // Command to toggle/configure
33
+ pi.registerCommand("powerline", {
34
+ description: "Configure powerline status (toggle, preset)",
35
+ handler: async (args, ctx) => {
36
+ // Update context reference (command ctx may have more methods)
37
+ rt.currentCtx = ctx;
38
+
39
+ if (!args?.trim()) {
40
+ // Toggle
41
+ rt.enabled = !rt.enabled;
42
+ if (rt.enabled) {
43
+ setupCustomEditor(pi, rt, ctx);
44
+ ctx.ui.notify("Powerline enabled", "info");
45
+ } else {
46
+ rt.shellSession?.dispose();
47
+ rt.shellSession = null;
48
+ rt.bashTranscript.clear();
49
+ rt.bashModeActive = false;
50
+ rt.dismissWelcomeOverlay?.();
51
+ rt.dismissWelcomeOverlay = null;
52
+ rt.welcomeHeaderActive = false;
53
+ rt.welcomeOverlayShouldDismiss = false;
54
+ rt.welcomeDismissScheduler.cancel();
55
+ getPromptHistoryState().savedPromptHistory = [];
56
+ rt.stashedEditorText = null;
57
+ ctx.ui.setStatus("stash", undefined);
58
+ rt.restoreFooterStatusRepaintHook?.();
59
+ rt.restoreFooterStatusRepaintHook = null;
60
+ rt.stashShortcutInputUnsubscribe?.();
61
+ rt.stashShortcutInputUnsubscribe = null;
62
+ // Clear all custom UI components
63
+ ctx.ui.setEditorComponent(undefined);
64
+ ctx.ui.setFooter(undefined);
65
+ ctx.ui.setHeader(undefined);
66
+ ctx.ui.setWidget("powerline-top", undefined);
67
+ ctx.ui.setWidget("powerline-secondary", undefined);
68
+ ctx.ui.setWidget("powerline-bash-transcript", undefined);
69
+ ctx.ui.setWidget("powerline-status", undefined);
70
+ ctx.ui.setWidget("powerline-queue-preview", undefined);
71
+ ctx.ui.setWidget("powerline-last-prompt", undefined);
72
+ rt.footerDataRef = null;
73
+ rt.tuiRef = null;
74
+ rt.currentEditor = null;
75
+ rt.statusRenderScheduler.cancel();
76
+ resetLayoutCache(rt);
77
+ ctx.ui.notify("Powerline disabled", "info");
78
+ }
79
+ return;
80
+ }
81
+
82
+ const normalizedArgs = args.trim().toLowerCase();
83
+ const placementMatch = /^placement(?:\s+(above|below|toggle))?$/.exec(
84
+ normalizedArgs,
85
+ );
86
+ if (placementMatch) {
87
+ const requestedPlacement = placementMatch[1];
88
+ config.placement =
89
+ requestedPlacement === "above" || requestedPlacement === "below"
90
+ ? requestedPlacement
91
+ : config.placement === "above"
92
+ ? "below"
93
+ : "above";
94
+ config.invalidPlacement = null;
95
+ if (rt.enabled && ctx.hasUI) setupCustomEditor(pi, rt, ctx);
96
+
97
+ if (
98
+ writePowerlineOptionSetting(
99
+ ctx.cwd,
100
+ { placement: config.placement },
101
+ config.preset,
102
+ )
103
+ ) {
104
+ ctx.ui.notify(
105
+ `Powerline placement set to: ${config.placement}`,
106
+ "info",
107
+ );
108
+ } else {
109
+ ctx.ui.notify(
110
+ `Powerline placement set to: ${config.placement} (not persisted; check settings.json)`,
111
+ "warning",
112
+ );
113
+ }
114
+ return;
115
+ }
116
+
117
+ const preset = normalizePreset(args);
118
+ if (preset) {
119
+ config.preset = preset;
120
+ resetLayoutCache(rt);
121
+ if (rt.enabled) {
122
+ setupCustomEditor(pi, rt, ctx);
123
+ }
124
+
125
+ if (writePowerlinePresetSetting(preset, ctx.cwd)) {
126
+ ctx.ui.notify(`Preset set to: ${preset}`, "info");
127
+ } else {
128
+ ctx.ui.notify(
129
+ `Preset set to: ${preset} (not persisted; check settings.json)`,
130
+ "warning",
131
+ );
132
+ }
133
+ return;
134
+ }
135
+
136
+ // Show available presets
137
+ const presetList = Object.keys(PRESETS).join(", ");
138
+ ctx.ui.notify(`Available presets: ${presetList}`, "info");
139
+ },
140
+ });
141
+
142
+ pi.registerCommand("stash-history", {
143
+ description: "Open prompt history picker",
144
+ handler: async (_args, ctx) => {
145
+ if (!ctx.hasUI) return;
146
+ if (!rt.enabled) {
147
+ ctx.ui.notify("Powerline is disabled", "info");
148
+ return;
149
+ }
150
+
151
+ await openStashHistory(rt, ctx);
152
+ },
153
+ });
154
+
155
+ pi.registerCommand("bash-mode", {
156
+ description: "Toggle sticky bash mode (on, off, toggle)",
157
+ handler: async (args, ctx) => {
158
+ const mode = args?.trim().toLowerCase() || "toggle";
159
+ if (mode === "on") {
160
+ await setBashModeActive(rt, true, ctx);
161
+ return;
162
+ }
163
+ if (mode === "off") {
164
+ await setBashModeActive(rt, false, ctx);
165
+ return;
166
+ }
167
+ if (mode === "toggle") {
168
+ await setBashModeActive(rt, !rt.bashModeActive, ctx);
169
+ return;
170
+ }
171
+ ctx.ui.notify("Usage: /bash-mode [on|off|toggle]", "warning");
172
+ },
173
+ });
174
+
175
+ pi.registerCommand("bash-reset", {
176
+ description: "Reset the managed bash session",
177
+ handler: async (_args, ctx) => {
178
+ rt.shellSession?.dispose();
179
+ rt.shellSession = null;
180
+ rt.bashTranscript.clear();
181
+ if (rt.bashModeActive) {
182
+ try {
183
+ await ensureShellSession(rt);
184
+ } catch (error) {
185
+ rt.bashModeActive = false;
186
+ const message =
187
+ error instanceof Error ? error.message : String(error);
188
+ ctx.ui.notify(`Failed to restart shell session: ${message}`, "error");
189
+ requestStatusRender(rt);
190
+ return;
191
+ }
192
+ }
193
+ requestStatusRender(rt);
194
+ ctx.ui.notify("Bash session reset", "info");
195
+ },
196
+ });
197
+
198
+ pi.registerCommand("tps", {
199
+ description: "Show or set POWERLINE_TPS value",
200
+ handler: async (args, ctx) => {
201
+ rt.currentCtx = ctx;
202
+ const value = args?.trim();
203
+ if (!value) {
204
+ const current = process.env.POWERLINE_TPS || "not set";
205
+ ctx.ui.notify(`TPS: ${current}`, "info");
206
+ return;
207
+ }
208
+ process.env.POWERLINE_TPS = value;
209
+ ctx.ui.notify(`TPS set to: ${value}`, "info");
210
+ rt.tuiRef?.requestRender();
211
+ },
212
+ });
213
+
214
+ pi.registerCommand("open-ports", {
215
+ description: "Show open ports",
216
+ handler: async (_args, ctx) => {
217
+ rt.currentCtx = ctx;
218
+ try {
219
+ const stdout = execSync("ss -tuln", { encoding: "utf8" });
220
+ const lines = stdout
221
+ .split("\n")
222
+ .filter((line) => line.trim().length > 0);
223
+ const items: SelectItem[] = lines.slice(1).map((line) => ({
224
+ label: line.trim(),
225
+ value: line.trim(),
226
+ }));
227
+ if (items.length === 0) {
228
+ ctx.ui.notify("No open ports found", "info");
229
+ return;
230
+ }
231
+ const selected = await showSelectOverlay(
232
+ ctx,
233
+ "Open Ports",
234
+ "Select a port line for details",
235
+ items,
236
+ Math.min(items.length, 20),
237
+ );
238
+ if (selected) {
239
+ ctx.ui.notify(`Port: ${selected.value}`, "info");
240
+ }
241
+ } catch (error) {
242
+ ctx.ui.notify(
243
+ `Failed to list ports: ${error instanceof Error ? error.message : String(error)}`,
244
+ "error",
245
+ );
246
+ }
247
+ },
248
+ });
249
+
250
+ // Configurable powerline shortcuts (re-bound on /reload via settings.powerlineShortcuts).
251
+ if (rt.resolvedShortcuts.menu) {
252
+ pi.registerShortcut(rt.resolvedShortcuts.menu as KeyId, {
253
+ description: "Powerline menu (navigate / configure / info)",
254
+ handler: async (ctx) => {
255
+ await showPowerlineMainMenu(rt, ctx);
256
+ },
257
+ });
258
+ }
259
+ if (rt.resolvedShortcuts.info) {
260
+ pi.registerShortcut(rt.resolvedShortcuts.info as KeyId, {
261
+ description: "Powerline info (full open-ports list)",
262
+ handler: async (ctx) => {
263
+ rt.currentCtx = ctx;
264
+ await showOpenPortsList(ctx);
265
+ },
266
+ });
267
+ }
268
+ }
@@ -0,0 +1,46 @@
1
+ import type { BashModeSettings } from "../../bash-mode/types.ts";
2
+ import type {
3
+ PowerlineShortcutKey,
4
+ PowerlineShortcuts,
5
+ } from "./types.ts";
6
+
7
+ export const CUSTOM_COMPACTION_STATUS_KEY = "compact-policy";
8
+
9
+ export const STASH_HISTORY_LIMIT = 12;
10
+ export const PROJECT_PROMPT_HISTORY_LIMIT = 50;
11
+ export const STASH_PREVIEW_WIDTH = 72;
12
+
13
+ export const DEFAULT_SHORTCUTS: PowerlineShortcuts = {
14
+ stashHistory: "ctrl+alt+h",
15
+ copyEditor: "ctrl+alt+c",
16
+ cutEditor: "ctrl+alt+x",
17
+ ideaCapture: null,
18
+ queueOpen: "ctrl+alt+q",
19
+ editorStart: "super+shift+up",
20
+ editorEnd: "super+shift+down",
21
+ menu: "alt+p",
22
+ info: "alt+i",
23
+ };
24
+ export const DEFAULT_BASH_MODE_SETTINGS = {
25
+ toggleShortcut: "ctrl+shift+b",
26
+ transcriptMaxLines: 2000,
27
+ transcriptMaxBytes: 512 * 1024,
28
+ } as const satisfies BashModeSettings;
29
+ export const SHORTCUT_KEYS: PowerlineShortcutKey[] = [
30
+ "stashHistory",
31
+ "copyEditor",
32
+ "cutEditor",
33
+ "ideaCapture",
34
+ "queueOpen",
35
+ "editorStart",
36
+ "editorEnd",
37
+ "menu",
38
+ "info",
39
+ ];
40
+
41
+ export const PROMPT_HISTORY_LIMIT = 100;
42
+ export const LAYOUT_CACHE_TTL_MS = 250;
43
+ export const STREAMING_LAYOUT_CACHE_TTL_MS = 1000;
44
+ export const STATUS_RENDER_DEBOUNCE_MS = 33;
45
+ export const CONTEXT_STATUS_RENDER_MS = 250;
46
+ export const EDITOR_STATUS_DEFER_MS = 150;