@hcflabs/pi-deps 3.2.6 → 3.2.7
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 +2 -0
- package/extensions/deps.ts +23 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,6 +53,8 @@ Only Git-root lockfiles count. Package managers handle root npm and uv workspace
|
|
|
53
53
|
|
|
54
54
|
After ten minutes of `running` status, the TUI watcher removes the status file, clears the footer, and reports an error with the log path. It stops watching, not the installer. Opening Pi again cannot restore removed status.
|
|
55
55
|
|
|
56
|
+
If the watcher cannot read the status file, it stops and shows one warning with the file path and the error code. A file that is not valid JSON gets three reads before the watcher stops, because the installer can be in the middle of a write. Other read errors, such as `EACCES` or `EISDIR`, stop the watcher at once. The watcher keeps the file, so each new session shows the warning again. Examine the file, then remove it.
|
|
57
|
+
|
|
56
58
|
Closing Pi stops its watcher and animation, but does not cancel the installer or consume its pending result.
|
|
57
59
|
|
|
58
60
|
For failures, including missing executables, examine `<worktree gitdir>/pi-deps/install.log` for command output and `pi-deps:` messages. The log remains after status removal.
|
package/extensions/deps.ts
CHANGED
|
@@ -71,6 +71,8 @@ export async function toggleDependencyHook(
|
|
|
71
71
|
const statusKey = "pi-deps";
|
|
72
72
|
const pollMs = 500;
|
|
73
73
|
const waitTimeoutMs = 10 * 60_000;
|
|
74
|
+
// The watcher accepts this many consecutive parse errors before it stops.
|
|
75
|
+
const maxParseFailures = 3;
|
|
74
76
|
const spinnerIntervalMs = 100;
|
|
75
77
|
const spinnerFrames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
76
78
|
|
|
@@ -97,12 +99,25 @@ async function watchDependencyInstallation(
|
|
|
97
99
|
if (git.code !== 0 || git.killed) return;
|
|
98
100
|
const stateDir = join(git.stdout.trim(), "pi-deps");
|
|
99
101
|
const statusPath = join(stateDir, "status.json");
|
|
102
|
+
let parseFailures = 0;
|
|
103
|
+
// The "unreadable" state is local to the watcher. Its message holds the error code.
|
|
100
104
|
const readStatus = async (): Promise<InstallStatus | undefined> => {
|
|
105
|
+
let text: string;
|
|
101
106
|
try {
|
|
102
|
-
|
|
107
|
+
text = await readFile(statusPath, "utf8");
|
|
103
108
|
} catch (error) {
|
|
104
|
-
|
|
105
|
-
|
|
109
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
110
|
+
if (code === "ENOENT") return undefined;
|
|
111
|
+
return { state: "unreadable", message: code ?? "unknown error" };
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const status = JSON.parse(text) as InstallStatus;
|
|
115
|
+
parseFailures = 0;
|
|
116
|
+
return status;
|
|
117
|
+
} catch {
|
|
118
|
+
// A parse error can come from a partial write. Retry it for a short bound only.
|
|
119
|
+
parseFailures++;
|
|
120
|
+
return parseFailures < maxParseFailures ? { state: "running" } : { state: "unreadable", message: "SyntaxError" };
|
|
106
121
|
}
|
|
107
122
|
};
|
|
108
123
|
|
|
@@ -128,6 +143,11 @@ async function watchDependencyInstallation(
|
|
|
128
143
|
if (!status) return;
|
|
129
144
|
}
|
|
130
145
|
signal.throwIfAborted();
|
|
146
|
+
if (status.state === "unreadable") {
|
|
147
|
+
// Keep the file so that the user can examine it.
|
|
148
|
+
ctx.ui.setWidget(statusKey, [`pi-deps: cannot read status file ${statusPath}: ${status.message}`]);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
131
151
|
await rm(statusPath, { force: true }); // consume so later sessions do not replay a stale outcome
|
|
132
152
|
if (status.state === "error" || status.state === "running") {
|
|
133
153
|
ctx.ui.setWidget(statusKey, [
|