shariq-pi-extensions 0.3.0 → 0.3.1

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 CHANGED
@@ -24,13 +24,10 @@ The package contains:
24
24
 
25
25
  - structured user questions
26
26
  - managed background terminals
27
- - copy-all transcript support
28
27
  - Firecrawl search and scraping
29
- - Git status UI
30
28
  - persistent task goals
31
29
  - branch-safe model-maintained task lists with live progress UI and compaction continuity
32
30
  - configurable steer, interrupt, or follow-up input behavior
33
- - dedicated multi-agent orchestration
34
31
  - Smart Compaction with high-fidelity checkpointing, delta-merging, and custom model routing
35
32
  - per-response TPS, TTFT, elapsed-time, and output status
36
33
  - Context Usage display
@@ -38,7 +35,7 @@ The package contains:
38
35
  - Pi subagents
39
36
  - lightweight URL fetching
40
37
 
41
- The package also includes the `ember-warm-dark` TUI theme and declares the `background-terminals`, `orchestration`, and `subagents` skills so Pi loads their operating guidance automatically. Pi reads them from the installed package; duplicating files under `<agent-dir>/skills` is unnecessary and would leave stale copies after removal.
38
+ The package also includes the `ember-warm-dark` TUI theme and declares the `background-terminals` and `subagents` skills so Pi loads their operating guidance automatically. Pi reads them from the installed package; duplicating files under `<agent-dir>/skills` is unnecessary and would leave stale copies after removal.
42
39
 
43
40
  See [`docs/EXTENSIONS.md`](docs/EXTENSIONS.md) for commands, tools, configuration, and external dependencies.
44
41
 
@@ -1,6 +1,6 @@
1
1
  # Architecture
2
2
 
3
- Last verified: 2026-08-21
3
+ Last verified: 2026-09-04
4
4
 
5
5
  ## Package boundary
6
6
 
@@ -17,7 +17,7 @@ docs/ package-level maintenance documentation
17
17
  scripts/ repository validation helpers
18
18
  ```
19
19
 
20
- Extension entrypoints register tools, commands, providers, events, or UI. Shared code stays in `extensions/shared` only when more than one extension owns the behavior. The shared activity dock combines active Task List, terminal, subagent, and orchestration rows under one bounded widget; shared tool cards keep lifecycle operations compact in the timeline while preserving expanded output. Provider-specific protocol and authentication code remains inside its provider directory. The background-terminal, orchestration, and subagent skills ship beside their extensions so a new machine receives the required lifecycle guidance with the tools.
20
+ Extension entrypoints register tools, commands, providers, events, or UI. Shared code stays in `extensions/shared` only when more than one extension owns the behavior. The shared activity dock combines active Task List, terminal, and subagent rows under one bounded widget; shared tool cards keep lifecycle operations compact in the timeline while preserving expanded output. Provider-specific protocol and authentication code remains inside its provider directory. The background-terminal and subagent skills ship beside their extensions so a new machine receives the required lifecycle guidance with the tools.
21
21
 
22
22
  ## Dependency model
23
23
 
@@ -37,7 +37,6 @@ Installed package directories are treated as immutable. Extensions resolve writa
37
37
  - Smart Compaction configuration and details ledgers: `<agent-dir>/smart-compaction.json`
38
38
  - Input mode configuration: `<agent-dir>/input-mode.json`
39
39
  - Subagent configuration and catalog: paths derived from `getAgentDir()`
40
- - Orchestration settings and run ledgers: `<agent-dir>/orchestration/`
41
40
  - Goal and Task List state: branch-local Pi session entries; neither writes a separate runtime-state file
42
41
  - project configuration: paths derived from Pi's `CONFIG_DIR_NAME`
43
42
 
@@ -1,6 +1,6 @@
1
1
  # Development and cutover
2
2
 
3
- Last verified: 2026-08-21
3
+ Last verified: 2026-09-04
4
4
 
5
5
  ## Requirements
6
6
 
@@ -45,7 +45,7 @@ Keep secrets out of examples and fixtures. Tests should inject temporary roots,
45
45
 
46
46
  ## Skills paired with extensions
47
47
 
48
- The root manifest declares `skills/background-terminals`, `skills/orchestration`, and `skills/subagents`. Pi loads them directly from the managed package. Do not copy them into the agent directory from install scripts; that would create duplicates and leave stale files after removal.
48
+ The root manifest declares `skills/background-terminals` and `skills/subagents`. Pi loads them directly from the managed package. Do not copy them into the agent directory from install scripts; that would create duplicates and leave stale files after removal.
49
49
 
50
50
  When any paired skill changes, validate its structure and keep its behavior aligned with the corresponding extension tools.
51
51
 
@@ -1,6 +1,6 @@
1
1
  # Extension catalog
2
2
 
3
- Last verified: 2026-09-03
3
+ Last verified: 2026-09-04
4
4
 
5
5
  ## Agent workflow
6
6
 
@@ -24,12 +24,6 @@ The subagent extension runs flat Pi child agents with profiles, capability polic
24
24
 
25
25
  The extension supplies tools including `spawn_agent`, `task`, `check_agent`, `list_agents`, `wait_agent`, `send_message`, `close_agent`, `reply_question`, and `apply_agent_changes`. These lifecycle operations render as compact expandable main-chat cards; only active manager entries contribute to the bounded Active work dock, while workflow progress is intentionally omitted from the footer so persisted history cannot inflate or duplicate live status. Cancellation and reload interruption use a distinct `cancelled` state rather than `error`. All completed and cancelled production subagent snapshots and transcripts persist across Pi restarts (`<agent-dir>/subagents/runs/`), allowing `resume_from` to resume completed workers at any point. Interruption immediately cascades across all child fibers in `<10ms`. Child settlement stays in a private extension queue while the parent is active, then starts one custom-result turn at Pi's safe idle edge with the summary guaranteed in model context and never rendered as user-authored or follow-up input; status tools are for explicit inspection, not waiting.
26
26
 
27
- ### [Orchestration](../extensions/orchestration/README.md)
28
-
29
- The Orchestration extension coordinates explicitly requested large tasks through a dedicated orchestrator plus configurable explorer, frontend, backend, general-worker, and reviewer models. `/orchestration` opens the dashboard and `/orchestration settings` opens the interactive role-configuration panel with the Searchable Model Picker. It reuses the canonical Subagents runtime, maintains a 10-worker pool per project, isolates Git writers in task worktrees, resumes the original worker for substantial review fixes, and applies final reviewed changes without committing or pushing.
30
-
31
- The model-facing `create_orchestration` tool starts planning only after an explicit orchestration request. `get_orchestration` reports status without advancing work. Both use compact expandable timeline cards, and active runs share the full-screen Active work dock with explicit plan-ready, blocked, running, and paused states instead of duplicating workflow progress in the footer. The full-height framed dashboard provides scrollable multi-task inspection and runs editors and confirmations outside its overlay to avoid nested-input stalls. Interrupted runs recover paused under `<agent-dir>/orchestration/`.
32
-
33
27
  ### [Smart Compaction](../extensions/smart-compaction/README.md)
34
28
 
35
29
  Replaces standard context compaction with a defensive, high-fidelity continuity engine. It intercepts `session_before_compact` events and synthesizes multi-turn conversations into structured checkpoint summaries capturing primary goals and negative constraints, progress ledgers (`Done`/`In Progress`/`Blocked`), verbatim code snippets for active/uncommitted edits, exact error root causes, architectural decisions, resume anchors, and deterministic file/diff state.
@@ -73,14 +67,6 @@ Displays the estimated prompt and session contribution to the active context win
73
67
 
74
68
  Adds a responsive footer-area status row while each assistant message is active and for an eight-second completion linger, then clears it to avoid permanent footer noise. Live TPS/output are marked as estimates; final TPS uses conventional decode throughput from first streamed token to message completion. TTFT and total elapsed time separately expose provider latency, prefill, and hidden reasoning; output tokens and active tools remain separate.
75
69
 
76
- ### [Git info](../extensions/git-info/README.md)
77
-
78
- Adds repository state to Pi's interface. `/lg` opens the local Git view and `/pr` exposes pull-request context when available.
79
-
80
- ### [Copy all](../extensions/copy-all/README.md)
81
-
82
- `/copy-all` copies the current conversation in a readable form while omitting tool protocol noise that does not belong in the transcript.
83
-
84
70
  ### [Input mode](../extensions/input-mode/README.md)
85
71
 
86
72
  `/input-mode` chooses what ordinary Enter does while Pi is running: steer before the next model step, interrupt the active run, or wait as a follow-up. The global selection lives in `<agent-dir>/input-mode.json`; explicit Alt+Enter follow-ups and non-interactive inputs retain native behavior. Pi does not expose extension rows in core `/settings`, so this is a dedicated extension settings picker rather than a private TUI patch.
@@ -4,7 +4,7 @@ Internal runtime utilities used by more than one extension. This directory is no
4
4
 
5
5
  ## Modules
6
6
 
7
- - `activity-dock.ts` aggregates bounded urgency-ordered live rows from Task List, Background Terminals, Subagents, and Orchestration into one automatic widget.
7
+ - `activity-dock.ts` aggregates bounded urgency-ordered live rows from Task List, Background Terminals, and Subagents into one automatic widget.
8
8
  - `activity-status.ts` formats compact running/completed/failed status counts.
9
9
  - `child-session.ts` owns trust-aware child resources and bounded session shutdown.
10
10
  - `context-utilization.ts` formats model-context usage and capacity.
@@ -18,8 +18,6 @@ export const CHILD_EXCLUDED_TOOL_NAMES = [
18
18
  "subagent_check",
19
19
  "subagent_list",
20
20
  "workflow",
21
- "create_orchestration",
22
- "get_orchestration",
23
21
  "ask_user",
24
22
  ] as const;
25
23
 
@@ -1,5 +1,4 @@
1
1
  export const MODEL_INFO_CHANNEL = "dashboard:model-info";
2
- export const GIT_INFO_CHANNEL = "dashboard:git-info";
3
2
  export const REFRESH_CHANNEL = "dashboard:refresh";
4
3
 
5
4
  export interface ModelInfoState {
@@ -15,19 +14,6 @@ export interface ModelInfoState {
15
14
  generating: boolean;
16
15
  }
17
16
 
18
- export interface PullRequestInfo {
19
- number: number;
20
- url: string;
21
- isDraft: boolean;
22
- }
23
-
24
- export interface GitInfoState {
25
- isRepository: boolean;
26
- branch: string | null;
27
- changedFiles: number;
28
- pullRequest: PullRequestInfo | null;
29
- }
30
-
31
17
  export function emptyModelInfoState(): ModelInfoState {
32
18
  return {
33
19
  provider: "",
@@ -43,15 +29,6 @@ export function emptyModelInfoState(): ModelInfoState {
43
29
  };
44
30
  }
45
31
 
46
- export function emptyGitInfoState(): GitInfoState {
47
- return {
48
- isRepository: false,
49
- branch: null,
50
- changedFiles: 0,
51
- pullRequest: null,
52
- };
53
- }
54
-
55
32
  function isRecord(value: unknown): value is Record<string, unknown> {
56
33
  return typeof value === "object" && value !== null;
57
34
  }
@@ -76,24 +53,3 @@ export function isModelInfoState(value: unknown): value is ModelInfoState {
76
53
  typeof value.generating === "boolean"
77
54
  );
78
55
  }
79
-
80
- function isPullRequestInfo(value: unknown): value is PullRequestInfo {
81
- if (!isRecord(value)) return false;
82
-
83
- return (
84
- typeof value.number === "number" &&
85
- typeof value.url === "string" &&
86
- typeof value.isDraft === "boolean"
87
- );
88
- }
89
-
90
- export function isGitInfoState(value: unknown): value is GitInfoState {
91
- if (!isRecord(value)) return false;
92
-
93
- return (
94
- typeof value.isRepository === "boolean" &&
95
- (value.branch === null || typeof value.branch === "string") &&
96
- typeof value.changedFiles === "number" &&
97
- (value.pullRequest === null || isPullRequestInfo(value.pullRequest))
98
- );
99
- }
@@ -107,8 +107,6 @@ const CHILD_EXCLUDED_TOOL_NAMES = [
107
107
  "task",
108
108
  "reply_question",
109
109
  "workflow",
110
- "create_orchestration",
111
- "get_orchestration",
112
110
  "ask_user",
113
111
  ] as const;
114
112
 
@@ -64,7 +64,7 @@ Run:
64
64
  /tasks
65
65
  ```
66
66
 
67
- While work is active, the shared bounded **Active work** dock above the editor shows progress and current items alongside any live terminals, subagents, or orchestration runs without stacking separate widgets. A finished list lingers for four seconds so the final checkmark is visible, then clears from the live chrome while remaining available in session history.
67
+ While work is active, the shared bounded **Active work** dock above the editor shows progress and current items alongside any live terminals or subagents without stacking separate widgets. A finished list lingers for four seconds so the final checkmark is visible, then clears from the live chrome while remaining available in session history.
68
68
 
69
69
  `/tasks` opens the full-width interactive dashboard:
70
70
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shariq-pi-extensions",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Cross-platform extension suite for the Pi coding agent.",
5
5
  "license": "MIT",
6
6
  "author": "Shariq Riaz",
@@ -40,12 +40,9 @@
40
40
  "./extensions/ask-user/index.ts",
41
41
  "./extensions/background-terminals/index.ts",
42
42
  "./extensions/context-usage/index.ts",
43
- "./extensions/copy-all/index.ts",
44
43
  "./extensions/firecrawl-web/index.ts",
45
- "./extensions/git-info/index.ts",
46
44
  "./extensions/goal/index.ts",
47
45
  "./extensions/input-mode/index.ts",
48
- "./extensions/orchestration/index.ts",
49
46
  "./extensions/performance-status/index.ts",
50
47
  "./extensions/shell-shortcuts/index.ts",
51
48
  "./extensions/smart-compaction/index.ts",
@@ -55,7 +52,6 @@
55
52
  ],
56
53
  "skills": [
57
54
  "./skills/background-terminals",
58
- "./skills/orchestration",
59
55
  "./skills/subagents"
60
56
  ],
61
57
  "themes": [
@@ -1,15 +0,0 @@
1
- # Copy All
2
-
3
- Copies a readable transcript of the active Pi conversation branch to the system clipboard.
4
-
5
- ## Command
6
-
7
- `/copy-all` waits for the current agent run to settle, then copies visible user and assistant messages from the active branch. Messages are labeled `USER` and `ASSISTANT` and separated with a horizontal divider.
8
-
9
- The exported transcript intentionally excludes system messages, tool calls, tool results, and hidden reasoning. Image blocks are represented as `[image]`. Empty branches produce an informational notification instead of changing the clipboard.
10
-
11
- Clipboard access uses Pi's cross-platform clipboard helper. A clipboard failure is shown in the interface and does not alter the session.
12
-
13
- ## Validation
14
-
15
- From the repository root, run `npm run validate`.
@@ -1,72 +0,0 @@
1
- import {
2
- copyToClipboard,
3
- type ExtensionAPI,
4
- } from "@earendil-works/pi-coding-agent";
5
-
6
- export function textFromMessageContent(content: unknown): string {
7
- if (typeof content === "string") return content.trim();
8
- if (!Array.isArray(content)) return "";
9
- return content
10
- .map((block) => {
11
- if (!block || typeof block !== "object" || !("type" in block)) return "";
12
- if (
13
- block.type === "text" &&
14
- "text" in block &&
15
- typeof block.text === "string"
16
- ) {
17
- return block.text;
18
- }
19
- if (block.type === "image") return "[image]";
20
- return "";
21
- })
22
- .filter(Boolean)
23
- .join("\n")
24
- .trim();
25
- }
26
-
27
- export function formatConversation(
28
- messages: ReadonlyArray<{ role?: unknown; content?: unknown }>,
29
- ): string {
30
- return messages
31
- .filter(
32
- (message) => message.role === "user" || message.role === "assistant",
33
- )
34
- .map((message) => ({
35
- role: String(message.role).toUpperCase(),
36
- text: textFromMessageContent(message.content),
37
- }))
38
- .filter((message) => message.text)
39
- .map((message) => `${message.role}:\n${message.text}`)
40
- .join("\n\n---\n\n");
41
- }
42
-
43
- export default function copyAllExtension(pi: ExtensionAPI) {
44
- pi.registerCommand("copy-all", {
45
- description: "Copy visible user and assistant text from the current branch",
46
- handler: async (_args, ctx) => {
47
- await ctx.waitForIdle();
48
- const messages = ctx.sessionManager
49
- .getBranch()
50
- .filter((entry) => entry.type === "message")
51
- .map((entry) => entry.message);
52
- const visibleMessages = messages.filter(
53
- (message) => message.role === "user" || message.role === "assistant",
54
- );
55
- const transcript = formatConversation(visibleMessages);
56
- if (!transcript) {
57
- ctx.ui.notify("No user or assistant messages to copy", "info");
58
- return;
59
- }
60
- try {
61
- await copyToClipboard(transcript);
62
- } catch (error) {
63
- ctx.ui.notify(
64
- `Could not copy the conversation: ${error instanceof Error ? error.message : String(error)}`,
65
- "error",
66
- );
67
- return;
68
- }
69
- ctx.ui.notify(`Copied ${visibleMessages.length} branch messages`, "info");
70
- },
71
- });
72
- }
@@ -1,25 +0,0 @@
1
- # Git Info
2
-
3
- Shows the current Git branch and working-tree state in Pi and provides an interactive changed-file viewer.
4
-
5
- ## Interface and commands
6
-
7
- - The footer status displays the branch, changed-file count, and open pull-request number when known.
8
- - `/lg` opens a TUI browser for changed and untracked files, line counts, and bounded textual diffs.
9
- - `/pr` refreshes pull-request information for the current branch and reports its URL.
10
-
11
- Status refreshes after user input and tool execution, with debounce and stale-result protection. Outside a Git repository, the footer is hidden and commands return a clear notice.
12
-
13
- ## Dependencies and limits
14
-
15
- - Requires `git` for repository status and diffs.
16
- - `/pr` additionally requires an authenticated GitHub CLI (`gh`); unavailable or non-open pull requests are treated as no matching open pull request.
17
- - The changed-file viewer loads at most 250 files and bounds each textual diff to 20,000 lines.
18
- - Binary file statistics may be unavailable and are displayed without fabricated counts.
19
- - Repository paths and command output are sanitized before TUI rendering.
20
-
21
- The extension reads repository state only. It does not stage, commit, push, or modify files.
22
-
23
- ## Validation
24
-
25
- From the repository root, run `npm run validate`.
@@ -1,160 +0,0 @@
1
- import {
2
- BorderedLoader,
3
- type ExtensionAPI,
4
- type ExtensionContext,
5
- type ExtensionUIContext,
6
- } from "@earendil-works/pi-coding-agent";
7
- import {
8
- loadChangedFiles,
9
- loadGitSummary,
10
- loadPullRequest,
11
- type GitSummary,
12
- } from "./src/git.ts";
13
- import { openGitChanges } from "./src/ui.ts";
14
-
15
- const STATUS_KEY = "git-info";
16
- const REFRESH_DEBOUNCE_MS = 150;
17
-
18
- function statusText(ui: ExtensionUIContext, summary: GitSummary): string | undefined {
19
- if (!summary.isRepository || !summary.branch) return undefined;
20
- const changed = summary.changedFiles === 0
21
- ? ui.theme.fg("muted", "✓")
22
- : ui.theme.fg("warning", `+${summary.changedFiles}`);
23
- const pr = summary.pullRequest
24
- ? ` · ${ui.theme.fg("accent", `PR #${summary.pullRequest.number}${summary.pullRequest.draft ? " draft" : ""}`)}`
25
- : "";
26
- const command = summary.changedFiles > 0 || summary.pullRequest ? ` · ${ui.theme.fg("dim", "/lg")}` : "";
27
- return `${ui.theme.fg("muted", "git")} ${ui.theme.fg("accent", summary.branch)} ${changed}${pr}${command}`;
28
- }
29
-
30
- export default function gitInfoExtension(pi: ExtensionAPI) {
31
- let ui: ExtensionUIContext | undefined;
32
- let summary: GitSummary = { isRepository: false, changedFiles: 0 };
33
- let generation = 0;
34
- let refreshTimer: ReturnType<typeof setTimeout> | undefined;
35
- let refreshSequence = 0;
36
-
37
- const publish = () => ui?.setStatus(STATUS_KEY, statusText(ui, summary));
38
-
39
- const refresh = async (ctx: ExtensionContext, expectedGeneration: number) => {
40
- const sequence = ++refreshSequence;
41
- try {
42
- const next = await loadGitSummary(pi, ctx.cwd);
43
- if (generation !== expectedGeneration || sequence !== refreshSequence) return;
44
- const sameBranch = next.branch && next.branch === summary.branch;
45
- summary = {
46
- ...next,
47
- pullRequest: sameBranch ? summary.pullRequest : undefined,
48
- };
49
- publish();
50
- } catch {
51
- if (generation === expectedGeneration && sequence === refreshSequence) {
52
- summary = { isRepository: false, changedFiles: 0 };
53
- publish();
54
- }
55
- }
56
- };
57
-
58
- const scheduleRefresh = (ctx: ExtensionContext) => {
59
- if (!ui) return;
60
- const expectedGeneration = generation;
61
- if (refreshTimer) clearTimeout(refreshTimer);
62
- refreshTimer = setTimeout(() => {
63
- refreshTimer = undefined;
64
- void refresh(ctx, expectedGeneration);
65
- }, REFRESH_DEBOUNCE_MS);
66
- refreshTimer.unref?.();
67
- };
68
-
69
- pi.on("session_start", (_event, ctx) => {
70
- generation++;
71
- summary = { isRepository: false, changedFiles: 0 };
72
- if (ctx.hasUI) ui = ctx.ui;
73
- void refresh(ctx, generation);
74
- });
75
- pi.on("input", (_event, ctx) => {
76
- scheduleRefresh(ctx);
77
- return { action: "continue" };
78
- });
79
- pi.on("tool_execution_end", (_event, ctx) => scheduleRefresh(ctx));
80
- pi.on("session_shutdown", () => {
81
- generation++;
82
- refreshSequence++;
83
- if (refreshTimer) clearTimeout(refreshTimer);
84
- refreshTimer = undefined;
85
- ui?.setStatus(STATUS_KEY, undefined);
86
- ui = undefined;
87
- });
88
-
89
- pi.registerCommand("lg", {
90
- description: "Browse changed files and diffs in the current Git repository",
91
- handler: async (_args, ctx) => {
92
- if (ctx.mode !== "tui") {
93
- if (ctx.hasUI) ctx.ui.notify("The Git changes viewer requires the TUI", "warning");
94
- return;
95
- }
96
- type LoadOutcome =
97
- | { loaded: Awaited<ReturnType<typeof loadChangedFiles>> }
98
- | { error: string }
99
- | null;
100
- const outcome = await ctx.ui.custom<LoadOutcome>((tui, theme, _keybindings, done) => {
101
- const loader = new BorderedLoader(tui, theme, "Loading Git changes…");
102
- let settled = false;
103
- const finish = (value: LoadOutcome) => {
104
- if (settled) return;
105
- settled = true;
106
- done(value);
107
- };
108
- loader.onAbort = () => finish(null);
109
- loadChangedFiles(pi, ctx.cwd, loader.signal).then(
110
- (loaded) => finish({ loaded }),
111
- (error: unknown) => {
112
- if (loader.signal.aborted) finish(null);
113
- else finish({ error: error instanceof Error ? error.message : String(error) });
114
- },
115
- );
116
- return loader;
117
- });
118
- if (!outcome) {
119
- ctx.ui.notify("Git changes load cancelled", "info");
120
- return;
121
- }
122
- if ("error" in outcome) {
123
- ctx.ui.notify(`Could not load Git changes: ${outcome.error}`, "error");
124
- return;
125
- }
126
- const { loaded } = outcome;
127
- if (!loaded) {
128
- ctx.ui.notify("Not a Git repository", "warning");
129
- return;
130
- }
131
- if (loaded.files.length === 0) {
132
- ctx.ui.notify("Working tree is clean", "info");
133
- return;
134
- }
135
- await openGitChanges(ctx, loaded.root, loaded.files, loaded.omitted);
136
- },
137
- });
138
-
139
- pi.registerCommand("pr", {
140
- description: "Refresh pull-request information for the current branch",
141
- handler: async (_args, ctx) => {
142
- const next = await loadGitSummary(pi, ctx.cwd);
143
- if (!next.isRepository) {
144
- ctx.ui.notify("Not a Git repository", "warning");
145
- return;
146
- }
147
- const pullRequest = await loadPullRequest(pi, next.root ?? ctx.cwd);
148
- summary = { ...next, pullRequest };
149
- publish();
150
- if (!pullRequest) {
151
- ctx.ui.notify(`No open pull request found for ${next.branch ?? "this branch"}`, "info");
152
- return;
153
- }
154
- ctx.ui.notify(
155
- `PR #${pullRequest.number}${pullRequest.draft ? " (draft)" : ""}: ${pullRequest.url}`,
156
- "info",
157
- );
158
- },
159
- });
160
- }