@henryqw/pi-pr 2.0.4 → 2.1.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/README.md +4 -2
- package/extensions/pr-ui.ts +7 -3
- package/extensions/pr.ts +22 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,7 +23,9 @@ Run `/pr` without arguments in a GitHub checkout. It reads the current branch pu
|
|
|
23
23
|
| Surface | Type | Purpose |
|
|
24
24
|
| --- | --- | --- |
|
|
25
25
|
| Footer | ui | Show a linked `PR #number` and one plain-language status. |
|
|
26
|
-
| Widget
|
|
26
|
+
| Widget | ui | Show one actionable icon-prefixed `Run /pr to …` hint. |
|
|
27
|
+
|
|
28
|
+
The footer already shows the pull request and status. Actionable widgets omit duplicate identity and status. Each uses one semantic status icon, a space, and a plain `Run /pr to …` route. `✗` marks errors, `!` warnings, `✓` success, and `●` accent or neutral routes. In TUI, only the icon uses a theme color. RPC and non-TUI output use the same plain text without ANSI.
|
|
27
29
|
|
|
28
30
|
## Flow
|
|
29
31
|
|
|
@@ -65,7 +67,7 @@ Ordinary conversation comments do not trigger a route or block a merge. Changes
|
|
|
65
67
|
|
|
66
68
|
The footer and widget load at session start. They refresh after local commits, PR creation, pushes, and each dispatched workflow settles. They also poll every 30 seconds. Polling updates presentation only and may be stale.
|
|
67
69
|
|
|
68
|
-
The create
|
|
70
|
+
The create widget stays hidden until the local branch has a commit beyond its creation point. Any displayed widget clears as soon as `/pr` starts. A dispatched workflow keeps it hidden until the agent settles. A direct merge, no-action route, or failed command refreshes the widget when the handler finishes.
|
|
69
71
|
|
|
70
72
|
Presentation uses route priority, so draft appears before running CI. `/pr` reads fresh state before routing or merging. The command is authoritative for actions.
|
|
71
73
|
|
package/extensions/pr-ui.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getCapabilities, hyperlink } from "@earendil-works/pi-tui";
|
|
1
|
+
import { getCapabilities, hyperlink, truncateToWidth } from "@earendil-works/pi-tui";
|
|
2
2
|
import {
|
|
3
3
|
deriveNextStep,
|
|
4
4
|
type NextStep,
|
|
@@ -93,6 +93,10 @@ export function formatPrFooter(display: PrDisplay, theme: PrTheme): string | und
|
|
|
93
93
|
return `${link} · ${theme.fg(display.footer.color, display.footer.text)}`;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
export function formatPrWidget(display: PrDisplay): string | undefined {
|
|
97
|
-
|
|
96
|
+
export function formatPrWidget(display: PrDisplay, theme?: PrTheme, width?: number): string[] | undefined {
|
|
97
|
+
if (display.widget === undefined) return undefined;
|
|
98
|
+
const color = display.footer?.color ?? "accent";
|
|
99
|
+
const icon = color === "error" ? "✗" : color === "warning" ? "!" : color === "success" ? "✓" : "●";
|
|
100
|
+
const line = `${theme ? theme.fg(color, icon) : icon} ${display.widget}`;
|
|
101
|
+
return [width === undefined ? line : truncateToWidth(line, Math.max(1, width))];
|
|
98
102
|
}
|
package/extensions/pr.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
formatPrFooter,
|
|
13
13
|
formatPrWidget,
|
|
14
14
|
projectPrDisplay,
|
|
15
|
+
type PrDisplay,
|
|
15
16
|
} from "./pr-ui.ts";
|
|
16
17
|
|
|
17
18
|
const POLL_INTERVAL_MS = 30_000;
|
|
@@ -39,10 +40,25 @@ export default function pullRequestExtension(
|
|
|
39
40
|
let active: AbortController | undefined;
|
|
40
41
|
let queued = false;
|
|
41
42
|
let refreshFailureReported = false;
|
|
42
|
-
let displayedWidget:
|
|
43
|
+
let displayedWidget: PrDisplay | undefined;
|
|
43
44
|
let commandGeneration = 0;
|
|
44
45
|
const activeInvocations = new Map<number, "routing" | "workflow">();
|
|
45
46
|
|
|
47
|
+
const setWidget = (ctx: ExtensionContext, display: PrDisplay | undefined): void => {
|
|
48
|
+
if (display?.widget === undefined) {
|
|
49
|
+
ctx.ui.setWidget(UI_KEY, undefined);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (ctx.mode === "tui") {
|
|
53
|
+
ctx.ui.setWidget(UI_KEY, (_tui, theme) => ({
|
|
54
|
+
invalidate() {},
|
|
55
|
+
render: (width) => formatPrWidget(display, theme, width)!,
|
|
56
|
+
}));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
ctx.ui.setWidget(UI_KEY, formatPrWidget(display));
|
|
60
|
+
};
|
|
61
|
+
|
|
46
62
|
const render = (
|
|
47
63
|
ctx: ExtensionContext,
|
|
48
64
|
pullRequest: Awaited<ReturnType<typeof loadCurrentPullRequest>>,
|
|
@@ -53,10 +69,10 @@ export default function pullRequestExtension(
|
|
|
53
69
|
if (pullRequest !== null && footer === undefined) {
|
|
54
70
|
throw new Error("Current pull request display is missing a footer");
|
|
55
71
|
}
|
|
56
|
-
displayedWidget =
|
|
72
|
+
displayedWidget = display.widget === undefined ? undefined : display;
|
|
57
73
|
const widget = activeInvocations.size > 0 ? undefined : displayedWidget;
|
|
58
74
|
ctx.ui.setStatus(UI_KEY, footer);
|
|
59
|
-
|
|
75
|
+
setWidget(ctx, widget);
|
|
60
76
|
};
|
|
61
77
|
|
|
62
78
|
const stop = (): void => {
|
|
@@ -172,7 +188,7 @@ export default function pullRequestExtension(
|
|
|
172
188
|
const generation = sessionGeneration;
|
|
173
189
|
const invocation = ++commandGeneration;
|
|
174
190
|
activeInvocations.set(invocation, "routing");
|
|
175
|
-
if (displayedWidget !== undefined)
|
|
191
|
+
if (displayedWidget !== undefined) setWidget(ctx, undefined);
|
|
176
192
|
let nextStep: Awaited<ReturnType<typeof commandHandler>>;
|
|
177
193
|
try {
|
|
178
194
|
nextStep = await commandHandler(args, ctx);
|
|
@@ -181,7 +197,7 @@ export default function pullRequestExtension(
|
|
|
181
197
|
cancelRefresh();
|
|
182
198
|
activeInvocations.delete(invocation);
|
|
183
199
|
if (!activeInvocations.size) {
|
|
184
|
-
|
|
200
|
+
setWidget(ctx, displayedWidget);
|
|
185
201
|
}
|
|
186
202
|
refreshInBackground();
|
|
187
203
|
}
|
|
@@ -192,7 +208,7 @@ export default function pullRequestExtension(
|
|
|
192
208
|
if (nextStep !== "none" && nextStep !== "merge") {
|
|
193
209
|
activeInvocations.set(invocation, "workflow");
|
|
194
210
|
if (nextStep === "create") ctx.ui.setStatus(UI_KEY, undefined);
|
|
195
|
-
|
|
211
|
+
setWidget(ctx, undefined);
|
|
196
212
|
} else {
|
|
197
213
|
activeInvocations.delete(invocation);
|
|
198
214
|
refreshInBackground();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@henryqw/pi-pr",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Run /pr to automatically choose the current pull request's next safe lifecycle step: create, update, address feedback, fix CI, or merge when ready.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|