privateer-agent 0.12.0 → 0.12.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.
@@ -143,23 +143,83 @@ function runToCompletion(cmd, cmdArgs, opts = {}) {
143
143
  });
144
144
  }
145
145
 
146
+ // npm gives no usable progress, so on a TTY show a braille spinner while it runs
147
+ // and keep its output buffered — shown only if the install fails. Non-TTY (CI,
148
+ // piped) keeps the old passthrough behaviour. The global package is replaced in
149
+ // place, so re-reading our own package.json afterwards yields the NEW version.
150
+ function updateNpmPackage() {
151
+ const cmd = isWin ? "npm.cmd" : "npm";
152
+ const npmArgs = ["install", "-g", "privateer-agent@latest", "--no-fund", "--no-audit"];
153
+ if (!process.stdout.isTTY) {
154
+ console.log("Updating privateer-agent to the latest release…");
155
+ // npm is npm.cmd on Windows; Node >=18.20 needs a shell to spawn a .cmd (EINVAL otherwise).
156
+ runToCompletion(cmd, npmArgs, { shell: isWin });
157
+ return;
158
+ }
159
+ // Ask npm for the globally installed version — REPO/package.json would lie when
160
+ // this copy runs from somewhere other than the global root (e.g. an npx cache).
161
+ const globalVer = () => {
162
+ try {
163
+ const r = spawnSync(cmd, ["ls", "-g", "privateer-agent", "--depth=0", "--json"], { shell: isWin, encoding: "utf8" });
164
+ return JSON.parse(r.stdout).dependencies?.["privateer-agent"]?.version ?? null;
165
+ } catch { return null; }
166
+ };
167
+ const before = globalVer();
168
+ console.log(`\x1b[1m⚓ Updating Privateer\x1b[0m${before ? ` \x1b[2m(currently ${before})\x1b[0m` : ""}`);
169
+ const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
170
+ let captured = "";
171
+ const child = spawn(cmd, [...npmArgs, "--loglevel=error"], { shell: isWin, env: process.env });
172
+ child.stdout.on("data", (d) => (captured += d));
173
+ child.stderr.on("data", (d) => (captured += d));
174
+ process.stdout.write("\x1b[?25l");
175
+ const t0 = Date.now();
176
+ let i = 0;
177
+ const timer = setInterval(() => {
178
+ const s = Math.round((Date.now() - t0) / 1000);
179
+ process.stdout.write(`\r \x1b[36m${frames[i++ % frames.length]}\x1b[0m updating privateer-agent@latest \x1b[2m${s}s\x1b[0m\x1b[K`);
180
+ }, 80);
181
+ const restore = () => { clearInterval(timer); process.stdout.write("\r\x1b[K\x1b[?25h"); };
182
+ child.on("exit", (code, signal) => {
183
+ restore();
184
+ if (code === 0) {
185
+ const after = globalVer();
186
+ if (before && after && before === after) {
187
+ console.log(`\x1b[32m✓\x1b[0m Already ship-shape — privateer-agent ${after} is the latest release.`);
188
+ } else {
189
+ console.log(`\x1b[32m✓\x1b[0m Updated privateer-agent${before ? ` ${before} →` : ""}${after ? ` ${after}` : ""}`);
190
+ console.log(`\nRun \x1b[1mprivateer\x1b[0m to set sail on the new release.`);
191
+ }
192
+ process.exit(0);
193
+ }
194
+ if (captured.trim()) process.stderr.write(captured);
195
+ if (signal) process.kill(process.pid, signal);
196
+ else process.exit(code ?? 1);
197
+ });
198
+ child.on("error", (e) => {
199
+ restore();
200
+ console.error(`privateer: failed to launch npm — ${e.message}`);
201
+ process.exit(1);
202
+ });
203
+ }
204
+
146
205
  // --- `privateer update` ----------------------------------------------------
147
206
  // Fetch the latest release and exit. Bundle installs re-run the download+extract
148
207
  // installer; npm installs update the global package.
149
208
  if (sub === "update") {
150
209
  if (BUNDLED) {
151
- console.log("Updating Privateer to the latest release…");
210
+ // PRIVATEER_UPDATE=1 flips the installer into update mode: weigh-anchor banner,
211
+ // "X → Y" version reporting, and an early exit (no download) when already current.
212
+ // ?update=1 tells the server this fetch is an update, not a fresh install.
213
+ const env = { ...process.env, PRIVATEER_UPDATE: "1" };
152
214
  if (isWin) {
153
- runToCompletion("powershell", ["-NoProfile", "-Command", "irm https://privateer.pro/install.ps1 | iex"]);
215
+ runToCompletion("powershell", ["-NoProfile", "-Command", "irm 'https://privateer.pro/install.ps1?update=1' | iex"], { env });
154
216
  } else {
155
- runToCompletion("sh", ["-c", "curl -fsSL https://privateer.pro/install.sh | sh"]);
217
+ runToCompletion("sh", ["-c", "curl -fsSL 'https://privateer.pro/install.sh?update=1' | sh"], { env });
156
218
  }
157
219
  } else {
158
- console.log("Updating privateer-agent to the latest release…");
159
- // npm is npm.cmd on Windows; Node >=18.20 needs a shell to spawn a .cmd (EINVAL otherwise).
160
- runToCompletion(isWin ? "npm.cmd" : "npm", ["install", "-g", "privateer-agent@latest"], { shell: isWin });
220
+ updateNpmPackage();
161
221
  }
162
- // runToCompletion exits via the child's exit handler.
222
+ // both paths exit via their child's exit handler.
163
223
  }
164
224
 
165
225
  // --- `privateer harbor [run|install|uninstall|status]` ---------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "privateer-agent",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Privacy-first terminal coding agent — bring your own model across 20 providers (Anthropic, OpenAI, OpenRouter, Google, local Ollama…). Safe-by-default permissions, MCP, sub-agents, workflows, and verifiable TEE inference. Built on the Pi toolkit.",
5
5
  "type": "module",
6
6
  "license": "MIT",