@averyyy/pi-client 1.2.0-piclient.1 → 1.3.0-piclient.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/CHANGELOG.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  ### Fixed
4
4
 
5
+ - Restarted updated runtimes through `/reload` with the current session, branch, and startup options. Shared update generations let each active session switch runtimes, and runtime lookup or handoff errors remain visible without relaunching the old runtime.
6
+ - Invoked npm through Node on Windows so global updates can start without a shell.
5
7
  - Reported upstream Pi 1.0.0 and its full source commit in package metadata.
6
8
  - Documented remote model operations, server-side credentials, and the 64 KiB UTF-8 request limit.
7
9
  - Enabled remote prompt-cache warming with streaming and idle modes, bounded request bodies, and session usage accounting.
package/bin/pi-client.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawnSync } from "node:child_process";
3
- import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
4
- import { tmpdir } from "node:os";
3
+ import { mkdtempSync, readFileSync, rmSync } from "node:fs";
4
+ import { homedir, tmpdir } from "node:os";
5
5
  import { dirname, join } from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { runPiClientSend } from "./send.js";
@@ -33,6 +33,8 @@ function runPiClientCli(args) {
33
33
  const reloadStatePath = join(reloadDir, "state.json");
34
34
  let cliPath = getLocalCliPath();
35
35
  let childArgs = args;
36
+ let reloadLeafId;
37
+ let runtimeUpdatedAt = readRuntimeUpdateGeneration();
36
38
 
37
39
  try {
38
40
  for (;;) {
@@ -43,6 +45,8 @@ function runPiClientCli(args) {
43
45
  PI_SERVER_MODE: "true",
44
46
  PI_CLIENT_VERSION: packageVersion,
45
47
  PI_CLIENT_RELOAD_STATE_PATH: reloadStatePath,
48
+ PI_CLIENT_RELOAD_LEAF_ID: reloadLeafId,
49
+ PI_CLIENT_RUNTIME_UPDATED_AT: runtimeUpdatedAt,
46
50
  },
47
51
  stdio: "inherit",
48
52
  });
@@ -53,14 +57,10 @@ function runPiClientCli(args) {
53
57
  }
54
58
 
55
59
  const state = readReloadState(reloadStatePath);
56
- if (!state) {
57
- console.error("pi-client reload failed: missing session state from the previous runtime.");
58
- process.exitCode = 1;
59
- return;
60
- }
61
- rmSync(state.updateMarkerPath, { force: true });
62
- childArgs = state.sessionDir ? ["--session-dir", state.sessionDir, "--session", state.sessionId] : ["--session", state.sessionId];
63
- cliPath = getUpdatedGlobalCliPath() ?? getLocalCliPath();
60
+ cliPath = getUpdatedGlobalCliPath();
61
+ reloadLeafId = state.leafId ?? "";
62
+ runtimeUpdatedAt = state.updatedAt;
63
+ childArgs = [...state.args, ...(state.sessionDir ? ["--session-dir", state.sessionDir] : []), "--session", state.sessionId];
64
64
  }
65
65
  } finally {
66
66
  rmSync(reloadDir, { recursive: true, force: true });
@@ -72,24 +72,42 @@ function getLocalCliPath() {
72
72
  return join(dirname(entry), "cli.js");
73
73
  }
74
74
 
75
+ function readRuntimeUpdateGeneration() {
76
+ const markerPath = join(process.env.PI_CODING_AGENT_DIR ?? join(homedir(), ".pi", "agent"), "pi-client-update.json");
77
+ try {
78
+ const marker = JSON.parse(readFileSync(markerPath, "utf-8"));
79
+ if (typeof marker?.updatedAt !== "string") throw new Error(`Invalid pi-client update marker: ${markerPath}`);
80
+ return marker.updatedAt;
81
+ } catch (error) {
82
+ if (error.code !== "ENOENT") console.error(`Could not read pi-client update marker: ${error.message}`);
83
+ return "";
84
+ }
85
+ }
86
+
75
87
  function getUpdatedGlobalCliPath() {
76
88
  const npmCli = join(dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
77
- const result = existsSync(npmCli)
89
+ const result = process.platform === "win32"
78
90
  ? spawnSync(process.execPath, [npmCli, "root", "-g"], { encoding: "utf-8" })
79
91
  : spawnSync("npm", ["root", "-g"], { encoding: "utf-8" });
80
- if (result.status !== 0) return undefined;
92
+ if (result.error) throw result.error;
93
+ if (result.status !== 0) {
94
+ throw new Error(`Could not locate the updated pi-client runtime: ${result.stderr.trim()}`);
95
+ }
81
96
  const root = result.stdout.trim();
82
- const cliPath = join(root, "@averyyy", "pi-client", "node_modules", "@earendil-works", "pi-coding-agent", "dist", "cli.js");
83
- return existsSync(cliPath) ? cliPath : undefined;
97
+ return join(root, "@averyyy", "pi-client", "node_modules", "@earendil-works", "pi-coding-agent", "dist", "cli.js");
84
98
  }
85
99
 
86
100
  function readReloadState(path) {
87
- try {
88
- const value = JSON.parse(readFileSync(path, "utf-8"));
89
- if (typeof value.sessionId !== "string" || typeof value.updateMarkerPath !== "string") return undefined;
90
- if (value.sessionDir !== undefined && typeof value.sessionDir !== "string") return undefined;
91
- return value;
92
- } catch {
93
- return undefined;
101
+ const value = JSON.parse(readFileSync(path, "utf-8"));
102
+ if (
103
+ typeof value?.sessionId !== "string" ||
104
+ typeof value?.updatedAt !== "string" ||
105
+ !Array.isArray(value.args) ||
106
+ !value.args.every((arg) => typeof arg === "string") ||
107
+ (value.leafId !== null && typeof value.leafId !== "string") ||
108
+ (value.sessionDir !== undefined && typeof value.sessionDir !== "string")
109
+ ) {
110
+ throw new Error(`Invalid pi-client reload state: ${path}`);
94
111
  }
112
+ return value;
95
113
  }
package/bin/update.js CHANGED
@@ -12,10 +12,6 @@ function readPackageMetadata(packageRoot) {
12
12
  return JSON.parse(readFileSync(resolve(packageRoot, "package.json"), "utf-8"));
13
13
  }
14
14
 
15
- function runStep(runner, command, args, cwd, stdio = "inherit") {
16
- return runner(command, args, { cwd, stdio, encoding: "utf-8" });
17
- }
18
-
19
15
  function defaultUpdateMarkerPath() {
20
16
  return join(process.env.PI_CODING_AGENT_DIR ?? join(homedir(), ".pi", "agent"), "pi-client-update.json");
21
17
  }
@@ -25,12 +21,13 @@ function writeUpdateMarker(path) {
25
21
  writeFileSync(path, `${JSON.stringify({ version: "latest", updatedAt: new Date().toISOString() })}\n`);
26
22
  }
27
23
 
28
- function runNpmGlobalUpdate(runner, cwd, stdout, stderr, updateMarkerPath) {
24
+ function runNpmGlobalUpdate(runner, cwd, stdout, stderr, updateMarkerPath, platform) {
29
25
  stdout.write("Updating npm packages: @averyyy/pi-client@latest @averyyy/pi-server@latest\n");
30
- const result = runStep(
31
- runner,
32
- "npm",
26
+ const command = platform === "win32" ? process.execPath : "npm";
27
+ const result = runner(
28
+ command,
33
29
  [
30
+ ...(platform === "win32" ? [join(dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js")] : []),
34
31
  "install",
35
32
  "-g",
36
33
  "--ignore-scripts",
@@ -39,7 +36,7 @@ function runNpmGlobalUpdate(runner, cwd, stdout, stderr, updateMarkerPath) {
39
36
  "@averyyy/pi-client@latest",
40
37
  "@averyyy/pi-server@latest",
41
38
  ],
42
- cwd,
39
+ { cwd, stdio: "inherit", encoding: "utf-8" },
43
40
  );
44
41
  if (result.status !== 0) {
45
42
  stderr.write(
@@ -59,10 +56,11 @@ export async function runPiClientUpdate(_args = [], options = {}) {
59
56
  const stdout = options.stdout ?? process.stdout;
60
57
  const stderr = options.stderr ?? process.stderr;
61
58
  const updateMarkerPath = options.updateMarkerPath ?? defaultUpdateMarkerPath();
59
+ const platform = options.platform ?? process.platform;
62
60
  const pkg = readPackageMetadata(packageRoot);
63
- const baseVersion = pkg.piClient?.basePiVersion ?? "unknown";
64
- const baseCommit = pkg.piClient?.basePiCommit ?? "unknown";
61
+ const baseVersion = pkg.piClient.basePiVersion;
62
+ const baseCommit = pkg.piClient.basePiCommit;
65
63
 
66
64
  stdout.write(`pi-client ${pkg.version} (based on pi ${baseVersion}, upstream ${baseCommit})\n`);
67
- return runNpmGlobalUpdate(runner, process.cwd(), stdout, stderr, updateMarkerPath);
65
+ return runNpmGlobalUpdate(runner, process.cwd(), stdout, stderr, updateMarkerPath, platform);
68
66
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@averyyy/pi-client",
3
- "version": "1.2.0-piclient.1",
3
+ "version": "1.3.0-piclient.1",
4
4
  "description": "Lightweight CLI wrapper that connects to a pi-server instance",
5
5
  "type": "module",
6
6
  "piClient": {
@@ -25,7 +25,7 @@
25
25
  "prepublishOnly": "npm run build"
26
26
  },
27
27
  "dependencies": {
28
- "@earendil-works/pi-coding-agent": "npm:@averyyy/pi-coding-agent@1.2.0-piclient.1"
28
+ "@earendil-works/pi-coding-agent": "npm:@averyyy/pi-coding-agent@1.3.0-piclient.1"
29
29
  },
30
30
  "devDependencies": {
31
31
  "shx": "0.4.0",