@ryan_nookpi/pi-extension-setup-sh 0.1.0 → 0.2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @ryan_nookpi/pi-extension-setup-sh
2
2
 
3
- Automatically runs the nearest `setup.sh` when a pi session starts.
3
+ Automatically runs `setup.sh` from the current pi working directory when a session starts.
4
4
 
5
5
  This is useful for repositories that need a predictable bootstrap step before the agent starts editing, testing, or running commands.
6
6
 
@@ -12,52 +12,37 @@ pi install npm:@ryan_nookpi/pi-extension-setup-sh
12
12
 
13
13
  ## What it does
14
14
 
15
- - searches the current directory and parent directories for `setup.sh`
15
+ - looks for `setup.sh` only in the current working directory
16
16
  - runs `setup.sh` automatically on session startup
17
17
  - skips automatic reruns when the same `setup.sh` already completed successfully
18
+ - keeps a single `/setup-sh` command for manual control
18
19
  - shows running, pending, failed, cancelled, and stale states in the pi UI
19
20
  - keeps per-project logs and state under pi's setup-sh state directory
20
21
  - prevents duplicate setup runs with a lock file
21
22
 
22
- ## Commands
23
+ ## Command
23
24
 
24
25
  ```text
25
26
  /setup-sh
26
- /setup-sh status
27
- /setup-sh rerun
28
- /setup-sh cancel
29
- /setup-sh clear
30
- /setup-sh help
31
27
  ```
32
28
 
33
- ### `/setup-sh`
29
+ `/setup-sh` is a toggle-style command:
34
30
 
35
- Runs the nearest `setup.sh` manually, or attaches to the current run if one is already active.
31
+ - if no setup run exists yet, it starts `./setup.sh`
32
+ - if setup is currently running, it aborts the active run
33
+ - if setup already finished, it reruns `./setup.sh`
36
34
 
37
- ### `/setup-sh status`
38
-
39
- Shows the current setup state and recent log lines.
40
-
41
- ### `/setup-sh rerun`
42
-
43
- Runs `setup.sh` again even if the previous run succeeded.
44
-
45
- ### `/setup-sh cancel`
46
-
47
- Sends a termination signal to the active setup process.
48
-
49
- ### `/setup-sh clear`
50
-
51
- Hides the setup widget for the current session.
35
+ No subcommands are registered.
52
36
 
53
37
  ## Behavior
54
38
 
55
- - `setup.sh` is executed with `/bin/zsh` from the directory containing the script.
39
+ - `setup.sh` is executed with `/bin/zsh` from the current working directory.
56
40
  - A successful automatic run is remembered by the script hash, so changing `setup.sh` allows it to run again.
57
41
  - Long-running setup output becomes `pending` in the UI when logs have been idle for a while.
58
- - Failed and stale states stay visible so you can inspect them with `/setup-sh status` or rerun with `/setup-sh rerun`.
42
+ - Failed and stale states stay visible and can be rerun with `/setup-sh`.
43
+ - If the current directory does not contain `setup.sh`, `/setup-sh` reports that it was not found in the current folder.
59
44
 
60
45
  ## Requirements
61
46
 
62
47
  - pi
63
- - a readable `setup.sh` file in the project directory or one of its parents
48
+ - a readable `setup.sh` file in the current pi working directory
package/context.ts CHANGED
@@ -49,13 +49,8 @@ export function findSetupPath(cwd: string): string | null {
49
49
  // Keep resolved cwd when the directory cannot be canonicalized yet.
50
50
  }
51
51
 
52
- while (true) {
53
- const candidate = path.join(current, "setup.sh");
54
- if (isExecutableOrReadable(candidate)) return candidate;
55
- const parent = path.dirname(current);
56
- if (parent === current) return null;
57
- current = parent;
58
- }
52
+ const candidate = path.join(current, "setup.sh");
53
+ return isExecutableOrReadable(candidate) ? candidate : null;
59
54
  }
60
55
 
61
56
  export function resolveSetupContext(cwd: string): SetupContext | null {
package/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
1
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
  import { PENDING_AFTER_MS, STATE_ROOT, STATUS_KEY, WIDGET_KEY, WIDGET_REFRESH_MS } from "./constants.js";
3
3
  import { displayPath, findSetupPath, repoKeyFor, resolveSetupContext } from "./context.js";
4
4
  import { cancelSetup, createWrapperScript, startSetup } from "./runner.js";
@@ -10,22 +10,10 @@ import {
10
10
  installWidget,
11
11
  refreshWatcher,
12
12
  renderWidgetLine,
13
- showStatus,
14
13
  stopWatcher,
15
14
  type Watcher,
16
15
  } from "./widget.js";
17
16
 
18
- function commandHelp(): string {
19
- return [
20
- "/setup-sh [status|rerun|cancel|clear]",
21
- "- 인자 없음: 현재 폴더의 setup.sh 실행 또는 실행 상태 표시",
22
- "- status: 상세 상태와 로그 tail 표시",
23
- "- rerun: 성공/실패 상태와 무관하게 재실행",
24
- "- cancel: 실행 중인 setup.sh 종료",
25
- "- clear: 현재 세션의 setup widget 숨김",
26
- ].join("\n");
27
- }
28
-
29
17
  async function notifyStartResult(ctx: ExtensionContext, result: StartResult): Promise<void> {
30
18
  if (result.kind === "started") {
31
19
  ctx.ui.notify(`setup.sh 실행 시작: ${displayPath(result.context.repoRoot)}`, "info");
@@ -61,10 +49,9 @@ export const __test__ = {
61
49
 
62
50
  export default function setupShExtension(pi: ExtensionAPI): void {
63
51
  let watcher: Watcher | null = null;
64
- const hiddenRepoKeys = new Set<string>();
65
52
 
66
53
  async function watch(ctx: ExtensionContext, context: SetupContext): Promise<void> {
67
- if (!ctx.hasUI || hiddenRepoKeys.has(context.repoKey)) return;
54
+ if (!ctx.hasUI) return;
68
55
  stopWatcher(ctx, watcher);
69
56
  watcher = {
70
57
  context,
@@ -81,10 +68,7 @@ export default function setupShExtension(pi: ExtensionAPI): void {
81
68
 
82
69
  async function runOrAttach(ctx: ExtensionContext, mode: StartMode): Promise<StartResult> {
83
70
  const result = await startSetup(ctx.cwd, mode);
84
- if (result.kind !== "no-setup" && result.kind !== "failed") {
85
- hiddenRepoKeys.delete(result.context.repoKey);
86
- await watch(ctx, result.context);
87
- }
71
+ if (result.kind !== "no-setup" && result.kind !== "failed") await watch(ctx, result.context);
88
72
  return result;
89
73
  }
90
74
 
@@ -118,55 +102,28 @@ export default function setupShExtension(pi: ExtensionAPI): void {
118
102
  });
119
103
 
120
104
  pi.registerCommand("setup-sh", {
121
- description: "Run or inspect ./setup.sh for the current folder",
122
- getArgumentCompletions: (prefix: string) => {
123
- const values = ["status", "rerun", "cancel", "clear", "help"];
124
- return values
125
- .filter((value) => value.startsWith(prefix.trim()))
126
- .map((value) => ({ value, label: value, description: `/setup-sh ${value}` }));
127
- },
105
+ description: "Run, rerun, or abort ./setup.sh in the current folder",
128
106
  handler: async (args, ctx) => {
129
- const action = args.trim() || "run";
130
- const context = resolveSetupContext(ctx.cwd);
131
- if (action === "help") {
132
- ctx.ui.notify(commandHelp(), "info");
133
- return;
134
- }
135
- if (!context) {
136
- ctx.ui.notify("현재 폴더 또는 상위 폴더에서 setup.sh를 찾지 못했습니다.", "warning");
107
+ if (args.trim().length > 0) {
108
+ ctx.ui.notify("사용법: /setup-sh", "warning");
137
109
  return;
138
110
  }
139
111
 
140
- if (action === "clear") {
141
- hiddenRepoKeys.add(context.repoKey);
142
- stopWatcher(ctx, watcher);
143
- watcher = null;
144
- ctx.ui.notify("setup.sh widget을 숨겼습니다.", "info");
145
- return;
146
- }
147
-
148
- if (action === "status") {
149
- hiddenRepoKeys.delete(context.repoKey);
150
- await watch(ctx, context);
151
- await showStatus(ctx, context);
112
+ const context = resolveSetupContext(ctx.cwd);
113
+ if (!context) {
114
+ ctx.ui.notify("현재 폴더에서 setup.sh를 찾지 못했습니다.", "warning");
152
115
  return;
153
116
  }
154
117
 
155
- if (action === "cancel") {
118
+ const current = await finalizeRunIfNeeded(context);
119
+ if (current?.status === "running") {
156
120
  const message = await cancelSetup(context);
157
- hiddenRepoKeys.delete(context.repoKey);
158
121
  await watch(ctx, context);
159
122
  ctx.ui.notify(message, "warning");
160
123
  return;
161
124
  }
162
125
 
163
- if (action !== "run" && action !== "rerun") {
164
- ctx.ui.notify(commandHelp(), "warning");
165
- return;
166
- }
167
-
168
- const mode: StartMode = action === "rerun" ? "rerun" : "manual";
169
- await notifyStartResult(ctx, await runOrAttach(ctx, mode));
126
+ await notifyStartResult(ctx, await runOrAttach(ctx, current ? "rerun" : "manual"));
170
127
  },
171
128
  });
172
129
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryan_nookpi/pi-extension-setup-sh",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Auto-run setup.sh extension for pi.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -33,8 +33,8 @@
33
33
  ]
34
34
  },
35
35
  "peerDependencies": {
36
- "@mariozechner/pi-coding-agent": "*",
37
- "@mariozechner/pi-tui": "*"
36
+ "@earendil-works/pi-coding-agent": "*",
37
+ "@earendil-works/pi-tui": "*"
38
38
  },
39
39
  "publishConfig": {
40
40
  "access": "public"
package/widget.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { ExtensionContext, Theme } from "@mariozechner/pi-coding-agent";
2
- import type { TUI } from "@mariozechner/pi-tui";
3
- import { truncateToWidth } from "@mariozechner/pi-tui";
1
+ import type { ExtensionContext, Theme } from "@earendil-works/pi-coding-agent";
2
+ import type { TUI } from "@earendil-works/pi-tui";
3
+ import { truncateToWidth } from "@earendil-works/pi-tui";
4
4
  import { PENDING_AFTER_MS, STATUS_KEY, WIDGET_KEY } from "./constants.js";
5
5
  import { displayPath } from "./context.js";
6
6
  import { finalizeRunIfNeeded } from "./state.js";
@@ -49,11 +49,11 @@ export function formatSnapshotLine(snapshot: Snapshot, theme: Pick<Theme, "fg">)
49
49
 
50
50
  if (snapshot.status === "success") return `${theme.fg("success", "✅")} setup.sh done ${duration} · ${repo}`;
51
51
  if (snapshot.status === "failed") {
52
- return `${theme.fg("error", "❌")} setup.sh failed${exit} · ${repo}${suffix} · /setup-sh status`;
52
+ return `${theme.fg("error", "❌")} setup.sh failed${exit} · ${repo}${suffix} · /setup-sh`;
53
53
  }
54
54
  if (snapshot.status === "cancelled") return `${theme.fg("warning", "⚠️")} setup.sh cancelled · ${repo}${suffix}`;
55
55
  if (snapshot.status === "stale") {
56
- return `${theme.fg("warning", "⚠️")} setup.sh stale · ${repo}${suffix} · /setup-sh rerun`;
56
+ return `${theme.fg("warning", "⚠️")} setup.sh stale · ${repo}${suffix} · /setup-sh`;
57
57
  }
58
58
  if (snapshot.status === "pending") {
59
59
  return `${theme.fg("warning", "⏳")} setup.sh pending${owner} ${duration} · ${repo}${suffix}`;